Feeds:
文章
留言

Archive for 2007 年 08 月

 

MSN SpaceGoogle DocGoogle Blog
Chui-Wen Chiu
2007.08.22

今天收到一個錯誤訊息"The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF", Google 一下有相當多這方面的資料。我就不一一細列,這個錯誤主要是因為 Web Server 回傳的 HTTP 訊息結尾只有 n,而 .NET 實作的 WebRequest 預設情況下,必須符合 RFC 855 實作,也就是結尾必須包含 rn。所以,當 .NET 的 WebRequest 收到這個 HTTP 訊息時,就會出現錯誤。

解法兩個,一個就是讓 Web Server 丟出的 HTTP 訊息符合 RFC 855,另一個就是是讓 WebRequest 睜一隻眼閉一隻眼,亦即將 WebRequest 的 UseUnsafeHeaderParsing 屬性設為 true,這個屬性在 MSDN 文件上得描述如下:

當這個屬性設定為 false 時,會在 HTTP 剖析期間執行下列驗證:

  • 在行結尾程式碼中使用 CRLF;不允許單獨使用 CR 或 LF。

  • 標頭名稱中不應該有空格。

  • 如果有多個狀態列,會將所有額外狀態列視為不正確的標頭名稱/值組。

  • 除了狀態碼外,狀態列還必須有狀態描述。

  • 標頭名稱中不能有非 ASCII 字元。無論這個屬性設定為 truefalse,都會執行這個驗證。

當發生通訊協定違規時,會擲回 WebException 例外狀況,並將狀態設定為 ServerProtocolViolation。如果 UseUnsafeHeaderParsing 屬性設定為 true,則會忽略驗證錯誤。

將這個屬性設定為 true 具有安全性含義,因此只有在需要與伺服器的回溯相容性 (Backward Compatibility) 時,才應該執行此動作。

需要注意的是這個屬性到 .NET 2.0 才新增的,且文件中也提到除非為了 Web Server 回溯相容,否則還是設定為 false。另外,如果要全面套用到每一個使用到 WebRequest 的地方,在 app.config 加上下面的設定:

<system.net>
    <settings>
        <httpWebRequest useUnsafeHeaderParsing="true" />
    </settings>
</system.net>

Read Full Post »

TWSkype 是利用 Twitter 上的最新訊息來更新 Skype 的心情文字或暱稱,有興趣者請先啟動 Skype 3.2.x 或更新版本,然後下載 7138F53BC828450B98B75AC9EB66C977.sparc 安裝。畫面依序如下:

1. 版權宣告

2007082001

2. 賦予 Skype 連接權限,否則 TWSkype 沒有辦法執行

2007082002

3. 執行畫面

你可以依需要將你的 Twitter ID 填寫按下設定,並按下立即更新即可。原則上,訊息每 1 秒更新 1 次,如果訊息內容一樣,更新時間會延長,最大延長到 1 分鐘更新一次。

2007082003

補充:
該程式使用 .NET 2.0 開發,系統必須具有 .NET Framework 2.0 才能運作。

Read Full Post »

