山大芋折腾志

The world is a … 〇

Good bye,Good luck

过去的一年是自身发生不少变化的一年。

开始了期待已久的工作生涯。去南京看鸡鸣寺的樱花。在上海谜底热情拥抱陌生人。独自出远门去了重庆和泸沽湖。潦草完成坑爹的毕业论文。迎来了一些人,送别了一些人。认识到了自己过去的种种愚蠢。明白了对待很多事情的正确方式。一些情景现在回想,哪怕最后扑街是必然,但若早些知道更好的方式,或许能有个好看些的姿势。

感谢一年来遇见的美丽的人们和一直陪伴的朋友们。许多收获,都是缘分,不过顺势而为,保持真实与自由,做自己认为应该的事情,并未太多投入。虽然结局并不都与预期相同,也留下些许烂肠困惑,但想起来终归还是会感到欣喜。这些都让我对未来怀抱信心与期待。

希望来年能够少些杂念与杂事,多一些自己计划中的有趣事情,有一些积累和沉淀。其他一切依旧随缘,如果世上真的有神明,他似乎还蛮喜欢我的嘿嘿。祝你我都能好运。新年愉快 :)

《黑客与画家》摘录

黑客与画家》是我今年看到过的最好的非技术类书籍,没有之一。有机会的情况下我会向每个朋友推荐这本书。其中探讨了一些有趣但一直被忽视了的事情:青少年与所处世界的关系、黑客与其他创作者相似的地方、对于分配不均的再认识、如何保持观点又不惹恼他人、怎样创造出优美可靠的软件等等。

无论你是程序员,创业者,设计师或者对这个世界的运作存在着疑惑,都能够在其中找到答案。

当时一时头脑发热,才看了一半就把它放上了摆摆书架。之后就不断收到有人想要向我借阅的通知,并且目前只有我这么一本可借。现在看完了,发现有点儿舍不得,但是既然都做了这种决定了还是贡献出来吧。

于是我决定对这本书做一些摘录,把其中较为普适,值得与大部分人分享的部分记录分享一下,也希望后续的读者们可以继续进行这个事情,一本书只有被人们反复阅读,其价值才能够得以不断升华。

1.在任何社会等级制度中,那些对自己没信心的人就会通过虐待他们眼中的下等人来突显自己的身份。 … 正是因为这个原因,在美国社会中低层白人是对待黑人最残酷的群体。(p6)

2.一起攻击一个外人,所有人都因此成了自己人。这就是为什么最恶劣的以强凌弱的事件都与团体有关的原因。(p7)

3.我认为,真实世界的关键并非在于它是由成年人组成的,而在于它的庞大规模使得你做的每件事都能产生真正意义上的效果。学校、监狱、上流社会的女士午餐会,都做不到这一点。这些场合的成员都好像关在封闭的泡沫之中,所作所为只对泡沫内部有影响,对外部没有影响。(p9)

4.凭什么说13岁的小孩自己有问题。如果这是激素过多的生理问题,那就应该普遍存在。可是,蒙古的游牧民族在13岁时难道也是这么空虚吗?我读过许多历史资料,找不到任何一条20世纪之前的历史事实支持这个理论上应该普遍存在的现象。(p11)

5.如果存在对于真正能力的外部测试,待在等级关系的底层也不会那么痛苦。球队的新人并不会怨恨老队员的球技,他希望自己也能如此 … 最重要的是,老队员的地位是通过他们本身出色的能力获得的,而不是通过排挤他人获得的。(p14)

6.现行体系中没有什么事是必然的。他是现在这个样子,大部分是因为没人去改变它。(p16)

7.黑客与画家的共同之处,在于他们都是创作者。… 他们本质上都不是在做研究,虽然在创作过程中,他们可能会发现一些新技术。(p18)

8.计算机科学就像一个大杂烩,由于某些历史意外,很多不相干的领域被强行瓶装在一起。这个学科的一端是数学家…中间部分是计算机博物学家…另一端则是黑客,志向写出有趣的软件,对于他们来说,计算机知识一种表达的媒介。(p18)

