tag:blogger.com,1999:blog-74832653789748225462024-03-13T07:57:06.125+08:00Pacess LaboratoryMy studies, development and creations on Robotics, iPhone Apps, Andriod Apps,...etc.Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.comBlogger2062125tag:blogger.com,1999:blog-7483265378974822546.post-47711648279468661862021-05-12T22:41:00.005+08:002021-05-12T22:41:34.950+08:00MIRROR 名牌<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-S3BaNxPCCrw/YJvnV65AneI/AAAAAAAASjA/EQVrcK21l7IKwWp3hKvAfntyWxv19Mr0gCLcBGAsYHQ/s0/mirror_badge.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-S3BaNxPCCrw/YJvnV65AneI/AAAAAAAASjA/EQVrcK21l7IKwWp3hKvAfntyWxv19Mr0gCLcBGAsYHQ/s0/mirror_badge.jpg"/></a></div>
訂了三塊不同顏色的 LED 名牌,只收到兩塊...。既然都收到,就開始試玩。我用的是 macOS Big Sur,以「pip3 install pyhidapi」及「brew install hidapi」安裝好 Driver,然後以 Python 程式把文字及自製的 MIRROR 標誌,經 USB 線上傳到 LED 名牌。這是送給兩個女兒的禮物,看來不錯呢!Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-42348053722774529882021-02-12T21:23:00.002+08:002021-02-12T21:31:18.323+08:00拿到公開的 Clubhouse Bio早前有個想法,希望可以畫出 Clubhouse 的長輩圖;要達到這個目的,先要有相關數據。數據要經 clubhouseapi.com 存取,而它受到 Certificate Pinning 技術的保護,免受中間人攻擊。利用中間人攻擊的目的是找出 API 的路徑及參數;既然此路不通,只好另覓出路。終於找到了讀取公開 Bio 的方法。下一步可以製作圖譜了。Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-9125720519318854892021-02-10T23:54:00.005+08:002021-02-10T23:54:52.052+08:00Clubhouse 房間活動記錄<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-qNVfIdqx5H8/YCQAy2EHqPI/AAAAAAAAScE/4IyXZ4uAEPkp43jdIJ-CYptBRyE_Rn0aQCLcBGAsYHQ/s0/Clubhouse_room_activity.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" data-original-height="1222" data-original-width="2573" src="https://1.bp.blogspot.com/-qNVfIdqx5H8/YCQAy2EHqPI/AAAAAAAAScE/4IyXZ4uAEPkp43jdIJ-CYptBRyE_Rn0aQCLcBGAsYHQ/s0/Clubhouse_room_activity.png"/></a></div><br>
抓到了 Clubhouse 房間的活動變化,很想把它製作成圖表,以影像方式觀看變化;於是寫了一個呈現房間活動的圖表網頁。目前顯示的是房間人數、新增人數、離開人數。從幾個房間的數據看,發現每 10 至 20 分鐘,總會有一批人離開,不論是哪一個房間。是應用程式的設計?還是巧恰?Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-55990682090006976242021-02-08T23:35:00.004+08:002021-02-10T23:46:55.007+08:00Clubhouse 用戶數據<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-aF31ac-o7gg/YCP9ZNRfNrI/AAAAAAAASb4/YU-_Trb6abMH75hAQLCy3hKJDzkhHoVSwCLcBGAsYHQ/s0/Clubhouse_members.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" data-original-height="580" data-original-width="1010" src="https://1.bp.blogspot.com/-aF31ac-o7gg/YCP9ZNRfNrI/AAAAAAAASb4/YU-_Trb6abMH75hAQLCy3hKJDzkhHoVSwCLcBGAsYHQ/s0/Clubhouse_members.png"/></a></div><br>
上星期五,朋友介紹了 Clubhouse 這款新型態社交應用程式給我,一玩之下就停不了。原本充滿電的 iPhone XR 可以用上兩天都變成一天;每天花平均五小時在這個應用程式上。<br><br>
我喜歡它是因為把人的距離拉近了、也讓我的眼界大開了。其中一個房間邀請了 Clubhouse 第一位香港用戶 Jane 分享她踏上逆向工程的故事;令開始玩膩了的我研究它背後的通訊。花了點時間,抓到房間更新的內容。圖中是一位用戶的數據。最令我感興趣的是 skintone 膚色一欄。想來想去都想不出它用於哪個地方。在網上找找看,卻找到 Jane 在 2020 年 11 月發現長按「舉手」會彈出膚色選單,這個數值就是結果。Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-50758051411767078422021-01-30T13:12:00.003+08:002021-01-30T13:12:43.939+08:00在 MacBook Pro M1 跑 Android 模擬器<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-ZX9sjqmGN0Q/YBTopYK8RaI/AAAAAAAASa4/YMWxdTCH4zkSO4Ov-qO5KZNxxVMN2tJKQCLcBGAsYHQ/s0/Android_Studio_M1.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" data-original-height="1202" data-original-width="1602" src="https://1.bp.blogspot.com/-ZX9sjqmGN0Q/YBTopYK8RaI/AAAAAAAASa4/YMWxdTCH4zkSO4Ov-qO5KZNxxVMN2tJKQCLcBGAsYHQ/s0/Android_Studio_M1.png"/></a></div><br>
最近入手了 MacBook Pro M1,在安裝了 Android Studio 後,發現跑 Android 模擬器會出現 Intel HAXM 錯誤。M1 是 Apple 的處理器而不是 Intel,所以跑不了。然而,Google 也推出了支援 M1 的 Android 模擬器;不過要自行到 <a href="https://github.com/google/android-emulator-m1-preview/releases">https://github.com/google/android-emulator-m1-preview/releases</a> 下載 .dmg 檔並進行安裝。之後,在 Android Studio 的 AVD Manager 便能選 M1 專屬的模擬器。Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.comtag:blogger.com,1999:blog-7483265378974822546.post-56750777268640677882020-09-05T21:37:00.000+08:002020-09-08T21:41:44.313+08:00可編程操作的瀏覽器<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-jft45ZXq-qw/X1eJ6253ASI/AAAAAAAAR4w/k25NLGNxzsUh6qTRi5VQ-ztJ4DHIYhg-QCLcBGAsYHQ/s939/cityline.png" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" width="800" data-original-height="504" data-original-width="939" src="https://1.bp.blogspot.com/-jft45ZXq-qw/X1eJ6253ASI/AAAAAAAAR4w/k25NLGNxzsUh6qTRi5VQ-ztJ4DHIYhg-QCLcBGAsYHQ/s600/cityline.png"/></a></div><br>
早一兩年經常有同事向我求助,幫忙購買演唱會門券。當時使用的技術是利用 Man-in-the-middle Proxy 去即場修改網頁內容,達到高頻交易,增加成功機會。進入到購買頁面後還是要手動操作。這個方法能幫到手,卻不是理想的方案。<br>
<br>
現時肺炎疫情持續,這些大型活動也停止了,沒甚麼需求。正好是學習及優化一下技術,開發出更醒目的購票程式。其中一個技術是應用 Selenium + WebDriver 做出可由程式操作的瀏覽器。於是,我把相關工具安裝到 Raspberry Pi 4 伺服器,配合 Jupyter 便能方便地使用。安裝過程如下:<br>
<pre>$ cd ~/Downloads/
$ pip3 install selenium
$ sudo wget https://github.com/fg2it/phantomjs-on-raspberry/releases/download/v2.1.1-jessie-stretch-arm64/phantomjs
$ sudo chmod +x phantomjs
$ sudo mv phantomjs /usr/local/bin
$ sudo apt install firefox-geckodriver</pre>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.comtag:blogger.com,1999:blog-7483265378974822546.post-40900386000367914582020-08-29T22:55:00.005+08:002020-08-31T20:40:34.545+08:00安裝 Pi-hole<center><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-ZLDRubmKDR0/X0sxSK4hjMI/AAAAAAAAR2g/pkyygE32Zmgt6gFFyGEE9s6B3NG3i3X4gCLcBGAsYHQ/s2048/pi-hole.PNG" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" width="800" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-ZLDRubmKDR0/X0sxSK4hjMI/AAAAAAAAR2g/pkyygE32Zmgt6gFFyGEE9s6B3NG3i3X4gCLcBGAsYHQ/s600/pi-hole.PNG"/></a></div></center>
同事介紹使用 Pi-hole 去阻擋廣告追蹤,它支援 Raspberry Pi 4。於是把它安裝到家中的迷你伺服器。它又多了一個新功能!Pi-hole 能在 Raspberry Pi 4 本身的 Laravel HTTPS routing 外加建 HTTP 的 routing,不用擔心兩者衝突,很方便。安裝邊法也挺簡單:<br>
<pre>$ curl -sSL https://install.pi-hole.net | bash</pre>
<br>
Raspberry Pi 4 是運行 Nginx,在安裝過程中沒有安裝 Lighttpd,所以同時要自行修改 /etc/nginx/sites-available/default 的內容:
<pre>server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
server_name _;
autoindex off;
index pihole/index.php index.php index.html index.htm;
location / {
expires max;
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
fastcgi_param FQDN true;
}
location /*.js {
index pihole/index.js;
}
location /admin {
root /var/www/html;
index index.php index.html index.htm;
}
location ~ /\.ht {
deny all;
}
}</pre><br>
也要把網頁根目錄及 www-data 用戶加入權限:
<pre>$ chown -R www-data:www-data /var/www/html
$ chmod -R 755 /var/www/html
$ usermod -aG pihole www-data</pre>
<hr>
參考: <a href="https://docs.pi-hole.net/guides/nginx-configuration/">https://docs.pi-hole.net/guides/nginx-configuration/</a>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.comtag:blogger.com,1999:blog-7483265378974822546.post-30195845804998519892020-08-24T23:44:00.005+08:002020-08-30T12:48:40.262+08:00逆向週末<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-Hhwh2uG7_zo/X0supbw7pTI/AAAAAAAAR2U/xJPgXjmhS1MMunjEMlHRd91h6z3cn8IFwCLcBGAsYHQ/s1836/hex-edit-nca.png" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" width="800" data-original-height="862" data-original-width="1836" src="https://1.bp.blogspot.com/-Hhwh2uG7_zo/X0supbw7pTI/AAAAAAAAR2U/xJPgXjmhS1MMunjEMlHRd91h6z3cn8IFwCLcBGAsYHQ/s600/hex-edit-nca.png"/></a></div>
過了一個 Reverse Engineering 的學習週末。還記得我的第一次接觸 Reverse Engineering 是在 16 歲左右的時候。當時一位朋友教導我怎樣使用 Pctools 3.1 修改《波斯王子》的遊戲儲存檔,使得生命由 3 條變成 255 條。從此打開了好奇的心,不斷嘗試修改印證;由生命值、魔法值這些數據資料,到修改 Assembly 邏輯程序,跳過遊戲的密碼保護。《電腦時代》雜誌刊登的金手指碼也研究一餐。正常人看來普通的修改碼,在深入研究後就知道那是 Assembly 程序碼,為何 0x75 要改為 0xEB,就是在 Intel 80386 中的 if...else 指令;把原來輸入錯誤密碼都當成是正確。回頭看來,十多二十歲的時光,在資訊那麼缺乏的情況下能有這麼高端的技術,是因為宅男的「專注」吧!
Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.comtag:blogger.com,1999:blog-7483265378974822546.post-21497631311605260422020-08-04T20:52:00.007+08:002020-08-04T21:04:19.162+08:00Benford's Law最近看 Netflix 的《數據大同》認識了神奇的 Benford's Law。它說明了從實際生活得出的自然數據中,拿取數字最左面的號碼,統計出現律,得出以 1 為首位數字的出現率約為總數的 30.1%,接近直覺得出之期望值 1/9 的 3 倍。越大的數的出現率就越低。它可用於檢查各種數據是否有造假。看畢很想親手試作,驗證一下數據是否為自然之數。第一個實驗是拿了<a href="https://data.gov.hk/tc-data/dataset/hk-dh-chpsebcddr-novel-infectious-agent"> 2019 冠狀病毒香港數據</a>,以「報告日期」的確診數字來驗證。發現結果跟 Benford's Law 有少許出入;算是意料中事。後來又拿股票每天交易量數據來做比較;先拿我最喜愛的 2313.HK「申洲國際」,得出漂亮的 Benford's Law 曲線:
<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-EZDZLk2Kz5w/XylV75am2CI/AAAAAAAAR0Y/GL451FK0moMFtrKYX_NrmpVN87KFWs9ugCLcBGAsYHQ/s940/2313hk_20051124.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="713" data-original-width="940" src="https://1.bp.blogspot.com/-EZDZLk2Kz5w/XylV75am2CI/AAAAAAAAR0Y/GL451FK0moMFtrKYX_NrmpVN87KFWs9ugCLcBGAsYHQ/s640/2313hk_20051124.png" width="640" /></a></div>
<br>
看來成功了。拿另一支股票 0066.HK「港鐵公司」,跟 Benford's Law 曲線有少許出入:
<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-HmzVmShE3WQ/XylV6ZO9VkI/AAAAAAAAR0M/kO27LAJQxUABMOt_IqsbfkvOGVdqPX2-QCLcBGAsYHQ/s940/0066hk_20001009.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="713" data-original-width="940" src="https://1.bp.blogspot.com/-HmzVmShE3WQ/XylV6ZO9VkI/AAAAAAAAR0M/kO27LAJQxUABMOt_IqsbfkvOGVdqPX2-QCLcBGAsYHQ/s640/0066hk_20001009.png" width="640" /></a></div>
<br>
然後 0002.HK「中華電力」:
<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-VLpRi9N8Hjc/XylV6WR1wrI/AAAAAAAAR0I/D9agB4ZA_rQrrB-uysOt_omPGKjWhZxJwCLcBGAsYHQ/s940/0002hk_20000104.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="713" data-original-width="940" src="https://1.bp.blogspot.com/-VLpRi9N8Hjc/XylV6WR1wrI/AAAAAAAAR0I/D9agB4ZA_rQrrB-uysOt_omPGKjWhZxJwCLcBGAsYHQ/s640/0002hk_20000104.png" width="640" /></a></div>
<br>
看看 0005.HK「匯豐控股」,開始跟 Benford's Law 有較大出入:
<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-3WHiIrF8UKQ/XylV6g1LCkI/AAAAAAAAR0Q/OAIiZ21M-HgZvSnhL38OIwmMIMYa7k5UwCLcBGAsYHQ/s940/0005hk_20000103.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="713" data-original-width="940" src="https://1.bp.blogspot.com/-3WHiIrF8UKQ/XylV6g1LCkI/AAAAAAAAR0Q/OAIiZ21M-HgZvSnhL38OIwmMIMYa7k5UwCLcBGAsYHQ/s640/0005hk_20000103.png" width="640" /></a></div>
<br>
再來 2628.HK「中國人壽保險」,差距越來越大:
<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-luznmsAa33w/XylV7-GRlHI/AAAAAAAAR0c/1VuU0RG1D9Qo_7zoW2rif2FBNQwEnRdLgCLcBGAsYHQ/s940/2628hk_20031218.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="713" data-original-width="940" src="https://1.bp.blogspot.com/-luznmsAa33w/XylV7-GRlHI/AAAAAAAAR0c/1VuU0RG1D9Qo_7zoW2rif2FBNQwEnRdLgCLcBGAsYHQ/s640/2628hk_20031218.png" width="640" /></a></div>
<br>
最後 1113.HK「長江實業集團」,可以說是極不吻合:
<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2vuCZBvIgb4/XylV7kzSHqI/AAAAAAAAR0U/jYkV3hoUXNoQl9xj420NNIqfWHjyU04NwCLcBGAsYHQ/s940/1113hk_20150603.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="713" data-original-width="940" src="https://1.bp.blogspot.com/-2vuCZBvIgb4/XylV7kzSHqI/AAAAAAAAR0U/jYkV3hoUXNoQl9xj420NNIqfWHjyU04NwCLcBGAsYHQ/s640/1113hk_20150603.png" width="640" /></a></div>
<br>
經過幾次實驗,我發現在選取數字是要有一點技巧。數字範圍要夠大,像是拿身高來代入的話,會得到另一種結果;畢竟正常成人的身高分別不大。又例如手機號碼;在香港只有 4-9 而沒有 1-3。另外,有人嘗試過拿它來驗證相片是自然拍攝,還是被改動過;這個題材也很吸引,而且帶一點技術,不是把所有像素都算進去就行。遲些會做做實驗,有結果再分享。
Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-37609580615557256682020-07-28T21:49:00.001+08:002020-07-28T21:49:46.349+08:00收集 WiFi 訊號<a href="https://1.bp.blogspot.com/-1MLAaDJCCF4/XyArfs3cPuI/AAAAAAAARzc/KXAJt7LPyLcXOa_fsZciL0TCIy2dPrKHACLcBGAsYHQ/s2042/wifi.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1128" data-original-width="2042" height="354" src="https://1.bp.blogspot.com/-1MLAaDJCCF4/XyArfs3cPuI/AAAAAAAARzc/KXAJt7LPyLcXOa_fsZciL0TCIy2dPrKHACLcBGAsYHQ/w640-h354/wifi.png" width="640" /></a><br>
週末時給自己一個項目。收集家中的 WiFi 訊號,希望籍著訊號去得知家人是否在家、甚麼時候外出、甚麼時候回來。利用 ESP8266 的混雜模式 (Promiscuous mode) 來取得附近的裝置訊號。把數據儲存起來並作出分析。有興趣的朋友可參考<a href="https://github.com/pacess/family-detector">我的 GitHub</a>。比想像中遇到的問題多,花了大半天時間才完成。然後花了一天時間收集數據。發現家中關機了的 Nintendo Switch 竟然不停地發放 Management Action Frame 訊號...。我再次確認 Switch 是關機狀態。按一下開機鍵,看見的是任天堂標誌。如果是睡眠模式,應該會顯示新聞的頁面。證明了遊戲機是關著的!這就奇怪了,明明是關機狀態,竟然不斷發送訊號,究竟是為何事?Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-58857914202070996732020-05-15T00:11:00.003+08:002020-05-15T00:21:37.573+08:00動物森友會物品圖抓取程式
<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-_WoVS6Zqwk0/Xr1rmrPRFyI/AAAAAAAARsQ/YKSHS9JzdRo_gR8-v8qXFkbCPY01MEzOACK4BGAsYHg/acnh_items.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="1280" src="https://1.bp.blogspot.com/-_WoVS6Zqwk0/Xr1rmrPRFyI/AAAAAAAARsQ/YKSHS9JzdRo_gR8-v8qXFkbCPY01MEzOACK4BGAsYHg/s640/acnh_items.jpg" width="640" /></a></div><br br="" python="" />
最近都忙於玩《動物森友會》,香港簡稱《動森》。之前經常都日本小島炒賣大頭菜,賺到兩千萬鈴錢;到三個星期前發現了郵箱漏洞,輕鬆變成四千萬,脫離炒賣的行列。現在主要是周圍尋找不同我傢俬道具,跟朋友分享。為了能有效地給朋友選擇物品,我希望能有一個網頁,顯示出獲得的物品,甚至給朋友下單。但要是人手逐張逐張圖準備不是我的風格,這樣沉悶的工作當然要自動化一下;於是簡單地以 Python 寫了一個裁圖程式:
<pre style="background: rgb(255, 255, 224); color: black; padding: 10px;">#!/usr/bin/python
from PIL import Image
import glob, os
_inputFolder = "Screenshots/"
_outputFolder = "Items/"
_itemsPerRow = 8
_rowCount = 4
## Search images file in folder
index = 0
width = 132
height = 120
for file in glob.glob(_inputFolder+"*.jpg"):
#fileArray = _inputFolder+"2020050621303300-02CB906EA538A35643C1E1484C4B947D.jpg"
print(file)
## Load image one by one
filePath = file
image = Image.open(filePath)
## Extract item images X:112, Y:154, W:132, H:120
top = 154
for y in range(_rowCount):
left = 112
for x in range(_itemsPerRow):
filePath = _outputFolder+"item_"+str(index)+".png"
right = left+width
bottom = top+height
index = index+1
itemImage = image.crop((left, top, right, bottom))
itemImage.save(filePath)
left = left+width
top = top+127
</pre>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-44495604061054331122020-05-03T16:41:00.001+08:002020-05-03T16:43:22.802+08:00動物森友會:免費、搖錢樹提示 QR Code<a href="https://4.bp.blogspot.com/-N3L8ZcwVaz0/Xq6Dw8zSEOI/AAAAAAAARqk/1rfnorlasJogd0M78nfcbgref9K-lSrzgCLcBGAsYHQ/s1600/Free_QR.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-N3L8ZcwVaz0/Xq6Dw8zSEOI/AAAAAAAARqk/1rfnorlasJogd0M78nfcbgref9K-lSrzgCLcBGAsYHQ/s1600/Free_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://2.bp.blogspot.com/-Jl9XCy1exPo/Xq6EH1sJcMI/AAAAAAAARqs/-KDktzywfoQd6nTUsDdp1TUaRMiJ0gbYgCLcBGAsYHQ/s1600/Dollar-sign_QR.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-Jl9XCy1exPo/Xq6EH1sJcMI/AAAAAAAARqs/-KDktzywfoQd6nTUsDdp1TUaRMiJ0gbYgCLcBGAsYHQ/s1600/Dollar-sign_QR.png" data-original-width="440" data-original-height="270" /></a>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.comtag:blogger.com,1999:blog-7483265378974822546.post-7754498498968948902020-05-03T09:22:00.003+08:002020-05-03T16:40:47.380+08:00動物森友會:道路 QR Code<a href="https://3.bp.blogspot.com/-AuZE3lZESdo/Xq4cRMTzYMI/AAAAAAAARpY/0aGpeNIAj18B1N87cxiZNuWliWKVYZ_5ACLcBGAsYHQ/s1600/Road-bottom-left-in_QR.png" imageanchor="1" ><img border="0" src="https://3.bp.blogspot.com/-AuZE3lZESdo/Xq4cRMTzYMI/AAAAAAAARpY/0aGpeNIAj18B1N87cxiZNuWliWKVYZ_5ACLcBGAsYHQ/s1600/Road-bottom-left-in_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://4.bp.blogspot.com/-yJAA7WQ_EZo/Xq4cRGsPGPI/AAAAAAAARpc/Si1n016N82gMeECHpCJxCaCYbSiGgoL1gCLcBGAsYHQ/s1600/Road-bottom-left-out_QR.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-yJAA7WQ_EZo/Xq4cRGsPGPI/AAAAAAAARpc/Si1n016N82gMeECHpCJxCaCYbSiGgoL1gCLcBGAsYHQ/s1600/Road-bottom-left-out_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://2.bp.blogspot.com/-00Ss7Y7ZLbA/Xq4cREijX7I/AAAAAAAARpU/onbuINFDOFs6k2wJyEDhlVQwh85XA3DAgCLcBGAsYHQ/s1600/Road-bottom-right-in_QR.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-00Ss7Y7ZLbA/Xq4cREijX7I/AAAAAAAARpU/onbuINFDOFs6k2wJyEDhlVQwh85XA3DAgCLcBGAsYHQ/s1600/Road-bottom-right-in_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://2.bp.blogspot.com/-Z45NtPPCrdk/Xq4cSY-oF8I/AAAAAAAARpg/HWrivoWCEyQUdnX6-EAo3RDUXmAdvYvzACLcBGAsYHQ/s1600/Road-bottom-right-out_QR.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-Z45NtPPCrdk/Xq4cSY-oF8I/AAAAAAAARpg/HWrivoWCEyQUdnX6-EAo3RDUXmAdvYvzACLcBGAsYHQ/s1600/Road-bottom-right-out_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://2.bp.blogspot.com/-PMWIbU2FLp4/Xq4cSxQ3b-I/AAAAAAAARpk/dI6hpKpQY3EeszHor1SEQuGDjvV8RkVcwCLcBGAsYHQ/s1600/Road-bottom_QR.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-PMWIbU2FLp4/Xq4cSxQ3b-I/AAAAAAAARpk/dI6hpKpQY3EeszHor1SEQuGDjvV8RkVcwCLcBGAsYHQ/s1600/Road-bottom_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://4.bp.blogspot.com/-qLuhRjPmHNM/Xq4cTCMAeFI/AAAAAAAARpo/_mUo8dSNiTE-H7_1Oqw55csfsoPtOwGFgCLcBGAsYHQ/s1600/Road-left_QR.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-qLuhRjPmHNM/Xq4cTCMAeFI/AAAAAAAARpo/_mUo8dSNiTE-H7_1Oqw55csfsoPtOwGFgCLcBGAsYHQ/s1600/Road-left_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://2.bp.blogspot.com/-wM4GXzi5ics/Xq4cTd3wEHI/AAAAAAAARps/KbH2KLoTV3gTvgN3BEz0zSFyuMeLVSDWQCLcBGAsYHQ/s1600/Road-right_QR.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-wM4GXzi5ics/Xq4cTd3wEHI/AAAAAAAARps/KbH2KLoTV3gTvgN3BEz0zSFyuMeLVSDWQCLcBGAsYHQ/s1600/Road-right_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://4.bp.blogspot.com/-eoxjTlP3OfI/Xq4cTuhs_5I/AAAAAAAARpw/9-Rvek6umLcl4kacTfEGqBW5sKH7QBl-gCLcBGAsYHQ/s1600/Road-top-left-in_QR.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-eoxjTlP3OfI/Xq4cTuhs_5I/AAAAAAAARpw/9-Rvek6umLcl4kacTfEGqBW5sKH7QBl-gCLcBGAsYHQ/s1600/Road-top-left-in_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://2.bp.blogspot.com/-1OqLwGsSjmk/Xq4cUCAsrbI/AAAAAAAARp0/11yLxWB5O2I8JBJTplvcHkjUKrhw74qrACLcBGAsYHQ/s1600/Road-top-left-out_QR.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-1OqLwGsSjmk/Xq4cUCAsrbI/AAAAAAAARp0/11yLxWB5O2I8JBJTplvcHkjUKrhw74qrACLcBGAsYHQ/s1600/Road-top-left-out_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://3.bp.blogspot.com/-1cTaDEaQTus/Xq4cUMoYuKI/AAAAAAAARp4/lZ8rJDKfMUA7qibNcX89viprQWgnjL72wCLcBGAsYHQ/s1600/Road-top-right-in_QR.png" imageanchor="1" ><img border="0" src="https://3.bp.blogspot.com/-1cTaDEaQTus/Xq4cUMoYuKI/AAAAAAAARp4/lZ8rJDKfMUA7qibNcX89viprQWgnjL72wCLcBGAsYHQ/s1600/Road-top-right-in_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://4.bp.blogspot.com/-VD8pbfKw0rQ/Xq4cUiVjJvI/AAAAAAAARp8/jwezNUZFATQ7ohu43kMQ0bCKIQl-mZ2QgCLcBGAsYHQ/s1600/Road-top-right-out_QR.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-VD8pbfKw0rQ/Xq4cUiVjJvI/AAAAAAAARp8/jwezNUZFATQ7ohu43kMQ0bCKIQl-mZ2QgCLcBGAsYHQ/s1600/Road-top-right-out_QR.png" data-original-width="440" data-original-height="270" /></a><a href="https://2.bp.blogspot.com/-BvYFrRJtJ1w/Xq4cVKvOcPI/AAAAAAAARqA/DiVC2qVjJ94WJsueGCsh4ilkkfpBaXspACLcBGAsYHQ/s1600/Road-top_QR.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-BvYFrRJtJ1w/Xq4cVKvOcPI/AAAAAAAARqA/DiVC2qVjJ94WJsueGCsh4ilkkfpBaXspACLcBGAsYHQ/s1600/Road-top_QR.png" data-original-width="440" data-original-height="270" /></a>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.comtag:blogger.com,1999:blog-7483265378974822546.post-32194596245518349062020-03-23T23:59:00.002+08:002020-03-23T23:59:23.457+08:00編輯器無法使用 Tab 縮排<a href="https://4.bp.blogspot.com/-7gGzrzOU6R4/Xnjb6O-N85I/AAAAAAAARmY/BbRUKTzDnNMSOgVySrbgVdHtB1BdtdszQCLcBGAsYHQ/s1600/editorconfig.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-7gGzrzOU6R4/Xnjb6O-N85I/AAAAAAAARmY/BbRUKTzDnNMSOgVySrbgVdHtB1BdtdszQCLcBGAsYHQ/s640/editorconfig.png" width="640" height="487" data-original-width="822" data-original-height="626" /></a><br>
在編寫程式時的縮排,我喜歡用 Tab 多於空白。最近在寫 Laravel 時卻發玩編輯器都轉用了空白,無論我怎樣設置也是一樣。後來發現編輯器會跟據當時目錄中的 .editorconfig 內容來影響設定。於是打開 .editorconfig 檔,把裡面的 space 改為 tab 就沒再出現空白的情況。Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-30003387464258127192020-03-22T08:59:00.000+08:002020-03-22T10:36:42.432+08:00在 Raspberry Pi 4 上安裝 Pandas DataReader如果在 Raspberry Pi 4 上的 Ubuntu 18.04 以 pip 指令安裝 Pandas DataReader,會出現報錯內容。主要問題是找不到 libxml2 檔案。網上的解決方案是用 apt-get 去安裝 libxml2,在我的情況下沒有改善。原來不單止要安裝 libxml2,還需要 libxslt。正確方法如下:
<pre class="command">
$ sudo apt-get install libxml2-dev libxslt-dev
$ pip3 install lxml
$ pip3 install pandas-datareader
</pre>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-27720123723844233452020-03-21T15:57:00.002+08:002020-03-22T12:24:00.267+08:00Raspberry Pi 4 伺服器軟體設定<a href="https://3.bp.blogspot.com/-222F2fIaEOU/XnXKb7Ks3rI/AAAAAAAARlQ/KlBn_EDPrhwcWXuhFN3H9vogzkJY7I9xQCLcBGAsYHQ/s1600/raspberry-pi-4-ssd-server.jpg" imageanchor="1" ><img border="0" src="https://3.bp.blogspot.com/-222F2fIaEOU/XnXKb7Ks3rI/AAAAAAAARlQ/KlBn_EDPrhwcWXuhFN3H9vogzkJY7I9xQCLcBGAsYHQ/s640/raspberry-pi-4-ssd-server.jpg" width="640" height="480" data-original-width="1600" data-original-height="1200" /></a><br>
按照之前的步驟把 Ubuntu 18.04 安裝好到 Raspberry Pi 4,還用上了 SSD 作為主要儲存媒體。下一步便是安裝所需軟件。在這之前,先做一下更新,確保所有資源都是最新。在 Raspberry Pi 4 上登入 Console 並輸入:
<pre class="command">
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt dist-upgrade
$ sudo reboot
$ sudo apt-get install ubuntu-desktop
$ sudo apt-get install -y xterm
$ sudo apt-get install python3.7
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 2
$ sudo update-alternatives --config python3
</pre>
為了安全起見,先建立一個新用戶並把它加到 sudo 群組。往後就是用這個帳號來做設定:
<pre class="command">
$ sudo adduser sitachan
$ sudo usermod -aG sudo sitachan
</pre>
這時回到 macOS 的 Terminal,測試新帳號能否登入:
<pre class="command">
$ ssh sitachan@192.168.1.100
$ exit
</pre>
除了使用密碼登入 SSH 外,還可以 SSH Key 來登入,能省卻了輸入密碼的步驟。在 macOS 的 Terminal 下輸入:
<pre class="command">
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/home/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/home/.ssh/id_rsa.
Your public key has been saved in /Users/home/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:4CQn536JOnKchPefJ9XZdK6nGKzP92hbqto8VfIwPSI home@MacBook-Pro-2019-Pacess.local
The key's randomart image is:
+---[RSA 2048]----+
| |
| |
| o = . |
| O . E .=.+|
| . o S ..+.O.|
| . o. . ...o o o|
| + oo o. o. ..|
| . =......=.o++.|
| o.. .ooooB===.|
+----[SHA256]-----+
</pre>
這時生成了一組登入密匙,下一步是把它安裝到 Raspberry Pi 4 上:
<pre class="command">
$ ssh-copy-id sitachan@192.168.1.100
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/home/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
sitachan@192.168.1.100's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'sitachan@192.168.1.100'"
and check to make sure that only the key(s) you wanted were added.
</pre>
嘗試再登入一次。今次不用輸入密碼了:
<pre class="command">
ssh sitachan@192.168.1.100
</pre>
接著是正式的安裝步驟。先安裝 MySQL:
<pre class="command">
$ sudo apt install mysql-server
$ sudo mysql_secure_installation
</pre>
MySQL 也同樣建立新的登入帳號和資料庫給 Laravel 使用:
<pre class="command">
$ mysql -u root -p
mysql> GRANT ALL ON *.* TO 'sita'@'localhost' IDENTIFIED BY 'Password';
mysql> GRANT ALL ON *.* TO 'sita'@'%' IDENTIFIED BY 'Password';
mysql> CREATE DATABASE laravel DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
mysql> GRANT ALL ON laravel.* TO 'laraveluser'@'localhost' IDENTIFIED BY 'Password';
mysql> FLUSH PRIVILEGES;
mysql> quit
</pre>
另外要把 MySQL 的綁定地址由 127.0.0.1 修改為 0.0.0.0:
<pre class="command">
$ sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
$ sudo service mysql restart
$ sudo ufw allow from any to any port 3306 proto tcp
</pre>
安裝 Nginx 及配件:
<pre class="command">
$ sudo apt install nginx nginx-extras
</pre>
安裝防火牆:
<pre class="command">
$ sudo ufw app list
Available applications:
CUPS
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH
$ sudo ufw allow 'Nginx Full'
$ sudo ufw enable
$ sudo ufw status
Status: active
To Action From
-- ------ ----
3306/tcp ALLOW Anywhere
8888/tcp ALLOW Anywhere
OpenSSH ALLOW Anywhere
Nginx Full ALLOW Anywhere
3306/tcp (v6) ALLOW Anywhere (v6)
8888/tcp (v6) ALLOW Anywhere (v6)
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx Full (v6) ALLOW Anywhere (v6)
</pre>
Ubuntu 18.04 跟機的是 Python 3.6,要把它換成 Python 3.7:
<pre class="command">
$ sudo apt install python3.7 python3.7-dev
</pre>
為了不讓項目的模組互相干擾,需要用到 virtualenv 把它們分隔:
<pre class="command">
$ sudo apt install python3-pip python3-dev virtualenv
$ virtualenv -p python3.7 jupyter-env
$ . jupyter-env/bin/activate
</pre>
有了 Python 3.7 及進入了 virtualenv 後,就是安裝不同的模組了:
<pre class="command">
(jupyter-env) sudo apt-get install libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev
(jupyter-env) sudo apt-get install python3-dev python3-setuptools
(jupyter-env) sudo apt-get install libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python3-tk libharfbuzz-dev libfribidi-dev
(jupyter-env) /home/sitachan/jupyter-env/bin/python3 -m pip install --upgrade pip
(jupyter-env) /home/sitachan/jupyter-env/bin/python3 -m pip install --upgrade Pillow
(jupyter-env) /home/sitachan/jupyter-env/bin/python3 -m pip install python3-opencv
(jupyter-env) /home/sitachan/jupyter-env/bin/python3 -m pip install pandas
(jupyter-env) /home/sitachan/jupyter-env/bin/python3 -m pip install Cython
</pre>
有部份模組無法用 PIP 安裝,需要由 source code 編譯,像是 Matplotlib:
<pre class="command">
(jupyter-env) cd ~/Downloads
(jupyter-env) git clone https://github.com/matplotlib/matplotlib
(jupyter-env) cd matplotlib/
(jupyter-env) /home/sitachan/jupyter-env/bin/python3 setup.py build
(jupyter-env) sudo /home/sitachan/jupyter-env/bin/python3 setup.py install
</pre>
還有 Scipy:
<pre class="command">
(jupyter-env) cd ~/Downloads
(jupyter-env) git clone https://github.com/scipy/scipy.git
(jupyter-env) cd scipy/
(jupyter-env) /home/sitachan/jupyter-env/bin/python3 setup.py build
(jupyter-env) sudo /home/sitachan/jupyter-env/bin/python3 setup.py install
</pre>
到安裝 Jupyter 了:
<pre class="command">
(jupyter-env) pip3 install Cython --install-option="--no-cython-compile"
(jupyter-env) pip3 install pyzmq
(jupyter-env) pip3 install jupyter
(jupyter-env) jupyter notebook password
(jupyter-env) which jupyter-notebook
(jupyter-env) mkdir /home/sitachan/Documents/Jupyter-notebook
</pre>
設定以下內容:
<pre class="command">
(jupyter-env) sudo vi /etc/systemd/system/jupyter.service
[Unit]
Description=Jupyter Notebook
[Service]
Type=simple
PIDFile=/run/jupyter.pid
ExecStart=/bin/bash -c ". /home/sitachan/jupyter-env/bin/activate;jupyter-notebook --notebook-dir=/home/sitachan/Document”s/Jupyter-notebook
User=sitachan
Group=ubuntu
WorkingDirectory=/home/sitachan/Documents/Jupyter-notebooks
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
</pre>
重新啟動 Jupyter,它會出現在 http://192.168.1.100:8888/:
<pre class="command">
(jupyter-env) sudo systemctl enable jupyter.service
(jupyter-env) sudo systemctl daemon-reload
(jupyter-env) sudo systemctl start jupyter.service
(jupyter-env) systemctl status jupyter.service
</pre>
新的 Raspberry Pi 4 上其中一個功能是提供 VPN 服務。使用的是 L2TP 通訊格式。安裝方法如下:
<pre class="command">
(jupyter-env) wget https://git.io/vpnsetup -O vpnsetup.sh && sudo sh vpnsetup.sh
</pre>
安裝完成後會看到以下畫面:
<pre class="command">
================================================
IPsec VPN server is now ready for use!
Connect to your new VPN with these details:
Server IP: 17.172.224.47
IPsec PSK: akZVHfUFCNXJedSA8f3d
Username: vpnuser
Password: ce5XKjNJAKHLMt2D
Write these down. You'll need them to connect!
Important notes: https://git.io/vpnnotes
Setup VPN clients: https://git.io/vpnclients
================================================
</pre>
上面的 vpnsetup.sh 已自動建立了一個 VPN 帳號。為了安全考慮,要把帳號更改一下。先修改 PSK 密碼。在 Password 輸入自己的密碼並儲存:
<pre class="command">
(jupyter-env) sudo vi /etc/ipsec.secrets
%any %any : PSK "Password"
</pre>
然後設定帳號:
<pre class="command">
(jupyter-env) sudo vi /etc/ppp/chap-secrets
"pacess" l2tpd "Password" *
"sitachan" l2tpd "Password" *
</pre>
儲存後重新啟動 VPN 服務:
<pre class="command">
(jupyter-env) sudo service xl2tpd restart || sudo systemctl restart xl2tpd
(jupyter-env) sudo service ipsec restart || sudo systemctl restart ipsec
</pre>
建立網頁服務:
<pre class="command">
(jupyter-env) sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/www.pacess.com
(jupyter-env) sudo vi /etc/nginx/sites-available/www.pacess.com
server {
root /var/www/www.pacess.com/public;
# Add index.php to the list if you are using PHP
index index.php index.html;
server_name pacess.com www.pacess.com;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ /index.php?$query_string;
}
# pass PHP scripts to FastCGI server
#
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
(jupyter-env) sudo ln -s /etc/nginx/sites-available/www.pacess.com /etc/nginx/sites-enabled/
(jupyter-env) sudo systemctl reload nginx
</pre>
安裝 Certbot:
<pre class="command">
(jupyter-env) sudo add-apt-repository ppa:certbot/certbot
(jupyter-env) sudo apt-get update
(jupyter-env) sudo apt-get install python-certbot-nginx
(jupyter-env) sudo certbot --nginx -d pacess.com -d www.pacess.com
</pre>
<br>參考:
<br>https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04#step-4-—-obtaining-an-ssl-certificate
<br>https://computingforgeeks.com/build-ipsec-vpn-server-with-ipsec-l2tp-and-cisco-ipsec-linux/
<br>https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-18-04
<br>https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-on-ubuntu-1804Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-35135777365504133992020-03-20T23:20:00.000+08:002020-03-21T17:48:40.339+08:00架設 Raspberry Pi 4 以 SSD 起動Raspberry Pi 必須要以 SD 卡啟動,至少就目前來說是這樣。我希望它能以 SSD 作為主要儲存媒體。要達到這個目的,需要做一點修改。以下是在 macOS Catalina 的步驟。<br>
<br>
<a href="https://2.bp.blogspot.com/-TqNaL_jhhwE/XnTSSwCdJyI/AAAAAAAARk4/uJ5YB2oNK7oQhCQEQluaLzMVFgEj2LMjACLcBGAsYHQ/s1600/raspberrypi-ubuntu-usb-drive.jpg" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-TqNaL_jhhwE/XnTSSwCdJyI/AAAAAAAARk4/uJ5YB2oNK7oQhCQEQluaLzMVFgEj2LMjACLcBGAsYHQ/s640/raspberrypi-ubuntu-usb-drive.jpg" width="640" height="254" data-original-width="1600" data-original-height="635" /></a><br>
首先,到 <a href="https://ubuntu.com/download/raspberry-pi">https://ubuntu.com/download/raspberry-pi</a> 下載 Ubuntu 18.04 64-bit 版本。把影像檔以 <a href="https://www.balena.io/etcher/">balenaEtcher</a> 分別燒錄到 SD 卡及 SSD。在 Terminal 輸入 lsusb。把 SSD 以 USB 接上電腦,然後再輸入:
<pre class="command">$ lsusb</pre>
查看多出來的一行的 SSD 的編號。如上圖所示,我的 SSD 編號是 152d:0583,把它記錄下來。插入 SD 卡,打開 /nobtcmd.txt。把「root=LABEL=writable」改為「root=/dev/sda2」。如果使用的是非 ORICO 連接合,則需要在行首輸入「usb-storage.quirks=152d:0583:u 」,那是剛才得到的 SSD 編號。這是告知 Raspberry Pi 啟動的裝置是 SSD。<br>
<br>
<a href="https://1.bp.blogspot.com/-h93lfmYuPew/XnTSS2qbSaI/AAAAAAAARk8/kWlSh5oXf6UqaPtO5GFU7AO1ts4C2CyXQCLcBGAsYHQ/s1600/raspberrypi-ubuntu-ssd-expanded.jpg" imageanchor="1" ><img border="0" src="https://1.bp.blogspot.com/-h93lfmYuPew/XnTSS2qbSaI/AAAAAAAARk8/kWlSh5oXf6UqaPtO5GFU7AO1ts4C2CyXQCLcBGAsYHQ/s640/raspberrypi-ubuntu-ssd-expanded.jpg" width="640" height="294" data-original-width="1600" data-original-height="734" /></a><br>
把 SD 卡和 SSD 都接上 Raspberry Pi 4,然後開機。當成功運行後,輸入:<br>
<pre class="command">$ findmnt -n -o SOURCE /</pre>
如果顯示 /dev/sda2 代表了正在使用 SSD 作為主要儲架媒體。再以:
<pre class="command">$ df -h</pre>
觀看 SSD 的大小。我的 SSD 是 512GB,看到哪個 470G 就是了。<br>
<hr>參考:
<br><a href="https://krdesigns.com/articles/raspberry-official-ubuntu-18.04.04-bootable-from-USB-SSD-drive">https://krdesigns.com/articles/raspberry-official-ubuntu-18.04.04-bootable-from-USB-SSD-drive</a>
<br><a href="https://jamesachambers.com/raspberry-pi-4-usb-boot-config-guide-for-ssd-flash-drives/">https://jamesachambers.com/raspberry-pi-4-usb-boot-config-guide-for-ssd-flash-drives/</a>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-67881725770097893272020-03-19T22:13:00.000+08:002020-03-21T14:50:19.272+08:00安裝新伺服器硬體<a href="https://1.bp.blogspot.com/-4eGoseOsFl4/XnTM_VeK6KI/AAAAAAAARkY/BnJF6bFFTF0ygFVUbzQULUDrmps2gEwsACLcBGAsYHQ/s1600/raspberry-pi-4.jpg" imageanchor="1" ><img border="0" src="https://1.bp.blogspot.com/-4eGoseOsFl4/XnTM_VeK6KI/AAAAAAAARkY/BnJF6bFFTF0ygFVUbzQULUDrmps2gEwsACLcBGAsYHQ/s640/raspberry-pi-4.jpg" width="640" height="480" data-original-width="1600" data-original-height="1200" /></a><br>
公司的 Raspberry Pi 4 是二十四小時全天候運行,它的透明塑膠外殼附帶了一把小風扇能有效散熱,只感到微微的溫暖。我的 Raspberry Pi 是用來作為伺服器,熱力可能會更高,所以選擇了散熱效能更強的外殼。<br>
<br>
<a href="https://4.bp.blogspot.com/-10ZsW4g4wWA/XnTM_TLPhJI/AAAAAAAARkc/XbGhaNJfz5APNPrAccz9tqSGhpt34aPpgCLcBGAsYHQ/s1600/raspberry-pi-4-case.jpg" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-10ZsW4g4wWA/XnTM_TLPhJI/AAAAAAAARkc/XbGhaNJfz5APNPrAccz9tqSGhpt34aPpgCLcBGAsYHQ/s640/raspberry-pi-4-case.jpg" width="640" height="480" data-original-width="1600" data-original-height="1200" /></a><br>
星期一在淘寶以 ¥60 購買了這款外殼。它是由鋁製成,還附帶了兩把小風扇;金屬外殼與晶片之間貼上了導熱矽膠,能把熱力快速傳播並由冷風帶走。希望不會使伺服器的溫度太熱。<br>
<br>
<a href="https://2.bp.blogspot.com/-r-8cOBoJLZE/XnTPK9YX5lI/AAAAAAAARks/TKGzzdd2kWAEabECZQGihy3indoyPYAKwCLcBGAsYHQ/s1600/raspberry-pi-4-server.jpg" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-r-8cOBoJLZE/XnTPK9YX5lI/AAAAAAAARks/TKGzzdd2kWAEabECZQGihy3indoyPYAKwCLcBGAsYHQ/s640/raspberry-pi-4-server.jpg" width="640" height="480" data-original-width="1600" data-original-height="1200" /></a><br>
<a href="https://pacess.blogspot.com/2020/03/raspberry-pi-4-ssd-server-02.html">安裝好 SSD 儲存裝置</a>後,便是我新的 Raspberry Pi 4 伺服器了。Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-78356807232031935732020-03-18T21:50:00.000+08:002020-03-21T14:49:15.376+08:00安裝 SSD<a href="https://2.bp.blogspot.com/-YLGmal_SReQ/XnS6Ckjc2PI/AAAAAAAARjo/02ug86cbpTwvtCOhGmcpBVPg41JRn1iYQCLcBGAsYHQ/s1600/orico-nvme-m2-ssd-enclosure.jpg" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-YLGmal_SReQ/XnS6Ckjc2PI/AAAAAAAARjo/02ug86cbpTwvtCOhGmcpBVPg41JRn1iYQCLcBGAsYHQ/s640/orico-nvme-m2-ssd-enclosure.jpg" width="640" height="382" data-original-width="1600" data-original-height="955" /></a><br>
我喜歡 ORICO NVMe M.2 SSD Enclosure TCM2-C3 的透明設計。它的包裝普通而細心。一條 USB Type-A 到 USB Type-C 線、一條 USB Type-C 到 USB Type-C 線、一支小螺絲批、兩片導熱矽膠。<br>
<br>
<a href="https://1.bp.blogspot.com/-S8kM45FkX0c/XnS6HkBZoYI/AAAAAAAARjs/WaVa0TtwD5URKOr5ekHi4_CqouoSppetQCLcBGAsYHQ/s1600/adata-xpg-sx8200-pro-512gb-ssd.jpg" imageanchor="1" ><img border="0" src="https://1.bp.blogspot.com/-S8kM45FkX0c/XnS6HkBZoYI/AAAAAAAARjs/WaVa0TtwD5URKOr5ekHi4_CqouoSppetQCLcBGAsYHQ/s640/adata-xpg-sx8200-pro-512gb-ssd.jpg" width="640" height="439" data-original-width="1600" data-original-height="1097" /></a><br>
SSD 方面,了解過不同牌子和型號,選擇了 Seagate 512GB BarraCuda 510 M.2 2280。可是到旺角電腦中心購買時沒有貨,選擇了這款次選的 ADATA 512GB XPG SX8200 Pro M.2 2280。除了一片 SSD 外,還附帶一片散熱片。<br>
<br>
<a href="https://1.bp.blogspot.com/-ioyXsIbXyrA/XnTDiV3K_qI/AAAAAAAARkE/nRLlJcYntCQ7B9oqPEtMJ7G04HIDeWMMACLcBGAsYHQ/s1600/orico-nvme-m2-ssd-enclosure-only.jpg" imageanchor="1" ><img border="0" src="https://1.bp.blogspot.com/-ioyXsIbXyrA/XnTDiV3K_qI/AAAAAAAARkE/nRLlJcYntCQ7B9oqPEtMJ7G04HIDeWMMACLcBGAsYHQ/s640/orico-nvme-m2-ssd-enclosure-only.jpg" width="640" height="491" data-original-width="1600" data-original-height="1228" /></a><br>
ORICO 的盒子只要輕輕一推便能鬆開。要拿出電路板,把 SSD 安裝進去。<br>
<br>
<a href="https://1.bp.blogspot.com/-xjNapcR6TbY/XnTDXfX_gWI/AAAAAAAARj8/noe6zfDl1TgaYDM8yaPad5tdcs_eclyQgCLcBGAsYHQ/s1600/orico-nvme-m2-ssd-enclosure-with-adata-ssd.jpg" imageanchor="1" ><img border="0" src="https://1.bp.blogspot.com/-xjNapcR6TbY/XnTDXfX_gWI/AAAAAAAARj8/noe6zfDl1TgaYDM8yaPad5tdcs_eclyQgCLcBGAsYHQ/s640/orico-nvme-m2-ssd-enclosure-with-adata-ssd.jpg" width="480" height="640" data-original-width="1200" data-original-height="1600" /></a><br>
在 SSD 末端裝上卡關螺絲後,把電路板放回盒子。然後在 ORICO 的散熱板背部貼上導熱矽膠。位置是隨意地貼。我選了 SSD 晶片較集中的位置。<br>
<br>
<a href="https://1.bp.blogspot.com/-LxjiP1w4zKk/XnTDXe_C1zI/AAAAAAAARkA/XzgGWfj9i-wfZOXgS1mfvlgHpqHYENzDgCLcBGAsYHQ/s1600/orico-nvme-m2-ssd-enclosure-installed.jpg" imageanchor="1" ><img border="0" src="https://1.bp.blogspot.com/-LxjiP1w4zKk/XnTDXe_C1zI/AAAAAAAARkA/XzgGWfj9i-wfZOXgS1mfvlgHpqHYENzDgCLcBGAsYHQ/s640/orico-nvme-m2-ssd-enclosure-installed.jpg" width="640" height="480" data-original-width="1600" data-original-height="1200" /></a><br>
最後把蓋子合上就完成安裝 SSD 的步驟。這就是新伺服器的儲存裝置。Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-11518273705192066832020-03-16T22:21:00.000+08:002020-03-21T14:48:43.660+08:00選擇新伺服器硬件<a href="https://3.bp.blogspot.com/-iqwQCjZAx9M/XnBr7TppWfI/AAAAAAAARi4/68CnLCNHLAMGoB_LVEl6Nkz66WNNTvEmwCLcBGAsYHQ/s1600/800182E6-8065-4618-8096-290DC4E94BE1.jpeg" imageanchor="1" ><img border="0" src="https://3.bp.blogspot.com/-iqwQCjZAx9M/XnBr7TppWfI/AAAAAAAARi4/68CnLCNHLAMGoB_LVEl6Nkz66WNNTvEmwCLcBGAsYHQ/s640/800182E6-8065-4618-8096-290DC4E94BE1.jpeg" width="640" height="480" data-original-width="1600" data-original-height="1200" /></a><br>
家中帶有光碟機的 Mac mini Server 是很多年前的產品,已經變得很慢。雖然它還能提供服務,但就不能切合時代變遷的需求,是時候退下來到蘋果產品博物館。從功能、體積、效能、價錢各方面的考慮後,新的伺服器將選用 Raspberry Pi 4 + 512GB SSD。<br>
<br>
伺服器是 24 小時運作,如果單純用大容量 SD 卡的話,速度是夠快,但壽命則不會長久。SD 卡及 Flash Drive 的設計是讀寫頻率低的工作。既然是全天候運作,得找讀寫頻率高的設備。SATA 硬碟及 SSD 硬碟就能滿足這個需求。我希望裝置細小、快速、安靜、堅固,預算在 HK$600 左右。SSD 有符合這些條件的選擇。<br>
<br>
SSD 有兩種設計。一種是細小的盒子,以 USB Type-A 線連接;另一種是手提電腦用,像記憶體般的 m2 格式電路板。Raspberry Pi 4 沒有相關接合,須另購連接盒;能以 USB Type-C 線連接。有了盒子的話,兩者都方便攜帶。然而,前者的傳輸速度多為每秒 540MB;後者則多為每秒 3400MB。USB Type-C 的傳輸上限為每秒 20G bps,約是 2500MB 左右。而 Raspberry Pi 4 只有 USB Type-A 3.0 接口,速度是 5G bps,約是 640MB 左右。意味著用 m2 也最多只有這種速度,確是有點浪費。不過,小盒子與 m2 在相同容量的價錢只相差 HK$100 左右。在眾多品牌和型號中,我選擇了後者的 ADATA 512GB XPG SX8200 Pro M.2 2280 PCIe Gen3x4 SSD。外置盒則選擇 ORICO NVMe M.2 SSD Enclosure TCM2-C3,喜歡它的外形和透明設計。
Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-29206059392019875262020-03-12T22:47:00.000+08:002020-03-12T22:47:09.653+08:00武漢肺炎強制家居檢疫趨勢圖<a href="https://4.bp.blogspot.com/-XaM4ZzazcA4/XmoAzJFPCSI/AAAAAAAARiU/gNdwBVAKcPA8ucUoO9H3aqtMlKTnF-VKACLcBGAsYHQ/s1600/20200311_wuhan.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-XaM4ZzazcA4/XmoAzJFPCSI/AAAAAAAARiU/gNdwBVAKcPA8ucUoO9H3aqtMlKTnF-VKACLcBGAsYHQ/s640/20200311_wuhan.png" width="640" height="382" data-original-width="1191" data-original-height="711" /></a><br>
武漢肺炎疫情持續有一個多月了。我們身處數位時代,香港政府的資料一線通提供了滯後的「<a href="https://data.gov.hk/tc-data/dataset/hk-dh-chpsebcddr-novel-infectious-agent/resource/590caeff-3edf-45cb-991b-0e13f4847545">根據香港法例第 599C 章正在接受強制家居檢疫人士所居住的大廈名單</a>」。雖為何會說滯後?因為強制家居隔離十四天,如果數據是 3 月 10 日,理應完成隔離的時間是十四天的 3 月 23 日。當然輸入資料需時,但也不用四天吧。雖然資料滯後,但還是有參考價值。<br>
<br>
利用 Python 3.7 + Pandas 把 CSV 數據載入並以圖表顯示,能讓我們更容易了解箇中的趨勢變化:
<pre style="background:#fff9e7; padding:10px">
import datetime
import pandas
import numpy
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plot
%matplotlib inline
## Read CSV data
dataPath = "../Dataset/Coronavirus Disease (COVID-19)/20200311_home_confinees_tier2_building_list.csv"
data = pandas.read_csv(dataPath)
## Convert string to datetime
fieldName = data.columns[3]
data[fieldName] = pandas.to_datetime(data[fieldName], format='%d/%m/%Y')
_title = '衛生署 COVID-19 家居隔離 599C 資料'
count = data.shape[0]
_csvNote = '截至 2020 年 3 月 11 日,共 '+str(count)+' 人'
## Prepare title
fieldName = data.columns[3]
x = data[fieldName].to_numpy()
fromDate = numpy.amin(x)
fromDateString = pandas.to_datetime(str(fromDate)).strftime('%b-%d')
toDate = numpy.amax(x)
toDateString = pandas.to_datetime(str(toDate)).strftime('%b-%d')
title = '由 '+fromDateString+' 至 '+toDateString+' 隔離人數'
## Show chart base on finish date
fieldName = data.columns[3]
result = data.groupby([fieldName])[fieldName].count().reset_index(name='Count').sort_values([fieldName], ascending=True)
x = result[fieldName].to_numpy()
y = result['Count'].to_numpy()
height = numpy.amax(y)
x2 = [pandas.to_datetime(str(date_obj)).strftime('%b-%d') for date_obj in x]
plot.rcParams['font.sans-serif'] = ['Heiti TC']
plot.rcParams['axes.unicode_minus'] = False
plot.rcParams['font.size'] = 16
figure, axis = plot.subplots(figsize=(20,10))
axis.plot(x2, y, marker='o')
axis.set(xlabel=fieldName, ylabel='數量', title='所有地區隔離人數')
axis.grid()
for i, j in zip(x2, y):
axis.annotate(str(j), xy=(i, j))
plot.xticks(rotation=80)
plot.suptitle(_title, fontsize=28)
plot.text(0, height, _csvNote, fontsize=16)
plot.show()</pre>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.comtag:blogger.com,1999:blog-7483265378974822546.post-77268124940633349922020-03-11T21:54:00.000+08:002020-03-11T21:54:33.287+08:00測試股票買賣演算法<a href="https://3.bp.blogspot.com/-47DHAnLVDqo/XmjsjveVvZI/AAAAAAAARiI/B6k_ZHQz3jwUZfw4tJajDcsDNmx1EzBXwCLcBGAsYHQ/s1600/0005.hk-2313.hk.jpg" imageanchor="1" ><img border="0" src="https://3.bp.blogspot.com/-47DHAnLVDqo/XmjsjveVvZI/AAAAAAAARiI/B6k_ZHQz3jwUZfw4tJajDcsDNmx1EzBXwCLcBGAsYHQ/s640/0005.hk-2313.hk.jpg" width="640" height="345" data-original-width="1209" data-original-height="651" /></a><br>
昨天學習到利用 Pandas DataReader 取得過往股票數據;今日嘗試編寫股票買賣演算法去估算資產收益。如果十年前以 HK$100,000 本金去購買兩隻股票,到今日資金會變成接近 $37 萬或 $20 萬。看來成效不錯。繼續修改演算法,看看會否有更好的成績,或是不論哪隻股票也是有這樣的表現。Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-26787452782790378882020-03-10T22:49:00.000+08:002020-03-12T17:48:54.950+08:00Pandas DataReader<a href="https://2.bp.blogspot.com/-z-plPYY4H40/XmenxNsmf-I/AAAAAAAARhc/SC-VSA0zfxg1_JHChImlaPDWPobXugXXACLcBGAsYHQ/s1600/pandas-datareader.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-z-plPYY4H40/XmenxNsmf-I/AAAAAAAARhc/SC-VSA0zfxg1_JHChImlaPDWPobXugXXACLcBGAsYHQ/s640/pandas-datareader.png" width="640" height="484" data-original-width="1600" data-original-height="1209" /></a><br>
瀏覽網頁時,發現到一個叫 Pandas DataReader 的 Python 模組,能讓程式猿輕易取得過往的股票數據;不論是美股還是港股,都能提取;而且是免費呢。真的十分方便。安裝方法如下:
<pre style="background:#000000; color:#00ff00; padding:10px">pip3 install pandas-datareader</pre>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-81733158249641265132020-03-08T10:21:00.000+08:002020-03-08T11:43:16.525+08:00NFC Checkin 開發結果離開了 iOS 最新技術有幾年時間,變得生手。這個項目,由最開始用 SwiftUI 建構畫面失敗,換回 Objective-C 而藍牙 Framework 出事,還是要轉回 Swift,今次嘗試純 Swift 5。邊學邊做,花了 22 小時完成了一個 NFC Solution。能成功辨認到 MiFARE Classic 1K 卡的獨立編號很有滿足感。看似是小事,但這是 Vendor 說的不可能,我把它實現。遇到 Framework 沒有觸發時的 Callback,要令到 Solution 好用、快速、簡單,想到用 Threading 方法解決。重重難題都解決了,下一步是找個場合正式使用。
<br>
<iframe width="560" height="315" src="https://www.youtube.com/embed/R6iXsBYTMIY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0tag:blogger.com,1999:blog-7483265378974822546.post-558385890845661872020-03-07T20:14:00.002+08:002020-03-07T20:14:43.318+08:00用 PIL 把 PNG 轉成 Webp自行修改的 WhatsApp Sticker 應用程式在幾個月前加入了 Pack URL 安裝功能,不用再把 PNG 轉成 Webp 後再打包上 TestFlight,流程加快了很多。經過幾個月後,老人家忘了如何把 PNG 轉成 Webp,需要在這裡記載一下:
<pre style="background:#fff9e7; padding:10px">from PIL import Image
image = Image.open("snake.png")
image.save("snake.webp", "webp")</pre>Pacesshttp://www.blogger.com/profile/06132943565155241514noreply@blogger.com0