作者存档: Alex Hwang

凄风苦雨学彷徨 – 方舟子 1989-1990 书信摘录

转:

凄风苦雨学彷徨       – 方舟子 1989-1990 书信摘录

·方舟子·

年少自轻狂

不费思量

凄风苦雨学彷徨

最是仓惶离国日

一样风光

 

往事已茫茫

梦醒愁长

江山无限苦情伤

芳草连天霜后绿

莫向残阳

 

——调寄《浪淘沙》

 

(一)一九八九年八月十四日致WY

 

   在家休息一个多月,不得不又来容忍合肥的炎热,因为要参加GRE考试。这次科大报考GRE的人数是创纪录的。为了能领到表,大家挤着,嚷着,抢着,都成了名副其实的暴徒。就象一群遭遇海难的旅客,完全失去了自救和救援的希望,都拼命往小小的救生艇上挤。

   而我就是其中的一个。虽然我知道同样是人类社会,美国也未必就比中国好多少。但是我现在所能作的——或者说是赖以生存下去的支柱——也只能是如此。就象《野草》中的过客,虽然明知前方只有坟,也只能不带任何希望地向它走去。明年不成就再等一年、两年,总之非去看个明白不可。如果命中注定了我只能留在中国,那么我就找个小地方,安安静静、浑浑噩噩地活下去,把所有的才华和棱角都埋葬掉。这样的生活未必就不好,虽然对我来说这很难办到。

   在家又翻了翻鲁迅的著作。经过了一场“血与火的洗礼”,也就更感到鲁迅伟大得可怕,就象一位先知。而到社会的基层了解民众对这次运动的见解,又提供了许多悲哀的例证。对民族的根源和国民的德性了解得越透彻就越觉得悲凉无比。是的,我已经没有了普渡众生的豪情壮志了(那十八岁少年的骄傲哪里去了呢?),只能先解脱了自己。我很敏感,也许预感也颇好,就象一只小老鼠,预见到地震将临,自己的家园将毁于一旦,却除了逃走之外别无他法。

   回家前写了封信,不知收到没有。这是传几条夸大的消息都会入狱十年的时候,倘那封信你没收到,我大概只能在监狱中了却余生了(你瞧,我变得多么胆小)。科大抓走了两个,管制了四十八个,很幸运都轮不到我(恐怕要把科大人全抓光才能挖到我这个暗藏的分子)。下学期减少招生百分之二十五,只要不是减少百分之百,想要阻止现代思想的传递就只是一厢情愿。他们所能作的,不过是洗脑和把新生隔离开而已。

(二)一九八九年九月十四日致WY

   这几天被迫参加洗脑,之后还要抓紧时间学英语,没有别的心思干别的事情。今天是中秋,趁机轻松一下,第一个想到的是该给你回信了。

 

   现在下着雨,见不到月亮。即使是晴天,我也未必会装模作样地去赏月。我是近视的,月亮于我只是模糊的一团。戴上眼镜吧,我又怀疑见到的不是它真实的模样。毕竟,美丽的儿时月亮是再也见不到了。

   我真的会颓废下去吗?发发牢骚而已。我这样的人是至死也不会颓废的。按中国颓废派的老例,第一是要烂醉如泥。但我虽会喝一点酒,却不爱喝酒,而且许是自制力强的缘故,绝不会喝醉的。“眼见人尽醉,何忍我独醒”,我却偏偏不得不醒着,没办法,怎么也醉不了。 

   第二,是要装糊涂。但我偏偏太重理性,眼见不平,即使嘴上不说,心里也腹诽不已,而且怒形于色。无论如何也糊涂不起来。这就注定了我特别痛苦。

   你瞧,儿时的月亮在我的记忆中是何等美丽,后来变成了模糊的一团,现在却是消失得无影无踪了。而我却无法装模作样地去赏月,对别人赞叹说:“今晚的月光很好。”颓废派是应该这样的,可是我办不到。可是现在有人逼着我表态赞颂现在的月亮,我当然只有逃了。至于是否美国的月亮真的比中国的圆,倒是无关紧要的。

 

   很惭愧,已很久没有写诗的冲动了。整天读英文,对汉语的应用也不怎么自如了,所以我曾开玩笑说要学着用英文写诗。翻翻旧作,最近的一首也写于一个多月前了。写得实在不怎么样,但颇能表达现在的心境。形式是无关紧要的,重要的是内容。因为不再为发表而写作,也就不为了“艺术性”的缘故玩些吓人的花样,不如坦诚地撇开一切来得痛快。当然还未到如你们报社的那位同仁那样大呼口号的地步,因为我的内心要复杂得多。

   你们报社的另一位同仁曾说我的写诗是属于青春期的躁动。我当时付之一笑。我的内心确实躁动不已,只是我小心翼翼地用理性压抑着,再小心翼翼地让它们在诗中得到表达。如果我能在其他事情上得到宣泄,就不必乞灵于诗了。但最后的结果可能是这种躁动将持续一生,诗也就将伴随我一生。

 

(三)一九八九年十一月一日致HR

 

   我生日那天,我们又在“湘皖”吃了一顿,加上AL的女友,仍是五个。当然,没有你,便少了许多欢乐,因此大家都挺想念你的。《荒原》现在算是寿终正寝了,这是由国内的大气候和科大的小气候决定的。我们在一起的日子实在是它最繁荣的时候,而标志其繁荣的就是上四楼编稿和下“湘皖”。

  10月14日考了GRE,自我感觉很好。一直有传闻说要加强对自费留学的限制,但至今未得证实。不管怎样,我已没有退路了,因为应届毕业生除了不到百分之十保送外,其他一律工作两年才准报考研究生。对这一决定最感悲伤的可能是老师,本来就招不到研究生,这回就更难了。

   开学后停课政治学习两周,然后是表态、忏悔、汇报自己在五十天的表现,文革想必也不过如此。因为事关前途,所以大家都装得很乖,良心竟没丝毫的不安。科大收审了两个:MR和GTS,据说均遭毒打。监视了六个,其中一个即是白。近百名上了学习班,包括MR的妹妹(MR一家全部遭殃,人称“革命家庭”)。WYK先是被撤销一切职务,然后是隔离审查,前几天听说被抓进了公安局。ZH公司也被撤销了。

   据说是要整顿校风,接连开除了好几个学生。请了几个合肥小痞子成立公安局的科大分局,一时人心惶惶。前几天中国足球队赢了一场球,大家不过狂喊几声而已,还没摔瓶子呢,结果那几个小痞子吹一阵哨子,竟然就鸦雀无声。真令我感到难过。科大的自由至此是消失殆尽了。幸好我也呆不了几天了。中旬就要到北京作毕业论文,去体验体验戒严的气氛。

   曾经计划考完GRE之后就连写几天诗,至今却半句也写不出来。那一点文学才华已经被英语单词、基因和酶挤掉了。我不知道应该值得庆幸还是该觉得可悲?我也不知道我生命中的这一部分是否会真的因此永远离我而去。近日翻翻《荒原》,翻翻旧作,总倍感亲切,这也许就是它们的价值所在了。开学初科大照例来一次卖旧书热,居然有人把《荒原》之类的旧刊物也拿出来卖。我留心了好长一段时间,却不见有人问津,连翻也没人翻,简直是不屑一顾。我想如果是在几年前,如果我是新生,即使不买也会翻翻的。真正是一代不如一代,科大的诗坛到此绝种,我那句名言“我们是科大最后一代诗人”竟成谶语,呜呼!

 

