2008年12月27日 星期六

墨子

近來看到了一些事。感謝友人介紹墨子給我。以古鑒今,讀得我汗流直下…不得不佩服古人的智慧,真的是真知灼見。歷史果然是以不同的面貌一再重演。今日看著一些人花了大把大把的銀子,得到的卻是一個謊言。雖然花了很多工夫來說服自己,這些是別人的錢,而且這也不在手臂範圍內,在自己的範圍內對得起自己,對得起投資人。投資人也不是笨蛋,如果事態這麼明顯了還看不出來,他們自己就要承受風險。看著台灣投資人的錢就這樣的被糟蹋,揮霍,心裏相當的難過。
一場大卡司的真實戲碼在眼前上映著,一面難過著一個看似美好的機會在眼前破滅, 也一面慶興著自己在年輕之時就可以上到這麼昂貴的一課,學到相當寶貴的經驗。更加了解在夢想這條路上有那些陷阱,和風險。在這場大卡司的戲碼中,看著一個有理想有才華的人被小人包圍,看著他的恐懼、看著他逃避、封閉自我、在精神上吸毒、不停的欺騙、最後沉淪,變得和他身旁的人沒兩樣。我們雖然被一些人欺騙、惡搞、看似受害者,雖然我們幫不上什麼忙,在這恐怖的經驗之中替他感到痛心,替投資時間、金錢於他的人感到可惜,也學得深刻的教訓,也許能保持自我且依然年輕的我們才是最大的受益者。

這讓我想起了第一份工作的公司所標榜的企業精神:"誠信正直"。真的說得很好。

夢想讓我們充滿熱情、創意讓我們與眾不同、技術讓我們拿到門票、運氣讓我們得以進入門檻,而要真正的成功:“誠信正直” 真的很重要。

這真的很難,也很重要。我想…成功的人那麼少,也許就是要真正落實實在太難了吧,不然也不用拿出來標榜。
修鍊、修鍊…

國高中時,完全不讀不下去的古文。沒想到在經歷了一些事之後,讀起來卻是異常的深刻…熟悉…
念書、念書…

墨子、卷一


親士
入國而不存其士,則亡國矣。見賢而不急,則緩其君矣。非賢無急,非士無與慮國,緩賢忘士而能以其國存者,未曾有也。

昔者文公出走而正天下,桓公去國而霸諸侯,越王句踐遇吳王之醜,而尚攝中國之賢君。三子之能達名成功於天下也,皆於其國抑而大醜也。太上無敗,其次敗而有以成,此之謂用民。

吾聞之曰:“非無安居也,我無安心也。非無足財也,我無足心也。”是故君子自難而易彼,眾人自易而難彼,君子進不敗其志,內究其情,雖雜庸民,終無怨心, 彼有自信者也。是故為其所難者,必得其所欲焉,未聞為其所欲,而免其所惡者也。是故偪臣傷君,諂下傷上。君必有弗弗之臣,上必有詻詻之下。分議者延延,而 支苟者詻詻,焉可以長生保國。

臣下重其爵位而不言,近臣則喑,遠臣則唫,怨結於民心,諂諛在側,善議障塞,則國危矣。桀紂不以其無天下之士邪?殺其身而喪天下。故曰:“歸國寶,不若獻賢而進士。

今有五錐,此其銛,銛者必先挫。有五刀,此其錯,錯者必先靡,是以甘井近竭,招木近伐,靈龜近灼,神蛇近暴。是故比干之殪,其抗也;孟賁之殺,其勇也;西施之沈,其美也;吳起之裂,其事也。故彼人者,寡不死其所長,故曰:“太盛難守也。”

故雖有賢君,不愛無功之臣;雖有慈父,不愛無益之子。是故不勝其任而處其位,非此位之人也;不勝其爵而處其祿,非此祿之主也。良弓難張,然可以及高入深; 良馬難乘,然可以任重致遠;良才難令,然可以致君見尊。是故江河不惡小谷之滿己也,故能大。聖人者,事無辭也,物無違也,故能為天下器。是故江河之水,非 一水之源也。千鎰之裘,非一狐之白也。夫惡有同方取不取同而已者乎?蓋非兼王之道也。是故天地不昭昭,大水不潦潦,大火不燎燎,王德不堯堯者,乃千人之長也。

其直如矢,其平如砥,不足以覆萬物,是故溪陝者速涸,逝淺者速竭,墝埆者其地不育。王者淳澤不出宮中,則不能流國矣。


修身
君子戰雖有陳,而勇為本焉。喪雖有禮,而哀為本焉。士雖有學,而行為本焉。是故置本不安者,無務豐末。近者不親,無務來遠。親戚不附,無務外交。事無終始,無務多業。舉物而闇,無務博聞。

是故先王之治天下也,必察邇來遠,君子察邇而邇脩者也。見不脩行,見毀,而反之身者也,此以怨省而行脩矣。譖慝之言,無入之耳,批扞之聲,無出之口,殺傷人之孩,無存之心,雖有詆訐之民,無所依矣。

是故君子力事日彊,願欲日逾,設壯日盛。君子之道也,貧則見廉,富則見義,生則見愛,死則見哀。四行者不可虛假,反之身者也。藏於心者,無以竭愛。動於心者,無以竭恭。出於口者,無以竭馴。暢之四支,接之肌膚,華髮隳顛,而猶弗舍者,其唯聖人乎!

志不彊者智不達,言不信者行不果。據財不能以分人者,不足與友。守道不篤,偏物不博,辯是非不察者,不足與游。本不固者末必幾,雄而不脩者,其後必惰,源濁者流不清,行不信者名必秏。 名不徒生而譽不自長,功成名遂,名譽不可虛假,反之身者也。務言而緩行,雖辯必不聽。多力而伐功,雖勞必不圖。慧者心辯而不繁說,多力而不伐功,此以名譽 揚天下。言無務多而務為智,無務為文而務為察。故彼智無察,在身而情,反其路者也。善無主於心者不留,行莫辯於身者不立。名不可簡而成也,譽不可巧而立 也,君子以身戴行者也。思利尋焉,忘名忽焉,可以為士於天下者,未嘗有也。


所染
子墨子言見染絲者而嘆曰:“染於蒼則蒼,染於黃則黃。所入者變,其色亦變。五入必而已,則為五色矣。故染不可不慎也。”

非獨染絲然也,國亦有染。舜染於許由、伯陽、禹染於皋陶、伯益,湯染於伊尹、仲虺,武王染於太公、周公。此四王者所染當,故王天下,立為天子,功名蔽天地。舉天下之仁義顯人,必稱此四王者。

夏桀染於干辛、推哆,殷紂染於崇侯、惡來,厲王染於厲公長父、榮夷終,幽王染於傅公夷、蔡公穀。此四王者所染不當,故國殘身死,為天下僇。舉天下不義辱人,必稱此四王者。

齊桓染於管仲、鮑叔,晉文染於舅犯、高偃,楚莊染於孫叔、沈尹,吳闔閭染於伍員、文義,越句踐染於范蠡大夫種。此五君者所染當,故霸諸侯,功名傅於後世。

范吉射染於長柳朔、王胜,中行寅染於籍秦、高彊,吳夫差染於王孫雒、太宰嚭,智伯搖染於智國、張武,中山尚染於魏義、偃長,宋康染於唐鞅、佃不禮。此六君者所染不當,故國家殘亡,身為刑戮,宗廟破滅,絕無後類,君臣離散,民人流亡。舉天下之貪暴苛擾者,必稱此六君也。

凡君之所以安者,何也?以其行理也,行理性於染當。故善為君者,勞於論人,而佚於治官。不能為君者,傷形費神,愁心勞意,然國逾危,身逾辱。此六君者,非不重其國,愛其身也,以不知要故也。不知要者,所染不當也。

非獨國有染也,士亦有染。其友皆好仁義,淳謹畏令,則家日益,身日安,名日榮,處官得其理矣,則段干木、禽子、傅說之徒是也。其友皆好矜奮,創作比周,則家日損,身日危,名日辱,處官失其理矣,則子西、易牙、豎刀之徒是也。《詩》曰:“必擇所堪。”必謹所堪者,此之謂也。


法儀
子墨子曰:“天下從事者,不可以無法儀,無法儀而其事能成者無有也。雖至士之為將相者,皆有法,雖至百工從事者,亦皆有法。百工為方以矩,為圓以規,衡以水,直以繩,正以縣。無巧工、不巧工,皆以此五者為法。巧者能中之,不巧者雖不能中,放依以從事,猶逾己。故百工從事,皆有法所度。”

今大者治天下,其次治大國,而無法所度,此不若百工辯也。然則奚以為治法而可?當皆法其父母,奚若?天下為 父母者眾,而仁者寡,若皆法其父母,此法不仁也。法不仁不可以為法,當皆法其學,奚若?天下之為學者眾,而仁者寡,若皆法其學,此法不仁也。法不仁不可以 為法,當皆法其君,奚若?天下之為君者眾,而仁者寡,若皆法其君,此法不仁也。法不仁不可以為法。故父母、學、君三者,莫可以為治法。

然則奚以為治法而可?故曰莫若法天。天之行廣而無私,其施厚而不德,其明久而不衰,故聖王法之。既以天為法,動作有為,必度於天,天之所欲則為之,天所不 欲則止。然而天何欲何惡者也?天必欲人之相愛相利,而不欲人之相惡相賊也。奚以知天之欲人之相愛相利,而不欲人之相惡相賊也?以其兼而愛之,兼而利之也。 奚以知天兼而愛之,兼而利之也?以其兼而有之,兼而食之也。

今天下無大小國,皆天之邑也。人無幼長貴賤,皆天之臣也。此以莫不犓羊牛、豢犬豬,絜為酒醴粢盛,以敬事天,此不為兼而有之,兼而食之邪?天苟兼而有食之,夫奚說以不欲人之相愛相利也?故曰:“愛人利人者,天必福之,惡人賊人者,天必禍之。”曰:“殺不辜者,得不祥焉。夫奚說人為其相殺而天與禍乎?是以知天欲人相愛相利,而不欲人相惡相賊也。”

