Saturday, December 20, 2008

用jQuery.extend遇到的问题, 与大家共勉

官方接口: jQuery.extend( [deep], target, object1, [objectN] )

如果target未指定, 则jQuery名字空间接受extend后的属性, 但是, 如果object中包含dom属性, deep又设置为true的话, 则会出现recursively error, 因为dom树存在循环引用!
  • 看代码就很容易明白了,
  • extend函数的核心:
    if ( deep && copy && typeof copy === "object" && !copy.nodeType )
    target[ name ] = jQuery.extend( deep, src || ( copy.length != null ? [ ] : { } ), copy );
  • 可以看到这里copy.nodeType处理了dom node, 就是为了避免这种递归, 但是当我们自己有个对象, 此对象是互相引用的结构时, 这个情况就再所难免了, 所以一定要注意
  • 另外: $.ajax({param: ...}), 中的param, ajax函数内部就是一个jQuery.extend, 所以这里也要注意一下


Tuesday, November 18, 2008

今天整理文档, blog一下, 备忘: getNamedItem

getNamedItem以前做xml解析经常用到的函数, 在document dom中也是可用的,
用于获取某个标签的私有属性(非rfc标准的),
这个属性, IE会自动给解析出来, 例如dom.customize_field_name, 就直接可以访问,
Firefox却不会自动给解析,
只能用dom.attributes.getNamedItem('customize_field_name').value访问,

最后通用一点就是都用dom.attributes.getNamedItem('customize_field_name').value, IE下也是支持的

Friday, November 07, 2008

CI Email notification

在cruisecontrol标签之后, project标签之前, 添加plugin, 方便多个project共享htmlemail的通用设置, 例:
<plugin name="htmlemail"
mailhost="mail.mailserver.com"
username="notification@mailserver.com"
password="password"
reportsuccess="always"
returnaddress="notification@mailserver.com"
skipusers="false"
subjectprefix="CI"
defaultsuffix=""
buildresultsurl="http://serveraddress:7777/buildresults/${project.name}"
/>
在project的publishers节点下, 添加htmlemail通知任务:
<onfailure>
<htmlemail>
//只要构建失败, 就发邮件给emp1
<always address="emp1@mailserver.com"/>
// emp2, emp3可以映射到emp2@mailserver.com, emp3@mailserver.com
//此处设置的意思是, 如果本次构建失败了, 则通知提交代码的人 ,
提交代码的人的SCM帐户名称从recently modifications中可以拿到,
然后map就是完成从SCM帐户到email帐户的映射, alias ='emp2'中的emp2就表示SCM的帐户名称.
<map alias="emp2" address="emp2@mailserver.com"/>
<map alias="emp3" address="emp3@mailserver.com"/>
</htmlemail>
</onfailure>

John Resig

John Resig, the creator and lead developer of the jQuery JavaScript library.
His blog address: http://ejohn.org/, we can learn more about
javascript from his articles.

"Object()" or "new Object()" in javascript

We can implement an Object, which can be instance by "Object()" or
"new Object()", here's an example:

function User(name, age){
//if ( !(this instanceof User) )这个也是可以工作的, 但是arguments.callee更通用

if ( !(this instanceof arguments.callee) )
return new User(name, age);

this.name = name + " - " + age;
}

var user = User("xlty", 27); <==> var user = new User("xlty", 27);

flexible arguments

more generic usage of "apply":

Math.min accept a list of number:
> Math.min(1,43);

We want to pass an array to Math.min
> Math.min.apply( Math, array );

Friday, October 31, 2008

实现了一个简单的js test工具集