(四)一九八九年十一月二十二日致HR

   我到北京恰好一周。住在研究生院,每天早上六点半动身前往研究所,晚上六点半才回校,花在搭车的时间有两个多小时——如能加以利用,这两个多小时倒是写诗的好时候,可惜我现在是一点创作灵感也没有了。赶车、查阅文献、做实验瓜分了我的生活,至多偷闲看看闲书,吹吹牛。人一旦如机器人一般地生活,是绝对不会空虚的,但其代价是失去了人性的另一半。

 

   SF跟我一起上北京联系工作,已于昨日回校,其结果似乎还不错。星期天一起游了北海,然后我一个人去寻找鲁迅博物馆。千辛万苦!北京人知道这个地方的似乎不多,恐怕再过几年连鲁迅是何许人也很少有人知晓了。陈列室据说是在施工维修,不开放,但不见有大动土木的样子,我只能把这当作偷懒不上班的借口。但偷懒得也并非全无道理,因为那地方现在是几乎无人去的,现在的老师大概也不会带学生到那里接受教育。整个下午我只碰到一位拜谒者(大学生模样),寂寥之极,加上满地的落叶无人打扫,我踏碎它们时发出的沙沙声在我听来如先生绝望的呐喊,无比悲壮,令人几至泪下。我就这样在院子里到处乱转,隔着玻璃观看先生的故居,我所挚爱的《野草》就是在这里写出来的,我似乎早已来过,感到非常的亲切,一时间热血沸腾,但终未成章。

   我本来是把在北京的半年作为我对国内生活的最后体验的,但现在听说已有文件下达严禁出国留学,果真如此,我倒不如“破罐破摔”,干脆在北京呆下去,活得潇洒点。或者回家乡,学着平平庸庸、安安分分地作人。我至今还不知道该如何选择我的未来。其实选择也没用,一纸命令就让你玩完。

又:据悉WYK现被囚禁于北京。

(五)一九八九年十二月七日致HR

 

   收到信时正忙着纯化蛋白质,读完信恍惚了一会,一回神才发觉蛋白已跑了不少。最近做实验老走神,极不顺利。然而我正是崇尚“知其不可而为之”,愈受挫折愈觉有味,是故仍干得起劲。且人缘还不坏,宛如经过了脱胎换骨,重新做人:活泼可爱,和蔼可亲,活脱脱一个受女孩青睐的那种俗男子。说不定我会打破誓言,在这里收一个女朋友呢?

   刚刚跟系党总支书记“谈了心”,他是来出差,顺便落实我的毕业去向的。我的回答倒挺简单:研究生不读,工作吗自己找。我班的托派已有不少倒戈的了,而我仍不看风使舵,坚定不移,真正是死不改悔。能出国则搞研究,出不了国则随便到哪混口饭吃,决不走中间道路。抱定了大不了当临时工的决心,反而心安理得。这一次的谈心是使我再次面对现实:马上就要毕业了。在这样的国度,这是最痛苦、最残酷的现实。象牙塔外是酱缸,我必须走出去了。

  我的立志出国,究竟是为了逃避责任,还是为了解脱自己,或者是为了到另一世界看个究竟,不至于对人生太感绝望?不知道。但有一点是肯定的:总有一天我终将归来,不管以什么方式(如果能出去的话),因为在我的内心深处可悲地无可奈何地深爱着这个多灾多难一点也不可爱的民族,悲悯她的前途,然而仇恨她的现在。悲剧是我只能看着我的爱人一步一步走向深渊却无能为力。六月的惨剧只是她积四十年之久的又一次垂死挣扎而已,而其结果不过再一次证明了她的不可救药。因此我只得走了,或者转过脸去。我还没有堕落到在她的棺材上狂欢等着瓜分她的尸体,也无法高尚到与她殉葬。

 

   爱是无理性的(我找不到一条爱的理由),恨是理性的。这两者交织在一起便形成了绝望与反抗的主旋律,这在六十年前已由鲁迅演奏过了,难道我在今天还要继续演奏下去?然而我何德何能?有什么能耐?我实在是连一点病根都找不出来(我只能凭感觉说她已病入膏肓),更别说开出哪怕一剂药方了,因此也就加倍地痛苦。

   我不相信这种痛苦只属于我们这一代。每一代中的高尚者都真诚地希望民族的苦难在自己的手中结束,甘愿为下一代的幸福作出牺牲。就连鲁迅也自欺欺人地打气说要扛着黑暗的闸门,把下一代放到光明的天地去。然而直至现在我们仍扛着这道闸门,而且份量越来越重,而且会子子孙孙扛下去,直到闸门重重合上的那一天。

   开学初,曾有一朋友打电话问候老W。老W当时还在校接受审查,很是感动,然而不希望有人效法,以免株连。不久老W即被关在科学岛的一个小黑屋,与外界断绝了联系。然后是进了合肥公安局,最后是押到精英汇集的北京秦城监狱。牢友中有声学研究所的C校友,当年毛诗词的“伪造者”,二进秦城,真是莫大的讽刺。他的妻子就在我的隔壁实验室工作,天天见面。她是在68年C被定为反革命之后才与他结婚的,此后是天天盼他回来,想不到现在还得盼。呜呼!

(六)一九八九年十二月二十七日致WY

   我确实是不注重语言的,不是不会,而是不屑。这是与我对内在的追求相背的。所以我的诗实在是粗糙得很,经不起推敲,有时更象散文。写诗本来于我就是一种无价值的劳动,连装饰也不是,也就顾不得让它“艺术化”。

   《那时候》一诗更是写得匆忙,并非完整的作品,你也就不必在里面寻找什么特点。在它的基础上完成了《传统下的预言》,可说是我对北京的观感,颇费了点心机,自己也较满意,再修改修改,简直可以当作我的代表作了。

   这几天非常忙,经常工作到深夜。过了元旦也许会轻松一些。我要一直工作到明年六月,但愿能在这里见面。

   合肥考区的GRE成绩还未到,也就使我放不下心来。明年出国的可能性看来已经不大了,但我拒绝认认真真地在国内找份工作。我是可以把前途当儿戏的,没什么可怕的。如果我要平庸下去,干什么工作都一样。

   下过一场雪,我以为很大,但别人却不以为然。以前每逢下雪都要激动一番,现在却是麻木不仁了。只是在听到罗马尼亚的消息时令我兴奋了一天。罗马尼亚的今天也就是中国的明天。中国不可能走匈牙利、东德的道路,只好作出另一种残酷的选择。

(七)一九九零年一月十四日致WY

    明天就要回家渡寒假了。居然觉得有点舍不得离开北京。解除戒严给我的好处是我终于能在回家前进入天安门广场去寻觅昨天的故事,寻觅今天的灵感。是的,昨天的一幕历历在目,当我面对纪念碑正面和东侧那几级被坦克碾去了一半的台阶,我只觉得无比的悲哀。一切是如此的真切,连曾经火烧的痕迹也无法抹去。城楼上那一双眼睛此刻显得多么忧郁,他想要告诉我什么呢?他的灵魂并没有随着身体被禁锢在水晶棺里,有这么多的人如此虔诚地去朝拜一具尸体就是明证——是的,非常的虔诚!当我从他身边走过的时候,我默默地祈祷,让他安眠吧,永远不要醒来。而实际上他的时代遗风犹存,远未逝去。再过几十年,当那个时代成为一个遥远的、神秘的、令人憧憬的神话,就象法国青年在拿破仑墓前宣誓,也许也会有人跪倒在这位巨人的棺材前扼腕吧?到那时候,我们对他的憎恨将变得多么可笑,毕竟,我们时代的苦难不过是历史活剧中的一个小小的插曲罢了,与未来的人们无关。但是无论如何,我们仍然必须为自己为现在的人们而战。