9.你把整个程序想清楚的时间点,应该是在编写代码的同时,而不是在编写代码之前,这与作家、画家和建筑师的做法完全一样。(p22)

10.一种好的编程语言,应该向油画颜料一样,能够使得我们很从容地改变想法。动态类型语言在这一点上就是赢家,因为你不必提前就设置好各种变量的数据类型。 … 优美的软件也要求对美的狂热追求。如果你查看优秀软件的内部,就会发现那些预料中没有人会看见的部分也是优美的。(p28)

11.事实表明,从他人的角度思考问题正式成功的奥秘所在。 … 了解别人对于事情的看法,并不代表你为他的利益服务。某些情况下,比如打仗的时候,了解对手正是为了打击对手。… 判断一个人是否具备“换位思考”的能力有一个好方法,那就是看他怎样向没有技术背景的人解释技术问题。(p31)

12.(当主流的声音与自己认为正确的意见相背时,如何与对方辩论)一种方法就是逐步把辩论提升到一个抽象的层次 … 公鸡它的“元标签”。 … 另一种反击的方法就是使用隐喻。 … 所有反击方法中,最好的一种可能就是幽默。狂热分子都有一个共同特点:缺乏幽默感。(p49)

13.盗版实际上是一种价格歧视,只不过针对的是最底层的消费者。 … 有些服装品牌的目标客户是“都市青少年”,这些品牌的专卖店对店内偷窃行为就睁一只眼闭一只眼,因为在它们的目标市场中,那些在店内行窃的“顾客”也是流行风尚的带头人,可能会带动本品牌的销售。(p76)

14.真正重要的是做出人们需要的东西,而不是加入某个公司。(p98)

15.波音747飞机驾驶员的收入大概是商场收银员的40倍,但前者不是贵族,后者也不是奴隶,这种收入差距只是因为前者的技能比后者的要值钱得多。… 现代社会的收入差距扩大是一种健康的信号。… 如果不得到报酬,人们是否愿意创造财富?唯一个可能是,工作必须能提供乐趣。(p121)

耍两个css3小trick

介绍两个css3做的小效果。都是在webkit下做着玩的,完全没考虑浏览器兼容什么的。

效果一:摇晃

用过iphone的同学应该知道,当你要调整图标顺序或者删除app的时候,长按之,然后所有图标都会很萌的在那里打颤,并且脑门上会多出来一个小叉让你点。

仔细看了一下,其实这种小颤的效果就是图标在左右小幅度摇摆而已,当中或许还加入了一些很细微的随机位移吧。

好,我现在想把这种效果用到web页面上要怎么弄嘞。

一开始我想到的是css3 transition这个属性。transition,顾名思义就是过渡的意思,语法如下:

transition:prop duration timingfunc delay [reference]

这样就会在某个property改变的时候先delay一段时间,然后从原状态通过timingfunc所代表的缓动方程,经过duration的时间,过渡到目标状态。

我们要用它来完成shake的效果,就需要用setInterval反复的把元素旋转的角度正负来回设,中间状态会由transition来完成。

目的是达到了,但是transition表示压力很大,人家只是个做过渡的,循环动画什么的有点儿hold不住啊。setInterval第一次执行的时候肯定会有停顿,而且元素一多,不断的设置一堆dom元素的属性,肯定会慢得要死的啊笨蛋!

有木有更好的办法嘞?答案是有的。不就是做循环动画咩,有专门干这活儿的家伙。就是我们的css3 animation属性集啦。

写起来就像这样:

.elem{
  1.  -webkit-animation-name: shake;//自己定义的动画名字
  2.  -webkit-animation-duration: .15s;
  3.  -webkit-animation-timing-function: linear;
  4.  -webkit-animation-direction: alternate; //顺着放完后倒带放回来
  5.  -webkit-animation-iteration-count: infinite; //就这样直到永远
  6. }
  7.  
  8. @-webkit-keyframes shake {
  9.  from {-webkit-transform:rotate(-5deg);}
  10.  to {-webkit-transform:rotate(5deg);}
  11. }

