2017年6月25日 星期日

木工機絲

前年家裡房子拆了,留下一堆木材(角材),又厚又重,且每根長度都不同,造成整理堆疊起來很佔空間,非常礙眼.於是想一想看有沒有可以利用的地方,第一個念頭就是做成桌腳,再找一找廢棄的木板,翻變家裡頭,剛好有兩塊120cmX60cm 的木板,一片用來當桌面,另外一塊當作收納底座.但想到要鋸木頭,就頭大,如果要用手鋸,要很久又很累,心一橫,索性上網買個電鋸回來,所謂工欲善其事必先利其器,當然要先作功課,畢竟一台不便宜,常人言:工欲善其事必用新台幣,真是一針見血.

我要鋸的廢木材大概 6cm ~ 7 cm厚又很硬,原本打算要買 GST65,價格不到 2000新台幣,似乎經濟又實惠,但網路上說 400W 的電鋸似乎像是一台玩具,功率太低,實際他的有效輸出要打個折,可能1/3 馬力都不到, 1馬力約等於 746W,心想可能無法負荷去切割這麼厚的木板,高瓦數的圓鋸聽說很危險,非專業的人士恐要很小心使用,線鋸似乎安全多了,於是鎖定一台線鋸,人生第一台線鋸,先用知名品牌的,也許安全係數會好一點,穩定度耐用度等等這些可靠性指標可能都比較好(其實心裡因素佔的層面恐怕是最高的),最後,網購花了 3400 新台幣買了一台650W的 GST75BE,查了一下官網,實際有效輸出是360W,大約 1/2 馬力,同品牌線鋸還有更高馬力的,但價格更高,或許等更專業一點後有需要再說,隨機附了一隻鋸片 T144D,但太短了,無法切割 7cm 厚木材,於是又加購了較長的鋸片 T344D.切割後的木材,邊邊多少會有銳角,且廢棄木頭也難免有毛刺,再花個1050新台幣添購了一台砂紙機,想說把木材磨平點免得傷人.上購物網看到拆螺絲的神奇機絲,好奇就訂購了一組,後來想用線鋸來切鐵片或是將木台切漂亮一點,就多買了一些鋸片,像是 T345XF 3 支, T318A 5 支, T101B 5 支, T344D 3 支,前兩個是用來鋸鐵的,後兩個則是用來鋸木頭的,其中 T344D 最長(整隻長 15cm, 扣掉刀柄用來切 7cm 應該不成問題),考慮到將來也許會運用它改裝當作桌鋸使用.就這樣零零總總花了將近750塊新台幣,算一算總共花了約新台幣 5200元.網購東西這種欲望真的很邪惡,看到心動的,手一滑就無法控制了.

收到貨後,興致沖沖的趕快架起木頭開始施工練功.第一刀小心翼翼的切了下去,花了幾秒鐘就把厚厚的木材一刀兩斷了,摸一摸斷面還算平整,真是大快人心.想說待我完成桌子後,這錢就花的值得了,鋸了幾次後發現,要鋸成垂直線,真的有相當難度,如果沒有平整的水平桌面,即使垂直地面下刀,切斷後去看他的斷面,會發現面雖然是平的,但卻是斜面.因此之後要切之前,都先拿水平泡泡量一下水平再切,但終究還是切不直,再仔細去看斷面,很像是微微的 S 型曲面.一旦桌腳鋸不直,桌子就不會穩.上網看了一堆影片,有人用培林導引鋸片,並倒裝成桌鋸,再用直線靠山導引木頭去鋸才會直.但花時間且工程太大,如要買工作台,又要不少花費,到這時終於體會出原來線鋸並不是用來鋸直線的,而圓鋸也不是鋸圓線用的.或許換個話應該說線鋸是用來鋸曲線的,而圓鋸比較適合鋸直線的.同樣的價錢,想當初應該買圓鋸才對.但木已成舟,只好將就點.接著鋸了較薄( 3cm)的木材當旁邊支柱,這斷面看起來就直多了.我想應該是鋸片太長,當鋸厚木材時,可能是反彈力量過大,導致線鋸的培林偏向,使得無法正確導引成一直線造成扭曲的s平面.仔細看T344D 規格上寫著:厚建築木料,軟木 5-100mm, 我想它只限軟木,而我鋸的可能是硬木吧!最後再到五金行買了4個輪子鎖到桌腳,桌旁支撐橫桿再多鑽點螺絲鎖上去,用直角鐵片加強,鎖住四個角落,才勉強解決了桌子搖晃不穩的問題,木工收納桌完工,雖然長的很醜,但是還蠻實用的,想到很多東西要收納,又再利用廢棄衣櫥的厚板邊,並利用線鋸裁出需要的長度,裝到桌子中間,變成另一層收納板,這樣子總算可交待了,這5200塊裝備的第一項任務就圓滿達成.後續再想想該如何好好利用(例如改裝成桌鋸).畢竟多完成一項任務,錢就花的更值得,這 DIY 樂趣的成就感自然不在話下.

之後突發起想,有沒有將不直的斷面加工變直面的工具.如果用圓鋸,大概沒問題,但一想到危險兩個字就縮手了.刨木機上網看了看,感覺太貴又不怎麼實用,路達雕刻機也許是個好玩意,衝動之下,不小心手殘,竟又花了約新台幣2800添購了新裝備,包含主機用的配件有下壓式底座,角度傾斜座,另外加上12支修編刀,整組 700多瓦的修邊主機內含修邊基座及滑輪修邊制具,加上直線導規及一片圓形導規,到網路上比一比價錢,真的是便宜到爆.要是買回來,鐵定賺到.因為這是我第一次上露天拍賣買東西,既期待又怕受傷害,當收到到機器,打開一看,外觀品質,很像是工廠打下來的次級品,有不少地方看起來不是很滿意,甚至塑膠接頭還有破損的地方,可能不會影響到修邊的功能,許多像是螺絲的地方用衛生紙擦拭,還看的到鐵鏽(對廠商來說或許功能才是一切,但對消費者來說,其實會很無言),若不用機油保養擦拭大概很快就報銷了,這時才有所體悟,原來便宜的背後必定有挑惕的地方(切記,切記,切記!)趕緊試試看是否有功能上的瑕疵,無話可說,摸摸鼻子,算了接受吧,對於木工的門外漢,也許夠用了,便宜終究戰勝了一切.就不要再強求了.有人說高轉速的路達雕刻機(這台每分鐘轉速可以從10000到30000之間作6段調整)是一個危險物品,目前我還深刻的警惕著,到現在都還沒用它施工過,暫時先到 youtube 上看看網路達人的使用心得,有了概念再玩也不遲,畢竟這等便宜貨,主機不過1400左右,壞了也不算心疼,等熟練了有需要再升級買其它有品牌的來用.再說配件屬金屬材質,儲存的當應該可以保存很久,就當作這2800是買配件用的.上網去看,其實雕刻機的配件還蠻貴的.清點附件時發現修邊機共附了3個修邊刀夾頭(有 6mm, 6.35mm, 8mm), 視雕刻刀的柄徑要適時更換.再清點一下還發現有一組碳刷附件,萬一壞掉要自行替換,這應該難不倒我,馬達的東西,要壞其實很難,如果有電路板另當別論.把玩了一陣子,發現以前插電式電鑽的把手竟然可以安裝在這組雕刻機的下壓底座當推動把手用.

最近看了許多影片,對於路達雕刻機(trim router)終於有了一些概念,雕刻機附了許多零件,都是有用途的:

1. 圓形導規(英文稱之為 guide bushing)是利用其突出的圓形外圈貼邊去修飾雕刻刀經過的地方(就把它當成培林滑行用,只不過要靠人力去推動基座,產生滑動效果),如果雕刻刀直徑是A,圓形導規最外圈直徑是 B(B一定大於A,這樣雕刻刀才可伸的出去),那修過的地方,邊邊偏移的距離等於 (B-A)/2

