March 31, 2004

JALbum

jlogo.gif
http://jalbum.net
用java寫的相簿網頁產生器
我覺得做的還不錯
而且可以套用各種skin
還挺實用的

Posted by popcorny at 10:52 PM | Comments (344) | TrackBack

"looking glass" project

http://wwws.sun.com/software/looking_glass/
只能說太屌了吧
看他的demo之後真的是印象深刻
如果效能真的很好的話
那其他桌面管理系統大概都要哭了吧
而且可以開發更多另類的應用程式
很難想像這是java寫的
實在太神奇了

Posted by popcorny at 10:40 PM | Comments (0) | TrackBack

March 27, 2004

花心的家芸

又換blog了
http://www.jiayun.org/plog/
希望他趕快找到穩定的歸宿

Posted by popcorny at 01:36 PM | Comments (0) | TrackBack

March 21, 2004

Groovy Language PartII

此篇是延續Groovy PartI。同樣的,也是節錄這篇的內容Groovy - Scripting for Java

Groovy Ranges
Range是由".."或是"..."產生
定義如下
3..7 產生一個range從 3 到 7
3...7 產生一個range從 3 到 6
"A".."D" 產生一個range從 "A" 到 "D"
"A"..."D" 產生一個range從 "A" 到 "C"

Groovy Switch
Groovy中Switch支援個種物件,包括Class、List、Range、Pattern。
case是透過isCase這個method來做判斷。而很groovy提供許多overrloaded的isCase。
除非overloaded特別的型態,isCase是用equals此method。如果case後面是
接一個class,則使用instanceof此operator。而isCase也可以在我們所定義
的class中override掉。
以下是各種type的例子

    switch (x) {
      case 'Mark':
        println "got my name"
        break
      case 3..7:
        println 'got a number in the range 3 to 7 inclusive'
        break
      case ['Moe', 'Larry', 'Curly']:
        println 'got a Stooge name'
        break
      case java.util.Date:
        println 'got a Date object'
        break
      case ~"\\d{5}":
        println 'got a zip code'
        break
      default:
        println "got unexpected value ${x}"
    }

Groovy Looping
有提供六種loop
for

    for (i in 1..1000) { println i }

while
    i = 1
    while (i <= 1000) { println i; i++ }

each
    (1..1000).each { println it }

times
    1000.times { println it }
    // values go from 0 to 999

upto
    1.upto(1000) { println it } 

step
    1.step(1001, 1) { println it }
    // values go from 1 to 1000;
    // stopping one before the parameter value


List/Map/String Methods That Accept a Closure
List Map String都支援Closure當作參數
each
它會把collection中的每一個元素或是String的每一個字元都跑一遍。
並且都丟入closure執行。如下

    [5, 9, 1, 6].each {x | println x} 

或是
    [5, 9, 1, 6].each {println it} 

collect
它會把collection或string轉成另一個新的。下面是把每個都乘二的例子。
    doubles = [5, 9, 1, 6].collect {x | x * 2} //回傳[10, 18, 2, 12]

find
取得collection中第一個符合closure中的元素。

    [5, 9, 1, 6].find {x | x > 5} //回傳9


findAll
    [5, 9, 1, 6].findAll {x | x > 5} // 回傳[9, 6]

every
回傳是否所有的collection的item都符合closure的條件。

    [5, 9, 1, 6].every {x | x < 7} // 回傳false


any
回傳是否有任何collection的item符合closure的條件。
    [5, 9, 1, 6].any {x | x < 7} //回傳true


inject
傳進一個value到第一輪的closure中,而之後都把前一輪的結果
丟進下一輪中。以下是一個比較奇怪的方式算費式函數(factorial)
    factorial = [2, 3, 4, 5].inject(1) {
      prevResult, x | prevResult * x
    }    

File I/O
從檔案一行一行讀進來 (兩種選擇)
以下的"..."都代表省略的code

    file = new File('myFile.txt')
    file.eachLine { println it }
    lineList = file.readLines()

讀二進位的檔案 (兩種選擇)
    file = new File('myFile.txt')
    file.eachByte { println it }
    byteList = file.readBytes()

找出目錄中的所有檔
    dir = new File('directory-path')
   dir.eachFile { file | . . . }