效果不错,丝般顺滑。猛击这里看下效果对比。

效果二:翻转

这个效果需要用到的几样东西说明一下。

-webkit-transform: rotateY(180deg);

这个属性之前也有用到。3d旋转有xyz三根轴,x轴从左到右,y轴从上到下,z轴从屏幕里戳出来。rotateX,rotateY,rotateZ可以分别使元素围绕其旋转。上一例中的普通rotate就可以想象成围绕z轴的旋转。此外还有translate,scale等属性可以用来作平移啊缩放啊等事情。[reference]

-webkit-transform-style: preserve-3d

这个属性有两个值,preserve-3d|flat。前者可以使其子元素能够在他的3d空间的基础上应用3d变换。

设为flat的话子元素就都跟他贴在一个平面上了。默认值似乎是前者,所以可以省略。[reference]

-webkit-perspective: 500

定义了元素进行3d变换时的透视程度,可以想象成镜头距离物件的距离,默认是无限远,就是看起来完全没有透视感。火影忍者里的很多打斗就大量运用了夸张的透视效果。

-webkit-backface-visibility: hidden

这个属性也是两个值initial和hidden。前者的话我们的元素就相当于一张塑料薄片,翻转之后上面的内容还是可见的,设置为hidden它就变成了一张卡纸,翻过去就不可见了

最后你可以在源码中发现翻转的hover写在了最外层的元素上,这是因为翻转的时候实际上改变了元素的大小,这样,动画一开始元素缩小了,hover状态就没有了,这显然不是我们希望的,放到一个透明的外层容器上去就没事情喽。

猛击这里看demo吧!

如何设计用户登录

这篇文章是对自己实践的一份总结,未必靠谱,牛人看了觉得有误请别吝惜手中板砖。

第一种:最简陋的方法,直接在用户名密码与数据库中的记录匹配后设置一个session,浏览器一关它就没了,需要重新登录

第二种:将用户名密码存在cookie里,保存一段时间,期间访问网站时就尝试用他们登录。成功后设置session,避免每次重复访问数据库作检查。但是如果有坏朋友来用你的电脑,翻下cookie就能知道你的密码了。

第三种:所以在之前的基础上,我们把密码用md5或者sha1加密一下。每次不是直接匹配用名和密码,而是通过用户名找到密码,再把密码加密一下看是否与你提供的一致。坏朋友又来了,这回他不知道你的密码了,但是他把这对cookie拷回去,又可以冒充你来登录了。

第四种:所以我不但要避免别人得到我登录信息,还要防止别人拿到cookie后可以伪造登录。

于是现在的做法是登录成功后把sessionid,用户id,ip信息,浏览器信息等一起保存在服务器这边。cookie里只保存这个sessionid,以及其他信息一起加密后的字串,相当于一个信物。

登录的时候服务器就可以拿到它保存着的信息,然后获取你正在使用的ip与浏览器信息,用相同的办法加密出来和你手里的结果一比对就知道是不是你了。坏朋友把你的cookie带回家,但是他登录时的ip或浏览器与你使用的不同就不管用。

当然他可以把这些也记下来,回去也一并伪造了,还可以猜测信息连接的顺序,所使用的加密算法等,也就是几十种组合,狗屎运的话还是可以试出来。

那就在加密的时候再加一个只在服务器这边记录的字串,道理上,他就彻底没辙了。这样做就相当于以前我为了开个门一直把钥匙留在身边,大多情况够用了。但别人可以偷过去复制一把。所以我们只保留一个信条,每次要开门的时候出示一下,然后保管员会看一下你的面容啊,指纹啊什么的再去和资料库里比对一下,然后帮你把门开了。

总结:

当然用户登录这种事情其实还要麻烦很多,比如绑定第三方账号啊(说白了就是多配几把能开门的钥匙),多账户切换啊,跨域问题啊等等(这些就不是很明白了,还没亲手接触到),要保证正确的人随便怎样都能简单快速的登录,想干坏事的随便怎样都登录不了,难度还是有点的。