2.如果利用雕刻刀的培林貼邊去滑動, 此時 B 相當等於 A,因此修邊偏移距離等於0,如同去複製樣板邊邊的效果,英文稱之為 template guide,或者翻譯成樣板導規.

3.基座的所附的貼邊輪也是類似培林(滾珠軸承,英文稱之為 ball bearing)的滑行效果,好處是可以上下調整貼邊的參考點,用法就是要用眼睛去觀察將要貼的邊與刀口邊成一直線,這樣就可挖出垂直線來,也是使用樣板導規的方式來修邊.

4.平行導規可以貼邊後去挖內槽,也可固定後,隨者平行板的旋轉而挖出一圈圓型,類似圓規的作用.

5.使用 T型修邊刀,應該先用小直刀挖出小溝槽,接著用較大直徑的T型刀深入再挖出 T 槽

6. 下壓式底座(英文稱之為 plunge base)可以用來精確的挖出溝槽深度,可以事先做好樣板(樣板深度已測量過)作為比對依據: (a)將雕刻刀下壓至樣板底部(b) 暫時鎖定下壓底座,固定雕刻機工作深度,調整尺下降刻度到工作面固定位置,有三個可旋轉的預設刻度可調整(c) 釋放下壓底座 (d) 回到工作台,貼到要挖的木板上(e)打開電源,直接下壓至工作面,鎖定底座,開始精確深度挖槽,這樣挖出來的深度就等於樣板的深度.

7. youtube 上有教人製作制具,英文稱之為 jig,因此會用一些木板當檔牆,英文稱之為 fence,用來挖木板的中間溝槽(英文稱之為 dado 或 groove),或挖邊槽(英文稱之為 rabbet)或是製作榫接(英文稱之為 mortise或tenon),或是直接鑲嵌 (英文稱之為inlay),而各種雕刻刀稱為 router bits,這些專有名詞大概要記一下,這樣搜索影片會比較方便點. 修邊刀有分很多種類,像是 Straight & groove forming bit(直線槽刀,通常不帶培林的修邊刀直接挖槽), Laminate trimming bits(層壓修邊刀,通常前端帶有基準邊的培林刀),Edge forming bit(產生花邊的刀,通常也帶有培林),flushing trimming bits(培林直徑與刀柄直徑相同,用來將邊緣刮除乾淨)...

8. 修邊刀的筒夾一定用用板手扭緊,否則脫落時修邊刀在裡面滾動著就變成磨刀器,修邊刀是靠很緊的磨擦力固定的,一旦被磨平,就固定不住,當然就報銷了,因此筒夾是消耗品,要緊記.

9.所有要修邊的木材,務必故固定牢靠,否則高速圓周運動修產生的切線動力,會將木材帶動或是把碎屑亂拋,恐會造成危險,一旦有不正常振動或不穩定就必須關機確保安全.

10.要作裝備保養時,務必關閉電源.基座的塑膠部份千萬不要用汽油,揮發性的物質或酒精去擦拭,因為,可能會產生化學反應而導致褪色,變形龜裂.

2017年5月5日 星期五

理解 iptables 的使用


網路上的文章幾乎都使用舊版說明,雖然過時,但仍然可以學點常識.
iptables 資訊:  http://www.iptables.info/en/iptables-contents.html
各鏈條流程圖:  http://www.iptables.info/files/tables_traverse.jpg

列出 iptables 指令的使用方式:
        iptables   --help

        iptables   -h

常用的命令列格式:
      iptables   規範命令   鏈條名稱   規範選項
或     
      iptables   規範選項   規範命令   鏈條名稱

其中 規範選項  的各項順序只要處理得當,可以依照喜好自由調換位置.iptables 鏈條(chain)的規範命令是以"-大寫簡稱"或"--小寫全名"擇ㄧ使用:
   -A 或 --append  用於附加鏈條規則
   -C 或 --check  用於檢查鏈條規則是否存在
   -D 或 --delete  用於刪除鏈條規則, 以數字 1 為基準當第一條鏈條
   -I 或 --insert  用於插入鏈條規則, 若沒設定插入位置, 預設是插入當作第一條規則
   -L 或 --list  用於詳細列出鏈條規則
   -S 或 --list-rules  用於顯示鏈條簡表
   -N 或 --new   用於自訂鏈條規則
   -P 或 --policy  用於鏈條的預設政策,當鏈條的具體行動沒指定時將啟用(ACCEPT 或  DROP)
   -E 或 --rename-chain  用於改變鏈條名稱
   -R 或 --replace  用於改變鏈條的順序
   -F 或 --flush  用於刪除鏈條的規則
   -X 或 --delete-chain  用於刪除自訂鏈條
   -Z 或 --zero   用於鏈條計數器歸零

目前版本(version 1.6.0) iptables 內部共有五個表格(filter, mat, mangle,raw,security)可由規範選項 -t 來指定),每個表格各有不同的鏈條名稱,使用 -L 可以列出各表格的鏈條規則:
         $iptables    -t    filter    -L
由此來看 filter 有  INPUT,   FORWARDOUTPUT   3個鏈條,接著看:
         $iptables    -t   nat     -L
因此 nat 應該有  REROUTINGINPUTOUTPUTPOSTROUTING   4個鏈條,再來看:
         $iptables    -t   mangle    -L
所以 mangle 有  PREROUTINGINPUTFORWARDOUTPUTPOSTROUTING   5個鏈條
另外兩個 raw, security 似乎比較少用,詳細可上網找文章閱讀看看.

規範選項部份除了版本(-V--version)以外,都是以"-小寫簡稱"或"--小寫全名"擇ㄧ使用,有些選項可以使用驚嘆號 ! (反邏輯),將選項的邏輯允以反向(也就是在原本用意加上'非'這個字眼),例如:
  !  -p 或 --protocol  用於網路協定,像是  tcp 或 udp 或 icmp 或 all
  !  -s 或 --source  用於來源網址或網域, 像是  ipaddress 或 ipaddress/mask 之類的位址
  !  -d 或 --destination 用於目標網址或網域,像是 ipaddress 或 ipaddress/mask之 類的位址
  !  -i  或  --in-interface  用於來源網路界面, 像是 lo eth0 之類的名稱
  !  -o 或 --out-interface  用於目標網路界面, 像是 lo eth0 之類的名稱
  !  -f 或  --fragment  用於像是片狀的封包 ???
 只要不加驚嘆號, 就如字面上意義(正邏輯).

只能用正邏輯的規範選項有 :
   -j 或  --jump  指定目標(target), 可用 ACCEPT 或 REJECT 或 DROP
   -g 或 --goto  直接跳進指定的鏈條規範不返回
   -m 或 --match  使用指定模組來拓展匹配
   -t 或 --table   指定表格,可有 filter 或 nat 或 mangle 來過濾封包, 若未指定,則內定用 filter
   -w 或  --wait  等待表格鎖定時間,以秒為單位
   -v 或  --verbose  顯示冗餘資訊,像是目前計數器的數值... 等等

其它正邏輯選項還有:
   -4 或 --ipv4   用於 ipv4  的封包 ???
   -6 或 --ipv6  用於 ipv6 的封包 ???
   --modprobe=載入外部模組 ???
   -n 或 --numeric   網路位址(ip address/netmask)及端口(port)使用數字展開
   -x 或 --exact  展開數字 ???
   --line-numbers  當顯示列表時,前面附加行數的順序.

在 linux mint 系統上執行 iptables 必須要有 superuser 權限,自行定義一個變數(例如 iptables) 便於重複利用並簡化輸入:
    iptables='sudo iptables'
 
將鏈條名稱與規範選項合併就成為該鏈條的一個規則, iptables 如果定義規則時沒用選項 -t 來指定來表格,將會用 filter 當作內定表格.而且不同的表格將有不同的規範選項,因此底下說明可能只適用於 filter 表格(等同使用了 -t filter).