昔之聖王禹、湯、文、武,兼愛天下之百姓,率以尊天事鬼,其利人多,故天福之,使立為天子,天下諸侯皆賓事之。暴王桀、紂、幽、厲,兼惡天下之百姓,率以詬天侮鬼。其賊人多,故天禍之,使遂失其國家,身死為僇於天下。後世子孫毀之,至今不息。故為不善以得禍者,桀、紂、幽、厲是也。愛人利人以得福者,禹、湯、文、武是也。愛人利人以得福者有矣,惡人賊人以得禍者亦有矣!


七患
子墨子曰:國有七患。七患者何?城郭溝池不可守而治宮室,一患也。邊國至境四鄰莫救,二患也。先盡民力無用之功,賞賜無能之人,民力盡於無用,財寶虛於待客,三患也。仕者持祿,游者愛佼,君脩法討臣,臣懾雨不敢拂,四患也。君自以為聖智而不問事,自以為安彊而無守備,四鄰謀之不知戒,五患也。所信不忠,所忠不信,六患也。畜種菽粟不足以食之,大臣不足以事之,賞賜不能喜,誅罰不能威,七患也。以七患居國,必無社稷;以七患守城,敵至國傾。七患之所當,國必有殃。

凡五穀者,民之所仰也,君之所以為養也。故民無仰則君無養,民無食則不可事。故食不可不務也,地不可不力也,用不可不節也。五穀盡收,則五味盡御於主,不 盡收則不盡御。一穀不收謂之饉,二穀不收謂之旱,三穀不收謂之凶,四穀不收謂之餽,五穀不收謂之饑。歲饉,則仕者大夫以下皆損祿五分之一。旱,則損五分之 二。凶則損五分之三。餽,則損五分之四。饑,則盡無祿,稟食而已矣。故凶饑存乎國,人君徹鼎食五分之三,大夫徹縣,士不入學,君朝之衣不革制,諸侯之客,四鄰之使,雍飧而不盛,徹驂騑,塗不芸,馬不食粟,婢妾不衣帛,此告不足之至也。

今有負其子而汲者,隊其子於井中,其母必從而道之。今歲凶,民饑道餓,重其子此疚於隊,其可無察邪?故時年歲善,則民仁且良;時年歲凶,則民吝且惡。夫民 何常此之有?為者疾,食者眾,則歲無豐。故曰:“財不足則反之時,食不足則反之用。”故先民以時生財,固本而用財,則財足。故雖上世之聖王,豈能使五穀常 收而旱水不至哉?然而無凍餓之民者,何也?其力時急而自養儉也。故《夏書》曰:“禹七年水。”《殷書》曰:“湯五年旱。”此其離凶餓甚矣。然而民不凍餓者,何也?其生財密,其用之節也。

故倉無備粟,不可以待凶饑;庫無備兵,雖有義不能征無義;城郭不備全,不可以自守;心無備 慮,不可以應卒。是若慶忌無去之心,不能輕出。夫桀無待湯之備,故放;紂無待武之備,故殺。桀、紂貴為天子,富有天下,然而皆滅亡於百里之君者,何也?有 富貴而不為備也。故備者,國之重也;食者,國之寶也;兵者,國之爪也。城者所以自守也。此三者國之具也。

故曰:以其極賞,以賜無功,虛其府庫,以備車馬、衣裘、奇怪,苦其役徒,以治宮室觀樂;死又厚為棺槨,多為衣裘。生時治臺榭,死又脩墳墓。故民苦於外,府庫單於內,上不厭其樂,下不堪其苦。故國離寇敵則傷,民見凶饑則亡,此皆備不具之罪也。且夫食者,聖人之所寶也。故《周書》曰:“國無三年之食者,國非其國也;家無三年之食者,子非其子也。”此之謂國備。

辭過
子墨子曰:古之民,未知為宮室時,就陵阜而居,穴而處,下潤濕傷民,故聖王作為宮室。為宮室之法,曰:室高足以辟潤濕,邊足以圉風寒,上足以待雪霜雨露,宮牆之高,足以別男女之禮,謹此則止。凡費財勞力,不加利者,不為也。役,脩其城郭,則民勞而不傷;以其常正,收其租稅,則民費而不病。民所苦者非此也,苦於厚作斂於百姓。是故聖王作為宮室,便於生,不以為觀樂也。作為衣服帶履,便於身,不以為辟怪也,故節於身,誨於民,是以天下之民可得而治,財用可得而足。

當今之主,其為宮室則與此異矣。必厚作斂於百姓,暴奪民衣食之財,以為宮室,臺榭曲直之望,青黃刻鏤之飾。為宮室若此,故左右皆法象之,是以其財不足以待凶饑、振孤寡,故國貧而民難治也。君實欲天下之治,而惡其亂也,當為宮室不可不節。

古之民,未知為衣服時,衣皮帶茭,冬則不輕而溫,夏則不輕而凊。聖王以為不中人之情,故作誨婦人治絲麻,梱布絹,以為民衣。為衣服之法:冬則練帛之中,足以為輕且暖;夏則絺綌之中,足以為輕且凊,謹此則止。故聖人之為衣服,適身體和肌膚而足矣。非榮耳目而觀愚民也。當是之時,堅車良馬不知貴也,刻鏤文采,不知喜也。何則?其所道之然。故民衣食 之財,家足以待旱水凶饑者,何也?得其所以自養之情,而不感於外也。是以其民儉而易治,其君用財節而易贍也。府庫實滿,足以待不然。兵革不頓,士民不勞, 足以征不服。故霸王之業,可行於天下矣。

當今之主,其為衣服則與此異矣,冬則輕煥,夏則輕凊,皆已具矣。必厚作斂於百姓,暴奪民衣食之財,以為錦繡文采靡曼之衣,鑄金以為鉤,珠玉以為珮,女工作文采,男工作刻鏤,以為身服,此非云益煥之情也。單財勞力,畢歸之於無用也,以此觀之,其為衣服非為身體,皆為觀好,是以其民淫僻而難治,其君奢侈而難諫也。夫以奢侈之君,御妤淫僻之民,欲國無亂,不可得也。君實欲天下之治而惡其亂,當為衣服不可不節。

古之民未知為飲食時,素食而分處,故聖人作誨男耕稼樹藝,以為民食。其為食也,足以增氣充虛,彊體適腹而巳矣。故其用財節,其自養儉,民富國治。今則不 然,厚作斂於百姓,以為美食芻豢,蒸炙魚鱉,大國累百器,小國累十器,前方丈,目不能遍視,手不能遍操,口不能遍味,冬則凍冰,夏則餲饐,人君為飲食如此,故左右象之。是以富貴者奢侈,孤寡者凍餒,雖欲無亂,不可得也。君實欲天下治而惡其亂,當為食飲,不可不節。

古之民未知為舟車時,重任不移,遠道不至,故聖王作為舟車,以便民之事。其為舟車也,完固輕利,可以任重致遠,其為用財少,而為利多,是以民樂而利之。故法令不急而行,民不勞而上足用,故民歸之。

當今之主,其為舟車與此異矣。完固輕利皆已具,必厚作斂於百姓,以飾舟車。飾車以文采,飾舟以刻鏤,女子廢其紡織而脩文采,故民寒。男子離其耕稼而脩刻鏤,故民饑。人君為舟車若此,故左右象之,是以其民饑寒並至,故為姦邪。姦邪多則刑罰深,刑罰深則國亂。君實欲天下治而惡其亂,當為舟車,不可不節。

凡回於天地之間,包於四海之內,天壤之情,陰陽之和,莫不有也,雖至聖不能更也。何以知其然?聖人有傳:天地也,則曰上下;四時也,則曰陰陽;人情也,則 曰男女;禽獸也,則曰牡牝雄雌也。真天壤之情,雖有先王不能更也。雖上世至聖,必蓄私,不以傷行,故民無怨。宮無拘女,故天下無寡夫。內無拘女,外無寡 夫,故天下之民眾。當今之君,其蓄私也,大國拘女累千,小國累百,是以天下之男多寡無妻,女多拘無夫,男女失時,故民少。君實欲民之眾而惡其寡,當蓄私不可不節。

凡此五者,聖人之所儉節也,小人之所淫佚也。儉節則昌,淫佚則亡,此五者不可不節。夫婦節而天地和,風雨節而五穀孰,衣服節而肌膚和。


三辯
程繁問於子墨子曰:“夫子曰:‘聖王不為樂’,昔諸侯倦於聽治,息於鐘鼓之樂;士大夫倦於聽治,息於竽瑟之樂;農夫春耕、夏耘、秋斂、冬藏,息於瓴缶之樂。今夫子曰:‘聖王不為樂’,此譬之猶馬駕而不稅,弓張而不弛,無乃非有血氣者之所不能至邪?”

子墨子曰:“昔者堯舜有茅茨者,且以為禮,且以為樂。湯放桀於大水,環天下自立以為王,事成功立,無大後患,因先王之樂,又自作樂,命曰《護》,又脩《九招》。武王勝殷殺紂,環天下自立以為王,事成功立,無大後患,因先王之樂,又自作樂,命曰《象》。周成王因先王又自作樂,命曰《騶虞》。周成王之治天下也,不若武王。武王之治天下也,不若成湯。成湯之治天下也,不若堯舜。故其樂逾繁者,其治逾寡。自此觀之,樂非所以治天下也。”

程繁曰:“子曰:‘聖王無樂’。此亦樂已,若之何其謂聖王無樂也?”子墨子曰:“聖王之命也,多寡之。食之利也,以知饑而食之者智也,因為無智矣。今聖有樂而少,此亦無也。”

2008年12月14日 星期日

迷人的 git

如果你常常寫 code,一定會遇到一種情況:寫改目前會動的 code,又怕會改壞…這時,就是 SCM (Source Code Management) 程式的時候了。

前一陣子,不知怎麼的,好幾個朋友問我,他們公司/專案要選 SCM,要選用那一個呢?

SCM 百百種… CVS SVN SVK Monotone bitkeeper git etc. etc.
要用那一個比較好呢?

在過去…我會說 SVN, SVN 比 CVS 方便多了,流水號的機制讓開發過程相當的清晰。
現在我強烈推薦 git
自從用了 git 之後~我已經離不開 git 了…