一时兴起, 实现了一个简单的js测试框架, 结构如下:
==========================================================================
//测试项
var TestEntry = function(id){
return {
//目前只实现了一个简单的方法, 其他的可以自由扩展
assertTrue: function(result){
var r = ET.get(id);
r.append(result? "Ok" : "Error");
r.addClass(result? "ok" : "error");
}
}
}
//测试执行器
var Test=function(){
var mc;
return {
init:function(dom){
ET.get(dom || document.body).append("<div
id='messageconsole'><b>Message console:</b></div>");
mc = ET.get("messageconsole");
},
addTest: function(msg){
var id = UUID.generate("v4");
mc.append("<br><b class='item'>test "+msg+" <b class='result'
id='"+id+"'></b></b>");
return TestEntry(id);
},
reset: function(){
mc.html("<br>");
},
report: function(){
//设置延时是为了, 等待异步执行的部分ajax测试完成
setTimeout(function(){
var total = ET.getByJQSelector("b.item").length;
var error = ET.getByJQSelector("b.error").length;
var ok = ET.getByJQSelector("b.ok").length;
mc.append("<br><br>"+
"<b class='item'>Totally "+total+" tests,</b>"+
"<b class='passed'> passed "+ok+" tests,</b>"+
"<b class='failed'> failed "+error+" tests,</b>"+
"<b class='unfinished'> unfinished "+(total-ok-error)+" tests</b>");
},
1000);
}
}
}();
==========================================================================
css代码:
.item {
color: blue;
}

.result, .unfinished, .failed {
color: red;
}
.passed {
color: #55FF55;
}
==========================================================================
用法:
Test.init();

//普通测试项
Test.addTest("log message here").assertTrue(1+2==3);

//异步操作的测试
var ajaxTest = Test.addTest("ajax request test");
Ajax.request({data:{id:1}, url:'../getName.htm', callback:function(data){
ajaxTest.assertTrue(data.name='apple');
}
});

Test.report();

解释说明:
Test.addTest在系统中添加一条测试记录,
返回一个TestEntry, 用返回的TestEntry的assert系列方法, 来断定此测试项的正确与否

Thursday, October 30, 2008

[转] 北京的慢性驱逐令

原文: http://home.donews.com/donews/article/1/130211.html
很有同感的一篇文章, 转来分享一下


离开北京已经有一年多了,但至今还是常有人不理解地问:"为什么你在北京有房有车有公司,却会在一夜之间决定彻底离开北京?"问的朋友多了,于是,我想倒不如把我是如何"被北京抛弃"的原因说说,也好省些口舌。

北京的慢性驱逐令

1996年的建军节乘火车到北京,直至20078月与人签订售房合同,我在北京整整生活了11个年头。其间,住过中央社会主义学院的办公楼,住过小南庄的居民楼,住过万寿寺的老院子,直至自己买楼置业。过去的11年历历在目。

说句实话,我还是比较喜欢北京人的,虽然对老北京不够上进和锐气有些失望,但多元的北京文化不像上海的市侩、小气,也不像南方人的生意、烦躁。恬淡、性情的文化使外来的人们感觉不到太强的排外感。倒是外来的人群对老北京有些"排内"。

然而,我终究是成不了北京人的。

1998年,我跳槽到一家新的报社工作,报社提出员工档案要统一放到(原)电子人才中心管理,我托老爹去浙江丽水市最早分配的工作单位调档。结果告知:因为原来与单位签订的5年劳动合同没有执行完,我就擅自离职,剩余年限需按每年1000元交钱后才能调档。

我当时就有砍人的冲动:当时在丽水工作半年,一个月400元工资,一共才发了我二千多元的工资,现在居然要收我4000元——半年白干不说,还要倒贴钱。如果是大城市,我也就认了,丽水这么个"浙江的西藏"也值得我打破脑袋往里钻?

单位领导还算"仁慈":你还没干满一年,按理,要照五年计算,我们就只算了你四年的钱。

后 来有一次,总编曾经提出可以帮我的户口"弄"到北京。当然,我因此会欠他老大的人情,我还不得不和报社签订长期的"卖身契"。考虑到用"自由换户口"不是 什么划算的"交易",我也就没应这茬——户口这种老掉牙的玩意迟早会死掉的,说不定十年后就没什么用了,社会总不会倒退吧?

2000年底,我去了《计算机世界》报社。突然有一天,当时一位领导不知抽了什么风,要求员工把档案在限期时间前必须把档案调到北京市人才,否则工资只能拿到正常工资的1/3

这一下,全报社的同事都忙活了起来,我当然也不例外。当时我的档案还在电子人才,当我去电子人才办调档手续的时候,被告知:户口不在北京的人员档案不能在北京不同档案管理中心之间直接调档,须先调回户口所在地,再调过来。

于是,我把档案调回到了老家县城的人才中心。再委托人将档案调至北京市人才。过了很长时间,每次打电话,北京市人才总说没有我的档案。只好打电话问县人才,告之:档案被北京市人才退回去了。

又打电话问北京市人才,工作人员说,你的档案在县人才,我们没法接收,你必须先高到当地地市一级以上的人才才可以调过来。

我又托老爸将档案调到了当地市人才。又过了很长时间,北京市人才又说档案被打回去了,原因是我当初没有转正就离职,档案里没有"干部"身份。我终于明白了:北京是"干部"呆的地方,不是"干部"就免进。

从此,我患上了档案过敏症——一提到档案,脑袋嗡嗡作响。

报社和我类似的情况很多,领导的"高招"最后不得不不了了之。

过去在北京没有户口是无法上车牌的。尽管一直想自己买辆车,但一想到上车牌还是找北京本地户口的人"挂靠",这又是件脑袋大的事。

2001年十月,北京市宣布拥有工作寄住证(工作居住证的前身)的人可以允许上车牌。我的"寄住"证是前一家单位办的,没有按规定交回,不过快到期了。我赶紧挑了辆车去上牌,工作人员疑惑地看着我:这个玩意儿能上车牌吗?

你没看新闻吗?我心里忐忑不安地回答,紧盯着工作人员打电话询问的每一个动作和表情。看到他的脸皮松驰着,我心安了一点——总算有自己的车牌了!

2002年小家伙出生后,麻烦又要开始了:有小孩的日子过得很快,以后的上学又成了一个麻烦事。交赞助费倒在其次,更担心以后考大学——北京的教学应试能力没法和浙江比,小孩要在北京上学,回浙江考大学就惨了。原来大学同班的北京同学分数要低200分左右,这种成绩在浙江是上不了大学的。分数线的差异可能要了小孩未来的命。

我第一次感到自己对中国的改革过乐观了:几千年的户籍制度改革比蜗牛都慢,而小孩却长得飞快。也许我们这一辈子是看不到真正的自由户籍制度的了。

离京:无奈的选择

选择离开北京不是件容易的事,毕竟人的一生不会有太多的11年。在北京,我从一个毛头小伙成了一个中年人。但最终,我决定离开北京——我想无论我多努力,我终究成不了北京人。

2007年春节回家后,我断然决定:准备离开北京,停止公司开展新业务,老项目执行完后就关闭公司,卖房子离开。

对南方人来说,北京是脏,北京是干,但其实这些都可以适应,而一次次政策性的歧视让人有不如奴隶的感觉——即使是奴隶,他的努力工作也多少会搏得主人的一些欢心;而那些对外地人的羁绊却像故宫的一重重门槛一样走不到头,而且坚不可摧。

所以,故宫我是不喜欢去的,除了有一次陪长辈,我从未进去游玩过——在我看来,这是一个阵旧的,封建的象征,体制的"故宫"我已经走厌了,再不愿去看那形式的故宫。

2007年回到杭州,买了一套房子,找了一份工作,今年上半年时把户口转到了杭州,小孩也顺利地进入了小学。打工的日子花钱没像以前那么随意了,但我还是认为自己的决定并没有错。

窗外秋雨迷离,我回过头去看看自己的脚印,一步一步从浙江走到北京,又走回到浙江。那一段激情燃烧的岁月,那一段北京的创业史都随风而去,只在记忆里隐约可见。

一段时间里,我一直在想:是我抛弃了北京,还是北京抛弃了我?我想也许在北京看来,我是一个寄住者,我去北京是和北京人抢地盘、抢资源的,所以,我遇到的事总会在有意无意地驱逐我。一些朋友从国外回来,最后又走了,我于是想:是祖国抛弃了他们,还是他们抛弃了祖国?

中 国太多的东西沉淀了几千年,以至于每个人对它熟视无睹。当人们习惯成自然的时候,不合理也变成了合理。就像有多少人知道蛋白精的存在却当成了一件合理的 事,这是一种可怕的沉沦,这种沉沦的更可怕之处在于沉沦者的不自知——用人血馒头治痨病的人还隐藏于每一个人的心灵深处,它因此影响着中国的政治、经济、 文化和所有的社会环境。

JQuery 树插件介绍: jQuery SimpleTree Drag&Drop plugin

发现一个很好的树插件: jQuery SimpleTree Drag&Drop, 感觉很好, 代码质量不错, 支持拖拽, 风格清晰, 这里推荐一下. Demo看这里.

Saturday, October 18, 2008

Taffy DB : A JavaScript database for your browser

Taffy DB : A JavaScript database for your browser

Taffy DB is a free and opensource JavaScript library that acts as thin data layer inside Web 2.0 and Ajax applications.

What makes it cool:
  • Under 10K!
  • Simple, JavaScript Centric Syntax
  • Fast
  • Easy to include in any web application
  • Compatible with major Ajax libraries: YUI, JQuery, Dojo, Prototype, EXT, etc
  • CRUD Interface (Create, Read, Update, Delete)
  • Sorting
  • Looping
  • Advanced Queries

Think of it as a SQL database in your web browser.

Link To Taffy DB

Wednesday, October 15, 2008

最近动向

  1. 正在比较深入的研究前台开发, 写一些小的框架.
  2. 研究SEO, Google Adsense, 正处于实验阶段, 本站就是实验室, 争取把"小楼听雨"给优化到google, baidu搜索结果的第一页, 这个任务可以比较重, 呵呵.
  3. 整理, 搭建公司的基础架构, 这一块任务比较重, 需要考虑的比较详细.
  4. 另外的一个django站点, 纯凭自己的爱好做着玩的也会在最近上线, 正好用来研究前台开发, 呵呵.
  5. 以后有了什么经验, 会及时拿来分享.

Tuesday, October 14, 2008

A ibatis code generator - iBATOR

iBATOR is a code generator for iBATIS. iBATOR will introspect a database table (or many tables) and will generate iBATIS artifacts that can be used to access the table(s). This abates some of the initial nuisance of setting up objects and configuration files to interact with database tables. iBATOR seeks to make a major impact on the large percentage of database operations that are simple CRUD (Create, Retrieve, Update, Delete). You will still need to hand code SQL and objects for custom queries, or stored procedures.

iBATOR will generate:

  • SqlMap XML Files
  • Java Classes to match the primary key and fields of the table(s)
  • DAO Classes that use the above objects (optional)
Example Class Usage Notes:
  • Example Class has ored Criteria list and every Criteria has many anded filed list
I want to implement a ibatis code generator some day, But I find it "unfortunately".

Saturday, October 11, 2008

Get Computed Style Attribute

when a dom style has been setted more than one times in css file, the final style should be computed, such as:
css file:

#abc{
color: red;
}

div #abc{
color: red;
}