讀入並關掉資源
此方法可以保證在讀完後會把資源關閉,即時會產生exception。
    file.withReader { reader | . . . }
    reader.withReader { reader | . . . }
    inputStream.withStream { is | . . . }

寫出並關掉資源
此方法可以保證在寫完後會把資源關閉,即時會產生exception。
    file.withWriter { writer | . . . }
    file.withPrintWriter { pw | . . . }
    file.withOutputStream { os | . . . }
    writer.withWriter { writer | . . . }
    outputStream.withStream { os | . . . }

Overloaded Left Shift Operator
連接字串(To append strings)

    s = 'foo'
    s = s << 'bar'

連接字串緩衝(To append to a StringBuffer)
    sb = new StringBuffer('foo')
    sb << 'bar'

新增到List(To add to lists)
    colors = ['red', 'green']
    colors << 'blue'

寫到串流最後(To write to the end of streams)
    w = new File('myFile.txt').newWriter()
    w << 'foo' << 'bar'
    w.close()


Object Navigation
用"->"來代替"."可以避免產生NullPointerException。
    class Team {
      String name
      Person coach
      players = []
    }
   
    class Person {
      String name
    }

    p = new Person(name:'Mike Martz')
    t = new Team(name:'Rams', coach:p)

    // The next line prints the same as team.getCoach().getName().
    println "coach = ${t.coach.name}"

    t = new Team(name:'Blues')

    // The next line returns null,
    // it doesn't throw NullPointerException.
    println "coach = ${t->coach->name}"

    // The next line throws NullPointerException.
    println "coach = ${t.coach.name}"


Groovy Reflection
印出所有GString中的methods
GString.class.methods.each { it.name }

Catching Unimplemented Methods
類別可以去捕捉所有沒有實作的類別,例子:

    o = new CatchCall()

    // 這行會印出 "unknown method Mark called with [19]".
    println o.foo("Mark", 19)

    class CatchCall {
      invokeMethod(String name, Object args) {
        try {
          return metaClass.invokeMethod(this, name, args)
        } catch (MissingMethodException e) {
          // Can insert logic here to deal with certain
          // method names and arguments in special ways.
          return "unknown method ${name} called with ${args}"
        }
      }
    }

Groovy Markup
Groovy Markup使用了剛提到的invokeMethod這個method去把所有沒定義
的method轉換成"nodes". 傳進的參數會被視為nodes的屬性。而method後的
closure會被視為nodes的內容。有非常多的使用方式如,

  • 建造簡單的Data Structure tree. (NodeBuilder)

  • 建造Dom Tree. (DomBuilder)

  • 產生SAX Event. (SaxBuiulder)

  • 產生HTML或XML (MakeupBuilder)

  • 執行AntTask (AntBuilder)

  • 產生Swing的GUI (SwingBuilder)


除此之外,也可以透過繼承BuilderSupport去客製化自己的builder。

Generating HTML
以下是透過MarkupBuilder產生HTML的範例

    import groovy.xml.MarkupBuilder

    mb = new MarkupBuilder()
    mb.html() {
      head() {
        title("This is my title.")
      }
      body() {
        p("This is my paragraph.")
      }
    }
    println mb

產生的HTML

    <html>
      <head>
        <title>This is my title.</title>
      </head>
      <body>
        <p>This is my paragraph.</p>
      </body>
    </html>


Generating XML
以下是透過MarkupBuilder產生XML的範例
    import groovy.xml.MarkupBuilder;

    mb = new MarkupBuilder()        
    mb.autos() {
      auto(year:2001, color:'blue') {
        make('Toyota')
        model('Camry')
      }
    }
    println mb

產生的XML
    <autos>
      <auto year='2001' color='blue'>
        <make>Toyota</make>
        <model>Camry</model>
      </auto>
    </autos>

Groovy SQL
Groovy讓使用SQL更容易,以下是範例

    import groovy.sql.Sql

    dbURL = 'jdbc:odbc:MusicCollection'
    jdbcDriver = 'sun.jdbc.odbc.JdbcOdbcDriver'
    sql = Sql.newInstance(dbURL, jdbcDriver)
    sql.eachRow('select * from Artists') {
      println it.Name
    }

Groovlets
Groovlet可以拿來取代Servlet或JSP,他提供以下幾種隱性變數。

  • out - 等同HttpServletResponse.getWriter()

  • request - the HttpServletRequest

  • session - the HttpSession

