IE6 CSS Hack

Tagged Under : , ,

最近在做一些UT的工作,写一些HTML和CSS,又遇到了一直很头疼的浏览器兼容问题。

主要就是让人讨厌的IE6,总是需要进行很多特殊的处理。

遇到表格类型的HTML区域,我一直觉得用table是最合适的,解决局部的单层表格,table是最方便的,HTML语言加入table这个标签的初衷就在这里。

不过因应用需要,我这回必须要用div实现table的布局,只能硬着头皮搞了。

对表格区域,我用ul标签,用li作为每行的容器。

在每个li标签中,用div作为列单元的容器。

这会遇到几个问题,同时也有一些优点吧:

  1. (缺点)列的宽度必须用样式来定义,比如每行相同的列单元,都必须使用相同的class,在css中给这个class定义绝对宽度,用width=240px这类的语句,代码冗余比较多
  2. (缺点)每个div必须添加float:left的css定义,因为div是块状元素,默认是按行竖着排列的,设为浮动元素后,才可以横着排列
  3. (缺点)float:left这个属性的排列方式,我总结的是按左上原则,可以理解为左上角是引力中心,把每个float元素都紧紧地吸附着,如果右侧有空间,就顺序排列在右侧,如果没空间了,就到下面一行尽量靠左的位置开始排列……,因此如果宽度不够,改行左边单元的高度又高于其他单元,那么最右侧的单元会卡在左边的单元右侧,呃,可能不好理解,回头我给个图,专门说一下这个规则
  4. (缺点)li的高度默认不是自适应,当div单元的高度很大时,会突破li容器,影响下一行li的显示,呃……不过这个是有办法解决的,这篇文章主要就是来说明这个解决办法
  5. (优点)div对浏览器来说就是一个简单的元素,浏览器每读完一个div,就可以立即显示,不必等待所有html代码都下载完才画出页面,这也是大家不喜欢table的主要原因
  6. (优点)每行都有自己单独的列元素,每列的宽度可以不一致,这点table很难做到,即便能做到,也是用非常绕弯的方法,而用li+div来解决,就很灵活
看似缺点比较多,不过缺点都可以解决。
下面列举几个方法,就不一一对应了,其实道理都是相通的:
  1. float元素排列被卡住的问题,可以给同行的每个div单元设定一个足够的高度,这样就不会形成“阶梯”状排列的单元,当右侧没有足够的宽度容纳新单元时,这个单元会自动到下一行开始排列(有点像windows的资源管理器,显示图标的时候,就是按照这个规则,注意,windows的每个图标,都有足够的高度和宽度)
  2. li高度不会自适应,可以搞定,给每行li设置overflow:auto(注意,尽管默认就是auto,但是否显式指定,显最终的效果是不一样的),同时设置li的宽度,width用px绝对值,li中的每个div,也要设置绝对的宽度,这几项都是必须的,缺少任何一项都会导致页面错乱
  3. IE6的hack,其实现代浏览器,IE7+,Firefox,Opera和Safari等都可以很好地兼容div的页面布局,只有IE6很不兼容,网上也有很多hack方法,我觉得最好用的就是一点:只有IE6支持_开头的属性名,比如对margin的理解,IE6跟其他浏览器是不一样的,但在CSS中,我们可以这样写 div.test {margin:8px; _margin:4px;} ,那么,只有IE6会认为边距是4像素,其他浏览器都会认为是8像素,刚好解决IE6的问题。
简单的说说就这些了,也是最近几天的心得,跟大家分项一下~~

Regular Expression 排除字符串 不包含字符串

Tagged Under :

今天在写一个 Symfony 的路由匹配规则,查看文档的时候发现有一个 requirements 参数,可以对自定义的变量匹配正则表达式。用它匹配特定的字符串很容易,比如 requirements: { id: \d+ } 表示匹配一个或多个数字形式的 id,但我的要求是排除某些字符串之后的匹配,这个我就不知道怎么做了。

上网找了很多,最后还是 Google 帮我找到了想要的结果。