為什麼呢?
1. 因為我用 notebook 寫 code, 這表示我可能會在辦公室寫,在家寫,睡不著時在床上寫,在無聊的會議中寫,在坐車時寫,在山林中寫… 而且我寫的東西大多要merge 回 upstream。可是很多地方是沒有網路的。或是網路不好…如果我用SVN 的話…就必需開始用 quilt寫 patch 了…管理 Code 變得相當的麻煩。
Git 是一個分散式的 SCM,也就是在你目前工作的環境下,就是一個完整的 source code repository. 當你從網路上用 git 抓下 code 的同時,你已經把完整的開發 tree 抓回來,放在你的電腦之中了…而 commit code 時也是 commit 到你 local 端之中。所以你就可以一直寫,到處寫,直到你有網路之時再一次 push 回去…
2. 我很愛改 Code,而 git 的版本管理是用 patch 做出來的,也就是說 branch 會變得相當的容易。當我想做任何風險較大的變動時,可以先開一個 branch 出來,在裏面惡搞一翻。如果結果不錯的話,就 merge 回主要的 branch。
3. git 超級快,因為 git 把所有的 patch 都抓回來了,要做 diff ,翻 log 就變成超級快速而且穩定的事。
4. 支援 SVN 和 CVS,git-svn 可以把 svn 之中的所有 commit 變成 git 之中的一個 branch。
也就是不管upstream 用的是 SVN or CVS ,我都可以用 git 來管理。事實上,還有一些更好玩的玩法
5. SHA1-hash 的版本管理方式,讓 git 跳脫 SVN 之類強烈線性的版本管理…可以 rebase, cherry-pick ...
6. 開始一個 repository 超級方便,git init 就好了

Anyway 說了這麼多好處…怎麼用呢?就先給 link 嘍…
戒色夫 "我愛 Git"
Git User manual

我不打算在這寫另一個 manual 就寫幾個個人覺得很實用的 use cases.
1.做實驗
當你的 master branch 可以 run,但你想要對某個演算法大修時…
a. git checkout -b test_xxxx
b. 大修你的演算法…且 做細部的 commit,直到完成
c. git checkout master 回到本來的 master
d. git pull 把再新的 master 拉回來
e. git checkout test_xxxx
f. git rebase master 把再新的 master commit rebase 上去…可能會要解 conflict
(c, d, e, f, 可變成 git fetch origin/master; git rebase -i origin/master)
g. git checkout master
h.1 git rebase test_xxxx 把 test_xxxx 的東西再 rebase 過來
h.2 git cherry-pick xxxxxx 把某個 patch 挑過來
i. git push 把修改送回main stream

2.用 git-svn 搬 SVN repository
如 project P 要從 repository A 搬到 B 玩法如下
a. mkdir A_svn; pushd A_svn; git svn init http://A/trunk/ ;git svn fetch; popd
b git clone file://`pwd`/A_svn B_svn
c. cd B_svn; git svn init http://B/trunk/
d. git checkout -b master_tmp
e. git svn init http://B/trunk/ ; git svn fetch
f. git checkout -b svn --track git-svn
g. git checkout master; git rebase svn
h. git-rev-list master_tmp (suppose the last line is 532d2f35aa73331d409475efa84c00a1afa0e1a0)
i. git svn set-tree 532d2f35aa73331d409475efa84c00a1afa0e1a0
j. git rebase master_tmp; git svn dcommit

3. 粉飾太平
當 git commit 了一些笨笨的 code
可以用 git rebase -i xxxx 來拿掉/合並 一些 commit

2008年11月3日 星期一

心目中的 Linux development 課程建議

早上讀了一封某國立大學資訊系教授的信,百感交集。也不想評論些什麼…
就說說自已的想法罷了
我個人覺得,一個活在 AC 2008 Embedded GNU/Linux Software Developer 要會以下一些東西。
我認為…這只是基礎。這些會了,再來談創意…
光是空想,手上沒有工具,或是有工具不會用…只是白搭。

技術方面
* C programming
-- study forever...
-- Learning how to tracing code - Learning from the master

* Shell programming
-- Bash & awk & sed & grep & diff & patch
-- Python | Perl | Ruby

* Software testing
-- smoke test
-- boundary test
-- stress test
...

* cross toolchain.
-- Static link & Share Library
-- ABI
-- Dependency tree
-- How kernel execute programs & ELF study

* SCM
-- git
-- svn
-- cvs
-- patch
---- quilt

* Distribution structure
-- How system boots
-- Build a distribution from scratch

* Misc tools
-- gdb
-- valgrind
-- gprof
-- gcov
-- doxygen
-- autotools

文化方面
* Mailing List
* Bugzilla
* Hacker ethics
* IRC
* English
* Eat your dog food
* Coding style
* Knowledge management skill - search & skip

很明顯以上不是一門課就可以上完的,不過可以分散在幾門課之中。
0. 計概
1. OS
2. C programming
3. System programming
4. XXX 專題

作為:
. 老師自已開始始用 GNU/Linux or any Unix like system 把自已丟進 FOSS 的世界…會更有 fu

. 鼓勵學生在大一時,就學習用 GNU/Linux,以及使用公開格式文件。
學校為什麼要為 MS 做免費的廣告呢?
要求學生使用不是每個人都買得起的東西,使用不公開格式的文件…
這是不道德也不經濟的。
學生也可以真正的體會 FOSS 的文化,有興趣的人還可以真正深入了解系統的運作。

. 要求學生使用 gpg keys 以及使用 ssh key

. 作業用 git+ssh 繳交…

. 教導學生使用 Unix 下的一些超級工具
-- 一旦學會了…一輩子受益。可惜…很多老師自已不會,學一下吧。 ~>_<~

. 要求學生加入有名的 open source 的專案,成為期中作業。(以 commit log 為準)

. OS 課程之中,指派學生 Trace Linux kernel code ,對照 textbook 內容,且 present 給大家,作為作業。

. Algorithm 課程中,指派學生 Trace glibc | stdc | stdc++ | java library code ,使用,且學習用它們的 API 自已 cleanroom 一個出來,用 test framwork 來測。

. C programming 中,學生的每個程式作業,都要擺出 autotools 的架式,以及使用 doxygen 產生文件 (或不同工具)

. RTFM, 選一些重要的 manual 叫學生讀,學會讀文件和學會讀 code 是一樣重要的。

. 出幾題如 pythonchallenge 之類的上機作業給學生…

. 要求程式作業要先交 .h 檔,先上 git

. 鼓勵學生訂 mailing list, 為課程開 mailing list,在上面討論課程和作業

. 老師也要學習新把戲 ;-) 如果您在教 GNU/Linux development 而上面的任何 Item 不清楚的話,或不了解怎麼做的話…也許要再 update 一下您的 knowledge 了。

基礎很重要。手中有工具,才能玩遊戲。

小弟其實懂得不多,每天也還忙著學新東西,不過看完了某教授的信後,心裏是這麼想的。

2008年10月30日 星期四

Neo 機器人

月初從朋友那拿了一個控制 servo 的 LSC chip,以及一雙由 servo 組成的腳…
就在想,能不能拿 Neo 來做機器人呢?

Neo 上有兩個 g-sensor ,GPS chip,2.5G GSM chip, bluetooth,還有 wifi…
如果它能動…那會有多可怕… 拿它來開船、開飛機。可用 bluetooth wifi 和 GSM 來遙控…
應該會是一個很好玩的東西…

為了可以在 Neo 上能快快樂樂的玩 servo ,我開了個小案子:LSCD

把 servo 的 driver 寫好,再寫一個 python-binding... 就可以快快樂樂的玩了

liblscd 是控制 chip 的 API 可讀寫每個servo 的角度和速度。
pylsc 是 liblscd 的 python binding
在 tests 中還有一個 robot.py ,可以用來控制由 servo 組合而成的 robot...
未來想把 pylsc 寫成 freesmartphone 的一個 service 如此就可以和 phone event manager 整合在一起… (感覺起來可以做很多壞事 :P )


怎麼玩呢?
1. kernel 要有 HIDDEV drvier (Debian default 有,Ubuntu 沒有), Neo 從今天開始的 stable kernel 就會有 :P

2.1 在 laptop 上玩:
a. 安裝 gcc python cython pyrex python2.5-dev intltool libgettextpo-dev libtool automake autoconf make subversion
b. > svn checkout http://lscd.googlecode.com/svn/trunk/ lscd
c. > cd lscd
> ./autogen.sh
> make
> sudo make install
d. 接上 LSC device, sudo chmod 777 /dev/usb/hiddev0
e. 就可以進 test 來玩 robot.py 了
2.2 在 Neo 上玩
a. wget http://lscd.googlecode.com/files/liblscd0_armv4t.opk
b. opkg install
liblscd0_armv4t.opk
c. 用 wifi or bluetooth 連進Neo
http://wiki.openmoko.org/wiki/Wifi

http://wiki.openmoko.org/wiki/Manually_using_Bluetooth#Bluetooth_networking_with_a_Linux_system
d. 把 usb 切到 host mode http://wiki.openmoko.org/wiki/USB_host#Selecting_USB_host_modes
e. 接上 LSC device (要有一個 mini 公 <----> USB B公的線, 可以用組合的)
example:
(mini公 <--> A 公 | A 母 <--> A 母 | A公<-->B 公)
f. 就可以玩了 ^_^

除了接線外…一切都可寫成 script :P




2008年10月23日 星期四

kernel indent 備忘

indent -kr -i8 -ts8 -sob -l80 -ss -bs -ps1

也可以看 scripts/Lindent

2008年9月10日 星期三

Share Screen 備忘

Screen 是一個很古老又好用的工具,雖然自已不是很常用…不過有時在幫別人做一些事情時,我們可以用 screen 的 share 功能,多人同時使用同一個 screen。在 demo,教學上實在蠻方便的。
很久之前有在用,不過一陣子沒用後就忘了,寫下來以免自已又忘掉。

1. sudo chmod u+s /usr/bin/screen
2. sudo chmod 755 /var/run/screen
3. screen
4.在另一個 terminal 上 screen -x

如要多人 share

1. ^a + :multiuser on
2. ^a + :acladd

3. 另一個人就可以 screen -x /[pid] 連上去

2008年7月30日 星期三

Using git-svn migrate svn repository server

