hit counter for blogger

黑暗執行緒

 黑暗執行緒搬新家囉!! http://www.darkthread.net

8/31/2006

跟防毒公司比賽--黑暗版的病毒警告

這幾天為了一個幾家防毒軟體大廠都還無法偵測的病毒(或是SpyWare?)搞得人仰馬翻。因為現成的防毒軟體到目前都還沒有解決方案,這裡就先提出我的觀察心得讓大家知道。不過,我並非病毒專家,以下只是個人見解,大家參考就好,不負任何保證責任。

【症狀】

           執行了有毒的檔案後,我的電腦檔案總管”(Explorer.exe)的動作會變慢,在某些機器上甚至系統會Hang住一段時間。之後你用檔案總管去開啟任何Folder(包含網路分享的Folder,這是它主要跨電腦傳播的管道),如果其中有EXE檔或是DLL檔,就會受感染,改寫檔案,並在後方加上約26K的病毒碼。
進階說明:
被感染的EXE/DLL檔案,如果用UltraEdit去看二進位資料,會發現原本在第64個Byte起不久應該有一段Window程式專有的This program cannot be run in DOS mode訊息不見了,取而代之的是P(0x50) E(0x45)的NT Signature及程式碼。
例如: 正常的EXE程式
NormalExe
感染後的EXE程式
VirusExe

【行為分析】

n            受感染時,機器會變慢,並利用檔案總管傳播感染本機或遠端分享目錄的EXE/DLL。但現在的觀察,並不會全面性的主動掃瞄傳播。

n            可能有些背後的網路木馬動作,所以Outlook、MSN Messenger可能會不正常。(MSN出現超出每分鐘訊息數限制等怪訊息)

n            在一些機器上,只要重新登入,病毒就會喪失感染力。

n            重登後,某些機器則會在檔案總管按右鍵後再次具有感染力(我發現或許與WinZip32 Shell的右鍵選單DLL也被感染有關)。

n            有些機器則在感染及重開機後,一切動作變得很慢,導致電腦幾乎不能用,

n            最悲慘的狀況可能會導致OS無法開機登入。

(影響程度不同或許與受感染EXE、DLL的範圍有關係)


【偵測】
           監看了感染過程,我發現最簡單的檢測方法是開個DOS視窗,執行以下的指令:


DosDetectVirus


           在正常的電腦上應該是找不到任何檔案的,若你發現一個43K的vCab.DLL檔,表示你現在登入的這個User中毒了,或曾中過毒。但沒發現並不代表整台電腦都OK,也許某些檔案已中毒了,或用這台電腦的其他User有中毒,都有可能。

           我寫了一個HTA程式可以代為執行以上的測試。但要再次強調,這個測試僅代表現在登入的User是否已被感染而已,不代表整台電腦都OK。


HtaDetectVirus

 

【解毒】

           目前尚無完善的解毒對策。我有用.NET 1.1 DIY了一個掃瞄EXE/DLL有無中毒徵兆的程式,但無法解毒,也還沒完整測試過,懷疑自己中毒的人再個別向我索取好了。

8/29/2006

KB-不可信的LENB函數

在一個Encoding為BIG5的網頁有以下的Code,你覺得結果會是多少?
<script language=vbscript>

S=中文123

MsgBox LenB(S)

</script>


依照LenB的定義,S字串的Big5位元組數應為7,多年來我也一直這樣以為。實際跑過,你會發現它的結果是10!! 也就是123也被視為Double Bytes。


在藍色小舖有篇文章證實了這一點,但文中提到的FN_Len函數已經失傳了,所以我試著自己動手寫了一個(希望夠嚴謹,發現有問題的人再回報給我),大家可以參考看看:


'取代LENB傳回BIG5字串的正確位元組數
Function GetBytesCount(S) 

    Dim I,C,A

    C=0

    For I=1 To Len(S)

       A=ASC(Mid(S,I,1))

       C=C+1

       '如果是ASC 0-255,表示為Single Byte

       '否則為Double Byte,算雙位元組

       If (A>255 OR A<0) THEN C=C+1

    Next

    GetBytesCount=C