原文在这里:

http://www.cnblogs.com/deerchao/archive/2007/02/15/651411.html

deerchao的blog,文章详细叙述了作者的试验过程,很有意义,后面的评论也很有价值,最后的正则就是回复评论的人提供的,在这里我也顺便感谢一下!

简单说来,目标:当字符串中不包含 google 和 leakon 的时候,匹配字符串。

正则就是 \b((?!google|leakon)\w)+\b。

这里可能看得不是很清楚,我写了个 wiki,里面还有几个测试的例子,请大家看看:

http://wiki.leakon.com/RegularExpressionTips

辅助开发工具

平时经常会做一些编码和解码之类的转换,每次都要写个小文件,真麻烦,上网找过一些客户端的小工具,也都不太好用。

自己写了一个页面,随时可以使用,而且做了一系列的人性化设计,比如高亮显示之类的,感觉还不错。

大家看看吧:http://code.leakon.com/php/tools

只有一个页面,随时可以扩充新的转换。

看源码:http://leakon.googlecode.com/svn/trunk/leakon/php/tools/index.php

diff 用法

语法:diff [选项] file1 file2

说明:该命令告诉用户,为了使两个文件 file1 和 file2 一致,需要修改它们的哪些行。如果用 “- ”表示 file1 或 file2,则表示标准输入。如果 file1 或 file2 是目录,那么 diff 将使用该目录中的同名文件进行比较,同时两个目录中的不同文件也会以 only in 目录名 : 文件名 列出。

通常输出由下述形式的行组成:

n1 a n3,n4

n1,n2 d n3

n1,n2 c n3,n4

字母(a、d和c)之前的行号(n1,n2)指file1 的n1~n2行,其后面的行号(n3,n4)指 file2 的n3~n4行。字母 a、d 和 c 分别表示附加、删除和修改操作。

在上述形式的每一行的后面跟随受到影响的若干行,以 “<” 打头的行属于第一个文件,以 “>” 打头的行属于第二个文件。

diff 能区别块和字符设备文件以及 FIFO(管道文件),不会把它们与普通文件进行比较。

如果 file1 和 file2 都是目录,则 diff 会产生很多信息。如果一个目录中只有一个文件,则产生一条信息,指出该目录路径名和其中的文件名。

该命令的各选项含义如下:
-i 忽略大小写匹配
-b 忽略行尾的空格,而字符串中的一个或多个空格符都视为相等。
-c 采用上下文输出格式(提供三行上下文)。
-C n 采用上下文输出格式(提供 n 行上下文)。
-e 产生一个合法的 ed 脚本作为输出。
-r 当 file1 和 file2 是目录时,递归作用到各文件和目录上。

Netscape Bookmark File Format

The Microsoft Internet Explorer Favorites file format is exactly the same as the Netscape Bookmark file format. Netscape usually stores its bookmarks in an HTML file called Bookmark.htm.

File Format

The file starts with the following text:

 

<!DOCTYPE NETSCAPE-Bookmark-file-1>
    <!--This is an automatically generated file.
    It will be read and overwritten.
    Do Not Edit! -->
    <Title>Bookmarks</Title>
    <H1>Bookmarks</H1>

The rest of the file is as follows:

 

    <DL>
    {item}
    {item}
    {item}
    .
    .
    .
    </DL>

An item may be either a subfolder or a shortcut. If {item} refers to a subfolder, it is:

 

    <DT><H3 FOLDED ADD_DATE="{date}">{title}</H3>
    <DL><p>
        {item}
        {item}
        {item}
        .
        .
        .
    </DL><p>

If {item} refers to a shortcut, it is:

 

    <DT><A href="{url}" ADD_DATE="{date}" LAST_VISIT="{date}"
    LAST_MODIFIED="{date}">{title}</A>

NoteThroughout this file format definition, {date} is a decimal integer that represents the number of seconds elapsed since midnight January 1, 1970.

Exports and Imports