(八)一九九零年三月十日致WY

   如果不是那个早在意料之中的文件,我九月份已在布朗大学读博士了。这座美国著名的私立大学位于罗德岛——第一个宣布独立和最早废除奴隶制的自由之州,我的彼岸。

   这一切最终是一个梦。在听完文件传达后,科大研究生院的一名学生便悲壮地从公寓八楼楼顶(我正在八楼给你写信)跳了下去,留下了一大堆洗不掉的血迹,让我们天天踏着烈士的血迹前进。

   但是我还不死心,仍然不愿认认真真地找工作,出不了国,到哪里都一样。我在进行一场毫无希望的决战,而且似乎颇为孤单。

   我依然没有变得更加现实,这大概就是所谓的执着。没什么可钦佩的,无非证明了内心深处对残酷现实的拒绝。但是再也不会有梦想了。那么,我死死地盯着的,究竟是什么呢?是奇迹吗,那唯一的希望?

   为改变(或实现,谁知道呢?)自己的命运,作绝望的战斗,人生的目的,不过如此。因此我绝不认命,同时尽力保持着内心的宁静。在八楼楼顶,在月光或星光下,悠然操练一套濒于失传的太极拳——那位烈士,就是从那里跳下去的。

(九)一九九零年三月二十五日致HR

   这期间发生了许多事,令人先喜后悲再悲喜交加。先是GRE得了惊人的高分,然后是早在意料中的严禁出国留学的文件下达了,研究生院的一名学生因此跳楼自杀,血迹犹在。最近呢,是接连收到美国大学的录取通知,就象拿到了去天堂的门票,却不知如何上去。

   父母不是华侨或台胞,那是没办法的事。当然也有补救的办法,就是“出卖爱情”(还记得方方的《风景》吗?)。据说西区有研究生在《合肥晚报》登征婚启事,唯一的条件是必须是侨属,而据说居然有人应征——我认为这件事要是以后有人写新的《二十年目睹之怪现状》,是用得着的。

   今天又到天安门广场,站在纪念碑上,面对那些被坦克碾掉的台阶、被火烧黑的栏杆和隐约可见的弹痕,内心是异常的平静。我也许终于也象别人一样,不再刻骨铭心地时时回忆那场噩梦,而只专注于自己未来的美梦吧。但是现在,打消了普救众生的凌云壮志,却连自救的希望也被剥夺了,这样的生活,还有什么值得留恋的呢。

   虽然说过倘出不了国就学着平平庸庸地生活——但我知道这绝不可能,至少,没法真正地学会。他们可以否定我的选择,却没法剥夺我选择的权利,更无法改变我的内心,从此我大概将生活在梦中。而那梦也并非没有实现的可能。据说福建将实行特殊的政策,不管是真是假,我都愿意相信。

   毕业后的去向已经定下来了。当班上的同学为了十几个研究生名额争得焦头烂额时(这当然是文件下达后了),我却放弃了得到这种恩赐的机会。这样,除了去支边,我就只能回家了。于是我就将回家去。

   如果今年还是让我混了出去,经过了这一番的曲折和几个月的提心吊胆,自然会格外的高兴,而且,说不定一气之下,从此不再回来。所以上次的宏论,大概还是一派胡言。

(十)一九九零年四月七日致WY

   现在的政策似乎又有了变化。从北京市的情况看,是只要交了钱就能办护照。所以我估计今年大概仍能让我混出去——经过这番挫折,自然会更高兴的。

   这几天北京的气氛很紧张,广场和主要街道不必说,连校园里都可见带电棍的警察。而我认为这种紧张是人为的——当局心虚了。以现在的人心,岂还会有什么作为?而当局的举动倒使健忘的人们一时又想起了那些悲惨的日子,研究生院大概有人偷偷地在追悼三位屈死的烈士吧。四五那天,广场进不去,我就干脆远离京城,到慕田峪长城凭吊。这附着的一首诗,便是其结果。

   接下去的这两个月,当局恐怕还要提心吊胆,因为马上就是胡的忌日,四二六、五四……一直到六四。留学政策的突然放松,也许就与此有关。让大家重新作起美国梦,也就无心捣乱了。

(十一)一九九零年四月二十一日致WY

   我上封信也许太乐观了一些。确切的消息是只对北京实行特殊政策,其他省市仍严格把关。我的希望又要大打折扣了。奇怪的是我倒不觉得有什么悲伤,毕竟最绝望的时刻已经历了。

   很累,每天都有十几个小时在作实验,也许正是因此可以忘掉一切的不如意。也许我确实该只专注于本行,不去管别的劳什子了。在实验中可以求得解脱,这是我最近才深切地感觉到的。这是心灵的避难所。但是我很清楚不可能以此为家,总是要走出去的。那时候外面依然是灾难重重。

   近日听了台湾的马兆骏唱《会有那么一天》,莫名其妙地非常激动。我那少年的骄傲哪里去了呢?难道现在也只能如此声嘶力竭地进行自我安慰了吗?高唱“会有那么一天”,实际上内心已经承认了没有那么一天。我真的已经承认了吗?我真真没有勇气面对这个问题了。

   倘有时间,我自然也很想写写小说,即使是诗化的或哲理化了的(我很喜欢卡夫卡和博尔赫斯)。但诗是噩梦中的呻吟,而小说则是猛醒后的反顾。我现在仍身处梦中,那醒来的时刻遥遥无期。

(十二)一九九零年五月十四日致WY

   爱情真的如你所说是一种对别人的需要吗?有这样的想法,是可怕的。这几年来,从寻找到等待再到淡漠,也许终于将一直如此淡漠下去。我早已过了幻想的年龄了,然而至今仍执迷不悟。然而也不后悔。记得在南京时你曾劝我对此要变得现实一些。那自然是对的,但是我却无法接受这样的现实。也许,我所有的浪漫气质却唯独在这一方面表现出来。有谁能够开启我的心扉,让压抑着的激情喷射如注呢?恐怕未必有。因此我也就孤独地守着这一信念直到不可名状的斯芬克斯公主对我显露神秘的微笑,于是不可破译的密码便迎刃而解。那时候我将身处何处,中国还是美国?

   昨天晚上把信写到这,便去看了一会电视,回来时不幸被过道上的积水滑倒,昏迷了十几分钟,左眼眶尽裂,血流如注。到医院缝了两针,医生担心我会得脑震荡。这确是最可怕的事情了。我只有祈求上苍的垂怜,让我的大脑完整无缺,不论付出多大的代价都行,否则我只好自己来熄灭这一把可怜的生命之火。

   这一次的意外除了将会在眼眶上留下一块伤痕,使这张脸变得更吓人外,眼睛和四肢倒都无恙,也是不幸中的万幸了。当我昏迷的时候,似乎一直在做梦,现在却是一点也回想不起在那死亡的门槛我所依依不舍的究竟是什么了。就那样一直昏睡下去也是一种幸福,安祥而无忧无虑。我为什么终于要醒过来呢?

(十三)一九九零年七月十三日致JJ

   事情办得不太顺利,我已要求推迟一个月入学。在家待业一年半载也是有可能的。不管结果怎么样,早已麻木了。万一真的还得赋闲一年,倒也是一件喜事,至少可以多读几本在国外绝对不会读的书。那时也许会想到那片黄土地看个究竟,现在自然没有那样的心情,对你的邀请虽不至于笑话,却也只能表示可惜。如果真的如你所言的“天遂人愿,一个去了MSU,一个去了Chicago”,两三年后,我再陪你回家一趟,如何?击掌为誓,不得反悔。

   你的纪念册只是再随手写了几句开开玩笑,本想认认真真地把背后的两个空位填补,却一直没有找到那样的心境。近来油嘴滑舌惯了,要严肃不易。唯一正正经经(你之所谓深沉)的赠阅给了LZ。因爱而痛苦是值得敬重的,虽然我其实很不以为然却不敢亵渎。

   诗确实应该整理成集,虽然没有什么价值。但许多的时光已浪费在这上面,其中又处处可见已经逝去的青春的活力在闪着星星般微弱的光,无论如何我自己应该珍惜,那曾经是我生命的大部分。同时我必须抑制修改它们的欲望,以现在的眼光,自然不令我满意。那时候我要比现在骄傲得多,现在却只有痛苦留下了。

   这样,你耿耿于怀的那首《雪糕之歌》便翻了出来。即使仅从形式上看,也可知是游戏之作。但以当时的心情,却很难否认没有认真的成份在。究竟是一种什么样的情绪呢?如此不“神秘”的“Boy”如此不“从容”。

   每当想起你轻声问我为什么要出国(你似乎认为我应该留在国内捣乱?),总有一种凄凉之感。正如鲁迅所言,不过是“去寻找别样的人们”,去聆听一种全新的声音,去发现一个新的世界,以便对人类至少是民族的未来不至于太悲观,从而找到赖以生存下去的理由。因此其结果如何也就可以推想。只希望心灵的反叛至少能在几个人的心中得到回响,使命也就在此了。

