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 引擎的窘境。是相當值得一看的介紹!

相關技術