html file:
...

<div><span id='abc'>text in span...</span></div>
...

js code:

var spanEl = document.getElementById('abc');
var ret = document.defaultView.getComputedStyle( spanEl, null );
var color = ret.getPropertyValue("color");

so we can get the right style which appled to dom.

js简单继承的实现 - 网上做法修正篇

网上有些继承prototype实现上有bug例如:

function base() {
this.member = ["dnnsun_Member",2,3,4];
}
var child=function(){
};

child.prototype=new base;
var c1 = new child();
var c2 = new child();
c1.member[1]=333;
alert(c2.member[1]);

结果是: 333

base中如果有集合, 对象属性, 这种简单继承导致的后果是所有的child的实例都共享了base的同一个member属性. 所以要尽量避免此种情况, 尽量在父类中只是定义方法, 变量改为传入的方式. 估计这也是为什么jquery, ext等框架不强制继承的子类必须subclass_instance instanceof superclass==true的原因.

Event driven web application - javascript event bus

I implemented a javascript event bus for asynchronized web application, and this article hasn't any relationship with Ajax and Dom events
Using Event bus benefit your web application development, such as:
  1. low coupling between moudles
  2. flexible event dispatcher
  3. partible bussiness logic
  4. consistent code style
This is a very sample demo code to guide you.
I have two components in my web app, one is a tree, another is a grid list, when current highlighted tree node was been deleted, the grid list should load it's next sibling node's data.

normally, we could write in tree.js:

//delete current hightlighted tree node
...
GridList.clear();
GridList.load(next_sibling_node.name)
...
but GridList was defined in grid.js, so tree and grid moudle was high coupled.

in new asynchronized web application. we can write in tree.js:

//delete current hightlighted tree node
EventBus.publish("tree-node-deleted", node);

and write in grid.js:

EventBus.subscribe("tree-node-deleted", function(argObj){
GridList.clear();
GridList.load(argObj.name)
});

I think this is a good experence in web development.

Wednesday, October 08, 2008

利用event bus来降低前台业务代码耦合度, Event bus - javascript, js实现

/*
demo:
var observer = function(paramObj){
alert("bomb event comes!" + paramObj);
}

//add business event listener
EventBus.subscribe("tree-node-change",observer);
//remove business event listener
//EventBus.unsubscribe("tree-node-change",observer);
//publish business event
EventBus.publish("tree-node-change",{oldName:"abc", newName:"cdef", id: 123});
*/

/*
ReadMe:
Goal: Using business event dispatcher to reduce code couple between web moudle,
目标: 为了尽可能的减少模块之间业务逻辑的耦合度, 而开发了这个消息总线, 主要用于业务逻辑的事件传递
使用规范: 每个js模块尽可能通过事件去通信, 减少模块之间的直接调用和依赖(耦合)
*/

var EventBus = function(){
var observers={};

var publish=function(eventName, argObj){
var obs = observers[eventName];

if(!obs){
return;
}

for(var i=0;i<obs.length;i++){
obs[i](argObj);
}
}

var subscribe=function(eventName, observer){
var obs = observers[eventName];

if(!obs){
obs=[];
observers[eventName]=obs;
}

obs.push(observer);
}

var unsubscribe=function(eventName, observer){
var obs = observers[eventName];

if(!obs){
return;
}

for(var i=0;i<obs.length;i++){
if(obs[i]==observer){
obs.splice(i,1);
break;
}
}
}

var unsubscribeByObserver=function(observer){
for(var eventName in observers){
removeByName(eventName, observer);
}
}
return {
publish:publish,
subscribe:subscribe,
unsubscribe:unsubscribe,
subscribeByObserver:unsubscribeByObserver
}
}();

Monday, October 06, 2008

[转] 小三的爱情扒皮必修课 - 画皮精彩影评

   说是,小三必修课
    
    其实,是所有情场中人的扒皮戏。
    
    《画皮》是一个惊喜,有些是无心,有些是故意。
    
    因为戏路太善良,我们总是忍不住笑场。
    
    然而,面对,那些太刻意的真情告白……我们如果不笑,难道要跟着哭吗?
    
    这场戏,需要些时间沉淀,然后,就有人像我们回忆八十年代的港片一样来回忆这张《画皮》。
    
    不如把笑点抖一抖,顺便帮着大家扭曲一下逻辑。
    
    这个故事告诉我们生活中的许多大道理。
    
    故事的基本结构是这样的。
    
    
    
    陈坤和甄子丹本来是战友,两个人都喜欢赵薇。赵薇选择了嫁给陈坤,甄子丹愤而远走。
    画皮定律一:再好的朋友,抢一个心上人,也会翻脸。无论男女。
    
    陈坤救了一个女人周迅回家。周迅其实是妖怪。
    画皮定律二:如果一个有家的男人把一个单身女子带回家,这绝对是场冒险,不管这个姑娘会不会画皮。
    
    赵薇怀疑陈坤喜欢周迅,进而发觉周迅来了之后,城里开始死人。认准周迅就是妖怪,
    画皮定律三:如果一个女人发现自己的男人外面有了女人,那么到处跟人说那个女人是狐狸精,只能显得自己像个疯子,太小气。
    
    
    但是没有人相信她。她写信喊来了甄子丹。
    画皮定律四:还是去找自己的旧情人,是正路!(找旧情人来干什么,看你的兴趣)
    
    
    周迅想嫁给陈坤,不是做妾,而是做夫人。
    画皮定律五:如果一个小三,喜欢上了一个有妇之夫,又不像只是玩一玩就吃掉他,而是想要个名分,会搞得三个人都很凄惨。
    
    甄子丹来了,降魔者孙丽也来了,孙丽看着甄子丹很有感觉,甄子丹对孙丽也有点感觉。
    画皮定律六:男人终究是要变心的,不管他当初多么爱你,只不过是动手没动手的差别,而且,总是有更年轻的姑娘出现的!!
    
    还有个蜥蜴精追随周迅而来,蜥蜴精爱着狐狸精周迅,周迅不喜欢他。
    画皮定律七:讨厌长得不帅的男人,女人讨厌"长舌头"的男人,讨厌知道自己当年底细的男人,讨厌,吃的东西,跟自己口味不同的男人……之后数条,都是第一条的借口。
    
    
    甄子丹表示自己相信赵薇,赵薇说甄子丹是个好人。
    画皮定律八:如果一个人给你发了"好人卡",基本来说,这个人打算送死你去,吃定你一辈子了。不知道逃的,是傻瓜。
    
    
    周迅想色诱陈坤,蜥蜴精吃醋,进攻陈坤,大闹府里。
    画皮定律九:在两个女人之间摇摆的男人,比较吃香。在两个男人之间摇摆的女人,其实比较危险。女人斗心计,男人斗体力。
    
    
    蜥蜴精又进攻赵薇,关键时刻,陈坤选择去保护赵薇。
    画皮定律十:所有的男人,都会先考虑自己的老婆的,小三们的悲哀…… 其实,不是因为他更看重老婆,而是他的身份促使他必须先救自己的老婆,否则,会被人说,没有人味。
    
    周迅终于明白,陈坤更在乎身为老婆的赵薇。
    画皮定律十一:情人早晚会发现真相的,这个时候,怎么选择,能比较出一个人的智商。
    
    于是周迅直接胁迫赵薇离开,逼赵薇服毒。
    画皮定律十二:偷情的乐趣,就在于偷偷摸摸,有人争抢的感觉比较刺激,直接逼宫……注定是悲剧
    
    …………正邪开始大决战!!
    
    
    
    所谓,凡事,不能十三点。那就到此为止吧。
    
    爱情这种事情,都不能仔细推敲,一推敲,就千疮百孔。

