大淘宝开放平台 ( TOP ) ,给我们描绘出的是一幅十亿人民九亿商的宏伟画面。只要你想,就可以通过给TOP添砖加瓦来赚玛尼。
第一眼看到TOP的API文档,脑海里闪现的是以后做一个垂直B2C网站门槛会更低了:只要进行一个简单的封装,就可以把任何企业现有ERP的产品实时登录到TOP上,支撑电子商务的整套业务逻辑和数据访问压力都由淘宝来承担。公司目前线上营销部门每天花很多时间去做的人工在淘宝登录发布商品的资源浪费也将不复存在。当然,前提是有一批TOP应用开发的先行者做出优秀的插件来促成良性循环。
再看TOP的盈利模式: 淘宝客佣金 | 插件分成 | 软件销售 | 传统广告。看上去花样繁多,不过相同的本质都是通过增值服务来让卖家付费。在通过免费大旗打倒ebay易趣之后,淘宝看来是打算使用这种相对更自愿的方式来向卖家收费。这种类似跑跑卡丁车的盈利模式在中国应该还是很有市场的。当前,前提依然是有足够多好的插件可以吸引卖家来订购。
很阴暗的猜想一下,淘宝自己现在已经对一些计划中的新功能进行划分了,哪些作为淘宝网的基本功能提供,哪些放到付费插件平台去让卖家掏钱购买(不知道是不是还会包月包年的) -- 然后只要是您想用的功能,统统都是收费滴~~
对于我比较关心的软件销售模式与淘宝的分成关系在于:“当对TOP OpenAPI访问调用超过默认流量限制时,TOP将收取适当费用。在Beta运行期间,只记录流量限制记录,暂不收费。”这个接口使用费用的高低,将直接影响到TOP第三方软件的数量。
不管是 Firefox 、 Twitter 还是 Google Maps ,它们的第三方扩展/应用如此丰富的原因很大程度上都是因为免费。TOP这朵以盈利为指导思想的雨云诚如八戒眼中的棉花糖,好不好吃且看能不能咬到嘴吧~~
近日有位童鞋让我帮忙把某个在线的flash游戏做成单机硬盘版的好在自己的电脑上玩,恰好又有些其它swf文件的反编译需求,于是很不专业的折腾了一番。思路比较混乱,随手记一下。Flash 达人请直接飘过。
现在的flash不像以前都是单个SWF,直接下载下来就完事儿。在AS3里面可以采用Loader / URLLoader / Sound 等来按需加载不同的外部内容数据,减少单次下载的内容大小。通过 Firebug 的网络面板可以很容易知道在交互过程中产生了哪些二次数据请求,当然也就很容易把这些必需的外部文件也同步保存到本地。
但这样保存下来的内容不见得是整个应用所需的全部素材,因为你不见得会在一次访问过程中触发所有的可能性。所以最彻底的方式是反编译保存下来的SWF文件,然后用全局搜索查找出全部的调用内容。
反编译的工具,对我来说 Sothink SWF Decompiler 不错,基本上能很好的还原出fla文件。但这个工具有一个很严重的问题,在反编译还原 AS 类库文件的时候会出现很多错误,比如把某些变量进行了错误的替换,某些注释被错误的赋值给变量,等等(我用的是 v4.4 ,不知道最新的 v5.0 还有没有这个问题)。如果直接用 Flash CS3 / CS4 去打开生成反编译出来的项目的话,很可能会报出一大堆的编译器错误!所以还需要使用另外一个工具 Action Script Viewer 6 ( ASV6 之前的版本并不支持AS3脚本的反编译),用ASV的 "Export Rebuild Data (JSFL)" 功能导出的 rebuild 脚本虽然有时候并不能完整的重建项目,但导出来的 AS 库文件源代码却很完整。
把 ASV 生成的 AS 库文件复制覆盖到 Sothink 生成的项目文件夹,再打开 Sothink 生成的flp项目文件去编译,应该就不会有一堆莫名其妙的编译器错误了 ---- 一开始我太相信 Sothink 的反编译结果,一度很纠结为什么源代码有这么多编译错误还能生成SWF并正常交互,还以为是跟 Flash CS4 版本兼容性问题又去搞了个 CS3。
ASV 网上能找到的好用版本貌似只有到 asv6 alpha4 ,由于不是 relase 版本,在反编译的时候会提示说反编译出来的东西不一定是完整的 ---- 由于这个提示我一度放弃使用 asv6 ,直到后来拿 asv6 反编出来的源代码去和 Sothink 反编出来的做比较才发现原来声明自己并不一定完整的反而是准确可用的。
这两个工具最好都不要找什么绿色汉化版,有后门。如果常规性会有类似反编译需求的童鞋是值得花钱去买一份正版的来用的。
Sothink 生成的flp项目文件是 for Flash CS3 的, CS4 打开flp文件的方法是:选择“窗口”>“其它面板”>“项目”打开“项目”面板;在“项目”面板中,从“项目”弹出菜单中选择“打开项目”;在“浏览文件夹”对话框中,导航到包含 FLP 文件的文件夹,然后单击“确定”,即可。
为了完成反编译修改大业,终于把机器上尘封了N久的Flash8给卸掉,换成了 Flash CS3 。一开始搞了个精简版,结果对 as 源代码进行语法检查就报“JAVA 运行时环境初始化时出现错误,您可能需要重新安装Flash”。原来精简版把 JVM 都给精简了,需要装一个 jre 环境(或者找找机器上是不是已经有 jre 环境目录了),把jre下的内容复制到 Flash 安装目录下的 JVM 文件夹中(没有的话建一个)。
当然最好还是找个原版镜像出来的比较好,否则总会出现各种古怪问题(比如当Flash项目中用到的字体文件在你本地环境中找不到的话,精简版会直接程序崩溃,就为这个我又一度不得不上网去找来项目中用到的微软雅黑字体给装上)。有时候浓缩不一定是精华。
发布项目时出现“5003: 生成字节代码时发生未知错误”。可以尝试的解决方法: 1、 在“文件->发布设置”的“ActionScript 3.0 设置”中不要勾选“减小文件大小并改善性能”(发布设置这个菜单项平时是没有的,必须打开项目的默认fla文件,一度又很纠结为什么在项目面板鼠标右键点击fla文件的时候不出现这个发布设置...); 2、 “控制->删除 ASO 文件”; 3、 增加一个系统环境变量 JAVA_TOOL_OPTIONS ,变量值设置为 -Xmx512M (注意 512 这个数字需要根据情况调整,不同的电脑配置可设置的数值不一样,可以从 1024 开始往小里改。我的本本要改到 400 才行,大于 400 的数字会又一次导致'JAVA 运行时环境初始化出现错误';修改了环境变量之后可以开一个命令行窗口输入命令 SET JAVA_TOOL_OPTIONS=ANYTHING 让新的环境变量立即生效,重新打开 Flash CS 程序即可)。
当去掉了发布设置选项中的"省略 trace 动作"勾选框之后,测试项目时会输出"VerifyError: Error #1030: 堆栈深度不对称"的错误,没搞清为什么,只好把这个选项再勾上。
URLLoader 加载本地文件,相对路径如果写成 "./data/......" 的话,测试项目没问题,生成项目之后用某些支持SWF的播放器也没问题,但用 Flash Player 运行生成出来的SWF时会抛出类似"Error #2044: 未处理的 ioError:。 text=Error #2032: 流错误" 的 ioError ,需要把 "./" 去掉,直接写 "data/......" 这样的相对路径才能正常读取到相对目录下的内容。
折腾完毕,一个字:累。或许是早期版本Flash IDE对as脚本编写支持的超级弱让我对 Flash 一直很排斥,即便到现在还是如此。也许 HTML 5 真的可以让人抱有期待。本来嘛,都是基于浏览器的东西为什么不做成内置标准以最简单的方式来提供给开发者?
为研究 Firefox 扩展开发整的 Zeal.ChinaStock 从去年5月份开始提请审查,到今天将近一年的时间,终于得见天日不用再待在沙盒里面接收测试了。自贺一下。
历次被打回的理由如下:
1. Your add-on must have some reviews either on AMO or elsewhere on the web. See http://shawnwilsher.com/
第一次的提请审核时间最久,在我都已经快忘了这回事的时候 AMO 回了这么一封信。看来必须是在沙盒里面待到有一定的回复评论数量才行。
2. In order to prevent conflicts with other addons that may be installed by users, you need to wrap your 'loose' variables and functions within a JavaScript object. You can see an example of how to do this @ http://blogger.ziesemer.com/
第二次告诉我代码里面有用到全局变量,容易跟其他扩展的代码发生冲突。看了看其它公布在AMO网站上的附件组件,有不少也是存在大量全局变量的,估计要么是提交的早审核没这么严格,要么是影响力大AMO给开后门了。只好用Firebug查看所有的全局变量,把它们都封装到自己的命名空间对象下面。 AMO 提供的 how-to 链接是被墙的,需要翻墙阅读。
3. You're evaluating remote code, which may be a serious security risk. Please use https://developer.mozilla.org/
原来代码里面使用了 eval 来执行远程抓取到的内容。去掉了对 eval 的使用之后再提交,没过多久就收到 Congratulations 邮件了。
Updated 2009-04-02 11:50 -- 更新了一次版本,差不多等了一个多星期之后 Mozilla 完成版本review予以发布。有意思的是他们居然同时还在 Minefield 上进行了测试,并建议我 increase max compatible version from the developer control pane (no need to resubmit with an altered install.rdf) 。这直接促使我下载了还在开发中的 latest nightly build 进行测试。Mozilla 的测试人员确实是认真负责加勤奋,赞一个。
在 Firefox 自定义附加组件中扩展状态栏 statusbar 的内容一般通过在附件组件的 XUL 定义文件中添加 statusbarpanel 元素来实现。
每个 statusbarpanel 都可以定义不同的 CSS 样式。比如对于 <statusbarpanel id="zealiTestExt-panel" label="test label"/> ,可以用常规的方式来修改样式:
var pTargetEle = document.getElementById('zealiTestExt-panel');
with(pTargetEle.style){
fontWeight = 'bold';
color = '#f00';
}
但如果想修改 statusbarpanel 的背景,直接这样写你会发现没有起任何效果:
... backgroundColor = '#0f0';
原因是 Firefox 对状态栏的元素应用了基于操作系统的样式,或者当前使用的主题样式定义覆盖了用户自定义组件的样式。解决方法是加入 mozilla 的扩展CSS样式 -moz-appearance 以及 !important 声明:
...
pTargetEle.setAttribute('style','-moz-appearance: none !important; background-image: none !important;background-color: #0f0 !important;');
将 -moz-appearance 设置为 none 并加上 !important 强制 Firefox 不对该状态栏区域应用缺省系统样式;同时强制清除当前背景图片的样式并设定新的背景颜色。
Google 的工程师 Ben Lisbakken 利用他的 20% 时间捣鼓出一个展示 Google 所提供的各种 JavaScript API 功能的界面。开发人员通过这个界面可以迅速检索这些 API 的常用功能,然后对这些示例代码进行在线修改即时查看执行结果。
![]() |
- Visualization
- Search
- Language
- Blogger Data
- Libraries
- Maps
- Google Earth
- Feeds
- Calendar Data
其中 Libraries API 就是常用 JavaScript 库的 CDN 。对于安全性没有特别要求的中小型网站来说,使用 Google 集中提供的js库(比如jquery)可以减少一次自己服务器的http连接,同时使用 Google CDN 的人越多,这些库文件在浏览器缓存里面存在的可能性就越大,访问速度也就越快。如果 Google 能够永远“不作恶”,永远不倒闭,那么使用他的 Libraries API 绝对比在自己的服务器上放一份拷贝要好。
有趣的是虽然 Google 官方建议通过引用 <script src="http://www.google.com/jsapi"></script> 之后调用 google.load("jquery", "1"); 的方法来最高效的使用这些 Libraries API ,但就连这个 Googles AJAX APIs Playground 也是直接用 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript" charset="utf-8"></script> 这样的方式来调用 CDN 中的 js 代码库的。
两种方法要我选肯定也是选直接引用的,反正官方文档里面明确说明两种方法都可以,并且有给出每个库对应的引用URL,没必要多那么一举嘛。
前些日子一篇N久之前的老文忽然成了被阅读的热点,检查之后才发现自己使用那段代码来做pr查询的页面已经不能正常得到URL的Page Rank值了,取而代之的是一大段“In your email, please send us the entire code displayed below”之类的Google terms_of_service错误提示信息。看来是原先的接口已经失效了。
但我装在Firefox工具栏的扩展插件SearchStatus仍然能够正常解析出每个受访页的PR值,找到 SearchStatus 的插件包解开来看源码,果然是使用了不一样的验证码生成算法,在原先的 checksum 生成之后,还需要再进行一次计算,两次演算之后得到的才是正确的ch参数。
于是拿现成的js代码改造一番之后,新的PHP版本的 Google PageRank 查询接口方法就出来了。经过本地测试之后,谁想传到服务器之后又出现了该死的 terms_of_service 错误提示。把checksum的计算过程一步步打出来,发现经过了几次右位移之后本地和服务器上的数字就不一样了。这才想到服务器是64位机,32位系统下位移之后应该被cut掉的bit在那里就活得好好的。加了个 trunkbitForce32bit 方法,对所有算术运算之后的数值进行高位屏蔽,算是搞定了64位系统下的多余位问题。结果拿到32位Linux环境下跑又不兼容了,原因是PHP在进行算术处理出现溢出时,会自动尝试将int转为float。当发生的是负数溢出时,这一操作在Windows下能正确保留精度,但在Linux下就有问题了。
下面这段代码:
$a = -4294967295;
echo dechex($a)."<br />\n";
if ( $a < 0 ) $a += 4294967296;
echo dechex($a)."<br />\n";
第一个echo在Windows下能够正确输出该负数低32位的补码,而在32位Linux机上输出的则是int类型所能表示的最大负数0x80000000了。只有通过取巧的方式给这个溢出的大负数加上一个超出整数范围的大整数来抵消掉溢出的部分,才能复原低32位应该有的样子。
使用这些非常规手段,终于炮制出这个更新版的兼容Linux32/Linux64/Windows的Google PR值查询接口的PHP脚本实现(含完整代码)。
参考:
php异或运算的不可靠性
PHP vs. BIGINT vs. float conversion caveat
http://www.teamworksusa.com/RDS275/HydroWorks275/keygen.php
Reverse Geocoding ,也就是反向地理编码(逆地理编码),可以根据地图上某一点的经纬度值来查询该点附近的地理信息。比如要实现捕获用户鼠标事件判断用户点的是哪国哪省哪市哪条街道,就需要有相应的 reverse geocoding 服务支撑。
在当前版本的 Google Maps API 中对这项功能提供了有限支持。对于开放了 Geocoding (GClientGeocoder) 和 Driving Directions (GDirections) 接口的国家和地区,Nico Goeminne 写了个 GReverseGeocoder 类来完成反向地理编码解析(Google Pages 貌似这几天被 GFW 掉了,访问不到 Nico Goeminne 站点的朋友可以看我本地的镜像链接)。可惜的是目前谷歌中国的ditu.google.com还没有提供GDirections接口,不知道后续的版本会不会放出。下面是 Nico Goeminne 列出的 GReverseGeocoder 当前的国家支持情况(x=支持, n=不支持, p=理论上支持但未经过测试):
| Country | GClientGeocoder | GDirections | GReverseGeocoder |
|---|---|---|---|
| Austria | x | x | p |
| Australia | x | x | p |
| Belgium | x | x | x |
| Brazil | x | x | x |
| Canada | x | x | p |
| The Czech Republic | x | x | p |
| Denmark | x | x | p |
| Finland | x | x | p |
| France | x | x | x |
| Germany | x | x | x |
| Hong Kong | x | n | n |
| Hungary | x | x | p |
| India | x | n | n |
| Ireland | x | x | p |
| Italy | x | x | x |
| Japan | x | n | n |
| Luxembourg | x | x | x |
| The Netherlands | x | x | x |
| New Zealand | x | x | x |
| Norway | x | x | p |
| Poland | x | x | p |
| Portugal | x | x | p |
| Singapore | x | x | p |
| Spain | x | x | p |
| Sweden | x | x | p |
| Switzerland | x | x | x |
| Taiwan | x | n | n |
| Thailand | x | x | p |
| the United Kingdom | x | x | x |
| the United States | x | x | x |
实际上,在 Google Maps API 官方文档里面 GClientGeocoder 接口的 getLocations(address, callback) 方法里面虽然没有明确说明,却可以传递用逗号或空格分隔的经纬度值进去作为address参数,也能达到反向地理编码解析的目地。只是目前这样调用返回的Placemark对象精度只能到国家级别,并没有更进一步的所在地信息,还没有太多的实际价值。
一些非 Google Maps 提供的 geocoding / reverse geocoding 服务链接: http://groups.google.com/group/Google-Maps-API/web/resources-non-google-geocoders ,基本上可查询范围都是欧美国家,有偿服务居多。
中国区域的 reverse geocoding 服务方面, MapABC的搜索API中倒是有 reverseGeoCoding(msearchpointpara) 接口方法,美中不足的是其flash版本的地图跨浏览器兼容性又不是太好还有滚动广告条,文档的组织也够凌乱,所使用的经纬度坐标又不是标准的数字形式,极大的影响了使用体验;51ditu 的位置描述接口则直接作为收费接口有偿提供。看来想使用免费又称心的 reverse geocoding 还得耐心等谷歌地图开放相应的功能了。
看到有人说用了Safari之后"已经开始不愿意去用firefox了",忍不住也试用了一把,顺便看看最近几个应用在Safari下的兼容性。一打开浏览界面,果然很有苹果的酷炫风格,相当养眼。
然后就发现Safari的XMLHTTPRequest并没有如其他主流浏览器一样缺省使用utf-8编码来处理内容,必须在服务器端强制设定页面编码才不至于在Ajax处理中文时出现乱码(比如在脚本里面 header("Content-Type:text/html;charset=utf-8"); 或者在Apache的conf里面加上 AddDefaultCharset UTF-8 ,如果不幸服务器端的php.ini里面设置了不恰当的default_charset的话还必须在所有相关的php文件开头加上ini_set('default_charset','UTF-8'); 才行),也算相当有性格。
至于号称的 fastest browser in the world,没怎么感觉出来。IE6当然是没啥好比的;相较Firefox而言,去使用 Gmail 和自己的几个应用项目,速度上最多也就半斤八两各有快慢。或许因为是Mac移植版的缘故?没用过Mac版的,不得而知。
很常见的一个图片轮播Flash,使用之后发现在IE下按F5刷新之后Flash区域就变成一大块背景色,内容轮播出不来了。有趣的是右键点击Flash选择"关于Adobe Flash Player 9 ..."打开 Adobe 的官网之后再按F5刷新,内容又可以正常显示了。
一点点去掉代码发现是 <param name="scale" value="exactfit"> 这个参数作怪。在 Flash 的脚本里面强制指定了 Stage.scaleMode = "noScale"; 而我的 Flash 代码生成 js 里面缺省把 scale 设成了exactfit 。 似乎这两者之间发生了某些冲突,导致IE下出现这种奇怪的刷新之后就白屏的现象。Firefox下倒是没问题。把参数改成 <param name="scale" value="noScale"> 之后恢复正常。
本来拿 PHP Standalone OpenID Server 的代码改装出来的 Zeal OpenID Server 纯属好玩,最近发现对 OpenID 感兴趣的朋友日渐增多,发信留言询问相关的东西。所以干脆把整个汉化修改之后的 Zeal OpenID Server 整站源码打了个包,喜欢研究的朋友自己 down 一个下来瞧瞧吧。
如果使用过程中有什么问题,最好自己去搞定,俺不负责技术解答,嘿嘿 :)
gz 压缩包:
openid.zeali.net.tar.gz zip 压缩包:
openid.zeali.net.zip
Just Copy the whole folder to your server .
create a database ,
import tables information of file zeal_openid_server.sql
change config.php to fit your requirements.
default settings in config.php:
administrator user : admin
administrator pass : 123456
db host : localhost
db name : zeal_openid_server
db user : openuser
db pass : 123456
照例,每次的版本更新都会大幅提升 selector 的速度。不过这次的版本更新作为 1.1.x 的最后一个版本,为了给九月份的 1.2 版做铺垫,去掉了一些老版本中的方法。因此在使用之前最好确认一下原有代码的兼容性。
比如在 Validation 插件的 showLabel 方法中,作者采用 label = jQuery("<" + this.settings.errorElement + ">") 的方式来新建一个 dom 对象,在 1.1.4 中必须改为 label = jQuery("<" + this.settings.errorElement + "></" + this.settings.errorElement + ">") 才能被正常创建。否则在进行form输入字段验证的时候在IE下永远不会看到任何的提示信息显示出来。
具体 1.1.4 中 Deprecated 掉的内容包括:
- $("div//p") , $("div/p") , $("p/../div") , $("div[p]") , $("a[@href]") 这几种 selector 写法
- 带参数的 $("div").clone(false) 方法 ( 改而使用 .clone().empty() )
- $("div").eq() , $("div").lt() , $("div").gt() 均由新增加的 slice 方法来实现等价功能
- $("#elem").loadIfModified("some.php") , $.getIfModified("some.php") 均由调用底层的 $.ajax 方法来实现等价功能
- $.ajaxTimeout(3000) 需要改而使用 $.ajaxSetup({timeout: 3000}) 来实现
- $(…).evalScripts()
- 内存泄漏。像 Circular References / Closures / Cross-Page Leaks / Pseudo-Leaks 这些引起 IE 内存泄漏的因素已经被无数人分析讨论过(1 , 2)。据说 IE7 以及 IE6 的某个更新补丁能够解决 memory leak 的问题,但事实上即便在 IE7 下面还是一不小心就让你的脚本吃光内存。比如创建 DOM 对象的时候在加入节点之前就把事件处理函数绑定到该 DOM 对象,或者把 DOM 对象从节点中移除之后再进行事件的解绑。
- 以 DOM 方式频繁对 table 的整行(TR)进行 remove 和 append 。尤其是如果在 table 中使用了多个 tbody 并对这些 tbody 进行 remove / append 操作的话, IE 会直接出现非法操作框而退出。这个问题 IE7 倒表现良好,算是有点进步。
- 不同的事件/函数同时操作DOM的对象。由于 javascript 本身不提供同步机制(当然也不是完全没有办法),所以在 Ajax 这样的异步模式下容易产生对象操作冲突。
当在 window 的 resize 事件中包含某些页面内容处理或计算导致 resize 事件再次被触发的时候, IE 会随机陷入假死状态,而 Firefox 则能够很好的处理。要防止这样的假死,比较简单的处理方法是通过 setTimeout 延迟处理。以 jQuery 的时间绑定语法为例:
function dealWithSth() {
alert("resize event trigger");
};
var pResizeTimer = null;
$(window).bind(
'resize',
function() {
if(pResizeTimer) clearTimeout(pResizeTimer);
pResizeTimer= setTimeout(dealWithSth, 50);
}
);
ajaxError( callback ) 中关于 callback 函数的传入参数,并不像官方文档说明的那样依次是XMLHttpRequest / settings / exception object 。实际上在这三个参数之前的第一个参数是指向 callback 本身的一个引用对象,从第二个参数开始才是文档中所描述的参数。其它几个 ajaxComplete / ajaxSend / ajaxSuccess 估计也类似。
使用了 ifModified 参数之后(也就是在发送 http request 的时候添加 If-Modified-Since HEADER),在 IE6 下刷新页面经常出现 IE 崩溃退出, IE7 / Firefox 下则正常。怀疑是跟浏览器的一些外部加载项有关。
对于 flash 内容,如果设定宽度/高度为0, Firefox 不会真正载入这个 flash , IE 则似乎照常处理。
通常利用 apache 的 mod_rewrite 对 URL 进行重写的时候, rewrite 规则会写在 .htaccess 文件里。但要使 apache 能够正常的读取 .htaccess 文件的内容,需要对 .htaccess 所在目录进行配置。从安全性考虑,根目录一般都配置成不允许任何 Override ,即
<Directory />
AllowOverride None
</Directory>
在 AllowOverride 设置为 None 时, .htaccess 文件将被完全忽略。当此指令设置为 All 时,所有具有 ".htaccess" 作用域的指令都允许出现在 .htaccess 文件中。
AllowOverride 可用的指令如下:
- AuthConfig
- 允许使用与认证授权相关的指令(AuthDBMGroupFile, AuthDBMUserFile, AuthGroupFile, AuthName, AuthType, AuthUserFile, Require, 等)。
- FileInfo
- 允许使用控制文档类型的指令(DefaultType, ErrorDocument, ForceType, LanguagePriority, SetHandler, SetInputFilter, SetOutputFilter,
mod_mime中的 Add* 和 Remove* 指令等等)、控制文档元数据的指令(Header, RequestHeader, SetEnvIf, SetEnvIfNoCase, BrowserMatch, CookieExpires, CookieDomain, CookieStyle, CookieTracking, CookieName)、mod_rewrite中的指令(RewriteEngine, RewriteOptions, RewriteBase, RewriteCond, RewriteRule)和mod_actions中的Action指令。 - Indexes
- 允许使用控制目录索引的指令(AddDescription, AddIcon, AddIconByEncoding, AddIconByType, DefaultIcon, DirectoryIndex, FancyIndexing, HeaderName, IndexIgnore, IndexOptions, ReadmeName, 等)。
- Limit
- 允许使用控制主机访问的指令(Allow, Deny, Order)。
- Options[=Option,...]
- 允许使用控制指定目录功能的指令(Options和XBitHack)。可以在等号后面附加一个逗号分隔的(无空格的)Options选项列表,用来控制允许Options指令使用哪些选项。
所以对于 URL rewrite 来说,至少需要把目录设置为
<Directory /myblogroot/>
AllowOverride FileInfo
</Directory>
IE6下默认的字体尺寸大致在 12 - 14px 之间,当你试图定义一个高度小于这个默认值的 div 的时候, IE 会固执的认为这个层的高度不应该小于字体的行高。所以即使你用 height: 6px; 来定义了一个 div 的高度,实际在 IE 下显示的仍然是一个 12 px 左右高度的层。
要解决这个问题,可以强制定义该 div 的字体尺寸,或者定义 overflow 属性来限制 div 高度的自动调整。比如 <div style="height: 6px; font: 0px Arial;"></div> 或者 <div style="height: 6px; overflow: hidden;"></div> 都可以阻止 IE 的自作聪明。
该问题在 IE7 / Firefox /Opera 下均不存在。
不知道什么时候开始每次进入 Google Reader 的 Manage subscriptions 界面之后,无论点选哪一个 Tab 链接页面都会一闪之后自动跳回 Reader 的主页去。但我明明那时候是通过这里的 Import/Export 把 feeds 导进去的,结果现在想在到这里把 feeds 导出来做备份就死活进不去了。
原先我以为是 Google 的开发人员在对这些功能进行修改,暂时作了跳转屏蔽。反正 feeds 放在这里应该也不会出什么大问题,便没太在意。
但今天看到说SPA开始提供多国语言界面就想去试下。结果到了 snap 的定制页面 想选择 Bubble Language 为简体中文的时候,发现一点国旗页面就自动跳转掉了;状况跟 GReader 如出一辙。
查看了两者的源代码,都是使用了类似 <a href="" onclick="{return confirm('Clicked');}">Click Test</a> 的写法。正常来说当点击这样的 URL 链接后, onclick 先被触发,如果触发的处理脚本最终返回 true 的话, href 中的内容会被浏览器打开;如果返回 false 的话,不进行后续处理。
这才想起我前阵子做测试已经把浏览器升级到 IE7 了;赶紧跑到 IE6 和 Firefox 下试了一把,果然 GReader 和 Snap 都恢复了正常反应。
看来 IE7 不论 onclick 的返回是 true 还是 false ,对于 href 的内容是照处理不误( 1 , 2 )。如果不希望 href 坏了 onclick 的好事的话,最保险还是在 href 里面加上 javascript:void(0) 为好。
Snap Preview Anywhere™ 预览服务和最初相比,已经相继增加了不少个性化的界面定制功能。今天又从 dimlau 的日志上看到 SPA 已经推出了包括中文简体在内的9种语言界面。试用了一下,感觉中文界面看上去总是没有英文那样舒服。另外现在还提供了两个尺寸的预览窗口选择,觉得原来的预览图太小的话可以选择 large 模式。 进行这两项设置,只需要在原来的代码参数后面增加 &size=large&lang=zh-cn 这两个参数即可。
对于 block-level 的页面元素(比如 DIV )来说,要让他相对于父级元素居中显示的话,标准的做法是为该元素定义的样式中包含 margin: auto; 属性。虽然在 IE 下我们使用 text-align: center; 就可得到居中的效果,但如果要考虑到不同浏览器之间的兼容,还是使用标准的方式比较好( text-align 理论上应该只是用来指定 block-level 元素里面所包含的每一行 inline-level 元素 -- 比如 SPAN -- 的对齐方式)。
For block-level elements with horizontal flow in a containing block also with horizontal flow, the computed values of the 'width' and margins must satisfy this constraint:
(width of containing block) =
margin-left + border-left + padding-left + width + padding-right + border-right + margin-right
The following cases can occur:
- None of width, margin-left and margin-right are specified as 'auto' and the values satisfy the constraint.
- None of width, margin-left or margin-right was specified as 'auto' and the equation is not satisfied. There are two sub-cases: (1) if the 'direction' of the element is 'ltr', the specified value of 'margin-right' is ignored and 'margin-right' is set to the value that makes the equation true; (2) if 'direction' is 'rtl', it is 'margin-left' that is ignored and computed from the equation.
- If exactly one of width, margin-left or margin-right is 'auto', its value is computed from the equation.
- If width and one or both margins are 'auto', the margins that are 'auto' are set to 0 and the equation is solved for width.
- If both margin-left and margin-right are 'auto', the equation is solved under the extra constraint that margin-left = margin-right.
If, after solving the equation, width has a value that is smaller than 'min-width', the computed value of 'width' is set to the computed value of 'min-width' and the constraint is evaluated again as if width had been specified with this value.
If, after solving the equation, width has a value that is larger than both 'max-width' and 'min-width', the computed value of 'width' is set to the larger of 'max-width' and 'min-width' and the constraint is evaluated again as if 'width' had been specified with this value.
Note: case 5 can be used to center block-level elements:
BLOCKQUOTE {
width: 30em;
margin-left: auto;
margin-right: auto }
This is different from 'text-align: center', which centers each line inside the block, but not the block inside its parent.
Block-level elements with a vertical flow inside a containing block with a vertical flow are analogous, but with a constraint on height and margin-top/margin-bottom:
(height of containing block) =
margin-top + border-top + padding-top + height + padding-bottom + border-bottom + margin-bottom
- 10 confusions with their solutions before you start using CakePHP
- "X" Things, to Understand about Ruby on Rails
- Cake PHP useful tips: 21 Things You Must Know About CakePHP
- How to Bridge PHP and Java for Powerful Web Solutions
- 累了吗?来BSOD一下吧!
著名的Windows系统蓝屏。这也能拿来当屏幕保护。。。 - MP3 Player Steals £200,000 From Cash Machines
ATM看上去是越来越脆弱了。
- Censored Data via Amnesty International API
The Amnesty International API provides access to their database of content and sites that have been censored by both governments and corporations.
从 OpenNet Initiative (ONI) 提供的这张 Flash地图 可以看到相当直观的全球互联网信息审查的区域性强度对比。在 GFW 的巨大贡献下,最最红色的地域归属自然是毫无悬念;即便是在这么小的一张缩略图上,那一大块深红还是如此的醒目。
John Musser 说 : "There is more censorship occurring online than you may be aware of." 但对我们来说 , Censorship is everywhere. - The Habits of Highly Effective Web 2.0 Sites
- 網頁瀏覽加速法 (原文 Optimizing Page Load Time)
“使用者端可以做的就是打開 HTTP pipelining,Firefox 使用者只要在 URL 列打 about:config 然後找出 network.http.pipelining,改成 true 即可。而在伺服器端,也有些有趣的設定可以做”。 - EGOPOLY: Things that bother me about Ruby
- [JS]遭遇IE内存泄露
引起IE内存泄露的主要情况为js对象实例跟dom对象的相互引用、“内部函数引用(Closures)”以及DOM插入顺序泄漏。 - Memcache的分布式应用
- 是时候了,前端架构师 (原文 The Time is Now for Front-End Architects
“当后端技术伴随.Net, Rails和Java之类的框架发展得越来越抽象和强大,前端技术的潜在发展也日益复杂。在束缚前端技术潜在好处的差劲实现之前, Web需要更多的前端架构师。” - 电脑桌前的姿势要点
- 交通习惯
这位老外说:“我父母虽然对这样的交通不习惯,但是他们也没有说不好,以至说很佩服中国的司机能在注意四方的多种事物的同时安全地驾驶。”
当自己开始真正每天开着车子穿梭于城市之后,才发现马路上那些骑着脚踏车助动车或者迈着两条腿在机动车道上晃悠的人是多么的不珍惜自己的生命。从飞驰的汽车驾驶座上看出去,他们就像随时都会被忽略掉的一张张树叶。 - 关于心理暗示
- 《越狱》被指剽窃一对兄弟亲身经历 - I eric
- PES6出现!
下载源码包 make && make install 之后, apache 并不会自动往 init.d 里面添加自己的 httpd service。需要手工把 apache 安装目录的 bin/apachectl 拷贝一份到 /etc/init.d/httpd 。如果想让 httpd service 能够在不同的运行级别下都能自动启动,还需要 vi /etc/init.d/httpd ,在 #!/bin/sh 下面增加几行 chkconfig 需要的内容:
# chkconfig: 2345 70 30
# description: Apache is a World Wide Web server. It is used to serve \
# HTML files and CGI.
# processname: httpd
关键是 chkconfig: 2345 70 30 这一行,第一个数字 2345 表示让 apache 在 2345 这四个级别都自动运行;第二个数字 70 表示进程启动的优先级;第三个数字 30 表示进程停止的优先级。修改保存之后执行 /sbin/chkconfig httpd reset ,chkconfig 就自动在各个级别的 rc*.d 中增加 httpd 的 link 。要查看 chkconfig 是否 reset 正确,通过命令 /sbin/chkconfig --list httpd 就可以查看当前 httpd service 被配置在哪几个运行级别自启动。
之前总结了下如何用 css 来实现 table 的 border + bordercolordark + bordercolorlight 的边框明暗效果,然后有网友问我为什么他写了一个类似的 css 样式,但只能在 Opera 下正常看到表格的边框效果, IE 下则什么也没有。
于是我跑去下了个 Opera9 一看,确实如此。原因倒也不复杂:因为在 IE 下( Firefox 似乎和 IE 一致)如果某个 td 的内容为空的话,即便你设置了高度和宽度,这个 cell 的边框样式也是不会被显示出来的; Opera 则不管是否有内容与否,一概应用样式来渲染。这个问题刚毕业那会就碰到了,当时部门的科长来问我,后来我跟他说:给每个空的 td 加上 就行了。以后每次碰到这个问题,我就统统采用这个简单粗暴有效的方式来解决了。
但今天卯足了劲研究了几下,从 Jiarry 那知道原来 css 语法是允许我们对这些缺省行为进行改变的:使用 border-collapse:collapse; 和 empty-cells:show; 就可以让消失的边框显现出来。
class="test1": 加 border-collapse:collapse;
.test1{
border:1px solid #999999;
border-collapse:collapse;
width:60%
}
.test1 td{
border-bottom:1px solid #999999;
height:28px;
padding-left:6px;
}| class1 | 这儿有内容 | |||
| 这儿有内容 |
class="test2": 加 border-collapse:collapse; 和 empty-cells:show;
.test2{
border:1px solid black;
border-collapse:collapse;
width:60%
}
.test2 td{
border-bottom:1px solid black;
height:28px;
padding-left:6px;
empty-cells:show;
}| class2 | 这儿有内容 | |||
| 这儿有内容 |
class="test3": 不加 border-collapse:collapse; 和 empty-cells:show; 的情况下
.test3{
border:1px solid #999999;
width:60%
}
.test3 td{
border-bottom:1px solid #999999;
height:28px;
padding-left:6px;
}| class3 | 这儿有内容 | |||
| 这儿有内容 |
RewriteEngine On
RewriteRule ^entry/([0-9]+)$ blog/entry.php?id=$1&avoidrepeat=1 [L]
RewriteCond %{QUERY_STRING} ^id=([^&]+)$
RewriteRule ^blog/entry\.php$ /entry/%1? [R=301,N]
由于一开始的时候主机并不支持 mod_rewrite ,所以日志的 url 都是带 ? 参数的动态 url 。这次决定把该 SEO 的都给 SEO 起来,于是在根目录下加了这个 .htaccess 文件。
但想要让原来已经被 Search Engine 收录的动态 url 自动转到新的静态化的 url 上来却颇费功夫。本来以为直接加一条 R=301 的 RewriteRule 就行了,可实际上 RewriteEngine 对于 rewrite 之后的最终url与初始url完全一样的逻辑会直接给 Ignore 掉,所以必须加上一个无意义的 &avoidrepeat=1 参数来让 RewriteEngine 认为这是两个不同的请求。另外对于 ? 后面的参数字符串必须在 RewriteCond 里面来匹配而不是直接在 RewriteRule 匹配。
经过这样的处理之后,无论是通过老式的 entry.php?id=XXX 方式还是经过静态化的 /entry/XXX 方式来访问,最终都会定位到 /entry/XXX 这个静态化的 url 上,对于 Search Engine 来说应该可以更快的根据 R=301 的状态码来更新它的索引库。
现象:在 VirtualHost 配置块中启用 RewriteEngine ,进行 url rewrite ,结果发现重写到某一个目录下的url总是报错,说是 url 不存在。但通过实际的动态url去访问一切正常。
httpd-vhost.cnf相关配置如下:
<VirtualHost *:80>
ServerAdmin noname@gmail.com
DocumentRoot /www/html/scripts
ServerName scripts.zeali.net
ErrorLog /logs/scripts.zeali.net-error_log
CustomLog /logs/scripts.zeali.net-access_log common
<IfModule rewrite_module>
RewriteEngine On
RewriteRule /entry/([0-9]+)\.html /live/entry.php?id=$1
</IfModule>
</VirtualHost>
反复测试,发现如果把 /www/html/scripts 下的 live 目录重命名成其他的名字, url rewrite 就完全正常。难道说 live 是 mod_rewrite 的关键字?不太可能。继续检查,发现在操作系统的根目录下存在一个同名的 live 目录。把这个目录删除之后, rewrite 恢复正常。
结论: mod_rewrite 在执行 RewriteRule 的时候首先寻找的是操作系统的目录层次,而不是 DocumentRoot 下的相对目录层次;因此如果不幸在 DocumentRoot 目录下存在与操作系统根目录下一样的目录, mod_rewrite 将不会正确的找到 rewrite 的目标 url 。Updated 2006-07-18 14:40 -- 如果使用 .htaccess 文件设置 RewriteRule 的话,因为使用的是相对目录形式,就不会存在这个问题。
目前暂时找不到明确的文档来印证这个问题,或者说我对 mod_rewrite 的理解太浅。希望能看到更准确的说法来诠释这个现象。在此之前,只能认为这是 mod_rewrite 设计上的问题,注意不要让需要加入 RewriteRule 的文档地址与操作系统的目录结构发生冲突。
- EasyEclipse
Eclipse之所以势头如此强劲,甚至于搞到 Borland 都心灰意冷宣布出售整个 IDE 产品线 (虽然没有明显证据可以表明两者之间的因果关系),其开放性大概占了主导因素。
抛开开源免费的特性不谈,作为一个 SDK 而不是单纯的 IDE 面目出现,使得 Eclipse 具有了强大的生命力。只要是跟开发相关的功能需求,都可以作为扩展插件集成到这个统一的平台中去,最大限度的吸引了使用各种不同语言开发者的注意力( Firefox 打的也正是这一手牌)。
但在带来无比自由的同时,往往也会让初用者感到迷茫。如果你不知道该为你的 Eclipse 配些什么兵器的话,不妨到 EasyEclipse 逛逛。 - Google Answers: Understanding ulimit output
Pivot 自带的 wysiwyg 编辑器功能比较少,扩展起来也不方便,虽然 1.3 版本引入了 TinyMCE ,但都不合自己的习惯。好在可供选择的 wysiwyg 在线编辑器多得数不过来, Genii Software 甚至专门对这些编辑器做了详细对比。最终 我选择了 "excellent and easy to use" 的 Xinha 。不过再好的东西也会有 bug (尽管有时候 javascript 的脚本所谓 bug 往往是拜浏览标准的混乱所赐)。
最近发现用 Xinha 切换到 HTML Source 模式添加了图片 Map 区域之后( <AREA title="点击查看大图" shape="RECT" target="_blank" coords="0,0,81,150" href="http://www.zeali.net/images/lina/lina1.jpg"> ),切换回 wysiwyg 模式再切回来,AREA Tag 的 shape 和 coords 属性就消失了。一路跟踪下来,发现 Xinha 在 Toggle HTML Source 的过程中,使用了 HTMLArea.getHTMLWrapper 方法对整个内容进行了格式化处理,这其中用到了 attribute.specified 属性进行判断:
if (!a.specified && !(root.tagName.toLowerCase().match(/input|option/) && a.nodeName == 'value')) {
continue;
}
而让人想不通的是,对于 shape 和 coords 这两个属性来说,无论是否在 HTML 里面进行了设置, specified 的值都是 false ,而不是像 msdn 文档里面所描述的那样 “An attribute is specified if it is set through HTML or script”,只有像 title , target, href 这种比较常规的属性才能通过 specified 的值来判断是否已经做了设置。也正因为如此, Xinha 在对 HTML 代码进行重新格式化的时候, shape 和 coords 这两个属性的相关内容就被直接 continue 给忽略掉了。
有意思的是从 Xinha 上面的那段代码来看,已经对 input 和 option 这两个 Tag 的 value 属性进行了排除,可见 value 属性遭受的“不公平”待遇类似于 shape 和 coords 。可惜 Xinha 好事没做到底,msdn 貌似也没有明确的指出哪些 Tag 的哪些属性无法通过 specified 的值来判断存在与否,所以也只能是发现一例例外就在原来的语句基础上增加一个过滤语句了:
... &&
!(root.tagName.toLowerCase() == 'area' && a.nodeName.toLowerCase().match(/shape|coords/))
搞定,收工。
今天偶然发现在 Firefox 下点击我 Blog 页面头部的
图标并不像在 IE 下那样可以正常的跳转到 RSS feed XML 页面。难怪之前好像有朋友问我说我的 Blog 上的 RSS 订阅哪里去了?
原因:因为我用的是 window.navigate("URL") 而不是 location.href='URL' 来做跳转;不幸的是 Firefox 并不支持 navigate 方法。所以以后任何地方要做跳转,忘了 navigate 吧!
RSS feed 图标可以正常点进去了,又发现 RSS feed XML 的内容显示似乎有点异样。仔细一看原来是正文的内容没有被正确的转化回 html 格式化内容。
原因:因为我为这个 xml 文件加了 xsl 定义文件,并对于每篇日志的正文部分使用了 disable-output-escaping='yes' 属性来通知浏览器的 xml parser 不要把这部分 html 代码转义。同样的,这个属性为 MSXML 所支持,但 Transformiix 引擎就不支持了。 Firefox 等浏览器使用的 XSLT Processor 恰恰是 Transformiix 。所以,对于 Transformiix 系的浏览器,只能采用“曲线救国”的方法了,利用 javascript 代码找到所有没有被浏览器自动转义回来的内容并进行正确的转义, BunnyQ 在日志中详细描述了解决方案(包括其他几个需要注意的 XSL 兼容性问题)。我最终使用了比较简便的方式:
在原先的代码
<div class="list_introduce" id="content">
<xsl:value-of select='description' disable-output-escaping='yes' />
</div>
后面增加一段专门针对Transformiix的处理代码
<xsl:if test="system-property('xsl:vendor')='Transformiix'">
<script language="javascript">
var el = document.getElementById("content");
el.innerHTML = el.textContent;
</script>
</xsl:if>
css里面漏写一个分号,在本地浏览居然还能显示正常的效果,通过域名访问css的效果就不见了;
while($val=array_shift($arr))死活shift不出东西来,改成foreach($arr as $val)才正常;
但想通过测试代码来重现这两个现象,居然重现不了,css漏写分号就是显示错误,array_shift也能正常shift。郁闷ing。
刘润说:“不要搞封建活动。”再离奇的表象都可以找到合理的技术性解释。只不过在我们发现真相之前,往往被表象指引到一个错误的方向去思考问题了。
同一段代码在不同的机器上执行结果却莫名其妙的不同,这是最让人郁闷的事情。这两天用 DHTML 的 insertCell 方法来通过 javascript 脚本动态增加表格内容。在自己的本本上一切正常,等到让别人用的时候发现 insert 进去的 td 顺序正好倒了过来,本来应该是第一列的变成了最后一列。折腾半天,发现调用 inertCell 方法的时候可以不填写 index 的值,默认情况下自动添加td到当前行的末尾 oTD = TR.insertCell( [iIndex]) 。于是把所有的 index 参数去掉,问题消失。
等到后来想写段测试代码来重现这个问题,居然死活重现不了。
猜测:只有当 insertCell 遇上 XXX 之后才会出现插入顺序错误的问题,并且只有在WinXP sp2的 IE 上才会出现(我的本本是sp1,甚至我在 Firefox下看到的都是正常的)。
- 让文字自动适应Table宽度
关键样式:
table-layout:fixed 固定布局的算法,则表格被呈递的默认宽度为 100% (For IE,Mozilla)
text-overflow:ellipsis 当对象内文本溢出时显示省略标记(...) (For IE)
overflow:hidden 不显示超过对象尺寸的内容 (For IE,Mozilla)
white-space: nowrap 强制在同一行内显示所有文本,直到文本结束或者遭遇 br 对象 (For IE,Mozilla)
对Table设置第一个样式,对Table里面的tr或td设置后三个属性。这样可以实现表格不会换行,过长文字在IE下自动显示为... - 还是选择使用Leadbbs做论坛
- 用vsftp建立个人ftp站点
- 3 Ways to Read Like a Professional Smart Person
- 分析百度的中文分词结果
- CSS Caching Hack
为了防止页面被浏览器给Cache住而导致用户看不到更新了的内容,我们通常会在URL后面添加一个随机变化的参数,比如 http://.../myarticle/10022.xml?e234kk23s8234 。不过我们往往会忽视 CSS 样式文件被Cache的后果。事实上现在的页面内容和表现日渐分离,整体观感完全依赖于 CSS 文件,一旦你对服务器上的 CSS 文件做了些关键性的修改(比如增加了样式定义)并且在你的 html 文件里面使用了这些新的样式定义,用户再来浏览你的页面可能会发现页面忽然变得极其丑陋,必须按Ctrl-F5强制刷新所有内容才能看到正常的页面表现。这是因为在你的html页面得到更新的时候,css样式文件并没有被浏览器同步更新。因此,我们应该为引用的css样式文件也添加这样一个可以变化的参数来根据实际情况要求浏览器真正重新抓取一遍,比如:<link rel="stylesheet" xhref="http://www.zeali.net/css/zeal.css?version=1" type="text/css" /> - Google Related Links
类似 Google AdSense ,在你的页面上放置一段代码,Google自动把相关的新闻、链接显示出来。当然理论上来说这些相关内容是真正与你的页面相关,而非别人通过付费购买的 AdWords ,你也并非通过放置这段代码来赚取广告费,纯粹为了提高页面内容的丰富性。这样一个缺少明显驱动力的东西愿意去使用的人大概也就不多,何况据说目前这个服务对中文的支持度还有待提高。。 - How to quit your software job and become a millionaire instead
我在之前的日志里面提到:“当这种冗余的数据传输变得相当频繁的时候(比如我之前所做的即时比分系统为了让浏览器第一时间得到最新的比分变化XML数据必须以2、3秒一次的频率不停的刷新这个XML地址,或者类似的一些即时证券股票交易系统),由此所造成的网络带宽的无畏消耗会变得相当惊人。”
对于这个问题,临时性的解决方法是采取各种手段(压缩XML数据、采用YAML格式、优化 Http Header)减少数据传输量。但从根本上来说,只有让数据按需传输,才会使流量最小化。本来计划设计实现基于 server-push + Ajax 版本的即时数据分发系统,因为种种原因完全搁置了起来。现在 Alex 给它取了个名字叫 Comet ,并详细的描述了这个名词所代表的内容。
意料之中的,不少人对这个新名词嗤之以鼻。但在我看来,即便这个 Comet 是一个卫浴清洁剂品牌,至少是对现有技术的归纳总结,跟别人介绍的时候也免得大费口舌。就像 Ajax 一样,虽然只是几样老技术的综合体,之前也有不少人已经在用着这些技术;但只有在 Ajax 这个名词流行起来之后,才真正得到了大规模的应用,各种基于 Ajax 的 frameworks 才争相出炉。对于后进的开发者来说,有了 Ajax 这么一面大旗指路,就意味着少走一大段别人走过的路。
所以,不管这个架构最终会以什么外貌风行,姑且就叫做 Comet 。 Comet 实际上就是在传统的(这个词对于 Ajax 不知道是否合适) timely client-side pulling Ajax 基础上引入 server-side push 机制,在客户端(通常是 Browser )与服务器之间建立 long-lived 连接, server根据需要把数据主动的 push 到客户端。要做到这一点最简单的可以利用 HTTP 协议的 Keep-Alive 头,但如果要能很好的支持大并发量、方便的实现业务逻辑扩展,就不太可能基于传统的 Web server 来实现服务端的程序,只有重新设计 server 。
正如 Ajax 风行之前已经有许多开发者在利用 XMLHttpRequest 来实现着自己的应用一样,有着 Comet 概念的产品目前也并不算少:Lightstream、ICEfaces这样的商业化产品;Pushlets这样的开源项目。相信在一段时间的技术沉淀之后, push style Ajax 会像当初的 Ajax 一样得到个响当当的头衔。
- ActionScript 3 Language Specification draft released
ActionScript 3.0 语言规范草案发布。AS3运行于重写的AVM2执行虚拟机之上,之前的AVM1为很多人所诟病的运行效率将得到大幅的提升。同时AS3语言在设计上引入了更多OO的概念,在带给开发人员便利的同时也使得AS3.0在向下兼容的时候不得不有所舍弃。不论如何,AS3的推出足可以见Adobe对于Flash富客户端应用发展的野心。或许哪一天,当你所有的Web应用都可以包容在Flash之中轻松实现的时候,这个平台逐渐演变成为独立于浏览器之外的客户端平台也说不定。。目前要想体验AS3,你需要先安装 Flex Builder 2 Beta。 - JavaScript Style Attributes
CSS样式属性与JavaScript的属性变量之间的对应表。很实用的东东。 - 迟到的模仿:JDBC 3.0 RowSet,类似于ADO的编程方式
Rowset对比于ResultSet,除了不用保持Connecton外,更重要特点是能够类似于ADO的编程方式,直接对Row赋值来进行Insert与Update, 而不用写SQL语句。 - Don’t Use Frames
- Which PHP framework holds a promise for the future?
- 8 Ways to Extend Wireless Network Range
- Bloglines 新的 Feeds 管理介面
- 最短最酷后缀的1G邮箱,@x.cn
- Using prototype.js v1.4.0
prototype的非官方使用指南,有多国翻译版本(包括中文)。 - Seven ways to toggle an element with JavaScript
- PHP upload progress
显示文件上传进度 - 10 Things a Web Developer should do for the Client
- 9 tips for running more productive meetings
- Seven Deadly Web Analytics Sins
Far too often, the purpose of web analytics is to produce a graph that goes up and to the right. But, good, meaningful web analytics is a deductive process; not just an effort to produce a chart. - 揭穿理发店9大骗人谎言
看来以后到发廊最好就是单剪,别的啥也甭弄。
一直以来想把这个Blog从GB2312改到UTF-8编码,但因为pivot采用的文本数据库使用PHP的serialize存档方式,数据结构依赖于字符串长度,一旦从GB2312改到UTF-8,非英文字符串的长度就发生了变化,原有的日志读取将发生错误。日志一天天增多,编码切换可能的潜在危险就让我越来越不敢去做这件事情了。
昨天终于咬咬牙,决心彻底搞定这个问题,算是给自己新年带来的第一个新气象吧。写GB2UTF8的批量日志文件编码转换脚本、更新语言文件/模板文件、增加新的UTF-8相关的字符串处理函数,一切在本地机器上测试相当顺利。没想到覆盖到服务器上的时候居然出现莫名其妙的问题,页面没法正常重新生成。用ftp维护上传文件是件痛苦的事情,经过几个小时的折腾,终于是“暮然回首”,在pivot站点上发现了db repair的工具可以轻松的解决问题,修复升级之后被局部破坏的数据文件。
总算大功告成,两点教训:
- 覆盖之前一定要在服务器上备份目录,而不是只在本地备份!不同环境下的备份即便只是简单的copy,也可能存在差异性。没有服务器Shell登录的权限,也可以想办法用PHP的passthru之类的系统命令调用来曲线执行Shell命令。
- 碰到问题最好先到官方站点找找答案。看似简单的问题可能会越变越复杂,不如在自己给自己设套之前看看是不是有更简单现成的解决方法。
XML无疑在如今的各种网络/传统应用中扮演着重要的角色,不同服务之间通过统一的结构化标记语言来交换数据、发送请求,同时能进行文档的结构合法性检查。尤其时下大热的Ajax框架中,XML更是不可或缺的角色。
但同时,提供这些便利和健壮性的代价是数据传输量的倍增。有时候用以完整表述文档所使用的Tags和Attributes甚至比实际内容本身还要多。
当这种冗余的数据传输变得相当频繁的时候(比如我之前所做的即时比分系统为了让浏览器第一时间得到最新的比分变化XML数据必须以2、3秒一次的频率不停的刷新这个XML地址,或者类似的一些即时证券股票交易系统),由此所造成的网络带宽的无畏消耗会变得相当惊人。当然,我们可以通过调整Web Server的HTTP Header做些有益的工作(gzip, Http 1.1 Etag 与 Last-Modified等),但何不同时也考虑一下在优雅的XML之外使用其他的数据组织方式来传输那些“带宽至上”的数据?
YAML作为一种更为紧凑的数据序列化格式,在保证数据结构可读性的同时大大减少了结构化所需要的额外数据量。Laurence Moroney比较清晰的描述了XML和YAML之间的异同以及YAML的基本语法以及基本的YAML数据生成和解析的方法。
对于YAML来说最大的问题是其流行程度。目前的.NET和Java平台对YAML语法的解析支持都比较欠缺(不像XML你可以轻而易举从各种途径找到最好的解析器)。但 Ruby 、 Python 等已经提供了对YAML的很好支持 -- 包括PHP和Perl。流行度引发的另一个问题是YAML的数据结构目前无法通过DOM接口来解析,也就是说你如果在使用Ajax或者其他涉及到客户端DOM接口的应用,要么就放弃使用YAML的念头,要么就把YAML的内容包装在一个最简单的XML Tag之内,通过DOM来获取文档,然后再使用自己的YAML解析器来解析封装在里面的实际的YAML数据内容。
如果你的系统符合这些条件,不妨试试YAML:
- 用XML来交换数据使你的网络带宽支出费用剧增(随着用户数的增加)
- 数据的生成和接收方都在你的可控范围
- 你没有太多的时间去从头设计定义一个完全个性化的数据交换结构
- (或者)你正在使用Ruby :)
see also:
XML 问题: YAML 对 XML 的改进
Slaven Rezic's Javascript binding
Using YAML to Decrease Data Transfer Bandwidth Requirements
YAML 和 Ruby
获取XHTML页面上所有具有相同className的Element对象的javascript函数:
/**
* rootNode the root node to be checked on,
* for example 'document'
* classToSearch className to be matched
* tagName elements name to be searched between,
* '*' for all elements in 'rootNode'
* returns an array contains all elements matched
*/
function getElementsByClass(rootNode,classToSearch,tagName) {
var elementsToReturn = new Array();
var elementList = rootNode.getElementsByTagName(tagName);
var nLen = elementList.length;
var pattern = new RegExp("\\b"+classToSearch+"\\b");
for(var i = 0; i < nLen; i++){
if( pattern.test(elementList[i].className) ){
elementsToReturn[elementsToReturn.length] = elementList[i];
}
}
return elementsToReturn;
}
Ajax & PHP without using the XmlHttpRequest Object,这样的一个标题足够吸引我去看个究竟。然而文章本身其实倒没有太多特别的东西,简而言之是介绍了如何利用动态加载js来实现页面的无刷新数据提交。不过随后的四十几条回复评论内容却很丰富,讨论也颇激烈,让我一口气把它们给看了下来。
这其中议论的一大焦点在于作者采用的标题把Ajax给扯了进来,热门名词自然引发热门讨论。在不少人为这篇文章叫好的同时,大量Ajax'ers则认为文章所涉及的技术不值一晒。
- 从纯粹的字面来理解,既然没有XmlHttpRequest的使用,Ajax中的'x'基本上来说也就无从谈起,自然算不上Ajax了。作者多少有些文不对题自相矛盾。
- 从功能性上来说,通过 document.createElement('SCRIPT') 来动态创建js的引用,继而完成客户端数据的异步提交,只能算是类Ajax风格。如果考虑到客户端与服务器之间的交互性和数据提交状态的可跟踪性,js无疑是没法和XmlHttpRequest Object相提并论的。
Ajax是个好东西;Ajax之流行带来大量Ajax Framework的涌现对于开发人员来说更是好事(想当初为了实现这些功能所有代码都是自己从头一点点写出来的,早流行几年的话能给我省多少力气啊)。问题在于现在的Ajax就像web2.0一样,被说滥、用滥了。针对Ajax & PHP without ...一文的各种反对声音的批判逻辑往往是:“你这不是Ajax style的,所以你这东西就是trash。”
但其实很多时候,我们的需求只是像Ajax & PHP without ...文中的示例那样让表单提交过程更酷一点、避免整个页面的刷新而已。对于这些简单的需求,通过各种其他的"伪"Ajax技术来实现,足矣。其中一个回复评论提到的这篇文章很能说明问题。Remote Scripting的实现方式向来就有多种,针对不同的应用需求完全可以选择不同的解决方案。Ajax这个名词之所以流行,只是因为目前有像Gmail这样重量级的优秀应用实例出现吸引了足够的眼球而已。即使不用XmlHttpRequest对象,我们也可以使用Java Applet来实现类似的数据交互,甚至可以在Flash8里面用XMLSocket来做这件事情。
也许作者给自己的文章换个标题效果会更好 -- 就像 Javascript includes - yet another way of RPC-ing 和 Remote scripting with javascript 这两篇讲述类似内容的日志那样。
厌倦了和讯网摘的不道德(网摘显示的地址都是和讯的跳转页面而非最终url)和功能的不完整(至今也没有提供API和导出功能),而365key上面充斥着太多的垃圾条目,兜来兜去,我决定还是用回到美味书签。
好在我放在和讯上的网摘数量不多,总共一百多条,分页显示也就两页内容,可以很容易的把所有网摘的html代码拷贝下来。就算数量多,用程序去循环抓取也还简单。
原始信息有了,需要把它们解析出来导入到del.icio.us中。我选择用javascript来对原始html进行整理生成一个PHP数组变量,然后通过REST API把所有的网摘一次性导入(del.icio.us目前似乎屏蔽了导入功能,否则直接生成标准格式的bookmark文件就可以导入了,可以省去调用它的API接口的麻烦)。当然要注意执行导入的PHP脚本文件应该是UTF-8格式。
导入过程还算顺利,只是有几点小问题:
- 和讯网摘列表对于单个网摘只显示最多两个tag,所以对于两个以上的tags就只好让它丢失了
- 和讯网摘的网摘描述可以放很长一段文字,以至于我以前收录的时候有时候把文章正文全部作为描述放进去了,而del.icio.us支持的描述文字长度有限(中文字大概100个左右),所以只能把超长的文字截去
- 中文tags有些字造成乱码,好在数量不多(两三个),导入以后需要手工修改一下这几个网摘的tags
不管怎么说,所造成的问题在我能接受范围之内。
笔记本和家里的PC全部都重装了,顺便也就装上了Firefox 1.5 RC版。结果发现自己之前费了老大劲在Firefox1.0.x下面修改的Blog显示代码到了这个1.5RC又出现了问题。
最大的问题是iframe的显示又不对了,大部分的iframe内容统统变成白板,而且iframe页面的高度也完全和原来不一样。
经过无数次的测试+Google之后,终于把问题最终定位:原来我把iframe作为一部分内容放在了DIV里面,为了页面美观,我用js首先把这个DIV设成了display = 'none';然后在iframe的onload里面在把这个层设置为可见,同时根据实际的iframe.document的高度来动态调整iframe的高度。
这些操作在IE和Firefox之前版本里面能够正确的表现出来,但在1.5RC里面,Firefox似乎发生了一些错乱,当iframe载入文档的同时进行了DIV的display='none'操作(或者是Firefox本身对这两种操作进行了同步化?),这之后再去通过设置display='';来显示DIV的内容的话,IFRAME就会出现空白一片,除了iframe之外的页面元素却能全部正常的显示。
虽然知道了问题所在,但看来目前我没有更好的解决方法,只能是调整自己js的处理,暂时去掉了把DIV隐掉的操作。同时把这个现象作为bug提交给了bugzilla,希望在1.5的正式版本不会有这个问题存在。
----
P.S. 这个1.5版本有一个好的改进,那就是对于iframe高度的计算,之前的版本计算出来的高度不准确,以至于我必须在js里面单独针对Firefox进行判断:
var FFextraHeight=getFFVersion>=1.0? 16 : 0 ;
来把这个缺掉的16px的高度给加回去。现在1.5版本就完全不需要进行这个修补了:)
