1. BotCheck 改版...

    有鑑於好奇心強的網友,回應時老愛研究 BotCheck 跟內容的關聯性… (Honga 就是你…),一時興起把 BotCheck 的 ASCX 改寫了一下,會在驗証通過時,把 BotCheck 的題目及答案附加在 comment 的後面,就像這樣:

    image

    免的每次都在那邊貼這次的 BotCheck 是啥.. 哈! 特此留念!

    2008/04/01 .NET ASP.NET 作品集 有的沒的

  2. Code Formatter 更新: 複製CODE及HTML預覽

    無聊的宅男沒事又改起這個Live Writer的外掛程式了。原本的版本還不錯用,不過就是覺的少了點什麼… 除了加個框之外,跟網站版本也沒什麼差別嘛。用了一陣子,又加了兩個小功能上去…

    COPY CODE

    這個功能是從MSDN學來的,MSDN文章的範例程式碼,都會附個鈕讓讀者按,按一下程式碼就會被覆製到簡貼簿… 這個功能還蠻實用的,因為我常常這樣貼… 哈哈,不曉得看我 BLOG 的人有沒有這習慣? 不管了,我的BLOG,我寫的PLUGINS,我說好用的東西當然要加上去… 底下是改版後的外掛程式,張貼程式碼的樣子:

    —————-[以下開始]——————

    測試用的 C# Code Sample..

    //
    // 不重要的程式碼... 拿來當 Model 用的...
    //
    private int CountLeadingSpaces(string line)
    {
        int count = 0;
        foreach (char ch in line)
        {
            if (ch == ' ')
            {
                count++;
            }
            else
            {
                break;
            }
        }
        return count;
    }
    

    —————-[結束]———————–

    HTML PREVIEW

    另一個無聊的功能,是過去在寫些HTML相關的文章,常常要做這樣的動作: 一方面要想辦法把HTML秀到網頁上,就得用這種外掛來處理,不過另一方面又要讓讀者直接看一下HTML顯示出來的效果,一樣的CODE又要切到HTML編輯模式貼一次… 這次就是要省掉這個懶人工夫… 一次到位。來試一下這個功能:

    —————-[以下開始]——————

    HTML測試

    <H3>這是H3的效果</H3>
    <H3>這是H3的效果</H3>
    <H3>這是H3的效果</H3>
    <H3>這是H3的效果</H3>
    <H3>這是H3的效果</H3>
    

    HTML Preview

    這是H3的效果

    這是H3的效果

    這是H3的效果

    這是H3的效果

    這是H3的效果

    —————-[結束]———————–

    好,展示完畢,沒什麼突破的進展,純粹自己好用而以[H]。我也不曉得有沒有人在用,懶的打包放網站了,需要的人再跟我要…

    2008/03/31 .NET HTML/CSS 作品集 有的沒的

  3. WLW Plugins: Code Formatter

    最近常常貼一些需要附上程式碼的文章, 我都借助 c# code format 這網站幫忙轉, 轉成好看一點的 HTML code.. 然後 Live Writer 切到原始碼的模式去改 HTML, 然後再切回來際續編…

    人果然是懶惰的動物, 之前久久寫一篇還好, 最近就開始不耐煩了… 試了一套 Syntax Highlight 的 WLW plugins, 畫面不錯, 不過中文會亂掉.. 想說 c# code format 這網站的主人有 share source code, 我就把它拿來包成 Windows Live Writer Plugins 好了…

    就是這念頭開始寫這個 project, 蠻好寫的, 兩三個小時過去就堪用了, 經過幾天試用慢慢改成現在的樣子, 先現寶一下, 放幾張圖:

    [圖 1] 編輯畫面 image

    [圖 2] 預覽畫面 (底下當然要加點廣告… ) image

    結果就不用貼圖了, 底下這段就是用這 plugins 貼進來的…

    [程式 1] 這是測試程式

    using System;
    using System.IO;
    using System.Threading;
    
    public class Program {
      public static void Main(string[] args) {
        Console.WriteLine("Hello!!" );
      }
    }
    

    看起來效果還不錯, 雖然跟之前差不多, 不過手工的部份少很多, 貼上, 按 OK, 就收工了! 這個 c# code format 提供的 library 還不賴, 效果也是我試用幾種 lib 後比較滿意的, 滿意的地方是:

    1. Pure C# 開發的, 程式很短, 不過看的出作者功力不錯, 架構啥都棒.
    2. 用習慣了, 之前都用它網站版本的. 很熟悉它轉出來的格式.
    3. 轉出來的 code 比較乾淨. 不過它需要另外搭配它的 CSS.
    4. Unicode, 沒有什麼中文亂碼的問題.

    當初最主要用它的原因就是 (3), 其它捨棄 CSS 的結果, 就是產生出來的 HTML 參著一大堆 color code, 老實說這種 HTML code 看起來就很痛苦. 我是不想看啦, 不過我必需切到 HTML view 去貼上這堆字啊… c# code format 雖然要另外補上 .css, 不過看起來就清爽多了. 我直接把它附的 CSS 貼到我用的 community server 的 custom themes 裡 (部落格管理裡面就可以直接加, 不用改檔案), 用起來就很輕鬆愉快了 :D

    要來看 code 嗎? 其實 code 就沒什麼好看的了, 需要的直接抓回去看吧. 倒是不常寫 WinForm 的我, 竟然被內建的 ComboBox 小整了一下… WinForm 內建的 ComboBox 功能很完整, Items 可以放 object, 然後再指定 ValueMember, DisplayMember… blah blah. 當然也有直接提供最簡單的 Text Editor, 一行字就是一個 Item …

    image

    不過, 我要的是很簡單的 Value / Display 分別指定就好, 就是這個 plugins 讓 user 選擇格式的地方 (如上圖), 我希望第一項的 Value 是 “HTML”, 而顯示的是 “HTML / XML / ASP.NET”, 這樣簡單的要求, 我心裡想… 這麼簡單, 一定可以直接用 Designer 填一填就搞定, 不用再去寫 code, 就可以 init 完成..

    沒想到找了半天還真的找不到! :@ 翻了 MSDN, Microsoft community 等等技術支援網站通通都沒有. 教的都是一堆我覺的拖褲子放屁的作法… 不過是五個固定的選單而以啊…

    到最後, 宣告放棄, 妥協了… 我這個功能最後是用這幾行 code 搞定的… ㄨ!!! 本來一行 code 都不想寫的…

    替 ComboBox 設定初始值的程式碼片段:

    comboBox1.DisplayMember = "Value";
    comboBox1.ValueMember = "Key";
    comboBox1.Items.Add(new KeyValuePair<string, string>("HTML",  "HTML / XML / ASP.NET"));
    comboBox1.Items.Add(new KeyValuePair<string, string>("CS",    "C#"));
    comboBox1.Items.Add(new KeyValuePair<string, string>("VB",    "Visual Basic.NET"));
    comboBox1.Items.Add(new KeyValuePair<string, string>("MSH",   "MSH (PowerShell)"));
    comboBox1.Items.Add(new KeyValuePair<string, string>("SQL",   "T-SQL"));
    comboBox1.SelectedIndex = 1;
    

    哈, 最後這邊收的不大漂亮, 不過不管了, 還好沒幾行. 這個 plugins 需要的就自己抓去用吧, 以後可能會不定時更新. 有啥改進意見可以留話給我, 不過嘛, 當然是有空 & 想改才有動力去開 visual studio .. [H]

    – 下載: code formatter plugins

    2008/03/08 .NET 作品集

  4. Tips: 遠端桌面連線的小技巧

    查了文件, 才發現可以這樣用… 平常連到 server 用的遠端桌面連現, 常碰到幾個問題:

    1. 每次都要打 IP, 能不能拉捷逕出來, 我常連的那台只要點兩下就自動登入?
    2. 只有那幾種解析度可以選, 沒有我要的…
    3. 遠端桌面連進去的畫面, 跟本機的不一樣. 看不到某些在本機才看的到的訊息…

    原來這些都有解啊… (1) 最簡單, 把設定存檔就好, 就附圖的資訊, 底下有 [Save As], 以後直接點兩下存好的檔案就好了.

    image

    再來, (2) 跟 (3) 其實也有解, 只要先打開 DOS Prompt, 輸入 MSTSC /? 就會出現這個說明畫面:

    image

    答案就在影片中… 加上 /w:1440 /h:900 參數, 就可以用寬螢幕的解析度 1440 x 900 來搖控遠端的 server 了. 想要看 console (本機) 的畫面嘛? 比如有時 service 的 error message 只會秀在 console.. 這時只要加上 /console 參數就好. 整段指令如下:

    image

    開出來的視窗:

    image

    嗯, 看寬螢幕的果然比較爽, 當然這樣也就有機會用雙螢幕了. 小技巧, 需要的人可以參考看看!

    2008/03/06 Tips 技術隨筆

  5. Memory Management (III) - .NET CLR ?

    上篇 & 上上篇 ,同樣的問題,我改用 .NET 開發是不是就搞定了? 其實這篇才是我要寫的重點,只不過引言寫太高興,就是兩篇文章了,咳咳… 有人在問,為什麼我老是寫些冷門的文章? 沒辦法… 大家都在寫的東西我就沒興趣寫了,文筆沒別人好,網站沒別人漂亮,連範例程式都沒別人炫,只好挑些沒人寫的內容…

    大部份討論這主題的文章,講的都是 GC, GC 的 generation,IDisposable,還有 Heap 等等,不過這些知識都無法直接回答這次問題。底下的例子你會發現,預設的 GC 也無法解決 memory fragment 的問題,不過實際上是有解的,只是還要動用到秘技…

    回題,先來看看之前的問題為什麼會是個問題? 萬惡之首都在: 指標 (POINTER)。

    因為有 pointer,因此 C 絕對不能 自動 幫你調整記憶體位置,也就一定會有這種問題。看到為何我在上篇提到的程式碼要把 pointer 的值印出來? 因為這代表我可以輕易拿的到實際的位址,因此任何重新定址 (relocation) 的動作一定會影響到程式的執行。所以最根本的解決辦法就是把 pointer 這東西拿掉。

    年紀較輕的程式語言,如我常提到的 Java 跟 C#,都完完全全的把 pointer 從語言內移掉了,只留下 reference 這類差不多的東西。除了拿不到絕對的 address 之外,其它功能一個都不缺。但是這樣帶來的好處是很明顯的,除了一般書上講到爛的理由: “更安全,更簡易” 之外,很重要的一點就是,像 CLR or JavaVM 這種環境,開始有機會去搬移記憶體配置的區塊,徹底的由系統層面解決這種問題了。

    .NET / Java 回收記憶體的動作是自動的,就是常聽到的 Garbage Collection,而上面提到的 relocation,就是指在回收時順便把剩下已配置的空間排在一起,搬移記憶體區塊所需要的重新定址動作。這種類型的 GC 有個特別的名辭,叫作 compact collection。理論上,.NET 已經具備這樣的條件了,應該要有能力可以解決這樣的問題。

    不過 “可以解決” 跟 “已經解決” 仍然有一段差距,那麼現在的 .NET CLR 到底行不行? 一樣的範例程式用 C# 改寫一下,同樣的試看看,不過這次懶的再放好幾種版本試試看了,除了最大可用記憶體可能有差別之外,其它應該都統一了。我只針對 .NET 2.0 (x86) 一種版本測試,一樣,鐵齒的讀者們,有興趣就抓回去試一試…。

    整段程式碼跟之前 C 版本大同小異,就是照順序配置 64mb 的 byte[],直到丟出 OutOfMemoryException,然後跳著釋放,接著再配置 72mb 的 byte[],看看能不能配置成功? 直到再丟出 OutOfMemoryException 為止,能配置多少記憶體? 這邊為了方便,我直接在 vista x86 系統上測試:

    測試的結果令我想殺人,竟然是 FAIL ? 放掉的空間拿不回來…

    後來想到,程式移除 reference,不見得會立刻釋放記憶體,總得等垃圾車 (Garbage Collect) 來收拾一下… 手動呼叫了 GC,也強迫指定要回收所有的 Generation 了 (呼叫: GC.Collect(GC.MaxGeneraion) ) 再試一次:

    結果好不到那裡去,難到我沒用市政府的垃圾袋嘛? [:@] 查了一下 MSDN,常見的 generation 問題也試過,沒有用。90% 講 CLR GC 的問題都在探討 generation 的問題…  查到某 Java 名人的 文章,提到了 compact collection 比較接近,不過沒有講怎麼明確的啟動這樣的 GC 啊… 後來去翻 .NET runtime 裡關於 garbage collection 的設定,發現還有這玩意… gcConcurrent / gcServer:

    gcConcurrent: Specifies whether the common language runtime runs garbage collection on a separate thread.

    gcServer: Specifies whether the common language runtime runs server garbage collection.

    講的很清楚,不過對我沒啥用。gcConcurrent可能的影響是,也許呼叫後系統還在GC,我的程式就先跑下去了? 因此這東西關掉也許有幫助,再來試一次:

    真慘,一點幫助都沒有… 放掉的 768MB,只撈回 72MB,再來看一下最後一個 gcServer,看它的 HELP 看不大出來什麼是 “server garbage collection” ? 算了,試一下比較快:

    Bingo,看來這個參數下下去才是我預期的結果,放掉了 576MB,後面撈了 648MB 回來。這樣的作法,已經完全不會受到 memory fragment 問題的影響,証實了 compact collection 是有發恢它的效用的,只不過這個參數實際的作用,翻遍了 Google / MSDN,得到的都是很模菱兩可的答案,不外乎是你的程式如果是 blah blah blah 的話就要用 gcServer,這樣會比較好之類的,不過實際的差別則看不大出來。沒有任何一篇文件明確提到 server gc 會做 compact collection (如果這篇不算的話,哈哈),而 workstation gc 不會,也許前面的方式也會觸發 compact collection也說不定,只是時機不成熟…

    抱著不可能的希望,用 Reflector追看看,果然不出所料,Reflector也看不到細節,因為全都呼叫 native code 去了。不過這次的測試,至少確定了,在啟用 gcServer option 之後,CLR 的 GC 是會進行 compact collection 的。

    寫到這裡,本系列文章結束,只是為了在新的平台驗證古早的問題而以,果然時代在進步,以前耽心的問題現在都不再是問題了。這一連串試下來,學到了一課,原來 gcServer 有這個差別,算是值回票價了。最後把我的測試程式碼貼一下,一樣,歡迎拿去各種平台試一下,有不一樣的結果也記得通知我一聲!

    [Program.cs]

    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    namespace ClrMemMgmt
    {
        class Program
        {
            static void Main(string[] args) {
                List<byte[]> buffer1 = new List<byte[]>();
                List<byte[]> buffer2 = new List<byte[]>();
                List<byte[]> buffer3 = new List<byte[]>();
                
                //            
                //    allocate             
                //            
                Console.WriteLine();
                Console.WriteLine();
                Console.WriteLine("1. Allocate 64mb block(s) as more as possible...");
                try
                {
                    while (true)
                    {
                        buffer1.Add(new byte[64 * 1024 * 1024]);
                        Console.Write("#");
                        buffer2.Add(new byte[64 * 1024 * 1024]);
                        Console.Write("#");
                    }
                }
                catch (OutOfMemoryException)
                {
                }
                Console.WriteLine();
                Console.WriteLine("   Total {0} blocks were allocated ( {1} MB).", (buffer1.Count + buffer2.Count), (buffer1.Count + buffer2.Count) * 64);
                
                //        
                //    free  
                //        
                Console.WriteLine();
                Console.WriteLine();
                Console.WriteLine("2. Free Blocks...");
                buffer2.Clear();
                Console.WriteLine("   Total: {0} blocks ({1} MB)", buffer1.Count, buffer1.Count * 64);
    
                //        
                //  GC  
                //            
                GC.Collect(GC.MaxGeneration);  
                     
                //           
                //    allocate  
                //          
                Console.WriteLine();
                Console.WriteLine();
                Console.WriteLine("3. Allocate 72mb block(s) as more as possible...");
                try
                {
                    while (true)
                    {
                        buffer3.Add(new byte[72 * 1024 * 1024]);
                        Console.Write("#");
                    }
                }
                catch (OutOfMemoryException)
                {
                }
                Console.WriteLine();
                Console.WriteLine("   Total: 64mb x {0}, 72mb x {1} blocks allocated( {2} MB).\n", buffer1.Count, buffer3.Count, buffer1.Count * 64 + buffer3.Count * 72);
                Console.ReadLine();
            }
        }
    }
    

    [configuration file]

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>  
      <runtime>    
        <!--<gcConcurrent enabled="false" />-->    
        <!--<gcServer enabled="true" />-->  
      </runtime>
    </configuration>
    

    2008/03/03 系列文章: Memory Management .NET 作業系統 技術隨筆