Suppose we create a project on one SVN repository server say A, however that server is going to close and disappear. And we still want to develop that project. So we found another repository server say B as our new host. However if we cannot use svnadmin commit on server B.(if you can you can use this) How do we migrate?

git-svn gives us a chance to do such thing.

Now we have server A and want to migrate project to server B.

support you are in /tmp
1. git-svn clone svn://server_A/my_project my_project_from_A
2. git clone file:///tmp/my_project_from_A my_project_sent_to_B
3. cd my_project_sent_to_B
4. git-svn init svn+ssh://whoyouare@server_B/my_project
(Here svn://server_B/my_project should be empty, make sure you can commit)
5. git-svn fetch
6. git-svn set-tree [the very first one commit in master]
note:1
7. git-svn dcommit
Done, Happy hacking...

Step 1: clone the svn log from old repository (let it read only)
Step 2: does not clone the svn infomation in server_A, so that we will have a clean space to do the hack
Step 4, 5: get the information from Server_B and get the initial point

Step 6: push the very first one commit in master to server B svn
Step 7: commit the whole tree to server B

Combining these skills actually you can migrate/convert/clone many kinds of SCM.

extension reading:GIT first SVN later
Note 1:If you meet
CONFLICT (delete/modify): XXXX deleted in HEAD and modified in adding License declare. Version adding License declare or XXXX left in tree.

you can
git status
then
git add (those unmerged files/directories)
git rebase --continue

2008年7月17日 星期四

Easy Sample to create ipk files

step 1. ceate 2 new temp dirs say "_ipkg_temp" "_ipkg_tar"
step 2. use _ipkg_temp as root directory put your stuff there:
for example:
usr/bin/lala.sh
step 3. pushd _ipkg_temp; tar -czf ../ipkg_tar/data.tar.gz .; rm -rf * ; popd
step 4. create control file in _ipkg_temp
fill the following fields: (CONTROL="control")
        echo "Package: Your_package_name"   >  ${CONTROL}
echo "Version: 0.1" >> ${CONTROL}
echo "Description: your_descriptions">> ${CONTROL}
echo "Section: base" >> ${CONTROL}
echo "Priority: optional" >> ${CONTROL}
echo "Maintainer: Noname" >> ${CONTROL}
echo "Architecture: all" >> ${CONTROL}
echo "Homepage: http://ooo.xxx.vvv/svn/trunk" >> ${CONTROL}
echo "Tags: group::unknown" >> ${CONTROL}
echo "Depends: ooxxooxx" >> ${CONTROL}
echo "Source: http://ooxxooxx.ooxx.vvvoo/" >> ${CONTROL}
then tar -czf ../_ipkg_tar/control.tar.gz .
step 5. in _ipkg_tar create debian-binary file contents 2.0
echo "2.0" > debian-binary
step 6. in _ipkg_tar ar the ipkg file
ar -crf ooxx_0.1_arm.ipkg debian-binary data.tar.gz control.tar.gz

Done :-)

reference http://code.google.com/p/comic-reader/source/browse/trunk/packer/pack_eet2ipk.sh

2008年7月3日 星期四

Icescream

和大家分享一個好物: ICE SCREAM



它是一個分散式的 compiler 架構…
在Debian 和 Ubuntu 下相當好安裝… 只要
sudo aptitude install icecc icecc-monitor
然後
export PATH=/usr/lib/icecc/bin:$PATH
就好了

在同一個網域下,把一台機器設成 scheduler (一台就好)
cat /etc/default/icecc
# Defaults for icecc initscript
# sourced by /etc/init.d/icecc
START_ICECC="true"
START_ICECC_SCHEDULER="false"

把 false 改成 true
sudo /etc/init.d/icecc restart
一切就搞定了…

今天下午用了 10 台 4 CPU 的機器玩了一下 compile qtopia
make -j 20
本來要一個 CPU 要compile 快兩個小時的東西,十幾分鐘就搞定了。

^_^

2008年6月25日 星期三

sudoku solver partII

Sudoku Solver 比賽順利結束了,這個比賽相當看重速度,所以在加速和結構上做了相當大的取捨,也對於 python 這個語言的特性有一些更深入的了解。(這是小弟的第二支 python 程式)
和大家分享一下小弟的加速過程…

1. 第一步當然是先寫 Test Framework
Filename: testcase.py

#!/usr/bin/python

import sys
import tick_solver

if sys.argv.__len__() >= 2 and sys.argv[1] :
name = sys.argv[1]
else:
name = "case_01.txt"

bb = tick_solver.Board()
bb.file_read(name)

def TC_Board_group_get(bb):
if bb.group_get(0, 0) == 0 and \
bb.group_get(2, 2) == 0 and \
bb.group_get(2, 3) == 1 and \
bb.group_get(8, 8) == 8 and \
bb.group_get(5, 7) == 5 and \
bb.group_get(6, 7) == 8 and \
bb.group_get(3, 10) == -1 and \
bb.group_get(3, 0) == 3:
print "group_get passed!!"
else:
print "group_get failed!!"

def TC_Board_data_print(bb):
bb.data_print()
bb.pretty_print()

def TC_Board_group_print(bb):
for i in range(0,9):
print "Rows["+str(i)+ "]=" + str(bb.Rows[i].left)
print "Columns["+str(i)+ "]=" + str(bb.Columns[i].left)
print "Groups["+str(i)+ "]=" + str(bb.Groups[i].left)

def TC_Board_possible_value_get(bb):
for x in range(0,9):
for y in range(0,9):
print "("+str(x)+","+str(y)+") = "+str(bb.possible_value_get(x,y))

def TC_Board_puzzle_solving(bb):
bb.puzzle_solving()
bb.pretty_print()

import cProfile
def _TC_Board_profileing():
BB.run(LALA)

def TC_Board_profileing():
cProfile.run('BB.run(LALA)')

LALA = bb.data[:]
TC_Board_group_get(bb)
TC_Board_data_print(bb)
TC_Board_group_print(bb)
TC_Board_possible_value_get(bb)
bb.pretty_print()
BB = tick_solver.Board()
TC_Board_profileing()
BB.pretty_print()


再開始實做… (小弟習慣先寫 test case 再來寫實做,testcase 會和程式一同成長)
2. 決定演算法
從google 上找出sudoku 的rule
a. 每個 raw 的九個數字都不同
b. 每個 column 的九個數字都不同
c. 每個 group 的九個數字都不同
依這三條 rule 找出 candidates , 再從candidate 最少的 cell 猜起。
trace 的路徑是走迷宮的方式。

3. 開出 functions 實作每個 function , 先不管速度,先正確了再說

Filename: tick_solver.py


ROWS=9
COLUMNS=9
TOTAL_ELEMENTS=81

class Group:
def __init__(self):
self.left = range(1, COLUMNS+1)
def set(self, x):
if self.left.__contains__(x):
self.left.remove(x)
return True
return False
def unset(self, x):
if not self.left.__contains__(x):
self.left.append(x)
return True
return False
def candidate(self):
return self.left

class Cmd_Node:
def __init__(self, x, y, v, Data):
self.x = x
self.y = y
self.v = v
self.D = []
self.tried = []
for d in Data:
if d != v:
self.D.append(d)
self.tried.append(v)

def retry(self):
v=self.D.pop()
self.tried.append(v)
self.v = v;
return v;
def pretty_print(self):
print "x="+str(self.x)+" y="+str(self.y)+" v="+str(self.v)+" D="+str(self.D)+ " Tried="+str(self.tried)

class Board:
def __init__(self, name="case_01.txt"):
self.num_rest=TOTAL_ELEMENTS
self.trace = []
self.DATA = []
self.data = []
self.Rows = []
self.Columns = []
self.Groups = []
self.name = name
for i in range(0, ROWS):
self.Rows.append(Group())
self.Columns.append(Group())
self.Groups.append(Group())
for i in range(0, ROWS):
self.data.append([0, 0, 0, 0, 0, 0, 0, 0, 0])
self.DATA.append([[], [], [], [], [], [], [], [], []])
if not self.file_read(self.name):
print "Warning: Bad sudoku!!"


# index from 0 - 8
def value_set(self, x, y, v):
if (v==0):
return True
if self.Columns[y].candidate().__contains__(v) and \
self.Rows[x].candidate().__contains__(v) and \
self.Groups[self.group_get(x,y)].candidate().__contains__(v):
self.data[x][y] = v
self.Columns[y].set(v)
self.Rows[x].set(v)
self.Groups[self.group_get(x,y)].set(v)
self.num_rest = self.num_rest - 1;
return True
return False

def value_unset(self, x, y):
v = self.data[x][y]
self.data[x][y] = 0
self.Columns[y].unset(v)
self.Rows[x].unset(v)
self.Groups[self.group_get(x,y)].unset(v)
self.num_rest = self.num_rest + 1;
for x in range(0,9):
for y in range(0,9):
self.DATA[x][y] = self.possible_value_get(x,y)


def group_get(self, x, y):
#if (x < 0 or x > 8 or y < 0 or y > 8):
# return -1
return int(x/3)*3 + int(y/3)

def data_print(self):
print self.data

def pretty_print(self):
for i in range(0,ROWS):
print self.data[i]

def file_read(self, name):
f = open(name, "r")
for x in range(0,9):
for y in range(0,9):
if not self.value_set(x,y,int(f.read(2))):
print "Bad sudoku!!"
return False
return True

def possible_value_get(self, x, y):
if (self.data[x][y] != 0):
return
ans = [];
Group = self.Groups[self.group_get(x, y)].candidate()
Row = self.Rows[x].candidate()
Column= self.Columns[y].candidate()
for i in Group:
if i in Row and i in Column:
ans.append(i);
return ans;

def puzzle_solving_iterate(self):
min_x = 0
min_y = 0
min=10
for x in range(0,9):
for y in range(0,9):
pos = self.possible_value_get(x,y)
self.DATA[x][y] = pos
if pos == None:
continue
if len(pos) == 1:
v = pos[0]
self.value_set(x,y,v)
self.trace.append(Cmd_Node(x,y,v, pos))
if pos.__len__() < min:
min_x = x
min_y = y
min = pos.__len__()
if min == 1:
return True
#guess has to be made
if self.DATA[min_x][min_y].__len__() > 0:
guess = self.DATA[min_x][min_y][0]
self.trace.append(Cmd_Node(min_x, min_y, guess, self.DATA[min_x][min_y]))
return self.value_set(min_x, min_y,guess)
return False