(十四)一九九零年九月十四日致JJ

   “闽平渔”事件我倒是从喉舌上得知的。当我在省对台办活动时,工作人员正在为此开记者招待会对台抗议。我想大约只有纳粹驱赶犹太人进毒气室的情形与此相似。是什么使他们视讲同一方言的同胞如异族呢?倘是有目的的政治行动倒还说得过去,可怕的倒是自发的。人心是可怕的,如果把别人当作了异己的怪物。而中国人对待家贼往往比对外寇更凶残。四十多年、整整两代人的分隔就足以造成这一切了。然而我不能为此写诗。诗不能应时,那是杂文的事。很难再有慷慨激昂的时候了,所多的是自以为大彻大悟之后的静穆。所以我有时候也写些很平淡的诗,比如附上的这一首近作,你大概不会喜欢的。

   我现在最大的愿望是再读一遍二十四史。在北京时,一边走马观花地读《国语》《史记》,一边哀叹时间的不足。现在时间是有了(按我的读史法,三个月的时间就可以读完二十四史),却没有了条件。所以就改读诸子。经史子集,只有经和集不能使我感兴趣。心里装着这么一大堆破烂到异国他乡去,是多么的滑稽。我有时真痛恨自己为何仍对这些糟粕恋恋不舍。

(十五)一九九零年九月二十六日致SF

   我没有去单位报到,在家赋闲,上午打棋谱,下午听BBC,晚上看点杂书。就这样活几个月也未尝不是美事,但总该有结束的时候的。我班准备今年出去的都已经走了,我是最后一个,也可能是个例外。正是因为有这种忧虑,使我不能真正静下心来享受这最后的舒适,即使打一百趟太极拳也没有用。

   MM如果出国受阻,是否也有到粤工作的打算?如此,则荒原复兴基地初具规模矣。闲极无聊时也翻翻《荒原》,想想我们一起渡过的时光,而回想最多的竟是那几次争辩,与YZC、JYJ乃至可怜的MR。我实在是一个很好斗的Boy,至少以前是的。而现在,对这堵重重包围我的墙,却是有劲使不出,只好想些打洞的窍门了。

   你没能进特区,使我颇感意外,不知以后是否还有可能进去?坐在铁网之下,应该别有一番滋味吧,正与我现在端坐家中遥望彼岸的情绪相同。然而我不能再写些什么了,凝神一想,便不由悲从衷来,除了想狂嚎一声,什么也想不下去。还是让我回到棋谱上去吧。

(十六)一九九零年九月二十九日致JJ

   想不到公认的第一擂手竟自承其懒,未免过谦。想当初,当我一大早起来玩太极时,总能见你一本正经地背着书包到图书馆报到,难道只是作作样子?整日价杂学旁收也许反倒是懒的结果。与你相反,我现在倒很想有个实验室好好干点活,北京的老板一直希望我再去,如果不是这边半死不活地拖着,我早去了。闲书作伴真是无可奈何,因为身边连一个可以谈谈心的人儿都没有。

   文艺书我看得很少,看得最多的是存在主义和准存在主义的介于文学与哲学之间的著作以及鲁老夫子的文章。现在却很怕再读这类东西了,因为读着读着,就会忽然觉得悲从衷来,想要狂叫一声。诸子和史书的刺激就不至于这么激烈。而事实上,我现在最主要的消磨时光的方法是打棋谱和听BBC,慢慢地麻醉了自己。

   因“闽平渔”事件而感到的耻辱是肯定有的,不过我所感到的却大多是来自自己人,而聊以慰藉的法宝就是告诉自己人家也与我们一样。也许凭借这点精神胜利法,会使我坦然面对黄毛碧眼的垂怜吧。除此之外我想不出还有什么理由可以让我在这条一样被封得死死的船里苟活下去并梦想着能破船而出以便能在船外砸烂这条烂船。因此我们成功突围的那天我们依然要挺着胸面对所有的责难,只要心中仍怀着同胞的苦难。

(十七)一九九零年十一月五日致JJ

   我的诗集的整理一直未能完成,现在总算能静下心来了。有这番经历,滋味恐怕就会不同。五年的惨淡经营,到最后能存活下来的也许会不到二十首。枪毙自己的创造物真是一件愉快的事,可以好好地当一回上帝,这也是诗神给我的报酬。

(十八)一九九零年十一月八日致HR

   SF来信说你们和MM曾有过一次愉快的聚会,使《荒原》复兴基地初具规模,令人羡慕不已。我争取在出国前与你们见上一面,因为从此以后,各在天涯,相聚的日子恐怕就遥遥无期了。

   用四个月的奔波和等待为代价,总算看到了曙光,但似乎也不值得因此高兴。我感到的只有莫名的悲哀,而其中所经受的屈辱将永远记得。

2011年度总结

2011年度总结
来源:人人网 作者:唐申强

和往年一样,这是蛋疼的一年,坑爹的一年,杯具的一年,纠结的一年。

这一年,“我爸是李刚”拉开了中国人拚爹的序幕,大量的富二代官二代用他们的行动告诉我们:人生最重要的不是你所朝的方向,而是取决于你是谁的精子。

这一年,重庆的打黑运动让我们明白:电视上经常看到的那些衣着光鲜,人模狗样的公仆,他们往往在下一刻就变成了黑老大。而你是公仆还是黑社会,关键看你有没有站错队。

这一年,日本9.0级地震震垮了核电站,也震碎了国人愚昧的神经,那些买不起房而被迫单身的人们,因为手里有几袋碘盐而变得奇货可居。

这一年,国与民争利达到高潮,财政收入连创新高,人民饭碗却营养不良。GDP世界第二,百姓收入勉强苟活,房子彻底沦为多数人的浮云。而盛会,依然在一个叫隆重的地方举行。

这一年,苹果砸中牛顿沉寂数百年后,以数码产品的姿态席卷全球。世界上最遥远的距离是:我们一起出门,你去买苹果四代,而我却只能买四袋苹果。

这一年,谢霆锋终于意识到自己对柏芝的了解始终超越不了天涯上的民工,于是他放弃了。我固执的认为他一定看到了杂谈那个万人景仰的回复。男人,无论好坏,都翻不过那道绿帽砌成的坎,有的秋后算帐,有的立马摊牌。

这一年,芙蓉姐姐从大S变成了小S,凤姐的绿卡让我们彻底断了成功可以复制的念想。但不管是李宇春,还是曾轶可,都是我的哥,我的哥。。

这一年,南科大45名学子以非暴力不合作表达了对中国教育的鄙视,一潭死水总算荡起了一丝波浪。但死水原本就不应该有波浪,所以,他们在潭中注满了水泥。

这一年,转基因和地沟油让中国人坚信他们是核战争最后的幸存者。在网上,他们表达吐血身亡的语句变成了:遂吐3公升地沟油而亡。

这一年,各地下雨全是100年不遇,武汉的海景超过公交成为新的城市名片。成都,长沙,南京纷纷在报纸上表示自己是特大号护舒宝,流量再多也不用担心,随即就被老天爷一个无情的耳光扇过去。。分析认为:此护舒宝为山寨品,也就是:made in china。