它使用"Here Doc"的方式來產生文件

    out.println <<<EOS
    <html>
      <head>
        <title>My Simple Groovlet</title>
      </head>
      <body>
        <h1>My Simple Groovlet</h1>
        <p>Today is ${new java.util.Date()}.</p>
      </body>
    </html>
    EOS

GroovyServlet會編譯Groovlets並且快取(cache)住,直到內容改變。
以下是一個web.xml去註冊GroovyServlet的範例
    <?xml version="1.0"?>
    <!DOCTYPE web-app
      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
      "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
      <servlet>
        <servlet-name>Groovy</servlet-name>
        <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>Groovy</servlet-name>
        <url-pattern>*.groovy</url-pattern>
      </servlet-mapping>
    </web-app>

Posted by popcorny at 09:15 PM | Comments (8) | TrackBack

Groovy Language PartI

Groovy Language已經加入JSR 241了,他是完全貼近Java Platform的script language
以下是節錄Groovy - Scripting for Java
希望大家可以初步的了解

Introduction
Groovy是設計用來以精簡快速有趣的方式來在Java平台上處理事務,
並且把類似Python Ruby等的強大功能帶到Java的世界裡。
Groovy可以被直譯,也可以被編譯成bytecode,
所以Groovy可以取得跟Java差不多的效能,
這是跟其他script lanaguage是較不一樣的。


Downloading and Installing Groovy
要下載Groovy,請依下列步驟

安裝Groovy,請依下列步驟

  • 解開下載檔

  • 把GROOVY_HOME環境變數設到解壓縮的位置

  • 把$GROOVY_HOME/bin (UNIX) 或
    %GROOVY_HOME%\bin (Windows)放到PATH的環境變數裡


Running Groovy
分四種

  • Interactive Shell

  • Interactive Swing Console

  • Script File Execution

  • Compiled Script Execution

Some Syntax Details

  • 目標是能夠支援所有的JAVA語法,但是目前還沒完全達到。

  • statement最後的分號是可有可無的

  • 呼叫method旁邊的括號是可有可無的,只要不會造成ambiguous。但是constructor一定要有。

  • "return"也是可有可無的。只要最後一個statement有被執行,則他的值就代表回傳值。

  • Groovy的properties跟method預設皆是public,而非java的pacakge private。

  • 在java.lang groovy.lang groovy.util都是預設被import。

Dynamic Typing
型態對所有varibles、properties、method/closure parameters和
method ruturn type都是可有可無的。它們都是在指定值給他們時才
會真正決定是什麼type。所有type都可以被使用,即使是primitive type。
當有需要時,型別轉換會自動發生在String、primitive type、
wrapper class之間。也因此我們可以把所有type都放在collection中。

Added Methods
Groovy加了一些method在標準的Java類別中,
(如java.lang.Object、java.lang.String)
可以參考http://groovy.codehaus.org/groovy-jdk.html


Groovy Strings
字串可以可以是單引號或是雙引號。當用說引號時,我們可以在
字串中內嵌一些運算式。如以下的例子

String toString() { "${name} is ${age} years old." }

而多行的字串可以有三行的方式可以產生,其中最後一個例子是明確指定以下
為文件資料。EOS代表"End Of String"。
    s = "  This string
      spans three \"lines\"
      and contains two newlines."

    s = """  This string
      spans three "lines"
      and contains two newlines."""

    s = <<<EOS
      This string
      spans three "lines"
      and contains two newlines.
    EOS

Regular Expressions (regex)
使用J2SE1.4的regular expressions,但是多了這三個opeartion
~"pattern" 產生一個Pattern物件且等同於Pattern.compile("pattern").
"text" =~ "pattern" 產生一個Matcher物件且等同於Pattern.compile("pattern").matcher("text").
"text" ==~ "pattern" 回傳true或false,等同於Pattern.compile("pattern").matcher("text").matches().

Groovy Scripts
Groovy scripts是用".groovy"為副檔名的groovy原始檔。他們可以
是不屬於某個class的鬆散statements,可以定義method或是class。
以下是例子

// These are loose statements.
println 'loose statement'
myMethod 'Mark', 19
println new MyClass(a1:'Running', a2:26.2)

// This is a method definition that
// is not associated with a class.
def myMethod(p1, p2) {
  println "myMethod: p1=${p1}, p2=${p2}"
}