def puzzle_solving(self):
while self.num_rest > 0:
if self.puzzle_solving_iterate():
continue
continue_flag=True
while continue_flag:
cmd = self.trace.pop()
if cmd.D.__len__()==0:
self.value_unset(cmd.x, cmd.y)
continue
self.value_unset(cmd.x, cmd.y)
for x in range(0,9):
for y in range(0,9):
pos = self.possible_value_get(x,y)
self.DATA[x][y] = pos
while cmd.D.__len__() > 0:
v = cmd.retry()
if self.DATA[cmd.x][cmd.y].__contains__(v):
self.value_set(cmd.x, cmd.y, v)
self.trace.append(cmd)
continue_flag = False
break




4. run a lot of test cases to check out the bottleneck

如 case

0 7 8 1 0 0 5 0 0
0 0 6 0 0 0 0 0 0
5 0 0 0 4 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 4 8 0 0 0 0 0
0 0 0 0 0 9 2 0 3
0 0 1 0 0 2 0 0 8
9 6 3 0 0 0 0 5 0
0 0 0 4 0 0 3 0 9

以下是test case 分析出來的結果

172502 function calls in 0.651 CPU seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.651 0.651 :1()
1 0.000 0.000 0.651 0.651 testcase.py:45(_TC_Board_profileing)
1 0.000 0.000 0.002 0.002 tick_solver.py:102(file_read)
34101 0.318 0.000 0.507 0.000 tick_solver.py:111(possible_value_get)
98 0.033 0.000 0.188 0.002 tick_solver.py:123(puzzle_solving_iterate)
909 0.004 0.000 0.005 0.000 tick_solver.py:14(unset)
1 0.006 0.006 0.649 0.649 tick_solver.py:150(puzzle_solving)
53544 0.079 0.000 0.079 0.000 tick_solver.py:19(candidate)
341 0.002 0.000 0.002 0.000 tick_solver.py:23(__init__)
20 0.000 0.000 0.000 0.000 tick_solver.py:34(retry)
1 0.000 0.000 0.002 0.002 tick_solver.py:43(__init__)
442 0.007 0.000 0.017 0.000 tick_solver.py:64(value_set)
27 0.000 0.000 0.000 0.000 tick_solver.py:7(__init__)
303 0.064 0.000 0.424 0.001 tick_solver.py:78(value_unset)
1152 0.004 0.000 0.006 0.000 tick_solver.py:9(set)
18535 0.044 0.000 0.044 0.000 tick_solver.py:90(group_get)
4397 0.006 0.000 0.006 0.000 {len}
52821 0.073 0.000 0.073 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
323 0.001 0.000 0.001 0.000 {method 'pop' of 'list' objects}
81 0.000 0.000 0.000 0.000 {method 'read' of 'file' objects}
1152 0.002 0.000 0.002 0.000 {method 'remove' of 'list' objects}
1 0.000 0.000 0.000 0.000 {open}
4249 0.008 0.000 0.008 0.000 {range}


我們會發現
possible_value_get被 call 了 34101 次,花了 0.318 秒
candidate 被 call 了 53544 次…花了 0.079 秒
list 的 append 被 call 了 52821 次 花了 0.073 秒

種種的數據告訴我 possible_value_get 是最大的 bottleneck
array 的 operation 過於 大量且昂貴
而在這,我選擇的方式是…改變 Group 存數字的方式:用 binary operations
所以 Group 就變成了

class Group:
def __init__(self, value=0x1ff):
self.left = value
def set(self, x):
if self.left & (1 << (x-1)):
self.left &= (~(1<< (x-1)))
return True
return False
def unset(self, x):
if not self.left & (1 << (x-1)):
self.left |= (1 << (x-1))
return True
return False
def contains(self, x):
return not not self.left & (1 << (x-1))
def len(self):
ans = 0
v = self.left;
while v:
v &= v -1
ans += 1
return ans

def len(v):
ans=0
while v:
v &= v - 1
ans += 1
return ans

def min_value(V):
v=1
while not V & 1:
V = V >> 1
v+=1
return v


而 possible_value_get 變成了

def possible_value_get(self, x, y):
return self.Groups[(int(x/3)*3 + int(y/3))].left & self.Rows[x].left & self.Columns[y].left


沒錯…就變成了兩個 operations
而時間從 變成 0.651

27546 function calls in 0.126 CPU seconds
Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.126 0.126 :1()
1 0.000 0.000 0.126 0.126 testcase.py:45(_TC_Board_profileing)
1 0.001 0.001 0.002 0.002 tick_solver.py:114(file_read)
7280 0.024 0.000 0.024 0.000 tick_solver.py:127(possible_value_get)
128 0.042 0.000 0.104 0.001 tick_solver.py:136(puzzle_solving_iterate)
1161 0.002 0.000 0.002 0.000 tick_solver.py:14(unset)
1 0.007 0.007 0.124 0.124 tick_solver.py:172(puzzle_solving)
1404 0.002 0.000 0.002 0.000 tick_solver.py:19(contains)
12148 0.028 0.000 0.028 0.000 tick_solver.py:29(len)
415 0.001 0.000 0.001 0.000 tick_solver.py:37(__init__)
30 0.000 0.000 0.000 0.000 tick_solver.py:44(retry)
1 0.000 0.000 0.002 0.002 tick_solver.py:56(__init__)
27 0.000 0.000 0.000 0.000 tick_solver.py:7(__init__)
526 0.007 0.000 0.013 0.000 tick_solver.py:76(value_set)
1404 0.003 0.000 0.003 0.000 tick_solver.py:9(set)
387 0.003 0.000 0.006 0.000 tick_solver.py:90(value_unset)
490 0.001 0.000 0.001 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
387 0.001 0.000 0.001 0.000 {method 'pop' of 'list' objects}
161 0.000 0.000 0.000 0.000 {method 'read' of 'file' objects}
1 0.000 0.000 0.000 0.000 {open}
1591 0.003 0.000 0.003 0.000 {range}


從快的我們會發現 bottleneck 變成了
12148 0.028 0.000 0.028 0.000 tick_solver.py:29(len)
7280 0.024 0.000 0.024 0.000 tick_solver.py:127(possible_value_get)
由於我是用 binary operation 算 len 變成一個 cost 相當高的事。而小弟覺得用查表法實在不夠好玩… 就是不肯用,所以就找出 len 的使用點,只做最必要的計算。(其實還可以用其它變數去存…這也會比較快)
而possible_value_get 其實已經很快了…可是因為被 call 的次數很多,所以太花時間 (大多在 type checking 和 stack jump) 所以就直接 inline 到被 call 的地方

如此一直找 bottleneck 的位置,不停的 "反" refactoring
最後變成

2655 function calls in 0.039 CPU seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.039 0.039 :1()
387 0.002 0.000 0.002 0.000 tick_solver.py:107(value_unset)
1 0.000 0.000 0.000 0.000 tick_solver.py:137(array_get)
1 0.031 0.031 0.038 0.038 tick_solver.py:149(puzzle_solving)
387 0.001 0.000 0.001 0.000 tick_solver.py:29(len)
415 0.001 0.000 0.001 0.000 tick_solver.py:44(__init__)
30 0.000 0.000 0.000 0.000 tick_solver.py:51(retry)
1 0.000 0.000 0.000 0.000 tick_solver.py:68(reinit)
27 0.000 0.000 0.000 0.000 tick_solver.py:7(__init__)
1 0.000 0.000 0.039 0.039 tick_solver.py:84(run)
526 0.003 0.000 0.003 0.000 tick_solver.py:92(value_set)
490 0.001 0.000 0.001 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
387 0.001 0.000 0.001 0.000 {method 'pop' of 'list' objects


又快了三倍 ^_^

然而在高興之餘卻發現到有一些 test case 會跑非常的久

tick@tock:~/work/sudoku>./testcase.py case_09.txt
[0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 9, 0, 0]
[0, 0, 0, 0, 6, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 9, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 5, 0]
[0, 0, 0, 0, 0, 0, 8, 0, 0]
[0, 9, 0, 0, 0, 0, 0, 3, 0]
[0, 0, 0, 7, 0, 0, 0, 0, 0]
3838777 function calls in 47.685 CPU seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 47.685 47.685 :1()
1 0.000 0.000 47.685 47.685 testcase.py:47(_TC_Board_profileing)
1 0.000 0.000 0.001 0.001 tick_solver.py:134(array_get)
1 36.462 36.462 47.684 47.684 tick_solver.py:181(puzzle_solving)
639734 1.038 0.000 1.038 0.000 tick_solver.py:29(len)
568664 1.425 0.000 1.425 0.000 tick_solver.py:37(__init__)
71141 0.297 0.000 0.297 0.000 tick_solver.py:44(retry)
1 0.000 0.000 0.000 0.000 tick_solver.py:61(reinit)
27 0.000 0.000 0.000 0.000 tick_solver.py:7(__init__)
1 0.000 0.000 47.685 47.685 tick_solver.py:77(run)
639886 3.827 0.000 3.827 0.000 tick_solver.py:85(value_set)
639734 2.801 0.000 2.801 0.000 tick_solver.py:99(value_unset)
639850 0.893 0.000 0.893 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
639734 0.942 0.000 0.942 0.000 {method 'pop' of 'list' objects}


[7, 6, 9, 1, 2, 8, 3, 4, 5]
[1, 2, 8, 3, 4, 5, 9, 6, 7]
[3, 4, 5, 9, 6, 7, 1, 2, 8]
[6, 5, 7, 2, 1, 3, 4, 8, 9]
[2, 8, 3, 5, 9, 4, 6, 7, 1]
[9, 1, 4, 8, 7, 6, 2, 5, 3]
[5, 7, 2, 4, 3, 1, 8, 9, 6]
[8, 9, 1, 6, 5, 2, 7, 3, 4]
[4, 3, 6, 7, 8, 9, 5, 1, 2]

這是因為我走迷宮時用相當簡單的 guess ,找出最小的 candidate
而很不幸,在一些迷宮中…(尤其是那些只有唯一解的)一但走錯… cost 就會走很遠,再走回來…這是我在演算法上的miss。所以就再加上了一些演算法來做相當複雜的 guess。而演算法的選擇也是很出現機率最高的來選擇… 只為 hard guess 相當的花時間…所以我只有在題目相當困難時 (最少candidate 的cell 依然有超過三個選擇時) (關鍵少數) 才去做。其它的,就交給暴力走迷宮法。

而 hard guess 也很成功的減少了 retry 的次數… ^^;

tick@tock:~/work/sudoku>./testcase.py case_09.txt
[0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 9, 0, 0]
[0, 0, 0, 0, 6, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 9, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 5, 0]
[0, 0, 0, 0, 0, 0, 8, 0, 0]
[0, 9, 0, 0, 0, 0, 0, 3, 0]
[0, 0, 0, 7, 0, 0, 0, 0, 0]
372 function calls in 0.028 CPU seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.028 0.028 :1()
1 0.000 0.000 0.001 0.001 tick_solver.py:137(array_get)
1 0.025 0.025 0.027 0.027 tick_solver.py:149(puzzle_solving)
71 0.000 0.000 0.000 0.000 tick_solver.py:44(__init__)
1 0.000 0.000 0.000 0.000 tick_solver.py:68(reinit)
27 0.000 0.000 0.000 0.000 tick_solver.py:7(__init__)
1 0.000 0.000 0.028 0.028 tick_solver.py:84(run)
152 0.001 0.000 0.001 0.000 tick_solver.py:92(value_set)
116 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}