这一年,绿皮火车见到了蒸汽火车,感叹世间人情冷暖,我们终究都逃不过鸟尽弓藏的命运。开明的蒸汽火车说:历史的车轮在前进,我们都尽到了自己所处位置的责任,现在是高铁的时代了,你再不退下就是开历史的倒车,中国人民才被历史的车轮碾过,还没爬起来,一回头却看见你在倒车,你叫他们情何以堪呐。

这一年,高铁恍如一夜之间长满祖国各地,人们用高于普车数倍的价格向铁道部购买时间,而那些时间充裕的人因普车的取消也不得不买几个小时,然后在目的地玩手机来消磨时间。

这一年,号称世界领先的动车出轨了,人们悲怆的发现,吃的,住的,坐的竟没有一种让人蛋定,以河蟹着称的媒体也开始草泥马了,在经历了出事→微博讨论→小秘书删帖→微博疯狂讨论→小秘书来不及删帖→问责呐喊声四起→传统媒体跟进→微博谣言四起→政府辟谣→产生新的流行语→李承鹏发文→韩寒发文→讽刺段子出炉→五毛辟谣搅混水→讨论进入高潮→总理现身→微博一片体贴谅解→和谐,删帖,噤声→搞笑段子出炉→下次。。。后,酱油瓶仍旧在手,真相的高度永远高于酱油瓶的高度,对于善良的中国人来说,打酱油比抢碘盐还来得更轻松和毫无风险。

这一年,黑社会败给了社会黑,社会黑又催生了黑监狱,黑监狱关的却不是黑社会。黑社会说:监狱,本就是黑色,黑夜给了中国黑色的监狱,它们却用来禁锢冤屈。

这一年,灰太郎对喜洋洋说:我咬你,你不要动,我们要和谐。

这一年,五毛依旧凶猛,天涯沦落的不仅是国关,还有八卦。而在杂谈,五毛还是一如既往的苦逼。

这一年,人民仍然相信,皇帝是好的,中央是清白的,坏的只是地方。当不公降临在他身上时,他最期待的不是改良制度,而是渴望清官。

这一年,雷公也成了弱势群体,悲催的替铁道部背了黑锅。当我们在盘点中国事故责任人时,发现他们分别是临时工、临时工、临时工。。。还有雷公,这时玉帝大叫道:他也是临时工。

这一年,央视和百度,一个婊子一个奴才,为争牌坊打起来了。请问你支持谁?—-废话,当然是支持google。那么假如央视和百度同时落水,你是去吃火锅还是去K歌?—-废话,当然是掏出鸡鸡往水里尿尿。

这一年,我想对日本人说:不用担心,你们的国家不会抛弃你们!最后我要对中国人民说:不要幻想太多,你只能靠自己。

JW Player 编译及修改

修改方法去掉右键官方连接及官方logo水印:

  1. 去掉Logo水印;
    在文件“/com/longtailvideo/jwplayer/view/View.as ”中找到“_logo = new Logo(_player);及setupComponent(_logo, n++);”将其注释掉即可。【如果想保留logo,只是更改掉官方logo,查相关使用文档或者修改logo.as, 修改到logo.png的地址即可】
  2. 去掉右键about官网地址链接。
    在文件“/com/longtailvideo/jwplayer/view/RightclickMenu.as ”中找到“setAboutText();及addItem(about, aboutHandler);”将其注释掉即可。

我在flash builder 下面编译【Flex下面编译,同理】,建立文件pl.as:

package
{
	import com.longtailvideo.jwplayer.player.Player;

	public class pl extends Player
	{
		public function pl()
		{

		}
	}
}

最新jw player 5.7下载:点击下载 jw player 5.7 –采用GPU加速

附加问题:

  1. jw player源码问题,首先jw player是开源的,不需要破解反编译获得源码的,jw player源码现在地址为: http://developer.longtailvideo.com/svn/trunk/fl5
  2. 如果去编译jw player, 这个是基本Flash程序员需要学的基本知识,我是在src目录下建立fla文件的,需要将../lib目录中的as3corelib.swc设置好, 否则会提示json函数问题,虽然不影响基本使用。

HTML5游戏开发之一:动画制作

虽然目前几乎所有的webgame动画都使用Flash来实现,但是使用用JS来实现一场RPG的战斗动画,一直以来都不是什么难题。

去年我通过JS方式实现战斗引擎播放,效果也可以做的很绚丽,所有浏览器下,都测试通过,尚未发现卡的问题,但是,由于IE6下面,需要使用了VML()方式来处理PNG透明问题,并且要注意IE6缓存图片BUG的问题,解决这两个问题之后,JS耗CPU较少,但占用内存明显增大。基于兼顾IE6用户的考虑等等,我仍然会选择Flash来完成战斗动画。

由于将完成的一个游戏,是关卡玩法的游戏,PVE部分,比较适合放到手机平台上当做手机单机游戏来玩,所以我考虑,是否使用HTML5来完成战斗引擎,针对Webkit内核的等等支持HTML5的浏览器,我们可以使用HTML5来完成战斗动画播放,则可以直接使用在Andriod、iOS、WP7等手机平台上。

由于我从05年开始,我使用JavaScript越来越多,其中大部分是使用Prototype,所以下面这个例子,是基于了Prototype JS的。

注:如Internet Explorer的一些浏览器,不支持canvas标签或本演示。的Chrome、Firefox、Safari、Opera浏览器的最新版本正常工作。

不使用HTML5来完成动画的时候,通过css改变背景图片的偏移量可以做出战斗动画。使用HTML5来完成,只需要在Canvas上面循环画出图片上面不同帧即可。

如下例子中,使用了如下图片,一个攻击动画:
战斗动画图片

最好的说明是实例:

配置动画参数:

var attack = {
    name: 'attack',
    totalFrames: 10,
    loop: true,
    step: 4,
    width: 150,
    height: 150,
    sY: 0,
    sX: 0
}; //set initial animation set

角色动画:

/**
 * Sprite 系统,雏形
 *
 * @file_name   Sprite.js
 * @version     1.0
 * @author      黄新泽
 * @date        2011/1/14
 */

var	Sprite = Class.create({
	initialize : function(x, y, width, height, img, animation)//initialize sprite
    {
        this.canvas = document.createElement('canvas'); //动画canvas

        this.canvas.setAttribute('width', width);
        this.canvas.setAttribute('height', height);
        this.ctx = this.canvas.getContext('2d'); //get canvas drawing context

		this.x = x; // X position of this sprite
		this.y = y; //Y position of this sprite
		this.animation = 0; //current animation for this sprite
		this.currentFrame = 0; //current animation frame for this sprite
        this.width = width;
        this.height = height;

		this.image = img; //image that is being drawn to the canvas
		this.currentStep = 0; //number of frames since this sprite's animation was updated
		this.isReady = true; //sprite has finished loading and can be used

        this.animation = animation;
    },

    drawImage: function()
    {
        //draw image into sprite canvas
        this.ctx.clearRect(0, 0, this.width, this.height); //clear previous frame

        if(this.isReady)
        {
            //do not draw if sprite is not ready
            //calculate values for sprite based on animation
            var srcX = this.animation.sX + (this.currentFrame * this.animation.width);
            var srcY = this.animation.sY ;
            var srcWidth = this.animation.width;
            var srcHeight = this.animation.height;
            this.ctx.drawImage(this.image, srcX, srcY, srcWidth, srcHeight, 0, 0, srcWidth, srcHeight); //draw image
            this.stepSprite(); //advance animation
        }
    },

    stepSprite: function()
    {
        //advance animation based on animation speed (step value)
        if(this.currentStep >= this.animation.step)
        {
            this.currentStep = 0;
            this.currentFrame++;

            if(this.currentFrame >= this.animation.totalFrames)
            {
                if(this.animation.loop)
                {
                    this.currentFrame = 0; //loop animation back to start
                }
                else
                {
                    this.currentFrame = this.animation.totalFrames -1;	//if loop not set, hold on final frame
                }
            }
        }
        else
        {
            this.currentStep++; //advance step counter if step limit not reached
        }
    }
});