End Function

如果要用ASP或VBScript組裝固定欄位長度的字串時,要特別留意這個陷阱!

8/28/2006

原來Blogger也會掛點

Blogger有Goggle撐腰,理論上應該具有跟Google相同等級的High Availability才對。
2006-08-28 12:40 PM左右,看到這個難得的畫面!
BloggerBroken

鐵馬小試--關渡

上回與Lucas跑過一趟景美-大稻埕,發現了登山之外的另一種運動新選擇。
這個星期六,趁著小白馬的主人爬山去了,加上兒子不在家,"好爸爸Deadline"可以放寬,就挑戰了一下許多人都跑過的單車道終點--關渡。
小白馬果然是名門出身,騎起來比一兩千元的鐵馬省力許多。騎到手酸時,車身優異的穩定性,還可以讓你安心"放手騎"上好一陣子。想起小時候,放手騎可是苦練多年而不得的絕技,沒想到長大後,在車好、人少、路大條的天時地利之下,來就這麼不費吹灰之力就學成了。
大稻埕之前的景色,上回看過了,便不多停留。抵達時約花了一個半小時,時間與上次相近。此時已經九點半,算算最遲也得在兩小時內走完行程。看著大稻埕碼頭的地圖告示板盤算著,有三種選擇:
1) 立即原路折返,但這有點小無聊
2) 關渡有點遠(當時一直以為要繞完社子島才能接上關渡段),不如社子島走完走一小段內湖段,時限一到立刻折回圓山坐捷運回去
3) 拼了,把社子島-關渡走完,再坐捷運回程
最後,基於時程的風險考量(靠! 又把運動搞成軟體專案管理了),我決定採取方案2)...
從大稻埕重新出發,沒多久就到重陽大橋。奇妙的事發生了,前方出現了社子島向左、關渡向右的指標,意思是我可以跳過社子島的一大圈,直攻關渡,於是立刻改變戰略,決心今天把關渡走完!
CYBridge
沿著向關渡的自行車道路標前行,我看到了有名的推車上橋點--洲美大橋。
JMBridge在上橋點有兩三個自行車騎士(穿自行車賽車服的那種)在聊天,另外有一個歐吉桑(也是賽車服),為了確定起見,我向歐吉桑詢問往關渡怎麼走。沒想到他老兄開始熱心地指導我要設法從頭上的洲美穚向以北投焚化爐為地標前進,因此要先向回騎,設法上穚北行... 我不好意思直接點破可以推車上橋,只好假裝是不經意看到告示牌,引導他也發現這條捷徑,這才化解了一場尷尬。
照片中的樓梯兩側有推車用的斜坡,但說實在話,即便是小白馬這種鋁合金的輕車架,推起來還是要花點力氣的。快到橋面時,果然就看到有個婦人要推車下來,車子卻不聽使喚,人馬纏鬥的結果,造成後方要下橋的騎士大排長龍。
過了洲美穚,關渡就不遠了,這段車道兩邊都有柵欄,路面感覺就窄多了,但事實上供兩台車高速錯車也綽綽有餘,"窄"純粹是心理層面的感受問題。

距離開大稻埕不消一個小時,看到山邊有座大廟,不知不覺關渡就到了。在碼頭逗留了一下,另外再拍張水筆仔+關渡大橋的"存證照片",景美-關渡行程就算完成了。
QDBridge
時間不早,決定帶著車子坐捷運回大坪林,節省時間,順便嚐試一下腳踏車坐捷運的不同體驗。由於假日開放自行車搭捷運不論距離都是連人帶車100元,基於坐越遠賺越多的摳王心態,就再騎了一站到竹圍上車(:P 其實是因為竹圍站就在自行道旁邊)。
 關渡BikeMRTPlatform
自行車騎士要到窗口買專用票,同時售票小姐會跟你確認要下車的站名(因為不是每一站自行車都能出入),然後再親自幫你開門,由團體票的閘門進入。自行車只能上最前及最後一節車廂,每個門邊只容許停兩台車。我進了第一節車廂,發現車上已經有兩名中年自行車手(又是一身賽車手勁裝,故應以自行車手尊稱之),我一身的Polo衫加短褲,相形之下,顯得特別的瀟灑不羈~~
專用票在下車時會回收,忘了拍張照留念,看一下車廂照片裡夾在車架上的那張紙想像吧!
BikeMRT