[8, 2, 5, 1, 7, 9, 3, 4, 6]
[4, 1, 6, 3, 2, 5, 9, 7, 8]
[9, 3, 7, 4, 6, 8, 1, 2, 5]
[7, 5, 9, 2, 1, 6, 4, 8, 3]
[3, 4, 8, 5, 9, 7, 6, 1, 2]
[1, 6, 2, 8, 4, 3, 7, 5, 9]
[5, 7, 1, 9, 3, 2, 8, 6, 4]
[2, 9, 4, 6, 8, 1, 5, 3, 7]
[6, 8, 3, 7, 5, 4, 2, 9, 1]

有些地方被 inline 掉了 :P

以下是目前的 source code, 蠻髒的,不過也蠻好玩的

Filename: tick_solver.py


ROWS=9
COLUMNS=9
TOTAL_ELEMENTS=81

class Group:
def __init__(self, value=0x1ff):
self.left = value
def set(self, x):
if self.left & (1 << (x-1)):
self.left &= (~(1<< (x-1)))
return True
return False
def unset(self, x):
if not self.left & (1 << (x-1)):
self.left |= (1 << (x-1))
return True
return False
def contains(self, x):
return not not self.left & (1 << (x-1))
def len(self):
ans = 0
v = self.left;
while v:
v &= v -1
ans += 1
return ans

def len(v):
ans=0
while v:
v &= v - 1
ans += 1
return ans

def min_value(V):
v=1
while not V & 1:
V = V >> 1
v+=1
return v

class Cmd_Node:
def __init__(self, x, y, v, Data):
self.x = x
self.y = y
self.v = v
self.D = Data
self.D &= ~( 1 << (v-1) )

def retry(self):
v=0
while not self.D & (1 << v):
v+=1
self.D &= ~(1 << v);
v+=1
self.v = v;
return v;
def pretty_print(self):
print "x="+str(self.x)+" y="+str(self.y)+" v="+str(self.v)+" D="+str(self.D)

from test_module import *

class Board(TestModule):
def __init__(self):
self.reinit()

def reinit(self):
self.num_rest=TOTAL_ELEMENTS
self.trace = []
self.DATA = []
self.data = []
self.Rows = []
self.Columns = []
self.Groups = []
for i in xrange(0,9):
self.Rows.append(Group())
self.Columns.append(Group())
self.Groups.append(Group())
self.data.append([0, 0, 0, 0, 0, 0, 0, 0, 0])
self.DATA.append([ 0, 0, 0, 0, 0, 0, 0, 0, 0])


def run(self, array):
self.reinit()
self.array_get(array)
self.puzzle_solving()
return self.data


# index from 0 - 8
def value_set(self, x, y, v):
if (v==0):
return True
mask = (1<< (v-1))
if mask & self.Columns[y].left & self.Rows[x].left & self.Groups[(int(x/3)*3 + int(y/3))].left:
self.data[x][y] = v
mask = ~mask
self.Columns[y].left &= mask
self.Rows[x].left &= mask
self.Groups[(int(x/3)*3 + int(y/3))].left &= mask
self.num_rest = self.num_rest - 1;
return True
print "Set ("+str(x)+", "+str(y)+")="+str(v) +" Failed!!!"
return False

def value_unset(self, x, y):
v = self.data[x][y]
self.data[x][y] = 0
mask = (1 << (v-1))
self.Columns[y].left |= mask
self.Rows[x].left |= mask
self.Groups[(int(x/3)*3 + int(y/3))].left |= mask
self.num_rest = self.num_rest + 1;


def data_print(self):
print self.data

def pretty_print(self):
for i in xrange(0,9):
print self.data[i]

def file_read(self, name):
f = open(name, "r")
for x in xrange(0,9):
for y in xrange(0,9):
while True:
v = f.read(1)
if v >= '0' and v <= '9':
break;
if not self.value_set(x,y,int(v)):
print "Bad sudoku!!"
return False
return True

def array_get(self, array):
for x in xrange(0,9):
for y in xrange(0,9):
if not self.value_set(x,y,array[x][y]):
print "Bad sudoku!!"
return False
return True

def possible_value_get(self, x, y):
return self.Groups[(int(x/3)*3 + int(y/3))].left & self.Rows[x].left & self.Columns[y].left


def puzzle_solving(self):
while self.num_rest > 0:
min=10
for x in xrange(0,9):
for y in xrange(0,9):
if self.data[x][y]:
continue
pos = self.Groups[(int(x/3)*3 + int(y/3))].left & self.Rows[x].left & self.Columns[y].left
self.DATA[x][y] = pos
if pos == None:
continue
lentmp = 0
v = pos;
while v:
v &= v -1
lentmp += 1

if lentmp == 1:
v = 0
while not (pos & 1 << v):
v += 1
v += 1
self.value_set(x,y,v)
self.trace.append(Cmd_Node(x,y,v, pos))
if lentmp < min:
min_x = x
min_y = y
min = lentmp
if min == 1:
continue
#guess has to be made
if min > 0:
guess = 0
if min == 2:
while not (self.DATA[min_x][min_y] & 1 << guess):
guess += 1
guess += 1
else: # give a better guess here
Row = min_x % 3
R_base = min_x/3
Column = min_y % 3
C_base = min_y/3
V = self.DATA[min_x][min_y]
# remove hidden
while V:
a = V & 1
V = V >> 1
guess += 1
if not a:
continue
row_single_check = 0
column_single_check = 0
mask = (1 << (guess-1))
for i in [0, 1, 2]:
if Row != i and (self.Rows[R_base + i].left & mask):
row_single_check += 1
if Column != i and (self.Columns[C_base + i].left & mask):
column_single_check += 1
if row_single_check == 2 or column_single_check == 2: # guess first
break
#guess = self.hard_guess_find(min_x, min_y, self.DATA[min_x][min_y])
self.trace.append(Cmd_Node(min_x, min_y, guess, self.DATA[min_x][min_y]))
if self.value_set(min_x, min_y,guess):
continue


continue_flag=True
while continue_flag:
cmd = self.trace.pop()
lentmp = len(cmd.D)
if lentmp==0:
self.value_unset(cmd.x, cmd.y)
continue
self.value_unset(cmd.x, cmd.y)
for x in xrange(0,9):
for y in xrange(0,9):
if self.data[x][y]:
continue
self.DATA[x][y] = self.Groups[(int(x/3)*3 + int(y/3))].left & self.Rows[x].left & self.Columns[y].left
while lentmp > 0:
if lentmp==1:
v = cmd.retry()
if self.DATA[cmd.x][cmd.y] & (1<< (v-1)):
self.value_set(cmd.x, cmd.y, v)
self.trace.append(cmd)
continue_flag = False
break
else: # when there are more than one candidates, may be we can take long time to find out a better guess
v = self.hard_guess_find(cmd.x, cmd.y, cmd.D)
if self.DATA[cmd.x][cmd.y] & (1<< (v-1)):
cmd.D &= ~ (1<<(v-1))
self.value_set(cmd.x, cmd.y, v)
self.trace.append(cmd)
continue_flag = False
break
lentmp = len(cmd.D)

def hard_guess_find(self, x, y, V):
Row = x % 3
R_base = x/3
Column = y % 3
C_base = y/3
v = 0
# remove hidden
while V:
a = V & 1
V = V >> 1
v += 1
if not a:
continue
row_single_check = 0
column_single_check = 0
mask = (1 << (v-1))
for i in xrange(0,3):
if Row != i and (self.Rows[R_base + i].left & mask):
row_single_check += 1
if Column != i and (self.Columns[C_base + i].left & mask):
column_single_check += 1
if row_single_check == 2 or column_single_check == 2: # guess first
return v
return v


以下是跑 1000 個 test case 的分析圖 (用 octave 畫的)


可以看得出來其實大多數的 test case 都在 0.01 秒做完,而比較久的也在 0.02 秒內做完. 中位數在 0.003 秒
其實還有相當多地方可以改進… 如查表,pattern map等等…
不過…我個人覺得以一個小比賽來說…可以了… ^_^;

2008年6月19日 星期四

Sudoku solver

在公司內辦了一場 Python Sudoku solver 比賽
下星期二才會正式跑 benchmark ^^
今早寫了一下,加上一些 turning
就看著 code 是如何的一步一步的加速…
從開始到現在,竟然已經加速了 1000 多倍了…
可是 code 也越來越噁心…簡直就是 反refactoring
為了讓比賽更好玩… 先把 code post 出來了 ^_^


反正… just for fun :)

Filename: tick_solver.py


ROWS=9
COLUMNS=9
TOTAL_ELEMENTS=81