-- 爆音爆食 发布于:2008-09-23 22:37

Saturday, October 04, 2008

js简单继承的实现, 改进篇

前文表述: js简单继承的实现

前文问题:
alert(child instanceof base); 打印false, 此处并没有实现真正的继承

改进:
function base() {
this.member = "dnnsun_Member";
this.test=function(){
window.alert('in base');
}
}

base.prototype.test= function() {
window.alert("base member "+this.member);
}

function extend(child, b) {
b.call(child);
child.prototype=new b;
}
var childclass=function(){
this.test=function(){
window.alert("in child");
}
};


extend(childclass, base);

child = new childclass;

window.alert(child.member);
window.alert(child.test);
child.test();
window.alert(child instanceof base);

不能没有doctype

* 有他的好处, 我这里放下不表, 今天就说说没有他时, 在开发中遇到的问题
   * 在不同的浏览器下网页莫名其妙的布局问题
   * document.body与document.documentElement谁的属性是准的?
      * scrollLeft
* Right
* Top
* Bottom

Saturday, September 13, 2008

Ubuntu下映射windows系统中的硬盘盘符为固定名称, 并且可读写

修改/etc/fstab, 加入映射:
/dev/hda1 /media/c rw,relatime,user_i=0,group_id=0,nosuid,nodev,noatime,allow_other,ntfs 0 0
/dev/hda5 /media/d rw,relatime,user_i=0,group_id=0,nosuid,nodev,noatime,allow_other,ntfs 0 0
/dev/hda6 /media/e rw,relatime,user_i=0,group_id=0,nosuid,nodev,noatime,allow_other,ntfs 0 0
即可

Thursday, September 11, 2008

晒一下用trac打造的任务管理+需求管理平台

- 基础
所需要组件(在http://trac-hacks.org都能找到):
1. Trac 0.11.1 这个是必须的了
2. BatchModify 0.2.0 ticket批量修改工具
3. BreadCrumbsNavPlugin 0.1 最近访问的页面链接
4. ComponentsListMacro 在wiki上列出所有的components
5. PrivateWikis 1.0.0 基于path的wiki权限管理(trac-hacks上的不能工作, 需要修改一下, 需要patch请联系我)
6. TicketBox 0.11.1 在wiki上列出tickets, 可以用来动态生成报告
7. TicketValidator 0.1 ticket字段验证, 比如close状态时, 某个字段不能为空
8. TracAddCommentMacro 0.3 wiki comment插件
9. TracCustomRoadmap 0.4 custom roadmap
10. TracDiscussion 0.6 论坛
11. TracFullBlogPlugin 0.1 博客
12. TracMacroPost 0.2 wiki comment 依赖
13. TracTags 0.6 tag组件, 页面右下角显示tag, 可以形成tag云
14. TracTocMacro 11.0.0.3 Title of Content, 用来形成简洁的wiki页面index
15. TracWysiwyg 0.2 所见即所得wiki编辑器
16. TracXMLRPC 1.0.0 用来支持eclipse mylyn插件的rpc接口
17. Ticket-clone 顾名思义, 用来克隆ticket
18. Testingworkflow 测试工作流
- 用途
* 任务管理
* 增加ticket timing控制字段(开发人员实际用时, PM估计用时, 开发人员估计用时)
* 启用测试工作流
* 自定义扩展Priority中的Delay属性
* 增加
* Urgent
* Middle Term
* Long Term
* 自定义扩展Type属性(New, Bug, Improvement)
* 增加
* Ondemand Feature
* Discussion Feature
* 自定义各种形式的report
* Running Task(正在做的任务)
* Under Testing(等待测试区)
* Urgent Delay(紧急Delay的任务)
* 自定义components
* 增加
* 命名: PM
* 其他必须的component
* 需求管理
* 新需求形成需求ticket, Component=PM的为项目需求, Priority=Urgent/Middle Term/Long Term为讨论优先级
* 讨论通过需求ticket即刻被分解形成任务tickets
* 需求管理报告
* Discussion(等待讨论的需求)
* Wiki
* 管理系统需求, api文档
* 项目的knowledge base
* Blog
* 通知
* 新闻
* team成员原创的技术文章
* Discussion
* 五花八门forum
* 八卦信息


Monday, September 08, 2008

javascript 正则表达式在线测试 (javascript regexp online demo)

javascript regexp online demo http://www.regular-expressions.info/javascriptexample.html
用js需要注意的问题:
1. new RegExp的时候, 要手动转义, 例如: \w应该写成\\w
2. 这种方式var reg=/\w/ig, 不用手动转义
* re = new RegExp("\\w+") 等价于 re = /\w+/
3. test, match和search的区别:
* test:
* regexp对象的方法: 快速的判断给定的str是否匹配pattern
* search:
* string对象的方法: 快速的判断给定的str是否匹配pattern, 只返回第一个匹配的位置
* match:
* string对象的方法: 识别str中所有的pattern, 较前者速度稍慢

Tuesday, September 02, 2008

感觉自己到了珍惜时间的年纪了

以后就要被这些事情所累:
 - 结婚
 - 生子
 - ...

还有好多事情没有干好:
 - design pattern没看完
 - 买的新书没看完
 - python代码研究
 - django web dev
 - english
 - ...

还有好多地方没有去:
 - 大理
 - us
 - 欧洲
 - ...
抓紧时间吧!

Thursday, August 14, 2008

月满西楼

红藕香残玉簟秋
轻解罗裳 独上兰舟
云中谁寄锦书来
雁字回时 月满西楼
花自飘零水自流
一种相思 两处闲愁
此情无计可消除
才下眉头 却上心头

Friday, August 08, 2008

基于svn的cruise control config file

<?xml version="1.0" encoding="UTF-8"?>
<cruisecontrol>
<project name="test">
<bootstrappers>
<!-- 根据本地svn目录check -->
<svnbootstrapper localWorkingCopy="projects/${project.name}" username='yourname' password='yourpassword'/>
</bootstrappers>
<modificationset quietperiod="30">
<!-- 根据本地svn目录查找修改的代码文件 -->
<svn localWorkingCopy="projects/${project.name}" username='yourname' password='yourpassword'/>
</modificationset>
<schedule interval="300">
<!-- 定时构建, 标准ant -->
<ant buildFile="projects/${project.name}/build.xml" antHome="apache-ant-1.7.0" target='all'/>
</schedule>
<log>
<!-- 指定ant build log结果存放目录 -->
<merge dir="projects/${project.name}/target/test-results" />
</log>
<publishers>
<onsuccess>
<!-- 构建成功之后, 将bin移动到指定目录 -->
<artifactspublisher dest="artifacts/${project.name}" file="projects/${project.name}/target/${project.name}.jar" />
</onsuccess>

<!-- htmlemail -->
<!-- email -->
</publishers>
<listeners />
</project>
</cruisecontrol>

Thursday, August 07, 2008

tomcat下单独设置某个app的access log

在project的META-INF目录下添加context.xml文件, 内容:
<Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="appname_localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false" buffered="false"/> </Context>
这样就能够单独设置某个app的access log了

如果把
这一段放到server.xml中, 那么就是记录所有app的access log:
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="appname_localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false" buffered="false"/>

更详细的说明见文档
http://localhost:8080/docs/config/valve.html

Wednesday, August 06, 2008

Django ORM 中ForeignKey生成sql的方式

django根据model的name按照字母序升序排序, 然后依次生成sql, 例如有model A, B, C, 此时A外键引用B, C外键引用B, 则生成的sql即为:
create table app_a(...)
create table app_b(...)
create table app_c(...reference app_b(...))
alter table app_a add foreign key fkey_name reference app_b(...))