播放战斗动画:

var	FightAnimation = Class.create({

	canvas: 0, //main canvas object
	ctx: 0, //main canvas drawing context
	sprite: 0, //sprite object

	width: 900,
	height: 450,
	timer: 0,  //hold reference to game loop timer
	background: 0, //background image - for now is drawn right onto main canvas which is not ideal
	foreground: 0, //foreground object

	initialize: function(img)
    {
        //initialize FightAnimation
		this.canvas = document.getElementById('main');  //get canvas element from html
		this.ctx = this.canvas.getContext('2d'); //create main drawing canvas

		this.canvas.setAttribute('width', FightAnimation.width); //set attributes of canvas
		this.canvas.setAttribute('height', FightAnimation.height);

		this.sprite = new Sprite(0, 0, 150, 150, img, attack); //init sprite //create new Sprite object

        //document.body.insert(FightAnimation.sprite.canvas);
        this.timer = setInterval(this.drawFrame.bind(this), 40);
	},

	drawFrame: function()
    {
        //main drawing function
		this.ctx.clearRect(0, 0, this.width, this.height);  //clear main canvas

		//FightAnimation.ctx.drawImage(FightAnimation.background, 0, 0); // draw canvas background
		if(this.sprite)
        {
			this.sprite.drawImage(); //cause sprite to draw itself on its internal canvas
			this.ctx.drawImage(this.sprite.canvas, this.sprite.x, this.sprite.y);//draw sprite canvas onto main canvas
		}
	}
});

初始化战斗:

function startCanvas(e)
{
    new FightAnimation(img_res.successList['129_1_1'].img);  //initialize main Expermient object
}

document.on('img:oneloaded', startCanvas);  //处理进度条,........

var  img_res = ImgManage.getInstance();
img_res.addResourcesBag([["129_1_1", "/Images/actionicon/56/1/2.png"]]);

游戏中NPC 人工智能对话技术实现

其实就是08年,设想的,针对上班族,开发一个MSN机器人,通过对MSN机器人发送指令,来玩策略类网页游戏。 当初已经完成了MSN机器人的所有程序部分。通过MSN发送指令,可以完成游戏中几乎所有的建设、军事、消息指令…..

当继续想完善时候,发现完全使用中文是实现,目前缺少完善的AIML中文语料库,这个很难有现有资源利用……

# -*- coding: utf-8 -*-

import aiml
import sys
import time
import os.path
import thread
import re
from datetime import datetime
import marshal

loginemail="xinze@live.cn" # that robot will login to
loginpassword="11111" # account password
botname="Xinze...." # Robot's nickname
admin_email="xinze@live.cn" # emailaddress for admin the robot

# ==== normally nothing needs to be changed below ====

rootdir=os.getcwd()
configfile="%s/chatbot.ini" % rootdir
sessiondir="%s/sessions/%s" % (rootdir,loginemail)
os.system("mkdir -p %s" % sessiondir)
logfilename="%s/log" % sessiondir
sessionfilename="%s/session" % sessiondir

os.system("mkdir -p %s/tmp/" % rootdir)
msn_fortune="%s/tmp/msn-fortune" % rootdir
msn_fortune_zh="%s/tmp/msn-fortune-zh" % rootdir

blacklist=['sample@blacklist.org' ] # put here email addresses you want to block
blacklist=set(blacklist)
adminlist=[admin_email] # the 'admin' account's email address from which you send admin command
adminlist=set(adminlist)

dlist=[]
talkedto=[]

use_brain=True

def config(configfile, k):
    # setup bot properties such name, birthplace etc
    f=open(configfile)
    g=f.readlines()
    f.close()
    for i in g:
        h=i.split('=')
        if len(h)==2:
            k.setBotPredicate(h[0].strip(), h[1].strip()) 

    print sessionfilename
    # load session
    if os.path.exists(sessionfilename):
        f=open(sessionfilename)
        g=f.read()
        f.close()
        g=g.split('\n')
        for i in g:
            if i!='':
                talkedto.append(i)
                sessionFile = file("%s/%s.ses" %(sessiondir, i), "rb")
                session = marshal.load(sessionFile)
                sessionFile.close()
                for pred,value in session.items():
                    k.setPredicate(pred, value, i)

def dolog(message):
	global logfile
	logfile.write(message)
	logfile.flush()

def filter(message):
	message=message.replace("ALICE", botname)
	return message

def test_msg(senderemail, message):
    global dlist

    sender=senderemail.split("@")

    if senderemail in blacklist:
        return	

    dlist=[]

    if not senderemail in set(talkedto):
        talkedto.append(senderemail)

    logtime='%s/%s/%s %s:%s:%s' %( datetime.now().month, datetime.now().year, datetime.now().day, datetime.now().hour, datetime.now().minute, datetime.now().second)

    if not senderemail in adminlist:
        dolog('=== %s === Recv from %s < %s> ===\n%s\n' % (logtime, sender[0], senderemail, message))
    if message=='admquit' and senderemail in adminlist:
        message="%s is offline!" % botname
        #quit()

    if message=='admlist' and senderemail in adminlist:
        return

    if k.getPredicate("name", senderemail) =='':
        dispname=senderemail.split("@")
        if len(dispname) ==2:
            k.setPredicate("name", dispname[0], senderemail)
    remsg=k.respond(message, senderemail)
    remsg=filter(remsg)

    logtime='%s/%s/%s %s:%s:%s' %( datetime.now().month, datetime.now().year, datetime.now().day, datetime.now().hour, datetime.now().minute, datetime.now().second)
    if not senderemail in adminlist:
        dolog('=== %s === Send to %s < %s>===\n%s\n\n' % (logtime, sender[0], senderemail, remsg))

    print remsg

def savesession():
    # =========== save session
    f=open(sessionfilename, 'w')
    for i in talkedto:
        session = k.getSessionData(i)
        sessionFile = file("%s/%s.ses" % (sessiondir, i), "wb")
        marshal.dump(session, sessionFile)
        sessionFile.close()
        f.write("%s\n"% i)
    f.close()

def do_work():
    time.sleep(5)
    savesession() # save session data every 10 min
    thread.start_new_thread(do_work, ())

thread.start_new_thread(do_work, ())

# ================== Initialization
if __name__ == '__main__':
    k = aiml.Kernel()
    config(configfile, k)
    #k.verbose(False)

    # ================== load brain
    if use_brain and os.path.isfile("standard.brn"):
        k.bootstrap(brainFile = "standard.brn")
    else:
        k.bootstrap(learnFiles = "startup.xml", commands = "load aiml b")
        k.saveBrain("standard.brn")

    if os.path.exists(logfilename):
        logfile=open(logfilename, "a")
    else:
        logfile=open(logfilename, "w")

    player_email="alex@live.cn"

    while True:
        message = raw_input('>')
        test_msg(player_email, message)

在CentOS及Ubutun下安装Percona-Server和HandlerSocket注意事项

见: http://www.percona.com/docs/wiki/repositories:start

一、CentOS下安装Percona-Server及HandlerSocket

安装Percona Yum Repository

rpm -Uhv http://www.percona.com/downloads/percona-release/percona-release-0.0-1.i386.rpm
rpm -Uhv http://www.percona.com/downloads/percona-release/percona-release-0.0-1.x86_64.rpm
#自行选择对应的平台

yum install Percona-Server-server-51.i386
yum install Percona-Server-client-51.i386

编辑my.cnf

[mysqld]
plugin-load=handlersocket.so