class Group:
def __init__(self, value=0x1ff):
self.left = value
def set(self, x):
if self.left & (1 << (x-1)):
self.left &= (~(1<< (x-1)))
return True
return False
def unset(self, x):
if not self.left & (1 << (x-1)):
self.left |= (1 << (x-1))
return True
return False
def contains(self, x):
return not not self.left & (1 << (x-1))
def len(self):
ans = 0
v = self.left;
while v:
v &= v -1
ans += 1
return ans

def len(v):
ans=0
while v:
v &= v - 1
ans += 1
return ans

class Cmd_Node:
def __init__(self, x, y, v, Data):
self.x = x
self.y = y
self.v = v
self.D = Data
self.D &= ~( 1 << (v-1) )

def retry(self):
v=0
while not self.D & (1 << v):
v+=1
self.D &= ~(1 << v);
v+=1
self.v = v;
return v;
def pretty_print(self):
print "x="+str(self.x)+" y="+str(self.y)+" v="+str(self.v)+" D="+str(self.D)


class Board():
def __init__(self):
self.num_rest=TOTAL_ELEMENTS
self.trace = []
self.DATA = []
self.data = []
self.Rows = []
self.Columns = []
self.Groups = []
for i in range(0, ROWS):
self.Rows.append(Group())
self.Columns.append(Group())
self.Groups.append(Group())
self.data.append([0, 0, 0, 0, 0, 0, 0, 0, 0])
self.DATA.append([ 0, 0, 0, 0, 0, 0, 0, 0, 0])

def run(self, array):
self.array_get(array)
self.puzzle_solving()


# index from 0 - 8
def value_set(self, x, y, v):
if (v==0):
return True
if self.Columns[y].contains(v) and \
self.Rows[x].contains(v) and \
self.Groups[(int(x/3)*3 + int(y/3))].contains(v):
self.data[x][y] = v
self.Columns[y].set(v)
self.Rows[x].set(v)
self.Groups[(int(x/3)*3 + int(y/3))].set(v)
self.num_rest = self.num_rest - 1;
return True
return False

def value_unset(self, x, y):
v = self.data[x][y]
self.data[x][y] = 0
self.Columns[y].unset(v)
self.Rows[x].unset(v)
self.Groups[(int(x/3)*3 + int(y/3))].unset(v)
self.num_rest = self.num_rest + 1;


def group_get(self, x, y):
if (x < 0 or x > 8 or y < 0 or y > 8):
return -1
return int(x/3)*3 + int(y/3)

def data_print(self):
print self.data

def pretty_print(self):
for i in range(0,ROWS):
print self.data[i]

def file_read(self, name):
f = open(name, "r")
for x in range(0,9):
for y in range(0,9):
while True:
v = f.read(1)
if v >= '0' and v <= '9':
break;
if not self.value_set(x,y,int(v)):
print "Bad sudoku!!"
return False
return True

def array_get(self, array):
for x in [0, 1, 2, 3, 4, 5, 6, 7, 8]:
for y in [0, 1, 2, 3, 4, 5, 6, 7, 8]:
if not self.value_set(x,y,array[x][y]):
print "Bad sudoku!!"
return False
return True

def possible_value_get(self, x, y):
return self.Groups[(int(x/3)*3 + int(y/3))].left & self.Rows[x].left & self.Columns[y].left

def puzzle_solving_iterate(self):
min_x = 0
min_y = 0
min=10
for x in range(0,9):
for y in range(0,9):
if self.data[x][y]:
continue
pos = self.Groups[(int(x/3)*3 + int(y/3))].left & self.Rows[x].left & self.Columns[y].left
self.DATA[x][y] = pos
if pos == None:
continue
lentmp = len(pos)
if lentmp == 1:
v = 0
while not (pos & 1 << v):
v += 1
v += 1
self.value_set(x,y,v)
self.trace.append(Cmd_Node(x,y,v, pos))
if lentmp < min:
min_x = x
min_y = y
min = lentmp
if min == 1:
return True
#guess has to be made
if min > 0:
guess = 0
while not (self.DATA[min_x][min_y] & 1 << guess):
guess += 1
guess += 1
self.trace.append(Cmd_Node(min_x, min_y, guess, self.DATA[min_x][min_y]))
return self.value_set(min_x, min_y,guess)
return False

def puzzle_solving(self):
while self.num_rest > 0:
if self.puzzle_solving_iterate():
continue
continue_flag=True
while continue_flag:
cmd = self.trace.pop()
lentmp = len(cmd.D)
if lentmp==0:
self.value_unset(cmd.x, cmd.y)
continue
self.value_unset(cmd.x, cmd.y)
for x in range(0,9):
for y in range(0,9):
if self.data[x][y]:
continue
self.DATA[x][y] = self.Groups[(int(x/3)*3 + int(y/3))].left & self.Rows[x].left & self.Columns[y].left
while lentmp > 0:
v = cmd.retry()
if self.DATA[cmd.x][cmd.y] & (1<< (v-1)):
self.value_set(cmd.x, cmd.y, v)
self.trace.append(cmd)
continue_flag = False
break

2008年6月14日 星期六

邪惡的小案子

提升大家宅度的邪惡計畫:
http://code.google.com/p/comic-reader/

2008年2月13日 星期三

Integrate Ecore_main_loop into gMainLoop

If we want to write a program with two kinds of event driven GUI libraries, we have to run each event processing function. There are some ways to do that.

When I was writing a program with EFL and glib, I met this problem.

There are two ways come up to me:
1. Write a multi thread program and each runs a main loop.
2. Put one main loop into another.

When I tried first one by writing two threads to dealing this problem, it works well, but I am very worry about the entropy of this program. It's too high, and complicated. I have to write spin lock to protect data.


static gpointer pk_thread(gpointer data) {
PConnect * pc = (PConnect *)data;
pc->loop = g_main_loop_new (NULL, FALSE);
debug("g_main_loop_run starts\n");
g_main_loop_run(pc->loop);
}

PConnect * pconnect_initial() {
PConnect * pc = (PConnect *)malloc (sizeof(PConnect));
memset(pc, 0, sizeof(PConnect));
if (! g_thread_supported ()) {
g_thread_init (NULL);
}
dbus_g_thread_init();
g_type_init ();
pc->thread = g_thread_create(pk_thread, (gpointer)pc, FALSE, &pc->error);
return pk_dbus_initial(pc);
}


The IPC becomes a nightmare.



After thinking for a while, I tried to merge ecore main loop into glib main loop.
Learning from Integrating QT/GTK
Both Ecore and Glib provides iterator event processing, so that I can wrap the ecore_main_loop_iterate into a GSource.

Make GMainLoop do a ecore_main_loop_iterate() once at each event processing by making preparing and checking always returns true.

Filename: mainlooptesting.c

#include <stdio.h>
#include <glib.h>
#include <Ecore.h>


static gboolean GEvas_prepare (GSource *source, gint *timeout_) {
return TRUE;
}

static gboolean GEvas_check(GSource *source) {
return TRUE;
}

static gboolean GEvas_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) {
ecore_main_loop_iterate ();
return TRUE;
}

static GSourceFuncs Iterator_funcs = {
GEvas_prepare,
GEvas_check,
GEvas_dispatch,
NULL,
NULL,
NULL
};

int evas_timer(void *data) {
printf("evas_timer ran!!!\n");
return 1;
}
gboolean glib_timer(gpointer data) {
printf("glib_timer ran!!!\n");
return TRUE;
}

int main (void) {
GMainContext *context = g_main_context_default();
GSource *source = g_source_new(&Iterator_funcs,sizeof(GSource));
GMainLoop *loop = g_main_loop_new (context,FALSE);
g_source_attach((GSource *)source, context);

ecore_timer_add(1.0f,evas_timer,NULL);
g_timeout_add(500,glib_timer,NULL);

g_main_run(loop);
}


I test each main loop by adding a timer event, and the following are results.
./a.out
glib_timer ran!!!
glib_timer ran!!!
evas_timer ran!!!
glib_timer ran!!!
glib_timer ran!!!
evas_timer ran!!!
glib_timer ran!!!
glib_timer ran!!!
evas_timer ran!!!
glib_timer ran!!!
glib_timer ran!!!
evas_timer ran!!!
^C

Works \^_^/

2008年1月14日 星期一

宅男遇上 Wii remote

前幾天看到同事分享 Johnny Lee的影片。心中有蠻大的震憾。一直認為 Wii Remote 已經很神奇了…沒想到還有那麼多的玩法…果然厲害。就開始想在自己的機器上玩玩 Wii Remote.

沒想到一切都是如此的美好: Ubuntu 已經有了 CWiid 的 package.
直接安裝後,把 bluetooth 打開,就可以玩了

身為一名陽光宅男…當然好好的研究一下這個好玩的東西…
也就寫了一支小小的程式…可以依 Wii remote 的水平改變小 Icon 的位置。

Filename: wii_toy.c

#include <wiimote.h>
#include <wiimote_api.h>
#include <Ecore_Evas.h>
#include <Ecore.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define WIDTH 800
#define HEIGHT 600

Ecore_Evas * ee;
Evas * evas;

struct remoter {
Evas_Object * o;
wiimote_t *wii;
double x,y,size;
};

inline void set_wiiremote(wiimote_t *wii) {
wii->led.one = 1;
wii->mode.ir = 1;
wii->mode.acc =1;
}

inline void change_position(struct remoter *handle) {
if ( abs(handle->wii->tilt.x) <= 90 &&
abs (handle->wii->tilt.y) <= 90) {

handle->x += (double)handle->wii->tilt.x/10.0f;
handle->y += (double)handle->wii->tilt.y/10.0f;
}
handle->x = handle->x <= 0 ? 0 : handle->x >= WIDTH - handle->size? WIDTH-handle->size : handle->x;
handle->y = handle->y <= 0 ? 0 : handle->y >= HEIGHT - handle->size? HEIGHT-handle->size : handle->y;


// fprintf(stderr, "remote: x=%3.3f y=%3.3f\n",handle->x,handle->y);
evas_object_move(handle->o, handle->x,handle->y);
}