Wednesday, July 30, 2008

备份, 同步svn版本库

初始化本地一个空的svn库: svnadmin create /home/lg/repo

从远程库初始化0版本: svnsync init file:///home/lg/repo remote_svn_repo

从远程库同步: svnsync sync file:///home/lg/repo

顺便看看svn的命令, 别整天被UI给宠坏了, 命令行也是很好用的, ^_^

注意:
初始化过程中会有提示你要创建hook, 到/home/lg/repo下的hooks下创建相应的空文件改名为.sh(.bat)加入可执行权限即可

解决连接池获取连接后不能用的问题

连接池8小时断掉的问题确实很烦, 有些连接池的连接自动测试又不管用, 在网上无数的人问这个问题, 说是connection pool的bug云云, 在我看来, 这个应该不是什么问题, 出现这个问题的根源是数据库, 故而直接设置了一下mysql的连接超时时间(当然数据库的连接数是要考虑的),
在mysqld section中加入:
#mysql 自动断掉链接的时间设为十年
wait_timeout=315360000
interactive_timeout=315360000

想必也世界上也没有几台服务器10年不当机, 呵呵

简单的文本搜索, 用ie和firefox默认的功能实现, 代码:


var range="";
if(document.createRange){
    range = document.createRange();
}else{
    range = document.body.createTextRange();
}
if(range.findText){
    while(range.findText("和尚")){
       range.pasteHTML(range.text.fontcolor("#ff0000"));
       range.collapse(true);
    }
}else{
    var s,n;
    s = window.getSelection();
    while(window.find("和尚")){
        var n = document.createElement("SPAN");
        n.style.color="#ff0000"
        s.getRangeAt(0).surroundContents(n);
    }
}

Tuesday, July 29, 2008

app退出时的回调, java有AddShutdownHook, python也有atexit

def goodbye( name, adjective ):
print "goodbye %s %s"%( name, adjective )

def bye(info):

print "printed on exiting", info


import atexit
atexit.register( goodbye, adjective="cat", name="dog")

atexit.register( bye , info="cat")

atexit.register( bye , info="dog")
不过python的回调顺序是添加顺序的逆序!
这里的结果为:
printed on exiting dog
printed on exiting cat

goodbye dog cat

利用python, 构建自己的URLModuleLoader

利用python, 构建自己的URLModuleLoader.
需求:
为了便于客户端的代码更新, 故将module放到了服务器上, 客户端只需要一个简单的run.py, 剩下的问题用URLModuleLoader来搞定!
资源: http://localhost:8080/modules下放置了很多python modules, 举例来说logger.py, etc...

from ihooks import ModuleLoader, ModuleImporter
from urllib2 import urlopen, HTTPError
from urlparse import urljoin
import tempfile
import os

url_path=['http://localhost:8080/modules']

"""URL loader 的实现"""
class URLModuleLoader(ModuleLoader):
def find_module(self, name, path=None):
stub=ModuleLoader.find_module(self, name, path)
if stub:
#print "module :", name, stub
return stub
if path:
return
 """本地module优先, 如果本地没有, 则到服务器上去取"""
for base in url_path:
url=urljoin(base, name+'.py')
try:
file = urlopen(url)
name=tempfile.mktemp()
stream=open(name, 'wb')
stream.write(file.read())
stream.close()
file.close()

file=open(name, 'r')
#print "module :", url
return file, url, ('.py', 'r', 1)
except HTTPError, e:
#print e
return None

"""实现importer"""
class URLImporter(ModuleImporter):
def __init__(self):
hooks, verbose=(None, 1)
loader=URLModuleLoader(hooks, verbose)
ModuleImporter.__init__(self, loader, verbose)


"""设置自己的module loader"""
URLImporter().install()

"""测试"""
if __name__=="__main__":
import logger
import re
import base64
logger.log("logger loaded from remote packages")
logger.log("logger infomation demo")

urls中pattern可以简写

from django.conf.urls.defaults import *

urlpatterns = patterns('',
(r'^$', "main.views.index"),
(r'^contact-us/$', "main.views.contact_us"),
)

可以简写为:
from django.conf.urls.defaults import *

urlpatterns = patterns('main.views',
(r'^$', "index"),
(r'^contact-us/$', "contact_us"),
)
pattern的第一个参数是一个前缀

Tuesday, July 22, 2008

Rasphone - Dial up Networking (RAS) - 已使用 Google 工具栏发送

Rasphone - Dial up Networking (RAS)


RASPHONE (Dial Up Networking)

Manage Remote Access Service (RAS) connections.
This is a part of the Dial-Up Networking service, typically used to connect a PC to an Internet Service Provider.

 Dial a RAS connection:
RASPHONE [-v] -f
PhoneBook_file
-d "
PhoneBook_entry
"

Hang up a RAS connection:
RASPHONE [-v] -f
PhoneBook_file
-h "
PhoneBook_entry
"

Display RAS Status dialogue box
RASPHONE -S

Other RAS options:
RASPHONE [-v] -f
PhoneBook_file

options
"
PhoneBook_entry
"

OPTIONS
-a : Add new PhoneBook entry
-e : Edit an existing PhoneBook entry
-c : Clone an existing PhoneBook entry
-r : Delete/remove an existing PhoneBook entry
-v : Disable - 'grey out' the option to rename the PhoneBook_entry

To use this command requires that Dial Up Networking Service be installed (via Control Panel - Networking)

The default location for PhoneBook entries is %SystemRoot%\System32\ras\

"Someone invented the telephone, And interrupted a nation's slumber, Ringing wrong but similar numbers" - Ogden Nash

Related Commands:

RASDIAL - Manage RAS connections
Connection Manager Administration Kit - VPN connections ( 2003 Resource Kit)
RASMON - Windows 2000 GUI Resource Kit tool
CHECKRAS - SMS support tools

apple store opened at 7.19

7.19正好同学来北京玩, 没空去参加apple的开业大典, 听apple店员说盛况空前啊, 7000多人, 鲁豫等人也去了,
总算是在apple开业第二天, 也就是周日得来空闲, 草草洗刷完毕, 吃完早饭, 就直奔三里屯village, 117路4站就到, 下车之后首先看到三里屯 village的主楼, 很酷的样子, 然后是adidas的大型卖场, 不知不觉往前边走, 抬眼一看, 竟然到了apple的后门! 竟然这样到了apple, 本来还打算好好找一通呢.
还好, 来的早, 人不是太多, 看了一通ipod, 试用了一下ipod touch之后, 就直奔主角而去 - macbook pro, 赞美之词就省了吧, 总想夸夸mb, 算了, 我也别说了, 怕一说就停不下来, 呵呵, 不知不觉就到了15点, 我也该回家了, 有空再来体验一下genius bar, 预约一个apple genius陪我聊聊pro..., 该睡觉了,
最后, 看看我用烂技术拍的艺术品: http://picasaweb.google.com/xlty.0512/Apple720