loose_handlersocket_port = 9998 # 指定读请求端口号
# the port number to bind to (for read requests) 

loose_handlersocket_port_wr = 9999 # 指定写请求端口号
# the port number to bind to (for write requests)

loose_handlersocket_threads = 16 # 指定读线程数目
# the number of worker threads (for read requests)

loose_handlersocket_threads_wr = 1 # 指定写线程数目
# the number of worker threads (for write requests)

open_files_limit = 65535
# to allow handlersocket accept many concurrent
# connections, make open_files_limit as large as
# possible.

重启MySQL后,查看handlersocket是否正常运行

netstat -lnp | grep 9998
netstat -lnp | grep 9999
#查看端口是否被监听

或者在mysql中查看
mysql> INSTALL PLUGIN handlersocket SONAME "handlersocket.so";
mysql>SHOW PLUGINS; # 查看插件是否加载成
mysql>SHOW PROCESSLIST; # 查看handlersocket是否正常运行

#如果handlersocket没有正常运行, 则先关闭SELinux后再试试看看。

二、Ubuntu下安装Percona-Server及HandlerSocket

安装apt-get源

gpg --keyserver  hkp://keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A
gpg -a --export CD2EFD2A | apt-key add -

在ubuntu下其它操作同上,如果没有正常运行,
mysql> INSTALL PLUGIN handlersocket SONAME “handlersocket.so”; 提示: “errno: 2 failed to map segment from shared object: Permission denied”

可以先 /etc/init.d/apparmor stop 然后重启MySQL, 然后 /etc/init.d/apparmor start

php handlersocket

一、安装php-handlersocket模块:

php-handlersocket, PHP extension for interfacing with MySQL Handler Socket.

wget http://php-handlersocket.googlecode.com/files/php-handlersocket-0.1.0.tar.gz
tar zxvf php-handlersocket-0.1.0.tar.gz
cd php-handlersocket
phpize
./configure
make
make install

二、php-handlersocket 使用示例:

	/*
	 * String  $host:MySQL ip;
	 * String  $port:handlersocket插件的监听端口,它有两个端口可选:一个用于读、一个用于写
	 */
	$hs = new HandlerSocket($host, $port);
	打开一个数据表:
	/*
	 * Int       $index:这个数字相当于文件操作里的句柄,HandlerSocket的所有其他方法都会依据这个数字来操作由这个	 openIndex打开的表,
	 * String  $dbname:库名
	 * String  $table:表名
	 * String  $key:表的“主键”(HandlerSocket::PRIMARY)或“索引名”作为搜索关键字段,这就是说表必须有主键或索引
	 *                 个人理解:要被当做where条件的key字段,这样可以认为handlersocket只有一个where条件
	 * String  $column:'column1,column2' 所打开表的字段(以逗号隔开),就是说$table表的其他字段不会被操作
	 */
	$hs->openIndex($index, $dbname, $table, $key, $column);
	查询:
	/*
	 * Int     $index: openIndex()所用的$index
	 * String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持'=', '>=', '< =', '>',and '< ';可以理解为where条件
	 * Array   $value
	 * Int       $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
	 * Int     $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
	 */
	$retval = $hs->executeSingle($index, $operation, $value, $number, $skip);
	插入(注意:此处的openIndex要用$port_wr,即读写端口):
	/*
	 * Int     $index: openIndex()所用的$index
	 * Array   $arr:数字元素数与openIndex的$column相同
	 */
	$retval = $hs->executeInsert($index, $arr);
	删除(注意:此处的openIndex要用$port_wr,即读写端口):
	/*
	 * Int     $index: openIndex()所用的$index
	 * String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持'=', '>=', '< =', '>',and '< ';可以理解为where条件
	 * Array   $value
	 * Int     $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
	 * Int     $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
	 */
	$retval = $hs->executeDelete($index, $operation, $value, $number, $skip);
	更新(注意:此处的openIndex要用$port_wr,即读写端口):
	/*
	 * Int     $index: openIndex()所用的$index
	 * String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持'=', '>=', '< =', '>',and '< ';可以理解为where条件
	 * Array   $value
	 * Int       $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
	 * Int     $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
	 */
	$retval = $hs->executeUpdate($index, $operation, $value, $number, $skip);
CREATE TABLE `user` (
  `user_id` int(10) unsigned NOT NULL,
  `user_name` varchar(50) DEFAULT NULL,
  `user_email` varchar(255) DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`user_id`),
  KEY `INDEX_01` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES ('1', 'aaa', 'aaa@dsf.com', '2011-04-07 18:26:03');
INSERT INTO `user` VALUES ('2', 'bbb', 'bbb@dsf.com', '2011-04-07 18:26:03');
INSERT INTO `user` VALUES ('3', 'ccc', 'ccc@test.com', '2011-04-07 18:26:03');
< ?php
$host = '192.168.5.28';
$port = 9998;
$port_wr = 9999;
$dbname = 'test';
$table = 'user';