8/19/2006

是洋蔥嗎? 不! 是Windows Live Writer!!

咦? 這是什麼來著? 有一種感動的感覺。我怎麼會流淚了呢?
是洋蔥嗎?  不! 是Windows Live Writer!!

這幾天,發現在自已訂閱的Blog中,最火紅的話題莫過於Microsoft最近推出的Windows Live Writer了,我已經看到陸續5名以上的Blogger提到它了! Windows Live Writer 是微軟最近推出的Blog寫作工具,我自己也試用了一下,只花了不消五分鐘,就不禁想為它起立鼓掌。

說穿了,Blog Editor不過就是個HTML編輯器罷了,市面上至少可以找到一打以上。Blog Editor好用與否的關鍵就在於整合!!

我的Blog平台策略是走時尚名牌風,採用的是Blogger(Google撐腰)+Flickr(Yahoo相挺)。而Windows Live Writer本身支援了多種知名的Blog系統,可以透過Blog系統提供的API與其溝通,從Live Writer就可以直接看到未來的呈現效果,按下Publish文章可自動送到Blog伺服器端,FrontPage與IIS/WSS等級的整合流暢性,活生生地在3rd Party的Blog服務上展現,這功能體著實做進Blogger們的心崁裡去了。
LiveWriter

如果只有如此還不算什麼,支援外掛Plug-In更是讓Live Writer如虎添翼,除了3rd Party提供的Plug-In之外,不滿意還可以自己動手寫(有SDK,這裡還有篇教學)。

目前社群已開發了幾個Plug-In,絕對不能錯過的就是Flickr4Writer ,它可以讓你瀏覽Flickr上的圖片後,直接插入不同尺寸的圖加連結到Blog文章中。我計算過,原先要從Flickr插入一張圖片,大約要七八個Click,Postback3-4次才能Copy到Image URL。透過Flickr4Writer,大約2-3個Click就可以完成。美中不足的是,當圖檔較小時,若選取插入Medium或Large圖片時,Flickr會直接連回原圖,但Plug-In卻還是會推算縮圖JPG的URL,導致連不到圖檔。不過,依我Trace Source Code的結果,這問題出在Flickr.API外部DLL,不算Plug-In的Bug,我想到可用HttpRequest去刺探的方式解決,待有時間來實作看看。
LiveWriter-FlickrPlugin

8/18/2006

KB-誰在叫我? .NET程式呼叫歷程的追蹤

在某些情況下,我們會想知道自己的程式碼被誰所呼叫,例如: 當某個共用函數發生錯誤時,若可知是哪一個類別呼叫這個函數時出錯,將十分有助於Debug。

各位應該都看過.NET Debug Build在出錯時,會顯示所謂的Call Stack(即Exception物件的StackTrace屬性),例如:
X:\>labs.exe
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.

   at Labs.Program.Lab0818() in F:\Documents and Settings\jeffrey\My Documents\V

isual Studio 2005\Projects\Labs\Labs\Program.cs:line 295

   at Labs.Program.Main(String[] args) in F:\Documents and Settings\jeffrey\My D

ocuments\Visual Studio 2005\Projects\Labs\Labs\Program.cs:line 304

那我們可以自己取得這些資訊嗎?

配合System.Diagnostics及System.Reflection的一些類別,這個理想是可能實現的!

我寫了一個簡單的範例:

class Caller
{

    public Caller() { }

    public void CallIt() 

    { Tracer.ShowCallerInfo("Called by Caller object"); }

}

class Tracer

{

    public static void ShowCallerInfo(string remark) 