北京烤鸭, 哈好吃

    这次的烤鸭个够大, 三个人愣是没吃完, 多亏鸭架汤上的太慢, 我们及时给要了回来, 打包回家, 烤鸭子总是那么的好吃啊. 慢慢感觉到生活的意义了, 呵呵.
    有点怀念全聚德的鸭皮沾白糖了, 好吃!
    picasa地址, 看看我拍的烤鸭和美味:  http://picasaweb.google.com/xlty.0512/dtzfDL

Sunday, July 20, 2008

研究了一通数字的格式化方法, 原来有个Number(num).toLocaleString()

Number(34443243244).toLocaleString() -> "34,443,243,244"

获取dom元素的绝对位置

function getPosition(ele){
var nTop = ele.offsetTop;
var nLeft = ele.offsetLeft;
while((ele = ele.offsetParent)!=null)
{
nTop += ele.offsetTop;
nLeft += ele.offsetLeft;
}
return {top:nTop,left:nLeft}
}

从dom书中获取某个元素的绝对位置, 跨浏览器IE, Firefox

Tuesday, July 15, 2008

用js动态实现图片热区

代码如下:
<html>
<body>
<button onclick="init();">init</button>
<img src='20080319_96325f230767e6ac385beuTiIglWzzkf.png' border=0 usemap='#Map'>
<map name="Map" id="MAP"></map>
<div id="maskDIV"></div>
<script language="JavaScript">
var maskDiv;
function mask(param){
if (!maskDiv)
{
maskDiv = document.getElementById('maskDIV');
maskDiv.style.position='absolute';
maskDiv.style.backgroundColor="red";
//document.appendChild(maskDiv);
}
maskDiv.innerHTML=param.title;
maskDiv.style.left=param.left+"px";
maskDiv.style.top=param.top+"px";
}

function init(){
var oAREA = document.createElement('AREA');
oAREA.shape = 'rect';
oAREA.coords = '0,0,225,299';
oAREA.href = 'showcity.aspx?cityid=10600';
oAREA.alt = '北京市西城区';
oAREA.title = '北京市西城区';
oAREA.onmouseover=function(e){
mask({left:e.clientX,top:e.clientY,title: oAREA.title});
}
document.getElementById("MAP").appendChild(oAREA);
}
</script>
</body>
</html>

好了, 技术问题搞定, 剩下的就是你的发挥了!

Sunday, July 13, 2008

重写django的FilterSpec来实现filter tag的数据自定义

重写django的FilterSpec来实现filter tag的数据自定义, 注意FilterSpec的register始终将新加的test function和factory的tuple放到registered list的最后, 但是当FilterSpec查找model匹配的FilterSpec的时候是顺序遍历的, 所以当在FilterSpec中只要有一个test function返回True, 那么model就用这个, 就是说model一直用第一个匹配的FilterSpec, 所以就有了下边的insert_first_filter_spec.

from django.contrib.admin.filterspecs import FilterSpec

def insert_first_filter_spec(test,factory):
FilterSpec.filter_specs.insert(0,(test,factory))

class AdvancedChoicesFilterSpec(FilterSpec):
def __init__(self, f, request, params, model):
super(AdvancedChoicesFilterSpec, self).__init__(f, request, params, model)
self.lookup_kwarg = '%s__exact' % f.name

make models's field default value to default filter
self.lookup_val = request.GET.get(self.lookup_kwarg, None) or self.field.default

def choices(self, cl):
yield {'selected': self.lookup_val is None,
'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
'display': _('All')}
for k, v in self.field.choices:
yield {'selected': str(k) == self.lookup_val,
'query_string': cl.get_query_string({self.lookup_kwarg: k}),
'display': v}

replace choices tag factory
insert_first_filter_spec(lambda f: bool(f.choices), AdvancedChoicesFilterSpec)

吓了一跳

看了自己的博客更是吓了一跳, 完全没有主观思想, 就是技术和记录!

这只是一份工作而已, 不是么?

每天对着电脑, 我的生活早己离不开它, 思维也慢慢的变的computer, 每天一成不变的check and read -- email, feed, blog, 期望看到, 发现一些感兴趣的事务, 文章, 思想, 但是看到, 发现了之后呢, 就又变得像机器一样learn it, 慢慢补充自己的知识储备, 而生活也慢慢变的一成不变, 像机器一般的生活, 简直是一个"机器人"了.
直到长假后回公司的第一天, 这么久没有看到满屏显示的code, 异常兴奋, 下意识的去拿鼠标, 然手下一阵失落传来, 紧跟着就是大脑的一阵惊慌, where is my mouse? why i am so afraid? 那一刻忽然想起人们经常谈论的话题: 没有电脑我们该怎么办?
""没有硝烟中的scrum和xp"" 作者提到一句话:
哦, 最后请不要忘记......
这只是一份工作而已, 不是么?

Friday, July 11, 2008

兼容各浏览器的Flash播放器封装: swfobject.js

这里下载最新版的SWFObject:http://blog.deconcept.com/swfobject/swfobject_source.js

用它的好处主要有:
1.IE中没有讨厌的虚框问题了。
2.提供了完善的版本检测功能,如果版本不够则显示其他东西,比如图片或文字。
3.易于使用,只要在页面头加载一个 .js 文件,然后 HTML 写一个容器,里面放普通的文本或图片(用于无法显示 Flash 时显示),最后 用脚本来替换这个元素里面的内容为 Flash。
4.可以通过验证——当然这个不是重点,只是顺带效果罢了。

只需要包含 swfobject.js这个js文件,然后在DOM中插入一些简单的JS代码,就能嵌入Flash媒体资源了。 下面是一个最简单的范例:

<script type="text/javascript" src="swfobject.js"></script>

<div id="flashcontent">
This text is replaced by the Flash movie.
</div>

<script type="text/javascript">
var so = new SWFObject("movie.swf", "mymovie", "200", "100", "7", "#336699");
so.write("flashcontent");
</script>

"ago filter" / date tag filter - django snippet

from django import template
from StringIO import StringIO

register = template.Library()

@register.filter_function
def date_tag(path, tags):
"""
{{ "/recent/"|date_tag:"0,1,2,3" }}
"""
html = StringIO()
if path:
path = path.strip()
else:
path=""
tags = [x.strip() for x in tags.split(',')]
for tag in tags:
if tag == "0":
html.write('<a href="%s%s/">%s</a><br>' % (path,tag,"today"))
elif tag == "1":
html.write('<a href="%s%s/">%s</a><br>' % (path,tag,"yesterday"))
else:
html.write('<a href="%s%s/">%s</a><br>' % (path,tag,tag+" days ago"))
return html.getvalue()

===================================
usage:
1. put this code to app/templatetags directory, named tags.py
2. load tags into template: {% load tags %}
3. use filter

Wednesday, June 25, 2008

[转] Module Dialog In IE & FF

原文: http://www.zhangsichu.com/blogview.asp?Content_Id=50