//GET
$hs = new HandlerSocket($host, $port);
if (!($hs->openIndex(1, $dbname, $table, HandlerSocket::PRIMARY, 'user_id,user_name,user_email,created')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

$retval = $hs->executeSingle(1, '>=', array('0'), 10, 0);

var_dump($retval);

$retval = $hs->executeMulti(
    array(array(1, '=', array('1'), 1, 0),
          array(1, '=', array('2'), 1, 0)));

var_dump($retval);

unset($hs);

//UPDATE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(2, $dbname, $table, '', 'user_name,user_email,created')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeUpdate(2, '=', array('2'), array('aaa', 'xun@dsf.com', '2011-04-07 18:26:03'), 1, 0) === false)
{
    echo $hs->getError(), PHP_EOL;
    die();
}

unset($hs);

//INSERT
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(3, $dbname, $table, '', 'user_id,user_name,user_email,created')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeInsert(3, array('5', 'aaa5', 'xun@dsf.com', '2011-04-07 18:26:03')) === false)
{
    echo $hs->getError(), PHP_EOL;
}
if ($hs->executeInsert(3, array('6', 'aaa6', 'xun@dsf.com', '2011-04-07 18:26:03')) === false)
{
    echo 'A', $hs->getError(), PHP_EOL;
}
if ($hs->executeInsert(3, array('7', 'aaa7', 'xun@dsf.com', '2011-04-07 18:26:03')) === false)
{
    echo 'B', $hs->getError(), PHP_EOL;
}

unset($hs);

//DELETE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(4, $dbname, $table, '', '')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeDelete(4, '=', array('1')) === false)
{
    echo $hs->getError(), PHP_EOL;
    die();
}
?>

MySQL插件HandlerSocket

HandlerSocket 是MySQL的一个插件,用来实现 NoSQL 功能,用于跳过MySQL的SQL层面,直接访问内部的InnoDB存储引擎。

wget http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-client-5.5.11-1.rhel4.i386.rpm
wget http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-devel-5.5.11-1.rhel4.i386.rpm
wget http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-server-5.5.11-1.rhel4.i386.rpm
wget http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-shared-5.5.11-1.rhel4.i386.rpm

rpm -ivh MySQL-client-5.5.11-1.rhel4.i386.rpm MySQL-devel-5.5.11-1.rhel4.i386.rpm MySQL-server-5.5.11-1.rhel4.i386.rpm MySQL-shared-5.5.11-1.rhel4.i386.rpm 

wget http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.11.tar.gz

一、安装HandlerSocket
获取安装包:https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL.git

tar -zxvf ahiguti-HandlerSocket-Plugin-for-MySQL-1.0.6-73-g0e63366.tar.gz
cd ahiguti-HandlerSocket-Plugin-for-MySQL-0e63366/
./autogen.sh
./configure --with-mysql-source=/home/xinze/software/mysql-5.5.11 --with-mysql-bindir=/usr/bin  --with-mysql-plugindir=/usr/lib/mysql/plugin
make && make install

修改/etc/my.cnf 配置

[mysqld]
plugin-load=handlersocket.so

loose_handlersocket_port = 9998 # 指定读请求端口号
# the port number to bind to (for read requests) 

loose_handlersocket_port_wr = 9999 # 指定写请求端口号
# the port number to bind to (for write requests)

loose_handlersocket_threads = 16 # 指定读线程数目
# the number of worker threads (for read requests)

loose_handlersocket_threads_wr = 1 # 指定写线程数目
# the number of worker threads (for write requests)

open_files_limit = 65535
# to allow handlersocket accept many concurrent
# connections, make open_files_limit as large as
# possible.

在mysql里加载HandlerSocket插件:

mysql> INSTALL PLUGIN handlersocket SONAME "handlersocket.so";
mysql>SHOW PLUGINS; # 查看插件是否加载成
mysql>SHOW PROCESSLIST; # 查看handlersocket是否正常运行

* 如果SHOW PROCESSLIST没有handlersocket 进程, 则先关闭SELinux后再试试看看。
* 在ubuntu下,可以先 /etc/init.d/apparmor stop 然后重启MySQL, 然后 /etc/init.d/apparmor start

二、安装 php-handlersocket 模块:

wget http://php-handlersocket.googlecode.com/files/php-handlersocket-0.1.0.tar.gz
tar zxvf php-handlersocket-0.1.0.tar.gz
cd php-handlersocket
phpize
./configure
make
make install

JW Player 5.5 去水印破解

自从根据JW Player源代码,编译破解去掉了官方水印之后,有很多网友下载使用了,但是从JW Player 5.3之后,我就再没有去编译,认为按照我们说的方法,很简单就编译出来,但是仍不停收到E-mail,求破解JW Player的最新版本………. 所以我就编译了最新版本的JW Player 5.5 去水印破解版本!

采用GPU加速的JW Player 5.5最新版本flash视频播放器,编译破解去除水印! 最新jw player 5.5下载

根据源代码编译方法见:去掉JW Player水印及右键官方菜单

Android and HTML5 开发手机应用

作为一个WEB开发者,HTML5让我兴奋,因为它可以将桌面应用程序功能带入浏览器中。但在国内,看着到处横行的IE8版本以下的浏览器,觉得到能大规模使用HTML5技术的那天,还遥遥无期。但面对iOS及Android等平台的手机用户越来越多,基于Webkit内核的移动浏览器一定能让HTML5先大规模应用起来。这将对对移动 Web 应用程序开发具有重大影响。

作为非常看好未来手机网络的我,也在一直研究Android平台的应用的开发,也许是因为自己更熟悉HTML及CSS、JS,并受到之前使用HTML和VC开发程序的影响,我也更愿意使用HTML来做Android程序的UI….

09年,在开发《华夏风云》游戏的时候,使用了基于Google Gear插件来做了很多离线应用,可惜Gear已经不在更新开发,被HTML5取代。下面介绍基于HTML 5 的Web 应用程序的本地存储,不再废话,例子说明一切。

 

一、离线应用缓存 HTML 5 Offline Application Cache

  • 在服务器上添加MIME TYPE支:text/cache-manifest
  • 如果在Apache下添加:

    AddType text/cache-manifest manifest

    如果为Nginx,在添加:

     text/cache-manifest                   manifest;

    或者通过动态程序生成:

    header('Content-type: text/cache-manifest; charset=UTF-8');
  • 创建 NAME.manifest:
  • 新建清单文件 manifest

    CACHE MANIFEST
    # This is a comment.
    # Cache manifest version 0.0.1
    # If you change the version number in this comment,
    # the cache manifest is no longer byte-for-byte
    # identical.
    
    /app/static/default/js/models/prototype.js
    /app/static/default/js/controllers/init.js
    
    NETWORK:
    # All URLs that start with the following lines
    # are whitelisted.
    
    http://a.com/
    
    CACHE:
    # Additional items to cache.
    /app/static/default/images/main/bg.png
    
    FALLBACK:
    demoimages/ images/
  • 给 <html> 标签加 manifest 属性
  • 建立manifest文件之后,需要在HTML文档中声明:
    声明清单文件 manifest

    
    
    <!doctype html> 
    <html manifest="notebook.manifest"> 
        <head> 
            <meta charset="UTF-8" /> 
    		<meta name = "viewport" content = "width = device-width, user-scalable = no"> 
            <title>NoteBook</title> 
        </head> 
        <body> 
        </body> 
    </html>

二、Key-Value Storage

三、Using the JavaScript Database

四、Android下使用WebView来做基于HTML5的App

见如下AndroidManifest.xml

< ?xml version="1.0" encoding="utf-8"?>

    
        
            
                
                
            
        
    
	

注意:

, 允许网络应用,必须!!

Android主程序代码:

package com.xinze.joke;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;

import android.content.DialogInterface;

import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import android.webkit.WebStorage ;

public class Joke extends Activity {

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		final WebView wv = new WebView(this);

		// 覆盖默认后退按钮的作用,替换成WebView里的查看历史页面
		wv.setOnKeyListener(new View.OnKeyListener() {

			@Override
			public boolean onKey(View v, int keyCode, KeyEvent event) {
				if (event.getAction() == KeyEvent.ACTION_DOWN) {
					if ((keyCode == KeyEvent.KEYCODE_BACK) && wv.canGoBack()) {
						wv.goBack();
						return true;
					}
				}
				return false;
			}
		});

		// 设置支持Javascript
		wv.getSettings().setJavaScriptEnabled(true);

		wv.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
		wv.getSettings().setDatabaseEnabled(true);
		wv.getSettings().setDatabasePath("/data/data/com.xinze.joke/databases"); 

		// 创建WebViewClient对象
		WebViewClient wvc = new WebViewClient() {

			@Override
			public boolean shouldOverrideUrlLoading(WebView view, String url) {
				wv.loadUrl(url);
				// 记得消耗掉这个事件。给不知道的朋友再解释一下,Android中返回True的意思就是到此为止吧,事件就会不会冒泡传递了,我们称之为消耗掉
				return true;
			}
		};

		// 设置WebViewClient对象
		wv.setWebViewClient(wvc);

		// 创建WebViewChromeClient
		WebChromeClient wvcc = new WebChromeClient() {

			// 处理Alert事件
			@Override
			public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
				// 构建一个Builder来显示网页中的alert对话框
				Builder builder = new Builder(Joke.this);
				builder.setTitle("笑死不偿命");
				builder.setMessage(message);
				builder.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						result.confirm();
					}
				});
				builder.setCancelable(false);
				builder.create();
				builder.show();
				return true;
			}

			// 处理Confirm事件
			@Override
			public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
				Builder builder = new Builder(Joke.this);
				builder.setTitle("删除确认");
				builder.setMessage(message);
				builder.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						result.confirm();
					}

				});
				builder.setNeutralButton(android.R.string.cancel, new AlertDialog.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						result.cancel();
					}

				});
				builder.setCancelable(false);
				builder.create();
				builder.show();
				return true;
			}

			// 处理提示事件
			@Override
			public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
					JsPromptResult result) {
				// 看看默认的效果
				return super.onJsPrompt(view, url, message, defaultValue, result);
			}

			@Override
		       public void onExceededDatabaseQuota(String url, String
		    		   databaseIdentifier, long currentQuota, long estimatedSize, long
		    		   totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
		    		                   quotaUpdater.updateQuota(204801);
		    		               } 

		};

		wv.loadUrl("http://192.168.1.14/index.html");

		// 设置setWebChromeClient对象
		wv.setWebChromeClient(wvcc);
		setContentView(wv);
	}
}

使用 JavaScript Database 的时候,需要特别注意:setDatabaseEnabled 以及 onExceededDatabaseQuota!

Page 1 of 1812345...10...Last »