(C#) 取得最新的 Twitter 訊息

MSN SpaceGoogle DocGoogle Blog
Chui-Wen Chiu
2007.08.20

測試環境
1. Windows XP Pro
2. Visual Studio 2005

TWessenger[1] 是一套抓取 twitter 最新訊息來更新 MSN 狀態的 Messenger Add-In,主要技術只有兩個,第一個是透過 Windows Live Messenger Add-In API 更新 MSN 狀態文字,第二個是抓取 ATOM 取得最新訊息。本文主要描述抓取最新 Twitter 訊息的方式,首先要取得一個 twitter id,然後可代換成 ATOM URL 如:http://twitter.com/statuses/user_timeline/1713501.atom,其中 1713501 是我個人的 twitter ID,你可以代換成任何 ID。*.atom 的內容類似如下:

<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom"&gt;
  <title>Twitter / Chui-Wen Chiu</title>
  <id>tag:twitter.com:Statuses</id>
  <link type="text/html" href="http://twitter.com/chui_wen_chiu&quot; rel="alternate"/>
  <subtitle>Twitter updates from Chui-Wen Chiu.</subtitle>
  <entry>
    <title>Chui-Wen Chiu: ebXML是一個開放性的電子商務建構標準 (http://www.ebxml.org.tw/big5/index.jsp)</title>
    <content type="html">Chui-Wen Chiu: ebXML是一個開放性的電子商務建構標準 (http://www.ebxml.org.tw/big5/index.jsp)</content>
    <id>tag:twitter.com,2007-08-19T17:51:32+00:00:http://twitter.com/chui_wen_chiu/statuses/214515122</id&gt;
    <published>2007-08-19T17:51:32+00:00</published>
    <updated>2007-08-19T17:51:32+00:00</updated>
    <link type="text/html" href="http://twitter.com/chui_wen_chiu/statuses/214515122&quot; rel="alternate"/>
  </entry>
  <entry>
    <title>Chui-Wen Chiu: 加快OpenOffice執行速度的方法 (http://blog.xuite.net/emisjerry/tech/13078174)</title>
    <content type="html">Chui-Wen Chiu: 加快OpenOffice執行速度的方法 (http://blog.xuite.net/emisjerry/tech/13078174)</content>
    <id>tag:twitter.com,2007-08-19T17:35:47+00:00:http://twitter.com/chui_wen_chiu/statuses/214495672</id&gt;
    <published>2007-08-19T17:35:47+00:00</published>
    <updated>2007-08-19T17:35:47+00:00</updated>
    <link type="text/html" href="http://twitter.com/chui_wen_chiu/statuses/214495672&quot; rel="alternate"/>
  </entry>
…略

接著透過 .NET 的 XmlTextReader 以 SAX 方式循序讀取 ATOM,直到搜尋 <content> 標籤,其標籤內容即為 twitter 內容,因為 ATOM 是從新到就排序,所以第一筆極為最新消息,因此,整個完成的程序如下:

using System;
using System.Xml;

namespace ConsoleApplication1 {
    class Program {
        static void Main(string[] args) {
            // Twitter ATOM URL
            string url = "http://twitter.com/statuses/user_timeline/1713501.atom";
            String statusMsg = String.Empty;
            String username = String.Empty;
            using (XmlTextReader xmlReader = new XmlTextReader(url)) {
                while (xmlReader.Read()) {                   
                    if (xmlReader.Name == "content") {
                        // 取得 twitter 內容
                        String tmp = xmlReader.ReadString();

                        // 內容切割
                        String[] contents = tmp.Split(new char[] { ‘:’ }, 2);
                        username = contents[0];
                        statusMsg = contents[1].Trim();                      

                        break;
                    }
                }
            }
            Console.WriteLine("Username: {0}", username);
            Console.WriteLine("Message: {0}", statusMsg); 
        }
    }
}

執行結果

參考資料
[1] TWessenger

Read Full Post »

來源:電子郵件,真正出處不詳

那是義大利一個電信公司招考部時所發生的一段小插曲。據說,招考部的筆試結束後,這家公司發給所有甄選通過的人一袋綠豆種子,並且要求他們在指定時間,帶著發芽的綠豆回來,誰的綠豆種得最好,誰就能獲得那份競爭激烈、待遇優渥的工作。

果然,當指定時間來臨,每個人都帶著一大盆生意盎然、欣欣向榮的綠豆芽回來,只有一個人缺席。總經理親自打電話問這人為何不現身?這人以混合著抱歉、懊惱與不解的語氣說他感到抱歉:因為他的種子還沒發芽,雖然在過去那段時間,他已費盡心血全力照顧,可種子依然全無動靜!「我想,我大概失去這個工作機會了。」據說,這是那唯一的缺席者,在準備放下電話前所說的一句話。

但經理卻告訴這孵不出綠豆芽的男子說:「你,才是唯一被我們錄用的新人!」

原來,那些種子都是被處理過的,不可能發芽。種不出綠豆芽,正證明了男子是一個不做假的人,公司高層認為,這樣的人必也是一個有道德操守的人。「而這」,總經理說:「就是我們用人的唯一準則!」……

有一句西方諺語說:「如果表現卓越是魚的話,那麼操守就是保鮮劑!」這話的意思是,工作追求卓越固然重要,但不講道德操守,一切都可能落空。就像一條魚,再怎麼美味,沒有保鮮劑,最後還是會腐爛。

同樣,那些志在必得的應徵者,所捧出的綠豆芽雖無比美麗茂盛,但不曾以誠實做為人格的保鮮劑,最後,他們終還是失去了那努力爭取、夢寐以求的工作。

——

不論這則故事是不是真實發生,聖經中也有提到"你們的話、是、就說是.不是、就說不是.若再多說、就是出於那惡者。(馬5:37)",所以,憑著你的良心作你該做的事情,其他的交給神吧~

Read Full Post »

最近再研究 WinVNC Source Code,看到下面這段有點怪的程式碼

BOOL
vncServer::RemoteEventReceived()
{
 vncClientList::iterator i;
 BOOL result = FALSE;
 omni_mutex_lock l(m_clientsLock);

 // Iterate over the authorised clients
 for (i = m_authClients.begin(); i != m_authClients.end(); i++)
 {
  result = result || GetClient(*i)->RemoteEventReceived();
 }
 return result;
}

其中 GetClient(*i)->RemoteEventReceived() 回傳 BOOL。這段 Code 的意思應該是找到第一個執行 RemoteEventReceived() 回傳 TRUE,之後就不要再執行 RemoteEventReceived(),如果是這樣,為什麼不寫成

BOOL
vncServer::RemoteEventReceived()
{
 vncClientList::iterator i;
 BOOL result = FALSE;
 omni_mutex_lock l(m_clientsLock);

 // Iterate over the authorised clients
 for (i = m_authClients.begin(); i != m_authClients.end(); i++)
 {
  if (GetClient(*i)->RemoteEventReceived()){
    result = TRUE;
    break;    
  }

 }
 return result;
}

如此,不是可以避免不必要的迭代和 assign 動作嗎?

Read Full Post »

20070817

Read Full Post »

(轉貼)Hi Ne Ni 我在這裡

原始連結:http://www.im.tv/vlog/personal/909360/2281226

耶和華我的主啊
求你使我放下心中、放下心中所愛
耶和華我的主啊
求你使我打碎心中、心中偶像
直到我在敬拜中獻上自己為祭
無怨無悔、永不回頭
直到我在祭壇那裡得著命定
無怨無悔、我在這裡

Hi- Ne- Ni、Hi -Ne- Ni
燒我差我,我在這裡。
Hi- Ne- Ni、Hi- Ne- Ni
燒我差我
Hi –Ne- Ni

為這世界黑暗的角落,我在這裡
為那不曾被安慰的靈魂,我在這裡
Hi- Ne-Ni

 
最近作什麼事情都懶洋洋,服事上也是如此,原本寫完文章想去睡覺,恰好看到"夏美~~なつみ"留言,所以又連上 I’m Vlog 看有什麼新音樂,再一次看到"獻上感恩的心"那篇寫的唐蒙恩自傳,很受感動,也讓我想了一下自己未來的道路。接著又看到"Hi Ne Ni 我在這裡"這首歌,他的歌詞真是讓我感動
 
"求你使我放下心中、放下心中所愛….求你使我打碎心中、心中偶像。直到我在敬拜中獻上自己為祭…直到我在祭壇那裡得著命定…"
,也許這就是此刻我需要對神的禱告~

Read Full Post »

MSN SpaceGoogle DocGoogle Blog
Chui-Wen Chiu
2007.08.16

Peter[1] 提出一種用於函數式編程的設計模式稱為"Lazy Function Definition"。首天他提出一個問題:

"撰寫一個 foo 函數,並回傳第一次呼叫 foo 的時間。"

針對這個問題,他提出下面四種不同的解法:

解法#1: 傳統解法-全域變數

var t; // 紀錄第一次呼叫 foo 的時間
function foo() {
if (t) { // 假如已經有存放時間,則直接回傳
return t;
}

t = new Date(); // 紀錄第一次呼叫時間
return t;
}

上述解法有兩個問題:

1. 需要一個額外的全域變數 t,該變數有可能在呼叫 foo 時被修改

2. 程式碼在執行階段無法達到最佳效率。因為每次呼叫都需要進行條件評估。雖然上述範例的條件式損耗很廉價,但是真實情況的條件式可能是多層次的 if-else-else-… 結構。

解法 #2: Module Pattern

利用 Cornford and Crockford 所提出的 Module Pattern[2] 可以解決解法#1 的第一個問題,透過 closure 技法將全域變數封裝成只有 foo 內的程式可存取,如下:

var foo = (function() {
var t; // 封裝在 foo 內的變數
return function() {
if (t) {
// 假如已經有存放時間,則直接回傳
return t;
}
t = new Date();
// 紀錄第一次呼叫時間
return t;
}
})();

這種解法仍有解法#1的第2個問題存在,仍需重複進行條件式評估。

解法 #3: 函數即物件-使用物件屬性保存狀態

function foo() {
if (foo.t) {
// 假如已經有存放時間,則直接回傳
  return foo.t;
}
foo.t = new Date();
// 紀錄第一次呼叫時間
return foo.t;
}

這個解法比 Module Pattern 更為簡潔,直接透過物件屬性存放資料,而不需要在產生一個額外的 Function Object。所以也能避免全域變數的問題。但這種解法仍有解法#1的第2個問題存在,仍需重複進行條件式評估。

解法 #4: Lazy Function Definition

var foo = function() {
var t = new Date();
foo = function() { // 改寫原先的函數定義
return t; // Closure t
};
return foo(); // 套用新的 foo 函數回傳值
};

當 foo 第一次被呼叫時,會先實體化一個 Date 物件並重新指定將 Date 物件 Closure 的 foo 函數,透過重新的指定可以改寫原來的函數定義,因為 Date 物件已經被 Closure,所以會一直存在。透過此一解法可以避免解法#1的兩個問題。

因此上述原來的 foo 函數定義可以想像成初始化內部 foo。簡單的說,第一次呼叫 foo 的函數定義如上程式,但之後的程式碼定義則是如下:
function foo() {
    return t; // Closure t
};

上述可透過下面的程式碼進行測試:

var foo = function() {   
    var t = new Date();
    alert(1);
    foo = function() {
        return t;
    };
    alert(2)
    return foo();
};
alert( foo() ); // 出現 1, 2, 日期
alert( foo() ); // 出現 日期

應用:判斷不同瀏覽器的頁面捲動

var getScrollY = function() {


if (typeof window.pageYOffset == 'number') {

getScrollY = function() {
return window.pageYOffset;
};

} else if ((typeof document.compatMode == 'string') &&
(document.compatMode.indexOf('CSS') >= 0) &&
(document.documentElement) &&
(typeof document.documentElement.scrollTop == 'number')) {

getScrollY = function() {
return document.documentElement.scrollTop;
};

} else if ((document.body) &&
(typeof document.body.scrollTop == 'number')) {

getScrollY = function() {
return document.body.scrollTop;
}

} else {

getScrollY = function() {
return NaN;
};

}

return getScrollY();
}

透過 "Lazy Function Definition" 只需要在第一次花費條件式評估,對於重複呼叫的函數特別能夠改善效率。

補充

Firefox/Safari/Opera 的 getter methods[3] 能夠在屬性上模擬 "lazy definition" 如下:

this.__defineGetter__("foo", function() {
var t = new Date();
this.__defineGetter__("foo", function() {
return t;
});
return t;
});

// To the user, foo appears as a plain old
// non-function valued property of the global object.
console.log(this.foo);
setTimeout(function(){console.log(this.foo);}, 3000);

參考資料
[1] Peter, "Lazy Function Definition Pattern"
[2] Eric Miraglia, "A JavaScript Module Pattern"
[3] "Core JavaScript 1.5 Guide:Creating New Objects:Defining Getters and Setters"

Read Full Post »

C++ 使用 JScript 和 VBScript

Live SpaceGoogle DocGoogle Blog
Chui-Wen Chiu
2007.08.08

測試環境
1. Windows XP Pro SP2
2. Visual Studio 2005

範例程式下載

一般 C++ 會使用 Python  作為 Script 引擎,但本文將說明透過 Windows 內建的 Script 引擎,讓 C++ 可以使用 VBScript 或 JScript 引擎。一切的核心是由 Microsoft Scripting ActiveX (MSSCR.OCX)元件所提供,由於是 COM 元件,所以,其他支援 COM 的語言也可透過類似的方法達到。

以下是 C++ 使用 JScript 的簡單範例

#import "msscript.ocx" no_namespace
#include <comutil.h>
#include <tchar.h>

const TCHAR JSCRIPT[]        = _T("JScript");
const int LANGUAGE_NAME_LEN    = 40;

int main(int argc, _TCHAR* argv[]){
    CoInitialize(NULL);

    // 建立 COM 元件
    IScriptControlPtr m_pScript;   
    HRESULT hr = m_pScript.CreateInstance(__uuidof(ScriptControl));
    _com_util::CheckError( hr );

    // 設定 Script Engine
    TCHAR    m_szLanguage[LANGUAGE_NAME_LEN+1];   
    _tcscpy(m_szLanguage, JSCRIPT);
    m_pScript->PutAllowUI( VARIANT_FALSE );   
    m_pScript->PutLanguage( _bstr_t(m_szLanguage ) );

    // 宣告一個新函數
    _bstr_t strCode = _T("function calc(a, b){ return a+b; }");
    m_pScript->AddCode( strCode );

    // 參數設定
    SAFEARRAY* saParameters;
    saParameters = SafeArrayCreateVector(VT_VARIANT, 0, 2);
    _variant_t var;   

    long lIndices = 0;
    var = 33;
    SafeArrayPutElement(saParameters, &lIndices, (void*)&var);   

    lIndices = 1;
    var = 44;
    SafeArrayPutElement(saParameters, &lIndices, (void*)&var);   

    // 呼叫函數 calc(33, 44) = 77
    VARIANT varRet = m_pScript->Run("calc", &saParameters);
    LPCTSTR result = (LPCTSTR)_bstr_t(varRet);

    // 顯示結果
    MessageBox(0, result, _T("Result"), 0);

    m_pScript = NULL;

    CoUninitialize();
    return 0;
}

只要將上述程式稍作修改,即可改用 VBScript 引擎

#import "msscript.ocx" no_namespace
#include <comutil.h>
#include <tchar.h>

const TCHAR VBSCRIPT[]        = _T("VBScript");
const int LANGUAGE_NAME_LEN    = 40;

int main(int argc, _TCHAR* argv[]){
    CoInitialize(NULL);

    // 建立 COM 元件
    IScriptControlPtr m_pScript;   
    HRESULT hr = m_pScript.CreateInstance(__uuidof(ScriptControl));
    _com_util::CheckError( hr );

    // 設定 Script Engine
    TCHAR    m_szLanguage[LANGUAGE_NAME_LEN+1];   
    _tcscpy(m_szLanguage, VBSCRIPT);
    m_pScript->PutAllowUI( VARIANT_FALSE );   
    m_pScript->PutLanguage( _bstr_t(m_szLanguage ) );

    // 宣告一個新函數
    _bstr_t strCode = _T("Function calc(a,b) calc = CInt(a)+CInt(b) End Function");
    m_pScript->AddCode( strCode );

    // 參數設定
    SAFEARRAY* saParameters;
    saParameters = SafeArrayCreateVector(VT_VARIANT, 0, 2);
    _variant_t var;   

    long lIndices = 0;
    var = 33;
    SafeArrayPutElement(saParameters, &lIndices, (void*)&var);   

    lIndices = 1;
    var = 44;
    SafeArrayPutElement(saParameters, &lIndices, (void*)&var);   

    // 呼叫函數 calc(33, 44) = 77
    VARIANT varRet = m_pScript->Run("calc", &saParameters);
    LPCTSTR result = (LPCTSTR)_bstr_t(varRet);

    // 顯示結果
    MessageBox(0, result, _T("Result"), 0);

    m_pScript = NULL;

    CoUninitialize();
    return 0;
}

上述的片段用來了解 Script 引擎是相當好,可是實務上太過於瑣碎不容易維護。所以,[1] 提供兩個好用輔助類別:CScriptObject 和 CSafeArrayHelper。下面使用這兩個類別改寫上述 JScript 的範例。

#include <tchar.h>
#include <windows.h>

#include "ScriptObject.h"
#include "SafeArrayHelper.h"

int main(int argc, _TCHAR* argv[]){
    CoInitialize(NULL);

    CScriptObject*    m_ScriptObj = new CScriptObject();

    // 設定 Script Engine
    m_ScriptObj->SetLanguage( _T("JScript") );

    // 宣告一個新函數
    m_ScriptObj->AddScript( _T("function calc(a, b){ return a+b; }") );

    // 參數設定
    CSafeArrayHelper sfHelper;
    _variant_t var;
    sfHelper.Create(VT_VARIANT, 1, 0, 2);   
    var = 33;
    sfHelper.PutElement(0, (void*)&var);   

    var = 44;
    sfHelper.PutElement(1, (void*)&var);   

    LPSAFEARRAY sa =  sfHelper.GetArray();
    _variant_t varRet;

    // 呼叫函數
    m_ScriptObj->RunProcedure(_T("calc"), &sa, &varRet);
    LPCTSTR result = (LPCTSTR)_bstr_t(varRet);

    // 顯示結果
    MessageBox(0, result, _T("Result"), 0);

    delete m_ScriptObj;

    CoUninitialize();
}

上述三個範例的執行結果都是如下:

參考資料
[1] Ernest Laurentin, "Adding VBScript and JScript support in your C++ applications"

Read Full Post »

終於體會到什麼是"神奇的一刀"

今晚青少契聚會,艾薇姐帶了"神奇的一刀"的活動,事前討論有聽過,可是不太懂,今天親身體體驗後,真是感覺到挺神奇的。什麼是神奇的一刀,源由摘自[1]:

"「文化大革命」時,有一位虔誠的美國宣教士到中國傳福音,被捕入獄,典獄長警告他不准向人傳講耶穌,否則將判他死刑!在監獄中這位宣教
士還是勇敢的向人傳「耶穌基督為世人贖罪被釘十字架」的福音。有一天典獄長非常兇惡的丟給他紙和剪刀,對他大聲吼叫:「你的耶穌如果
是真神,祂必能教你直線的一刀剪出十字架,我就放了你,否則槍斃!」(十字架有8 個直角,怎麼有可能一刀剪出十字架的紙樣?)
於是宣教士謙卑的跪下哭求:「至高全能的神、親愛的主耶穌基督啊!求你憐憫你的百姓,賜下神蹟救他們,因為在你沒有難成的事,讓他們
知道你是創造宇宙萬物的獨一真神!」

禱告後宣教士感覺有一雙奇妙的手牽著他摺紙,直直剪一刀,哈利路亞!竟然出現了十字架!更不可思議的是,將剪下來的十字架和剩下的碎紙一片也不差的,可排「永生」字樣;沒有十字架時,只能排「死亡」或英文HELL(地獄)的字樣。典獄長和周圍的人看了都大大震驚!俯伏在地,呼喊:「耶穌基督的確是又真又活的神!」於是他們都信了耶穌基督,釋放了宣教士。

多麼神奇!一刀顯出宇宙間最偉大的奧妙:「神愛世人,甚至將祂的獨生子賜給他們,叫一切信祂的,不至滅亡,反得永生。」(約翰福音三章十六節)人算什麼?祂竟如此愛我們!全能的神透過一位謙卑勇敢的宣教士,行了一件超越人類智慧所能想像得到的神蹟,賜給我們這傳福音的無價之寶──「神奇的一刀」!"

如果處在生死關頭,你是否能夠一個人冷靜的想出解法呢?我是不行,若沒有神的幫助我想我是作不到的。而且剪完後的碎片還可以拼成中文字,我覺得當下真的是沒有人辦得到,是不是很難理解這種神奇一刀剪出十字架的作法,可以先參考[2] 有圖片教導,或是到校園書房應該也可以買到這本書。[3] 是譚牧師對於奇妙十字架的詳細解說,可以下載投影片觀賞。願上帝透過這個遊戲觸摸到你的心,也讓你瞭解到十字架真理的寶貴~

參考資料
[1] 神奇的一刀
[2] 神奇的一刀.一刀剪出十字架
[3] 譚牧師, "奇妙的十字架"

Read Full Post »

Older Posts »