// This is a definition of a class that
// has two properties and one method.
class MyClass {
  a1; a2
  String toString() { "MyClass: a1=${a1}, a2=${a2}" }
}

Operator Overloading
Groovy允許某些部分的operator overloading,這些operator會對應到
某些method name,只要實作這些method在你的類別就可以用對應的
operator來呼叫這些method。
Comparison Operators
a == b maps to a.equals(b)
a != b maps to !a.equals(b)
a === b maps to a == b in Java
a <=> b maps to a.compareTo(b)
a > b maps to a.compareTo(b) > 0
a >= b maps to a.compareTo(b) >= 0
a < b maps to a.compareTo(b) < 0
a <= b maps to a.compareTo(b) <= 0
Other Operators
a + b maps to a.plus(b)
a - b maps to a.minus(b)
a * b maps to a.multiply(b)
a / b maps to a.divide(b)
a++ and ++a maps to a.increment(b)
a-- and --a maps to a.decrement(b)
a[b ] maps to a.get(b)
a[b ] = c maps to a.put(b, c)


Groovy Closures
Closure可以看成function,或是說程式的片段。他會被編譯成繼承於groovy.lang.Closure。
這個Class會有call這個method,透過它可以呼叫這個closure。closure用以下這種方法定義
{ comma-separated-parameter-list | statements }
例子

    closure = { bill, tipPercentage | bill * tipPercentage / 100 }
    tip = closure.call(25.19, 15)
    tip = closure(25.19, 15) // equivalent to previous line

而只有一個參數的closure可以用it這個關鍵字代表唯一的參數,
以下兩個是等義的
    { x | println x }
    { println it }

Groovy Beans
以下是一個Groovy Bean的例子

    class Car {
      String make
      String model
    }

但是背後事實上會是如此

    public class Car {
        private String make;
        private String model;
      
        public String getMake() {
            return make;
        }
      
        public String getModel() {
            return model;
        }
      
        public void setMake(String make) {
            this.make = make;
        }
      
        public void setModel(String model) {
            this.model = model;
        }
    }

Groovy Bean可以用有名參數(named parameter)的方式產生
    myCar = new Car(make:'Toyota', model:'Camry')


Groovy Lists
Groovy list是java.util.ArrayList的物件,以下是使用List的例子

    cars = [new Car(make:'Honda', model:'Odyssey'),
            new Car(make:'Toyota', model:'Camry')]

    println cars[1] // refers to Camry

    for (car in cars) { println car } // invokes Car toString method

    class Car {
      make; model
      String toString() { "Car: make=${make}, model=${model}" }
    }

Empty List可以直接用[]
    cars = []

一個物件可以用兩種方式新增
    cars.add car
    cars << car        

count
    [1, 2, 3, 1].count(1) 會回傳2

immutable
      list = [1, 2, 3].immutable()
      list.add 4 // throws java.lang.UnsupportedOperationException

intersect
    [1, 2, 3, 4].intersect([2, 4, 6]) returns [2, 4].           

join
    ['one', 'two', 'three'].join('^') 會回傳 "one^two^three".     

sort
排序可以接受用java.util.Compartor或是Closure
    fruits = ['kiwi', 'strawberry', 'grape', 'banana']
    // The next line returns [banana, grape, kiwi, strawberry].
    sortedFruits = fruits.sort()
    
    // The next line returns [kiwi, grape, banana, strawberry].
    sortedFruits =
      fruits.sort {l, r | return l.length() <=> r.length()}        

min/max
    [5, 9, 1, 6].min() 回傳 1
    [5, 9, 1, 6].max() 回傳 9

reverse
    [1, 2, 3].reverse() 回傳 [3, 2, 1] 

plus
    [1, 2, 3] + [2, 3, 4] 回傳 [1, 2, 3, 2, 3, 4]    

minus
    [1, 2, 3, 4] - [2, 4, 6] 回傳 [1, 3] 


Groovy Maps
Groovy Maps是java.util.HashMap的物件,以下是使用Map的例子
    players = ['baseball':'Albert Pujols',
               'golf':'Tiger Woods']

    println players['golf'] // prints Tiger Woods
    println players.golf // prints Tiger Woods

    for (player in players) {
      println "${player.value} plays ${player.key}"
    }

    // This has the same result as the previous loop.
    players.each {player |
      println "${player.value} plays ${player.key}"
    }

