2008年12月10日 星期三

使用 clueTip plugin 的注意事項

clueTip 是一個相當實用的 jQuery tip 外掛。在使用上有一些要注意的地方:
  1. clueTip 並不是呼叫後就會顯示工具提示;跟其它的 tips library(如 Walter Zorn 的 DHTML Tooltips)在使用上的概念有差異。我們不需要將它放在 mouseover 或是滑鼠其它事件中。其會自動的 bind 到指定的 HTML 標籤上。
  2. clueTip API 中的 onActivate: 的目的是要決定是否要顯示 tip;傳給 onActivate 的是 function 參考,該 function 可以依情況決定要回傳 true(表示顯示工具提示)或 false(不顯示)
  3. 若是 titleAttribute bind 到的 attribute 是動態決定的,記得要在 bind 到的 attribute 值設定前,將值先設定好,才對該 HTML 標籤呼叫 clueTip();!否則可能會出現滑鼠第一次移動到該 HTML 標籤時,並未正確顯示,第二次移到標籤上,才正常顯示(第一點似乎也可能造成這個問題)

2008年12月1日 星期一

移植 Greasemonkey script 到 IE7Pro

主要 IE7Pro 的 API 參考可以參考 http://www.iescripts.org/help/

jQuery

直接引用即可,不需透過 unsafeWindow。

getElementsByClassName

參考 http://www.robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/

2008年11月28日 星期五

O'REILLY InsideRIA AJAX framework 投票結果

雖然 Richard 似乎強力推薦 YUI,不過還沒拿到 YUI 的投影片,也沒打算去 survey。不過 O'REILLY 最近的投票結果出爐,還是 Dojo 奪魁。

2008年11月27日 星期四

Firefox 書籤工具列消失;或是一片空白

症狀是:
「書籤工具列」顯示時一片空白。

解決方法

工具列上按右鍵→自訂,將「書籤工具列」圖示拖拉到工具列上即可

2008年11月20日 星期四

IE7Pro Compatibility Script

IE7Pro Compatibility Script 將 Firefox 的 GreaseMonkey 語法移植到 IE7 上的 script。直接安裝後即可使用。
支援語法:
  • GM_setValue
  • GM_getValue
  • GM_log
  • GM_openInTab
  • GM_addStyle
  • GM_xmlhttpRequest
// FremyCompany Script
// version 0.1 build 4 ALPHA!
// 28/03/07
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.  To install it, you need
// IE Pro 9.12 or later (see at : http://www.iepro.com)
// Then restart Internet Explorer and revisit this script.
//
// --------------------------------------------------------------------
//
// ==UserScript==
// @name          .FremyCompany Script
// @description   Scripts made by FremyCompany to make IE Pro more compatbile with GreaseMonkey
// @include       *
// ==/UserScript==

(function(w,d) {
    w.GM_setValue=function(name, value) {
        return PRO_setValue(name, value);
    };
    w.GM_getValue=function(name, defaultValue) {
        return PRO_getValue(name, defaultValue);
    };
    w.GM_log=function(text) {
        return PRO_log(text);
    };
    w.GM_openInTab=function(url) {
        return PRO_openInTab(url);
    };
    w.GM_addStyle=function(css) {
        return PRO_addStyle(css);
    };
    w.GM_xmlhttpRequest=function (d) {
        // url, method, headers, data, onload, onerror, onreadystatechange;
        if (!d.url) { GM_log("URL is missing in xhr-call"); return false; }
        if (!d.method) { d.method="POST"; }
        if (!d.headers) { d.headers=new Array(); }
        var xhr={"readyState":0,"status":0,"statusText":"not loaded"};
        var xhr_value=xhr;
        try {
            xhr=GM_xmlhttpRequest._createRequest();
            
            // OPENING of the xhr
            xhr.open(d.method, d.url, true);
            for (h in d.headers) {
                try { xhr.setRequestHeader(h, d.headers[h]); } catch (ex) {}
            }
            
            // CallBack gesture
            xhr.onreadystatechange=function() {
                GM_xmlhttpRequest._createValue(xhr,xhr_value);
                try { d.onreadystatechange(xhr_value); } catch (ex) {}
                if (xhr.readyState==4) {

                    if (xhr.status==200||xhr.status==0) {
                        try { d.onload(xhr_value); } catch (ex) {}
                    } else {
                        try { d.onerror(xhr_value); } catch (ex) {}
                    }
                }
            }
            
            // SENDING the data
            xhr.send(d.data?d.data:null)
        } catch (ex) {
            try { d.onerror(xhr_value, ex); } catch (ex2) {}
        }
    };
    w.GM_xmlhttpRequest._createRequest=PRO_xmlhttpRequest;
    w.GM_xmlhttpRequest._createValue=function(x,v) {
        v.abort=function() { x.abort(); }
        v.getResponseHeader=function(n) { return x.getResponseHeader(n);  }
        v.getAllResponseHeaders=function() { return x.getAllResponseHeaders(); }
        v.responseText=x.responseText;
        v.responseHeaders=x.getAllResponseHeaders();
        v.responseText=x.responseText;
        v.responseBody=x.responseBody;
        v.readyState=x.readyState;
        v.status=x.status;
        v.statusText=x.statusText;
    };
})(window,document);

2008年11月10日 星期一

GM_xmlhttpRequest 和 unsafeWindow 的限制

詳細的限制請參考 http://wiki.greasespot.net/0.7.20080121.0_compatibility 的描述。主要的症狀是你會發現錯誤訊息出現:
Greasemonkey access violation: unsafeWindow cannot call GM_xmlhttpRequest. 

解決方法如下:

unsafeWindow.someObject.registerCallback(function(asin) {
  window.setTimeout(function() {  // 重點是利用 window.setTimeout
    GM_xmlhttpRequest({
       method: "GET",
       url: "http://www.amazon.com/asin/" + asin;
    });
  }, 0);    // <<<
});

實際例子

$("span[name!=NOT_AVAILABLE]").click(function(){
  GM_openInTab(entrezGene+$(this).attr("name"),1);
}).mouseover(function(){
  var url=url+$(this).attr("name")+".htm";
  window.setTimeout(function(ref){
    GM_xmlhttpRequest({
      method: "GET",
      url: url+"",
      onload: 
      function(xhr) {
 ref.attr("title","Information from Entrez Gene|"+xhr.responseText).cluetip(
 {width:400,splitTitle: '|',arrows: true,dropShadow: false, cluetipClass: 'gene', waitImage: true}
        );
      }
    });
  },0,$(this));  // 用這種方法可以將 $(this) 傳進去
});

2008年11月6日 星期四

Greasemonkey and Internet Explorer

目前看來最 active 開發的就是 IE7Pro。查了一下,從 2007 年三月起的 0.9.12 版,IE7Pro 開始支援 userscript。搭配上 Compatibility Script for IE7Pro,應該是目前跟 GreaseMonkey 本尊支援度最好的。使用上與語法也很類似 Greasemonkey。安裝好 Compatibility script 後,甚至可以直接使用 GM_ 系列的 API

其它 Greasemonkey4IE 工具

2008年10月29日 星期三

利用筆記型電腦的無線網路讓 iPod Touch 上網

因為家裡只有中華電信的 ADSL,沒無線 AP,只好靠筆記型電腦的點對點連線方式,分享網路給愛碰。 方法很簡單:

首先,啟用撥接 ADSL 的網路連線共用

再來就是設定點對點連線

以下是利用 ThinkPad 的 Access Connections 來設定;視情況看看要不要加上金鑰控制 另外在 IP 上,請指定靜態 IP;比如 192.168.0.1

最後在愛碰上,利用「其他...」來設定連線到筆記型電腦的 IP 進行點對點連線即可

2008年10月24日 星期五

第一次覺得看貨品運送過程還挺有趣的...

我的新玩具從蘇州運送到浦東機場了...呼
日期時間地點貨件狀態
23 Oct 2008 19:02:25 Pudong International Airport Shipment Received At Transit Point. 
23 Oct 2008 17:39:00 Suzhou Shipment In Transit. 
23 Oct 2008 17:34:04 Suzhou Shipment In Transit. 
23 Oct 2008 15:17:27 Suzhou Shipment Held In Warehouse. Follow Up Actions Underway. 

2008年10月19日 星期日

學一個慣用語:「強者我同學」之資格考篇

育倫只有一個強字可形容 XD 某大學資格考試之心路歷程
瞧!您還不夠班呢...哈哈

2008年10月8日 星期三

CSS selector