假設要設定 filter 表格內 OUTPUT 鏈條的規範,使用選項匹配模組(-m owner )去匹配是否等同指定的使用者(--uid-owner   $USER),如果選項匹配成功,執行指定目標(-j   REJECT ).將上述規則定義成一個變數 rule 方便後續使用:
    rule="OUTPUT   -m   owner   --uid-owner   $USER  -j   REJECT"

鏈條規範的執行流程會從所有設定規則的第一條開始一個個往下匹配,直到匹配成功去執行具體行動,如果在規則中沒有用 -j 設定目標,則會往下一條規則繼續匹配,如果全部規則都匹配不成,也就無具體行動,因此該鏈條的預設政策就會啟用(預設政策的規範選項僅可以是 ACCEPTDROP),要改變預設政策,使用規範命令 -P,例如:
     $iptables -P INPUT ACCEPT
     $iptables -P FORWARD  DROP
     $iptables -P OUTPUT  ACCEPT

使用  -A 添加規則到最後一條:
    $iptables   -A   $rule

如果認為規則很重要,可以使用 -I 插隊變成第一條規則:
    $iptables   -I   $rule

-L 可以詳細列出表格鏈條的規則,附加 --line-numbers 會將規則的順序一起列出:
    $iptables   -L   --line-numbers

或是用 -S 顯示表格鏈條的簡表:
    $iptables   -S

只要語法正確,就會被加入到鏈條的規則內, 因此相同的規則可能會重複,因此先檢查再添加可以防止重複添加,使用 -C 可以先檢查想啟用的規則是否存在,若存在只要輸出該規則的訊息:
    $iptables   -C   $rule   &&  echo Exist:$rule  ||  $iptables   -A   $rule

如果上述規則設定成功, 使用瀏覽器試試看,應該無法上網了.用 -D 可以刪除剛剛設定的規則:
    $iptables   -D   $rule

-D 只刪除第一個匹配到的規則,如果規則有重複,只會刪除第一個.如有需要可以執行 -D 多次直到刪除為止,或是用 -F 一次清除內部鏈條(但不含自訂名稱)所有的規則
    $iptables   -F  OUTPUT

-N 可以在表格自訂新鏈條,例如自訂一個有意義的鏈條名稱 OUTtcp:
     $iptables   -N   OUTtcp

一旦自訂鏈條名稱定義完成,就可以像正規鏈條一樣去定義規則:
     $iptables    -A   OUTtcp    -j   DROP

在相同表格內的自訂鏈條經由鏈條規範,使用選項 -j 當成目標(target)跳進去,例如:
     $iptables    -A   OUTPUT   -p   tcp   -j   OUTtcp

-X 可以清除自訂的鏈條(由 -N 指令去定義的鏈條),連同自訂鏈條名稱及規則都一併清除,如果 -X 後面不指定鏈條名稱,則清除全數自訂的鏈條:
    $iptables   -X   OUTtcp

用  -F  可以清除鏈條的規則,如果後面不指定表格,則只清除預設表格(-t filter)的鏈條規則(但不會清除自訂鏈條的名稱):
     $iptables   -F   OUTPUT

通常一開始設定 iptables 時,不僅要清除所有鏈條(包含自訂的)規則,連計數器也都一併清除為零,避免被無端的規則所干擾.
清除預設表自訂鏈條:
    $iptables   -X
清除預設表鏈條規則:
    $iptables   -F
清除預設表鏈條計數器:
    $iptables   -Z 

要注意的是 -P 所設定的預設政策(預設是全數鏈條 ACCEPT 開放)並不會因為清除而重設,只要之前有設定好,它就會持續有效.常用的伺服器端口,可以檢查 /etc/services 檔案內容,就可以略知一二,它包含有 tcp 及 udp 兩種通信協定:
    cat /etc/services | more

在 linux mint 系統,有些內部的 porcess 可能會使用 udp 端口相互溝通,如果全擋,怕會無法運作,可以用 ifconfig 查一下對外 ip 的界面,目前查到的是 enp2s0,因此管制該網路界面的輸出鍊,就能抵擋大部分的網路運作了.先清除所有規則,設定好預設政策,再分別設定 tcp 及 udp 的規則,把不符合規則的端口都丟棄:
    $iptables   -F
    $iptables   -P   INPUT   ACCEPT
    $iptables   -P   OUTPUT   ACCEPT
    $iptables   -A   OUTPUT   -o  enp2s0   -p    tcp     -j    DROP
    $iptables   -A   OUTPUT   -o  enp2s0   -p    udp    -j    DROP 

這樣子就阻擋了對外所有網路第三層的 tcp/udp 通信協定.執行 ping www.google.com.tw 看看,應該無法得到回應.但若直接用 ping 168.95.192.1 卻是可以的, 那是因為 ip 屬於第二層通信協定.只要插隊設定一條輸出鏈(-I   OUTPUT)的規則,管制網路界面(-o   enp2s0)的通信協定(-p   udp),比對端口(--dport   53),確認行動(-j   ACCEPT):
   $iptables   -I   OUTPUT -o   enp2s0   -p   udp   --dport   53   -j    ACCEPT

把 udp 端口 53 打開,主機就能向DNS(Domain Name Server)查詢到 ip 位址,接著就會得到 ip/icmp 回應,但此時仍無法用瀏覽器瀏覽網頁, 因為 http 是用 tcp 端口 80, 而 https 是用 tcp 端口 443.為了一次開放多個 tcp 端口,可以插隊設定一條輸出鏈(-I OUTPUT)的規則,管制通信協定(-p tcp),調用匹配模組(-m multiport),比對離散端口(--dport 80,443),確認行動(-j ACCEPT):
   $iptables   -I  OUTPUT  -o   enp2s0   -p   tcp -m multiport   --dport   80,443   -j  ACCEPT

此時用瀏覽器上網應該就能暢行無阻了,對於其它 tcp  端口,例如 ssh 端口 22, ftp 端口 21 等都可依樣畫葫蘆自行設定規則,總結這次瀏覽網頁所需設定的規則,使用預設表格(-t filter):
    iptables='sudo iptables'
    $iptables   -F
    $iptables   -P  INPUT   ACCEPT
    $iptables   -P  OUTPUT   ACCEPT
    $iptables   -A  OUTPUT   -o  enp2s0   -p  tcp     -j    DROP
    $iptables   -A  OUTPUT   -o  enp2s0   -p  udp    -j    DROP
    $iptables   -I   OUTPUT   -o  enp2s0   -p  udp   --dport   53   -j    ACCEPT
    $iptables   -I   OUTPUT   -o  enp2s0   -p  tcp -m  multiport   --dport   80,443   -j  ACCEPT