    {

        Console.Write(new string('=', 80));

        Console.WriteLine("Caller Remark: {0}", remark);

        StackTrace st = new StackTrace(true);

        StackFrame sf = st.GetFrame(1);

        MethodBase mb = sf.GetMethod();

        Console.WriteLine("Caller Module: {0}",mb.Module.FullyQualifiedName);

        Console.WriteLine("Caller Class & Method: {0}.{1}()", mb.ReflectedType.FullName, mb.Name);

        Console.WriteLine("File Info: Line {0} in {1}", sf.GetFileLineNumber(), sf.GetFileName());

        Console.WriteLine();

    }

}

然後,直接在Console Application呼叫及建立Caller物件後呼叫


static void Lab0818()
{

    Console.WriteLine(calcDiv(1, 0));

    Tracer.ShowCallerInfo("Called by main.cs");

    Caller c = new Caller();

    c.CallIt();

}

可以得到以下的執行結果:


X:\>labs.exe
================================================================

Caller Remark: Called by main.cs

Caller Module: X:\Labs.exe

Caller Class & Method: Labs.Program.Lab0818()

File Info: Line 290 in F:\Documents and Settings\jeffrey\My Documents\Visual Stu
dio 2005\Projects\Labs\Labs\Program.cs

================================================================
Caller Remark: Called by Caller object
Caller Module: X:\Labs.exe

Caller Class & Method: Labs.Caller.CallIt()

File Info: Line 15 in F:\Documents and Settings\jeffrey\My Documents\Visual Stud
io 2005\Projects\Labs\Labs\Tracer.cs

瞧! 我們自己也有能力取得呼叫者的相關資訊。不過,要注意以下幾點:


1.        不管是Debug Build或Release Build,我們都可以取得呼叫者的程序、類別、Method等資料,但必須有.pdb檔時,才能顯示出在哪個原始檔(.cs)的哪一列

2.        Debug Build沒有pdb時,無法顯示原始檔及所在程式列。

3.        Release Build經設定也可產生pdb。

4.        上述的程式碼中,使用了Reflection的技巧去取得呼叫者資訊,不利於效能,建議節制使用。

KB-Javascript字串的特殊字元處理

猜猜看,以下的程式碼中,jsAlert函式有什麼"可議之處"?

private void Page_Load(object sender, System.EventArgs e)
{
     string msg="Hello, World!";
     jsAlert(msg);
}
private void jsAlert(string msg)
{
     Response.Write("<script>alert(\""+msg+"\");</script>");
     Response.Write("<button onclick=\"alert('"+msg+"');\">CLICK</button>");
}


問題出在,當msg參數含有一些特殊字元時,這個網頁有可能產生JavaScript Error。


例如: 若msg="L1\r\nL2\rL3\n<Words>\"It's good!\"</Words>",其中的換行及雙引號會造成<script>列出錯,而單引號及換行則會讓<button>列掛點


簡單來說,當傳入的參數要形成Javascript的字串內容時,我們要特別留意換行及單雙引號這些特殊字元。廢話不多說,我寫了個函數來處理,大家直接看Code就明白。我想得到,該攔的應該都攔了,沒想到的就有勞大家集思廣義,多多檢舉了。


private void betterJsAlert(string msg)
{
     Response.Write("<script>alert('"+JSStringEscape(msg,false)+"');</script>");
     Response.Write("<button onclick=\"alert('"+JSStringEscape(msg,true)+"');\">CLICK</button>");
}
/// <summary>
///
字串要被宣告成JavaScript字串時的特殊處理。例如: Response.Write("&lt;script&gt;alert('"+msg+"');&lt;/script&gt;");
/// 中的msg有特殊字元如換行時,會造成JavaScript Error。此函數可以進行特殊字元的置換處理。
/// </summary>
///
<param name="raw">原始字串</param>
///
<param name="htmlAttribute">是否要宣告在HTML Attribute中,對單雙引號加入特別處理。
/// 例如: "&lgt;a onclick="alert('"+msg+"');"&gt;時,注意Attribute請使用雙引號包含字串</param>


/// <returns>置換特殊字元之後的字串</returns>
///
<remarks></remarks>
private string JSStringEscape(string raw, bool inHtmlAttribute)
{
     raw=raw.Replace("\r\n","\\n").Replace("\r","").Replace("\n","\\n");
     if (inHtmlAttribute)
           raw=raw.Replace("\"", "&quot;").Replace("'", "\\'");
     else
          raw=raw.Replace("'","\\'").Replace("\"","\\\"");
     return raw;
}