事后试了一下几个主流网站,就在本本上记录个cookie再跑去台式机上设一下,结果大多数时候不鸟你,不过也有少数妖怪情况会成功,不高兴仔细琢磨了,总之不鸟你才是对的。如果本文有说的不到位的地方欢迎补充啊。

Updata 2011-08-29: 写完之后才发现几天前coolshell上有一篇更为详尽,前后端都有涉及的文章,非常不错。点此

总结下Flash和外部的交互

好像是大三下的时候写过一篇利用amfphp和后端程序交互的文章,那不过是篇经验总结而已,个中原理依然不明白,而现在我也越来越不喜欢这种需要依靠第三方工具的笨重方式,只有简洁的东西在能永恒啊。于是这周的空闲时间里不务正业的拿起这块东西又研究了一下。

不同媒介间的通信,最基本的做法,说白了就是互相通过字符串来传递信息。先来看flash和php之间的消息传递,其实和后端通信,说白了就是发http请求过去,拿到运算结果,再做分析处理罢了,ajax是如此,flash也一样, 只是用来发请求的对象略有不同而已,做法如下。

ajax:

  1. var req;
  2. req = new XMLHttpRequest();
  3. req.open('POST','remote.php');
  4. req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  5. req.onreadystatechange = handler;
  6. req.send('say=hey man');
  7.  
  8. function handler() {
  9.  if(this.readyState == 4 && this.status == 200) {
  10.   console.log(this.responseText);
  11.  }
  12. }

flash:

  1. var loader,req,data
  2. var loader,req,data;
  3. loader = new URLLoader(); // flash.net.URLLoader
  4. req = new URLRequest(); // flash.net.URLRequest
  5. data = new URLVariables(); // flash.net.URLVariables;
  6.  
  7. data.say = "hey man";  
  8. req.url = 'remote.php';
  9. req.method = URLRequestMethod.POST; // flash.net.URLRequestMethod  
  10. req.data = data;
  11. loader.addEventListener(Event.COMPLETE,handler);
  12. loader.load(req);
  13.  
  14. function handler(e:Event):void{
  15.  trace(loader.data);//use a certain object to parse it as you like
  16. }

得到的response差不多都是这样的

  1. POST http://spud.in/demo/flash/remote/remote.php HTTP/1.1
  2. Host: spud.in
  3. Connection: keep-alive
  4. Content-Length: 13
  5. Origin: http://spud.in
  6. User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.8 Safari/535.1
  7.  
  8. content-type: application/x-www-form-urlencoded
  9. Accept: */*
  10. Referer: http://spud.in/demo/flash/remote/flash.swf
  11. Accept-Encoding: gzip,deflate,sdch
  12. Accept-Language: zh-CN,zh;q=0.8
  13. Accept-Charset: UTF-8,*;q=0.5
  14.  
  15. say=hey%20man

这部分就这点花头了,这些对象还有更多变的用法,但最基本的就这些了。下面来说下flash和页面上的js之间是如何交互的。

自打Flash 8开始,as中引入了ExternalInterface 这个对象(flash.external.ExternalInterface)。

flash -> js:

ExternalInterface.call(funcionName:String, … arguments):*

可以调用到window对象下的functionName方法。

js -> flash:

ExternalInterface.addCallback(functionName:String, closure:Function):void

这个方法会在flash被载入后,将特定的方法丢到承载他的<object>节点上。

有的聪明的同学就好奇了,js里不同类型的参数是怎么和as中不同类型的参数对上号的嘞?

原来flash被载入后会丢一堆方法到window上。

他们会把js方法名,和参数按特定的方式解析成很长一串xml字符串。再用flashobj.CallFunction(theXmlStr)将其传递给flash。更多细节可以参考tencent flash team的这篇文章

这次调用后,flash中的方法的返回值也按照正确的类型会反应到js中,若flash方法的返回类型为js中没有的复杂类型,则会抛出 “Error calling method on NPObject” 错误。

以上讲的是方法间的互相调用,此外,传递参数这件事情还可以通过flashvars来做,具体见此,不高兴写了嘿嘿。

Demos:

with backend (ajax|flash|source)

with js (demo|source)