To export data to a Web address, send an HTTP post request. To send a post request, call HttpOpenRequest with the following parameter values:

  • verb: “POST”
  • http version: “HTTP/1.0″
  • referer: none
  • accept-types: none(implies “text/*”)

Imports from a Web address are accomplished by calling the URLDownloadToCacheFile function.

统计项目代码行数

切换到你项目的根目录下,执行下面的命令,会逐行显示每个文件的行数,和累加值。

wc -l `find ./ |grep .php | grep -v .svn`

这里是统计PHP代码,对所有类型的文件分别执行这个命令,把结果加起来就可以了。

注意,这种方式把注释和换行都算作代码内容了,是粗略的统计。

PHP 文件锁 flock 负载均衡

最近有个项目,采用单台前端服务器提供Web服务,程序需要实时访问后端服务器。后端一共有几十台服务器,但有压力限制,单台负载不能过高,必须做负载均衡。

最简单的方式是用随机数,前端来请求的时候,随机挑选一台后端服务器,但这并不能保证压力平均分布,很有可能在某一段时间内请求都落到同一台服务器上,很容易导致这台服务器停止服务。

后来想到用文件锁的方式,来标记访问计数,顺序访问后端的每一台服务器,让每一台服务器一个周期只被访问一次。

在进行了多次功能测试和压力测试后,验证了这种想法的可行性,然后写了一个IDService类,封装了整个过程。

我在Google提供的SVN服务器上保存了源码,大家可以在

http://leakon.googlecode.com/svn/trunk/leakon/php/flock/flock.php

这个地址看到源码,或者用SVN工具CheckOut到本地。

核心过程,就是初始化的时候给一个ID范围,默认是从0开始,如果你的server_count是32,那么调用getId()方法的时候,我会顺序给你31至0这32个ID,采用文件锁就是考虑到并发请求之间彼此独立,一个进程读数据文件的时候要加独占锁,解锁前,其他进程无法读取数据文件。

ID分配给你了,每个ID对应哪个服务器,就是你自己做映射的事了,保证了这个模块的无关性和独立性,和其他所有模块保持无耦合。

这是在PHP5的环境下写的,const 定义了3个类常量:

LINE_FEED 是换行符,Windows 下是 \r\n,Linux 下是 \n,只是为了方便测试的时候实时查看数据,可以是任意字符,只要不是数字就OK;

MAX_LOAD 是计数器的最大值,计数器都是从0开始,如果有任何一个ID达到了最大值,则所有ID计数器全部归零,开始新的一轮计数,其实这个设置只要大于0就可以,最好不要太大,因为存储数字也是要占用存储空间的,越小,id_data_file的尺寸就越小,硬盘读取就越快;

DATA_BLOCK 是设置一次读文件的数据大小,硬盘的一个文件至少要占一个簇,一般文件系统一个簇是4K,这个取值要跟ID的总量有关系,如果你的LINE_FEED是\n,MAX_LOAD是99(采用文本方式存储,2字节),那么一个ID占用3个字节,如果你有100个ID,那么数据文件占用空间就是300Byue,因此DATA_BLOCK设置为300是最佳值,需要注意,如果ID范围变大,需要同步更改此值,因此我默认设置了2048字节,小于硬盘的一个簇,相对于300字节来说没有性能损失,因为都在一个簇内,数据存储是连续的,硬盘只需一次寻道和一次读写。

源码里有使用说明,很简单,在实例化对象的时候指定ID范围和数据文件位置即可。

已经经过测试,给一些压力测试数据吧:

在AMD3000+和7200转80G硬盘的台式机环境,可以提供到 1300+次/秒 的速度,此时磁盘IO是瓶颈;
换上Linux服务器,具体配置不太清楚,反正是SCSI硬盘,100多G,只是开发用机,性能并不高,但可以提供 5000+次/秒 的速度。

综合2中环境的测试数据,以目前前端服务器的最高负载(最高也就 200+次/秒),以及项目的实际负载,此代码性能足够满足需要。

单元测试

有些道理,大家都明白的,但真正要做的时候,却很少有人能落到实处。

在学软件工程的时候,第一次听到了单元测试和测试用例这些词,印象很深刻 。

书上讲的都是软件开发这个行业几十年来总结的经验,很有道理,也很有说服力,我也十分认同书上的做法。

我也感觉自己是一个喜欢追求完美的人,看到书上说的那些测试的方法,比如边缘测试之类的,在感叹前人总结的方法很优秀的同时,自己也暗下决心,以后我写的程序,也要有规范的接口,有明确的输入输出,要有完备的测试用例,把每一个细节都测试到,让自己的程序表现完美。

然而,在现实中,总是事与愿违。

大学期间写的程序就不说了,我到现在正式工作已经两年半了,写的代码少说也就几万行。Bug是难免的,但总是被别人发现。

我一直没有做过规范的单元测试。

原因是多方面的,但主要在自己。

懒惰,是程序员最大的敌人!

当需求明确时,我会立即投入编码,把脑子里那些自认为不错的逻辑,用程序代码实现出来,这个过程是十分开心的。程序完成后,输入预定的参数,得到预想的结果,那种成就感,难以用语言形容。

我想问一句,这个时候,这个程序算是开发完毕了吗?

以前,我是这样认为的。我也坚信,国内绝大部分的程序员,都是这样认为的。

实际上,这就好像万里长征刚迈出第一步而已。虽然有些夸张,但事实如此。

你给你的程序写出测试用例了吗?你对程序的每一个模块,做了单元测试了吗?在输入数据的时候,是否输入了边界值?是否输入了非法值?有没有试过不给输入,看看程序输出什么?

当然,那些自认为做事严谨的人,多少是会做一些测试的,这也使得他们的程序,比一般人的更稳定一些。

我想说的是,自己写的程序,定势思维会很强的,你很难想象出一些匪夷所思的参数去测试你的程序。

程序就像你的孩子,你希望他健壮,也许你会让你的孩子参加一些艰苦的锻炼,但你绝对不会拿个大铁棍砸向孩子的胳膊以检验他的骨骼是否强壮。

开个玩笑地说,拿铁棍砸别人的孩子,大多数人还是做的出来的。

我曾经自认为考虑的十分周到的程序,被人一眼就挑出一个bug,自己回去改,这个bug好了,另一个bug也随之而来,最后搞的svn被我当成磁盘一样用,改个字母都会提交一次!

话题有些远了,这篇文章的出发点,就是今天彻彻底底的进行了一次单元测试,真的是感受良多。

在做这个项目的时候,伴随着开发,我也一直在写测试用例,也一直在反复测试。我很早就知道PHP的单元测试框架,也看过很多文章,里面的很多过程和逻辑我都很清楚。可能还是因为懒吧,我只是把所有的测试用例放在一起,每次循环跑一下程序,把输出打在屏幕上,测试的时候看一眼,没什么问题就过去了。

这样很不好,还是思维定势的问题,有时候出现问题,可能就在一些细节的地方,面对满屏的输出,你是无法准确判断每个输出是否完全正确的。

后来,试着按照标准的测试框架的方式,对每一个输入,认真地写出人工判断的期望输出,然后由程序自动执行,看看是否能全部通过。

结果当然不会出乎意料,有一半的测试没有通过。

再返回头去改程序,这时才发现以前考虑逻辑的时候想法有多么简单,有那么多遗漏的地方。

你也可以邀请你的同事,鼓励他们想出各种办法来搞垮你的程序,你需要做的,就是把他们每一个稀奇古怪的输入都认真地记下来,这才是你最宝贵的财富。

我听过以前的同事讨论程序,说他新做的模块,测试了上千万的数据,一个bug都没有,但一上线,就出大问题,而且每次都这样。
另一个同事对他说,合法的输入,测试多少都没有意义,只有那些非预期的,非法的和异常的输入,才是重要的测试资源,而且,这些case都应该好好保留,以后每次测试,就从这些bad case入手。

我对这番对话记忆深刻,从那时起,我也在逐渐应用这种方式去测试我的程序。

今天,终于切身地感受到这种开发方式的好处。

我在线下修改一个bug,就可以避免上万的用户在线上碰到bug。

作为互联网产品,线上服务的稳定性绝对是第一位的!

话题基本到这里,我想再引申出另一个问题,就是关于“落实”这两个字。

现代人类文明,大概有2000年了,我们的前辈,给我们总结出了大量的经验教训,希望我们能少走弯路。

我领悟出一个道理,世上绝大部分事,都很容易做,每一份事业,都很容易成功,因为很多是前人做过的,他们总结的经验,我们很容易就能得到。

可实际情况却是,大部分人都不能把事做好,都不能做出一份成功的事业。

是他们不懂道理,没听过经验教训吗?

我想不是,原因就在于,他们没有很好地落实每一项应该完成的事。

就拿上学来说,我们都经历过至少十几年的校园生活,大部分人的学习成绩应该都不是所在学校的No.1吧?

你回想一下,那个时候的年级第一,他比你聪明吗?不见得吧。

那个时候老师都说,要好好学习,课前要预习,上课要认真听讲,课后要按时完成作业,不懂就问。很简单的道理,不是吗?我的印象中,学校里学习好的人,平时都很贪玩的。他们不比我聪明,晚上熬夜也没我时间长,他们比我学习好,只有一个原因,他们听话。他们认真地做到了老师要求的每一件事,而且一点也不难,很容易就超过了别人。

思维再跳跃一下,就说这开车吧。

不准酒后驾车,不准疲劳驾驶,交通路口要减速慢行,要与前车保持安全距离。

很简单的四条吧,大家看看新闻,哪次事故不是因为酒后驾车,超速行驶呢?出了事,轻则误事赔钱,重则车毁人亡,你说做到这几条有多难呢?还是难以落实。

再回到程序开发上,就像我遇到的问题,我们有很多开发经验,有软件工程,有测试框架,有编程习惯,有代码标准,可真正做到的有多少呢?有几项是我们真正落实的呢?

还有创业,我认为也一样。

很多成功的老总,都会总结他的经历。很多人都说,他之所以成功,就是因为坚持不懈,锲而不舍地做了一件事,把这件事认真地做好,他就成功了。

而现在的很多创业公司,拿着几千万美元的风险投资,就不知道该干嘛了,这也干,那也干,这么大的互联网,没有他不干的。讲起道理来,他比谁都能说,真正做起事来,前人总结的经验,就完全抛在脑后了。

还是一句话,落实很难。

还是收起浮躁的心,踏踏实实,脚踏实地,把最简单的事做好,每落实一件事,离成功就会更近一步,我坚信!

pure function

A pure function:

Has no side effects

Return value depends only on arguments

Example:

sub factorial {
my $n = shift;
$n == 0 ? 1 : $n * factorial($n-1);
}

cache 只对 pure function 有意义

这可以思考查询一个档案的修改时间的这种 function,他并非一个 pure function,所以对非 pure function cache 是没有意义的这里有一个例子

Highly Recursive Functions
sub fib {
my ($n) = @_;
return $n if $n ==0 || $n == 1;
return fib($n-2) + fib($n-1);
}

This function is very very slow!

Caching Fixes Recursion
Solution: Caching

@fib = (0, 1);
sub fib {
my ($n) = @_;
return $fib[$n] if defined $fib[$n];
return $fib[$n] = fib($n-1) + fib($n-2);
}

fib(20) computes fib(18) and fib(19)

fib(19) goes to compute fib(18)

But it is already in $fib[18]

Function is now very fast,Almost as fast as a pure iterative version,
Unlike the iterative version, this version required no ingenuity

以上文章节录自 http://perl.plover.com/yak/hw-dcpm/

Google

Google
LAMP-Linux-redhat LAMP-Apache LAMP-MySQL LAMP-Php Leakon-Wiki Leakon-BBS XueBaoBao Xyoyou