<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Thinking more...-資訊相關Idea與筆記</title>
<link>http://blog.roodo.com/thinkingmore/archives/cat_82804.html</link>
<description>Just thinking more...&amp;nbsp;訂閱 RSS

var gaJsHost = ((&quot;https:&quot; == document.location.protocol) ? &quot;https://ssl.&quot; : &quot;http://www.&quot;);
document.write(unescape(&quot;%3Cscript src=&#039;&quot; + gaJsHost + &quot;google-analytics.com/ga.js&#039; type=&#039;text/javascript&#039;%3E%3C/script%3E&quot;));















  google.load(&quot;jquery&quot;, &quot;1.2&quot;);
  google.setOnLoadCallback( function() {
    try {
      var pageTracker = _gat._getTracker(&quot;UA-97150-7&quot;);
      pageTracker._trackPageview();
    }catch(err) {}
    $(&quot;pre &gt; br&quot;).each( function() { $(this).replaceWith( &quot;\n&quot; ); } );
    $(&quot;textarea &gt; br&quot;).each( function() { $(this).replaceWith( &quot;\n&quot; ); } );
    SyntaxHighlighter.config.ClipboardSwf = &#039;http://alexgorbatchev.com/pub/sh/2.0.296/scripts/clipboard.swf&#039;;
    SyntaxHighlighter.all();
    dp.SyntaxHighlighter.ClipboardSwf = &#039;http://alexgorbatchev.com/pub/sh/2.0.296/scripts/clipboard.swf&#039;;
    dp.SyntaxHighlighter.HighlightAll(&#039;code&#039;);
  } );

</description>
<language>zh-tw</language>
<generator>Roodo Blog System</generator>
<copyright>All Rights Reserved</copyright>
<atom:link href="http://blog.roodo.com/thinkingmore/archives/cat_82804.xml" rel="self" type="application/rss+xml" />
<item>
	<title>quilt</title>
	<description><![CDATA[
			今天終於試用了 quilt，這是一個可以管理 patch 的工具，最早由 Andrew Morton 的一些 script 而來。

專案本來就有寫一些 script 來作 apply 的工作，只是，在想要倒回去或向前的時候，會變得非常麻煩!用 quilt 的話，可以方便的向前或向後。

因為已經有 patch 了，所以施作的方法很簡單，先 import，再 push。


quilt import patch01
quilt push
quilt import patch02
quilt push


之後就可以用 pop 往回推，或用 push 繼續往前了。

小記：坦白說，本來想放棄直接用 git 來作的...因為剛好在看 ProGit，覺得 git 或許會更適用也不一定，不過只是想簡單地往前或往後測試 patch，用 quilt 應該就夠了。

參考資料：Jserv's blog: quilt - 強大的 patch 管理工具quilt: An Introduction 

		]]>
	</description>
	<content:encoded><![CDATA[
			今天終於試用了 quilt，這是一個可以管理 patch 的工具，最早由 Andrew Morton 的一些 script 而來。

專案本來就有寫一些 script 來作 apply 的工作，只是，在想要倒回去或向前的時候，會變得非常麻煩!用 quilt 的話，可以方便的向前或向後。

因為已經有 patch 了，所以施作的方法很簡單，先 import，再 push。

<pre name="code" class="bash">
quilt import patch01
quilt push
quilt import patch02
quilt push
</pre>

之後就可以用 pop 往回推，或用 push 繼續往前了。

小記：坦白說，本來想放棄直接用 git 來作的...因為剛好在看 ProGit，覺得 git 或許會更適用也不一定，不過只是想簡單地往前或往後測試 patch，用 quilt 應該就夠了。

參考資料：<ul><li><a href="http://blog.linux.org.tw/~jserv/archives/001838.html">Jserv's blog: quilt - 強大的 patch 管理工具</a></li><li><a href="http://www.coffeebreaks.org/blogs/wp-content/archives/talks/2005/quilt/quiltintro-s5.html">quilt: An Introduction </a></li></ul>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9920263.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9920263.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 08 Sep 2009 16:47:19 +0800</pubDate>
</item>
<item>
	<title>Python 練習 - 抓書</title>
	<description><![CDATA[
			早上用了大概兩個小時搞這個，這是用來抓書的，除了抓以外，還直接把 script 、廣告...等都清掉，只留下書的內容。用法很簡單，執行這個 script，參數帶上那本書的網址就行了。

程式碼怎麼排都不行，所以丟到這裡了。


		]]>
	</description>
	<content:encoded><![CDATA[
			早上用了大概兩個小時搞這個，這是用來抓<a href="http://www.8book.cc/">書</a>的，除了抓以外，還直接把 script 、廣告...等都清掉，只留下書的內容。用法很簡單，執行這個 script，參數帶上那本書的網址就行了。<br />
<br />
程式碼怎麼排都不行，所以丟到<a href="http://sites.google.com/site/elleryq/home/python/getbook-py">這裡</a>了。<br />
<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9889413.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9889413.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 02 Sep 2009 16:48:14 +0800</pubDate>
</item>
<item>
	<title>Python 練習 - 將 Bing 的每日桌面圖像變成 GNOME 桌面</title>
	<description><![CDATA[
			上星期看到這篇：如何将Bing的每日桌面图像变成我的Windows 7桌面，就順手試試看改用 Python 來作，執行這個 script 以後，會自動拿 bing 的圖片來作為你 GNOME 的桌面背景圖片。
目前只有一個小問題，就是 xml.dom.minidom 有時候會因為 &amp; 的關係導致解析失敗。


#!/usr/bin/env python
import random
import os.path
import subprocess
import urllib2
import xml.dom.minidom
from xml.dom.minidom import Node

def get_xml():
        response = urllib2.urlopen('http://feeds.feedburner.com/bingimages')
        xml = response.read()
        return xml

def parse_and_get_first_image_uri( xml_str ):
        if xml_str=="":
                return ""
        doc=xml.dom.minidom.parseString( xml_str )

        urls=[]
        for node in doc.getElementsByTagName("enclosure"):
                urls.append( node.getAttribute("url") )
        index=random.randint( 0, len(urls)-1 )
        if len(urls)>0:
                return urls[ index ]
        else:
                return ""

def get_uri( uri, output ):
        response = urllib2.urlopen( uri )
        image_file=open( output, 'w' )
        image_file.write( response.read() )
        image_file.close()
        return

def set_wallpaper( filename ):
        args=[]
        args.append( 'gconftool-2' )
        args.append( '/desktop/gnome/background/picture_filename' )
        args.append( '--set' )
        args.append( filename )
        args.append( '--type=string' )
        subprocess.call( args )

uri=parse_and_get_first_image_uri( get_xml() )
tmp_dir = os.path.join( *(os.path.expanduser("~"), "tmp") )
if uri!="":
        if not os.path.exists( tmp_dir ):
                os.mkdir( tmp_dir )
        filename, extname = os.path.splitext( os.path.basename( uri ) )
        image_filename=os.path.join( *( tmp_dir, "bing" + extname ) )
        get_uri( uri, image_filename )
        set_wallpaper( image_filename )
else:
        print "get nothing."


		]]>
	</description>
	<content:encoded><![CDATA[
			上星期看到這篇：<a href="http://www.cnbeta.com/articles/90318.htm">如何将Bing的每日桌面图像变成我的Windows 7桌面</a>，就順手試試看改用 Python 來作，執行這個 script 以後，會自動拿 <a href="http://www.bing.com">bing</a> 的圖片來作為你 GNOME 的桌面背景圖片。
目前只有一個小問題，就是 xml.dom.minidom 有時候會因為 &amp; 的關係導致解析失敗。

<pre name="code" class="python">
#!/usr/bin/env python
import random
import os.path
import subprocess
import urllib2
import xml.dom.minidom
from xml.dom.minidom import Node

def get_xml():
        response = urllib2.urlopen('http://feeds.feedburner.com/bingimages')
        xml = response.read()
        return xml

def parse_and_get_first_image_uri( xml_str ):
        if xml_str=="":
                return ""
        doc=xml.dom.minidom.parseString( xml_str )

        urls=[]
        for node in doc.getElementsByTagName("enclosure"):
                urls.append( node.getAttribute("url") )
        index=random.randint( 0, len(urls)-1 )
        if len(urls)>0:
                return urls[ index ]
        else:
                return ""

def get_uri( uri, output ):
        response = urllib2.urlopen( uri )
        image_file=open( output, 'w' )
        image_file.write( response.read() )
        image_file.close()
        return

def set_wallpaper( filename ):
        args=[]
        args.append( 'gconftool-2' )
        args.append( '/desktop/gnome/background/picture_filename' )
        args.append( '--set' )
        args.append( filename )
        args.append( '--type=string' )
        subprocess.call( args )

uri=parse_and_get_first_image_uri( get_xml() )
tmp_dir = os.path.join( *(os.path.expanduser("~"), "tmp") )
if uri!="":
        if not os.path.exists( tmp_dir ):
                os.mkdir( tmp_dir )
        filename, extname = os.path.splitext( os.path.basename( uri ) )
        image_filename=os.path.join( *( tmp_dir, "bing" + extname ) )
        get_uri( uri, image_filename )
        set_wallpaper( image_filename )
else:
        print "get nothing."
</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9777437.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9777437.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Mon, 17 Aug 2009 19:08:41 +0800</pubDate>
</item>
<item>
	<title>jquery 與 iframe</title>
	<description><![CDATA[
			假設 iframe 的 id 是 f，裡面有個按鈕 id 是 btn，那麼要存取 iframe 裡的元素，可以這樣寫：

  // http://simple.procoding.net/2008/03/21/how-to-access-iframe-in-jquery/
  alert( $('#f').contents().find('#btn').html() );


再假設父頁面裡有個 id 是 ta 的 text，iframe 裡要存取父頁面裡的元素，有兩種寫法：

  // 方法一 (http://webdevel.blogspot.com/2007/03/iframes-and-jquery-working-with-iframes.html)
  alert( parent.$("#ta").val() );
  // 方法二 (http://groups.google.com/group/jquery-en/browse_thread/thread/5997ef4a60a123af?pli=1)
  alert( $("#ta", parent.document.body).val() );


不過，在碰到 cross domain 的情況時，就會行不通了。拜 Google 大神 的時候，大神有提到一些解，但我嫌麻煩就沒再去試了...

參考資料：simple » Blog Archive » How to access iframe in jQueryWeb Developer Blog: Iframes and jQuery - Working with an iframe's parentUsing JQuery Effects in Parent Window from iFrame? - jQuery (English) | Google 網上論壇

		]]>
	</description>
	<content:encoded><![CDATA[
			假設 iframe 的 id 是 f，裡面有個按鈕 id 是 btn，那麼要存取 iframe 裡的元素，可以這樣寫：
<pre name="code" class="javascript">
  // http://simple.procoding.net/2008/03/21/how-to-access-iframe-in-jquery/
  alert( $('#f').contents().find('#btn').html() );
</pre>

再假設父頁面裡有個 id 是 ta 的 text，iframe 裡要存取父頁面裡的元素，有兩種寫法：
<pre name="code" class="javascript">
  // 方法一 (http://webdevel.blogspot.com/2007/03/iframes-and-jquery-working-with-iframes.html)
  alert( parent.$("#ta").val() );
  // 方法二 (http://groups.google.com/group/jquery-en/browse_thread/thread/5997ef4a60a123af?pli=1)
  alert( $("#ta", parent.document.body).val() );
</pre>

不過，在碰到 cross domain 的情況時，就會行不通了。拜 <a href="http://www.google.com">Google 大神</a> 的時候，大神有提到一些<a href="http://ajaxian.com/archives/how-to-make-xmlhttprequest-calls-to-another-server-in-your-domain">解</a>，但我嫌麻煩就沒再去試了...<br/>

參考資料：<ul><li><a href="http://simple.procoding.net/2008/03/21/how-to-access-iframe-in-jquery/">simple » Blog Archive » How to access iframe in jQuery</a></li><li><a href="http://webdevel.blogspot.com/2007/03/iframes-and-jquery-working-with-iframes.html">Web Developer Blog: Iframes and jQuery - Working with an iframe's parent</a></li><li><a href="http://groups.google.com/group/jquery-en/browse_thread/thread/5997ef4a60a123af?pli=1">Using JQuery Effects in Parent Window from iFrame? - jQuery (English) | Google 網上論壇</a></li></ul>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9657289.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9657289.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 04 Aug 2009 16:40:52 +0800</pubDate>
</item>
<item>
	<title>python twisted sendmail</title>
	<description><![CDATA[
			buildbot 是用 twisted library 裡的 sendmail 寄信的，方法如下：
from email.Message import Message
from twisted.mail.smtp import sendmail
from twisted.internet import defer
from twisted.internet import reactor

m = Message()
m.set_payload("Hello world!!")
m['To']="someone@somewhere.com"
m['Subject'] = "Test"
m['From'] = "my@somewhere.com"
s = m.as_string()
done = sendmail( "mailserver", "my@somewhere.com", [ "someone@somewhere.com" ], s)
done.addCallback(lambda ignored: reactor.stop())
reactor.run()


但現在大多的 mail server 都需要先認證，這時候就得改用 ESMTPSenderFactory 來改寫了(可參考Twisted mail smtp API)，mailing list 裡正好有人貼出程式：
from twisted.mail import smtp
from twisted.internet import reactor
from twisted.internet import defer

try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

def sendmail_auth(smtphost, user, password,
                 from_addr, to_addrs, msg, senderDomainName=None, port=25):
    if not hasattr(msg,'read'):
        msg = StringIO(str(msg))
    d = defer.Deferred()
    factory = smtp.ESMTPSenderFactory(user, password, from_addr, to_addrs, msg, d,
                                      requireTransportSecurity=False)
    if senderDomainName is not None:
        factory.domain = senderDomainName
    reactor.connectTCP(smtphost, port, factory)
    return d


再套前面的例子，只要改動 sendmail 為 sendmail_auth 就行了：程式：
done = sendmail_auth( "mailserver", "your_username", "your_password", "my@somewhere.com", [ "someone@somewhere.com" ], s)


		]]>
	</description>
	<content:encoded><![CDATA[
			buildbot 是用 twisted library 裡的 sendmail 寄信的，方法如下：<pre name="code" class="python">
from email.Message import Message
from twisted.mail.smtp import sendmail
from twisted.internet import defer
from twisted.internet import reactor

m = Message()
m.set_payload("Hello world!!")
m['To']="someone@somewhere.com"
m['Subject'] = "Test"
m['From'] = "my@somewhere.com"
s = m.as_string()
done = sendmail( "mailserver", "my@somewhere.com", [ "someone@somewhere.com" ], s)
done.addCallback(lambda ignored: reactor.stop())
reactor.run()
</pre>

但現在大多的 mail server 都需要先認證，這時候就得改用 ESMTPSenderFactory 來改寫了(可參考<a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.mail.smtp.html">Twisted mail smtp API</a>)，mailing list 裡正好有人貼出<a href="http://twistedmatrix.com/pipermail/twisted-python/2006-April/012994.html">程式</a>：<pre name="code" class="python">
from twisted.mail import smtp
from twisted.internet import reactor
from twisted.internet import defer

try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

def sendmail_auth(smtphost, user, password,
                 from_addr, to_addrs, msg, senderDomainName=None, port=25):
    if not hasattr(msg,'read'):
        msg = StringIO(str(msg))
    d = defer.Deferred()
    factory = smtp.ESMTPSenderFactory(user, password, from_addr, to_addrs, msg, d,
                                      requireTransportSecurity=False)
    if senderDomainName is not None:
        factory.domain = senderDomainName
    reactor.connectTCP(smtphost, port, factory)
    return d
</pre>

再套前面的例子，只要改動 sendmail 為 sendmail_auth 就行了：<a href="http://twistedmatrix.com/pipermail/twisted-python/2006-April/012994.html">程式</a>：<pre name="code" class="python">
done = sendmail_auth( "mailserver", "your_username", "your_password", "my@somewhere.com", [ "someone@somewhere.com" ], s)
</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9559587.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9559587.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 28 Jul 2009 15:13:07 +0800</pubDate>
</item>
<item>
	<title>buildbot</title>
	<description><![CDATA[
			在Ubuntu上安裝Buildbot是很簡單的事情：sudo apt-get install buildbot。

比較麻煩的是設定，大致瀏覽了一下 Manual，還是不知道怎麼設定，轉而找 Google 大神，Mousebender 的這篇Installing buildbot，就很簡單易懂。但由於這篇提供的設定是 2006 年的，現在的設定稍稍有改變，c['bots'] 必須修正為 c['slaves']，後面會提到。

依據 Architecture，Buildbot必須要有 master 跟 slave，master 負責提供 web 介面跟叫 slave 做事，而 slave 就只聽命令做事，所以設定的時候就要分別設定 master 跟 slave。

master 的設定，得先使用 buildbot create-master [目錄名] 來建立，這會幫你建立一個目錄，並提供你設定檔的範本(master.cfg.sample)。第一步就是要把 master.cfg.sample 改為 master.cfg，然後修改 master.cfg。要調整的基本上有這幾個：c['schedulers']，要排程的時間。f1.addStep()，這決定怎麼編譯。c['slaves']、c['slavePortnum']，slave的名稱、密碼以及要 listen 的 port，待會建立 slave 時會用到。c['projectName']，你專案的名稱。c['projectURL']，你專案的網址。

接著要建立 slave，這邊用 master.cfg.sample 來舉例，也就是假設你剛剛沒改 c['slaves']、c['slavePortnum'] 的內容，所以這邊用 buildbot create-slave [目錄名] localhost:9989 bot1name bot1passwd 來建立 slave，接著把 slave 目錄下的 Makefile.sample 改為 Makefile 即可。

啟動的時候，要先啟動 slave 再啟動 master，啟動的指令都是 buildbot start [目錄名]，例如 buildbot start myproject-master、buildbot start myproject-slave。

這樣就大功告成，你可以打開 http://localhost:8010 來看 build 的進度了。

下面是我的設定檔：
# -*- python -*-
c = BuildmasterConfig = {}

####### BUILDSLAVES
from buildbot.buildslave import BuildSlave
c['slaves'] = [BuildSlave("myproject-slave", "password", max_builds=1)]
c['slavePortnum'] = 9989

####### CHANGESOURCES
from buildbot.changes.pb import PBChangeSource
c['change_source'] = PBChangeSource()

####### SCHEDULERS
from buildbot.scheduler import Scheduler, Periodic
c['schedulers'] = [
        Periodic("every_12_hours", ["buildbot-full"], 12*60*60 )
]

####### BUILDERS
from buildbot.process import factory
from buildbot.steps.source import CVS
from buildbot.steps.shell import Compile, ShellCommand
from buildbot.steps.python_twisted import Trial
f1 = factory.BuildFactory()
f1.addStep(ShellCommand(command=["/home/user1/build/build.sh"]))
f1.addStep(Compile())

b1 = {'name': "buildbot-full",
      'slavename': 'myproject-slave',
      'builddir': "full",
      'factory': f1,
      }
c['builders'] = [b1]


####### STATUS TARGETS
c['status'] = []

from buildbot.status import html
c['status'].append(html.WebStatus(http_port=8010))

####### PROJECT IDENTITY
c['projectName'] = "myproject"
c['projectURL'] = "http://myproject-server"
c['buildbotURL'] = "http://localhost:8010/"


		]]>
	</description>
	<content:encoded><![CDATA[
			在<a href="http://www.ubuntulinux.com">Ubuntu</a>上安裝<a href="http://buildbot.net/trac">Buildbot</a>是很簡單的事情：sudo apt-get install buildbot。<br/>
<br/>
比較麻煩的是設定，大致瀏覽了一下 <a href="http://djmitche.github.com/buildbot/docs/0.7.10/">Manual</a>，還是不知道怎麼設定，轉而找 Google 大神，<a href="http://mousebender.wordpress.com/">Mousebender</a> 的這篇<a href="http://mousebender.wordpress.com/2006/05/26/installing-buildbot/">Installing buildbot</a>，就很簡單易懂。但由於這篇提供的設定是 2006 年的，現在的設定稍稍有改變，c['bots'] 必須修正為 c['slaves']，後面會提到。<br/>
<br/>
依據 <a href="http://djmitche.github.com/buildbot/docs/0.7.10/#System-Architecture">Architecture</a>，<a href="http://buildbot.net/trac">Buildbot</a>必須要有 master 跟 slave，master 負責提供 web 介面跟叫 slave 做事，而 slave 就只聽命令做事，所以設定的時候就要分別設定 master 跟 slave。<br/>
<br/>
master 的設定，得先使用 buildbot create-master [目錄名] 來建立，這會幫你建立一個目錄，並提供你設定檔的範本(master.cfg.sample)。第一步就是要把 master.cfg.sample 改為 master.cfg，然後修改 master.cfg。要調整的基本上有這幾個：<ul><li>c['schedulers']，要排程的時間。</li><li>f1.addStep()，這決定怎麼編譯。</li><li>c['slaves']、c['slavePortnum']，slave的名稱、密碼以及要 listen 的 port，待會建立 slave 時會用到。</li><li>c['projectName']，你專案的名稱。</li><li>c['projectURL']，你專案的網址。</li></ul>
<br/>
接著要建立 slave，這邊用 master.cfg.sample 來舉例，也就是假設你剛剛沒改 c['slaves']、c['slavePortnum'] 的內容，所以這邊用 buildbot create-slave [目錄名] localhost:9989 bot1name bot1passwd 來建立 slave，接著把 slave 目錄下的 Makefile.sample 改為 Makefile 即可。<br/>
<br/>
啟動的時候，要先啟動 slave 再啟動 master，啟動的指令都是 buildbot start [目錄名]，例如 buildbot start myproject-master、buildbot start myproject-slave。<br/>
<br/>
這樣就大功告成，你可以打開 http://localhost:8010 來看 build 的進度了。<br/>
<br/>
下面是我的設定檔：<pre name="code" class="python">
# -*- python -*-
c = BuildmasterConfig = {}

####### BUILDSLAVES
from buildbot.buildslave import BuildSlave
c['slaves'] = [BuildSlave("myproject-slave", "password", max_builds=1)]
c['slavePortnum'] = 9989

####### CHANGESOURCES
from buildbot.changes.pb import PBChangeSource
c['change_source'] = PBChangeSource()

####### SCHEDULERS
from buildbot.scheduler import Scheduler, Periodic
c['schedulers'] = [
        Periodic("every_12_hours", ["buildbot-full"], 12*60*60 )
]

####### BUILDERS
from buildbot.process import factory
from buildbot.steps.source import CVS
from buildbot.steps.shell import Compile, ShellCommand
from buildbot.steps.python_twisted import Trial
f1 = factory.BuildFactory()
f1.addStep(ShellCommand(command=["/home/user1/build/build.sh"]))
f1.addStep(Compile())

b1 = {'name': "buildbot-full",
      'slavename': 'myproject-slave',
      'builddir': "full",
      'factory': f1,
      }
c['builders'] = [b1]


####### STATUS TARGETS
c['status'] = []

from buildbot.status import html
c['status'].append(html.WebStatus(http_port=8010))

####### PROJECT IDENTITY
c['projectName'] = "myproject"
c['projectURL'] = "http://myproject-server"
c['buildbotURL'] = "http://localhost:8010/"
</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9519357.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9519357.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 24 Jul 2009 15:58:52 +0800</pubDate>
</item>
<item>
	<title>無法移除的 Powershell v1.0</title>
	<description><![CDATA[
			如果你也跟我一樣，因為要安裝 Powershell v2.0 而無法移除 Powershell v1.0 的話，可以研讀 Powershell team 貼的這篇：Windows PowerShell Blog : Behind PowerShell Installer (for Windows XP / Windows Server 2003):，了解一下 Powershell 安裝程式做了什麼。不過這篇字太多了，我其實是參考這篇：BUGBUG: poor title » Blog Archive » How to uninstall Powershell v1.0 from Windows Server 2003 R2 來移除的，除了 pwrshsip.dll 無法刪掉之外，基本上不刪掉也沒關係。接著就可以上 Powershell v2.0 CTP3 了。
為什麼要上 Powershell v2.0 CTP3 呢？這是因為 SQL Server 2008 Management Studio Express 的緣故。真是太機車了...

		]]>
	</description>
	<content:encoded><![CDATA[
			如果你也跟我一樣，因為要安裝 Powershell v2.0 而無法移除 Powershell v1.0 的話，可以研讀 Powershell team 貼的這篇：<a href="http://blogs.msdn.com/powershell/archive/2007/01/09/behind-powershell-installer-for-windows-xp-windows-server-2003.aspx">Windows PowerShell Blog : Behind PowerShell Installer (for Windows XP / Windows Server 2003):</a>，了解一下 Powershell 安裝程式做了什麼。不過這篇字太多了，我其實是參考這篇：<a href="http://richardberg.net/blog/?p=71">BUGBUG: poor title » Blog Archive » How to uninstall Powershell v1.0 from Windows Server 2003 R2</a> 來移除的，除了 pwrshsip.dll 無法刪掉之外，基本上不刪掉也沒關係。接著就可以上 Powershell v2.0 CTP3 了。<br />
為什麼要上 Powershell v2.0 CTP3 呢？這是因為 SQL Server 2008 Management Studio Express 的緣故。真是太機車了...<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9486065.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9486065.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Mon, 20 Jul 2009 01:04:35 +0800</pubDate>
</item>
<item>
	<title>Ubiquity 0.5 + findbook</title>
	<description><![CDATA[
			Ubiquity 升級到 0.5 了，Parser API 也升級到了 2，語法有改變，所以參考轉換指南修正了一下之前的 findbook：


CmdUtils.CreateCommand({
  names: ["findbook"],
  contributors: ["elleryq"],
  license: "MPL",
  description: "讓買書變成更簡單的決定！",
  arguments: [ {role: 'object', nountype: noun_arb_text, label: '書名關鍵字'} ],
  icon: "http://findbook.tw/favicon.ico",
  execute: function(args) {
    Utils.openUrlInBrowser( "http://findbook.tw/search?keyword_type=keyword&q=" + encodeURIComponent(args.object.text) );
  }
});


如果你想入門的話，這份文件可以作為參考：Labs/Ubiquity/Ubiquity Source Tip Author Tutorial。
另外，在Ubiquity Command Editor頁面裡也有 command APIs，告訴你有哪些 API 可用。

		]]>
	</description>
	<content:encoded><![CDATA[
			Ubiquity 升級到 0.5 了，Parser API 也升級到了 2，語法有改變，所以參考<a href="https://wiki.mozilla.org/Labs/Ubiquity/Parser_2_API_Conversion_Tutorial">轉換指南</a>修正了一下之前的 findbook：

<pre name="code" class="javascript">
CmdUtils.CreateCommand({
  names: ["findbook"],
  contributors: ["elleryq"],
  license: "MPL",
  description: "讓買書變成更簡單的決定！",
  arguments: [ {role: 'object', nountype: noun_arb_text, label: '書名關鍵字'} ],
  icon: "http://findbook.tw/favicon.ico",
  execute: function(args) {
    Utils.openUrlInBrowser( "http://findbook.tw/search?keyword_type=keyword&q=" + encodeURIComponent(args.object.text) );
  }
});
</pre>

如果你想入門的話，這份文件可以作為參考：<a href="https://wiki.mozilla.org/Labs/Ubiquity/Ubiquity_Source_Tip_Author_Tutorial">Labs/Ubiquity/Ubiquity Source Tip Author Tutorial</a>。
另外，在<a href="chrome://ubiquity/content/editor.html">Ubiquity Command Editor</a>頁面裡也有 command APIs，告訴你有哪些 API 可用。

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9419447.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9419447.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Sat, 11 Jul 2009 00:09:57 +0800</pubDate>
</item>
<item>
	<title>cvs diff with meld</title>
	<description><![CDATA[
			公司還在用 CVS，Windows 下有 wincvs 這個方便的軟體，Linux 下，我還是習慣用 console 介面，console 介面下，很多事情就要自己來了。
wincvs 可以選用自訂的軟體來比對。但在 console 下，只能用 cvs diff，cvs diff 的話，只會列出 diff 的結果，沒辦法以視覺化的方式呈現比對結果。
所以只好刻一個，簡單的說就是利用 cvs update -p -r(revision) 將結果輸出到暫存檔，再用 meld 來比對這暫存檔與目前檔案：

#!/bin/bash
# author: elleryq
# version: 0.1
# distro: ubuntu
# dependency: cvsnt

if [ ! -e $1 ]; then
    echo "$1 is not existed, run 'cvs update $1' first!"
    exit -1
fi

[ -z $DIFF ] && DIFF=meld
 
function usage() {
    prog=`basename $0`
    echo "Usage:"
    echo "    $prog filename revision"
    exit 0
}
 
[ -z $1 ] && usage
if [ -z $2 ]; then
    revision=`cvs log $1 | grep head | awk '{print $2;}'`
else
    revision=$2
fi

tmpfile=/tmp/$1.$revision
cvs update -r $revision -p $1 > $tmpfile
$DIFF $tmpfile $1
rm -f $tmpfile
 
exit 0


你可以自訂 diff 軟體，只要設置好 DIFF 這個環境變數即可，預設是 meld。

		]]>
	</description>
	<content:encoded><![CDATA[
			公司還在用 CVS，Windows 下有 <a href="http://www.wincvs.org/">wincvs</a> 這個方便的軟體，Linux 下，我還是習慣用 console 介面，console 介面下，很多事情就要自己來了。<br/><br/>
<a href="http://www.wincvs.org/">wincvs</a> 可以選用自訂的軟體來比對。但在 console 下，只能用 cvs diff，cvs diff 的話，只會列出 diff 的結果，沒辦法以視覺化的方式呈現比對結果。<br/><br/>
所以只好刻一個，簡單的說就是利用 cvs update -p -r(revision) 將結果輸出到暫存檔，再用 meld 來比對這暫存檔與目前檔案：
<pre name="code" class="bash">
#!/bin/bash
# author: elleryq
# version: 0.1
# distro: ubuntu
# dependency: cvsnt

if [ ! -e $1 ]; then
    echo "$1 is not existed, run 'cvs update $1' first!"
    exit -1
fi

[ -z $DIFF ] && DIFF=meld
 
function usage() {
    prog=`basename $0`
    echo "Usage:"
    echo "    $prog filename revision"
    exit 0
}
 
[ -z $1 ] && usage
if [ -z $2 ]; then
    revision=`cvs log $1 | grep head | awk '{print $2;}'`
else
    revision=$2
fi

tmpfile=/tmp/$1.$revision
cvs update -r $revision -p $1 > $tmpfile
$DIFF $tmpfile $1
rm -f $tmpfile
 
exit 0
</pre>

你可以自訂 diff 軟體，只要設置好 DIFF 這個環境變數即可，預設是 <a href="http://meld.sourceforge.net/">meld</a>。

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9256919.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9256919.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Thu, 18 Jun 2009 00:24:35 +0800</pubDate>
</item>
<item>
	<title>Firefox 附加元件收藏集</title>
	<description><![CDATA[
			最近 Mozilla 推的 Firefox 附加元件收藏集 真的是好東西。

年初趁重裝 Firefox 3.1 的時候，很有心地用 Google docs 整理了一份附加元件的清單，只是後來又安裝/移除了一些元件以後，就忘了再去維護。現在有了 Firefox 附加元件收藏集 就可以方便地管理自己的附加元件了。另外，也可以訂閱別人的收藏集，來找到適合自己的附加元件，這個收藏集的功能實在是很感心啦～

這是目前我的收藏集：elleryq's collection，也就是我公司 Firefox 有裝的附加元件，居然也不知不覺地裝了 35 個...XD...

		]]>
	</description>
	<content:encoded><![CDATA[
			最近 <a href="http://www.mozilla.org">Mozilla</a> 推的 <a href="https://addons.mozilla.org/zh-TW/firefox/pages/collector">Firefox 附加元件收藏集</a> 真的是好東西。<br />
<br />
年初趁重裝 Firefox 3.1 的時候，很有心地用 <a href="http://docs.google.com">Google docs</a> 整理了一份<a href="http://spreadsheets.google.com/ccc?key=pYOVU6mxl_0tFLi9mQkCOSw">附加元件的清單</a>，只是後來又安裝/移除了一些元件以後，就忘了再去維護。現在有了 <a href="https://addons.mozilla.org/zh-TW/firefox/pages/collector">Firefox 附加元件收藏集</a> 就可以方便地管理自己的附加元件了。另外，也可以訂閱別人的收藏集，來找到適合自己的附加元件，這個收藏集的功能實在是很感心啦～<br />
<br />
這是目前我的收藏集：<a href="https://addons.mozilla.org/zh-TW/firefox/collection/elleryq_s_collection">elleryq's collection</a>，也就是我公司 Firefox 有裝的附加元件，居然也不知不覺地裝了 35 個...XD...<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/9242401.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/9242401.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 17 Jun 2009 03:31:41 +0800</pubDate>
</item>
<item>
	<title>gdb 連到遠端 gdbserver 的指令</title>
	<description><![CDATA[
			遠端先把 gdbserver 啟動，並指定 ip:port，例如：gdbserver 192.168.11.1:10000 hello

那麼本地端在啟動 gdb 以後，就可以用以下指令連到遠端：target remote 192.168.11.1:10000

再以 symbol-file 載入有除錯資訊的檔案，就可以進行 debug 了。

		]]>
	</description>
	<content:encoded><![CDATA[
			遠端先把 gdbserver 啟動，並指定 ip:port，例如：gdbserver 192.168.11.1:10000 hello<br />
<br />
那麼本地端在啟動 gdb 以後，就可以用以下指令連到遠端：target remote 192.168.11.1:10000<br />
<br />
再以 symbol-file 載入有除錯資訊的檔案，就可以進行 debug 了。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8813489.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8813489.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 28 Apr 2009 19:04:21 +0800</pubDate>
</item>
<item>
	<title>Seed(4) - Database</title>
	<description><![CDATA[
			Seed 也支援對資料庫的存取，目前只支援 SQLite。
用法也超級簡單...

基本上只有 constructor 跟用來執行 SQL 的 exec()。以下代碼來自源碼裡 (modules/sqlite/example.js)：

#!/usr/local/bin/seed
Seed.import_namespace("sqlite");
d = new sqlite.Database(Seed.argv[2]);

d.exec("create table t1 (t1key INTEGER PRIMARY KEY,data TEXT,num double,timeEnter DATE);");
d.exec("insert into t1 (data,num) values ('This is sample data',3);");
d.exec("insert into t1 (data,num) values ('More sample data',6);");
d.exec("insert into t1 (data,num) values ('And a little more',9);");

d.exec("select * from t1", function(results){Seed.print(JSON.stringify(results))});


取出資料的作法則是將 callback 傳入，以處理一筆 record。上面是用 JSON 輸出整筆 record 內容，其實你也可以將欄位名稱代入 indexer 來取得該欄內容：

d.exec("select * from t1", function(results){Seed.print(results["data"])});


		]]>
	</description>
	<content:encoded><![CDATA[
			Seed 也支援對資料庫的存取，目前只支援 SQLite。
用法也超級簡單...

基本上只有 constructor 跟用來執行 SQL 的 exec()。以下代碼來自源碼裡 (modules/sqlite/example.js)：
<pre name="code" class="javascript">
#!/usr/local/bin/seed
Seed.import_namespace("sqlite");
d = new sqlite.Database(Seed.argv[2]);

d.exec("create table t1 (t1key INTEGER PRIMARY KEY,data TEXT,num double,timeEnter DATE);");
d.exec("insert into t1 (data,num) values ('This is sample data',3);");
d.exec("insert into t1 (data,num) values ('More sample data',6);");
d.exec("insert into t1 (data,num) values ('And a little more',9);");

d.exec("select * from t1", function(results){Seed.print(JSON.stringify(results))});
</pre>

取出資料的作法則是將 callback 傳入，以處理一筆 record。上面是用 JSON 輸出整筆 record 內容，其實你也可以將欄位名稱代入 indexer 來取得該欄內容：
<pre name="code" class="javascript">
d.exec("select * from t1", function(results){Seed.print(results["data"])});
</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8630949.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8630949.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 03 Apr 2009 20:08:40 +0800</pubDate>
</item>
<item>
	<title>Run Android on VirtualBox/VMWare</title>
	<description><![CDATA[
			有人問了，所以這裡大致整理一下，也算是留下一個記憶（之後沒有要繼續...Orz...)。
事實上，網路上可以找到許多人的文章，根據歸納之後，我發現大多都是從 android-porting 裡的這篇：Howto build Android full source for X86 Architecture like EeePC(ASUS)轉貼來的，所以只要耐心爬完這篇，大致上都沒問題。

第一步當然是要把 source 拉下來，這個步驟，官方描述得很清楚：Get source (Android Open Source Project)，這裡不多作描述。如果你用的是 Ubuntu 8.10，會踩到雷的只有 libreadline5-dev，因為並沒有該頁面描述的 lib32readline5-dev。這裡我假設你跟官方教學步驟一樣，建了 mydroid 目錄。sync 整份 source code 以後，還需要 eee 701 的部份，所以要在 .repo 下新增一個檔案，並命名為 local_manifest.xml：&lt;manifest&gt;
    &lt;project name="platform/vendor/asus/eee_701" path="vendor/asus/eee_701"/&gt;
  &lt;/manifest&gt;，然後再 sync 一次。這次的 sync 會很快，結束以後，要先 build kernel。切到 mydroid/kernel 目錄下，複製 mydroid/vendor/asus/eee_701/kernel.config 為 mydroid/kernel/.config，接著執行 make menuconfig，進入 kernel configuration 選單以後，把這幾個 driver 選為 built-in：Device drivers / Network device support / Ethernet (10 or 100Mbit) / EISA, VLB, PCI and on board controllers / AMD PCnet32 PCI support Device drivers / Graphics support / Support for frame buffer devices / VESA VGA graphics supportDevice drivers / Graphics support / Console display driver support / Framebuffer Console supportDevice drivers / Graphics support / Console display driver support / Select Compiled-in fonts (VGA 8x8 font, VGA 8x16 font)，再把這些取消：Device drivers / Real Time Clock / Android alarm driverDevice drivers / Misc devices / Android pmem allocator，然後重新建置 kernel：make bzImage。編譯好之後，把 arch/x86/boot/bzImage 複製為 mydroid/vendor/asus/eee_701/kernel。我稍稍更動了一些設定，這樣我後面就省打一些東西：vendor/asus/eee_701/BoardConfig.mk：在 BOARD_KERNEL_CMDLINE 加上 vga=788vendor/asus/eee_701/init.eee_701.sh：把 netcfg eth0 dhcp 改為 dhcpcd eth0接著就是建置 image 了，這裡是我用的 script，把以下內容存為 build.sh，並放在 mydroid 下：#!/bin/bash
cp kernel/arch/x86/boot/bzImage vendor/asus/eee_701/kernel
mkdir -p out/target/product/eee_701/data/
cp kernel/arch/x86/boot/bzImage out/target/product/eee_701/kernel

TARGET_ARCH=x86 TARGET_PRODUCT=eee_701 DISABLE_DEXPREOPT=true make -j2 installer_img
，執行前別忘了 chmod +x 。建置完以後，你會在 out/target/product/eee_701 下找到 installer.img。把 installer.img 轉為 VirtualBox/VMWare 可用的 disk image，這邊要利用 VirtualBox 的 vboxmanage 來轉：vboxmanage convertfromraw -format vdi installer.img installer.vdi，如果你用 VMWare，則是：vboxmanage convertfromraw -format vmdk installer.img installer.vmdk建置新的 VM，設置為 Linux kernel 2.6，256M 的 RAM，以及一個超過 2G 的硬碟。然後把上個步驟轉好的 disk image 加為第二個儲存裝置。接下來，我只以 VirtualBox 為例，因為我沒試過 VMWare，不過原理一樣。將這個 VM 開機，一開機馬上按 F12，選擇從第二個儲存裝置開機。一開機，你會看到 grub 的開機選單，趕緊按下任意鍵，因為這邊要修改一下，預設 Loader 的開機磁碟是 hd(0,0)，你要按 e 進行修改，把 hd(0,0) 改為 hd(1,0)，再按 b 繼續開機(如果你不熟 grub，麻煩熟悉，這邊我不多說)。開機以後，就會開始進行安裝的動作，Android 會安裝到第一個磁碟上去，這個步驟要等一陣子，如果有錯誤，再重複一次即可，根據我的經驗，有時候會因為切割磁碟失敗而停止安裝，但再從第二個磁碟開機安裝一次，通常即可解決。安裝完成不會有什麼訊息，但看一下畫面上訊息，你應該可以知道已經完成，輸入 reboot 重新開機。最後就大功告成啦～接著你可以移除第二個磁碟，因為再也用不到啦～

最後的最後，希望我沒有遺漏～


		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="http://www.plurk.com/p/iftvw">有人問了</a>，所以這裡大致整理一下，也算是留下一個記憶（之後沒有要繼續...Orz...)。
事實上，網路上可以找到許多人的文章，根據歸納之後，我發現大多都是從 <a href="http://groups.google.com/group/android-porting/">android-porting</a> 裡的這篇：<a href="http://groups.google.com/group/android-porting/browse_thread/thread/66862bdb52dac936/1ae192cee32eaa71">Howto build Android full source for X86 Architecture like EeePC(ASUS)</a>轉貼來的，所以只要耐心爬完這篇，大致上都沒問題。

<ol><li>第一步當然是要把 source 拉下來，這個步驟，官方描述得很清楚：<a href="http://source.android.com/download">Get source (Android Open Source Project)</a>，這裡不多作描述。如果你用的是 Ubuntu 8.10，會踩到雷的只有 libreadline5-dev，因為並沒有該頁面描述的 lib32readline5-dev。這裡我假設你跟官方教學步驟一樣，建了 mydroid 目錄。</li><li>sync 整份 source code 以後，還需要 eee 701 的部份，所以要在 .repo 下新增一個檔案，並命名為 local_manifest.xml：<pre name="code" class="xml">&lt;manifest&gt;
    &lt;project name="platform/vendor/asus/eee_701" path="vendor/asus/eee_701"/&gt;
  &lt;/manifest&gt;</pre>，然後再 sync 一次。</li><li>這次的 sync 會很快，結束以後，要先 build kernel。切到 mydroid/kernel 目錄下，複製 mydroid/vendor/asus/eee_701/kernel.config 為 mydroid/kernel/.config，接著執行 make menuconfig，進入 kernel configuration 選單以後，把這幾個 driver 選為 built-in：<ul><li>Device drivers / Network device support / Ethernet (10 or 100Mbit) / EISA, VLB, PCI and on board controllers / AMD PCnet32 PCI support </li><li>Device drivers / Graphics support / Support for frame buffer devices / VESA VGA graphics support</li><li>Device drivers / Graphics support / Console display driver support / Framebuffer Console support</li><li>Device drivers / Graphics support / Console display driver support / Select Compiled-in fonts (VGA 8x8 font, VGA 8x16 font)</li></ul>，再把這些取消：<ul><li>Device drivers / Real Time Clock / Android alarm driver</li><li>Device drivers / Misc devices / Android pmem allocator</li></ul>，然後重新建置 kernel：make bzImage。</li><li>編譯好之後，把 arch/x86/boot/bzImage 複製為 mydroid/vendor/asus/eee_701/kernel。</li><li>我稍稍更動了一些設定，這樣我後面就省打一些東西：<ul><li>vendor/asus/eee_701/BoardConfig.mk：在 BOARD_KERNEL_CMDLINE 加上 vga=788</li><li>vendor/asus/eee_701/init.eee_701.sh：把 netcfg eth0 dhcp 改為 dhcpcd eth0</li></ul></li><li>接著就是建置 image 了，這裡是我用的 script，把以下內容存為 build.sh，並放在 mydroid 下：<pre name="code" class="bash">#!/bin/bash
cp kernel/arch/x86/boot/bzImage vendor/asus/eee_701/kernel
mkdir -p out/target/product/eee_701/data/
cp kernel/arch/x86/boot/bzImage out/target/product/eee_701/kernel

TARGET_ARCH=x86 TARGET_PRODUCT=eee_701 DISABLE_DEXPREOPT=true make -j2 installer_img
</pre>，執行前別忘了 chmod +x 。</li><li>建置完以後，你會在 out/target/product/eee_701 下找到 installer.img。</li><li>把 installer.img 轉為 <a href="http://www.virtualbox.org/">VirtualBox</a>/VMWare 可用的 disk image，這邊要利用 <a href="http://www.virtualbox.org/">VirtualBox</a> 的 vboxmanage 來轉：vboxmanage convertfromraw -format vdi installer.img installer.vdi，如果你用 VMWare，則是：vboxmanage convertfromraw -format vmdk installer.img installer.vmdk</li><li>建置新的 VM，設置為 Linux kernel 2.6，256M 的 RAM，以及一個超過 2G 的硬碟。然後把上個步驟轉好的 disk image 加為第二個儲存裝置。</li><li>接下來，我只以 <a href="http://www.virtualbox.org/">VirtualBox</a> 為例，因為我沒試過 VMWare，不過原理一樣。將這個 VM 開機，一開機馬上按 F12，選擇從第二個儲存裝置開機。一開機，你會看到 grub 的開機選單，趕緊按下任意鍵，因為這邊要修改一下，預設 Loader 的開機磁碟是 hd(0,0)，你要按 e 進行修改，把 hd(0,0) 改為 hd(1,0)，再按 b 繼續開機(如果你不熟 grub，麻煩熟悉，這邊我不多說)。開機以後，就會開始進行安裝的動作，Android 會安裝到第一個磁碟上去，這個步驟要等一陣子，如果有錯誤，再重複一次即可，根據我的經驗，有時候會因為切割磁碟失敗而停止安裝，但再從第二個磁碟開機安裝一次，通常即可解決。安裝完成不會有什麼訊息，但看一下畫面上訊息，你應該可以知道已經完成，輸入 reboot 重新開機。</li><li>最後就大功告成啦～接著你可以移除第二個磁碟，因為再也用不到啦～</li></ol>

最後的最後，希望我沒有遺漏～

<a href="http://www.flickr.com/photos/elleryq/3362016147/" title="Flickr 上 elleryq 的 android"><img src="http://farm4.static.flickr.com/3605/3362016147_459490a660.jpg" width="500" height="421" alt="android" /></a>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8533633.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8533633.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 17 Mar 2009 20:50:37 +0800</pubDate>
</item>
<item>
	<title>Seed(3) - Glade</title>
	<description><![CDATA[
			純手工寫 UI 實在是很苦，還好有 Glade，你可以用 Glade 設計出介面以後，再用 Seed 把事件指派一下就可以完成一個程式了。這裡假設你已經用 Glade 設計出畫面，把主要的視窗命名為 window1，並且存為 glade-1.glade。存好以後，要使用 gtk-builder-convert 把 .glade 轉為 .xml。gtk-builder-convert glade-1.glade glade-1.xml
接著就可以寫 code 了：
#!/usr/bin/env seed
// First, you need to use gtk-builder-convert to convert glade to xml.
// gtk-builder-convert glade-1.glade glade-1.xml

// Import libraries that are used by the program
Seed.import_namespace("Gtk");

// Initialize GTK+
Gtk.init(null, null);
var ui = new Gtk.Builder();
ui.add_from_file("glade-1.xml");

var window = ui.get_object("window1");
window.signal.hide.connect(Gtk.main_quit);

// Start the main GTK+ loop and initiate the program
Gtk.main();


參考資料：Desktop Linux Applications with Javascript

		]]>
	</description>
	<content:encoded><![CDATA[
			純手工寫 UI 實在是很苦，還好有 Glade，你可以用 Glade 設計出介面以後，再用 Seed 把事件指派一下就可以完成一個程式了。這裡假設你已經用 Glade 設計出畫面，把主要的視窗命名為 window1，並且存為 glade-1.glade。存好以後，要使用 gtk-builder-convert 把 .glade 轉為 .xml。<pre name="code" class="bash">gtk-builder-convert glade-1.glade glade-1.xml</pre><br/>
接著就可以寫 code 了：<pre name="code" class="javascript">
#!/usr/bin/env seed
// First, you need to use gtk-builder-convert to convert glade to xml.
// gtk-builder-convert glade-1.glade glade-1.xml

// Import libraries that are used by the program
Seed.import_namespace("Gtk");

// Initialize GTK+
Gtk.init(null, null);
var ui = new Gtk.Builder();
ui.add_from_file("glade-1.xml");

var window = ui.get_object("window1");
window.signal.hide.connect(Gtk.main_quit);

// Start the main GTK+ loop and initiate the program
Gtk.main();
</pre>

參考資料：<a href="http://www.ozzu.com/programming-forum/desktop-linux-applications-with-javascript-t94828.html">Desktop Linux Applications with Javascript</a>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8495829.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8495829.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 13 Mar 2009 20:11:50 +0800</pubDate>
</item>
<item>
	<title>Seed(2)</title>
	<description><![CDATA[
			GObject、Gio、Gtk、Glib、Clutter 等在範例裡看到的 library，在 Seed 原始碼裡是看不到的，Seed 是利用 GObject Introspection 來跟這些 library 互動。
Cairo、sqlite、readline 的話，因為並沒有使用 GObject 這個 library，所以 Seed 另外寫 Module 來跟這些 library 互動，你可以在 Seed 原始碼的 modules 目錄下看到～

Cairo 實際上是在 Canvas 這個 module 裡，Canvas 裡共有四個主要的類別：CairoCanvas、PDFCanvas、SVGCanvas、ImageCanvas，創建這些 Canvas 以後，基本上都是使用 Cairo 來在這些 Canvas 上繪圖。裡面沒有封裝 cairo_pattern_xxxx、cairo_text_xxxx、cairo_mask...等函數，所以不能用 Cairo 來繪圖或是繪字。
#!/usr/bin/env seed

Seed.import_namespace("Gtk");
Seed.import_namespace("Canvas");
Seed.import_namespace("Gdk");

//
// Initialize GTK+
//
Gtk.init(null, null);

// Create the main application window and set the title
var window = new Gtk.Window({title: "Canvas Demo"});
var vbox = new Gtk.VBox();
var drawingArea = new Gtk.DrawingArea();
var status = new Gtk.Statusbar();
var hbox = new Gtk.HBox();
var exposeEvent = function() { return true;};

//
// create Cairo Canvas
//
function createCairoCanvas()
{
	var cairo = Gdk.cairo_create( drawingArea.window );
	return new Canvas.CairoCanvas( cairo );
}

// 
// Demos from http://cairographics.org/tutorial/
//
function strokeDemo()
{
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.strokeStyle = "rgb( 0, 0, 255 )";
	canvas.strokeRect( 10, 10, 50, 50 );
	canvas.stroke();
	return true;
}

function fillDemo()
{
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.fillStyle = "rgb( 0, 0, 255 )";
	canvas.fillRect( 10, 10, 50, 50 );
	canvas.fill();
	return true;
}

function fourColorDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.strokeStyle = "rgb( 0, 0, 0 )";
	canvas.moveTo( 0, 0 );
	canvas.lineTo( 100, 100 );
	canvas.moveTo( 100, 0 );
	canvas.lineTo( 0, 100 );
	canvas.lineWidth = 10;
	canvas.stroke();

	canvas.fillStyle = "rgb( 255, 0, 0 )";
	canvas.globalAlpha = 0.8;
	canvas.fillRect( 0, 0, 50, 50 );

	canvas.fillStyle = "rgb( 0, 255, 0 )";
	canvas.globalAlpha = 0.6;
	canvas.fillRect( 0, 50, 50, 50 );

	canvas.fillStyle = "rgb( 0, 0, 255 )";
	canvas.globalAlpha = 0.4;
	canvas.fillRect( 50, 0, 50, 50 );
	return true;
}

function pathDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.strokeStyle = "rgb( 255, 0, 0 )";
	canvas.beginPath();
	canvas.moveTo( 25, 25 );
	canvas.lineTo( 50, 37.5 );
	canvas.lineTo( 75, 25 );
	canvas.arc( 50, 50, 25*Math.sqrt(2), -0.25*Math.PI, 0.25*Math.PI, false );
	canvas.bezierCurveTo( 50, 37.5, 50, 62.5, 25, 75 );
	canvas.closePath();
	canvas.stroke();
	return true;
}

function scaleAndTransformDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.strokeStyle = "rgb( 255, 0, 0 )";
	canvas.lineWidth=10;
	canvas.save();
	canvas.scale( 0.5, 1 );
	canvas.arc( 50, 50, 40, 0, 2*Math.PI, true );
	canvas.stroke();

	canvas.translate( 100, 0 );
	canvas.arc( 50, 50, 40, 0, 2*Math.PI, true );
	canvas.restore();
	canvas.stroke();

	return true;
}

// 
// Demos from http://cairographics.org/samples/
//
function arcDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	var xc = 128;
	var yc = 128;
	var radius = 100;
	var angle1 = 45 * (Math.PI/180);
	var angle2 = 180 * (Math.PI/180);

	canvas.lineWidth = 10;
	canvas.arc( xc, yc, radius, angle1, angle2, true );
	canvas.stroke();

	canvas.fillStyle = "rgb( 255, 51, 51 )";
	canvas.globalAlpha = 0.6;
	canvas.lineWidth = 6;
	canvas.arc( xc, yc, 10, 0, 2*Math.PI, true );
	canvas.fill();

	canvas.arc( xc, yc, radius, angle1, angle2, true );
	canvas.lineTo( xc, yc );
	canvas.arc( xc, yc, radius, angle2, angle2, true );
	canvas.lineTo( xc, yc );
	canvas.stroke();

	return true;
}

function clipDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.arc( 128, 128, 76.8, 0, 2*Math.PI, true );
	canvas.clip();
	canvas.beginPath();
	canvas.fillRect( 0, 0, 256, 256 );
	canvas.strokeStyle = "rgb( 0, 255, 0)";
	canvas.moveTo( 0, 0 );
	canvas.lineTo( 256, 256 );
	canvas.moveTo( 256, 0 );
	canvas.lineTo( 0, 256 );
	canvas.lineWidth = 10;
	canvas.closePath();
	canvas.stroke();

	return true;
}

function curveRectangleDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	var x0 = 25.6;
	var y0 = 25.6;
	var rect_width = 204.8;
	var rect_height = 204.8;
	var radius = 102.4;
	var x1, y1;

	x1 = x0 + rect_width;
	y1 = y0 + rect_height;
	if( rect_width/2 &lt; radius ) {
		if( rect_height/2&lt;radius ) {
			canvas.moveTo( x0, (y0+y1)/2 );
			canvas.bezierCurveTo( x0, y0, x0, y0, (x0+x1)/2, y0 );
			canvas.bezierCurveTo( x1, y0, x1, y0, x1, (y0+y1)/2 );
			canvas.bezierCurveTo( x1, y1, x1, y1, (x0+x1)/2, y1 );
			canvas.bezierCurveTo( x0, y1, x0, y1, x0, (y0+y1)/2 );
		}
		else {
			canvas.moveTo( x0, y0+raius );
			canvas.bezierCurveTo( x0, y0, x0, y0, (x0+x1)/2, y0 );
			canvas.bezierCurveTo( x1, y0, x1, y0, x1, y0+radius );
			canvas.lineTo( x1, y1-radius );
			canvas.bezierCurveTo( x1, y1, x1, y1, (x1+x0)/2, y1 );
			canvas.bezierCurveTo( x0, y1, x0, y1, x0, y1-radius );
		}
	}
	else {
		if( rect_height/2&lt;radius ) {
			canvas.moveTo( x0, (y0+y1)/2 );
			canvas.bezierCurveTo( x0, y0, x0, y0, x0+radius, y0 );
			canvas.lineTo( x1-radius, y0 );
			canvas.bezierCurveTo( x1, y0, x1, y0, x1, (y0+y1)/2 );
			canvas.bezierCurveTo( x1, y1, x1, y1, x1-radius, y1 );
			canvas.lineTo( x0+radius, y1 );
			canvas.bezierCurveTo( x0, y1, x0, y1, x0, (y0+y1)/2 );
		}
		else {
			canvas.moveTo( x0, y0+radius );
			canvas.bezierCurveTo( x0, y0, x0, y0, x0+radius, y0 );
			canvas.lineTo( x1-radius, y0 );
			canvas.bezierCurveTo( x1, y0, x1, y0, x1, y0+radius );
			canvas.lineTo( x1, y1-radius );
			canvas.bezierCurveTo( x1, y1, x1, y1, x1-radius, y1 );
			canvas.lineTo( x0+radius, y1 );
			canvas.bezierCurveTo( x0, y1, x0, y1, x0, y1-radius );
		}
	}
	canvas.closePath();
	canvas.fillStyle = "rgb( 128, 128, 255 )";
	canvas.fill(); // no fill_preserve(), so you won't see the border.
	canvas.strokeStyle = "rgb( 255, 0, 0 )";
	canvas.globalAlpha = 0.5;
	canvas.lineWidth = 10;
	canvas.stroke();

	return true;
}

function curveToDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	var x=25.6, y=128;
	var x1=102.4, y1=230.4, x2=153.6, y2=25.6, x3=230.4, y3=128.0;

	canvas.moveTo( x, y );
	canvas.bezierCurveTo( x1, y1, x2, y2, x3, y3 );
	canvas.lineWidth = 10;
	canvas.stroke();

	canvas.strokeStyle = "rgb( 255, 51, 51 )";
	canvas.globalAlpha = 0.6;
	canvas.lineWidth = 6;
	canvas.moveTo( x, y ); canvas.lineTo( x1, y1 );
	canvas.moveTo( x2, y2 ); canvas.lineTo( x3, y3 );
	canvas.stroke();

	return true;
}

function rotateDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.translate( 128, 128 );
	canvas.rotate( 45*Math.PI/180 );
	canvas.scale( 0.9, 0.9 );

	canvas.fillStyle = "rgb(200,0,0)";
	canvas.fillRect( 10, 10, 55, 50 );

	canvas.strokeStyle = "rgb( 0, 200, 0 )";
	canvas.strokeRect( 50, 50, 155, 150 );

	canvas.strokeStyle = "rgb( 0, 0, 255 )";
	canvas.arc( 137.5, 137.5, 100, 0, Math.PI*2, true );
	canvas.stroke();
	return true;
}

//
// routines
//
function createButton( label, handler ) {
	var button = new Gtk.Button( {label: label} );
	button.signal.clicked.connect( handler );
	return button;
}

function createButtonGroup()
{
	var buttonGroup = new Gtk.VBox();
	//var buttonGroup = new Gtk.VButtonBox();
	buttonGroup.pack_start( createButton( "Stroke", function() {
		exposeEvent = strokeDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Fill", function() {
		exposeEvent = fillDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "4 color", function() {
		exposeEvent = fourColorDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Path", function() {
		exposeEvent = pathDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Scale and Transform", function() {
		exposeEvent = scaleAndTransformDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Arc", function() {
		exposeEvent = arcDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Clip", function() {
		exposeEvent = clipDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Curve Rectangle", function() {
		exposeEvent = curveRectangleDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Curve To", function() {
		exposeEvent = curveToDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Rotate", function() {
		exposeEvent = rotateDemo;
		return exposeEvent();
	} ), true, true);
	return buttonGroup;
}

//
// Events
//
function drawingArea_ExposeEvent() {
	return exposeEvent();
}

//
// Main
//

// Make the program terminate when the window is closed
window.signal.hide.connect(Gtk.main_quit);

drawingArea.signal.expose_event.connect( drawingArea_ExposeEvent );

hbox.pack_start( createButtonGroup(), false, false);
hbox.pack_start( drawingArea, true, true );

vbox.pack_start( hbox, true, true );
vbox.pack_start( status, false, false, 0);

window.add(vbox);
window.show_all();
window.resize( 640, 480 );

// Start the main GTK+ loop and initiate the program
Gtk.main();

關於這個例子，大部分都是從 Cairo網站上的範例搬來的，也幾乎演示了所有的函數，但還是有少數函數與屬性沒有涵蓋到，如 transform、setTransform、clearRect、quadraticCurveTo...等～
有需要再自己去翻 seed-canvas.c 看吧～

		]]>
	</description>
	<content:encoded><![CDATA[
			GObject、Gio、Gtk、Glib、Clutter 等在範例裡看到的 library，在 <a href="http://live.gnome.org/Seed">Seed</a> 原始碼裡是看不到的，<a href="http://live.gnome.org/Seed">Seed</a> 是利用 <a href="http://live.gnome.org/GObjectIntrospection/">GObject Introspection</a> 來跟這些 library 互動。
Cairo、sqlite、readline 的話，因為並沒有使用 GObject 這個 library，所以 <a href="http://live.gnome.org/Seed">Seed</a> 另外寫 Module 來跟這些 library 互動，你可以在 <a href="http://live.gnome.org/Seed">Seed</a> 原始碼的 modules 目錄下看到～

Cairo 實際上是在 Canvas 這個 module 裡，Canvas 裡共有四個主要的類別：CairoCanvas、PDFCanvas、SVGCanvas、ImageCanvas，創建這些 Canvas 以後，基本上都是使用 Cairo 來在這些 Canvas 上繪圖。裡面沒有封裝 cairo_pattern_xxxx、cairo_text_xxxx、cairo_mask...等函數，所以不能用 Cairo 來繪圖或是繪字。
<pre name="code" class="javascript">#!/usr/bin/env seed

Seed.import_namespace("Gtk");
Seed.import_namespace("Canvas");
Seed.import_namespace("Gdk");

//
// Initialize GTK+
//
Gtk.init(null, null);

// Create the main application window and set the title
var window = new Gtk.Window({title: "Canvas Demo"});
var vbox = new Gtk.VBox();
var drawingArea = new Gtk.DrawingArea();
var status = new Gtk.Statusbar();
var hbox = new Gtk.HBox();
var exposeEvent = function() { return true;};

//
// create Cairo Canvas
//
function createCairoCanvas()
{
	var cairo = Gdk.cairo_create( drawingArea.window );
	return new Canvas.CairoCanvas( cairo );
}

// 
// Demos from http://cairographics.org/tutorial/
//
function strokeDemo()
{
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.strokeStyle = "rgb( 0, 0, 255 )";
	canvas.strokeRect( 10, 10, 50, 50 );
	canvas.stroke();
	return true;
}

function fillDemo()
{
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.fillStyle = "rgb( 0, 0, 255 )";
	canvas.fillRect( 10, 10, 50, 50 );
	canvas.fill();
	return true;
}

function fourColorDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.strokeStyle = "rgb( 0, 0, 0 )";
	canvas.moveTo( 0, 0 );
	canvas.lineTo( 100, 100 );
	canvas.moveTo( 100, 0 );
	canvas.lineTo( 0, 100 );
	canvas.lineWidth = 10;
	canvas.stroke();

	canvas.fillStyle = "rgb( 255, 0, 0 )";
	canvas.globalAlpha = 0.8;
	canvas.fillRect( 0, 0, 50, 50 );

	canvas.fillStyle = "rgb( 0, 255, 0 )";
	canvas.globalAlpha = 0.6;
	canvas.fillRect( 0, 50, 50, 50 );

	canvas.fillStyle = "rgb( 0, 0, 255 )";
	canvas.globalAlpha = 0.4;
	canvas.fillRect( 50, 0, 50, 50 );
	return true;
}

function pathDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.strokeStyle = "rgb( 255, 0, 0 )";
	canvas.beginPath();
	canvas.moveTo( 25, 25 );
	canvas.lineTo( 50, 37.5 );
	canvas.lineTo( 75, 25 );
	canvas.arc( 50, 50, 25*Math.sqrt(2), -0.25*Math.PI, 0.25*Math.PI, false );
	canvas.bezierCurveTo( 50, 37.5, 50, 62.5, 25, 75 );
	canvas.closePath();
	canvas.stroke();
	return true;
}

function scaleAndTransformDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.strokeStyle = "rgb( 255, 0, 0 )";
	canvas.lineWidth=10;
	canvas.save();
	canvas.scale( 0.5, 1 );
	canvas.arc( 50, 50, 40, 0, 2*Math.PI, true );
	canvas.stroke();

	canvas.translate( 100, 0 );
	canvas.arc( 50, 50, 40, 0, 2*Math.PI, true );
	canvas.restore();
	canvas.stroke();

	return true;
}

// 
// Demos from http://cairographics.org/samples/
//
function arcDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	var xc = 128;
	var yc = 128;
	var radius = 100;
	var angle1 = 45 * (Math.PI/180);
	var angle2 = 180 * (Math.PI/180);

	canvas.lineWidth = 10;
	canvas.arc( xc, yc, radius, angle1, angle2, true );
	canvas.stroke();

	canvas.fillStyle = "rgb( 255, 51, 51 )";
	canvas.globalAlpha = 0.6;
	canvas.lineWidth = 6;
	canvas.arc( xc, yc, 10, 0, 2*Math.PI, true );
	canvas.fill();

	canvas.arc( xc, yc, radius, angle1, angle2, true );
	canvas.lineTo( xc, yc );
	canvas.arc( xc, yc, radius, angle2, angle2, true );
	canvas.lineTo( xc, yc );
	canvas.stroke();

	return true;
}

function clipDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.arc( 128, 128, 76.8, 0, 2*Math.PI, true );
	canvas.clip();
	canvas.beginPath();
	canvas.fillRect( 0, 0, 256, 256 );
	canvas.strokeStyle = "rgb( 0, 255, 0)";
	canvas.moveTo( 0, 0 );
	canvas.lineTo( 256, 256 );
	canvas.moveTo( 256, 0 );
	canvas.lineTo( 0, 256 );
	canvas.lineWidth = 10;
	canvas.closePath();
	canvas.stroke();

	return true;
}

function curveRectangleDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	var x0 = 25.6;
	var y0 = 25.6;
	var rect_width = 204.8;
	var rect_height = 204.8;
	var radius = 102.4;
	var x1, y1;

	x1 = x0 + rect_width;
	y1 = y0 + rect_height;
	if( rect_width/2 &lt; radius ) {
		if( rect_height/2&lt;radius ) {
			canvas.moveTo( x0, (y0+y1)/2 );
			canvas.bezierCurveTo( x0, y0, x0, y0, (x0+x1)/2, y0 );
			canvas.bezierCurveTo( x1, y0, x1, y0, x1, (y0+y1)/2 );
			canvas.bezierCurveTo( x1, y1, x1, y1, (x0+x1)/2, y1 );
			canvas.bezierCurveTo( x0, y1, x0, y1, x0, (y0+y1)/2 );
		}
		else {
			canvas.moveTo( x0, y0+raius );
			canvas.bezierCurveTo( x0, y0, x0, y0, (x0+x1)/2, y0 );
			canvas.bezierCurveTo( x1, y0, x1, y0, x1, y0+radius );
			canvas.lineTo( x1, y1-radius );
			canvas.bezierCurveTo( x1, y1, x1, y1, (x1+x0)/2, y1 );
			canvas.bezierCurveTo( x0, y1, x0, y1, x0, y1-radius );
		}
	}
	else {
		if( rect_height/2&lt;radius ) {
			canvas.moveTo( x0, (y0+y1)/2 );
			canvas.bezierCurveTo( x0, y0, x0, y0, x0+radius, y0 );
			canvas.lineTo( x1-radius, y0 );
			canvas.bezierCurveTo( x1, y0, x1, y0, x1, (y0+y1)/2 );
			canvas.bezierCurveTo( x1, y1, x1, y1, x1-radius, y1 );
			canvas.lineTo( x0+radius, y1 );
			canvas.bezierCurveTo( x0, y1, x0, y1, x0, (y0+y1)/2 );
		}
		else {
			canvas.moveTo( x0, y0+radius );
			canvas.bezierCurveTo( x0, y0, x0, y0, x0+radius, y0 );
			canvas.lineTo( x1-radius, y0 );
			canvas.bezierCurveTo( x1, y0, x1, y0, x1, y0+radius );
			canvas.lineTo( x1, y1-radius );
			canvas.bezierCurveTo( x1, y1, x1, y1, x1-radius, y1 );
			canvas.lineTo( x0+radius, y1 );
			canvas.bezierCurveTo( x0, y1, x0, y1, x0, y1-radius );
		}
	}
	canvas.closePath();
	canvas.fillStyle = "rgb( 128, 128, 255 )";
	canvas.fill(); // no fill_preserve(), so you won't see the border.
	canvas.strokeStyle = "rgb( 255, 0, 0 )";
	canvas.globalAlpha = 0.5;
	canvas.lineWidth = 10;
	canvas.stroke();

	return true;
}

function curveToDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	var x=25.6, y=128;
	var x1=102.4, y1=230.4, x2=153.6, y2=25.6, x3=230.4, y3=128.0;

	canvas.moveTo( x, y );
	canvas.bezierCurveTo( x1, y1, x2, y2, x3, y3 );
	canvas.lineWidth = 10;
	canvas.stroke();

	canvas.strokeStyle = "rgb( 255, 51, 51 )";
	canvas.globalAlpha = 0.6;
	canvas.lineWidth = 6;
	canvas.moveTo( x, y ); canvas.lineTo( x1, y1 );
	canvas.moveTo( x2, y2 ); canvas.lineTo( x3, y3 );
	canvas.stroke();

	return true;
}

function rotateDemo() {
	drawingArea.window.clear();

	var canvas = createCairoCanvas();
	canvas.translate( 128, 128 );
	canvas.rotate( 45*Math.PI/180 );
	canvas.scale( 0.9, 0.9 );

	canvas.fillStyle = "rgb(200,0,0)";
	canvas.fillRect( 10, 10, 55, 50 );

	canvas.strokeStyle = "rgb( 0, 200, 0 )";
	canvas.strokeRect( 50, 50, 155, 150 );

	canvas.strokeStyle = "rgb( 0, 0, 255 )";
	canvas.arc( 137.5, 137.5, 100, 0, Math.PI*2, true );
	canvas.stroke();
	return true;
}

//
// routines
//
function createButton( label, handler ) {
	var button = new Gtk.Button( {label: label} );
	button.signal.clicked.connect( handler );
	return button;
}

function createButtonGroup()
{
	var buttonGroup = new Gtk.VBox();
	//var buttonGroup = new Gtk.VButtonBox();
	buttonGroup.pack_start( createButton( "Stroke", function() {
		exposeEvent = strokeDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Fill", function() {
		exposeEvent = fillDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "4 color", function() {
		exposeEvent = fourColorDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Path", function() {
		exposeEvent = pathDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Scale and Transform", function() {
		exposeEvent = scaleAndTransformDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Arc", function() {
		exposeEvent = arcDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Clip", function() {
		exposeEvent = clipDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Curve Rectangle", function() {
		exposeEvent = curveRectangleDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Curve To", function() {
		exposeEvent = curveToDemo;
		return exposeEvent();
	}), true, true);
	buttonGroup.pack_start( createButton( "Rotate", function() {
		exposeEvent = rotateDemo;
		return exposeEvent();
	} ), true, true);
	return buttonGroup;
}

//
// Events
//
function drawingArea_ExposeEvent() {
	return exposeEvent();
}

//
// Main
//

// Make the program terminate when the window is closed
window.signal.hide.connect(Gtk.main_quit);

drawingArea.signal.expose_event.connect( drawingArea_ExposeEvent );

hbox.pack_start( createButtonGroup(), false, false);
hbox.pack_start( drawingArea, true, true );

vbox.pack_start( hbox, true, true );
vbox.pack_start( status, false, false, 0);

window.add(vbox);
window.show_all();
window.resize( 640, 480 );

// Start the main GTK+ loop and initiate the program
Gtk.main();
</pre>
關於這個例子，大部分都是從 <a href="http://cairographics.org">Cairo</a>網站上的範例搬來的，也幾乎演示了所有的函數，但還是有少數函數與屬性沒有涵蓋到，如 transform、setTransform、clearRect、quadraticCurveTo...等～
有需要再自己去翻 seed-canvas.c 看吧～

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8345465.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8345465.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 20 Feb 2009 18:22:23 +0800</pubDate>
</item>
<item>
	<title>xming 與中文輸入</title>
	<description><![CDATA[
			開終端機以後，要先設置環境變數，告訴兩大 framework 你要使用的輸入法：export GTK_IM_MODULE=gcin
export QT_IM_MODULE=gcin，這裡的 gcin，你可以替換為自己熟悉的輸入法，例如 scim、fcitx...。Hot key 會打架，所以你用 ctrl-space 的話，是 windows 的輸入法起來，不是 linux 的輸入法起來。因此要把 hot key 換掉，gcin 可以用 ctrl+alt+數字鍵 來切換，要切換為英文，則可以用 caps lock。這邊就看你自己輸入法的設定了。

		]]>
	</description>
	<content:encoded><![CDATA[
			<ol><li>開終端機以後，要先設置環境變數，告訴兩大 framework 你要使用的輸入法：<pre name="code" class="bash">export GTK_IM_MODULE=gcin<br />
export QT_IM_MODULE=gcin</pre>，這裡的 gcin，你可以替換為自己熟悉的輸入法，例如 scim、fcitx...。</li><li>Hot key 會打架，所以你用 ctrl-space 的話，是 windows 的輸入法起來，不是 linux 的輸入法起來。因此要把 hot key 換掉，gcin 可以用 ctrl+alt+數字鍵 來切換，要切換為英文，則可以用 caps lock。這邊就看你自己輸入法的設定了。</li></ol><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8341589.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8341589.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Thu, 19 Feb 2009 16:40:26 +0800</pubDate>
</item>
<item>
	<title>Seed(1)</title>
	<description><![CDATA[
			在Ubuntu裡安裝 Seed 很簡單，參考PPA for Orange Owners裡，把deb http://ppa.launchpad.net/orange-owners/ppa/ubuntu intrepid main
deb-src http://ppa.launchpad.net/orange-owners/ppa/ubuntu intrepid main放到 /etc/sources.list 裡，然後用 sudo apt-get update 更新，sudo apt-get install seed 來安裝即可。

執行 script 也很簡單，有兩種方法：直接以 seed 執行：seed your_script.js把 js 檔的第一行改為 #!/usr/bin/env seed，再以 chmod +x 為 js 檔加上執行權限，就可以用 ./your_script.js 執行。
目前官方沒有文件說明 Seed 內部有哪些類別與方法，這很讓人困擾，這兩天看了 source code 跟 example code 之後，大致上有點了解。

Seed 主要的類別是 Seed，提供了如下方法：include：用來含括其他 js，讓你可以為程式作適當的切割，不至於讓檔案變得太大而難以維護。Seed.include("other.js");print：印字串。Seed.print("Hello world!");check_syntax：檢查語法，你可以傳 javascript 程式進去檢查，如果有錯，會丟出 exception。try { 
	Seed.check_syntax("Seed.print(;");
	Seed.print("syntax ok!");
}
catch( e ) {
	Seed.print( e.message );
}spawn：執行外部程式，執行以後會回傳一個 object，這個 object 有兩個屬性：stdout 與 stderr。var result = Seed.spawn("ls");
Seed.print( "=== spawn result(stdout) ===" );
Seed.print( result.stdout );
Seed.print( "=== spawn result(stderr) ===" );
Seed.print( result.stderr );
fork：這跟 C 的 fork() 一樣，回傳值是 0，表示是子行程，-1 表示失敗，大於 0 的值，表示是父行程。var pid = Seed.fork();
if( pid == 0 ) { // child process
	var result = Seed.spawn( "ls" );
	Seed.print( result.stdout );
	Seed.quit();
}
else if( pid == -1 ) {
	Seed.print( "cannot create child process." );
}
else { // parent process.
	Seed.print( "I am parent process." );
}
quit：離開。introspect：這個函數可以用來探知類別成員函數如何使用，安裝 Seed 以後，/usr/share/doc/seed/examples 下有個 introspect.js，就是一個很好的範例。不過我還不是很懂怎麼去用～import_namespace：含括其他 library 進來使用，不要跟 include 搞混了，include 是含括其他 js 檔。

		]]>
	</description>
	<content:encoded><![CDATA[
			在<a href="http://ubuntulinux.com">Ubuntu</a>裡安裝 Seed 很簡單，參考<a href="https://edge.launchpad.net/~orange-owners/+archive/ppa">PPA for Orange Owners</a>裡，把<pre>deb http://ppa.launchpad.net/orange-owners/ppa/ubuntu intrepid main
deb-src http://ppa.launchpad.net/orange-owners/ppa/ubuntu intrepid main</pre>放到 /etc/sources.list 裡，然後用 sudo apt-get update 更新，sudo apt-get install seed 來安裝即可。<br/>
<br/>
執行 script 也很簡單，有兩種方法：<ol><li>直接以 seed 執行：seed your_script.js</li><li>把 js 檔的第一行改為 #!/usr/bin/env seed，再以 chmod +x 為 js 檔加上執行權限，就可以用 ./your_script.js 執行。</li></ol>
目前官方沒有文件說明 <a href="http://live.gnome.org/Seed">Seed</a> 內部有哪些類別與方法，這很讓人困擾，這兩天看了 source code 跟 example code 之後，大致上有點了解。<br/>
<br/>
<a href="http://live.gnome.org/Seed">Seed</a> 主要的類別是 Seed，提供了如下方法：<ul><li>include：用來含括其他 js，讓你可以為程式作適當的切割，不至於讓檔案變得太大而難以維護。<pre name="code" class="javascript">Seed.include("other.js");</pre></li><li>print：印字串。<pre name="code" class="javascript">Seed.print("Hello world!");</pre></li><li>check_syntax：檢查語法，你可以傳 javascript 程式進去檢查，如果有錯，會丟出 exception。<pre name="code" class="javascript">try { 
	Seed.check_syntax("Seed.print(;");
	Seed.print("syntax ok!");
}
catch( e ) {
	Seed.print( e.message );
}</pre></li><li>spawn：執行外部程式，執行以後會回傳一個 object，這個 object 有兩個屬性：stdout 與 stderr。<pre name="code" class="javascript">var result = Seed.spawn("ls");
Seed.print( "=== spawn result(stdout) ===" );
Seed.print( result.stdout );
Seed.print( "=== spawn result(stderr) ===" );
Seed.print( result.stderr );
</pre></li><li>fork：這跟 C 的 fork() 一樣，回傳值是 0，表示是子行程，-1 表示失敗，大於 0 的值，表示是父行程。<pre name="code" class="javascript">var pid = Seed.fork();
if( pid == 0 ) { // child process
	var result = Seed.spawn( "ls" );
	Seed.print( result.stdout );
	Seed.quit();
}
else if( pid == -1 ) {
	Seed.print( "cannot create child process." );
}
else { // parent process.
	Seed.print( "I am parent process." );
}
</pre></li><li>quit：離開。</li><li>introspect：這個函數可以用來探知類別成員函數如何使用，安裝 <a href="http://live.gnome.org/Seed">Seed</a> 以後，/usr/share/doc/seed/examples 下有個 introspect.js，就是一個很好的範例。不過我還不是很懂怎麼去用～</li><li>import_namespace：含括其他 library 進來使用，不要跟 include 搞混了，include 是含括其他 js 檔。</li></ul>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8334873.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8334873.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 18 Feb 2009 14:00:31 +0800</pubDate>
</item>
<item>
	<title>把檔案內容放到環境變數</title>
	<description><![CDATA[
			在 bash 下很簡單的一件事情，批次檔似乎沒有比較好的解～

在 bash 下：VERSION=`cat version.txt`

在批次檔裡，我發現可以用 for 來解：@For /f "" %%a in (version.txt) do (set VERSION=%%a)
但缺點是，當檔案有多行時，VERSION 會是最後一行的內容。

		]]>
	</description>
	<content:encoded><![CDATA[
			在 bash 下很簡單的一件事情，批次檔似乎沒有比較好的解～<br />
<br />
在 bash 下：<pre name="code" class="bash">VERSION=`cat version.txt`</pre><br />
<br />
在批次檔裡，我發現可以用 for 來解：<pre>@For /f "" %%a in (version.txt) do (set VERSION=%%a)</pre><br />
但缺點是，當檔案有多行時，VERSION 會是最後一行的內容。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8321203.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8321203.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 17 Feb 2009 13:24:21 +0800</pubDate>
</item>
<item>
	<title>當 jQuery().ajax() 遇到 ASP</title>
	<description><![CDATA[
			利用 jqGrid 新增中文欄位資料時，到伺服器端時，就變成亂碼了。
請 FireBug 大神幫忙，發現 request header content-type 的編碼是 utf-8，查過jqGrid的 source code，裡面也只是調用 jQuery 的 ajax 函數而已。
照理來說，應該可以用 $.ajaxSetup() 來修正，但試了好一陣子，發現沒辦法，即使我在 contentType 裡指定了 charset=big5，最後送出時，仍然會是 utf-8...

好吧，山不轉路轉，再拜請Google大神，發現有人利用 escape() 解，也就是先用 javascript escape() 編碼，server 端再解碼，這樣就解了。
大致的代碼是這樣：//
$("#jqGrid2").jqGrid( 
  // ... 略 ...
).navGrid( "#pager2", {
  // ... 略 ...
  add:true,
  addfunc: function() {
    $("#jqGrid2").editGridRow( "new", {
      url: "server.asp",
      beforeSubmit: function( postdata, o ) {
        var s = postdata[ "your_field_name" ];
        var ret=[true, "", ""];
        postdata[ "your_field_name" ] = escape( s );
        return ret;
      }
    } );
    return false;
  }
} );



		]]>
	</description>
	<content:encoded><![CDATA[
			利用 <a href="http://www.trirand.com/blog/">jqGrid</a> 新增中文欄位資料時，到伺服器端時，就變成亂碼了。<br/>
請 <a href="https://addons.mozilla.org/zh-TW/firefox/addon/1843">FireBug</a> 大神幫忙，發現 request header content-type 的編碼是 utf-8，查過<a href="http://www.trirand.com/blog/">jqGrid</a>的 source code，裡面也只是調用 <a href="http://www.jquery.com">jQuery</a> 的 ajax 函數而已。<br/>
照理來說，應該可以用 <a href="http://docs.jquery.com/Ajax/jQuery.ajax#options">$.ajaxSetup()</a> 來修正，但試了好一陣子，發現沒辦法，即使我在 contentType 裡指定了 charset=big5，最後送出時，仍然會是 utf-8...<br/>
<br/>
好吧，山不轉路轉，再拜請<a href="http://www.google.com">Google</a>大神，發現<a href="http://www.cn-java.com/www1/?action-viewnews-itemid-10527" title="asp,jquery,ajax中文乱码解决办法 - 中文JAVA技术网">有人利用 escape() 解</a>，也就是先用 javascript escape() 編碼，server 端再解碼，這樣就解了。<br/>
大致的代碼是這樣：<pre name="code" class="javascript">//
$("#jqGrid2").jqGrid( 
  // ... 略 ...
).navGrid( "#pager2", {
  // ... 略 ...
  add:true,
  addfunc: function() {
    $("#jqGrid2").editGridRow( "new", {
      url: "server.asp",
      beforeSubmit: function( postdata, o ) {
        var s = postdata[ "your_field_name" ];
        var ret=[true, "", ""];
        postdata[ "your_field_name" ] = escape( s );
        return ret;
      }
    } );
    return false;
  }
} );
</pre>


		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8295421.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8295421.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 13 Feb 2009 02:20:36 +0800</pubDate>
</item>
<item>
	<title>Xming 的字太小?</title>
	<description><![CDATA[
			Xming 等同是 Windows 上的 X Server，使用的說明可以參考：Xming 簡易使用說明，圖文並茂，寫的非常好。

對我來說，唯一的問題是字太小，該怎麼解決？我找了好久～
最後終於意外發現，只要在 XLaunch 最後一個步驟的畫面的 "Additional parameters for Xming" 裡填上 -dpi 100，就可以解決字太小的問題。

		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="http://sourceforge.net/projects/xming/" title="Xming XServer for Windows">Xming</a> 等同是 Windows 上的 X Server，使用的說明可以參考：<a href="http://www.cs.nctu.edu.tw/help/xming.html">Xming 簡易使用說明</a>，圖文並茂，寫的非常好。<br />
<br />
對我來說，唯一的問題是字太小，該怎麼解決？我找了好久～<br />
最後終於意外發現，只要在 XLaunch 最後一個步驟的畫面的 "Additional parameters for Xming" 裡填上 -dpi 100，就可以解決字太小的問題。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8261345.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8261345.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 06 Feb 2009 16:40:44 +0800</pubDate>
</item>
<item>
	<title>vim auto completion</title>
	<description><![CDATA[
			在Linux Today看到這篇文章：Vi and Vim Editor: 5 Awesome Examples For Automatic Word Completion Using Ctrl-X Magic，看完的當下，非常的高興。
原本以為要安裝特定 plugin 才能達到的 auto completion 功能，居然早已內建，而且只需要在編輯時按下 ctrl+x ，再搭配下列按鍵即可：ctrl+p：向前找可以自動完成的字ctrl+n：向後找ctrl+i：找所有單行開頭的，特別適合寫程式，因為通常函數都會是先以單行宣告，根據同事實驗，這還會去找 header 裡的...ctrl+f：檔名的自動完成

能說什麼呢？只能說Vim太威了！


		]]>
	</description>
	<content:encoded><![CDATA[
			在<a href="http://linuxtoday.com">Linux Today</a>看到這篇文章：<a href="http://www.thegeekstuff.com/2009/01/vi-and-vim-editor-5-awesome-examples-for-automatic-word-completion-using-ctrl-x-magic/">Vi and Vim Editor: 5 Awesome Examples For Automatic Word Completion Using Ctrl-X Magic</a>，看完的當下，非常的高興。<br />
原本以為要安裝特定 plugin 才能達到的 auto completion 功能，居然早已內建，而且只需要在編輯時按下 ctrl+x ，再搭配下列按鍵即可：<ul><li>ctrl+p：向前找可以自動完成的字</li><li>ctrl+n：向後找</li><li>ctrl+i：找所有單行開頭的，特別適合寫程式，因為通常函數都會是先以單行宣告，根據同事實驗，這還會去找 header 裡的...</li><li>ctrl+f：檔名的自動完成</li></ul><br />
<br />
能說什麼呢？只能說<a href="http://www.vim.org">Vim</a>太威了！<br />
<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/8090287.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/8090287.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 13 Jan 2009 23:53:45 +0800</pubDate>
</item>
<item>
	<title>Convert vdi to vmdk using CloneZilla</title>
	<description><![CDATA[
			利用 qemu-img convert 要把 VirtualBox vdi 轉為 vmdk 時，似乎有 2G 的限制，轉出的 vmdk 檔案永遠只有 2G。
沒辦法，只好把腦筋動到 VirtualBox 上。

VirtualBox 可以掛載 vmdk，所以可以用 qemu-img 建立 vmdk 檔案，然後再用 Clonezilla 來進行磁碟複製的工作，雖然麻煩，但不失為一個好方法。

		]]>
	</description>
	<content:encoded><![CDATA[
			利用 qemu-img convert 要把 <a href="http://www.virtualbox.org/">VirtualBox</a> vdi 轉為 vmdk 時，似乎有 2G 的限制，轉出的 vmdk 檔案永遠只有 2G。<br />
沒辦法，只好把腦筋動到 <a href="http://www.virtualbox.org/">VirtualBox</a> 上。<br />
<br />
<a href="http://www.virtualbox.org/">VirtualBox</a> 可以掛載 vmdk，所以可以用 qemu-img 建立 vmdk 檔案，然後再用 <a href="http://drbl.nchc.org.tw/clonezilla/">Clonezilla</a> 來進行磁碟複製的工作，雖然麻煩，但不失為一個好方法。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7707439.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7707439.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 25 Nov 2008 17:40:35 +0800</pubDate>
</item>
<item>
	<title>svk mirror 錯誤</title>
	<description><![CDATA[
			如果你在 svk mirror 時，出現類似 "xxx is not a mirrored path." 或 "xxx 不是一個映射路徑。" 的錯誤時，請使用 svk propedit svm:mirror // 指令進行編輯，將有問題的路徑移除之後，就不會有問題了。

解法參考自：#6000: Renaming a mirror loses its source[svk-devel] misutilization

		]]>
	</description>
	<content:encoded><![CDATA[
			如果你在 svk mirror 時，出現類似 "xxx is not a mirrored path." 或 "xxx 不是一個映射路徑。" 的錯誤時，請使用 svk propedit svm:mirror // 指令進行編輯，將有問題的路徑移除之後，就不會有問題了。<br />
<br />
解法參考自：<ul><li><a href="http://of.openfoundry.org/rt/Ticket/Display.html?ShowHeaders=1;id=6000">#6000: Renaming a mirror loses its source</a></li><li><a href="http://lists.bestpractical.com/pipermail/svk-devel/2007-January/000503.html">[svk-devel] misutilization</a></li></ul><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7570645.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7570645.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 14 Nov 2008 15:00:20 +0800</pubDate>
</item>
<item>
	<title>python + opengl = pyopengl</title>
	<description><![CDATA[
			安裝：安裝Python，我用 2.5。安裝EasyInstall，這是類似 Perl CPAN、Ruby Gems的工具。等等會利用這個來安裝 PyOpenGL。打開命令提示字元，切換到 c:\python25\scripts，執行 easy_install pyopengl。最後，你還需要 GLUT：Nate Robins - OpenGL- GLUT for Win32，下載以後，丟到 c:\windows\system32 即可。

都好了以後，你就可以試試看下面這個小程式了：
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

def display():
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    glPushMatrix()
    #glTranslatef(0.,1.,-1.) #move to where we want to put object
    glBegin( GL_TRIANGLES )
    glColor3f( 1., 0., 0. )
    glVertex2d( -1., 0. )
    glColor3f( 0., 1., 0. )
    glVertex2d( 1.,0. )
    glColor3f( 0., 0., 1. )
    glVertex2d( 0., 1. )
    glEnd()
    glPopMatrix()
    glutSwapBuffers()
    return

glutInit( sys.argv )
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB |GLUT_DEPTH)
glutInitWindowSize(400,400)
glutCreateWindow("Hello, World")
glClearColor(0.,0.,0.,1.)
glutDisplayFunc(display)
glutMainLoop()


想試試的原因，最主要是想說，Python 可以比較方便地進行測試與練習，接觸以後，發現代碼也很容易轉換為 C/C++，就這樣。

參考資料：#148 (pyOpenGL egg needs to include glut32.dll.) - EPD Trac - TracPython short course


		]]>
	</description>
	<content:encoded><![CDATA[
			安裝：<ol><li>安裝<a href="http://www.python.org">Python</a>，我用 2.5。</li><li>安裝<a href="http://peak.telecommunity.com/DevCenter/EasyInstall">EasyInstall</a>，這是類似 <a href="http://www.perl.org">Perl</a> <a href="http://www.cpan.org">CPAN</a>、<a href="http://www.rubygems.org">Ruby Gems</a>的工具。等等會利用這個來安裝 <a href="http://pyopengl.sourceforge.net/">PyOpenGL</a>。</li><li>打開命令提示字元，切換到 c:\python25\scripts，執行 easy_install pyopengl。</li><li>最後，你還需要 GLUT：<a href="http://www.xmission.com/~nate/glut.html">Nate Robins - OpenGL- GLUT for Win32</a>，下載以後，丟到 c:\windows\system32 即可。</li></ol>

都好了以後，你就可以試試看下面這個小程式了：<pre name="code" class="python">
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

def display():
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    glPushMatrix()
    #glTranslatef(0.,1.,-1.) #move to where we want to put object
    glBegin( GL_TRIANGLES )
    glColor3f( 1., 0., 0. )
    glVertex2d( -1., 0. )
    glColor3f( 0., 1., 0. )
    glVertex2d( 1.,0. )
    glColor3f( 0., 0., 1. )
    glVertex2d( 0., 1. )
    glEnd()
    glPopMatrix()
    glutSwapBuffers()
    return

glutInit( sys.argv )
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB |GLUT_DEPTH)
glutInitWindowSize(400,400)
glutCreateWindow("Hello, World")
glClearColor(0.,0.,0.,1.)
glutDisplayFunc(display)
glutMainLoop()
</pre>

想試試的原因，最主要是想說，<a href="http://www.python.org">Python</a> 可以比較方便地進行測試與練習，接觸以後，發現代碼也很容易轉換為 C/C++，就這樣。<br/>

參考資料：<ul><li><a href="https://svn.enthought.com/epd/ticket/148">#148 (pyOpenGL egg needs to include glut32.dll.) - EPD Trac - Trac</a></li><li><a href="http://www.wag.caltech.edu/home/rpm/python_course/">Python short course</a></li></ul>


		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7520377.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7520377.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Thu, 06 Nov 2008 15:30:50 +0800</pubDate>
</item>
<item>
	<title>trinity.vim</title>
	<description><![CDATA[
			前兩天想說找找看 Vim 有沒有 GNU Global 的 plugin 時，看到了 trinity.vim。
這個 plugin 整合了三個 plugin：Source explorer, taglist, NERD tree 在 Vim 模擬出接近 Source Insight 的效果。
有用過 Source Insight 的人，相信都知道很難找到替代品，我前幾年也曾經試圖找過，但都一直沒找到。
這個 plugin 真的不錯，讓Vim更好用了～

有優點當然也有缺點：Source explorer 裡呼叫 ctags 的地方是寫死的，所以如果你的 ctags 放在別的地方，最好自行去搜索有呼叫到 ctags 的地方，加上路徑。把 Source explorer 打開的時候，速度會變慢，這是因為它試圖利用 ctags 資料庫去找跟游標所在位置有關的程式片段。我自己是比較少用，不能用對我影響不大。

		]]>
	</description>
	<content:encoded><![CDATA[
			前兩天想說找找看 <a href="http://www.vim.org">Vim</a> 有沒有 <a href="http://www.gnu.org/software/global/">GNU Global</a> 的 plugin 時，看到了 <a href="http://www.vim.org/scripts/script.php?script_id=2347">trinity.vim</a>。<br />
這個 plugin 整合了三個 plugin：<a href="http://www.vim.org/scripts/script.php?script_id=2179">Source explorer</a>, <a href="http://www.vim.org/scripts/script.php?script_id=273">taglist</a>, <a href="http://www.vim.org/scripts/script.php?script_id=1658">NERD tree</a> 在 <a href="http://www.vim.org">Vim</a> 模擬出接近 <a href="http://www.sourceinsight.com/">Source Insight</a> 的效果。<br />
有用過 <a href="http://www.sourceinsight.com/">Source Insight</a> 的人，相信都知道很難找到替代品，我前幾年也曾經試圖找過，但都一直沒找到。<br />
這個 plugin 真的不錯，讓<a href="http://www.vim.org">Vim</a>更好用了～<br />
<br />
有優點當然也有缺點：<ol><li><a href="http://www.vim.org/scripts/script.php?script_id=2179">Source explorer</a> 裡呼叫 ctags 的地方是寫死的，所以如果你的 ctags 放在別的地方，最好自行去搜索有呼叫到 ctags 的地方，加上路徑。</li><li>把 <a href="http://www.vim.org/scripts/script.php?script_id=2179">Source explorer</a> 打開的時候，速度會變慢，這是因為它試圖利用 ctags 資料庫去找跟游標所在位置有關的程式片段。我自己是比較少用，不能用對我影響不大。</li></ol><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7515251.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7515251.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 05 Nov 2008 16:38:59 +0800</pubDate>
</item>
<item>
	<title>以 bash script 為 sqlite database 產生 C/C++ struct</title>
	<description><![CDATA[
			最近寫的一個 bash script，用來幫你把 sqlite database 裡的 table schema 轉成 C/C++ struct。
這裡只處理 text 與 integer 型態，text 轉成 wstring/string，integer 則轉為 int。轉換的工具是使用 awk/sed。

只要稍稍改動一下，也適用在其他語言上。

#!/bin/bash
if test -z "$1"
then
	echo "You need to specify the database file name."
	exit -1
fi

db=$1
dbname=`basename $1 .db`
tables=`sqlite3 $db ".table"`
output="db_${dbname}_schema.h"

touch $output

cat >> $output > $output
	sqlite3 $db ".schema $table" | awk '/^\ /{printf("%s %s;",$2,$1);}' | sed -e 's/,/\ /g' | sed -e 's/text/db_string /g' | sed -e 's/integer/int /g' >> $output
	struct_name=`echo $table | awk -f cap.awk`
	echo "}$struct_name;" >> $output
	echo "" >> $output
done

cat >> $output 
		]]>
	</description>
	<content:encoded><![CDATA[
			最近寫的一個 bash script，用來幫你把 sqlite database 裡的 table schema 轉成 C/C++ struct。<br/>
這裡只處理 text 與 integer 型態，text 轉成 wstring/string，integer 則轉為 int。轉換的工具是使用 awk/sed。<br/>
<br/>
只要稍稍改動一下，也適用在其他語言上。<br/>

<pre name="code" class="bash">#!/bin/bash
if test -z "$1"
then
	echo "You need to specify the database file name."
	exit -1
fi

db=$1
dbname=`basename $1 .db`
tables=`sqlite3 $db ".table"`
output="db_${dbname}_schema.h"

touch $output

cat >> $output << EOF
#ifndef __db_${dbname}_schema_h__
#define __db_${dbname}_schema_h__

#include &lt;string&gt;

#ifdef _UNICODE
typedef std::wstring db_string;
#else
typedef std::string db_string;
#endif

EOF

for table in $tables
do
	echo "typedef struct {" >> $output
	sqlite3 $db ".schema $table" | awk '/^\ /{printf("%s %s;",$2,$1);}' | sed -e 's/,/\ /g' | sed -e 's/text/db_string /g' | sed -e 's/integer/int /g' >> $output
	struct_name=`echo $table | awk -f cap.awk`
	echo "}$struct_name;" >> $output
	echo "" >> $output
done

cat >> $output << EOF
#endif
EOF

# call "astyle" to format the code.  Beside "astyle", you can use "indent".
astyle $output

exit 0
</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7413717.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7413717.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 21 Oct 2008 14:52:24 +0800</pubDate>
</item>
<item>
	<title>Project.vim</title>
	<description><![CDATA[
			同事最近拋棄了 Source Insight 3，開始用 Vim 寫 code，所以有人跟我一起研究了。
他最近介紹我一個 plugin : project - Organize/Navigate projects of files (like IDE/buffer explorer)，看起來不錯用，他可以把某個目錄下所有檔案都建立為專案檔，讓你可以快速瀏覽所有檔案，不過美中不足的是他沒有把 CVS、.svn、_svn 等目錄過濾掉，我在 VimDirListing 函數裡添加了兩行把這些目錄過濾掉。
這是原來的樣子：
    if isdirectory(glob(fname))
        let {a:dirvariable}={a:dirvariable}.a:padding.fname.a:separator
        let {a:dircount}={a:dircount} + 1
    else
    " other stuff


改過以後：
    if isdirectory(glob(fname))
        if fname != 'CVS' && fname != '.svn' && fname != '_svn'
            let {a:dirvariable}={a:dirvariable}.a:padding.fname.a:separator
            let {a:dircount}={a:dircount} + 1
        endif
    else


如果你懶得看英文的話，對岸的朋友翻譯了該 plugin 的文檔：VIM-Project Plugin - I Know you Know - C++博客

		]]>
	</description>
	<content:encoded><![CDATA[
			同事最近拋棄了 Source Insight 3，開始用 <a href="http://www.vim.org">Vim</a> 寫 code，所以有人跟我一起研究了。<br/>
他最近介紹我一個 plugin : <a href="http://www.vim.org/scripts/script.php?script_id=69">project - Organize/Navigate projects of files (like IDE/buffer explorer)</a>，看起來不錯用，他可以把某個目錄下所有檔案都建立為專案檔，讓你可以快速瀏覽所有檔案，不過美中不足的是他沒有把 CVS、.svn、_svn 等目錄過濾掉，我在 VimDirListing 函數裡添加了兩行把這些目錄過濾掉。<br/>
這是原來的樣子：<pre>
    if isdirectory(glob(fname))
        let {a:dirvariable}={a:dirvariable}.a:padding.fname.a:separator
        let {a:dircount}={a:dircount} + 1
    else
    " other stuff
</pre>

改過以後：<pre>
    if isdirectory(glob(fname))
        if fname != 'CVS' && fname != '.svn' && fname != '_svn'
            let {a:dirvariable}={a:dirvariable}.a:padding.fname.a:separator
            let {a:dircount}={a:dircount} + 1
        endif
    else
</pre>

如果你懶得看英文的話，對岸的朋友翻譯了該 plugin 的文檔：<a href="http://www.cppblog.com/DrMagic/archive/2007/11/19/36964.html">VIM-Project Plugin - I Know you Know - C++博客</a>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7374995.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7374995.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 14 Oct 2008 16:33:15 +0800</pubDate>
</item>
<item>
	<title>Ubiquity command - findbook(更新)</title>
	<description><![CDATA[
			上一版沒有對 uri 作 encoding，所以找中文時會出錯，現在補上，只要呼叫 Ubiquity 內建的 encodeURIComponent() 就行了...


CmdUtils.CreateCommand({
  name: "findbook",
  contributors: ["elleryq"],
  license: "MPL",
  description: "讓買書變成更簡單的決定！",
  takes: {"書名關鍵字": noun_arb_text},
  icon: "http://findbook.tw/favicon.ico",
  execute: function(directObject) {
    Utils.openUrlInBrowser( "http://findbook.tw/search?keyword_type=keyword&q=" + encodeURIComponent(directObject.text) );
  }
});


		]]>
	</description>
	<content:encoded><![CDATA[
			上一版沒有對 uri 作 encoding，所以找中文時會出錯，現在補上，只要呼叫 Ubiquity 內建的 encodeURIComponent() 就行了...

<pre name="code" class="javascript">
CmdUtils.CreateCommand({
  name: "findbook",
  contributors: ["elleryq"],
  license: "MPL",
  description: "讓買書變成更簡單的決定！",
  takes: {"書名關鍵字": noun_arb_text},
  icon: "http://findbook.tw/favicon.ico",
  execute: function(directObject) {
    Utils.openUrlInBrowser( "http://findbook.tw/search?keyword_type=keyword&q=" + encodeURIComponent(directObject.text) );
  }
});
</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7237339.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7237339.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 24 Sep 2008 14:47:54 +0800</pubDate>
</item>
<item>
	<title>Ubiquity command - findbook</title>
	<description><![CDATA[
			Ubiquity已經很多人介紹了，這裡是分享一個 commands，如果你有用 Findbook 的話，可以用用看...
安裝 command 方法很簡單，打開 Ubiquity Command Editor 後，把下面的程式碼貼上去即可：
CmdUtils.CreateCommand({
  name: "findbook",
  author: { name: "elleryq"},
  contributors: ["elleryq"],
  license: "MPL",
  description: "讓買書變成更簡單的決定！",
  takes: {"書名關鍵字": noun_arb_text},
  icon: "http://findbook.tw/favicon.ico",
  execute: function(directObject) {
    Utils.openUrlInBrowser( "http://findbook.tw/search?keyword_type=keyword&q=" + directObject.text );
  }
});


		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="http://labs.mozilla.com/2008/08/introducing-ubiquity/">Ubiquity</a>已經很多人介紹了，這裡是分享一個 commands，如果你有用 <a href="http://findbook.tw">Findbook</a> 的話，可以用用看...
安裝 command 方法很簡單，打開 <a href="chrome://ubiquity/content/editor.html">Ubiquity Command Editor</a> 後，把下面的程式碼貼上去即可：
<pre name="code" class="javascript">CmdUtils.CreateCommand({
  name: "findbook",
  author: { name: "elleryq"},
  contributors: ["elleryq"],
  license: "MPL",
  description: "讓買書變成更簡單的決定！",
  takes: {"書名關鍵字": noun_arb_text},
  icon: "http://findbook.tw/favicon.ico",
  execute: function(directObject) {
    Utils.openUrlInBrowser( "http://findbook.tw/search?keyword_type=keyword&q=" + directObject.text );
  }
});
</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7048255.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7048255.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 29 Aug 2008 10:54:20 +0800</pubDate>
</item>
<item>
	<title>Banshee 的 PlayQueue</title>
	<description><![CDATA[
			1.0 版以後多了一個新功能-PlayQueue，我很喜歡這功能，因為你可以一直把想聽的歌丟進去，Banshee會播放這個Queue裡的歌直到Queue沒有歌為止。
本來以為這是內建的功能，後來看了之後，才發現這是一個 Extension。
它主要繼承 PlaylistSource、IBasicPlaybackController，把自己實作成一個 Playlist 來源，在Banshee播放時，實際上來源已經不是原來的 Music library 了。

所以如果要取得這個 Source，應該是利用 ServiceManager.SourceManager 來取得，要加入 PlayQueue 的話，則是使用 AddSelectedTracks()。
目前我還沒研究出如何在 Extension 裡面呼叫其他 Extension 的方法...

		]]>
	</description>
	<content:encoded><![CDATA[
			1.0 版以後多了一個新功能-PlayQueue，我很喜歡這功能，因為你可以一直把想聽的歌丟進去，<a href="http://banshee-project.org/">Banshee</a>會播放這個Queue裡的歌直到Queue沒有歌為止。<br />
本來以為這是內建的功能，後來看了之後，才發現這是一個 Extension。<br />
它主要繼承 PlaylistSource、IBasicPlaybackController，把自己實作成一個 Playlist 來源，在<a href="http://banshee-project.org/">Banshee</a>播放時，實際上來源已經不是原來的 Music library 了。<br />
<br />
所以如果要取得這個 Source，應該是利用 ServiceManager.SourceManager 來取得，要加入 PlayQueue 的話，則是使用 AddSelectedTracks()。<br />
目前我還沒研究出如何在 Extension 裡面<strong>呼叫</strong>其他 Extension 的方法...<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6544067.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6544067.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 23 Jul 2008 08:42:57 +0800</pubDate>
</item>
<item>
	<title>.NET framework essential Chapter 5</title>
	<description><![CDATA[
			這一章主要講 ADO.Net。
DataSet、DataTable、DataRow、DataRelation... 這一組類別完全是一個抽離實體層的類別，所以有 DataAdapter 這一組與 Connection、Command、DataReader ...等類別溝通。

GetChildRows[] 可以依據 Relationship 來取得子Table與父Table相關的資料列。一個 DataAdapter 基本上對應一個 DataTable，但他不管所在的 DataSet，所以你可以都塞到同一個 DataSet 裡面去。另外 DataAdapter 不處理 Relationship，所以用 Fill 取得資料並放到 DataSet 裡的 DataTable 之後，得自己加上 Relationship。由於 DataSet 與 XML 有一定的關係，第五章最後簡單地介紹了 XML 的相關函數。

		]]>
	</description>
	<content:encoded><![CDATA[
			這一章主要講 ADO.Net。<br />
DataSet、DataTable、DataRow、DataRelation... 這一組類別完全是一個抽離實體層的類別，所以有 DataAdapter 這一組與 Connection、Command、DataReader ...等類別溝通。<br />
<br />
<ul><li>GetChildRows[] 可以依據 Relationship 來取得子Table與父Table相關的資料列。</li><li>一個 DataAdapter 基本上對應一個 DataTable，但他不管所在的 DataSet，所以你可以都塞到同一個 DataSet 裡面去。另外 DataAdapter 不處理 Relationship，所以用 Fill 取得資料並放到 DataSet 裡的 DataTable 之後，得自己加上 Relationship。</li><li>由於 DataSet 與 XML 有一定的關係，第五章最後簡單地介紹了 XML 的相關函數。</li></ul><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6536721.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6536721.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Mon, 21 Jul 2008 13:16:58 +0800</pubDate>
</item>
<item>
	<title>foxyproxy 自動組態指令碼的小問題</title>
	<description><![CDATA[
			因為有在用 foxyproxy 的關係，昨天遇到一個問題，就是 foxyproxy 突然無法解析 pac 檔案了。Log 裡面有這樣的訊息：TypeError: invalid 'in' operand this._sandBox

我試了好久，也找了好久，最後找到官方這篇討論串：PAC support，討論串裡面，作者很熱心想要解決，可是在他那邊複製不出這個問題，所以後面他就乾脆說，有遇到問題的，可以寫信跟他要測試版的 foxyproxy 試試看～

我實在是懶得寫信去要，所以就繼續試，結果無意中被我試出一個 workaround，於是趕緊貼上討論串給其他人參考。
今天去看的時候，發現有人說我的 workaround 有效～蠻令人高興的。

我的 workaround 就是，先把 foxyproxy 關閉，接著重新去把你的樣式設定為"使用自動組態指令碼"，然後關閉。接著再切換你剛剛設置的樣式，就行了。
如果沒有先把 foxyproxy 關閉的話，在關閉的時候會出現錯誤訊息。

		]]>
	</description>
	<content:encoded><![CDATA[
			因為有在用 <a href="https://addons.mozilla.org/zh-TW/firefox/addon/2464">foxyproxy</a> 的關係，昨天遇到一個問題，就是 <a href="https://addons.mozilla.org/zh-TW/firefox/addon/2464">foxyproxy</a> 突然無法解析 pac 檔案了。Log 裡面有這樣的訊息：<blockquote>TypeError: invalid 'in' operand this._sandBox</blockquote><br />
<br />
我試了好久，也找了好久，最後找到官方這篇討論串：<a href="http://foxyproxy.mozdev.org/drupal/content/pac-support">PAC support</a>，討論串裡面，作者很熱心想要解決，可是在他那邊複製不出這個問題，所以後面他就乾脆說，有遇到問題的，可以寫信跟他要測試版的 <a href="https://addons.mozilla.org/zh-TW/firefox/addon/2464">foxyproxy</a> 試試看～<br />
<br />
我實在是懶得寫信去要，所以就繼續試，結果無意中被我試出一個 workaround，於是趕緊貼上討論串給其他人參考。<br />
今天去看的時候，發現有人說我的 workaround 有效～蠻令人高興的。<br />
<br />
我的 workaround 就是，先把 <a href="https://addons.mozilla.org/zh-TW/firefox/addon/2464">foxyproxy</a> 關閉，接著重新去把你的樣式設定為"使用自動組態指令碼"，然後關閉。接著再切換你剛剛設置的樣式，就行了。<br />
如果沒有先把 <a href="https://addons.mozilla.org/zh-TW/firefox/addon/2464">foxyproxy</a> 關閉的話，在關閉的時候會出現錯誤訊息。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6443363.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6443363.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 09 Jul 2008 17:41:04 +0800</pubDate>
</item>
<item>
	<title>在 .reg 表明要移除 key</title>
	<description><![CDATA[
			謝謝你，Rob van der Woude！

原來在 .reg 裡面也可以表明要移除某個 key。
參考Rob van der Woude的這篇文章：Batch files - Use REGEDIT to add, read or delete registry values，只要這樣寫就行了：;表明移除整個 DummyTree [-HKEY_CURRENT_USER\DummyTree];表明移除指定項目[HKEY_CURRENT_USER\DummyTree]"ValueToBeRemoved"=-
文章裡面還有許多其他關於 registry 的技巧喔～

		]]>
	</description>
	<content:encoded><![CDATA[
			謝謝你，<a href="http://www.robvanderwoude.com">Rob van der Woude</a>！<br />
<br />
原來在 .reg 裡面也可以表明要移除某個 key。<br />
參考<a href="http://www.robvanderwoude.com">Rob van der Woude</a>的這篇文章：<a href="http://www.robvanderwoude.com/regedit.html">Batch files - Use REGEDIT to add, read or delete registry values</a>，只要這樣寫就行了：<pre>;表明移除整個 DummyTree <br/>[-HKEY_CURRENT_USER\DummyTree]<br/>;表明移除指定項目<br/>[HKEY_CURRENT_USER\DummyTree]<br/>"ValueToBeRemoved"=-</pre><br />
<a href="http://www.robvanderwoude.com/regedit.html" title="Batch files - Use REGEDIT to add, read or delete registry values">文章</a>裡面還有許多其他關於 registry 的技巧喔～<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5835589.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5835589.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 09 Apr 2008 15:16:07 +0800</pubDate>
</item>
<item>
	<title>以 public key 進行 SSH 登入</title>
	<description><![CDATA[
			首先，謝謝你！HowToForge。

環境：以下都是從電腦 A 要登入到 Server B (Linux)

步驟：先為電腦A產生Private/Public keyLinux: 用 ssh-keygenWindows: 用 puttygen.exe把產生好的 Public key (用 ssh-keygen 的話，通常是 id_dsa.pub﹔用 puttygen.exe 的話，它就在上面的方塊裡。)附加到 Server B 登入帳號的 .ssh 目錄下的 authorized_keys2 裡面，如果沒有 authorized_keys 就自己建一個！舉例來說，如果你帳號是 xyz，那麼就是 $HOME/.ssh/authorized_keys 。收工。

參考資料：How To Set Up SSH With Public-Key Authentication On Debian Etch | HowtoForge - Linux Howtos and Tutorials

		]]>
	</description>
	<content:encoded><![CDATA[
			首先，謝謝你！<a href="http://www.howtoforge.com">HowToForge</a>。<br />
<br />
環境：以下都是從電腦 A 要登入到 Server B (Linux)<br />
<br />
步驟：<ol><li>先為電腦A產生Private/Public key<ul><li>Linux: 用 ssh-keygen</li><li>Windows: 用 <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">puttygen.exe</a></li></ul></li><li>把產生好的 Public key (用 ssh-keygen 的話，通常是 id_dsa.pub﹔用 puttygen.exe 的話，它就在上面的方塊裡。)附加到 Server B 登入帳號的 .ssh 目錄下的 authorized_keys2 裡面，如果沒有 authorized_keys 就自己建一個！舉例來說，如果你帳號是 xyz，那麼就是 $HOME/.ssh/authorized_keys 。</li><li>收工。</li></ol><br />
<br />
參考資料：<a href="http://www.howtoforge.com/set-up-ssh-with-public-key-authentication-debian-etch">How To Set Up SSH With Public-Key Authentication On Debian Etch | HowtoForge - Linux Howtos and Tutorials</a><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5795979.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5795979.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 02 Apr 2008 13:42:02 +0800</pubDate>
</item>
<item>
	<title>Banshee hack</title>
	<description><![CDATA[
			從 src/Core/Banshee/Services/Banshee.Database/BansheeDbFormatMigrator.cs 的InitializeFreshDatabase()裡面可以看到 Banshee 建立了這些 table：CoreConfigurationCoreTracksCoreArtistsCoreAlbumsCorePlaylistsCorePlaylistEntriesCoreSmartPlaylistsCoreSmartPlaylistEntriesCoreRemovedTracksCoreTracksCacheCoreCache
並且針對各個 Table 建立了必要的 Index (好吧，我的疑慮解除了，其實 Banshee 有幫建檔的音樂作索引，那還要繼續看下去嗎?)

BansheeDbFormatMigrator.cs 裡面還可以看到以 Migrate_ 開頭的函式前面有 [DatabaseVersion] 這個 Attribute，這些函式是用來作 Migrate(升級)的函式，Banshee 會先檢查 CoreConfiguration table 的 DatabaseVersion 欄位，看目前 Database 是什麼版本，然後再決定要怎麼去作升級(這部份可以參考 Migrate(), InnerMigrate())。

存取資料庫的部份被包在 src/Core/Banshee.Services/Banshee.Collection.Database下的各個以 AlbumInfo 結尾的檔案裡面，裡面都大同小異，provider 成員為主要的提供者，這裡會傳入 ServiceManager.DbConnection 讓 BansheeModelProvider 的 instance 能根據此 connection 去存取資料庫。
所有的 connection 都是由 ServiceManager.DbConnection (src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs) 而來，而 DbConnection 其實只是一個服務 (src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs)，在 ServiceManager 被初始化(static ServiceManager())的時候被註冊進去。

BansheeDbConnection 繼承自 HyenaSqliteConnection (src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs)，從 HyenaSqliteConnection.cs 看起來似乎是為了要把存取資料庫這整個部份獨立為 Thread 以提昇 UI 效率，所以才另外作 Hyena.Data.Sqlite。
不過最終底層還是 Sqlite 3。

Banshee 的 Main() 在 Client 類別 (src/Client/Nereid/Nereid/Client.cs)，Client 繼承自 GtkBaseClient (src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs)，扣掉註解不到 30 行...

補充1：HACKING Guide
補充2：我看的 code 是目前最新的版本，後來看過 0.13 的資料庫，發現的確沒有建 Index。

		]]>
	</description>
	<content:encoded><![CDATA[
			從 src/Core/Banshee/Services/Banshee.Database/BansheeDbFormatMigrator.cs 的InitializeFreshDatabase()裡面可以看到 Banshee 建立了這些 table：<ul><li>CoreConfiguration</li><li>CoreTracks</li><li>CoreArtists</li><li>CoreAlbums</li><li>CorePlaylists</li><li>CorePlaylistEntries</li><li>CoreSmartPlaylists</li><li>CoreSmartPlaylistEntries</li><li>CoreRemovedTracks</li><li>CoreTracksCache</li><li>CoreCache</li></ul><br />
並且針對各個 Table 建立了必要的 Index (好吧，我的疑慮解除了，其實 <a href="http://www.banshee-project.org">Banshee</a> 有幫建檔的音樂作索引，那還要繼續看下去嗎?)<br />
<br />
BansheeDbFormatMigrator.cs 裡面還可以看到以 Migrate_ 開頭的函式前面有 [DatabaseVersion] 這個 Attribute，這些函式是用來作 Migrate(升級)的函式，Banshee 會先檢查 CoreConfiguration table 的 DatabaseVersion 欄位，看目前 Database 是什麼版本，然後再決定要怎麼去作升級(這部份可以參考 Migrate(), InnerMigrate())。<br />
<br />
存取資料庫的部份被包在 src/Core/Banshee.Services/Banshee.Collection.Database下的各個以 AlbumInfo 結尾的檔案裡面，裡面都大同小異，provider 成員為主要的提供者，這裡會傳入 ServiceManager.DbConnection 讓 BansheeModelProvider 的 instance 能根據此 connection 去存取資料庫。<br />
所有的 connection 都是由 ServiceManager.DbConnection (src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs) 而來，而 DbConnection 其實只是一個服務 (src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs)，在 ServiceManager 被初始化(static ServiceManager())的時候被註冊進去。<br />
<br />
BansheeDbConnection 繼承自 HyenaSqliteConnection (src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs)，從 HyenaSqliteConnection.cs 看起來似乎是為了要把存取資料庫這整個部份獨立為 Thread 以提昇 UI 效率，所以才另外作 Hyena.Data.Sqlite。<br />
不過最終底層還是 <a href="http://www.sqlite.org/">Sqlite 3</a>。<br />
<br />
<a href="http://www.banshee-project.org">Banshee</a> 的 Main() 在 Client 類別 (src/Client/Nereid/Nereid/Client.cs)，Client 繼承自 GtkBaseClient (src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs)，扣掉註解不到 30 行...<br />
<br />
補充1：<a href="http://svn.gnome.org/viewvc/banshee/trunk/banshee/HACKING?view=markup">HACKING Guide</a><br />
補充2：我看的 code 是目前最新的版本，後來看過 0.13 的資料庫，發現的確沒有建 Index。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5732279.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5732279.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 21 Mar 2008 10:36:50 +0800</pubDate>
</item>
<item>
	<title>我的第一個 Greasemonkey user script - ClickNextPage</title>
	<description><![CDATA[
			為了看線上漫畫方便而寫的，本來是要滑鼠按上一頁、下一頁，現在只要按下'x'或'c'就可以到上一頁或下一頁，目前只能使用於九啦啦動漫～
原理不難，就只是請 Greasemonkey 在頁面載入時，幫忙掛上寫好的 userscript，而這個 userscript 也只是去處理 keyup 事件而已。

從看Dive Into Greasemonkey入門到完成，大概花了一個小時多一點的時間，應該算慢的吧～
我估計如果對 Javascript DOM 熟的人，應該可以比我更快寫好，我對 Javascript DOM 並不是那麼熟悉，而且，我已經被 jQuery 給馴化了...唉～沒辦法，jQuery 實在是好用又好查啊～

完成的作品在這裡，如果你有裝Greasemonkey的話，點選連結以後，就會有對話框問你是否要安裝了～

		]]>
	</description>
	<content:encoded><![CDATA[
			為了看線上漫畫方便而寫的，本來是要滑鼠按上一頁、下一頁，現在只要按下'x'或'c'就可以到上一頁或下一頁，目前只能使用於<a href="http://www.9lala.com/">九啦啦動漫</a>～<br />
原理不難，就只是請 <a href="https://addons.mozilla.org/en-US/firefox/addon/748">Greasemonkey</a> 在頁面載入時，幫忙掛上寫好的 userscript，而這個 userscript 也只是去處理 keyup 事件而已。<br />
<br />
從看<a href="http://diveintogreasemonkey.org/">Dive Into Greasemonkey</a>入門到完成，大概花了一個小時多一點的時間，應該算慢的吧～<br />
我估計如果對 Javascript DOM 熟的人，應該可以比我更快寫好，我對 Javascript DOM 並不是那麼熟悉，而且，我已經被 <a href="http://www.jquery.com">jQuery</a> 給馴化了...唉～沒辦法，<a href="http://www.jquery.com">jQuery</a> 實在是好用又好查啊～<br />
<br />
完成的作品在<a href="http://elleryq.googlepages.com/clicknextpage.user.js">這裡</a>，如果你有裝<a href="https://addons.mozilla.org/en-US/firefox/addon/748">Greasemonkey</a>的話，點選<a href="http://elleryq.googlepages.com/clicknextpage.user.js">連結</a>以後，就會有對話框問你是否要安裝了～<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5728249.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5728249.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Thu, 20 Mar 2008 14:43:25 +0800</pubDate>
</item>
<item>
	<title>VisualSVN Server</title>
	<description><![CDATA[
			想到可以來介紹一下這個：VisualSVN Server。
讓我想想～記得應該是去年年底的時候，不知在哪兒逛到的～
原本以為會不會跟VisualSVN一樣，是個商業化的產品，後來看過以後，才知道並不是。

言歸正傳，VisualSVN Server骨子裡其實就是Apache HTTP Server+Subversion，另外再加上VisualSVN製作的一個簡單管理介面。
如果你覺得自己手動安裝 Apache HTTP Server+Subversion很麻煩而你剛好又不想用 Linux 的話，不妨試試看這個，我自己試過了，如果你沒有要綁什麼特別的認證機制(如 SSPI)的話，這個軟體可說是相當地方便。

p.s. VisualSVN是一個給 Visual Studio 用的 plugin，讓 Visual Studio 也能直接以Subversion來作代碼管理。

		]]>
	</description>
	<content:encoded><![CDATA[
			想到可以來介紹一下這個：<a href="http://www.visualsvn.com/server/">VisualSVN Server</a>。<br />
讓我想想～記得應該是去年年底的時候，不知在哪兒逛到的～<br />
原本以為會不會跟<a href="http://www.visualsvn.com/" title="VisualSVN - Subversion plugin for Visual Studio">VisualSVN</a>一樣，是個商業化的產品，後來看過以後，才知道並不是。<br />
<br />
言歸正傳，<a href="http://www.visualsvn.com/server/">VisualSVN Server</a>骨子裡其實就是<a href="http://httpd.apache.org/">Apache HTTP Server</a>+<a href="http://subversion.tigris.org/">Subversion</a>，另外再加上<a href="http://www.visualsvn.com/" title="VisualSVN - Subversion plugin for Visual Studio">VisualSVN</a>製作的一個簡單管理介面。<br />
如果你覺得自己手動安裝 <a href="http://httpd.apache.org/">Apache HTTP Server</a>+<a href="http://subversion.tigris.org/">Subversion</a>很麻煩而你剛好又不想用 Linux 的話，不妨試試看這個，我自己試過了，如果你沒有要綁什麼特別的認證機制(如 SSPI)的話，這個軟體可說是相當地方便。<br />
<br />
p.s. <a href="http://www.visualsvn.com/" title="VisualSVN - Subversion plugin for Visual Studio">VisualSVN</a>是一個給 Visual Studio 用的 plugin，讓 Visual Studio 也能直接以<a href="http://subversion.tigris.org/">Subversion</a>來作代碼管理。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5716755.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5716755.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 18 Mar 2008 13:55:14 +0800</pubDate>
</item>
<item>
	<title>[軟體]Text to VBString</title>
	<description><![CDATA[
			最近都在寫 ASP/HTML/Javascript，今天剛好在訂閱的 MSDN Feeds 裡面看到 Joe Stagner的這篇文章：Utility to Convert Text / HTML to a Visual Basic String
內容是介紹Text to VB String這工具，這下可以省掉不少把 html 轉成 vb string 的功夫了~

p.s. 這個光頭的照片我經常看到，由此可推斷，這傢伙在網路上相當活躍，應該是個牛人。

		]]>
	</description>
	<content:encoded><![CDATA[
			最近都在寫 ASP/HTML/Javascript，今天剛好在訂閱的 MSDN Feeds 裡面看到 <a href="http://blog.msdn.com/joestagner/">Joe Stagner</a>的這篇文章：<a href="http://blogs.msdn.com/joestagner/archive/2008/03/13/utility-to-convert-text-html-to-a-visual-basic-string.aspx">Utility to Convert Text / HTML to a Visual Basic String</a><br />
內容是介紹<a href="http://www.softpedia.com/progDownload/Text-to-VB-String-Download-29794.html" title="Text to VB String Download - Softpedia">Text to VB String</a>這工具，這下可以省掉不少把 html 轉成 vb string 的功夫了~<br />
<br />
p.s. 這個光頭的照片我經常看到，由此可推斷，這傢伙在網路上相當活躍，應該是個牛人。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5695179.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5695179.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Fri, 14 Mar 2008 10:17:25 +0800</pubDate>
</item>
<item>
	<title>如何在指令列改變 Registry key 的權限</title>
	<description><![CDATA[
			首先要謝謝你，Wikipedia 上的 Windows Registry 條目。

裡面提到了微軟其實有釋出一個工具：SubInACL.exe
用這個，就可以改變某個 Key 的權限。

這一行就是讓自己可以得到 HKEY_LOCAL_MACHINE\software 這個 key的完全控制權：subinacl /keyreg HKEY_LOCAL_MACHINE\software /grant=%USERNAME%=F
但是這邊要注意， /key 只針對該 key，在之下的 subkey，你仍然沒有完全控制權，如果你要得到 subkey 的完整控制權，你應該改用：subinacl /subkeyreg HKEY_LOCAL_MACHINE\software /grant=%USERNAME%=F

p.s. 如果你需要刪除某個指定 key，可以參考這篇文章：Delete OE Identity from HKCU\Identities using WSH Script。

		]]>
	</description>
	<content:encoded><![CDATA[
			首先要謝謝你，<a href="http://en.wikipedia.org/wiki/Windows_Registry">Wikipedia 上的 Windows Registry 條目</a>。<br />
<br />
裡面提到了<a href="http://www.microsoft.com">微軟</a>其實有釋出一個工具：<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e8ba3e56-d8fe-4a91-93cf-ed6985e3927b&amp;DisplayLang=en">SubInACL.exe</a><br />
用這個，就可以改變某個 Key 的權限。<br />
<br />
這一行就是讓自己可以得到 HKEY_LOCAL_MACHINE\software 這個 key的完全控制權：<pre>subinacl /keyreg HKEY_LOCAL_MACHINE\software /grant=%USERNAME%=F</pre><br />
但是這邊要注意， /key 只針對該 key，在之下的 subkey，你仍然沒有完全控制權，如果你要得到 subkey 的完整控制權，你應該改用：<pre>subinacl /subkeyreg HKEY_LOCAL_MACHINE\software /grant=%USERNAME%=F</pre><br />
<br />
p.s. 如果你需要刪除某個指定 key，可以參考這篇文章：<a href="http://www.pcreview.co.uk/forums/thread-1713621.php">Delete OE Identity from HKCU\Identities using WSH Script</a>。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5674483.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5674483.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Mon, 10 Mar 2008 16:15:16 +0800</pubDate>
</item>
<item>
	<title>jquery.ingrid</title>
	<description><![CDATA[
			最近使用了jquery.ingrid這個jQuery的插件，這裡分享幾點心得：
官方文件提供的資訊極有限，所以原始碼沒事最好要看一下。Client 端的 html 只要在 &lt;table&gt; 裡面放 &lt;thead&gt;, &lt;thead&gt;, &lt;th&gt; 即可，不需要放別的。另外最好用一個 &lt;div&gt; 包起來，這樣可以比較方便於作 requery，因為在呼叫 ingrid() 之後，DOM 會作必要的改變，因此原來你使用 selector 指定到的 element，可能就再也找不到了。使用 &lt;div&gt; 包起來的好處是，可以藉由 html() 重新指定 &lt;div&gt; 的內容。這樣就能再次使用 selector 找到要改變的 table。Server 端需要處理 page, sort, dir 三個參數，這是由 Client 端的 ingrid() javascript 送出的，此外，如果 dataType 是 HTML (預設也是) 的話，只要輸出 &lt;table&gt;、&lt;tbody&gt;與&lt;td&gt;即可。如果你還需要指定其他的參數，可以藉由複寫 extraParams 來達到你的目的：var options={
  url: 'remote.html',
  extraParams: {param1: 'param1', param2: 'param2' }
};
$("#grid").ingrid( options ); 
記得要指定 colWidths，有幾個 column，就要指定幾個，這是官方文件沒提及的部份。如果不指定，會很殘忍的給你錯誤。$("#grid").ingrid( {
  // other stuff...
  colWidths: [ 225,225,225,225 ],
  // other stuff...
}); 


此外它還有排序、調整欄寬...等等的功能，整體來說，是個相當不錯的插件。

		]]>
	</description>
	<content:encoded><![CDATA[
			最近使用了<a href="http://reconstrukt.com/ingrid/">jquery.ingrid</a>這個<a href="http://www.jquery.com">jQuery</a>的插件，這裡分享幾點心得：
<ul><li><a href="http://reconstrukt.com/ingrid/">官方文件</a>提供的資訊極有限，所以原始碼沒事最好要看一下。</li><li>Client 端的 html 只要在 &lt;table&gt; 裡面放 &lt;thead&gt;, &lt;thead&gt;, &lt;th&gt; 即可，不需要放別的。另外最好用一個 &lt;div&gt; 包起來，這樣可以比較方便於作 requery，因為在呼叫 ingrid() 之後，DOM 會作必要的改變，因此原來你使用 selector 指定到的 element，可能就再也找不到了。使用 &lt;div&gt; 包起來的好處是，可以藉由 html() 重新指定 &lt;div&gt; 的內容。這樣就能再次使用 selector 找到要改變的 table。</li><li>Server 端需要處理 page, sort, dir 三個參數，這是由 Client 端的 ingrid() javascript 送出的，此外，如果 dataType 是 HTML (預設也是) 的話，只要輸出 &lt;table&gt;、&lt;tbody&gt;與&lt;td&gt;即可。如果你還需要指定其他的參數，可以藉由複寫 extraParams 來達到你的目的：<pre name="code" class="javascript">var options={
  url: 'remote.html',
  extraParams: {param1: 'param1', param2: 'param2' }
};
$("#grid").ingrid( options ); 
</pre><li>記得要指定 colWidths，有幾個 column，就要指定幾個，這是官方文件沒提及的部份。如果不指定，會很殘忍的給你錯誤。<pre name="code" class="javascript">$("#grid").ingrid( {
  // other stuff...
  colWidths: [ 225,225,225,225 ],
  // other stuff...
}); 
</pre></li></ul>

此外它還有排序、調整欄寬...等等的功能，整體來說，是個相當不錯的插件。

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5628631.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5628631.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Mon, 03 Mar 2008 17:39:04 +0800</pubDate>
</item>
<item>
	<title>適合程式設計師用的字型</title>
	<description><![CDATA[
			陸陸續續在網路上看到很多文章介紹，不過並沒有列出所有不錯的字型，這兒列出來的是目前我有試過而且感覺不錯的，同時直接提供下載連結：
Consolas，下載位址：Consolas Font Pack for Microsoft Visual Studio 2005Inconsolata，下載位址在此Andale Mono，下載位址：andale32.exe(from sourceforge.net)

其他參考：Choosing the Best Font for your Delphi / Pascal Code

		]]>
	</description>
	<content:encoded><![CDATA[
			陸陸續續在網路上看到<a href="http://www.google.com.tw/search?q=programmer+fonts&ie=utf-8&oe=utf-8&aq=t">很多文章介紹</a>，不過並沒有列出所有不錯的字型，這兒列出來的是目前我有試過而且感覺不錯的，同時直接提供下載連結：<br />
<ul><li><a href="http://zh.wikipedia.org/wiki/Consolas">Consolas</a>，下載位址：<a href="http://www.microsoft.com/downloads/details.aspx?familyid=22e69ae4-7e40-4807-8a86-b3d36fab68d3&amp;displaylang=en">Consolas Font Pack for Microsoft Visual Studio 2005</a></li><li><a href="http://www.ghostscript.com/~raph/type/myfonts/inconsolata.html">Inconsolata</a>，下載位址<a href="http://www.ghostscript.com/~raph/type/myfonts/Inconsolata.otf" title="OpenType file">在此</a></li><li><a href="http://corefonts.sourceforge.net/">Andale Mono</a>，下載位址：<a href="http://prdownloads.sourceforge.net/corefonts/andale32.exe">andale32.exe(from sourceforge.net)</a></li></ul><br />
<br />
其他參考：<ul><li><a href="http://delphi.about.com/od/standards/a/best_ide_font.htm">Choosing the Best Font for your Delphi / Pascal Code</a></li></ul><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5603463.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5603463.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 27 Feb 2008 16:28:36 +0800</pubDate>
</item>
<item>
	<title>指定 Google maps API script 的編碼</title>
	<description><![CDATA[
			是的，Google maps API 的 javascript 預設編碼是 utf-8，如果你的網頁編碼是 big5 或其他的，你應該要同時調整 javascript 的輸出編碼，否則你可能會遇到奇怪的錯誤。
方法就是加上隱藏的參數 oe，以 big5 為例：

&lt;script src="http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;key=your_key&amp;amp;oe=big5" type="text/javascript"&gt;&lt;/script&gt;


或許你也跟我注意到了，這兒並不是使用 &amp;，而是使用 &amp;amp;，並不是我故意寫錯，而是官方提供的範例就是如此，而且 IE6、IE7、Firefox 都可以接受...

		]]>
	</description>
	<content:encoded><![CDATA[
			是的，<a href="http://code.google.com/apis/maps/">Google maps API</a> 的 javascript 預設編碼是 utf-8，如果你的網頁編碼是 big5 或其他的，你應該要同時調整 javascript 的輸出編碼，否則你可能會遇到奇怪的錯誤。<br/>
方法就是加上隱藏的參數 oe，以 big5 為例：
<pre name="code" class="html">
&lt;script src="http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;key=your_key&amp;amp;oe=big5" type="text/javascript"&gt;&lt;/script&gt;
</pre>
<br/>
或許你也跟我注意到了，這兒並不是使用 &amp;，而是使用 &amp;amp;，並不是我故意寫錯，而是<a href="http://code.google.com/apis/maps/documentation/examples/">官方提供的範例</a>就是如此，而且 IE6、IE7、Firefox 都可以接受...

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5559477.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5559477.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Mon, 18 Feb 2008 17:18:28 +0800</pubDate>
</item>
<item>
	<title>plugin_syntaxhighlighter</title>
	<description><![CDATA[
			在 blogger 使用 dp.syntaxhighlighter 的話，你會發現根本無法生效，主要是因為 blogger 把換行符號都替換成 &lt;br/&gt; 了，而且還沒有設定可以決定是否要替換。
很幸運地，有人已經提出解決方法：yehyeh: Blogger dp.SyntaxHighlighter斷行問題解決方法

只是，我已經套用blogger-ext2了，於是想說，是不是可以寫一個blogger-ext2的 plugin 來解決這個問題。
非常感謝jQuery的強大功能，不到半天就完成了，最重要的是，不用像上面解決方法一樣，寫了一堆 code。

// Register dp.SyntaxHighLighter
// Dependency:
//   jQuery-1.2.1
//   blogger-ext2-core (最新版，0.7.x 的樣子)
//   dp.syntaxhighlighter-1.5.1
BloggerExt.SH = function() {
  // Plugin 會由此開始
  if( dp!='undefined' ) {
    // 找到 pre, textarea 下所有 br，然後替換成換行符號，收工。
    jQuery("pre > br").each( function() { jQuery(this).replaceWith( "\n" ); } );
    jQuery("textarea > br").each( function() { jQuery(this).replaceWith( "\n" ); } );
    dp.SyntaxHighlighter.ClipboardSwf = 'http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/clipboard.swf';
    dp.SyntaxHighlighter.HighlightAll('code');
  }
};
BloggerExt.SH.user_pref = function() {
	var prefs = [];
	return prefs;
};
BloggerExt.SH.update_pref = function(prefs) {
};
BloggerExt.register('SH', { SH: true} );


使用範例：

  &lt;script type="text/javascript" src="jquery-1.2.1.pack.js"&gt;&lt;/script&gt;
  &lt;script src="blogger_ext2.js" type="text/javascript"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shCore.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCSharp.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushVb.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushPhp.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushJScript.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushSql.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushXml.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushPython.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCss.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCpp.js'&gt;&lt;/script&gt;
  &lt;!--假設你已經把上面代碼存為 plugin_syntaxhighlighter.js 了 --&gt;
  &lt;script type="text/javascript" src='plugin_syntaxhighlighter.js'&gt;&lt;/script&gt;


		]]>
	</description>
	<content:encoded><![CDATA[
			在 <a href="http://www.blogger.com">blogger</a> 使用 <a href="http://code.google.com/p/syntaxhighlighter/">dp.syntaxhighlighter</a> 的話，你會發現根本無法生效，主要是因為 <a href="http://www.blogger.com">blogger</a> 把換行符號都替換成 &lt;br/&gt; 了，而且還沒有設定可以決定是否要替換。<br/>
很幸運地，有人已經提出解決方法：<a href="http://yehhou.blogspot.com/2007/06/blogger-dpsyntaxhighlighter.html">yehyeh: Blogger dp.SyntaxHighlighter斷行問題解決方法</a><br/>
<br/>
只是，我已經套用<a href="http://code.google.com/p/blogger-ext2/">blogger-ext2</a>了，於是想說，是不是可以寫一個<a href="http://code.google.com/p/blogger-ext2/">blogger-ext2</a>的 plugin 來解決這個問題。<br/>
非常感謝<a href="http://www.jquery.com">jQuery</a>的強大功能，不到半天就完成了，最重要的是，不用像上面解決方法一樣，寫了一堆 code。<br/>
<pre name="code" class="javascript">
// Register dp.SyntaxHighLighter
// Dependency:
//   jQuery-1.2.1
//   blogger-ext2-core (最新版，0.7.x 的樣子)
//   dp.syntaxhighlighter-1.5.1
BloggerExt.SH = function() {
  // Plugin 會由此開始
  if( dp!='undefined' ) {
    // 找到 pre, textarea 下所有 br，然後替換成換行符號，收工。
    jQuery("pre > br").each( function() { jQuery(this).replaceWith( "\n" ); } );
    jQuery("textarea > br").each( function() { jQuery(this).replaceWith( "\n" ); } );
    dp.SyntaxHighlighter.ClipboardSwf = 'http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/clipboard.swf';
    dp.SyntaxHighlighter.HighlightAll('code');
  }
};
BloggerExt.SH.user_pref = function() {
	var prefs = [];
	return prefs;
};
BloggerExt.SH.update_pref = function(prefs) {
};
BloggerExt.register('SH', { SH: true} );
</pre>
<br/>
使用範例：
<pre name="code" class="html">
  &lt;script type="text/javascript" src="jquery-1.2.1.pack.js"&gt;&lt;/script&gt;
  &lt;script src="blogger_ext2.js" type="text/javascript"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shCore.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCSharp.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushVb.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushPhp.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushJScript.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushSql.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushXml.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushPython.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCss.js'&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCpp.js'&gt;&lt;/script&gt;
  &lt;!--假設你已經把上面代碼存為 plugin_syntaxhighlighter.js 了 --&gt;
  &lt;script type="text/javascript" src='plugin_syntaxhighlighter.js'&gt;&lt;/script&gt;
</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4685373.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4685373.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 19 Dec 2007 17:44:01 +0800</pubDate>
</item>
<item>
	<title>Postfix log 出現 Database files are not up-to-date 的解法</title>
	<description><![CDATA[
			Google it!! 請參照：[CentOS] Postfix /etc/aliases problem
postconf -e "alias_maps = hash:/etc/aliases"
postconf -e "alias_database = hash:/etc/aliases"

Then run 'newaliases' to rebuild the aliases.db file from the text file.


		]]>
	</description>
	<content:encoded><![CDATA[
			Google it!! 請參照：<a href="http://lists.centos.org/pipermail/centos/2006-April/064210.html">[CentOS] Postfix /etc/aliases problem</a><br />
<blockquote>postconf -e "alias_maps = hash:/etc/aliases"<br />
postconf -e "alias_database = hash:/etc/aliases"<br />
<br />
Then run 'newaliases' to rebuild the aliases.db file from the text file.<br />
</blockquote><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4676643.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4676643.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Tue, 18 Dec 2007 23:04:14 +0800</pubDate>
</item>
<item>
	<title>SyncToy</title>
	<description><![CDATA[
			AllwaySync是可以用，但卻有限制，如果一次同步超過 20000 個檔案，抱歉，請買原版，現在有特價，約美金 20 元。該買嗎？

我不死心地再找了一次，突然想起前一陣子丟在桌面的 SyncToy，既然是Microsoft的好意，不如裝起來試試吧。
喔！
不錯用呢～ (對不起，不附圖片了...因為，豆漿濃...)
使用的體驗與 AllwaySync 接近，而且比 AllwaySync 聰明，會自動判定檔案是否被更名，而不會傻傻的刪除，再重新複製。

好東西，下載網址：SyncToy: a free powertoy download for file synchronization

p.s. 官方說法 XP/Vista 適用，經過我的實驗，Windows 2000 也可以用，只要有裝 .Net framework 2.0 即可。

		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="www.allwaysync.com/">AllwaySync</a>是可以用，但卻有限制，如果一次同步超過 20000 個檔案，抱歉，請買原版，現在有特價，約美金 20 元。該買嗎？<br />
<br />
我不死心地再找了一次，突然想起前一陣子丟在桌面的 <a href="http://www.microsoft.com/windowsxp/using/digitalphotography/prophoto/synctoy.mspx">SyncToy</a>，既然是<a href="http://www.microsoft.com">Microsoft</a>的好意，不如裝起來試試吧。<br />
喔！<br />
不錯用呢～ (對不起，不附圖片了...因為，豆漿濃...)<br />
使用的體驗與 <a href="www.allwaysync.com/">AllwaySync</a> 接近，而且比 <a href="www.allwaysync.com/">AllwaySync</a> 聰明，會自動判定檔案是否被更名，而不會傻傻的刪除，再重新複製。<br />
<br />
好東西，下載網址：<a href="http://www.microsoft.com/windowsxp/using/digitalphotography/prophoto/synctoy.mspx">SyncToy: a free powertoy download for file synchronization</a><br />
<br />
p.s. 官方說法 XP/Vista 適用，經過我的實驗，Windows 2000 也可以用，只要有裝 .Net framework 2.0 即可。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4559081.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4559081.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Thu, 29 Nov 2007 18:16:10 +0800</pubDate>
</item>
<item>
	<title>用 Python smtplib 寄信出現認證失敗</title>
	<description><![CDATA[
			如果你使用 Python smtplib.py 寄信時，遇到認證錯誤訊息(Authentication error)，不妨試試改變一下認證的順序，請在 smtplib.py 裡面找
        # List of authentication methods we support: from preferred to
        # less preferred methods. Except for the purpose of testing the weaker
        # ones, we prefer stronger methods like CRAM-MD5:
        preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN]
然後修改一下順序，        preferred_auths = [AUTH_LOGIN, AUTH_CRAM_MD5, AUTH_PLAIN]
或許就能迎刃而解。

		]]>
	</description>
	<content:encoded><![CDATA[
			如果你使用 <a href="http://www.python.org">Python</a> smtplib.py 寄信時，遇到認證錯誤訊息(Authentication error)，不妨試試改變一下認證的順序，請在 smtplib.py 裡面找
<pre name="code" class="python">        # List of authentication methods we support: from preferred to
        # less preferred methods. Except for the purpose of testing the weaker
        # ones, we prefer stronger methods like CRAM-MD5:
        preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN]</pre>
然後修改一下順序，<pre name="code" class="python">        preferred_auths = [AUTH_LOGIN, AUTH_CRAM_MD5, AUTH_PLAIN]</pre>
或許就能迎刃而解。

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4506713.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4506713.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Mon, 19 Nov 2007 17:38:28 +0800</pubDate>
</item>
<item>
	<title>Prism 的網路設定</title>
	<description><![CDATA[
			如果你已經安裝了Prism 0.8(下載)，而環境正好有該死的 Proxy 的話(是的，目前Prism 0.8不提供網路設定的選項)，那麼你可以試著修改 C:\Documents and Settings\your_username\Application Data\Prism\Profiles\xxxxxxx.default\prefs.js，在後面加上這幾行：
如果是自動偵測的話，user_pref("network.proxy.type","4");如果已經知道 proxy 位址與 port的話，user_pref("network.proxy.http","localhost");
user_pref("network.proxy.http_port","3128");
user_pref("network.proxy.type","1");如果知道Proxy自動設定網址的話，user_pref("network.proxy.autoconfig_url", "http://isawp1.msi.com.tw:80/wpad.dat");
user_pref("network.proxy.socks_version", 0);
user_pref("network.proxy.type", 2);

		]]>
	</description>
	<content:encoded><![CDATA[
			如果你已經安裝了<a href="http://labs.mozilla.com/2007/10/prism/" title="Mozilla Labs Blog » Blog Archive » Prism">Prism 0.8</a>(<a href="http://starkravingfinkle.org/projects/webrunner/prism-0.8-win32.exe" title="Prism 0.8">下載</a>)，而環境正好有該死的 Proxy 的話(是的，目前<a href="http://labs.mozilla.com/2007/10/prism/">Prism 0.8</a>不提供網路設定的選項)，那麼你可以試著修改 C:\Documents and Settings\<b>your_username</b>\Application Data\Prism\Profiles\xxxxxxx.default\prefs.js，在後面加上這幾行：<br />
<ol><li>如果是自動偵測的話，<pre>user_pref("network.proxy.type","4");</pre></li><li>如果已經知道 proxy 位址與 port的話，<pre>user_pref("network.proxy.http","localhost");<br />
user_pref("network.proxy.http_port","3128");<br />
user_pref("network.proxy.type","1");</pre></li><li>如果知道Proxy自動設定網址的話，<pre>user_pref("network.proxy.autoconfig_url", "http://isawp1.msi.com.tw:80/wpad.dat");<br />
user_pref("network.proxy.socks_version", 0);<br />
user_pref("network.proxy.type", 2);</pre></li></ol><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4386905.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4386905.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Mon, 29 Oct 2007 16:08:57 +0800</pubDate>
</item>
<item>
	<title>Apache SSL on Windows</title>
	<description><![CDATA[
			新版的Apache Windows 版最近加上了 SSL 支援，建立憑證的方法跟在 Linux 下一樣，需要的話可以參考：鳥哥的Linux私房菜：建立 SSL (https) 網站

指令大致都一樣，只有一點點不同：
cd "C:\Program Files\Apache Group\Apache2\conf"
mkdir ssl.key
..\bin\openssl genrsa -out ssl.key\server.key 1024
mkdir ssl.crt
..\bin\openssl req -new -x509 -key ssl.key\server.key -out ssl.crt\server.crt -config .\openssl.cnf

接著修改你的 httpd.conf/mod_ssl.conf ，修改完成以後，重新安裝 Apache 到"服務"裡面去：
..\bin\apache -k stop
..\bin\apache -k uninstall
..\bin\apache -D SSL -k install

接著重新啟動，就完成了。
..\bin\apache -k  start

		]]>
	</description>
	<content:encoded><![CDATA[
			新版的<a href="http://httpd.apache.org">Apache</a> Windows 版最近加上了 SSL 支援，建立憑證的方法跟在 Linux 下一樣，需要的話可以參考：<a href="http://linux.vbird.org/linux_server/0360apache.php#www_ssl">鳥哥的Linux私房菜：建立 SSL (https) 網站</a><br/>
<br/>
指令大致都一樣，只有一點點不同：
<pre>cd "C:\Program Files\Apache Group\Apache2\conf"
mkdir ssl.key
..\bin\openssl genrsa -out ssl.key\server.key 1024
mkdir ssl.crt
..\bin\openssl req -new -x509 -key ssl.key\server.key -out ssl.crt\server.crt -config .\openssl.cnf</pre>
<br/>
接著修改你的 httpd.conf/mod_ssl.conf ，修改完成以後，重新安裝 Apache 到"服務"裡面去：<br/>
<pre>..\bin\apache -k stop
..\bin\apache -k uninstall
..\bin\apache -D SSL -k install</pre>
<br/>
接著重新啟動，就完成了。
<pre>..\bin\apache -k  start</pre>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4285587.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4285587.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Thu, 11 Oct 2007 16:33:22 +0800</pubDate>
</item>
<item>
	<title>ImageMagicK 範例大全</title>
	<description><![CDATA[
			今天打算寫 script 來產生圖片，這當然要用 ImageMagicK 囉～
上官方網站一看，範例都幫你寫好好的了：ImageMagick v6 Examples

這下只要套用之前寫過的產生 5000 首 mp3 的 script ，稍作修改就行了。

		]]>
	</description>
	<content:encoded><![CDATA[
			今天打算寫 script 來產生圖片，這當然要用 <a href="http://www.imagemagick.org/">ImageMagicK</a> 囉～<br />
上官方網站一看，範例都幫你寫好好的了：<a href="http://www.imagemagick.org/Usage/">ImageMagick v6 Examples</a><br />
<br />
這下只要套用之前寫過的產生 5000 首 mp3 的 script ，稍作修改就行了。<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4164865.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4164865.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Wed, 19 Sep 2007 19:01:50 +0800</pubDate>
</item>
<item>
	<title>Vim folding</title>
	<description><![CDATA[
			今天無聊把玩Vim的 :help，想起了以前有試過，但忘記的功能 - folding～

可是跟以前記得的用法好像不太一樣，總之，現在的用法很簡單：
set foldmethod=syntax
(Python或Boo的話，可以用 set foldmethod=indent
這樣就行了。其他的用法請參考 :help。)

你會看到Vim已經依照語法自動幫你把相關的 function/class 都折疊起來了。
接著就可以用 zo 打開，zc 關閉，zO 打開目前 folding 裡面的所有 folding，zC 則是關閉目前 folding 裡面的所有 folding～


		]]>
	</description>
	<content:encoded><![CDATA[
			今天無聊把玩<a href="http://www.vim.org">Vim</a>的 :help，想起了以前有試過，但忘記的功能 - folding～<br />
<br />
可是跟以前記得的用法好像不太一樣，總之，現在的用法很簡單：<br />
<pre>set foldmethod=syntax</pre><br />
(<a href="http://www.python.org">Python</a>或<a href="http://boo.codehaus.org/">Boo</a>的話，可以用 <pre>set foldmethod=indent</pre><br />
這樣就行了。其他的用法請參考 :help。)<br />
<br />
你會看到<a href="http://www.vim.org">Vim</a>已經依照語法自動幫你把相關的 function/class 都折疊起來了。<br />
接著就可以用 zo 打開，zc 關閉，zO 打開目前 folding 裡面的所有 folding，zC 則是關閉目前 folding 裡面的所有 folding～<br />
<br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4142293.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4142293.html</guid>
	<category>資訊相關Idea與筆記</category>
	<pubDate>Sat, 15 Sep 2007 21:25:01 +0800</pubDate>
</item>
</channel>
</rss>