nat 表格的轉向(REDIRECT)的功能.由插入 nat 表格事前輸入鍊(-I PREROUTING  -t nat)當範例,當從外部(-i   enp2s0)接收到的封包時,原本要傳給 tcp 端口 80(-p  tcp  --dport 80)的,事先改成(REDIRECT)端口 3128(--to-port  3128),之後才進主機作後續鏈條的處理(可先參考網址有關鏈條的流程會比較清楚脈絡: http://www.iptables.info/files/tables_traverse.jpg)
    $iptables -I  PREROUTING   -t   nat  -i   enp2s0  -p  tcp   --dport  80   -j   REDIRECT   --to-port   3128 

送出去的封包更換端口也可以透過轉向的功能,由插入 nat 表格的輸出(-I OUTPUT -t nat)當範例,將原本要送出 tcp 端口 8888(-p tcp --dport 8888)的封包,換成(REDIRECT)端口 80(--to-port  80)後直接丟出去:
    $iptables -I  OUTPUT  -t   nat  -p   tcp  --dport   8888  -j   REDIRECT   --to-port   80

上述端口轉向並不一定會用到 ip 路由(Route)的功能,如果只是轉向特定端口,就不必將 /proc/sys/net/ipv4/ip_forward 打開.要將 linux 當作 ip 分享器,需利用超級使用者的權限開啟 ip_forward 的功能,再用 iptables 設定 nat 表格的事後鍊(POSTROUTING)把送出封包的來源位址(soure  ip)直接替換成主機位址,有兩種方式可以達成 ip 分享的目的:

第一個,當主機的位址是動態取得時,簡單設定 nat 表格的事後鍊(-A  POSTROUTING  -t  nat)讓 linux 內核把要送出去的封包(-o   enp2s0)自動改裝(-j MASQUERADE),變成 ip 分享器:
    sudo su
    echo 1 > /proc/sys/net/ipv4/ip_forward
    iptables  -A 
POSTROUTING  -t  nat    -o   enp2s0    -j   MASQUERADE


另一個是當主機固定位址時,把要送出去的封包(-o   enp2s0),直接用主機位址(假設 ip = 10.0.0.1)替換掉來源位址( -j SNAT --to-source),雖然麻煩一點,但速度較快:
    iptables  -A  POSTROUTING  -t  nat   -o   enp2s0   -j  SNAT --to-source 10.0.0.1 

如果要處理經 nat 改裝的封包,可以設定事前(-A PREROUTING -t nat),由網路界面收到的封包(-i   enp2s0),事先更換封包的目標位址(-j  DNAT --to-desination)由主機(10.0.0.1)來取代,藉此將它轉給主機再作後續處理:
    iptables  -A  PREROUTING  -t  nat  -i   enp2s0   -j  DNAT --to-desination 10.0.0.1
.

2017年5月2日 星期二

Wine 利用 winepath 轉換 linux 系統上檔案位置到 Wine 系統上使用

為了要用滑鼠拖拉(drag and drop)的方式開啟檔案,首先執行檔要能接收檔案,若是用 bash script 可以使用 $1 接收第一個參數,經由命令變數 $(winepath -w %1)可以轉換給 Wine 應用程式使用.而使用副檔名 .desktop 的執行檔則可以用  %f 來接收滑鼠傳來的檔案位置,同樣也是利用命令變數 $(winepath -w %f) 轉換給 Wine 應用程式加以使用.類似像這樣:
[Desktop Entry]
Exec=env  WINEPREFIX=/home/mint/.wine  wine  'c:\\windows\\notepad.exe' $(winepath -w %f)
Type=Application

記得將它存檔並設定為可執行檔,這樣就可以利用滑鼠拖拉檔案到該執行擋上,Wine 應用程式就可以從滑鼠接收到檔案接著轉換檔案位置,最後在 Wine 系統中開啟檔案.

當然如果有建立 mswin  群組,並將 mint 加入該群組, 透過切換群組開啟檔案,只要將上述檔案稍微修改一下改用 sg 命令:
[Desktop Entry]
Exec=sg mswin "env  WINEPREFIX=/home/mint/.wine  wine  'c:\\windows\\notepad.exe' $(winepath -w %f)"
Type=Application

 Wine 已更新到 2.7 版了, 參考網站: https://wiki.winehq.org/Ubuntu

sudo dpkg --add-architecture i386
wget https://dl.winehq.org/wine-builds/Release.key
sudo apt-key add Release.key
sudo apt-add-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ xenial main'
sudo apt-get update
sudo apt-get install --install-recommends winehq-staging

2017年5月1日 星期一

避免 Wine 的應用程式開啟網路

參考文章: https://askubuntu.com/questions/19346/how-to-block-internet-access-for-wine-applications
有些 windows 應用程式太邪惡了, 許多病毒或是木馬甚至原版軟體都有可能偷偷上網傳遞資訊,使用者根本無法察覺,如果將它安裝成 Wine 的應用程式想必也不例外,因此有必要限制 Wine 的網路行為.在 linux mint 可以用 groupadd 產生新的群組,用 adduser 將使用者加入這新的群組,再透過 iptables 阻斷群組的網路行為:
       sudo groupadd  mswin
       sudo adduser  mint  mswin
       sudo iptables  -A  OUTPUT  -m  owner  --gid-owner  mswin  -j  REJECT

往後只要用 sg 先切換使用群組,之後才載入 Wine 的應用程式(例如內建瀏覽器 wine iexplore.exe),這樣就能徹底隔絕 Wine 應用程式的網路運作了.
       sg  mswin  "wine iexplore.exe"

如果要用滑鼠雙擊就可執行的 Wine 應用程式,可以編輯一個檔案副檔名用 .desktop 命名, Exec 指定內容則改用 linux 的 sg 切換群組並包住 env 命令,像這樣:
[Desktop Entry]
Exec=sg mswin "env  WINEPREFIX=/home/mint/.wine  wine  'c:\\windows\\notepad.exe'"
Type=Application

要注意的是 env 命令的部份要用引號括起來. 在 wine 的應用程式敘述用單引號而整個 env 部份則改用雙引號.單引號與雙引號的不同在於:單引號裡面內容,如果有$變數或執行()命令或者跳脫字元\時,並不會展開賦值(evaluate),而是一成不變的照實敘述,但如果放在雙引號裡面則會先展開變數才會執行後續動作.記憶口訣: 一層不變(一成不變), 二度就要(二度就樂一ㄠˋ)

2017年4月30日 星期日

執行備份的 wine 應用程式

安裝完 wine 的應用程式後,預設全都會放在 ~/.wine 底下, 可以先切換到家目錄(~)再將 .wine 目錄打包備份,之後把 wine.tgz 移至別處加以收藏,在終端機輸入以下命令將 .wine 打包:
       cd  ~
       tar  -zcvf  wine.tgz  .wine

如果有任何意外破壞了 .wine 的目錄結構,可以先刪掉該目錄(rm -rf .wine)再藉由回存指令(tar  -zxvf wine.tgz), 就可以恢復該目錄所有檔案,並不需要將應用程式重頭安裝.至於剛安裝完 wine 執行 winecfg 時,一開始會要求從網路下載穩定版本的 gecko 及 mono, 但使用備份檔的好處是因為先前已安裝過並備份到 wine.tgz 裡面了, 因此不用再從網路下載資源浪費時間.假設 /path_to 是 wine.tgz 想要解壓縮之位置,而 /path_from 是備份檔案 wine.tgz 所收藏之地方,在終端機輸入以下命令,用打包的檔案還原檔案:
        sudo  mkdir   /path_to
        sudo  chown  mint   /path_to
        cd   /path_to
        tar  -zxvf   /path_from/wine.tgz

如果 .wine 的目錄不是放在家目錄(~/.wine)底下,可以透過 linux 的 env 命令(設定環境變數並執行後續命令,相關用法使用 man env 就可以瞭解),先將環境變數 WINEPREFIX 指向 .wine 所在的位置,接著用 wine去 載入應用程式來執行.想要執行 windows 內建的 notepad.exe,在終端機輸入:
        env  WINEPREFIX="/path_to/.wine"   wine    "c:\\windows\\notepad.exe"

如果覺得用 env 執行命令很繁瑣,也可以先切換到家目錄(~), 再用符號連結(symbolic link)的方式去建立連結,在終端機輸入命令:
        cd  ~
        ln   -sf   /path_to/.wine    .wine

之後在終端機用 wine 就可以載入應用程式並執行:
      wine    "c:\\windows\\notepad.exe"

另外用 wine regedit 去手動設定 windows 的內建環境變數, 可以在裡面添加 path:
       REGEDIT4

       [HKEY_CURRENT_USER\Environment]
       "path"="%path%;c:\windows"

或將上述內容存成 winenv.reg 檔案, 在終端機輸入 wine regedit 檔名,把要註冊的內容放進 windows 環境變數內:
       wine regedit  winenv.reg

往後就不用再打一長串的路徑,直接在終端機用 wine 載入應用程式,windows 會自動用 path 所指定的目錄去找尋執行檔來執行,因此要執行內建的 notepad.exe 只要在終端機輸入 :
      wine notepad

在 linux mint上有更直接的用法,去編輯一個檔案,將副檔名以 .desktop 命名,在桌面進入點的段落 [Desktop Entry] 敘述中包含 Exec 及 Type 這兩個關鍵字,其中 Exec 讓它等於上述 linux 的 env 命令,將需要執行 wine 程式的相關參數隨後填入,而 Type 則直接等於 Application 這個字, 類似像這樣:
     [Desktop Entry]
     Exec=env  WINEPREFIX="/home/mint/.wine"  wine  "c:\\windows\\notepad.exe"
     Type=Application

將它存檔,先隨便取個名字(例如 notepad.desktop), 之後用滑鼠右鍵將它改成中文名,要執行時只要用滑鼠左鍵雙擊該檔案就能直接執行,相當方便.

2017年4月23日 星期日

用 nodejs 內建的 Promise 語法執行 child_process 外部程式 ffmpeg


定義 function ffmpeg,記得要將可執行檔 ffmpeg 放在目前目錄底下:
1. 這是原始function的定義,傳進來參數命名為 options,  檔名: child.js
      function ffmpeg(options) {
          const child = require('child_process');    // 調用內建child_process程式庫
          var cmd =__dirname+'/ffmpeg ' + options;   // 傳給child_process 時所需要的參數
          child.exec(cmd,function (err, stdout, stderr) { // child_proces開始處理指令
                  if( err )   console.log('出錯了:'+err+'\nstderr:'+stderr);
                  else       console.log('成功了:'+stdout);
           });  // end child_process
       } // end of ffmpeg
       ffmpeg('-version'); // 呼叫 ffmpeg 函式:

2. 這是將上述 function ffmpeg(options )轉化成 Promise 的用法, 檔名: child.js
      function ffmpeg(options) {
           return new Promise(function (ok,ng) {//回傳 closure,將會有兩個callback function
               const child = require('child_process');
               var cmd =__dirname+'/ffmpeg ' + options;
               child.exec(cmd, function (err, stdout, stderr) {
                   if(  err )  ng('出錯了:'+err+'\nstderr:'+stderr);// 回調(callback) ng
                   else       ok('成功了:'+stdout);   // 回調(callback) ok
               }); // end child_process
           }); // end of closure
       } // end of ffmpeg
      // 轉化成 Promise,就可以呼叫 then( ) 及 catch( ), 執行指令:
       ffmpeg('-version').then(console.log).catch(console.log);
      // 其中 then( ) 裡面的 callback 對應到 ok, 而 catch( ) 裡面的 callback 對應到 ng

3.  存檔用 nodejs 執行
       js  child.js


p.s. 轉檔時, 避免操壞硬碟, 改用 RAMDISK, linux 的 ramdisk 位置在 /dev/shm, 參考範例:
    var fs = require('fs'),
    var dirRAM='/dev/shm/hls'; // create a directory in ramdisk
    fs.mkdir(dirRAM, function(err) {
        fs.symlink(dirRAM, __dirname + '/hls', function(errlink ) { // create a symbolic link
            process.chdir(__dirname + '/hls'); // enter to the directory
            ffmpeg('-i '+ __dirname + '/oceans.mp4  -hls_flags delete_segments playlist.m3u8').then(console.log).catch(console.log); // media file transcode
        })
    })

2017年4月20日 星期四

下載 ffmpeg-3.3 自行編譯,讓它支援 pthreads, librtmp, libx264, libvpx, libx265, libvorbis, libmp3lame, libass 方便轉換影音檔

1. 上官網先下載原始碼(source code) 並解壓縮:
    wget http://ffmpeg.org/releases/ffmpeg-3.3.tar.bz2
    tar -xvf ffmpeg-3.3.tar.bz2
    cd ffmpeg-3.3
或是利用 git 複製出整個 repository:
    git clone https://git.ffmpeg.org/ffmpeg.git

2. 下載編譯環所需要的標頭檔:
sudo apt-get install librtmp-dev libx264-dev libvpx-dev libx265-dev libvorbis-dev libmp3lame-dev libass-dev yasm

3. 設定環境並開始編譯:
  ./configure --enable-gpl --enable-pthreads --enable-librtmp  --enable-libx264 --enable-libvpx --enable-libx265 --enable-libvorbis --enable-libmp3lame --enable-libass
  make

4. 複製 ffmpeg 到 /usr/bin
   sudo cp ffmpeg /usr/bin


5. 一些使用 ffmpeg 的範例:
   列出 webcam 支援的格式:
       ffmpeg -f v4l2 -list_formats all -i /dev/video0
   
   讓 ffmpeg 在背景擷取 webcam 影像,轉換產生 http live streaming (HLS) 所需要的檔案:
   ffmpeg -f v4l2 -i /dev/video0 -hls_flags delete_segments playlist.m3u8

   讓 ffmpeg 在背景擷取mp4檔案,轉換產生每個ts檔大約是10秒的HLS檔案:
   ffmpeg -i oceans.mp4 -hls_time 10 playlist.m3u8

   
   架設 http live streaming server 只要架設好 http server,再將轉換完成的HLS檔案放在讓 HLS client 可以下載到的地方,一旦下載完 playlist.m3u8 就可以隨後播放裡面的ts影片擋了.

bash 變數, 錢字符號 $, ${ }, $( ), $(( )) 不同點

參考文章: http://stackoverflow.com/questions/27472540/difference-between-and-in-bash-scripting
設定 bash 的變數 var 成為一個字串, 例如:  
     var = 'This is a test'
若要將變數內容取出來,在變數名稱前面加上錢字符號 $ 就可:
     echo $var
如果變數後面有跟隨其它字元時,用大括號刮起來以便區別成變數,因此 $ 與 ${ } 是相同用法.
     echo ${var}string,  append some string behind
但 $( ) 在小括號裡的是一個指令, 會被 bash 先取出來執行,執行完的輸出就是變數內容, 簡稱指令變數, 例如:
     echo  目前目錄是:$(pwd)
用雙小括號變數可以做簡單整數的加減乘除(+-*/)四則運算,:
   echo $(( 5-19+2*3 + 3/3 ))

bash 命令列的管線

參考文章: http://stackoverflow.com/questions/24793069/what-does-do-in-bash
標準輸入(stdin)的內建編號等於 0
標準輸出(stdout)的內建編號等於 1
標準錯誤(stderr)的內建編號等於 2
語法:
1. 內建編號 >  檔案名稱    : 若忽略內建編號,指的是將標準輸出轉向到檔案名稱, 相當於:  1> 檔案名稱
2. 內建編號 &> 檔案名稱  : 若忽略內建編號,指的是將標準輸出及標準錯誤都同時轉向到檔案名稱
3. 內建編號 >& 內建編號或檔案名稱  : 若忽略內建編號,指的是將標準輸出及標準錯誤都同時轉向


至於 2 與 3 有何不同呢? 舉個例子來看,  先產生一個文字檔 t:
       echo  This is a test file > t
列出 t 及 txxx 檔案的內容, 將標準輸出轉到 a, 並將標準錯誤轉到 b
       cat t  txxxxx      1>a   2>b
再來將 t 及 txxx 檔案的內容列印出來, 管線將標準輸出及標準錯誤同時轉到檔案 c
無論用  cat  t  txxxxx  &>  c 或  cat  t  txxxxx   >&  c 都得到相同結果,但
用   cat t  txxxxx      &>  1 卻是產生一個案名稱 1, 不會輸出到螢幕上.
而   cat t  txxxxx     >&  1 則是輸出到標處準輸出(螢幕)上, 不會另外產生一個檔案.

因此要使用 &> 或 >& , 就看要輸出是新檔案還是內建編號(0,1,2), 若要輸出到一般檔案就用 &> , 若要輸出到內建編號就要另外使用 >&了.



2017年4月17日 星期一

玩玩 Gstreamer

先安裝: sudo apt-get install gstreamer-1.0  libgstreamer1.0-dev gstreamer-tools
參考網址:
1.  https://gstreamer.freedesktop.org/documentation/tutorials/basic/index.html
2.  https://gstreamer.freedesktop.org/documentation/tutorials/basic/gstreamer-tools.html
程式範例:
      git clone git://anongit.freedesktop.org/gstreamer/gst-docs
      cd ./gst-docs/examples/tutorials
      gcc basic-tutorial-1.c -o basic-tutorial-1 `pkg-config --cflags --libs gstreamer-1.0`
      ./basic-tutorial-1

3. Gstreamer 名詞解釋:
    Elements: Gstreamer 的基礎單元
        例如一些內建的基礎單元: videotestsrc, decodebin, videoconvert, xvimagesink 等等,
        用 gst-inspect-1.0|egrep 查看說明:
        gst-inspect-1.0|egrep "videotestsrc|decodebin|videoconvert|xvimagesink"

    Pipeline: 管線, gst-launch-1.0 用 ! 將處理單元串接在一起, 根據輸入的順序由左至右一一串接資料流, 這種將資料流與處理單元互相串接集合成套稱之為管線

    GstPad: Gstreamer 用來作為溝通的端口稱之為 pads,簡稱 GstPad, 分別有:
            Sink pad: 作為資料吸入端
            Source pad: 作為資料輸出端
 
    Filter: 過濾中間端,有兩個端口(GstPads),端口型態一邊是輸入端(sink pad),另一邊則是輸出端(source pad)
 
    Property: 屬性, 由成對的 key=value 所組成的敘述, 例如:
                  uri="http://127.0.0.1:8080/movie.mp4"
                  uri="file:///home/mint/movie.mp4"
                  location="movie.mp4"

    Muxed: 例如一個檔案帶有 video 及 audio 資料流的稱之為 multiplexed (簡稱 muxed) file,
           常見的資料流格式: Matroska(MKV), Quick Time(QT,MOV), Advanced System Format(ASF), MWV, WMA ...等等

    Demuxer:資料流的解開程序稱之為 demuxers, 有一個吸入端(single sink pad), 多個輸出端(multiple source pad)
        例如decodebin就有一個吸入端(sink pad)及兩個輸出端分別是audio及video(source pads),用來分離出影像及聲音用

4. Gstreamer 常用處理單元:
    展現聲音單元通常用 osssink, 其他還有 "directsoundsink", "esdsink", "alsasink", "osxaudiosink", or "artsdsink".
    展現影像單元通常用 xvimagesink, 其他還有  "d3dvideosink", "ximagesink", "sdlvideosink", "osxvideosink", or "aasink".
    當處理單元無法連結時,有可能是格式不相容,可以先行轉換:
    影像傳換用: videoconvert
    聲音傳換用: audioconvert,  聲音取樣率轉換用 audioresample

5. 播放範例:
    播放影像測試信號源, 花樣採用第 11 號影像源
    gst-launch-1.0  videotestsrc pattern=11 ! videoconvert ! autovideosink
 
    擷取檔案 oceans.mov,由 decodebin 先分離出聲音與影像, 再透過聲音/影像轉換器轉換後分別交由alsasink及xvimagesink播放出來
    gst-launch-1.0  filesrc location=oceans.mov ! decodebin name=decoder decoder. ! queue ! audioconvert ! audioresample ! alsasink decoder. ! videoconvert ! xvimagesink




 

2017年4月16日 星期日

讓 c++ 程式與 Javascript 做朋友

參考網址: https://nodejs.org/api/addons.html
node-gyp 是編譯 nodejs 模組的工具,用 c++ 語言寫模組的程式,經由node-gyp開發工具編譯成 .node 模組, javascript 程式則透過 require 將自訂模組引進加以運用:

1. 先安裝 node-gyp
    sudo npm install node-gyp -g

2. 用 JSON 語法,將目標(targets)需求(所要定義的模組名稱 target_name, 及原始c++檔案名稱 sources ),寫入 binding.gyp 檔案,例如:
// binding.gyp
    {  "targets": [
          {
                "target_name":  "hellocc",
                "sources":  [ "hello.cc" ]
          }                    
    ]}

3. 開始寫 c++ 程式,先引入標頭檔 node.h,所有取用 javascript 的部份,要使用node.h內所提供的方法及宣告, 最主要部份是編寫 Method這個c++程式,  而init()主要是將c++的程式模組名稱匯出,類似 module.exports = { } 這個動作,最後交由巨集 NODE_MODULE(hellocc,init) 將 javascript 模組名稱與c++程式相互連結.
 // hello.cc:
    #include < node.h >
    namespace demo {
          using v8::FunctionCallbackInfo;
          using v8::Isolate;
          using v8::Local;
          using v8::Object;
          using v8::String;
          using v8::Value;
          void Method(const FunctionCallbackInfo < Value >& args) {
                  Isolate* isolate = args.GetIsolate(); // 獲取輸出入參數的方法
                  args.GetReturnValue().Set(String::NewFromUtf8(isolate, " cc"));// 回傳字串 cc
          }
         void init(Local < Object > exports) {
                NODE_SET_METHOD(exports, "hello", Method); // exports.hello = Method
         }
        NODE_MODULE(hellocc, init)
   }

4. configure 讓 node-gyp 根據 binding.gyp 的內容,自動建立 node-gyp 編譯環境,並將檔案寫進 build 目錄內:
     node-gyp configure  

5. build 開始編譯 hello.cc,如果沒意外的話,將會產生 hellocc.node 模組
     node-gyp build

6. 寫一個  javascript 引進該模組使用,已經編譯好的模組通常放在 ./build/Release下面:
    // hello.js
    const addon = require('./build/Release/hellocc'); // 引入自訂模組
    console.log(addon.hello()); // 呼叫模組程式 hello( ), 並印出傳回來的字串

7. 執行 javascript, 印出  cc
    js hello.js

8. clean 刪除編譯環境,會將整個目錄 build 全部移除.
    node-gyp clean


   
 

2017年4月6日 星期四

聊聊 npm ABC

參考文章: https://docs.npmjs.com/getting-started/using-a-package.json
安裝 npm (sudo apt-get install npm ,它是 Node Package Mmagement的縮寫),主要是用來管理套件的工具.

(A) npm init,  package.json
若要自訂功能可以將文件寫在 package.json 裡面, package.json 內容是用 json (Javascript Object Notation的縮寫)的語法來描述,它是成對的 key:value 加上逗號後,全部再用大括號框起來,其中key必須是用雙引號括起來的字串, value 除了可以用雙引號括起來的字串外,若有多個項目時,也可以用另一個json的語法來描述.一個最簡單的package.json內容,裡面必須要有"name"及"version"這兩個key的描述,其他可以選擇性的加入,另外key敘述的順序並不重要,當用 npm init 執行時,它會用問答的方式一個一個填入package.json裡面:

// package.json
   {
     // 常用的 key 有:
    "name": "目前的專案名稱"
    "version": "版本編號,通常使用像是 1.0.0 這種3個數字的方式來編碼",
    "description": "簡單的敘述",
    "main": "主程式檔案名稱",
    "scripts":
          {  // 可以執行的命令列, 例如
            "test": "js --version"
            "go": "js main.js"
          },
    "keywords": "關鍵詞",
    "author": "作者姓名",
    "license": "版權宣告",
    "bugs": "待解問題",
    "homepage": "官網網址",
    "dependencies": "依賴相關套件",
    "devDependencies": "依賴開發中的相關套件"
    "repository":
         { //該專案的寄存位置
            "type": "git",
            "url":  "https://github.com/username/package"
         }
  }

每次初始一個專案都要一個個輸入填寫,會覺得煩死人,可以利用nodejs對物件的語法將它匯出來( 檔案路徑及名稱是 ~/.npm-init.js ),需要注意跟json語法不同的是 ~/.npm-init.js 實際上是一個javascript,會經 nodejs執行過,因此對於物件的key並不需特別用雙引號括起來.示範用工具 vi 來編輯檔案 ~/.npm-init.js:

        vi   ~/.npm-init.js

//檔案內容
  module.exports = {
       name: 'hello',
       version: '1.0.0',
  }

將它存檔之後,只要一道命令:
    npm init -y
正常來講,會在當前目錄底下生成package.json檔案,內容就是上述檔案匯出的預設值,同時也不會出現惱人的問答,當然直接編輯package.json也是可以的.

(B) npm install, dependencies, devDependencies
如果在package.json有描述dependencies,那麼指令 npm install 就會自動安裝缺少的相關套件,一般並不需要特別去填寫這個項目,如果要自行安裝單獨套件只要下命令:
   npm install 套件名稱
如果npm install後面再添加 --save 那該套件名稱的相關性,自然會寫進package.json的 dependencies 物件裡面,如果npm install後面再添加 --save-dev 那該套件名稱的相關性就會自動寫入package.json的 devDependencies 物件裡面,示範安裝套件 uglifyjs, javascript-obfuscator, js-beautify, browserify:
   npm install   --save-dev   uglify-js@github:mishoo/UglifyJS2#harmony
   npm install   --save-dev   javascript-obfuscator
   npm install   --save   js-beautify
   npm install   --save   browserify
當完成安裝後再打開檔案package.json,可以看到在dependencies及devDependencies處,會自動加入上述套件名稱,而套件所提供的命令,通常放在 ./node_modules/套件名稱/bin 或是./node_modules/套件名稱/js/bin目錄下,用 ls 指令來找找看:
   ls -al node_modules/uglify-js/bin/uglifyjs
   ls -al node_modules/javascript-obfuscator/bin/javascript-obfuscator.js
   ls -al node_modules/js-beautify/js/bin/js-beautify.js
   ls -al node_modules/browserify/bin/cmd.js

(C) npm run, scripts
有了命令檔的存放位置後,就可自行定義由 javascript 所寫的命令,把它加在package.json的scripts物件定義裡面:
"scripts:": {
   "uglify": "js node_modules/uglify-js/bin/uglifyjs"
   "encode": "js node_modules/javascript-obfuscator/bin/javascript-obfuscator.js"
   "beauty": "js node_modules/js-beautify/js/bin/js-beautify.js"
   "browse": "js node_modules/browserify/bin/cmd.js"
   }
存檔完,用 'npm  run  自訂命令  主參數  --  其它參數' 來執行,不用輸入一長串的指令,例如:
   npm run uglify my.js
   npm run encode my.js --  -o my_obfus.js
   npm run beauty  my.js
   npm run browse my.js
當然上述簡化的動作用 linux 指令 ln -sf 也可以做到, 只是產生的連結檔,恐影響到整個專案的目錄結構,看起來雜亂無章,將它寫在 package.json裡,列出檔案時就乾淨多了.使用者也只要根據這個 package.json 就可以下載到該專案所需要的資源,省事方便多了.

2017年4月2日 星期日

上 github 申請帳號, 上傳網頁, 開啟個人網頁伺服器

加入會員:
   1. 上 github網站 ( https://github.com ) 註冊( sign-up )一個帳號, 填入
       a. 使用者名稱 (Username)
       b. 電子郵件帳號( Email Address )
       c. 認證密碼( Password )
   2. 點擊 Create an account 確認加入會員
   3. 到信箱去收電子郵件, 點選郵件內的連結認證函

會員登入:
   1. 登入(sign-in) github 網站, 鍵入申請會員時所填寫的個人資訊:
       a. 使用者名稱 (Username)或電子郵件帳號( Email Address )
       b. 認證密碼( Password )
   2. 點擊 Sign In 確認進入維護個人網頁伺服器


註冊使用個人網頁: 參考網址文章 https://pages.github.com/
   1. 登錄後, 在右下角 Your repositories 處點擊 New repository 建立個人網頁專用網址
   2. 在 repository 欄的地方, 填入前述所申請的個人網頁, 例如 amitmason.github.io,  其中 amitmason 必需是改用自己所申請的英文名稱.
   3. 點擊 Create repository

建立並上傳網頁:   
   1. 開啟終端機先下載個人網頁的 repository, 一開始是空的專案: 
       git clone https://github.com/amitmason/amitmason.github.io
   2. 進入專案目錄
       cd amitmason.github.io
   3. 建立網頁:
       echo "Hello, this is my web pages" > index.html
   4. 上傳
       git add --all
       git commit -m "My webpage"
       git push -u origin master
   5. 填寫登錄帳號及密碼
   6. 回到 github 個人網頁的 repository, 點選設定(Settings) 允許 Github Pages 運作.
   7. 開啟網址,瀏覽網頁.


2017年4月1日 星期六

linux mint 安裝新版 wine 示範並安裝 Window application

安裝 wine1.8 過程:
sudo  add-apt-repository ppa:ubuntu-wine/ppa
sudo apt-get update
sudo apt-get install wine1.8

安裝 wine 最新開發版過程:
sudo add-apt-repository ppa:wine/wine-builds
sudo apt-get update
sudo apt-get install winehq-devel
參考:
http://askubuntu.com/questions/879304/wine-2-0-says-it-supports-office-2013-how-do-i-actually-install-it
p.s.  SketchUP 2016 與 wine 2.4 版似乎不相容, 安裝時會有問題!, 因此最好還是安裝 wine1.8


底下會安裝 windows application: SketchUP 2016
1. 下載 32位元版本的 sketchup 2016:  https://www.sketchup.com/zh-TW/download/all
或直接下載: http://dl.trimble.com/sketchup/2016/zh-TW/SketchUpPro-2016-1-1450-80432-zh-TW-x86.exe

2. 設定組態以便安裝 sketchup 2016, 執行: 選單 -> Wine -> Configure wine 來設定程式組態, 參考文章:  http://askubuntu.com/questions/719504/how-do-i-install-sketchup-on-ubuntu-15-10
    a. 應用程式(標籤): window 版本選擇 windows 7
    b. 函式庫(標籤): 新增函式庫覆載 riched20, 新增一筆.
    c. 套用設定成 "預設組態"

3. 瀏覽選擇要安裝的程式(SketchUpPro-2016-1-1450-80432-zh-TW-x86.exe),啟用滑鼠右鍵選擇用Wine Loader來安裝, 安裝完成後, 它會加在: 選單 -> Wine -> SketchUp 程式底下,點選就可以執行.

4. 關閉 Sketchup 的歡迎畫面詳見: https://www.youtube.com/watch?v=9Tk__kTjiJc
    a.下載 Resource Hacker:  http://www.angusj.com/resourcehacker/
    b. 用 Wine Loader執行Resource Hacker修改以下2個檔案, 找尋startup的機碼,將它刪除並存檔:
         c:/Program Files (x86)/SketchUp/SketchUp 2016/SketchUp.exe
         c:/Program Files (x86)/SketchUp/SketchUp 2016/resources/zh-TW/SketchUpRc.dll
    c. Resource Hacker 存檔時會先將原檔案更名,並將主檔名附加 _original 備份,以防不時之需

5. 瀏覽並選擇程式: 啟用滑鼠右鍵, 選擇 SketchUp.exe 使用 Wine loader 來執行.


p.s.  Linux mint 18.1 的 wine 升級成 2.0.1: 詳見: https://wiki.winehq.org/Ubuntu
   sudo dpkg --add-architecture i386 
   wget https://dl.winehq.org/wine-builds/Release.key 
   sudo apt-key add Release.key
   sudo apt-add-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ xenial main'
        sudo   apt-get update
        sudo apt-get install --install-recommends winehq-stable

2017年3月29日 星期三

解決 geany 與新酷音輸入法相衝

Geany 在 linux mint 中文版與新酷音輸入法的 Ctrl + Space 相衝,只要修改快速鍵定義就可以了:
1. 求助(H) -> 快速鍵(K)
往下拉到 "補完字詞" , 它的設定正好是 Ctrl + Space
2. 點選 Edit
    往下拉到 "補完字詞" , 點選並修正此快速鍵的定義
3. 重新開啟 Geany


另外透過安裝完 js-beautify可以啟用 javascript 的美化功能, 先安裝好 js-beautify
     sudo npm -g install js-beautify
再來開啟 Geany  自訂命令, 透過滑鼠右鍵叫出選單:
      格式(F) -> 發送選取區域到(S) -> 設定自訂命令 -> Add
命令欄填入 js-beautify
按 OK 完成設定,
之後將所選的文字並透過滑鼠右鍵叫出選單傳給自訂命令:
      格式(F) -> 發送選取區域到(S) -> js-beautify
也可以用它所定義的快速鍵(Ctrl+1 ...等等)直接美化所選的文字區域

另外也可以 uglify-js 來醜化或美化, 若要支援 ES6, 可以安裝 harmony版本的 Uglifyjs2
   sudo npm install uglify-js@github:mishoo/UglifyJS2#harmony -g
若不加任何參數,它內定會將 javascript 醜化,加上參數 -b 或 --beautify 可以改成美化的功能, 因此命令列若改用:
  uglifyjs -b

  uglifyjs --beautify
就相當於
  js-beautify
的功能
但 ulifyjs --beautify 功能比不上  js-beautify 來的好用, 習慣上還是直接用 js-beautify 就好

2017年3月28日 星期二

linux mint 18 安裝 brackets

1. 到  http://brackets.io/ 下載 brackets binary
    sudo wget https://github.com/adobe/brackets/releases/download/release-1.9/Brackets.Release.1.9.64-bit.deb
2. 安裝遺失的library: libgcrypt11 及 libcurl3
    sudo wget https://launchpad.net/~ubuntu-security-proposed/+archive/ubuntu/ppa/+build/7110687/+files/libgcrypt11_1.5.4-2ubuntu1.1_amd64.deb
    sudo apt deb libgcrypt11_1.5.4-2ubuntu1.1_amd64.deb
    sudo apt-get install libcurl3
3. 最後安裝所下載的 brackets
    sudo apt deb Brackets.Release.1.9.64-bit.deb
4. 喜愛的插件(extensions):
    Autoprefixer
    Beautify
    Bracket Color Picker
    Bracket Git
    Emmet
    Inline Regex Editor
    Integrated Development
    Markdown Preview
    Match Highloghter
5.喜愛的佈景主題:
    DarkSoda

升級 nodejs


為了使用 nodejs 6.10.1 升級指令:
1. curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
2. sudo apt-get install -y nodejs

// javascript 程式使用 class
class ClassA {
    constructor(name) {
        this.aliasName = name;      
    }
    get name() {
        return this.aliasName.toUpperCase();
    }
    set name(name){
        if(name){ 
            this.aliasName = name;
        }
    }   
}
class ClassB extends ClassA {
constructor(name) {
super(name);// super needs to be called first
this.newp = function(){console.log("Hi"); }
}
}
let a = new ClassB("first"); // invoke constructor
console.log(a.aliasName+' : '+a.name); // invoke getter
a.name = "second"; // invoke setter
console.log(a.aliasName+' : '+a.name);// invoke getter
a.newp();

2017年3月23日 星期四

node js 使用 events 及 child_process

// 內建的 events,  產生 events.EventEmitter() 後,就可以定義/註冊(附帶一提: .on() 或 .addListener() 兩者功能相同只是名稱不同而已)事件監聽器(event listenter), 之後透過 .emit() 來觸發該條件, 同時將參數傳遞給 event_Listener(callback function)讓它動起來

// events.js
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('bing', console.log);//  .on(event_Pattern, event_Listenter)
emitter.emit('bing','go');          //  .emit(event_Pattern, parameters_to_Listener)

// 內建的 child_process,  裡面的 .exec(), .spawn(), .fork()  可以讓指令平行處理, 如果要做自動化程序它是一個很好用的模組
//          .exec()  --> 開啟環境執行另一條系統指令, 可以攜帶 error,stdout.stderr,如有需要, 可以自行處理 callback function
//          .spawn() --> 開啟環境執行另一條系統指令, 使用 events 來處理指令所帶進來的資料
//          .fork()  --> 開啟環境執行另一份 javascript, 並使用 events 來處理指令所帶進來的資料, 其實等同用 .spawn() 開啟環境執行指令前面加上 js 來執行 javascript

// test.js
const process = require('child_process');
for(var i=0; i<2 i="" p="">   var exec = process.exec('js events.js',function(err, stdout, stderr) {    
      if (err)  console.log('stderr: ' + stderr);
      else      console.log(stdout);
   });

   exec.on('exit', function (code) {
      console.log('process exist code='+code);
   });
}

2017年3月21日 星期二

node js 使用 redis 資料庫

1. 先安裝好 redis-server:
      sudo apt-get install redis-server
2. 編輯修改 redis 的設定: /etc/redis/redis.conf, 將 requirepass 這個註解取消, 並填上自行設定的密碼, 剛開始可以用  '123456' 來測試看是否運作正常, .之後記得要改掉.
3. 重新啟動 redis server:
     sudo /etc/init.d/redis-server stop
     sudo /etc/init.d/redis-server start
4. node js 是使用 createClient(port, host, auth_pass)  api 來連線
5. 為了避免非同步程式出現callback hell(輪迴地獄), 並讓程式看起來簡潔比較好理解一點,可以使用 bluebird 這隻 Promise 模組, 用 npm 就可以直接安裝, 用 require('bluebird') 導進程式後就可以使用了:
    npm install bluebird --save
6. 經過 promisifyAll 的 redis API 會帶有 Async 的尾綴詞,  是因為它都是非同步的API,  因此 .on() 須改為 .onAsync(), .get() 須改用 .getAsync(), .set() 須改用 .setAsync(), 當然原先 API 還是可以使用, 只不過程式寫起來會很累綴. 對於像是 , .on('error', console.log) 就可以直接顯示錯誤訊息,其實並不需要使用經 promisify 過的 API:

// redisTest.js
var Promise = require("bluebird");
var redis=Promise.promisifyAll(require("redis"));
var port=6379;
var host='127.0.0.1';
var auth_pass={auth_pass:'123456'};
var service=redis.createClient(port, host, auth_pass);

service.onAsync('ready').then( function() { // console.log('ready');
    service.getAsync('version').then(function(reply) {
        if( reply !== null ) { console.log(reply); return ; }
        service.setAsync('version','1.0.0.0').then(function(reply) {
            console.log(reply); // should be 'OK'
        })
    })
})

service.on("error",console.log);

2017年3月19日 星期日

用 node js 及 express 寫個簡單的 https server

// 參考文章:
//  https://nodejs.org/api/https.html
//  http://stackoverflow.com/questions/11744975/enabling-https-on-express-js
// npm install express

// exps.js
var https   = require("https");
var fs      = require("fs");
var url     = require("url");
var path    = require("path");
var express = require("express");
var options = {
    key:  fs.readFileSync('mypass.key'),
    cert: fs.readFileSync('mypass.crt')
};

function getDOC(req,res) {
    var uri = url.parse(req.url).pathname;
    var filename = path.join(process.cwd()+"/www", uri);                    // add doc root: /www
    fs.access(filename, function(accessErr) {
        if(accessErr) {   res.send("File not found");  return; }
        if (fs.statSync(filename).isDirectory()) filename +='/mybaby.htm';  // default html document
        fs.readFile(filename, "binary", function(err, file) {
            if(err) { res.send(err); return; }        
            res.writeHead(200);
            res.write(file, "binary");
            res.end();
        });      
    })
}
 
var app = express();
    app.get('/*',getDOC);

var server=https.createServer(options, app);
server.listen(4443, function() {
console.log("HTTPS sever started at port %s",server.address().port);
});

// 再寫個 Makefilet 產生 ssl 所需要的檔案及目錄,方便使用及執行.
// Makefile
run: genkey exps.js
@js exps.js

genkey: mypass.crt www

mypass.key:
openssl genrsa -out mypass.key 2048
mypass.csr: mypass.key
openssl req -new -key mypass.key -out mypass.csr
mypass.crt:  mypass.csr mypass.key
openssl x509 -req -in mypass.csr -signkey mypass.key -out mypass.crt
www:
mkdir www

clean:
rm -f mypass.*