空的Map可以用[:]代表
    players = [:]   


to be continued...

Posted by popcorny at 07:46 PM | Comments (8) | TrackBack

March 17, 2004

廣州會展中心

gzconv.jpg

實在太壯觀了
真的給他嚇到
真希望台灣也有一個那麼大的會展中心 >"<
相關討論在這

Posted by popcorny at 10:25 AM | Comments (8) | TrackBack

March 16, 2004

我姊要出差去德國耶


Nachts1.jpg

還要去法蘭克福
我最愛的歐洲城市之一
也是歐洲最多摩天大樓的城市
真是羨慕阿
將來有機會一定要去走一趟

Posted by popcorny at 10:22 PM | Comments (12) | TrackBack

March 15, 2004

Distributed Transaction

以下幾篇是在Pyrasun - The Spille Blog 裡面的文章
對transaction有非常深入的探討

XA Exposed, Part I
XA Exposed, Part II
XA Exposed, Part III: The Implementor's Notebook
XA Exposed III.I

第一篇是針對Distributed transaction的簡介
還有2 Phase Commit (2PC)是如何協同合作的

第二篇是針對2PC commit中各個時間點如果有failure
要如何做recover做探討

第三篇是實作Transaction Manager的細節
最主要在Transaction Log的地方探討相當仔細

事實上我覺得如果只是J2EE application developer
看第一篇就很足夠了
而二三篇是給開發TM或是RM的人看的

其實JTA的角色有三個
第一個是Transaction Manager(TM)的開發者
事實上應該說是提供JTS(Java Transaction Manager)

第二個是Resouce Manager(RM)的提供者
他必須實作javax.transaction.xa.XAResouce
他一方面要聽TM的指示
另一方面要能確保底層resouce能達到ACID的原則
比較常見的RM有
jdbc中XAConnection取得的XAResouce
jms中XASession取得的XAResouce
jca中ManagedConnection取得的XAResouce
這些都可以加進global transaction中


第三個就是J2EE client
也就是我們所開發的需要支援distributed transaction的應用程式
他可以跟JTS或是application server要一個global transaction
並且把所有的XAResouce加進(enlist)這個transaction
之後分別對這些resouce做些需要transaction的動作
最後要commit的時候透過TM來完成2PC

在此要非常強調一點
不是所有的transaction都需要2PC
只有對需要同時對很多個transaction resouce做動作的時候才需要做2PC
例如說對很多的database同時做update
或是要支援JMS transaction跟database的update在同一個transaction中
這種需求才需要2PC
如果需求只是對一個資料庫做transaction
那請只需要用到jdbc中connection的transaction就好
不需要使用複雜的2PC也不需要用到JTA/JTS

Posted by popcorny at 02:14 PM | Comments (0) | TrackBack

看大陸網站的好工具

Alibabar
他是一個IE的Plugin
我覺得很好用
下載網址如下
http://alf-li.tripod.com/c_alibabar.html

Posted by popcorny at 01:11 PM | Comments (0)

March 14, 2004

隨性散步

昨天跟我高一的同學約出來
因為不知道要幹麻
就去信義計畫區隨便逛逛

天南地北的聊
感覺真的不錯
現在能跟我無話不談的朋友真的不多了
他是其中一個..:)

在A8館看到許多不錯的牌子
DIESEL的櫃還真是大
而且因有盡有
好想買個DIESEL jean唷
但是好貴
以後有賺錢再買
A11的四樓戶外廣場弄得好漂亮唷
我晚上去還有band在那邊唱歌
天氣有點濕濕的
但是搭配的微弱的燈光跟撲鼻的咖啡香
還真挺有氣份

接下來去101的pageone
其實跟誠品的風格有點像
都是走高檔路線
但是比較讓我注意的是一個是她們開放給讀著坐著閱讀的空間很不錯
還有她們櫃子的兩層的設計 我也覺得挺特別的

信義計畫區真的越來越漂亮了
也已經很有都市感了
但是美中不足的是市政府蓋太矮
導致後面的建築也不能蓋太高
再者taipei101太巨大了
導致辦公室需求都被搶走
旁邊也不敢概高樓..
這樣的信義計畫區真的很突兀
我還比較希望像是東京新宿一樣
十幾個四五十層的建築
會比較有整體感些