利用類似 regular expression 的語法來選擇網頁元素:
span[class^="ARGM-"]{background:#FFFFCC}
span[class="IASL-NEG"]{background:#FFFFCC}

2008年10月7日 星期二

2008年10月3日 星期五

海角七號盜版流出...

這下真的流出了,上面印有一個大大的 Sample。希望票房不會受到影響;衝破三億!

2008年10月2日 星期四

無趣的資格考終於考完了...

連續啃書啃了兩天,終於在今天結束了無趣的考試。

考題了無新意;唯一沒看過的題目大概就是 S-R latch 的真值表和 1024 個 processors 要用 network 還是 bus 去連結比較合適。不過了無新意總比考不過要來的好 XD

帳號密碼檢視工具

昨天臨時試了幾個之前收著的免費密碼檢視器(其實主要是要抓「撥號連線」的密碼);像是 DialupassDial-up Password Recovery Master,都不能完全抓到電腦上設定的 ADSL 的連線密碼,有的是只有使用者名稱,或是只有撥號連線名。

用一用還是只有對岸同胞的侠客密码查看器才能滿足需求。除了撥號連線密碼外,這工具幾乎是全都包了:
  • Windows 系統顯示的星號密碼查看
  • 撥號密碼查看,包括 ADSL 上網密碼與 LAN 上網密碼
  • IE 自動完成密碼、表單內容查看與密碼列表保存
  • OutLook Express 郵件帳戶密碼查看
  • CMOS 開機密碼清除

2008年9月26日 星期五

Firefox 3.0.2 密碼無法使用的 bug

才剛更新完我的 Firefox 3.0.2 馬上就發現問題:Sxipper、PMOG 失效,導因於大部分既存的密碼都無法使用,也無法除儲存新的密碼。依據官方的說法,這導因於 FF 3.0.2 無法讀取包含有非 ASCII 編碼資訊的密碼。

檢查自己是不是碰到這問題的方法很簡單,就是開啟 FF 的錯誤控制台,然後看看是不是有出現:

this._storage is null
...
[Exception... "'Error: Error in getRegisteredUsername: [Exception... "'[JavaScript Error: "this._storage is null" {file: "file:///C:/Program%20Files/Mozilla%20Firefox/components/nsLoginManager.js" line: 425}]' when calling method: ...
之類的錯誤。基本上目前 Mozilla 表示會盡快弄出 patch 檔,然後這段期間要請廣大的使用者自己手動輸入帳號密碼(這真的還蠻囧的)。若是對於密碼苦手的人...只好請你自行將 FF 在倒退嚕回去 FF 3.0.1
目前已知的非官方解法:http://forum.moztw.org/viewtopic.php?p=134732
  1. 到 C:\Users\Your User Name\AppData\Roaming\Mozilla\Firefox\Profiles\XXXXX.default 目錄下(適用於 Vista,XP 應該是 C:\Documents and Settings\Your User Name\Application Data\Mozilla\Firefox\Profiles\XXXXX.default)
  2. 將 signons3.txt 檔轉換成 UTF-8 格式
  3. 重新啟動 Firefox 即可

2008年9月25日 星期四

2008年9月23日 星期二

2008/09/21 的海角七號...還是爆滿

禮拜天終於去看了「海角七號」...

原本以為已經上檔快一個月的片,熱潮應該已經過了吧;在高雄喜滿客的網路訂票系統看起來也頗多空位(心裡的 OS 是,或許高雄人比較沒那麼瘋),於是就打算到現場再買票,再看看能不能用聯名卡弄點優惠。決定好下午四點四十分的場次,四點便從楠梓開車過去夢時代...事實證明是,我太天真了;四點半到喜滿客售票大廳:「驚!竟然要排隊...」

很久沒看院線片了,我承認我是抱著看二輪片的心態去看的,反正就提早個十分鐘到...買個票進去找個地方做就好了;好吧就給它排吧...囧的是排沒多久就聽到廣播說:「五點五十分的海角七號,只剩下前三排的位置了...請各位觀眾...」啥碗糕...有沒這麼扯

Anyway...最終我還是看到了這部在網路、電視、報章媒體廣告到不行的台灣電影。第一句台詞:「幹,我操你媽的台北!」或許就宣告了這部片的不同吧...

除了已經被討論到爛的劇情之外,最主要的是看到許多很熟悉的街景,新的恆春街跟舊的恆春街道交錯的記憶...每年過年都去慈濟精舍;我真的很久沒回恆春了

2008年9月15日 星期一

在投影片中直接嵌入網頁內容

在使用 Microsoft PowerPoint present 時,有時會需要將網頁嵌入到 slide 中做展示。一般性的方式大概就是插入一個連結,然後滑鼠點擊切換視窗到瀏覽器進行操作,最後再回到投影片 side 接續 present。

藉由使用 LiveWeb macro,我們可以在 present 時,不用經過切換,讓整個 presentation 較為流暢。

2008年9月14日 星期日

Google Chrome 上的猴子

就是 Greasemetal;目前支援最基本的 script 功能。Greasemonkey 特有的功能目前還不支援。

2008年9月13日 星期六

Google Chrome 的一些使用 tips

  1. 在「上一頁」的按鈕上按下滑鼠右鍵即能顯示最近拜訪過的網頁列表
  2. Crtl+Shift+T 開啟最後一次關閉的分頁
  3. 直接在 address bar 輸入單位換算;比如 1ns in s,會自動利用 Google 計算機進行單位轉換(FF 也支援,只是不見得會利用 Google 計算機)
  4. 變大 textarea 如下圖:
    寄件者 HJ@Taipei
其它參考

替相片改裝吧...

又是一個有趣的線上相片改裝服務:PhotoFunia,版型也很多。免費幫三芝小豬打個廣告: Image Hosted by ImageShack.us

浮點數轉換器

將十進位數字表示法轉換為浮點數表示:IEEE-754 Floating-Point Conversion。可藉由這個線上工具瞭解電腦上使用的浮點數表示法。

有需要考計算機組織的也有可能會用到...:P

其它的 IEEE-754 Converter:

2008年9月12日 星期五

db4o 與結構化的物件;如何處理物件間的關連

我們導入另一個更複雜的物件 Article:

儲存結構化的物件

如同儲存一般物件一樣,我們也是呼叫 Set() 方法來儲存 Article 物件。與 Article 物件關連的 Sentence 物件會被自動儲存!
string pmid = "123";
string title = "sent0";
Article article = new Article(pmid, title);
List abs=new List();
abs.Add(new Sentence("sent1","METHOD"));
abs.Add(new Sentence("sent2","METHOD"));
abs.Add(new Sentence("sent3","CONCLUSION"));
article.SentencesOfAbstract=abs;

db.Set(article);
上面的程式碼相當於我們手動將各物件存入資料庫:
List abs=new List();
abs.Add(new Sentence("sent1","METHOD"));
abs.Add(new Sentence("sent2","METHOD"));
abs.Add(new Sentence("sent3","CONCLUSION"));
db.Set(abs);

string pmid = "123";
string title = "sent0";
Article article = new Article(pmid, title);
article.SentencesOfAbstract=abs;
db.Set(article);

取回結構化物件

QBE

要取回所有的 Article 物件,我們跟以前一樣,只要提供一個空的 prototype 即可:
Article proto = new Article(null,null);
IObjectSet result = db.Get(proto);
ListResult(result);
當然,我也可以取回所有的 Sentence 物件!
Sentence proto = new Sentence(null,null);
IObjectSet result = db.Get(proto);
ListResult(result);
我們也可以取得所有 Article 物件中滿足 section 為 TITLE 的 Sentence 物件:
Sentence title = new Sentence(null,"TITLE");
Article article = new Article(null,title);
IObjectSet result = db.Get(article);
ListResult(result);

Native Queries

對結構化物件使用 Native Query 跟一般物件幾乎一模一樣。下面示範如何取回 一群 Article 物件,使其 Title Sentence 滿足指定的參數:
/// C# .NET 1.1
public class RetrieveArticlesByTitlePredicate : Predicate
{
   readonly string _title;
   public RetrieveArticlesByTitlePredicate(string title)
   {
      _title = title;
   }
   public bool Match(Article candidate)
   {
      return candidate.SentenceOfTitle.RawText == _title;
   }
}

// 使用方法
string title = "sent0";
IObjectSet results = db.Query(new
RetrieveArticlesByTitlePredicate(title));
ListResult(results);

/// C# .NET 2.0
string title = "sent0";
List
results = db.Query
(delegate(Article article) { return article.SentenceOfTitle.RawText == title; }); listResults(results);

SODA Query API

使用 SODA 的話,必須 descend 兩次以便取得 rawText:
IQuery query = db.Query();
query.Constrain(typeof(Article));
query.Descend("title").Descend("rawText")
.Constrain("sent0");
IObjectSet result = query.Execute();
ListResult(result);
另外,我們也可以藉由指定 SentenceOfTitle 欄位來達到相同的效果:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
Sentence proto = new Sentence("sent0", null);
query.Descend("title").Constrain(proto);
IObjectSet result = query.Execute();
ListResult(result);
下面我們示範如何取得所有 PMID 為 123 的 SentencesOfAbstract 欄位:
IQuery artQuery = db.Query();
artQuery.Constrain(typeof(Article));
artQuery.Descend("pmid").Constrain("123");
IQuery sentQuery = artQuery.Descend("_SentencesOfAbs");
IObjectSet result = sentQuery.Execute();
ListResult(result);

更新結構化物件

如同一般物件一般,要更新結構化物件,也是對它們再次呼叫 Set() 方法:
IObjectSet result = db.Get(new Article("123",null));
Article found = (Article)result.Next();
found.SentenceOfTitle = new Sentence("sentXYZ",null);
db.Set(found);
下面我們嘗試直接更新 SentenceOfAbstract 物件內容:
IObjectSet result = db.Get(new Article("123",null));
Article found = (Article)result.Next();
List abs=new List();
abs.Add(new Sentence("sent1","INTRODUCTION"));
abs.Add(new Sentence("sent2","METHOD"));
abs.Add(new Sentence("sent3","CONCLUSION"));
found.SentenceOfAbstract=abs;
db.Set(found);
看起來似乎一切都很簡單、美好?但是實際上,若是我們再度存取資料庫,檢查我們的更新:
result = db.Get(new Article("123",null));
ListResult(result);
我們會發現,更新並未成功!這是因為效能上的考量,db4o 不會自動的更新結構化物件內的所有成員類別!為了兼顧效能與程式碼撰寫的簡潔,db4o 導入了 update depth 的概念,來控制程式在更新時,物件成員樹的更新深度。

update depth

對於所有的物件而言,預設的 update depth 是 1,代表只有 primitive 以及 String 成員會被更新。

db4o 提供了相當精細的方法來控制 update depth。下面我們藉由設定 CascadeOnUpdate 為 true,指定 db4o 完整的更新 Article 物件的內容:

Db4oFactory.Configure().ObjectClass(typeof(Article))
.CascadeOnUpdate(true);
// 接下來才去設定 Article 物件內容
要注意的地方是,先設定好 update depth 後才去更新才有效。

刪除結構化物件

一樣,用 Delete() 方法即可:
IObjectSet result = db.Get(new Article("123",null));
Article found = (Article)result.Next();
db.Delete(found);
result = db.Get(new Car(null));
我們應該會認為 db4o 應該也會把 Article 物件內一堆的 Sentence 物件也刪除了吧?但是實際上, db4o 並不會幫我們做這件事!

遞迴刪除結構化物件內成員

跟更新時一樣,我們可以設定 db4o,幫我們完成這件事:
Db4oFactory.Configure().ObjectClass(typeof(Article))
.CascadeOnDelete(true);

// 接下來才去刪掉
// ...
另外要注意的一點是,目前的 db4o 版本(6.0)中,就算我們要刪除的資料庫物件,目前仍然被程式內的變數參考到,它們經由遞迴刪除後,一樣會被從資料庫內移除。

2008年9月11日 星期四

db4o 的 query 方法簡述

db4o 提供三種 query 系統。

Query-By-Example;QBE

QBE 使用上相當簡單,只要提供 db4o 一個 template 物件,db4o 會自動回傳符合 template 物件中非預設欄值的所有物件。這是經由 reflecting 機制加以建立一個 query expression,其利用 AND 將所有非預設值欄位加以結合。

這個方式有下列幾點限制:
  • db4o 必須 reflect template 物件的所有成員
  • 我們無法進行更進接的 query expressions(比如 AND、OR、NOT)
  • 我們無法建立某些特殊的限制條件,比如值必須是整數 0、空字串或是 null。因為它們會被解譯為非條件。
這些限制,都可以藉由 Native Query(NQ)系統加以解決。

Native Queries

Native queries 是 db4o 主要的 query 介面。其概念可以參考如下兩篇白皮書:

範例

在 C# 1.1 中,我們必須建立一個繼承自 com.db4o.Predicate 的類別,並且必須實作 Match() 方法,其傳入的參數決定了物件的範圍。
bool Match(Sentence candidate);

下面我們看一個更複雜的 query;我們嘗試找出所有的 Sentence 物件,並滿足:section 必須為 TITLE,並且其 sentence 長度不能大於 20 個字:

// C# .NET 2.0
IList <Sentence> result = db.Query%lt;Sentence> (delegate(Sentence sent) {
return sent.RawText.Length < 20 && sent.SECTION == "TITLE";
});
原則上,我們可以將任意的程式碼轉化為 Native Query,只要我們知道自己在做什麼就好了...我們再看一個例子:

SODA Query API

SODA query API 是 db4o 最底層的 query API,使用它能讓我們直接存取 query graph 上的節點。因為 SODA 使用字串來識別欄位,因此本身缺乏程式語言的支援(比如編譯時期型態檢驗),而且撰寫起來也比較冗長。因此對於大部分的應用而言, Native Query 會是比較好的選擇!然而,因為有一些應用,有動態產生 query 的需求,這時就需要用到 SODA。

範例

下面示範如何利用 SODA 取回全部的 Sentence 物件。我們利用 ObjectContainer 的 Query() 方法建立了 Query 物件,接著我們可以藉由 Constraint 物件加入限制到 Query 物件中:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
IObjectSet result = query.Execute();
ListResult(result);
要經由 section 名取得某個 Sentence 物件,我們必須利用 Descend() 方法進一步的加強限定它的 Section 欄位:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("section").Constrain("TITLE");
IObjectSet result = query.Execute();
ListResult(result);
值的一提的是,類別限定其實可以拿掉;假若去掉類別限定,我們將會 query 取得所有包含指定的 section 資料欄位值的物件。再看另一個例子:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("rawText").Constrain("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.");
IObjectSet result = query.Execute();
ListResult(result);

進階範例

有時我們並不確定某特定欄位,但是需要去 query 符合特定範圍值的物件,或是不包含特定值的物件,這些都可以經由 Constraint API 辦到。

下面的例子找出,所有 RawText 不是「Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.」的 Sentence 物件:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("rawText").Constrain("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.").Not();
IObjectSet result = query.Execute();
ListResult(result);
我們也可以加入其它的邏輯運算:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
IConstraint constr = query.Descend("rawText")
.Constrain("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.");
// 也可以用 .Or(constr);
query.Descend("section")
.Constrain("TITLE").And(constr);

IObjectSet result = query.Execute();
ListResult(result);
我們也利用限制來比較給定的值:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
// 找到長度大於 50 的 Sentence 物件
query.Descend("length")
.Constrain(50).Greater();
IObjectSet result = query.Execute();
ListResult(result);
SOAD API 也允許我們去 query 欄位值為資料型態的預設值的物件:
Sentence s = new Sentence("Sentence 1", null);
db.Set(s);
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("section").Constrain(null);
IObjectSet result = query.Execute();
ListResult(result);
db.Delete(s);
我們也可以請 db40 對 query 結果進行排序:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("length").OrderAscending();
IObjectSet result = query.Execute();
ListResult(result);
query.Descend("length").OrderDescending();
result = query.Execute();
ListResult(result);
前述的所有範例都可以任意結合,形成更複雜的 query。最後我們示範如何清除資料庫內所有的 Sentence 物件:
IObjectSet result = db.Get(typeof(Sentence));
foreach (object item in result)
{
  db.Delete(item);
}

ASP.NET 的 XSS 攻擊偵測

伺服器出現:

A potentially dangerous Request.Form value was detected from the client (="...it (Omega<<A)>

Description: Request Validation has detected a potentially dangerous client input value, and processing of the request has been aborted. ...

的錯誤,起因是因為 ASP.Net 1.1 後導入對提交表單進行自動檢查是否存在 XSS(跨站腳本攻擊)的能力。當 client 端試圖用某些特定符號的輸入影響頁面返回結果時,ASP.NET 引擎會拋出 HttpRequestValidationExceptioin。

最簡單的方式就是加入在 web.confing 中加入 validateRequest="false" 的選項


...
 
 
    

或是在 @Page 中加入 ValidateRequest="false"
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" ValidateRequest="false" %>

當然若應用程式不會受到此類攻擊的話,這是一個可接受的解決方法。

參考

2008年9月9日 星期二

用 Email 上傳相片到 Picasa Web Albums

現在利用用 Email 就可以在沒安裝 Picasa 的情況下,直接上傳相片到 Picasa Web Albums 上。

首先,必須先到 Setting page中將「使用電子郵件上載相片」(Allow me to upload photos by email.)選項啟用。並在輸入視窗中填入想要使用的 Email 地址:username.secretkey@picasaweb.com。接下來,只要直接寄信到該地址即可。

預設,Picasa 會將收到的相片放置到預設的「上傳投遞箱」相簿中。不過我們可以就由在主旨內指定既存的相簿名稱,即可將相片上傳到該相簿內!

目前支援最多一次上傳 20MB 的圖檔;包含 JPG、PNG 和 GIF。對於使用 Picasas mobile site 的使用者,這可以是另一種方式來分享相片。

2008年9月8日 星期一

海角七號

最近海角七號似乎掀起了一陣風潮。這禮拜原本想跟女朋友一起去看,幸好沒去嘗試;皮哥說他連兩天去戲院想說要老婆去看,沒想到票都賣光,爆滿...

不過,今晚跟的哥聊了一下才知道,原來這個劇中的「阿嘉家」(下圖;阿嘉是誰囧...沒看過電影的人),是小時候我們常經過的恆春巷子口裡的房子。

之後這地方應該會像金瓜石的「四連棟」一樣,因為「轉角遇到愛」變成觀光景點吧。

最受歡迎的 NLP/Text Mining Framework 是?

GATE 或者是...不需要 framework :-)
參考這裡

2008年9月4日 星期四

2008年9月3日 星期三

Google Chrome;Google 瀏覽器!

Google 推出自己的瀏覽器了!這裡有漫畫式(繪者是 McCloud)的說明;大抵是說明現有的 Web 應用已經超出當時瀏覽器設計出來的原意,現在各式各樣的應用都經由瀏覽器來呈現、操作,因此瀏覽器本身也需要再進化!比如:
  • 更穩定
  • 更快速(尤其是對於應用 JavaScript 的網站而言!)
  • 更安全
  • 而在操作介面上,應該更簡潔、簡單

Google 瀏覽器本身一如 Google 的其它眾多服務一樣,是免費的;甚至它是 Open Source 的!

另外,跟一般瀏覽器的差異在於 Google 瀏覽器的 process 控制。(看來要複習一下作業系統了 XD)。一般的瀏覽器的實作是 multi-thread on single process。所以,我們若是開了許多分頁,基本上它們都在同一個 process 上,但是一旦某個 thread (如分頁)上的 JavaScript 執行過久把 CPU 吃掉的話,那整個瀏覽器就都掛了。

IE 都是由同一個 PID 4132 的 process 來處理分頁

而 Google 瀏覽器則是把分頁的動作都各自建立一個 Process,如同作業系統的行程管理一般,Google 瀏覽器會管理這些 process。因此若是某個分頁在忙碌的呈現網站內容時,其它分頁仍舊可以正常運作!因為每個分頁都是獨立的 process,若是某個分頁掛掉了,我們也只會遺失該分頁的資訊內容。(不過這也應該會帶來了記憶體使用量會不會因此大增的問題吧)

Google Chrome 則由 PID 4980 來管理產生、刪除 process。如上圖,第一個分頁,4980 產生了 PID=9112 來處理。下圖,我又多開了一個分頁,另一個 process;PID=10232 被產生。

在漫畫裡,有相當簡潔清楚的比較傳統瀏覽器記憶體管理和 Google 以 process 為主的差異(很像在複習作業系統的感覺哈哈)。另外用漫畫呈現也讓人容易瞭解,比如用了許多有趣的小例子,如「無限猴子定理」,一群人坐在一台小汽車上,來描述現有 JavaScript 引擎的窘境。是相當值得一看的介紹!

相關技術

2008年8月31日 星期日

jQuery 相關教學連結

不需安裝 PDF 檢視軟體,線上觀看 PDF 檔

PDFMENOT 提供了線上觀看 PDF 的服務。可讓使用者經過 URL 或是上傳的方式直接線上觀看 PDF 內容。

除此之外,PDFMENOT 還提供了 FF 的擴充套件以及 Blogger 的 script 等工具。詳情參考這裡

在 ASP.NET 中遇到 Access is denied 錯誤

在舊版的 IIS 中加入「ASP.NET Machine Account」和「Internet 的 Guest 帳戶」即可解決這個問題。

在新版的 IIS 6.0 中,則必須加入 NETWORK SERVICE 方能解決這個問題:

C# 的 Regex.Replace

在 Perl 中正規表示法的取代,可以簡單的利用 $1、$2 等方式來輕鬆指代記憶的群組;比如:

$text="Hypermethylation of E-cadherin is an independent predictor of improved survival in head and neck squamous cell carcinoma. Shematic illustration of E-cadherin in adherens junction. E-cadherin homodimer on the cytoplasmic membranes of adjacent cells is shown. Moreover, overexpression of E-cadherin, which was found underexpressed in MTX-resistant cells, also sensitized the cells toward the chemotherapeutic agent";
$text=~s/([^>])(\bE-cadherin\b)([^<])/$1$2<\/span>$3/g;
print $text;

# 輸出:
Hypermethylation of E-cadherin is an independent predictor of improved survival in head and neck squamous cell carcinoma. Shematic illustration of E-cadherin in adherens junction. E-cadherin homodimer on the cytoplasmic membranes of adjacent cells is shown. Moreover, overexpression of E-cadherin, which was found underexpressed in MTX-resistant cells, also sensitized the cells toward the chemotherapeutic agent

在 C# 中,也可以辦到:

2008年8月30日 星期六

Windows 快速鍵

F3

在 Windows 系統裡,按下 F3 就可以呼叫出「搜尋」功能,可以輸入關鍵字後搜尋電腦裡的檔案。在 IE 瀏覽器裡,按下 F3 則可以切換到自訂的搜尋引擎網站,不需要再輸入搜尋引擎的網址或點選我的最愛。

Word 便條紙功能 Ctrl+Alt鍵+M

想要在某段文字加上 note,只要 Ctrl+Alt+M,便能呼叫「註解功能」。

「Win+F」搜尋檔案

找檔案時只要「Win+F」再輸入檔名,縮短搜尋時間。

「Win+L」立即登出電腦

暫離座位時,按「Win+L」登出系統畫面,防止竄改文件。

Word 中快速改變字母大小寫,Shift+F3
只要將想要改變的字選取起來,按下 Shift+F3 就可以讓小寫變大寫、大寫變小寫。

C# static constructor

在 Java 的類別宣告裡,可以使用 static 區塊來宣告靜態初始化的變數:
class Demo{
    private static int i;
    private static String s;
    static{
        i=24;
        s="abc"
    }
}
在 C# 則可以利用 static constructor 達到同樣的效果:
class Demo{
    private static int i;
    private static String s;
    static Demo(){
        i=24;
        s="abc"
    }
}

2008年8月28日 星期四

中華電信推出「行動導遊 Lite」基地台定位服務

中華電信新推出的「行動導遊 Lite」服務將個人導航加值服務擴大至一般手機上,就算使用的手機沒有 GPS,也能透過基地台定位而使用這項服務。

這個服務的概念,我最早是在 Common Craft 裡看到;介紹 Google Map 的新服務:

跟中華電信的另一個利用 GPS 服務的「行動導遊」僅支援特定 AGPS 手機的加值服務相比(利用手機基地台輔助衛星定位,讓不論在室內或戶外的使用者均能快速定位並搜尋附近的生活資訊),該服務讓低階手機用戶也能使用。

與行動導遊最大不同之處,在於 Lite 透過基地台以 Cell ID 方式定位所在地,即使手機沒有 GPS 定位功能,也能定位搜尋附近影院、加油站、百貨公司與餐廳等生活資訊,甚至提供路徑規劃。不過因為所有資訊包括圖資系統均仰賴行動網路傳輸,因此較適合以 3G 手機使用。

目前只要月付 50 元,就可以無限使用這項加值服務。不過我上去晃了一下,發現不支援我的手機(囧)...原來我的手機比一般低階手機更低階...

2008年8月27日 星期三

AJAX 圖示產生器

如何做好一個合格的下屬

好文共享;其實看完還頗有感觸,好幾點都可以找到認識的人去做對應... 一個好的下屬應該具備哪些方面的特性:
  1. 自己崗位職責上的工作,必須要自己來完成,不要什麼事情都去麻煩上司出面,要明白公司設定我們這個崗位的目的就是要完成工作的。
  2. 不要裝「酷」,在任何時候,面對任何問題的時候都說沒有問題,而在實際工作當中老是就有問題。不懂並不是缺點,用心學習,態度端正才是領導的最愛!
  3. 要充分瞭解自己的領導,不要忽略領導的感受,在開展工作的時候,要多想想領導想要的結果及欣賞的做事方法。
  4. 不要把領導當傻瓜。做事腳踏實地,不要表面一套背裡一套;不要油頭滑面,要知道在我們的背後有無數的眼睛。
  5. 不要吝嗇把功勞推給領導,記住,要想讓自己獲得成功,就必須懂得如何要讓別人先成功。我們的所有成績都應該歸功於領導的正確指導。
  6. 不要老是犯同樣的錯誤或不該犯的錯誤,人無完人,只要是人都有可能會出錯,但是要學會總結,同樣的問題絕對不能重犯,不該出現的問題絕對不能出現。
  7. 要勇於承擔責任,但問題發生時,其實損失最大是公司,不可能是個人,最為一個下屬,要勇敢的面對問題,不要推卸責任,領導是最討厭那些整天推卸責任的下屬。
  8. 要善於幫助領導承擔責任,但問題發生時,不僅僅是下屬的單方面問題,領導就應該付領導責任!面對這個時候,做為一個聰明的下屬,就要學會如何合理的代領導 承擔責任。但是絕對不是要下屬盲目的去承擔,要看是發生了什麼問題,不痛不癢的或者是無關決定工作前程的可以承擔,如果是發生了重大問題時,就不適合了, 作為下屬最好只付自己那些責任就可以了,不能冒然出頭!
  9. 工作時候要仔細謹慎,不要放棄任何一個環節,不要以為事情太小,就可以不抓。但是更要注意衡量利弊,千萬不要抓了芝麻丟了西瓜。
  10. 做事情時,不要老是討價還價,要知道任何一個人都是討厭老是討價還價的人。
  11. 面對額外的工作任務時,要端正態度,適當考慮,服從第一,拒絕時需要十足的理由,千萬別找借口。
  12. 有事情可以商討解決,千萬不要越過自己的上級,去反映事情,做為管理者要時刻明白,越級上報現象的弊端或容易引發的事情。
  13. 不要老是提問題,公司用我們是讓我們來解決問題的,不是來提問題的,一般問題的發現是普遍的,而解決問題的是很少的。作為一個合格的下屬,應該懂得反映問題的方法:提問題時,一定要有自己的見解和解決方案,拿出來一同讓領導考慮。千萬不要老是給領導製造麻煩。
  14. 作為一個合格的下屬,一定要注意自己的言行舉止,一般的領導都比較注重這個方面,任何一個領導不可能喜歡那些吹牛皮的人,也不可能喜歡背後議論他人是非的人,更不可能喜歡作風不良,衛生不講究的下屬。
  15. 和領導一起時,一定要注意保持距離,不要太近乎,否則會讓領導產生反感,或者會產生那種認為你拍馬屁的想法。和領導在一起時,也要注意千萬在面對大眾時,不要去搶領導的風頭,自己要做好一個跟班。
  16. 當領導遇到難題時,在自己能力範圍之內的,不管是不是自己的工作,都應該主動的,而且默默無聞的幫助領導度過難關。
  17. 作為一個下屬,要帶好自己的團隊,要作到自己的團隊與別人比較起來佔有絕對的優勢。在面對工作時,要作到讓領導,省心,放心,開心!
  18. 作為一個合格的下屬,在面對自己的工作崗位,一定要有創新的理念或事物,保持工作原狀,絕對不是公司招我們的目的,在工作上一定要有不斷的突破,一定要做的比前人好,比別人好,才可能證明自己的價值。
  19. 作為一個合格的下屬,應該擁有穩定的心態,不要做暴風雨類的人物,也不要什麼問題與不滿都強壓心頭,要時刻調整自己的心態,沒有過不去的坎,沒有辦不好的事情!
  20. 作為一個管理者,也必須要有著自己的性格,如果都和別人一樣,那在這個世界也不需要有我們的存在。做事情在不能夠違反原則的情況下,要保持著自己良好的個性。

2008年8月26日 星期二

db4o 簡介與初探

db4o object database 引擎主要由一單獨的 DLL 組成。目前版本支援了 Microsoft .NET. framework 1.0/1.1 以及 2.0。

一般 .NET framework 的 DLL 檔位於安裝目錄內的 bin/net/ 目錄底下;.NET Compact Framework 則位於 bin/compact/ 下(我使用的 6.4 版本檔名為 Db4objects.Db4o.dll)。在開發時,必須將這個 DLL 加入到參考中。

Db4objects.Db4o namespace

包含了大部分開發所需要用到的功能。其中最重要的兩個類別是 Db4objects.Db4o.Db4oFactory 和 Db4objects.Db4o.IObjectContainer。

  • Db4oFactory:提供的靜態方法讓我們可以開啟資料庫檔案、啟動伺服器或是連線到既存的伺服器。另外,它也允許我們再開啟資料庫前先設定好 db4o 的環境變數。
  • IObjectContainer:則是我們最常會使用到,也是最重要的資料庫程式介面。它代表的就是我們的 db4o 資料庫。
    • IObjectContainer 可能是處於單一使用者模式的某個資料庫,或是一個連線到某個 db4o 伺服器的客戶端連線。
    • 每一個 IObjectContainer 都擁有一個 transaction。每個執行的動作都是處於 transaction 狀態;當我們開啟一個 IObjectContainer,我們就處於一個 transaction 之中;當我們下達 Commit() 或是 Rollback(),將會馬上切換到另一個 transaction。
    • 只要我們有在操作 IObjectContainers,它將會持續保持開啟連接的狀態。當我們關閉一個 IObjectContainer,所有存在記憶體中的資料庫參考將會被丟棄。

第一個 db4o 程式

我們首先常是如何儲存、擷取、更新和刪除某個只包含 primitive 以及字串成員的類別 。

public class Sentence
{
 private string rawText;

 /// raw 參數代表原本的文字內容
 /// section 參數則為該文字所屬的 section
 public Sentence(string raw, string section)
 {
     rawText = raw;
     this.section = section;
 }
 public string RawText
 {
     get { return rawText; }
     set { rawText = value; length=value.Length}
 }
 private int length;
 public int Length
 {
     get { return length; }
     set { length = value; }
 }

 private string html;
 public string HTML
 {
     get { return html; }
     set { html = value; }
 }
 private string section;
 public string Section
 {
     get { return section; }
     set { section = value; }
 }
}

開啟資料庫

要存取一個 db4o database 資料檔或是建立一個新的資料庫,我們只要呼叫 Db4oFactory.OpenFile(),並提供我們想要存取的資料庫檔案路徑當作參數及可。該方法會回傳一個 IObjectContainer 實例。

如前述,IObjectContainer 代表的就是一個資料庫,並且扮演了我們跟 db4o 將的主要溝通橋梁。藉由呼叫 Close() 方法,將關閉該 IObjectContainer 資料庫檔,並且是放所有參考到的資訊。

// accessDb4o
IObjectContainer db = Db4oFactory.OpenFile(dbfilename);
try
{
// do something with db4o
}
finally
{
  db.Close();
}

儲存物件

要儲存某個物件,我們只要對我們的資料庫呼叫 Set() 方法,並且存給它某個物件當作參數及可!

// store First Sentence object
Sentence s = new Sentence("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.", "Title");
db.Set(s);
Console.WriteLine("Stored {0}", s);

取回物件

db4o 提供三種不同的 query 系統:

  • Query by Example (QBE)
  • Native Queries (NQ)
  • SODA Query API (SODA)
這裡我們先嘗試利用 QBE。而 NQ 則是 db4o 主要的 query 介面,文件也建議開發者使用該介面為主。

當使用 QBE 時,我們會提供 db4o 一個原型物件(prototypical object)作為我們想要取得的物件的一個範例,並呼叫 Get() 方法。db4o 將會依據傳給 Get() 方法的物件的內容,從資料庫內取得包含跟我們提供的物件一樣資料值欄位的所有物件(非預設值;一般物件的預設值為 null,int 為 0),並以 ObjectSet 實例回傳(代表所有符合的物件)。

下面我們示範如何從資料庫中取得所有的 Sentence 實例。方法很簡單,我們只要提供一個空的 Sentence 原型即可(所有的資料欄位值都為預設值):

Sentence sents = new Sentence(null, null);
ObjectSet result = db.Get(sents);
ListResult(result);

// ...略

public static void ListResult(IObjectSet result)
{
    Console.WriteLine(result.Size());
    while (result.HasNext())
    {
        Console.WriteLine(result.Next());
    }
}

db4o 另外提供了一個簡便的方法讓我們可以取得某類別的所有實例:

ObjectSet result = db.Get(typeof(Sentence));
ListResult(result);
對於泛型物件,可以利用 query() 方法取得:
IList <Sentence> sents = db.query<Sentence>(typeof(Sentence));

下面示範如何依據 section 來查詢:

Sentence sent = new Sentence(null, "BACKGROUND");
ObjectSet result = db.Get(sent);
ListResult(sent);

更新物件

更新物件跟儲存物件的動作很類似;我們也是呼叫同樣的 Set() 方法:

ObjectSet result = db.Get(new Sentence(null, "TITLE"));
Sentence found = (Sentence)result.Next();
found.Section="BACKGROUND";
db.Set(found);
Console.WriteLine("Modified section for" + found);

注意很重要的一點是我們第一個步驟是先去 query 物件。假若,當我們呼叫 Set() 方法去修改一個未知的(但是實際上我們想要修改的是既存的物件)的物件;也就是說我們沒有先去 queyr 物件,那麼 db4o 將會在資料庫內插入一個新的物件。db4o 並不會自動的把我們產生的物件跟資料庫內的物件進行比對;它假設我們實際上要插入一個剛剛好有同樣值的物件到資料庫內。

刪除物件

在資料庫內的物件可經由 DELETE() 方法加以移除。
IObjectSet result = db.Get(new Sentence("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.", null));
Sentence found = (Sentence)result.Next();
db.Delete(found);
Console.WriteLine("Deleted {0}", found);

Object Database 相關連結

依據之前使用 object database 的經驗,查詢速度印象中並不理想,尤其當資料量非常大的時候(不知道是不是錯誤的記憶)。

最近又想要在嘗試一下。下面列出 object database 相關連結:

2008年8月24日 星期日

jQuery 筆記:用 jQuery 快速選取元素

完整的文件可以參考官方網站。以下摘錄重點:

$("div").addClass("special");
$ 記號是 jQuery 的物件(其實是 jQuery 函數的縮寫),使用 $("div") 就是用 jQuery 來選取元素,這個範例可以選取文件內所有的 <div> 元素。後面接著的 .addClass("special") 就是用來做一些事情,這個範例是將先前所選取到的所有元素都加上一個名為 "special" 的 class。也就是透過 $("div").addClass("special") 的語法,可以一次幫文件上有的 <div> 元素都加入 special 的 class。

這和原本使用 JavaScript 來寫程式有很大的差異,原本自己寫可能會需要用到迴圈之類的語法,而 jQuery 的函數大多具有批次處理的功能! $ 記號 $ 是使用 jQuery 過程中最重要的函數,可以用來用來找元素;使用方式只要把參數帶入即可。下面的範例,結果將會和上面的範例一模一樣:

jQuery("div").addClass("special");
如前述,$ 是 jQuery 函數的縮寫。

選取元素

前面的例子使用 $("div") 來選取元素,帶入的參數 div 表示要找的元素,這是 CSS 選擇器(CSS Selector)的語法,如同 CSS 在做排版和外觀所使用的選擇器語法一樣。jQuery 所支援的 CSS Selector 包含了 CSS 1、CSS2 以及仍未正式發佈的 CSS3,透過 plugin 還可支援常用的 XPath 語法。

這是一段原始的 HTML: 以下用一連串的範例,以展示基本的語法與文件中會被選取的元素。

$("#body")
  • 選取到:<div id="body">
  • 解釋:選取 id 為 body 的元素

$("div#body")
  • 選取到:<div id="body">
  • 解釋:選取 id 為 body 的 <div>

$("div.contents p")
  • 選取到:<p>...</p><p>...</p>
  • 解釋:選取 class 為 contents 的 <div> 元素所包住的所有下層的 <p>

$("div > div")
  • 選取到:<div class="contents">
  • 解釋:選取被 <div> 包住的下一層 <div>

$("div:has(div)")
  • 選取到:<div id="body">
  • 解釋:選取至少有包住一個 <div> 的 <div>

2008年8月20日 星期三

Songsterr 吉他 tab 撥放器

吉他通常採用簡譜的方式來紀錄如何彈奏歌曲。但是這種方法對於樂曲節奏的呈現上有先天的不足。

Songsterr 服務藉著在每個簡譜中插入音樂檔,來呈現樂曲原有的旋律、節奏。

2008年8月14日 星期四

咕咕克拉克---線上鬧鐘

需要設定時間提醒你嗎?...Kuku Klok 提供線上鬧鈴的服務。

Windows Vista 更新後,Word 2007 無法開啟

今天中午吃飯前,放著讓 Vista 自動更新,更新完後(應該是有自動重開機),想利用 Word 2007 改 comment,沒想到卻無法使用。症狀是:只要開啟 Word 2007,整個視窗就 hold 住;無回應。

查了一下 Word 2007 解決方案中心在「在 Windows Vista - 架構電腦上安裝自動更新 Word 2007 供您可能會遇到許多問題」一文中找到了解決方案。節錄如下:

徵狀

自動更新在安裝之後,必須重新啟動電腦。不過,如果在重新啟動電腦時,正在執行 Word 2007,則可能會遇到下列問題:

  • 使用 Word 2007 時滑鼠無法運作
  • 無法開啟一份 Word 文件
  • 嘗試啟動或結束 Word 時當機
  • 開啟 [ 開啟 ] 對話方塊時, Word 停止回應
  • 儲存文件時,Word 停止回應
  • 關閉文件時,Word 停止回應

解決方案

利用 regedit,刪除 HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Data 登錄子機碼即可解決!

我是大明星

我是大明星網站提供了將使用者上傳的相片,依據版型輸出成雜誌的服務。

參考下圖為其輸出的範本(恩,相片是誰我也不清楚...:P):

JSMin 瘦身 JavaScript

JSMin 幫忙替 JavaScript 檔案瘦身。

驗證 JavaScript 程式:JSLint

JSLint 提供了線上驗證 JavaScript 語法的服務。

2008年8月13日 星期三

在 blogger 中高亮度顯示程式原始碼

JSPWiki 移轉到 Blogger 以來,最大的困擾除了語法不能像 Wiki 那麼簡潔之外,另一個問題就是程式碼在顯示上不能像 JSPWiki 有一些 plug-in 可使用。

一個方式大概就是利用 Format My Source Code For Blogging 的服務,可以產生格式化的語法。然後貼到 Blogger 上。

但是這種方式其實只是把原始碼稍微排版一下而已(近似於原本 Wiki 的 {{{、}}} 語法)。另一種方式就是利用類似 Hightlight Code Coverter: 將排版後的程式碼轉換成 HTML 輸出 的工具輸出 HTML 後再貼上。

不過這些方式都要繞一大圈才能。這裡介紹一種或許比較好的方式(支援高亮度顯示);利用 syntaxhighlighter

syntaxhighlighter 支援了大部分常見的程式語言,如 C++、Java、C# 等(完整列表見此列表)。

使用方法
  1. 首先到 syntaxhighlighter 下載 StyleHighlighter 原始碼
  2. 將壓縮檔內的 Scripts 和 Styles 目錄解壓到可公開存取的網站目錄內
  3. 修改您的 Blogger 的範本,加入如下程式碼
    <link type="text/css" rel="stylesheet" href="css/SyntaxHighlighter.css"></link>
    <script language="javascript" src="js/shCore.js"></script>
    <script language="javascript" src="js/shBrushCSharp.js"></script>
    <script language="javascript" src="js/shBrushXml.js"></script>
    <script language="javascript">
    window.onload = function(){
    dp.SyntaxHighlighter.ClipboardSwf = '/flash/clipboard.swf';
    dp.SyntaxHighlighter.HighlightAll('code');
    }
    </script>
  4. 最後在以下列語法修改包含原始碼的 HTML 片段:
    1. 利用 <pre> tag,並設定 name 屬性為 code、class 屬性為對應的程式語言代碼(參考此表
      <pre name="code" class="c-sharp">
      ... some code here ...
      </pre>
    2. 利用 <textarea> tag。
      <textarea name="code" class="c#" cols="60" rows="10">
      ... some code here ...
      </textarea>
      
範例
<html>HTML 測試</html>
collapse
nogutter
注意事項
  • 使用 <pre> 來包含程式碼時,中若是程式碼中有 < 符號,則必須將其置換為 &lt;,否則原始碼可能會被截斷。
  • 在 class="xxx" 中可以利用「:」指定額外的控制參數。詳細控制參數列表參考此表

2008年8月12日 星期二

今晚,英仙座流星雨

英仙座流星雨(每年最先登場的流星雨)將在今晚七時卅分到十時達到極大期,據報導每小時約有一百顆流星畫過天際(四金ㄟ嗎?) 在光害少的地方,只要抬頭就有可能看到流星!

英仙座 in Google Sky

幕末古寫真;走回老式相片

幕末古寫真提供了線上將現代相片轉換成老式相片風格的有趣服務。

參考右圖是旗山製冰廠拍的彩色相片經由轉換後的結果。

2008年8月9日 星期六

北京奧運開幕!

奧運會聖火宣傳片 聖火點燃

鄉民低調碼自動還原

裝了這個到 FF 上,就不用再每次猜測 ptt 上的鄉民們在低調甚麼了 :)

安裝後會在 FF 的搜尋引擎中自動加入[鄉民低調碼自動導向]...接著就是把低調碼貼進去就對了

2008年8月8日 星期五

2008 Best of Open Source Software Awards

InfoWorld 公布了 2008 年的 OSS Awards。下面整理大概會用到的東西:
  • GitVersion control
  • soapUIWeb Services Testing Tools

2008年8月7日 星期四

Mloovi RSS&Blog 翻譯服務

藉由 Mloovi 提供的服務,來訂閱國外網站的 RSS feed,可以直接將其內文翻譯成自訂的語言。

比如下面是 TechCrunch 的繁體中文 feed
http://mloovi.com/r/00885942775b267049eee20daf09d9d0

2008年8月5日 星期二

由 Greasemonkey script 直接產生 Firefox extension

參考這個線上工具。將 script 檔

// ==UserScript==

之後的所有原始碼直接貼上,即可產生 xpi 檔。
注意事項

==UserScript== 區塊中請把空白欄位去除。比如

// @include http://www.example.idv/*
// @exclude
^^^^^^^^^^^^^
 移除此欄

JavaScript 的 Sound API

SoundManager 2 補足了 JavaScript 欠缺的 Sound API。

2008年8月2日 星期六

8/4 Yahoo! 開放 kimo.com 帳號註冊

6 月時,Yahoo! 在全球推出了兩個全新的信箱網域 ymail.com 以及 rocketmail.com(我也去搶了一個帳號 :>)。今年的八月,台灣將成為 Yahoo! 推出第一個在地化域名的地區!Yahoo! 選擇的是先前併購進來的奇摩站帳號 kimo.com。據報導,主要原因是希望提供在地化、使用者較容易記憶聯想的域名。

8/4 記得想要申請自己容易記得的帳號的人,記得要到 Yahoo! 報到。

2008年7月31日 星期四

有時上網;電腦用一用常常會忘記時間的流逝。

KuKu Klock 提供了線上鬧鐘的服務,操作相當簡單,易用。

2008年7月29日 星期二

DOM 操作範例

下拉式選單

要在 select 或是 dropdown 元件中加入新的項目:

optionItem = new option(text, value, defaultSelected,
                         selected)

或是

  var opt = document.createElement(‘option’);
  opt.value=value;
  opt.text=text;
  select.options.add(opt, index);
動態建立表格

下面的程式碼示範如何取得表格目前的列數(row)。
若是表格目前沒有任何一列,則設定為 0。

   var lastRow = tbl.rows.length;
   var row = tbl.insertRow(lastRow);
   var cellLeft = row.insertCell(0);

接著下面示範如何動態加入表格內容:

  var totalRows='1'; //假設要完成的總列數為 1 列
  var totalCols='2'; //            總行數為 2 行
  var intRow;
  var intCol;
  for(intRow=0;intRow<totalRows;intRow++)
  {
     var row = tbl.insertRow(intRow);
     for(intCol=0;intCol<totalCols;intCol++)
     {
        var cellLeft = row.insertCell(intCol);
     }
  }
TextArea

下面示範如何動態建立一個文字區塊,並設定列數和行數

  var sample=document.getElementById('sample');
  var el = document.createElement('textarea');
  el.id="sample";
  el.rows=20; // 列數
  el.cols=20; // 行數
  el.style.backgroundColor="#FFFFFF";
  el.style.width="120px" ;
  el.style.height="120px";
  sample.appendChild(el);
動態加入文字

利用 text node 來加入文字內容:

 var textNode = document.createTextNode('hi');
 document.appendChild(textNode);

2008年7月27日 星期日

線上影音轉檔服務

現在越來越多的網站提供多元化的服務,也許哪天真的硬碟裡甚麼軟體都不用安裝,只要裝個網路卡驅動,加上瀏覽器就好了。

Movavi Online Video Converter 就提供了免費的線上合併、轉檔的服務,支援相當多的格式,並能直接將轉檔合併好的結果寄送到指定的 EMail 信箱,相當的方便

將排版後的程式碼轉換成 HTML 輸出

藉由 Hightlight Code Coverter 可將一般 IDE 或程式碼編輯器撰寫好的程式,轉換成 HTML 的輸出,並維持排版以及 highlight。

一個應用是用來貼在目前不支援程式碼 highlight 的 Blogger 上。

2008年7月26日 星期六

不要在伺服器上儲存圖檔了

利用 The data: URI kitchen 吧。 產生的字串類似:
var src="<a href="data:image/png,%89PNG%0D%0A%1A%0A%0DIHDR
%10%08%06%1F%F3%FFa%02%A4IDAT8%8D%A5RMkSA%14%3Do%E6%E5%7D%A4I
%8CIj%954j%2B%ADE%B1-%B8%90%AA%20%A2%B8%90%20%8A%8B%82hWn%0AU
%04%C5b%DDt%A5%9B%FE%02%B1%08BtQp%A1%2B7B%09%8A%18%85%12%84BA
lMJcb%9A%F7%F2%F1%5E%DE%D7%8C%8B%B4%86%D0%EE%1C%18%98%7B9%9Cs
%E6%DE%23p%CE%F1%3FG%DC%B5%BB0%28%C1%2C%9D%E5%9C%F7%0B%02L%10
%FA%197%CB%3Fv%83%0A%1D%0E%DE_%26%CE%EA%C7%7B%96%D5%F3%98%85O
F%B8%BC%1F%E0.%88%B1%02Z%FD%B6%A8F%D8%5Dab3%BB%2B%01%7Bw%81%D
8%3F3%AF%EC%E0%A5qq%28%09%A2%86A%A3%87a%D6*%F0%D5%F2%60%D5%02
%BC%EF%CF%1A%FE%60%E9%8Ax%5B%FB%B0M%40%B6%1FN%EE%EB%03%5B%19%
1B%97%8E%9E%83%E4%AFC%8A%8A%F0%25FQ%A6a%C8A%1DRT%01%3D%3E%D1%
D5%D4%D4%05w%BE%BB%BB%83%C0%99%EFU%1D%2B0%A3%0C%9D%82%1C%D2%2
1%8A%1A%08%ABoA%18%08%D7%E0%93u%A8%FB%1C8%13q%1B%F6%FD%0E%02%
D6%AC%9D%27%D1%81%3D%BE%80%01%C1%D1%5B%03%DCF%0B%C1%19%60i%80
%A5%810%1Dj%7F%02%9E%A7%5C%ED%D8%02s1%E0%8B%86%218U%60%7B%A6%
96%DE%D2w%9B%40%23%0F8%3A%40%7C%A0r%0Fh%28r%04%F5%1C%10Hl%AD%
END%AEB%60%82</a>

直接利用

var icon=document.createElement('img');
icon.src=src;
即可(注意 IE 不支援)

escape、encodeURI、encodeURICompoent 方法的差異

最近在進行一個小的 FF Greasemonkey project。發現用 encodeURI 後在 POST 出去的資料只要遇到 < 符號就會被截斷,直覺上就是編碼的關係。 查了一下 Google,才發現 escape、encodeURI、encodeURICompoent 方法上的差異(可參考 http://xkr.us/articles/javascript/encode-compare/
  • escape: 採用 ISO Latin 字符集對指定的字符串進行編碼。所有的空格符、標點符號、特殊字符以及其它非 ASCII 字符都將被轉化成 %xx 格式的字符編碼(xx 等於該字符在字符集表裡面的編碼的 16 進制數字)。比如,空格符對應的編碼是 %20。unescape方法與此相反。不會被此方法編碼的字符: @ * / +
  • encodeURI: 把 URI 字符串採用 UTF-8 編碼格式轉化成 escape 格式的字符串。不會被此方法編碼的字符: ! @ # $& * ( ) = : / ; ? + '
  • encodeURIComponent: 把 URI 字符串採用 UTF-8 編碼格式轉化成 escape 格式的字符串。與 encodeURI 相比,這個方法將對更多的字符進行編碼,比如 / 等字符。所以如果字符串裡面包含了 URI 的幾個部分的話,不能用這個方法來進行編碼,否則 / 字符被編碼之後 URL 將顯示錯誤。不會被此方法編碼的字符: ! * ( )

2008年7月21日 星期一

2008年7月19日 星期六

2008年7月13日 星期日

常用的 FF 套件

趁著拿到 X61 資料移轉的機會,把我常用的 FF 套件整理如下: Bookmark Tools Developmenet Tools Privacy Information
  • InFormEnter:快速填寫表單
  • Sxipper:好用的密碼管理工具
  • FEBE:FF 設定組態、密碼等備份工具 [參考]
    • CLEO:將 FEBE 備份打包成單一安裝檔

2008年7月7日 星期一

網頁時光機

這個網站讓我們可以重溫以前的舊網頁...

下面都要選用「Big5」編碼文字才能正常顯示

人都是念舊的...看看這些東西喚起一些遺忘的回憶

2008年7月2日 星期三

I Can Has Cheezburger?

pmog 的好處就是會經由 portal 轉換到你可能從來不曾去過、或是想去逛的網站。這圖是從 pmog 的 Badges. We has them Badge 來的。這部落格裡充滿了許多可愛的動物相片(超 cute)

cat 更多喵咪的相片:點我

2008年6月29日 星期日

暗黑破壞神 III!

玻璃渣的「暗黑破壞神」又來了!這個讓我們在大四的時候每天廢寢忘食、打寶、PK 的遊戲(還有 hack XD;用石頭複製鳳凰弓之類...哈哈哈)。有不少網友也是因為這個遊戲而結交。

遊戲展示一開始就是下方熟悉的紅藍球(藍色好像變淺了一點...笑),然後...就是跟以前類似視角的全 3D 畫面。

這影片介紹的是蠻力至上的「野蠻人」,感覺比以前瘦小了點。熟悉的 skill 在一開始就秀給我們看了(當然包括了野蠻人必備的龍捲風)...還有有屬性武器的更換、補血的血瓶、可以破壞的環境(還有熟悉的掉寶聲音,聽了一定高喊:好親切)、寶箱。

似乎多了不少新角色,影片中展示了一個叫 Witch Doctor 的新巫醫角色。類似死靈法師的召喚,不過對於那些生物還可以催化,使他們能力上升,甚至變成神空特攻隊,臨死前給你自爆一下;或是讓敵人陷入 confuse 狀態,彼此自相纏殺。本身也可以利用疾病和火焰的能力來自保,感覺上是一個很有趣的角色,蠻多特殊的害死人不償命的 skill,在操作上是需要頭腦的角色 XD

影片最後是一場驚心動魄的大混戰,跟以前一樣大家一起打怪;四個人對付一隻超大隻的 monster。這 monster 還可以把角色從地上撈起來狠狠咬一口...

幾個比較有印象的新設定:

  • 破壞四周的環境也可以造成怪物的損傷,這到是蠻真實的設定
  • NPC 跟隨;跟以前雇用的傭兵不同的是,可能不只一個獲救 NPC 會跟著你。NPC 在跟隨的途中還會跟你對話
  • 3D 畫面可拉近拉遠。多了一些比較特殊的小動作,如上下樓梯的攀爬
另外,現在的 event script 已經改變成隨機的,所以同一個場景可能每次的事件都不同

2008年6月28日 星期六

27 PMOG Badges and their corresponding web sites

PMOG

注意用星號標註的項目
Please note the items start with asterisk
* Dorian's Darlings Badge
4 facebook.com urls a day four days out of every seven, four weeks in a row.
* Soul Catcher Badge
4 hits at Flickr.com a day, four days a week, four weeks in a row.
* Space is the Place Badge
3 myspace.com urls a day, four days out of every seven, four weeks in a row.
Bounce Bounce Badge
For players who read Boing Boing every day they're logged on, for 7 contiguous days
VC Badge
For players who read Tech Crunch every day they're logged on, for 7 contiguous days
Champion Badge
Visit http://change-congress.org 3 days a week for two weeks.
Web of Warcraft Badge
Visit http://worldofwarcraft.com, http://thottbot.com, or http://wowinsider.com 3 days a week for two weeks.
Badges. We has them Badge
Visit http://icanhascheezburger.com 5 days a week for two weeks.
Queen Bee Badge
Visit http://perezhilton.com 5 days a week for two weeks.
Thumb Buster Badge
Visit any of kotaku.com, joystiq.com, eurogamer.net or gamespot.com once a week for a month.
KillahOm Badge
Visit http://gigaom.com 5 days a week for two weeks.
Better Than Halo 3 Badge
Visit http://eurogamer.net 5 days a week for two weeks.
Crowd Control Badge
Visit http://massively.com 5 days a week for two weeks.
Dealers Badge
Visit http://digg.com 5 days a week for two weeks.
Great Beast Badge
Visit http://metafilter.com 5 days a week for two weeks.
Lotus Drinkers Badge
Visit http://valleywag.com 5 days a week for two weeks.
Stop Motion Badge
Visit http://reddit.com 5 days a week for two weeks.
Science, It Works Bitches Badge
For players who read xkcd.com once a week for 4 contiguous weeks.
Flying with Radar Badge
Visit dopplr.com once a week for a month.
Little Birdie Badge
Visit twitter.com once a week for a month.
Awrooo! Badge
Visit oreilly.com once a week for a month.
All About Mii Badge
For players who visit nintendo.com more than twice a week for 4 contiguous weeks
Visit jezebel.com on three days of the week for a month.
Achiever Badge
For players who visit xbox360achievements.org and / or live.xbox.com more than twice a week for 4 contiguous weeks
Take Me to Your Readers Badge
Visit io9.com three times a week for a month.
The Red Tent Badge
Visit jezebel.com on three days of the week for a month.
Fun Theory Badge
Visit http://raphkoster.com 2 days a week for two weeks.
* Mesmerized Badge
4 youtube.com urls a day, three days each week, four weeks in a row.

2008年6月20日 星期五

感謝各位鄉民的熱情贊助...恭喜 ryan 榮登今日我最囧

今天被「天下第一狗仔」 bow 和我一起抓包中午出去把妹的 ryan,經過同事、元智的學弟們熱心的參與,我們完成了這張圖 :) 以下為參與名單,萬分感謝!
  1. bow
  2. sinyuhgs
  3. 奶油麵
  4. 捲米
  5. hongjie
  6. Hun
  7. Yu-Chun
  8. 查李王
  9. IvErSoN
  10. onlytaco
  11. 邱總
活動緣起:
在堂堂中研院大門口,跟不明女性有人親暱互動的 ryan,被狗仔用手機偷拍,相片廣被在 MSN Messenger 中流傳散佈...

於是乎,大家發起了改暱稱的運動:
由 bow 的「好朋友說再見的時候 會互相摸來摸去嗎」一詞率先發難,接著 sinyu 立即響應,並由 hongjie 由台北總部接力傳續到桃園內壢地區。使用語言從中文、韓文,一直到日文皆有之...

2008年3月21日 星期五

在 eclipse 中撰寫 script,並利用 script 控制 eclipse platform

  1. 下載 eclipse
  2. Help→Software Updates→Available Software 中加入 Europa Discovery Site 的下載網址: http://download.eclipse.org/releases/europa/
  3. 如下圖,在 Other Tools 中選取安裝 Eclipse Monkey
  4. 安裝完後,重新啟動 eclipse,應該會在選單列中看到一個新的選單:Scripts

參考

2008年1月3日 星期四

JavaScript 的 Hashtable 實作

JavaScript 的 Hashtable 實作
/*******************************************************************************************
 * Object: Hashtable
 * Description: Implementation of hashtable
 * Author: Uzi Refaeli
 *******************************************************************************************/
//======================================= Properties ========================================
Hashtable.prototype.hash   = null;
Hashtable.prototype.keys  = null;
Hashtable.prototype.location = null;

/**
 * Hashtable - Constructor
 * Create a new Hashtable object.
 */
function Hashtable(){
 this.hash = new Array();
 this.keys = new Array();
 this.location = 0;
}

Hashtable.prototype.keySet = function(){
 return this.keys;
}

/**
 * put
 * Add new key
 * param: key - String, key name
 * param: value - Object, the object to insert
 */
Hashtable.prototype.put = function (key, value){
 if (value == null)
  return;

 if (this.hash[key] == null)
  this.keys[this.keys.length] = key;

 this.hash[key] = value;
}

/**
 * get
 * Return an element
 * param: key - String, key name
 * Return: object - The requested object
 */
Hashtable.prototype.get = function (key){
  return this.hash[key];
}

/**
 * remove
 * Remove an element
 * param: key - String, key name
 */
Hashtable.prototype.remove = function (key){
 for (var i = 0; i < this.keys.length; i++){
  //did we found our key?
  if (key == this.keys[i]){
   //remove it from the hash
   this.hash[this.keys[i]] = null;
   //and throw away the key...
   this.keys.splice(i ,1);
   return;
  }
 }
}

/**
 * size
 * Return: Number of elements in the hashtable
 */
Hashtable.prototype.size = function (){
    return this.keys.length;
}

/**
 * populateItems
 * Deprecated
 */
Hashtable.prototype.populateItems = function (){}

/**
 * next
 * Return: true if theres more items
 */
Hashtable.prototype.next = function (){
 if (++this.location < this.keys.length)
  return true;
 else
  return false;
}

/**
 * moveFirst
 * Move to the first item.
 */
Hashtable.prototype.moveFirst = function (){
 try {
  this.location = -1;
 } catch(e) {/*//do nothing here :-)*/}
}

/**
 * moveLast
 * Move to the last item.
 */
Hashtable.prototype.moveLast = function (){
 try {
  this.location = this.keys.length - 1;
 } catch(e) {/*//do nothing here :-)*/}
}

/**
 * getKey
 * Return: The value of item in the hash
 */
Hashtable.prototype.getKey = function (){
 try {
  return this.keys[this.location];
 } catch(e) {
  return null;
 }
}

/**
 * getValue
 * Return: The value of item in the hash
 */
Hashtable.prototype.getValue = function (){
 try {
  return this.hash[this.keys[this.location]];
 } catch(e) {
  return null;
 }
}

/**
 * getKey
 * Return: The first key contains the given value, or null if not found
 */
Hashtable.prototype.getKeyOfValue = function (value){
 for (var i = 0; i < this.keys.length; i++)
  if (this.hash[this.keys[i]] == value)
   return this.keys[i]
 return null;
}


/**
 * toString
 * Returns a string representation of this Hashtable object in the form of a set of entries,
 * enclosed in braces and separated by the ASCII characters ", " (comma and space).
 * Each entry is rendered as the key, an equals sign =, and the associated element,
 * where the toString method is used to convert the key and element to strings.
 * Return: a string representation of this hashtable.
 */
Hashtable.prototype.toString = function (){

 try {
  var s = new Array(this.keys.length);
  s[s.length] = "{";

  for (var i = 0; i < this.keys.length; i++){
   s[s.length] = this.keys[i];
   s[s.length] = "=";
   var v = this.hash[this.keys[i]];
   if (v)
    s[s.length] = v.toString();
   else
    s[s.length] = "null";

   if (i != this.keys.length-1)
    s[s.length] = ", ";
  }
 } catch(e) {
  //do nothing here :-)
 }finally{
  s[s.length] = "}";
 }

 return s.join("");
}

/**
 * add
 * Concatanates hashtable to another hashtable.
 */
Hashtable.prototype.add = function(ht){
 try {
  ht.moveFirst();
  while(ht.next()){
   var key = ht.getKey();
   //put the new value in both cases (exists or not).
   this.hash[key] = ht.getValue();
   //but if it is a new key also increase the key set
   if (this.get(key) != null){
    this.keys[this.keys.length] = key;
   }
  }
 } catch(e) {
  //do nothing here :-)
 } finally {
  return this;
 }
};