本文实现了一个在IE和FF下都可以正常使用的ModuleDialog。
主要使用window.open方法打开Dialog。
使用window.onclick=function (){DialogWin.focus()};和event.cancelBubble = true;保证弹出窗口的Module样式。
详细内容:
ParentWindow
function OpenDialog()
{
if(window.document.all)//IE
{
//参数
var strPara = "dialogHeight:200px;dialogWidth:300px;help:off;resizable:off;scroll:no;status:off";
//传入的值
var strPassIn=window.document.getElementById("txtReturn").value;
//打开模态对话框
var strReturn=window.showModalDialog("ChildOpenWindow.htm",strPassIn,strPara);
//处理返回值
if(typeof(strReturn) != undefined)
{
window.document.getElementById("txtReturn").value=strReturn;
}
}
else//FireFox
{
//参数
var strPara = "dialogHeight:200px;dialogWidth:300px;help:off;resizable:off;scroll:no;status:off;modal=yes;dialog=yes";
var strPassIn=window.document.getElementById("txtReturn").value;

//注册事件
window.myAction=this;

//打开窗口
var DialogWin = window.open("ChildOpenWindow.htm","myOpen",strPara,true);

//传入参数
window.myArguments=strPassIn;

this.returnAction=function(strResult){
//处理返回结果
if(typeof(strResult) != undefined)
{
window.document.getElementById("txtReturn").value=strResult;
}
}

//处理打开窗口最上显示(不完美)
window.onclick=function (){DialogWin.focus()};
event.cancelBubble = true;
}
}

ChildWindow
function window_onload()
{
if(window.document.all)//IE
{
//对于IE直接读数据
var txtInput=window.document.getElementById("txtInput");
txtInput.value=window.dialogArguments;
}
else//FireFox
{
//获取参数
window.dialogArguments=window.opener.myArguments;
var txtInput=window.document.getElementById("txtInput");
txtInput.value=window.dialogArguments;
}
}

function OnOKClick()
{
//对于IE或者FireFox都需要设置returnValue进行返回值设定
var inputStr=window.document.getElementById("txtInput").value;
returnValue=inputStr;
window.close();
}

function window_onunload() {
//对于Firefox需要进行返回值的额外逻辑处理
if(!window.document.all)//FireFox
{
window.opener.myAction.returnAction(window.returnValue)
}
}
</script>
注册onload
<body language="javascript" onload="return window_onload()" onunload="return window_onunload()">

Monday, June 23, 2008

本地的html如何请求remote server的资源

本地的html文件内的ajax请求如果用异步的话, 通常readyState值返回为1或者是2, 而不是期望的4,
此时将ajax的异步改为同步即可, 此时get/post都是允许的.

Saturday, June 21, 2008

一个机器学习library: Lucene Mahout

Lucene最近新加了2个子项目Tika和Mahout, Tika前文介绍过, Mahout是一个机器学习的library, 包含: Classification, Clustering, Regression, Dimension reduction, ..., 可以看出lucene的野心

Apache 新出的工具文档解析器Tika

Apache 新出的工具文档解析器Tika, 可以支持ms系列, pdf, html, ..., 目前版本是0.1, 需要解析多种文档的同志们的福音啊

Friday, June 20, 2008

web.xml中的3种写法

web.xml中<url-pattern>的3种写法

a 完全匹配

<url-pattern>/test/list.do</url-pattern>

b 目录匹配