inline void show_status(wiimote_t *wii) {
fprintf(stderr, "AXIS x=%03d y=%03d z=%03d\n",
wii->axis.x,
wii->axis.y,
wii->axis.z);
fprintf(stderr, "TILT x=%.3f y=%.3f z=%.3f\n",
wii->tilt.x,
wii->tilt.y,
wii->tilt.z);
fprintf(stderr, "FORCE x=%.3f y=%.3f z=%.3f\n",
wii->force.x,
wii->force.y,
wii->force.z);
fprintf(stderr,"\n");
}

int scan_wii_event(void *data) {
struct remoter *handle=(struct remoter *)data;
if (wiimote_is_open(handle->wii)) {
if (wiimote_update(handle->wii) < 0) {
printf("Update Failed!! Exit!!\n");
wiimote_disconnect(handle->wii);
exit(1);
}
if (handle->wii->keys.home) {
printf("Home pressed!! Exit!!\n");
wiimote_disconnect(handle->wii);
exit(1);
}
change_position(handle);
//show_status(handle->wii);
}
return 1;
}

int main(int argc,char **argv) {
struct remoter handle;
if (argc < 2) {
fprintf(stderr, "Usage: test1 BDADDR\n");
exit(1);
}
Evas_Object * background;
ecore_evas_init();

ee = ecore_evas_software_x11_new(NULL, 0, 0, 0, WIDTH, HEIGHT);
ecore_evas_title_set(ee, "Tick's Wii Toy");
// ecore_evas_borderless_set(ee, 1); // borderless
ecore_evas_borderless_set(ee, 0); // border
ecore_evas_show(ee);


evas = ecore_evas_get(ee);
evas_font_path_append(evas, "fonts/");


background = evas_object_rectangle_add(evas);
evas_object_color_set(background,30,30,30,255);
evas_object_resize(background, WIDTH, HEIGHT);
evas_object_move( background,0 ,0 );
evas_object_focus_set(background, 1);
evas_object_show( background);

handle.size = 64;
handle.x=(WIDTH-handle.size)/2;
handle.y=(HEIGHT-handle.size)/2;
handle.o = evas_object_image_add(evas);
evas_object_image_file_set (handle.o, "/home/tick/work/e17/icon.png" ,NULL);
if (evas_object_image_load_error_get(handle.o)) {
printf("Evas can't load PNG files. Check Evas has PNG\n");
return 1;
}
evas_object_color_set(handle.o,255,255,255,128);
evas_object_move(handle.o, handle.x,handle.y);
evas_object_resize(handle.o,handle.size,handle.size);
evas_object_image_fill_set(handle.o, 0, 0, handle.size, handle.size);
evas_object_show(handle.o);

printf("Please press 1+2 to connect Wii remote!!\n");
handle.wii = wiimote_open(argv[1]);
if (!handle.wii) {
fprintf(stderr, "unable to open wiimote:\n");
exit(1);
}
printf("Connecting.......\n");
set_wiiremote(handle.wii);
ecore_timer_add(.01,scan_wii_event, &handle);
ecore_main_loop_begin();

return 0;
}




使用:
1.先下 /etc/init.d/bluetooth start 打開bluetooth
2.按下 Wii remote 的 1+2 鍵
3.當 Wii remote 的Led 還在閃時,做 hcitool scan 找出你的 remote bdaddr
4. compile 完程式後,打 ./wii_toy 00:1A:E9:3B:CA:49 <--- 每個人的 wii remote 不一樣 就可以玩了

tick@tock:~/work/e17>hcitool scan
Scanning ...
00:1A:E9:3B:CA:49 Nintendo RVL-CNT-01
tick@tock:~/work/e17>gcc `pkg-config --libs ecore-evas evas` -I/usr/local/include/libcwiimote-0.4.0/libcwiimote/ -lcwiimote -lbluetooth -Wall -pipe -D_ENABLE_TILT -D_ENABLE_FORCE -g2 -o wii_toy wii_toy.c
tick@tock:~/work/e17>./wii_toy 00:1A:E9:3B:CA:49
Please press 1+2 to connect Wii remote!!
Connecting.......


有圖有真象

2008年1月13日 星期日

學習 Evas

這陣子開始需要用 Evas 寫一些東西…
個人覺得學一個 library 最快的方法就是去真的拿它去寫程式。
如我的一個好友常說的:學中作,作中學 ^^
所以就寫了支小小的玩具… 和大家分享…


亂畫一個方塊,設定一個重力場,和一個 boundary反彈機制. ( 和一些阻泥 (mark 掉了)) 加上一個色彩空間的旋轉。就玩起來了 ^^

程式:

Filename: toy.c

#include <Ecore_Evas.h>
#include <Ecore.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define WIDTH 400
#define HEIGHT 400

Ecore_Evas * ee;
Evas * evas;
Evas_Object * base_rect;

double rotation[3][3] = { {0 , 0 , 1},
{1, 0, 0},
{0 , 1, 0}
};

struct bouncer {
Evas_Object *o;
int w,h;
double xs,ys;
double x,y;
double color[3];
};

inline void change_color(struct bouncer *bounce) {
double X[3];
int i,j;
int R,G,B;
for (i=0;i<3;i++) {
X[i]=bounce->color[i];
bounce->color[i]=0;
}
for (i=0;i<3;i++) {
for (j=0;j<3;j++) {
bounce->color[i] += rotation[i][j]*X[j];
}
}
R=bounce->color[0] < 0 ? bounce->color[0] + 255: bounce->color[0];
G=bounce->color[1] < 0 ? bounce->color[1] + 255: bounce->color[1];
B=bounce->color[2] < 0 ? bounce->color[2] + 255: bounce->color[2];
evas_object_color_set( bounce->o , R, G, B, 255);
}

inline void center(struct bouncer *bounce,double *x,double *y) {
*x = bounce->x + bounce->w/2;
*y = bounce->y + bounce->h/2;
}

inline void grav(struct bouncer *bounce) {
const double G=300;
double Gx,Gy,Gs;
double x,y;
double dist;
center(bounce,&x,&y);

dist = pow(pow(WIDTH/2-x,2) + pow(HEIGHT/2-y,2),0.5);
Gs = G/pow(dist,2);
Gx = (WIDTH/2 - x)/dist;
Gy = (HEIGHT/2 -y)/dist;
Gx = Gx * Gs;
Gy = Gy * Gs;

bounce->xs += Gx;
bounce->ys += Gy;

// Slow down~~
//bounce->xs = abs(bounce->xs) > 13 ? bounce->xs *(1/ pow(bounce->xs-10,2)): bounce->xs;
//bounce->ys = abs(bounce->ys) > 13 ? bounce->ys *(1/ pow(bounce->ys-10,2)): bounce->ys;
printf ("x=%2.2f y=%2.2f dist=%4.2f Gs=%2.2f Gx=%2.2f Gy=%2.2f xs=%2.2f ys=%2.2f\n",x,y,dist,Gs,Gx,Gy,bounce->xs,bounce->ys);
}
inline void calculate_pos(struct bouncer *bounce) {
grav(bounce);
bounce->x += bounce->xs;
bounce->y += bounce->ys;

// bounce
bounce->xs = bounce->x >=0 ? bounce->x + bounce->w <= WIDTH ? bounce->xs : -bounce->xs : -bounce->xs;
bounce->ys = bounce->y >=0 ? bounce->y + bounce->h <= HEIGHT? bounce->ys : - bounce->ys : - bounce->ys;
}

int move(void *data) {
struct bouncer *bounce =(struct bouncer *)data;
calculate_pos(bounce);
evas_object_move(bounce->o,bounce->x,bounce->y);
change_color(bounce);
return 1;
}

int main() {
struct bouncer bounce;
ecore_evas_init();

ee = ecore_evas_software_x11_new(NULL, 0, 0, 0, WIDTH, HEIGHT);
ecore_evas_title_set(ee, "Tick's Evas Study");
// ecore_evas_borderless_set(ee, 1); // borderless
ecore_evas_borderless_set(ee, 0); // border
ecore_evas_show(ee);


evas = ecore_evas_get(ee);
evas_font_path_append(evas, "fonts/");


bounce.o = evas_object_rectangle_add(evas);
bounce.w=bounce.h= (double)WIDTH/4;
bounce.x=(double)(WIDTH - bounce.w)/3;
bounce.y=(double)(HEIGHT- bounce.h)/6;
bounce.xs=-1.1; bounce.ys=1.1;
bounce.color[0]=128;
bounce.color[1]=64;
bounce.color[2]=255;
change_color(&bounce);
evas_object_resize( bounce.o, bounce.w, bounce.h);
evas_object_move( bounce.o,bounce.x,bounce.y);
evas_object_show( bounce.o);

ecore_timer_add((double)0.01,move,&bounce);

ecore_main_loop_begin();

return 0;
}


2008年1月9日 星期三

codecovert

Covert C code to Google prettyprint format

Filename: /usr/local/bin/codecovert

#!/bin/bash
for FF in $@;
do
if [ -e $FF ];then
echo Filename: $FF
echo "<pre class=\"prettyprint\">"
sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g' $FF
echo "</pre>"
fi
echo
done

Hello world


BITS 32

;section .text
;global _start
;_start:
jmp short two

one:
pop ecx ; using the db
; write
xor eax,eax
mov al, 4
xor ebx,ebx
mov bl, 1
xor edx, edx
mov dl, 13
int 0x80

;exit
xor eax,eax
mov al, 1
xor ebx, ebx
int 0x80

two:
call one
db "Hello_World!!"

Warning of "system" and "pipe"

I chatted with my friend about some security issues days before. I had mentioned about the function call "system" and "pipe" shall be avoid in many cases. It's very simple idea, but as I know many programmers even do not know it's very dangerous.
Please NEVER NEVER NEVER use this function to important programs.
NEVER allow user to touch the args, or PATH.
Please~~~



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void fake_ls(int args,char **argv) {
char buf[50];
char *ptr=buf;
int i;
sprintf(buf,"ls");
for (i=1;i<args;i++) {
ptr = buf + strlen(buf);
sprintf(ptr," %s",argv[i]);
}
printf("The command you send is: '%s'\n",buf);
system(buf);
}
int main (int args,char **argv) {
printf("argv=%p\n",argv);
fake_ls(args,argv);
}


you can use the following argument to execute
extra command: "-al\;cat /etc/passwd"
It's very easy to see how terrible it is. :-)