8/15/2006

KB-NetLogon 5774 Error Event

手邊有幾台Server會出現NetLogon 5774的錯誤: (以下為愛台灣的中文版)

DNS 記錄 d26400ba-960a-479e-a96b-656e6a43d9c6._msdcs.labs.com.tw. 600 IN CNAME LABS-DBS.labs.com.tw. 登錄失敗,因發生下列錯誤: DNS 不存在應該存在的 RR 組。

英文原文如下:


Registration of the DNS record ' d26400ba-960a-479e-a96b-656e6a43d9c6._msdcs.labs.com.tw. 600 IN CNAME LABS-DBS.labs.com.tw ' failed with the following error: DNS RR set that ought to exist, does not exist.

事件發生的頻率大約間接2小時或3小時一次。下圖是一台最會出狀況的主機,不過,注意哦! 它的訊息跟上述有點不同:


不存在應該存在的RR組 vs 存在不該存在的RR組




Google了一下,MS有篇KB說是因為DNS中存在萬用字元*的MX記錄,但檢查的結果DNS中並沒有任何MX記錄,故排除此種原因。


另外,找到數篇討論提到,當使用整合AD的DNS時,DC的TCP/IP設定中,DNS應該只指向自己,若指向其他DNS Server,就有可能產生此種錯誤。如果需要指定其他DNS,應採行類似下圖的設定。




檢查了一下,產生錯誤的DC果然在TCP/IP中設定了其他的DNS Server,將該設定移除,改為在DNS主控台中設定。


修改至今已24小時,未再發現類似錯誤,此一問題應可判定解決。

8/14/2006

38公里的鐵馬暖身操

老弟Lucas這陣子迷上了騎腳踏車,前幾天敗了台高檔新車。於是週日約了我一同去享受台北巿民權益,驗收一下河濱自行車道整合的成果。為了配合"好爸爸行程"(定義可以參考這裡)的限制,特別提早在六點集結出發,並約定大約七點半左右折返。

由於政大段的車道尚未與全線銜接,所以比較便利的走法是由政大,走木柵路經考試院、世新大學,在景美舊橋處進入下到河濱自行車道(路線可參考這裡)。

06:47 永福橋

景美起始的這一段仍有一部分在施工,路況不是很好,但沒多久就扺達永福橋,今天天氣不錯,水面平靜,可以看見橋的清楚倒影。


三台鐵馬並列,價值六千大洋的白馬果然光彩奮目。


07:01 馬場町紀念公園

前陣子親綠學者發表倒扁聲明的地方,我到今天才知原來在這裡。


天氣晴朗,水面無波,用Canon 10D挑戰一下河畔倒影照。


07:34 大稻埕碼頭

第一次拜訪,才知這裡也可以坐船。一排飛鳥型路燈及時鐘很有設計感。


水門內就是有名的南北貨總匯--迪化街,古船造景很有。(沒來過這裡,卻一直覺得眼熟,原來是小熊子有來外拍過)


此時已超過預定時間,開始折返。隨著接近中午,太陽愈來愈毒辣,流汗之餘,體力也開始下滑。加速時,開始有腿軟的感覺,看來登山所锻練的肌肉與騎自行車用到的肌肉群還是有點差別的。最後死命苦撐,總算趕在9點前回到家中。

統計了一下相關數據如下:
歷時約三小時,總里程38公里,行前體重81kg,結束時為79kg,但因過度口渴一陣狂飲,不久體重又回測82kg。

黑暗登山團初登場

我週末的登山活動一向獨來獨往,這個星期六,老同事Jim及Chris無懼於"好爸爸行程"透早就要集合的恐怖挑戰,約好要跟我同行。

早上六點半,三人在政大門口碰頭,坐Jim的車子前往草湳大榕樹。這天天氣還不錯,美中不足的是幾乎無風。