<url-pattern>/test/*</url-pattern>

c 扩展名匹配

<url-pattern>*.do</url-pattern>

servlet-mapping的重要规则:

容器会首先查找完全匹配,如果找不到,再查找目录匹配,如果也找不到,就查找扩展名匹配。
如果一个请求匹配多个"目录匹配",容器会选择最长的匹配。

css实现Tag云的两端对齐方式,

HTML Align
text-align:justify;text-justify:distribute-all-lines;

用css画个图标

用css画个图标出来 #com_a{ border-top:10px solid #FFFFCC;border-left:5px solid #FF3300;border-bottom:10px solid #FFFFCC;}

开源, 免费的安装程序制作工具, 可以支持Delphi脚本

下载地址: http://www.jordanr.dhs.org/isinfo.php

js简单继承的实现

function base() {
this.member = "dnnsun_Member";
this.method = function() {
window.alert(this.member);
}
}
function extend(child, b) {
b.call(child);
}
var child={
test:function(){
window.alert("in child");
window.alert(child.member);
}
};
extend(child, base);
window.alert(child.member);
window.alert(child.method);
child.test()

Sunday, June 15, 2008

getElementsByTagName返回值的问题

nodesList=getElementsByTagName返回的是一个类似NodeList的对象, 并且它的结果集动态的随元素的变化而变化, 例如将一个匹配的node从dom中remove时, 结果集将自动的remove此node,因此如果用
for (var i=0;i=nodesList.length;i++){
var node = nodesList[i];
node.parentNode.replaceNode(newNode,node);
}就遍历不完, 但是如果用for (var i=nodesList.length-1;i>=0;i--){...}就可以

Enjoy Euro 2008

Enjoy Euro 2008

Wednesday, February 27, 2008

[转贴] 从Larbin看互联网爬虫设计

互联网是一个庞大的非结构化的数据库,将数据有效的检索并组织呈现出来有着巨大的应用前景,尤其是类似RSS的以XML为基础的结构化的数据越来越多,内容的组织方式越来越灵活,检索组织并呈现会有着越来越广泛的应用范围,同时在时效性和可读性上也会有越来越高的要求。这一切的基础是爬虫,信息的来源入口。一个高效,灵活可扩展的爬虫对以上应用都有着无可替代的重要意义。
要设计一个爬虫,首先需要考虑的效率。对于网络而言,基于TCP/IP的通信编程有几种方法。
第一种是单线程阻塞,这是最简单也最容易实现的一种,一个例子:在Shell中通过curl,pcregrep等一系统命令可以直接实现一个简单的爬虫,但同时它的效率问题也显而易见:由于是阻塞方式读取,dns解析,建立连接,写入请求,读取结果这些步骤上都会产生时间的延迟,从而无法有效的利用服务器的全部资源。
第二种是多线程阻塞。建立多个阻塞的线程,分别请求不同的url。相对于第一种方法,它可以更有效的利用机器的资源,特别是网络资源,因为无数线程在同时工作,所以网络会比较充分的利用,但同时对机器CPU资源的消耗也是比较大,在用户级多线程间的频繁切换对于性能的影响已经值得我们考虑。
第三种是单线程非阻塞。这是目前使用的比较多的一种做法,无论在client还是server都有着广泛的应用。在一个线程内打开多个非阻塞的连接,通过poll/epoll/select对连接状态进行判断,在第一时间响应请求,不但充分利用了网络资源,同时也将本机CPU资源的消耗降至最低。这种方法需要对dns请求,连接,读写操作都采用异步非阻塞操作,其中第一种比较复杂,可以采用adns作为解决方案,后面三个操作相对简单可以直接在程序内实现。
效率问题解决后就需要考虑具体的设计问题了。
url肯定需要一个单独的类进行处理,包括显示,分析url,得到主机,端口,文件数据。
然后需要对url进行排重,需要一个比较大的url Hash表。
如果还要对网页内容进行排重,则还需要一个Document Hash表。
爬过的url需要记录下来,由于量比较大,我们将它写到磁盘上,所以还需要一个FIFO的类(记作urlsDisk)。
现在需要爬的url同样需要一个FIFO类来处理,重新开始时,url会从定时从爬过的url FIFO里取出来,写到这个FIFO里。正在运行的爬虫需要从这个FIFO里读数据出来,加入到主机类的url列表里。当然,也会从前一个FIFO里直接读url出来,不过优先级应该比这个里面出来的url低,毕竟是已经爬过的。
爬虫一般是对多个网站进行爬取,但在同时站点内dns的请求可以只做一次,这就需要将主机名独立于url,单独有一个类进行处理。
主机名解析完成后需要有一个解析完成的IP类与之应用,用于connect的时候使用。
HTML文档的解析类也要有一个,用来分析网页,取出里面的url,加入到urlsDisk。
再加上一些字符串,调度类,一个简单的爬虫基本上就完成了。
以上基本上是Larbin的设计思路,Larbin在具体实现上还有一些特殊的处理,例如带了一个webserver,以及对特殊文件的处理。 Larbin有一点设计不不太好,就是慢的访问会越来越多,占用大量的连接,需要改进,另外如果对于大规模的爬虫,这仅仅实现了抓取的部分,要分布式的扩展还需要增加url的集中管理与调度以及前台spider的分布式算法。

Tuesday, February 26, 2008

[转贴]Flash 视频(FLV)编码,转换,录制,播放方案一网打尽

[客户端编码工具(Client-Side-FLV-Encoding)
场景:拿到一个 MPG 或 AVI 文件,打算在个人电脑上转换成FLV.
1,Sorenson Squeeze
2,Riva FLV Encoder
3,Turbine Video Encoder
4,Flix Exporter
5,SWiSH Video
6,Flash 自带的Flash Video Exporter



服务器端转换工具(Server-Side-FLV-Conversion)
场景:想把 MPG 或 AVI 上传到你的服务器并自动转换成 FLV 吗?
1,FFmpeg | 教程一 | 教程二(Google Video 使用的就是这个东东.)
2,Flix Engine | 教程 | 范例
3,Turbine Video Engine
4,Video to Flash Console



录像/实时广播(Record/Broadcast)
场景:想制作一个语音视频Blog满足自恋的欲望吗?
1,RED5
2,Flash Media Server

在线编码,分享视频(Online Encode & Share)
场景:想不花钱就可以在线分享你的视频吗?
1,Google Video
2,You Tube
3,iFilm

本地 FLV 文件播放器(FLV Player)
场景:拿到了 FLV 文件不知道怎么播放了.
1,martijndevisser FLV Player
2,FlashGuru FLV Player
3,FCZone FLV Player

在线 FLV 文件播放器(Online FLV Player)
场景:知道一个在线FLV地址,又懒得下载和安装播放器.
1,Loadr
2,Google Player Generator

一个iptables脚本

一个iptables脚本

etho 接外网──ppp0
eth1 接内网──192.168.0.0/24


#!/bin/sh
#
modprobe ipt_MASQUERADE
modprobe ip_conntrack_ftp
modprobe ip_nat_ftp
iptables -F
iptables -t nat -F
iptables -X
iptables -t nat -X
###########################INPUT键###################################
iptables -P INPUT DROP
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 110,80,25 -j ACCEPT
iptables -A INPUT -p tcp -s 192.168.0.0/24 --dport 139 -j ACCEPT
#允许内网samba,smtp,pop3,连接
iptables -A INPUT -i eth1 -p udp -m multiport --dports 53 -j ACCEPT
#允许dns连接
iptables -A INPUT -p tcp --dport 1723 -j ACCEPT
iptables -A INPUT -p gre -j ACCEPT
#允许外网vpn连接
iptables -A INPUT -s 192.186.0.0/24 -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i ppp0 -p tcp --syn -m connlimit --connlimit-above 15 -j DROP
#为了防止DOS太多连接进来,那么可以允许最多15个初始连接,超过的丢弃
iptables -A INPUT -s 192.186.0.0/24 -p tcp --syn -m connlimit --connlimit-above 15 -j DROP
#为了防止DOS太多连接进来,那么可以允许最多15个初始连接,超过的丢弃
iptables -A INPUT -p icmp -m limit --limit 3/s -j LOG --log-level INFO --log-prefix "ICMP packet IN: "
iptables -A INPUT -p icmp -j DROP
#禁止icmp通信-ping 不通
iptables -t nat -A POSTROUTING -o ppp0 -s 192.168.0.0/24 -j MASQUERADE
#内网转发
iptables -N syn-flood
iptables -A INPUT -p tcp --syn -j syn-flood
iptables -I syn-flood -p tcp -m limit --limit 3/s --limit-burst 6 -j RETURN
iptables -A syn-flood -j REJECT
#防止SYN攻击 轻量
#######################FORWARD链###########################
iptables -P FORWARD DROP
iptables -A FORWARD -p tcp -s 192.168.0.0/24 -m multiport --dports 80,110,21,25,1723 -j ACCEPT
iptables -A FORWARD -p udp -s 192.168.0.0/24 --dport 53 -j ACCEPT
iptables -A FORWARD -p gre -s 192.168.0.0/24 -j ACCEPT
iptables -A FORWARD -p icmp -s 192.168.0.0/24 -j ACCEPT
#允许 vpn客户走vpn网络连接外网
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -I FORWARD -p udp --dport 53 -m string --string "tencent" -m time --timestart 8:15 --timestop 12:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP
#星期一到星期六的8:00-12:30禁止qq通信
iptables -I FORWARD -p udp --dport 53 -m string --string "TENCENT" -m time --timestart 8:15 --timestop 12:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP
#星期一到星期六的8:00-12:30禁止qq通信
iptables -I FORWARD -p udp --dport 53 -m string --string "tencent" -m time --timestart 13:30 --timestop 20:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP
iptables -I FORWARD -p udp --dport 53 -m string --string "TENCENT" -m time --timestart 13:30 --timestop 20:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP
#星期一到星期六的13:30-20:30禁止QQ通信
iptables -I FORWARD -s 192.168.0.0/24 -m string --string "qq.com" -m time --timestart 8:15 --timestop 12:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP
#星期一到星期六的8:00-12:30禁止qq网页
iptables -I FORWARD -s 192.168.0.0/24 -m string --string "qq.com" -m time --timestart 13:00 --timestop 20:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP
#星期一到星期六的13:30-20:30禁止QQ网页
iptables -I FORWARD -s 192.168.0.0/24 -m string --string "ay2000.net" -j DROP
iptables -I FORWARD -d 192.168.0.0/24 -m string --string "宽频影院" -j DROP
iptables -I FORWARD -s 192.168.0.0/24 -m string --string "色情" -j DROP
iptables -I FORWARD -p tcp --sport 80 -m string --string "广告" -j DROP
#禁止ay2000.net,宽频影院,色情,广告网页连接 !但中文 不是很理想
iptables -A FORWARD -m ipp2p --edk --kazaa --bit -j DROP
iptables -A FORWARD -p tcp -m ipp2p --ares -j DROP
iptables -A FORWARD -p udp -m ipp2p --kazaa -j DROP
#禁止BT连接
iptables -A FORWARD -p tcp --syn --dport 80 -m connlimit --connlimit-above 15 --connlimit-mask 24 -j DROP
#只允许每组ip同时15个80端口转发
#######################################################################
sysctl -w net.ipv4.ip_forward=1 &>/dev/null
#打开转发
#######################################################################
sysctl -w net.ipv4.tcp_syncookies=1 &>/dev/null
#打开 syncookie (轻量级预防 DOS 攻击)
sysctl -w net.ipv4.netfilter.ip_conntrack_tcp_timeout_established=3800 &>/dev/null
#设置默认 TCP 连接痴呆时长为 3800 秒(此选项可以大大降低连接数)
sysctl -w net.ipv4.ip_conntrack_max=300000 &>/dev/null
#设置支持最大连接树为 30W(这个根据你的内存和 iptables 版本来,每个 connection 需要 300 多个字节)
#######################################################################
iptables -I INPUT -s 192.168.0.50 -j ACCEPT
iptables -I FORWARD -s 192.168.0.50 -j ACCEPT
#192.168.0.50是我的,全部放行!