Posted by popcorny at 02:21 PM | Comments (8)

March 11, 2004

松竹楊梅四校聯合鋼琴演奏會

話說今天晚上跟ouch劉去聽這場演奏會
抱著裝氣質還有去看氣質女的心情去聽..^_^

真的很不錯..
讓我又想起高中時參加管樂社的熱血...
不過我對幾個比較有印象的是以下幾個

蕭邦:序事曲
很奔放豪邁
演奏的是一個胖子..
在我印象中..會談鋼琴的胖子都很強..
這個也不例外..

動物狂歡節..
恩.. 很有趣的曲子
不過我對最後的"終曲"非常請有獨鍾
其中一個女生談的超投入..
我喜歡看這種表演

蕭邦:練習曲<革命>
個人本身就喜歡這首
彈的還可以..
得布西:印象<金魚>
彈奏者是:"根本就是selina"
滿分

李斯特:音樂會練習曲<悲嘆>
印象中彈的不錯...
夠華麗..

蕭邦:夜曲
純粹喜歡這首曲子

魯托斯拉夫斯基:破格尼尼主題變奏曲
這個讚
難度高到不行...
其中的清大社長更是利害
剛開始出場看他穿西裝穿布鞋覺得很華稽
人長的又呆呆的
但是彈起剛情完全變成另一個人
最詭異的是他談到爆難的地方露出詭異的笑臉
W有自信也超投入
100分..
這首是兩個人和奏的
兩個都超強.... 竟然可以讓已經聽第二十首曲子的我那麼投入
我聽完後對ouch劉講了一句話:這樣鋼琴不會壞嘛?
可見這首演奏起來多激昂

葛利格:抒情小取<奔騰的婚禮>
曲中有特別的地方元素
聽起來很舒服
演奏者也表現成穩精湛
不愧是交大社長

聽完後覺得有氣質的都彈的普普
反倒是看起來比較沒有藝術細胞的都表現超好
這是我今天最後的結論

Posted by popcorny at 11:27 PM | Comments (8)

Something about MVC

在MFC下是Document/View model
這應該算是一種delegation的表現吧
View <>--- Document
view把資料的來源都delegate到Document
而view要呈現時..去跟Document要資料就好

但是這會牽扯到一個問題...
對Document的操作.. 修正...可能有很多種方式
若放在Document裡面則這方面的邏輯就跟Document綁死
放View裡面就跟某個View綁死
(在MFC中...可以把MessageMap放在View或是Document)
所以我們就希望有一個Controller的東西把這部分的邏輯抽出來
由它去決定Document如何去修改
並且告知View怎麼去呈現(或是該去更新)
這就是MVC model的精神

但是MVC在web跟gui app會有些許不同
在gui下...
controller的存在方式是去跟view去註冊event lisener
當事件發生時去改變docuemnt的資料..
並通知view去update
在web下
controller去接收client來的request..
根據request的資料去產生document..
再丟給view端(如jsp)去做呈現

但是asp.net試圖用gui那套來處理web
所以要如何改變document的資料呢
關鍵在於"postback"..
它把document的資料postback到client的hidden field..
下次request會一起把這個state送過來
所以才能以gui的那種方式達到MVC的架構

Posted by popcorny at 05:37 PM | Comments (8)

演算法的基本概念

好像還是很多人搞不清楚耶...
這篇是我po再programming版的

big o :Ο
通常會是來說明一個演算法的upper bound..
而O(f(n)) 代表此演算法所需花的時間最多為 k * f(n)

omega:Ω
通常會是用來說明一個問題的理論lower bound
而Ω(f(n))代表此問題至少需要時間 k * f(n) 才可以解決

theta:θ
當一個演算法的big O跟它所解決的問題的omega在同一個set裡面時
我們會說它是θ(f(n))
可以說明的是這個演算法很好
跟理論的lower bound完全一樣

但是這些符號不一定是用來表示時間的
也可以拿來描述空間的複雜度
只是初學演算法大部分都是拿時間來做分析而已

Posted by popcorny at 03:08 PM | Comments (0)

March 10, 2004

Shangrila Hotel - Chongqing, China

it's awesome..
i like it :D~
cc_shangrila2.jpg

cc_shangrila2.jpg

Posted by popcorny at 06:43 PM | Comments (0)