2018年6月9日 星期六
裝 Gentoo,可以學到什麼呢
首先,在安裝時,就和其他作法不同。它只提供一個最簡單的開機 image,或是久久才出一次的 Live DVD。甚至可以用其他系統,如 Ubuntu,來安裝。
更深入的瞭解 Linux的架構細節,理念
開機
相依性
系統的細節
選擇 Service 管理
出現問題,該重裝嗎?
2018年5月28日 星期一
惱人的 javascript context 和 this
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
測試 javascript this 所指的 context
</body>
<script type="text/javascript">
var tmodel = (function ()
{
var myself;
var set_myself = function() {
myself = this;
};
var self;
var v1 = 'tmodel v1';
var tst = {
self: this,
fun1: function () {
console.log('tst.fun1()');
console.log(this);
console.log(this.self);
if (typeof v1 !== "undefined") {
console.log(v1);
} else {
console.log('v1 is undefined!');
}
}
};
var fun2 = function () {
console.log('tmodel.fun2()');
console.log(this);
console.log(myself);
console.log(tst.self);
if (typeof v1 !== "undefined") {
console.log(v1);
} else {
console.log('v1 is undefined!');
}
tst.fun1();
};
var fun3 = function () {
self = this;
var v1 = 'fun3 var';
console.log('tmodel.fun3()');
console.log(this);
console.log(tst.self);
if (typeof v1 !== "undefined") {
console.log(v1);
} else {
console.log('v1 is undefined!');
}
fun2();
};
/*
* fun1.this => tst
* tst.this => Window,這個不會改變
* tmodel.v1
*/
tst.fun1();
return {
set_myself: set_myself,
fun2: fun2,
fun3: fun3
}
})();
tmodel.set_myself();
/*
* fun2.this => tmodel
* 在執行 tst.fun1 中
* fun1.this => tst
*/
tmodel.fun2();
/*
* fun3.this => tmodel
* fun3.v1 => local variable
* 在執行 fun2 中
* fun2.this => Window
* 可直接存取 tmodel.v1
* 無法存取 fun3.v1
* 在執行 tst.fun1 中
* fun1.this => tst
* 可直接存取 tmodel.v1
* 無法存取 fun3.v1
*/
tmodel.fun3();
console.log('tmodel');
console.log(tmodel);
</script>
</html>
js_this_tst.php:24 tst.fun1()
js_this_tst.php:25 {self: Window, fun1: ƒ}
js_this_tst.php:26 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:28 tmodel v1
js_this_tst.php:36 tmodel.fun2()
js_this_tst.php:37 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:38 undefined
js_this_tst.php:39 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:41 tmodel v1
js_this_tst.php:24 tst.fun1()
js_this_tst.php:25 {self: Window, fun1: ƒ}
js_this_tst.php:26 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:28 tmodel v1
js_this_tst.php:52 tmodel.fun3()
js_this_tst.php:53 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:54 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:56 fun3 var
js_this_tst.php:36 tmodel.fun2()
js_this_tst.php:37 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:38 undefined
js_this_tst.php:39 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:41 tmodel v1
js_this_tst.php:24 tst.fun1()
js_this_tst.php:25 {self: Window, fun1: ƒ}
js_this_tst.php:26 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:28 tmodel v1
js_this_tst.php:74 內部執行 BEGIN
js_this_tst.php:75 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:36 tmodel.fun2()
js_this_tst.php:37 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:38 undefined
js_this_tst.php:39 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:41 tmodel v1
js_this_tst.php:24 tst.fun1()
js_this_tst.php:25 {self: Window, fun1: ƒ}
js_this_tst.php:26 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:28 tmodel v1
js_this_tst.php:52 tmodel.fun3()
js_this_tst.php:53 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:54 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:56 fun3 var
js_this_tst.php:36 tmodel.fun2()
js_this_tst.php:37 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:38 undefined
js_this_tst.php:39 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:41 tmodel v1
js_this_tst.php:24 tst.fun1()
js_this_tst.php:25 {self: Window, fun1: ƒ}
js_this_tst.php:26 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:28 tmodel v1
js_this_tst.php:78 -- 內部執行 END --
js_this_tst.php:36 tmodel.fun2()
js_this_tst.php:37 {set_myself: ƒ, fun2: ƒ, fun3: ƒ}
js_this_tst.php:38 {set_myself: ƒ, fun2: ƒ, fun3: ƒ}
js_this_tst.php:39 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:41 tmodel v1
js_this_tst.php:24 tst.fun1()
js_this_tst.php:25 {self: Window, fun1: ƒ}
js_this_tst.php:26 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:28 tmodel v1
js_this_tst.php:52 tmodel.fun3()
js_this_tst.php:53 {set_myself: ƒ, fun2: ƒ, fun3: ƒ}
js_this_tst.php:54 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:56 fun3 var
js_this_tst.php:36 tmodel.fun2()
js_this_tst.php:37 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:38 {set_myself: ƒ, fun2: ƒ, fun3: ƒ}
js_this_tst.php:39 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:41 tmodel v1
js_this_tst.php:24 tst.fun1()
js_this_tst.php:25 {self: Window, fun1: ƒ}
js_this_tst.php:26 Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
js_this_tst.php:28 tmodel v1
js_this_tst.php:111 tmodel
js_this_tst.php:112 {set_myself: ƒ, fun2: ƒ, fun3: ƒ}
為了在 tmodel 中,能夠存取自身的 context,用一個 myself 的變數來存放自身的 context。但是因為在被呼叫之前,此 object 尚未建立,因此無裡面指定 myself,只能在它的外面執行。可能有更好的解決辦法,但我目前只能找到此方法。
這是為了解決 KnockoutJS 的 computed 變數的問題。
2018年5月19日 星期六
自訂 PHPstorm 的 BrowserRefresh 功能
雖然 PHPstorm 有個 LiveEdit,好像很強大,但是不會用。就參考先前用過的 Sublime 的 BrowserRefresh 功能,想辦法把它搬到 PHPstorm 來用。
我的作法,主要是參考 Sublime Text 的 BrowserRefresh 功能,在 Linux 下,使用 xdotool 來送出瀏覽器的 refresh 指令。在 Sublime Text 下,要有程式底子,才能看懂它在做什麼。但是在 PHPstorm,就簡單多了,只要建好 script 檔,確定功能正常,然後點一點滑鼠就 OK 了。
先建立可透過 xdotool 送出 refresh 指令的 script,並測試確定功能正常。
在 [Settings] > [Tools] > [External Tools] 下,新增 BrowserReferesh,並且,在 Program 欄位,填上 script 的 full path。
然後,在 [Settings] > [Keymap] > [External Tools] > [External Tools] 下,指定快捷鍵,例如,我是指定 Ctrl+Shift+R。雖然,這個已被使用,但幾乎我要用的組合,都被用了,也就不管,用自己習慣的吧。
BrowserReferesh 的程式碼
(chromium-refresh)
#!/bin/bash
xdotool search --sync --onlyvisible --class 'chromium' windowfocus key 'F5' windowactivate
(firefox-refresh)
#!/bin/bash
xdotool search --sync --onlyvisible --class 'firefox' windowfocus key 'F5' windowactivatet
對於 Chrome,有些困擾,會更新到 LINE 的擴充功能,就 chromium 了。因為 Chrome 和 Chromium 才有 Knockout JS 的 extension 可用。而 Firefox 改版之後,一些舊的 extension 都不能用了,另外,在我的 Linux 下,可能是設定的關係,版型變得怪怪的,要改網頁都抓不準,也是促成改用 chromium 的原因。
嗯,自從改用 PHPstorm 寫 PHP 程式,再也回不去了,現在根本就不想用 Sublime Text 了。
2018年4月17日 星期二
ThinkPad USB 小紅點鍵盤更換
更換步驟摘要
- 拆掉螺絲,有兩個在標籤下
- 用拆手機的撬棒,撬開卡筍
- 拆掉新的鍵盤上方的蓋子,電源鍵要拔掉,不然會卡住
- 拆下USB模組,鎖到新的鍵盤上
- 鍵盤模組與下列筆電相容 ThinkPad T400S T410 T410S T410i T420 T420S T420i T510 T510i W510 W520 X220 X220S X220T
8 顆螺絲拆下後,還是打不開來的。但也別再亂找了,懷疑在標籤下,或在塑膠墊下,還藏有螺絲。別找了,塑膠墊撕下後,雙面膠粘性就變差了。
不過多年之後,偶然知道有拆卡筍的翘片,只要用翘片沿着邊框走一圈,上下殼就分開来了。可是自己沒有,就試著用厚一點的保特瓶,剪2片來用。順著邊框塞進去移動一下,卡筍就分開來了,還真方便。自製的翹片,有時用起來不是很順,再加個一字小起子撐一下,也也很就拆開,也不怕弄壞卡筍。
後記 (2021-11-30):專業的作法,用拆手機的翘棒,可以很方便的翘開卡筍,尤其淘寶可以找到金屬翘棒,非常好用。
接下來,就是按圖索驥,到網拍上,找接腳和按鍵長得一模一樣的筆電鍵盤來換。其實也不用啦,因為已經有人研究過了,只要是給 ThinkPad T400S 就可以了。
請參考 Inside ThinkPad USB Keyboard with TrackPoint,這一款鍵盤也可用在下列這些筆電,ThinkPad T400S T410 T410S T410i T420 T420S T420i T510 T510i W510 W520 X220 X220S X220T。其為控制桿為第四代 (TrackPoint IV)。
雖然如此,買的時候,還是再確認一下,確定正面和背面都長得一樣,再下單購買會比較安心。有很多賣家,都說他的是正廠的,也有的說,不用管,有很多家在代工做鍵盤,都是一樣的。是的,聽說 ThinkPad 的鍵盤都是群光 (Chicony) 代工的,可能也有 NMB 和 ALPS 的吧。可以參考「看看你們筆電的鍵盤是誰家OEM的」
(http://www.mobile01.com/topicdetail.php?f=240&t=543557)另外,外接 USB 鍵盤多了一個 USB 模組,用的是光寶 (Lite-On) 的晶片),如紅圈所標示,用一字起子在排線接頭的下面,左右,左右,慢慢的頂,就可以把接頭拆下。再用小一號的十字起子,注意,不是最小的,拆下 USB 模組。
要記得把那個頂端的藍色按鍵的蓋子拆下,不然會卡住。常忘了拆,裝上後才發現又卡住,又要重拆一次。
和普通鍵盤的差別在於,紅圈旁邊那一塊鐵,裡面就 Trackpoint 控制板,是 IBM 在 1996 年取得的美國專利。不過,IBM 這種大公司,真的不在乎賺這種小錢,想買這種鍵盤,還真不容易。雖然,所有的東西都是台灣和大陸做的,IBM只負責收錢。
真希望別家也能做有 trackpoint 的鍵盤,像要是 Cherry 鍵盤配上 Trackpoint,那會多棒啊。等 2016 年之後,專利期過了,會有人做嗎?
來一張連接線的照片,鍵盤模組只是一堆開關,沒有電路。只有指桿控制器有電路,送出十條左右的控制線,合併到那一堆密密麻麻的連線。
小紅點加長
小紅點的霝敏度和加速,必需要設定,不然很難推。另外,把小紅點加長,也會好推一點。之前是用鐵衣架的塑膠帽來延伸,效果不是很好,但在找不到好的方法前,就這樣用了好久。後來買了一堆小紅帽,就想辦法用快乾膠把兩個小紅帽黏在一起,效果還不錯。
使用心得 2018-04-18
雖說沒有原裝與非原裝之後,但使用之後,覺得號稱原廠 3 色印刷的鍵盤,觸感比較好,也比較耐用。搜尋網上的討論,好不好用,好像是要看是那一家產的。不過,ThinkPad 落入中國的手中,品質真的是越來越爛,好壞只能看運氣。最近,有一個是滑鼠的中間的按鍵,卡筍斷了,只好再找一個來換。
後來買了宣稱「最好打的NMB 7列中文鍵盤」,試試看用起來如何。可惜鍵帽和其他的不合,雷射中文輸入又很不清楚,只好用貼紙。但貼紙又很難看,久了還會溢膠。可是,打久了,手感真的有那麼一點差別。
各家號稱全新鍵盤,價格也差很多,從台幣 1,400 到 2,500 都有。現在,變成鍵盤買得到,但外殼搶手,淘寶有不少人再徵舊的 USB 外接 Thinkpad 鍵盤。
七列鍵盤停產,2019-03-15
使用所謂的「最好打的NMB 7列中文鍵盤」將近一年,感覺還不錯,但是網拍的賣家說,七列鍵盤已停產,沒有貨了,只好作罷。真的是,有錢也買不到啊。
2018年4月5日 星期四
在中國,使用 shadowsocks 連上 Facebook 和 Line
這次出去前,原來想辦中華電信的漫遊,可惜預付卡不能辦,只好另想辦法。看到有人介紹 shadow-socks (ss),中文叫影梭,好像不錯。
在網路上找到 docker 的 image,目前有在維護的是 shadowsocks/shadowsocks-libev。就直接建個 docker-compose.yml,直接執行,很簡單,內容如下。
---------------------------------------
shadowsocks:
image: shadowsocks/shadowsocks-libev
ports:
- "443:8388"
environment:
- PASSWORD=xxyyzz2388
restart: always
---------------------------------------
使用的是辦公室的網站,網站只用 80 port,去中國玩的時候,就暫時把 443 port 拿來當跳板用,這樣不用費心地在防火牆打洞。
手機裝的是 Shadowocks client for Android 4.5.3。雖然在手機測試,可以連接,但還是不太確定只開 tcp port 能不能用,只能到實地再測試了。
到了張家界,連上 wifi,開啟影梭,連接一直有問題。在測試時,有時會出現 "無法解析 google.com" 的訊息。改變 "遠程 DNS" 為可以直接連上的辦公室的 DNS SERVER,仍來不行。後來,看到有設定 "個別應用程式的 VPN",就把它打開,並設定 "Chrome 瀏覽器",然後測試連線能力就成功了。再設定 LINE 和 Facebook,都可以順利的連上。
在旅程的其餘的日子裡,只要透過導遊的分享器上網,就能自在的在 FB 打卡,和自己的朋友互動,整個旅程也就變得有趣多了。還有一些的遺憾,大概就是無法幫同團的朋友裝 Shadowocks client,無法讓他們也能用 LINE。
2018年3月22日 星期四
使用 Knockout.js 與 Vue.js 的抉擇
記得在第一次看到 Codeigniter 的介紹時,心動
Knockout.js,很早就出現了,但我是到最近才接觸。在聽到它的名字之前,已經聽過 AngularJS,然後是最新出現的 Vue.js,最後,才知道 Knockout.js。也就是說,我知道 Knockout.js 時,基本上,它已被判死刑。
2018年3月7日 星期三
PHP 連接 MS SQL Server 2000 的考量
但是,使用 PHP,微軟提供的官方版本,只支援連接 SQL Server 2005 以上的版本。有人重新編譯,將限制拿掉,雖然可以連接 SQL Server 2000,但是使用上會有問題。
例如 $rs = DB::select("SELECT * FROM ifcrfcotmp where id=:p1", ['p1' => '']);
會出現 Invalid precision value 的錯誤。使用 Query builer 也有同樣的問題,ORM 我沒有用,所以沒測過。
這種問題,使用得在應用上,很不方便。因為使用 parameter 或 Query builer,可以處理特殊字元,如單引號,尤其可以避免 sql injection 的攻擊。
在 Linux 下面,PHP 7.0 以上的版本,可以使用 dblib 來連接,也不會有上述問題。
在 Windows 的平台,Laravel 5.2 之後,可以透過 ODBC 來連接 SQL Server 2000,但是無法傳回 UTF-8 編碼的字串,必須轉換。
現在辦公室,還在大量的使用 Windows Server 2003,只能跑 PHP 5.4,也就只能用 Laravel 5.0。Laravel 5.2 中,連接 ODBC 在單一的程式中,其在 Laravel 5.0 也可以使用,可在 composer.json 中,"scripts" 的 "post-update-cmd" 部分,加上下述命令,在 update 之後,以 5.2 的程式覆蓋。
"cp SqlServerConnector_52.php vendor/illuminate/database/Connectors/SqlServerConnector.php"
Laravel 的 database 設定檔,內容如下
'connections' => [
'odbc' => [
'driver' => 'sqlsrv',
'database' => '', // 需保留,可空白
'username' => 'uid',
'password' => 'pwd',
'charset' => 'utf8', // 這設定是沒用的
'prefix' => '',
'odbc' => true, // Tell the driver to use ODBC connection
'odbc_datasource_name' => 'Driver={SQL Server};Server=db_host;Database=db_name;', // Only the name, don't include 'odbc:' prefix
],
],
因此,難以抉擇的是,該用那一種方式。以前都是用微軟的driver,碰到錯誤再處理,或將長度為0的字串改為長度為1的空白。或偷懶,直接串 sql 指令。這些都不是好的解法。
若改為使用 odbc 來連接,雖然要在 big5 與 utf8 之間轉換,麻煩些。但比較麻煩的問題是,轉換之後,有些字會不見,如簡體字。
例如 " 机器人公民索菲亚",轉成 big5,再轉回 utf8,就變成 "机器人公民索菲?",最後一個字變問號了。
小結
整理這篇文章,供自己日後參考,以免以後又再做重複的比較,浪費時間。很顯然的,要連接 SQL 2000,一個是用 Linux + PHP 7.0 + dblib,若使用 Windows server 2003 + PHP 5.4 + sqlsrv driver,就麻煩點,處理好長度為0的字串。odbc 不予考慮,少字的問題,是無法控制的。