我想了想,猴山岳路線較短,由大榕樹過去再原路折返有點乏味,走90度拉繩垂降對不常爬山的人有點挑戰,而回程得踢馬路回大榕樹取車,有點無聊。所以還是決定帶大家走二格山的寬敞豪華路線,順便見識一下知名的綠豆湯,有機會還可以來上一碗(我至今還沒嚐過哩!)。

就這樣,黑暗登山團第一次出團囉!!

一路上,看著沿途的景色,Jim聊起多次造訪九寨溝的心得,而Chris在西藏高原、四川流浪多月的經歷更是讓人聽得津津有味,與老友一同爬山的樂趣果然跟獨行攻頂完全不同。

途中乍見地上有條斷掉的黃色長橡皮筋,仔細一看居然是條怪蟲,亂噁心一把的,透過Jim放上去的10元,應可以想見它的長度。
WeirdWorm

在半山腰,向翡翠水庫的山區看去,可以看到類似雲海的景觀。沒想到在木柵除了可以看海,還有雲海可賞,真是了不起。只是要看雲海有些先決條件,水氣要足、不能有風、時間要早,通常到七點半都散得差不多了。


兩位新團員體力挺不錯的,大約只花了一個半小時,我們就抵達了山頂觀景台,留下這張新團員合照留念。
EBGuys

在山頂待了約20分鐘,走階梯下山。到綠豆湯時已超過8:30,聞得到炭火的味道。本想盡一下地主之誼,順道也親嚐綠豆湯的滋味。沒想到,老闆娘搖搖手,說綠豆應該還沒熟,就這樣,與情深緣淺的綠豆湯又再次擦身而過了。

回到大榕樹,坐上Jim的柴油"休閒專車"(柴油車的油耗效率挺好的,7公升就可跑100公里;而這台小車在假日會車尾掛著腳踏車、車頂綁著衝浪板四處遊樂,夠Pro吧!),不消15分鐘就下到政大,結束了愉快的首次出團。

8/10/2006

KB-QueryAnalyzer Bug??

用Query Analyzer查詢一個Table的Text欄位,發現筆數一多就會發生以下的錯誤
[Microsoft][ODBC SQL Server Driver]Unknown token received from SQL Server

[Microsoft][ODBC SQL Server Driver]Protocol error in TDS stream

這導致明明要查一百筆,有時傳回59筆,有時傳回92筆,有時則100筆都傳回。於是我在查詢欄位中加入了DataLength去檢查Text欄位的大小,發現發生錯誤時最後一筆的DataLength會暴增(如下圖,應為3178,卻得到813572)。

我用Terminal Service連上SQL 2000主機,用本機的Query Analyzer做同樣的查詢,就算查500筆也不會出錯。因此研判這個問題與網路傳輸有關!



與網路傳輸有關,那麼是Query Analyzer的Bug或是底層的Driver有問題? 試了一下SQL 2005 Database Management Studio,就算查500筆也不會出錯。所以網路傳輸的部分應是OK的。


用QueryAnalyzer查了另一個Table的Text欄位,發生一樣的狀況

 
【結論】
Query Analyzer在連線遠端SQL 2000資料庫,查詢大量含Text欄位的資料時,當結果資料長度超過一定大小時,就可能發生中途截斷的狀況,並得到
Unknown token received from SQL Server 或 Protocol error in TDS stream的錯誤訊息。

8/08/2006

KB-SQL 2000的資料庫變數(Table Variable)

汗顏! 今天才發現一個新玩意,自SQL 2000起,除了暫存資料表之外,還有一個選擇資料表變數(Table Variable)

資料表變數與暫存資料表(Temporary Table, 例如: #myTable)的應用時機很像,但資料表變數具有以下優點:
1.        用於Stored Procedure時,不需要每次Recompile,速度較快
2.        比照Local Variable,Scope定義明確,在不需要時就立刻會被清除
3.        Transaction Lock存在時間短,也不影響實體資料庫,資料的更新操作更有效率
 
但有得必有失,資料庫變數有以下缺點:
1.        只支援PK及UNIQUE KEY,不能建立Non-Cluster Index,也沒有資料分佈統計機制,不利於大量資料或複雜的查詢,如果Table很大時,又有繁重的查詢時,這個問題會變得明顯。但是不要誤以為資料表變數永遠只用記憶體存資料,其在資料較大時也會引用磁碟空間存放資料。
2.        基於Local Variable的限制,使用sp_executesql時無法存取
3.        不支援SELECT INTO、INSERT EXEC
 
找到兩篇不錯的參考資料
http://www.developer.com/db/print.php/3414331
http://support.microsoft.com/?kbid=305977

8/07/2006

KB-Restore SQL 2000 Backup on SQL 2005的帳號刪除問題

有個資料庫要從SQL 2000搬到SQL 2005,採用先在SQL 2000 Backup成.BAK,再複製到SQL 2005上Restore的做法,過程順利,但要刪除無用帳號時卻發現以下錯誤訊息:

DropUserError

咳… 伺服器上裝的是本土化兼愛台灣的中文版SQL 2005,一邊碎碎唸一邊Google出訊息原文為:
The database principal owns a schema in the database, and cannot be dropped.

用這個訊息Google了一下,很快就找到善心人分享的Tips。原來SQL 2005強化了Schema的概念,在Restore SQL 2000 Backup檔的同時,自動為User建了同名Schema。

如果你確定原來所有的物件都是以dbo為Owner,則利用以下的UI將這些Schema砍了即可。


環遊世界進度表

Steve的Blog看到這個有趣小東西,就輸入了一下我目前旅遊過的地方,果然,見笑了,結果為7國,佔全世界3%,隨便找個大學女生經歷都比我豐富吧! 而活了大半輩子連亞洲都沒踏出去過(最遠的地方是蜜月時去了馬爾地夫),應該也是項記錄。

現在有工作,要養小孩,要四處走動的難度不低,環遊世界的夢想,就留待中了樂透或退休後再打算了。
(忽然想要,退休後能否成行,還要看兩個小蘿蔔頭將來爭不爭氣哩! 女兒、兒子,要加油呀! 可別讓老爸晚景淒涼哦。)

8/06/2006

偷得浮生半日閒


積了好幾件銀行的事待辦,加上這陣子天氣奇佳,索性就請了一天特休假,辦事之餘的時間剛好拿來征服平日"好爸爸行程"無法涵蓋的山頭。(註: 好爸爸行程意指已婚男子以不荒廢工作、不影響正常家庭作息為前題所從事的個人休閒活動。例如: 凌晨三點出發拍外木山火燒雲、凌晨五點前往至德園拍荷花、早上九點前爬完二格山等等。感謝小熊子提供好爸爸的攝影行程)
由於這等好天氣最適合前往高山享受絕佳展望,決定挑戰台北市第一高峰--七星主峰。此番攻頂適逢情人節及結婚七週年,帶著老婆同行,充分彰顯好爸爸+好情人+好丈夫的形象,真是佩服自己的決策。
車停在小油坑遊客中心的停車場,看了一下導覽看板,由小油坑到七星主峰1.5公里,耗時約一小時。本以為正午12點會熱到不行,沒想到天公作美,湛藍的天空配上清爽的涼風,實在是絕佳的踏青天。
比起冷水坑的登頂路線,小油坑線短但陡,步道兩旁盡是與人等高的箭竹,不若爬二格山時一路有樹蔭相挺,幸好今天老全程有天然電風扇相伴,否則非中暑不可。
一路上看著藍得不像話的天空,我也試了試借來的CPL鏡。果然,CPL的效果要老天爺幫忙,今天的效果比起前幾天薄陰天時強了N倍,不過轉得太極端時,會有色偏的現象。
如導覽所預測的,花了約一小時,果然就到了主峰頂。以前兩次登頂的經驗,只記得去抱那根"台北市第一高峰"石柱跳鋼管,這次終於會留意到在旁邊的一等三角點,當然不能免俗要拍照留念,不過為了紀念這個特別的日子,與三角點相伴的不是手機跟鏡頭蓋,而是我的婚戒。

山頂的風超大,吹得人都快站不穩! 在七星山頂吹風散熱之際,忽然有個身材火辣的外國美眉背著大背包爬上來,然後很興奮地拿著DV在山頂拍360度全景,邊拍還唸唸有詞地加上口白。接著她又拿出數位相機狂拍,一度請我們幫她拍照鋼管照。我隨口問了句"Whare are you from?"(咳... 我少數能開口的幾句洋文),她說她來自墨西哥,她媽媽在山下,懶得爬上來... 接著,可怕的事來了,墨西哥辣妹指著三角點座子上刻的中文說明問道,"What does it mean?" 媽呀! 叫我用英文解釋Web的傳送原理就算了,我連三角點的英文都不知,更何況解釋了。
"Ummmm... It's umm... kind of mark umm... for geographic!" (喵的,幸好還記得地理怎麼說,這下雖不中亦不遠矣了)
"Ummm... Its term is 'Triangle Point'!" (慘了,比美Long Time No See的洋涇濱英文出現了)
"Ummm... You can use it to mark the exact position on the surface of earth" (還用手比出球狀,有點蠢)
"Ummm... It was often set at the top of mountain, so you can stand here use a telescope(比出望遠鏡的手勢) to see another top of mountain, than you can know the distance, height..." (天哪! 我到底在說什麼呀?)
善解人意的墨西哥辣妹看出我已開始胡言亂語,決定不再為難我,用力地點點頭,做出晃然大悟的表情,為黑暗大師的臨時地理講座敲了下課鐘。
回到小油坑時,仰望天空仍舊蔚藍,只是多了些白雲,一時興起,拍了張仿XP預設桌布的藍天白雲綠地照,為美麗的一天留下註記。

PS: 到現在還好奇什麼是三角點的朋友請看這裡

8/04/2006

XML Attribute的特殊字元處理DIY

我有段程式為了貪圖效能,沒用XmlDocument,而用StringBuilder自己組XML:
sb.AppendFormat("<Event Log=\"{0}\" Message=\"{1}\" />\n",
                    logName,System.Web.HttpUtility.HtmlEncode(e.Message));
結果,今天突然程式發生Error,才發現這段程式乍看OK,嚴謹性卻大有問題。原因出在e.Message中可能包含一些HtmlEncode認定合法,但XML不接受的特殊字元(例如: 換行、\t之類的),組出來的XML是不合法的。

於是,我寫了以下的Code做測試(用了一個ASCII 01(笑臉)跟\n(換行)當成非法)
        static void Lab0802()
        {
            XmlDocument xd = new XmlDocument();
            xd.LoadXml("<ROOT></ROOT>");
            XmlElement xe = xd.CreateElement("X");
            XmlAttribute xa = xd.CreateAttribute("N");
            xa.Value = "<ab>\x1\n</ab>";
            xe.Attributes.Append(xa);
            xd.DocumentElement.AppendChild(xe);
            Console.WriteLine(xd.OuterXml);
            Console.WriteLine(System.Web.HttpUtility.HtmlAttributeEncode(xa.Value));
        }

使用XML DOM的結果,合法的XML應為<ROOT><X N="&lt;ab&gt;&#x1;&#xA;&lt;/ab&gt;" /></ROOT>,而使用HtmlEncode的結果,\n與\x1都沒被置換。當Attribute中出現這些非法字元,在XmlDocument.LoadXml時,就會發生Error!

找了半天,沒找到現成的函數可以處理這個問題(有個XmlConvert.EncodeName()可處理Attribute名稱的特殊字元(例如: 中文),但其規則與Attribute Value的Encode不同,所以無法借用),只好自己DIY寫了這個函數,有類似需求的人可以引用,發現邏輯有錯的話請通知我修改。
        //當字串中可能包含特別的ASCII碼時,做額外的轉換
        public static string XmlAttributeEncode(string raw)
        {
            string s = System.Web.HttpUtility.HtmlEncode(raw);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.Length; i++)
            {
                char c = s[i];
                //要處理的範圍
                if ((c>=0 && c < 32) || (c > 127 && c<=255))
                    sb.AppendFormat("&#x{0:x};", (byte) c);
                else
                    sb.Append(c);
            }
            return sb.ToString();
        }