2017/11/17

PostgreSQL 入門教材

PostgresSQL 官方文件實在缺東缺西,只好找第三方教學文件來看了:


這次會跑來看 PostgreSQL 主要是 Gitlab 對 MySQL 的支援實在有點爛,做 migration 會莫名其妙卡住,索性把 Gitlab 的資料丟到 PostgreSQL,但其他專案仍維持在 MySQL 運行。

2017/11/15

PHP 變數初始化 (?)

看到有 Java 工程師在學 PHP 遇到變數初始化的問題,覺得有趣,做個筆記順便複習 PHP 的特性。

Java 是強型別 (strong type) 的程式語言,所有的變數在使用之前都必須給資料型態以及初始值;PHP 則是弱型別,就算不給值、不給資料型態也沒差,interpreter 會在 runtime 的時候自動做型別轉換在繼續執行程式。我想 PHP 這一特性就會讓很多 Java 工程師決得很莫名其妙吧,沒定義的變數到底要怎麼用?執行的時候真的不會出事嗎? (其實就是會 XD)

先來看正常的寫法:
$x = 'hello';
var_dump($x);  // "hello"

如果變數沒有給值會發生什麼事?
var_dump($x);  // NULL

PHP 把沒有初始化的變數帶入 NULL 來使用,連錯誤訊息都沒噴耶?其實有,只是要調整一下 error reporting 的 level:
error_reporting(E_ALL);

var_dump($x);

// Notice: Undefined variable: x
// NULL

2017/11/10

函式中參數順序的設計

最近在 refactor legacy code,遇到很尷尬的函式定義,笑也不是哭也不是。

函式會要求使用者傳入多個參數,有時並不是所有的參數都必須給值,函式的設計者會以大家較常使用的方式來當作參數的預設值,例如 PHP 裡面的「json_decode()」:
json_decode($json);  // consider as json_decode($json, false)

json_decode($json, true);  // 不使用預設值才手動傳數第二個參數


但這次遇到比較尷尬的是,legacy code 把第一個參數設計為 optional,也就是有預設值。但問題來了,在 PHP 的語法當中,呼叫函式無法在前幾個參數不給值:
getData( , 'some', 'option');  // syntax error

所以不管怎麼樣,都至少要給第一個參數:
getData(null, 'some', 'option');

所以把有預設值的參數放在前面其實根本沒有省下什麼時間呀 ... XD

2017/10/30

PTT 官方網頁版

不多說,連結是:https://term.ptt.cc



這次會讓我比較興奮的是從 telnet 通訊協定,換上 HTTPS + websocket,這樣帳號密碼傳送就安全很多了。

其實叫早之前也是可以使用 SSH 連線:
ssh bbs@ptt.cc

ssh bbsu@ptt.cc   # UTF-8 版本



翻了一下 source code,這次網頁有用心處理編碼轉換問題,一開始就載入了 big5 <-> UTF-8 對應表。接下來就全部使用 websocket 連線了。

2017/10/20

讓 MySQL 在查詢時區分英文大小寫

今天又遇到相同的問題,解法有很多種,可以從 SQL 下手,也可以在 table schema 就先做好設定。


SQL 強制區分大小寫


假設原本的 SQL 為:
SELECT * FROM users WHERE name = 'john' ;

這樣會撈出「John」、「john」等結果。那麼可以要求 MySQL 使用 binary 的辨識方法去做搜尋:
SELECT * FROM users WHERE binary name = 'johhn';

這樣一來,查詢時 name 欄位就會區分大小寫來做查詢。



修改 table schema


如果在設計 table 時,就確定查詢一定要區分大小寫時,可以在 create table 就先將欄位設定好:
CREATE TABLE users (
    name varchar(100) binary
)

這樣之後下 query 時,只要遇到 name 欄位,就自動會區分大小寫。



修改 collation type


一般常用的 collation 是「utf8_general_ci」,該 collation 最後面的「ci」其實是「Case Insensitive」的意思,也就是不區分大小寫。

如果要讓該 table 的所有欄位都區分大小寫,可以將 collation 的 postfix 改為「cs」或是「bin」,例如:
CREATE TABLE user (
    name varchar(100)
) COLLATE utf8_general_bin ;



以上三個區分大小寫的方法 scope 差異頗大的,可以挑比較適合當下情況的方法來使用。

2017/10/18

各家廠商針對 wifi Krack 的動作

KRACK 問題不是僅針對特定 WPA 戰點的問題,而是通訊協定上面的問題,基本上各家廠商都需要為了這個漏洞進行修補。

BleepingComputer 網站上的作者,已經至各大 wifi 供應商搜尋官方回應以及解決 KRACK 的動作,可以看到 Cisco、D-Link、DrayTek、MikroTik、Netgear、TP-Link、Zyxel 幾乎都有動作了:https://www.bleepingcomputer.com/news/security/list-of-firmware-and-driver-updates-for-krack-wpa2-vulnerability/

補充:Github 這邊有更詳細的整理


至於 ASUS 呢?官方討論區一堆人在問,但是官方完全沒有回應。這可能會是以後我買 wifi AP 的一個評分項目 .....

2017/10/17

WPA2 金鑰交換協議問題導致的安全漏洞

T 客邦看到「破功確認!KRACK破解 WPA2 原理已公開,你家的無線路由器還安全嗎?」,是在於 wifi 路由器和 client 做金鑰交換時,原本擔心擔心環境中的訊號傳遞不好,所以在金鑰交換協議上制定在雙方都沒有確認金鑰交換成功時,可以再次跑一次金鑰交換的流程。

比較尷尬的是,這份金鑰交換的協議並沒有制定怎麼樣才算交換成功,而中止流程。所以駭客只要發出金鑰交換的訊號,client 以為要再次跑流程時就會中招。

看起來目前的解決方法,就是先降低 wifi 訊號強度,讓只有 wifi client 所在環境才收的到訊號,讓偽造的金鑰交換訊號沒辦法進入 wifi 使用環境範圍內。再來就是等 wifi 的通訊協定更新了。

gslin 這邊提到,走 wifi 最安全的方法還是用 VPN。總之,電磁波是任何人都可以收到的,有無線網路至少、至少都要使用有 HTTPS 的加密通訊。

2017/10/11

建立供行動裝置使用的網頁瀏覽界面

最近用手機追新聞有感,分享一下心得。

由於行動裝置的使用量漸漸超越了桌上型電腦,而行動裝置為了攜帶方便體積本身就小,連帶的螢幕也較桌上型電腦小很多,因此不少網路服務也跟著建立行動裝置專用的網頁,像是自由時報就有針對行動裝置客製化網頁:




有留意的話可以發現行動版網頁的網址和供一般電腦瀏覽的網址是不一樣的,如了全幅廣告不說,網頁寬度、排版方式都看電腦版不同。

這時如果覺得文章不錯,透過行動裝置分享道社交平台上,別人如果是使用電腦開啟時,則會出現這樣的畫面:


別人就會變成使用超大螢幕來看超小版面的新聞,而且還有全幅蓋版廣告喔 XD

如果有 sense 一點的人,可能會想試著把網址「http://m.ltn.com.tw」改成「http://www.ltn.com.tw」嘗試開啟一般網頁版來閱讀,可惜自由時報沒有這個設計,改完網址只會顯示 404 找不到網頁 (但蘋果日報將網址改為 www 開頭以後是可以正常瀏覽的,這個設計頗為貼心)。

那什麼樣的設計才能同時滿足行動裝置以及一般電腦呢?可以參考 Wikipedia

Wikipedia 使用 Responsive Web Design (RWD) 來讓瀏覽器自動判斷裝置、螢幕大小,並自動更換成適合閱讀的版面。即使網址相同,在不同裝置上可以呈現不同的畫面,讓使用者方便閱讀。

只是一自己的經驗,要設計一個讓不同行動裝置都可以正常瀏覽、顯示符合需求的 CSS,費工又費時,就看業者到底想要給使用者什麼樣的體驗了。

2017/10/09

PHP curl 的一些特性

curl 在 PHP 中是以 extension 形式存在,所以只能透過 resource reference 去操作 curl 行為,沒辦法透過 debug 工具摸清楚 curl 在背景到底做了哪些事情。

手癢用 memory_get_usage() 看了一下 curl 在 init、exec 以及 close 這幾個狀態的記憶體使用量,來猜測 curl 到底怎麼運作。

echo memory_get_usage() . "\n"   // 236136;

$ch = curl_init();
var_dump($ch);                   // resource(4) of type (curl)
echo memory_get_usage() . "\n";  // 237472

在 init_curl() 以後,會先在記憶體中 allocate 並放一些資料,所以吃掉大概 1 KB 左右的記憶體,再將 curl 的 reference 傳出來給 $ch。

2017/10/03

使用 VCS 時程式中不應該出現的東西

這件事情應該要從 FreeBSD 6 左右的 make build world && make install world 開始說起。每次 build world 以後,新版的 tool chain 設定檔可能都會有小部份的更新,可能是多幾個功能可以設定,或是把一些舊的功能拔掉,這時 install world 時為了擔心使用者改過的 config 檔直接被覆蓋掉,都會先做一次 diff 讓使用者確定設定檔更新以後不後搞垮系統。但有半數以上的 diff,均為 config 中開發人員的註解,像是「2005/xx/xx 最後更新」之類的,單單處理這類的 diff 就可以耗掉數十分鐘。

現在大家在寫程式時,應該都有習慣將 source code 放進 version control system (VCS) 中,方便做版本管理以及除錯。VCS 除了能夠協助開發者幫不同的修改留下記錄以外,也支援版本之間的比較、建立補丁 (patch) 等功能,讓開發者可以專心在功能的開發上。

既然 VCS 已經協助開發者記錄了這麼多東西,那有哪些是開發者已經不需要寫在 source code 裡面的呢?

  • 日期:大多數的 VCS 在開發者 commit 時就會記錄日期,開發者有修改時不必特別在程式中註解修改日期,只要 commit 時將 commit message 寫好讓其他人看得到、搜尋的到即可。
  • 作者:每個開發人員在 VCS 都會被視為不同的 commitor,所以哪個 commit 是誰送、甚至哪一行是誰修改的都有記錄。把修改原因寫清楚比較重要。
  • 註解掉不使用的程式碼:因為 VCS 會保留從古到今所有的程式碼異動,所以大可不用擔心程式碼刪除以後無法還原,若發現某一段程式已經不再使用了,就放心的把他刪掉吧,萬一誤砍了還是可以透過 VCS 復原回來。(如果 VCS 做不到這個功能就換一個吧 XD)
  • 與專案無關的 binary:大多數 icons、font、design files 都會與專案的版本一起演進,放進 VCS 是應該的。但與專案週期不同、或為一次性用途的 binary 檔案,如週年慶的活動圖片設計、影片等,就不適合放進 VCS,若真的有版本管理需要,應該另外開一個 repository。
  • symbolic link:恩 .... 有事嗎?

2017/09/29

三節禮品

經過幾間不同的公司,三節獎金和禮品也都不盡相同,想了想還是電影票比較實在。

電影票過期補差價還是可以繼續使用,如果沒在看電影,票券轉賣也比較容易。

但是收到米袋就有點 ....

2017/09/26

各家手機的 I/O 性能測試

以前一直以為是自己買的 MicroSD 卡不夠強,所以讀取、寫入都很慢,經過幾個朋友一起測試以後,才知道其實瓶頸根本不是在記憶卡,而是手機內建的硬體支援有些原本就很低。

以下的結果均是使用 A1 SD Bench 測試以後的結果,先來貼一下我自己正在使用的 Sony 系列測試。

Sony


Sony Xperia XZ:SD 卡的寫入速度只有 30 MB/s,不是你的 SD 卡不夠好

2017/09/12

使用 datastax/php-driver 對 Cassandra 做 query 需要留意的地方

最近在研究如何把 log 塞到 Cassandra 中,使用的 Datastax 的 php-driver 輕鬆很多,但還是有一些需要留意的地方,免得莫名其妙鬼打牆。

這邊先假設我要記錄一個使用者上傳檔案的記錄,包含 ID、檔案名稱、檔案大小以及上傳日期,建立了一個 table:
CREATE TABLE hermes_log.file (
    id uuid,
    name text,
    size decimal,
    create_time timestamp,
    PRIMARY KEY (id, name, size, create_time)
)

這個時候使用 PHP 塞資料進入,直接建立 CQL 且不使用 prepare/binding,可以成功執行 insertion:
<?php

$cluster = Cassandra::cluster()->build();
$session = $cluster->connect();
$cql = "
    insert into hermes_log.file
    (
        id,
        name,
        size,
        create_time
    ) values (
        uuid(),
        'gavatar.jpg',
        123.4,
        '2017-01-01 10:30:45.678'
    )
";

$session->execute($cql);

cqlsh 看一下資料格式:
cqlsh:zero_test> select name, size, create_time from file;

 name        | size  | create_time
-------------+-------+---------------------------------
 gavatar.jpg | 123.4 | 2017-01-01 02:30:45.678000+0000

(1 rows)

除了日期會自動轉為 UTC+00:00 以外其他都沒什麼太大的問題。

2017/09/05

Garmin 智慧手錶維修心得

先講一下故障情況:
  • 我使用的是 fenix 3 HR
  • 發現有問題的狀況
    • 去爬山時手錶的高度計比官方公佈的海拔高了超過 1000 公尺 (一個莫名其妙上百岳的狀態)
    • 自己壓脈搏時的心律與手錶顯示的差太多 (手量約 160 bpm,但手錶顯示約 90 bpm)
  • 已經心律感應器清洗乾淨

以上步驟做完還是有問題,於是寄信像客服詢問,客服這邊檢查的標準流程是:
  1. 先上官方網站更新韌體
  2. 清潔感應器
  3. 清理手錶右側的孔洞 (好像是氣壓計)

如果以上幾個步驟做完問題還在,再去填寫維修單,並將故障品送回廠內檢修:https://my.garmin.com.tw/myGarmin/rma/onlineNewRma

很意外的,工程師說檢查不出問題 (EMP 作祟),但讓我驚訝的是他們直接換一支新的手錶給我,雖然辦法判斷是新品還是良品,但由錶帶的鬆緊,可以卻認真的不是原有的手錶。

總之,整體服務讓我感到蠻貼心的。

用 Apache Bench (ab) 可能無法模擬高負載的網站實際情況

看到一篇「Why Apache Benchmark Is Not Enough」,這邊提到 Apache Benchmark (以下簡稱 ab) 由於都固定戳同一個 URL,這個情況下有很大的機會讓 HTTP server 或是 DB 用到相同的資並 cache 起來。

這樣子其實 ab 計算出來的 request per second 等數據,就失去了參考價值。

若要模擬真實的情境,像是「使用者看到圖片以後點擊連結開啟令一個網頁」,可以考慮使用 Apache jMeter 來建立不同的網頁 request 流程、隨意點擊,讓測試時更像真人在瀏覽網頁。

2017/09/04

使用 Linux rsyslog 儲存 ASUS Wifi 分享器的 log


因為一些原因,需要保留極度完整的 log,所以研究怎麼把 Wifi AP (router) 的記錄全部倒進 linux  的 rsyslog。

先修改 /etc/rsyslog.conf 裡面的幾個項目:
# provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

# provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514

把「ModLoad」、「UDPServerRun」、「InputTCPServerRun」的註解拿掉,這樣 rsyslog 就會使用 TCP 和 UDP listen port 514。當然在啟動之前要記得先去把防火強的設定弄好。

接下來重新啟動 rsyslog:
$ sudo service rsyslog

啟動完成沒有看到什麼錯誤訊息,表示已經開始運作了。接著「tail -f /var/log/syslog」應該就會看到 remote server 的資料。



但不同機器的訊息方在相同的檔案上實在很難追蹤,所以再多做一個設定,將不同機器傳過來的資料分開存放在不同的檔案。這類的設定檔會放在「/etc/rsyslog.d」,眼尖的話應該已經注意到 ufw、postfix 等服務已經有建立自己的設定了,我們參考著做即可。

假設今天 Wifi AP 的 IP 是「192.168.0.1」,而負責存放所有 log 的 loghost IP 為「192.168.0.101」,設定可以這樣寫:
if $fromhost-ip startswith '192.168.0.1' then /var/log/wifi.log
& ~

這樣 rsyslog 只要遇到從 192.168.0.1 傳過來的資料,就一律丟到「/var/log/wifi.log」。

我自己的 log 比較複雜一些,除了把防火牆以外,還有 kernel 的 log 分開成二個不同的檔案:
if $fromhost-ip startswith '192.168.0.1' and not ($msg contains 'DROP IN') then /var/log/ac3100.log
& ~

if $fromhost-ip startswith '192.168.0.1' and ($msg contains 'DROP IN') then /var/log/ac3100-fw.log
& ~



網路上大部分的資料,都是教別人怎麼把 log 往別台機器丟,只有比較少一部份是處理別台機器的 log,這邊留下一些參考文件:

2017/08/24

尋找適合自己的工作場所 - Coffee Highfive


COFFEE HIGHFIVE 是一個可以讓你搜尋適合自己工作場所的一個服務,可以找到咖啡廳、簡餐店等,也可以自己篩選店家是否有提供 wifi 和電源插座。

雖然現在社群提供的資料還不多,希望大家看到可以幫忙補上去,讓更多人受惠。

2017/08/20

大雪山一日遊遇好心人協助,大感謝

最近幾天實在很熱,趁機跑到台中大雪山的橫嶺山步道避暑兼運動。

騎上橫嶺山第一個入口,海拔約 1300 m 就能感受到涼意。在大坑派出所向警員問了路,才知步道有二個入口,第一個入口海拔較低,但是也可以從第二個入口 (在山洞旁) 進入 ,第一個入口會一路爬坡銜接道第二個入口,大約要走 4 ~ 5 小時。如果不想太累的話,可以直接從個入口進入,路比較平。

在第二個入口處比較不好找車位,停好車發現難得有手機訊號,並收到一個簡訊,表示劉先生撿道我的皮夾並送到派出所,要我盡快前往領取。

摸了一下口袋,幹 ... 皮夾因為山路叫抖、運動口袋又淺,居然已經滑出去了!!!

心跳瞬間衝到 180 bpm,馬上騎車回到剛剛問度路的派出所並找到聯絡上員警,沒想到聯絡我的警察和剛剛問度的是同一位,笑了一下說:「看來你今天是註定要來看我的」 XD

從四次元背包翻出了幾個收據和個人資料確認身份以後,發現皮夾的現金、證件一個都沒有少,實在太感動了。

這裡再次感謝匿名的劉先生和大坑派出所的林警員,謝謝!

-----

這樣跑了一趟以後,走步道的時間已經不夠了,想說就直接回市區。在派出所外面遇到一位陌生人,說先生走路上山去開車,但是已經走了好幾個小時還沒道,看看我有沒有辦法騎車上去找人順便傳話。

機車油箱還夠,借手機給那位太太試著聯絡,並同步了一下我和他先生穿的衣服樣式後,便上山找人了。這為先生很拼,從太坑派出所一直走,打算走到第二個山洞開車下來接他太太,不過聽起來太陽下山可能還來不及走到定點,便直接在他去找車。

這位毅力斐淺的林先生也是常常爬山旅遊的山友,一路上還特別推薦我台中附近幾個不錯的踏青步道,聊的實在很開心。

覺得這次受到好心人幫助以後,應該抱著同樣的心情,把這份恩情傳給別人,這樣社會才會更好 (就像是電影「讓愛傳出去」的感覺吧,有聽過這部電影的年紀應該都不小了 XD)。

ps. 覺得篇箱地區的人們,比城市裡的人更有人情味、更好相處

大雪山的橫嶺山步道路況

最後更新時間:2017/08/19


跑去大雪山的橫嶺山步道,順便記錄一下路況。

我是騎機車上山的,第一件事情就是不要完全按照 Google Maps 的建議路線行走,他會帶你去走私有土地 ... (死)

從東勢沿著專一道晚上騎到恆嶺山比較上面的入口,柏油路僅有幾處破洞,大致上沒什麼安全疑慮,不過沿路有幾處有落石,建議小心行駛。

越往山上的路寬越窄,請留意會車問題,且大約中午 12 點過後便開始起霧,行駛時請務必開大燈,讓自己與對象來車都能保持行車安全!

2017/08/18

puppeteer from Google Chrome

前幾天 Google 發布了 Puppeteer:一個可以控制 Chrome Headless 的 nodejs library。

透過 demo code 可以看到要產生 PDF 也好、要做 screen shot 也好,基本上都可以在數行以內解決:
const puppeteer = require('puppeteer');

(async() => {

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});

browser.close();
})();

感覺就是拿來做壞事的好工具呀,也不用寫什麼 JavaScript emulator 去取得實際的網頁 DOM 狀態了 XD

官方文件已經有 Chrome Headless + Pupetteer 的網頁 debug demo:https://developers.google.com/web/updates/2017/04/headless-chrome

2017/08/17

rpm 列出套件時不顯示套件版本號

一般在尋找 CentOS 上到底安裝哪一些套件時,指令大概會這樣下:
$ rpm -aq | grep php-fpm
php71-php-fpm-7.1.7-1.el7.remi.x86_64

不過如果是要用 diff 比對二台機器安裝的套件是否相同,這個時候多了套件版本號就頭大了。

查了一下資料,rpm 有提供「--qf」(query-format) 可以自行設定列表要輸出的內容。

若使希望看到套件名稱,而不想列出套件版本時,指令可以這樣下:
$ rpm -aq --qf "%{NAME}\n" | grep php-fpm
php71-php-fpm

記得行尾要換行,不然就 GG 了 XD

2017/08/05

PHP strict typing performance

聽說 PHP 使用 strict type hint 會讓速度變慢,於是來做了個簡單的測試,先來個沒有 type hint 的:
<?php

function repeat($str)
{
    return $str;
}

$start = microtime(true);

for ($i = 0; $i < 100000000; $i++) {
    repeat('test');
}

$end = microtime(true);

var_dump($end - $start);

使用 PHP 7.1.8 執行,大概會花費 3.7 秒左右:
$ php main.php
float(3.713329076767)


接下來改成 strict type 的寫法:
<?php

declare(strict_types=1);

function repeat(string $str): string
{
    return $str;
}

$start = microtime(true);

for ($i = 0; $i < 100000000; $i++) {
    repeat('test');
}

$end = microtime(true);

var_dump($end - $start);

執行時間大概變成 5.3 秒左右:
$ php main.php 
float(5.3128638267517)

的確慢了不少,不過先別著急,不要因為慢了一些就打算放棄 strict type hint。

使用 PHP 5.6 去執行第一個測試 (沒有 strict type) 就大約需要 19 秒:
$ php5.6 main.php
float(19.477375030518)

其實把 PHP 版本升級上 7.x 才是正確的吧 XD

2017/08/02

Apache / Nginx 與 PHP 各種搭配方式的效能測試

以 PHP 為主的 HTTP server 有很多種架設方式,最傳統的大概就是 Apache + mod_php 來執行 PHP scripts。隨著技術一直在翻新,後來也有了 Nginx + php-fpm 的搭配模式出現,甚至連 PHP 在 5.4.0 都推出了 built-in server

因公司需要,就順手測試了以下幾種搭配:

在開始看壓力測試結果之前,先來說一下測試環境:
  • 所有的 HTTP server 除了以上搭配方式之外,其他都使用預設值 (像是不開啟 gzip 壓縮等)
  • 另外壓力測試的 PHP script 內容也很簡單,僅有「phpinfo();」一行
  • 1 core CPU
  • 4 GB RAM
  • 使用 ab (Apache Bench) 做測試
  • ab 中每個 concurrency 固定會發出 1000 個 HTTP request,如 concurrency = 1 時僅有 1000 個 request,concurrency = 100 時,則送出 1000 x 100 個 request。
  • 每次 ab 跑完一次壓力測試,均重新啟動 HTTP server 與 PHP server,以防止使用到 cache。

先簡單做個結論,詳細的壓力測試結果再請大家自行過目:
  • concurrency = 1 時,沒有壓力測試會出現的情況,不過可以把 response time 和伺服器的 CPU、記憶體使用量當作一個基準值作為參考。
  • Apache mpm-prefork 搭配 mod_php 的記憶體使用量最大,畢竟要 fork 一個 Apache instance 出來就要把 Apache 個 module 也 initialize 出來。小型伺服器不推薦這個方案。
  • php-fpm 即使設定「pm.max_children = 50」,也可以輕鬆負荷超過 50 個 concurrency。比較微妙的是從 htop 看不出 php-fpm 有使用 thread 來同時處理 request。
  • php-fpm listen on Unix socket 的效率比 listen TCP (127.0.0.1:9000) 的效率還要高一些,但是在高負荷的情況下會變得很不穩定,猜測和 OS 的 socket 實作、設定有關連。
  • PHP built-in server 遇到在高負載的情況下表現的不錯,唯獨 log 給的資訊太少,不方便做分析。但也可考慮透過 Nginx proxy 給 PHP built-in server,讓 Nginx 來處理 log。

最後做個廣告,Hackmd 真不錯用,筆記寫完最後還以轉換成 HTML 下載,有夠方便的啦!

2017/08/01

在 PHP 判斷參數為 anonymous function 的方法

在追各個 framework 的一些元件結構,anonymous function 已經被大量使用在不同的用途上了。

如果 function 要判斷外部傳進來的參數,是否為 anonymous function,有幾個作法。

一個是判斷是否可以被呼叫:
is_callable($param)

另外,由於所有的 anonymous function 其實屬於一個 PHP Closure 類別,所以也可以用下面這個方法做判斷 (且判斷結果還比較準確):
$param instanceof \Closure

2017/07/19

vim 快速使用 sudo 存檔的語法

平常改設定檔通常都是「sudo vim xxx.conf」,不過直接切換成 root 修改檔案其實風險還蠻大的,特別是邊喝酒邊改系統的時候 (?)。

倘若不想使用 sudo vim 來修改系統設定檔時,就 vim xxx.conf 即可。雖然沒有寫入權限,但至少讀取檔案內容是沒問題的。

以一般使用者開啟系統擋時,每次做變更都會收到警告訊息「Warning: Changing a readonly file」,表示 vim 偵測到沒有權限變更檔案內容,避開非預期的異動正是避開誤寫的好方法。那當修改完成後需要寫入時,則可以使用以下指令臨時切換成 root 並寫入檔案:
:w !sudo tee %



說明一下上面那一段到底是什麼意思。

「:w」和大家所知道的寫入檔案是一模一樣的,但若後面加上其他指令,例如「:w ! tee」其實就是把預備寫入的檔案內容 pipe 給後面的指令處理,前面這個寫法就是把檔案內容丟給 console 的 tee 處理,所以可以看到 tee 檔案內容輸出到螢幕上 (stdout)。

vim 中的「%」符號代表的是正在編輯的檔案名稱,可以使用「:!echo %」指令看看會輸出什麼資料。若是「vim xxx.conf」則會印出「xxx.conf」;「vim path/to/xxx.conf」則會印出「path/to/xxx.conf」,應該不難理解。

綜合以上幾個撇步,「:w !sudo tee %」的意思,其實就是讓 vim 不要自己更新檔案,而是將檔案內容拋給以 root 身份執行的 tee,並讓 tee 寫入 vim 目前正在編輯的檔案。tee 寫完檔案以後,vim 會偵測到檔案異動並詢問是否要重新載入 (load) 更新過的檔案內容,重新載入以後就可以繼續下一個批次的修改。

2017/07/14

Nginx URL rewrite for REST API in subfolder

一般來說,要讓 Nginx 遇到 PHP 程式時,只要按照以下寫法就可以將 request 轉接給 php-fpm 處理:
server {
    location / {
        try_files $uri $uri/index.html =404;
    }

    location ~ \.php* {
        root /home/www/data;

        include        fastcgi_params;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    }
}

假設 project 在 document root (如上面的就是 /home/www/data),設定方式其實不難,網路到處都可以找的到。像是 Laravel 可以參考 pretty URL 的設定方式,把 index.php 隱藏起來:
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

上面這個設定,可以讓 request 從「http://my.site/user/1」,被改寫為「http://my.site/index.php/user/1」,這個時候 index.php 就可以從 $_SERVER 的參數來判斷到底要走哪個 route。

但假設寫的專案沒有一個 domain name、沒辦法做 virtual host,可以讓專案根目錄當作 document root,且新的 PHP framework 都會把 index.php 放在 /public 目錄下來避免安全問題,這樣的 URL rewrite 就會出問題。

例如今天的 request 是「http://my.site/project/user/1」,在經過上面的 route 以後會被轉成「http://my.site/index.php/project/user/1」,而實際上我們需要的是「http://my.site/project/index.php/user/1」才能讓專案正確運作。

這時需要另外建立 route 規則。先把 http://my.site/project 對應到的正確檔案路徑設定好:
location ^~ /project {
    # define script real path
    alias /home/www/data/project/public;

    try_files $uri $uri/ /project/public/index.php$uri;
}

到這邊算是設定完成一半,暫停來看一下目前 routing 的情況。請求「http://my.site/project/user/1」會被轉換為「http://my.site/project/public/index.php/project/user/1」。index.php 後半部的參數差了一點點,把「project/」片段拿掉就完成了。

這時我們再新增一條規則,使用 REGEX 來處理後面這段參數:
location @project-rule {
    # 若 URI 起始為 /project/
    # 把後面的參數抓出來,放在 /project/public/index.php/ 後方 
    rewrite ^/project/(.*)$ /project/public/index.php/$1 last;
}

調整後,完整的 Nginx URL rewrite 規則會長這樣:
location ^~ /project {
    alias /home/www/data/project/public;

    # 一般規則無法正確找到路徑
    # 就使用 @project-rule 規則來做查詢
    try_files $uri $uri/ @project-rule;
}

location @project-rule {
    rewrite ^/project/(.*)$ /project/public/index.php/$1 last;
}


Nginx 的 rewrite rule 實在很難 debug,這段是自己花了數小時嘗試錯誤並觀察 $_SERVER 參數變化才找到規律的,希望多少對大家有一點幫助。

2017/07/02

天興搬家公司 與 崔媽媽基金會

獲得了一個在新竹工作的機會,六月初從高雄搬家至新竹。在 PTT MoveHouse (搬家) 板上面一直找不到中意的搬家服務,最後在 play.google.com 上面亂找,發現有個 app 叫做「搬家 Easy Go」,列出由崔媽媽基金會評鑑、審核過的搬家公司,於是挑了高雄離家比較近的「天興搬家公司」來協助這次的旅程。

透過網頁上的聯絡方式打電話給高雄經理,經理聽過我的行李數量以後,說大概只需要用最小的卡車 (好像是 3 頓的那型) 半車就可以裝完,且早上八點上車以後,中午過後便可在新竹卸貨,開價是 12000。只要我在早到公司去做確認並簽約即可,費用則是搬家之後才收。

搬家當天遇到鋒面過境下大雨,意料之外的是快遞士大哥居然有準備封膜,把我的電腦椅和幾件重要家具都先包好,上推車以後在蓋一層防水布運送上卡車,全程都不需要我出力,大哥一個人就搞定了。由於雨勢過大,拿行李到高鐵上新竹花掉的時間可能比卡車還要慢,所以就搭了大哥的順風車。

大哥沒啥不良嗜好,也蠻聊的開的,開車也很穩,幾乎不太需要擔心。新竹下車時沒有下雨,一下子就把行李搬進房間,最後付款並填寫問卷。



車上有像大哥詢問了崔媽媽基金會和搬家公司有什麼關連。原來崔媽媽基金會成立主要是用來協助搬家公司建立完整的安全制度,包括各家搬家公司遇到的問題,像是如何固定家具才不會在運送途中損壞,雨天注意事項,或是需要使用吊車來協助家具進出時的安全規範,以及定期為搬家公司建立教育訓練,訓練及驗收。客戶也可以透過崔媽媽基金會找到有保障的搬家公司。

所以可以確定的是,有經過崔媽媽基金會認可的搬家公司,不會遇到家具搬到不見、損毀找不到地方求償、或是搬家後隨意加價等問題的發生,整個交易比較有保障。

以這次的經驗,以後有需求應該也會透過崔媽媽基金會來尋找搬家公司協助搬運。

「全勤獎」真的對公司也對員工都很好嗎?

全勤獎目的是為了讓員工可以盡量員工準時上下班,也盡可能安排假期能考慮到公司的時程。之前和同事討論以後有了不一樣的看法,全勤獎也有可能帶來負面的效果。

以一個工勤的上班族來說,通勤這段時間是完全無法預測的,塞車不說,如果遇到交通事故、或是道路維修等狀況,根本無法預期會花多久的時間到達公司。如果為了預防這樣意外發生而提早出門,自己的生活時間就少了一小時,或是更多,但是公司並沒有補貼這些通勤時間。

另外一個上班族可能的想法,就是在運輸工具上節省通勤時間,也就是「飆車」。但大家也應該都知道飆車的副作用是什麼,遭警察開罰單,或是因此發生交通事故導致無法繼續原來的工作 (住院,或是永久的身體傷害)。

這樣全勤獎的負面效果,似乎比正面效果來的還要大許多,那是否可以用其他方法來取代全勤獎的目的呢?

2017/06/29

Phalcon PHP framework 的 URL rewrite 方法

幾個比較常見的 PHP framework 像是 Silex、Slim、FuelPHP 和 Laravel,都是將 resource path 直接放在 index.php 後方。例如網址為「/my.site/user/10」則會被改寫為「/my.site/index.php/user/10」,所以在測試環境下,如果不想設定 URL rewrite 可以直接把 resource path 手動放在 index.php 後方。

今天研究 Phalcon 的 routing 很久,不管怎麼設定就是沒有 match 到 controller,而且還沒有任何錯誤訊息。把整個文件都翻遍以後,才發現 .htaccess 有個不一樣的地方:
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^((?s).*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

Phalcon 的 rewrite 行為和上述的不一樣,resource path 會轉到「_url」這個參數上面,所以若是沒有動到「_url」這個參數,router 就視為要開啟首頁,不管 index.php 後面接什麼都不會改變行為 ....。



可惡,八小時就這樣飛了 .....

2017/06/11

GRw - Fallen Ghosts

只想罵一下,沒想到 DLC 只是拿原本破壞遊戲平衡最主要的聯合軍做修改,變成五大步同兵種,而且聯合軍攻擊等級還維持在四個。



遊戲第一個任務完成以後,看起來玩法一樣是蒐集情報、升級武器零件、解開任務,沒有什麼特殊改變。花錢買 DLC 感覺浪費前虐自己而已。

2017/05/12

prestissimo for composer

composer 是一個解決 dependency hell 的好工具,但令人詬病的是跑得實在有點慢,特別是 composer update 的時候,搞不好就一直 update 到下班了 ... Orz

所以這裡介紹一個工具:prestissimo。當有多個 packages 需要下載時,prestissimo 會自動跑 multi-process 來下載 depends:
composer install -vvv
.....
Dependency resolution completed in 0.093 seconds
    Prefetch start: total: 27
    1/27:    https://codeload.github.com/sebastianbergmann/php-file-iterator/legacy.zip/3cc8f69b3028d0f96a9078e6295d86e9bf019be5
    2/27:    https://codeload.github.com/sebastianbergmann/code-unit-reverse-lookup/legacy.zip/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18
    3/27:    https://codeload.github.com/sebastianbergmann/php-timer/legacy.zip/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f
    4/27:    https://codeload.github.com/sebastianbergmann/php-text-template/legacy.zip/31f8b717e51d9a2afca6c9f046f5d69fc27c8686
    5/27:    https://codeload.github.com/sebastianbergmann/php-token-stream/legacy.zip/e03f8f67534427a787e21a385a67ec3ca6978ea7
    6/27:    https://codeload.github.com/myclabs/DeepCopy/legacy.zip/8e6e04167378abf1ddb4d3522d8755c5fd90d102
    7/27:    https://codeload.github.com/sebastianbergmann/diff/legacy.zip/13edfd8706462032c2f52b4b862974dd46b71c9e
    8/27:    https://codeload.github.com/sebastianbergmann/version/legacy.zip/99732be0ddb3361e16ad77b68ba41efc8e979019
    9/27:    https://codeload.github.com/sebastianbergmann/object-enumerator/legacy.zip/1311872ac850040a79c3c058bea3e22d0f09cbb7
    10/27:    https://codeload.github.com/phpDocumentor/ReflectionDocBlock/legacy.zip/8331b5efe816ae05461b7ca1e721c01b46bafb3e
    11/27:    https://codeload.github.com/sebastianbergmann/global-state/legacy.zip/bc37d50fea7d017d3d340f230811c9f1d7280af4
    12/27:    https://codeload.github.com/sebastianbergmann/comparator/legacy.zip/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be
    13/27:    https://codeload.github.com/phpspec/prophecy/legacy.zip/93d39f1f7f9326d746203c7c056f300f7f126073
    14/27:    https://codeload.github.com/mockery/mockery/legacy.zip/6fdb61243844dc924071d3404bb23994ea0b6856
    15/27:    https://codeload.github.com/symfony/yaml/legacy.zip/acec26fcf7f3031e094e910b94b002fa53d4e4d6
    16/27:    https://codeload.github.com/sebastianbergmann/php-code-coverage/legacy.zip/ef7b2f56815df854e66ceaee8ebe9393ae36a40d
    17/27:    https://codeload.github.com/sebastianbergmann/phpunit/legacy.zip/69c4f49ff376af2692bad9cebd883d17ebaa98a1
    Finished: success:17, skipped:10, failure:0, total: 27

我的 project 只有 27 個 packages 所以效果沒有很顯著,但若超過 50 個 packages 要抓時,相信你會非常有感覺。

安豬方法很簡單,把他裝成 global 的 composer package:
$ composer global require hirak/prestissimo

安裝完成以後 prestissimo 便會自動開始運作。

若覺得預設值不夠你用,可以到設定檔裡面自己調整需要的參數 (以下應該不是預設值,被我改過一次了):
$ cat ~/.composer/config.json
{
  "config": {
    "prestissimo": {
      "maxConnections": 10,
      "minConnections": 3,
      "pipeline": false,
      "verbose": false,
      "insecure": true,
      "cainfo": "/absolute/path/to/cacert.pem",
      "userAgent": "",
      "privatePackages": []
    }
  }
}

2017/05/05

為 ufw 建立應用程式的 rule set

以往在 ufw 加入防火牆規則時,都是一條一條新增上去:
ufw allow 80
ufw allow 443
ufw allow 8080
.....

這種方式雖然簡單,但是之後要維護會有點困難:到底哪個 port 是為了哪一個應用程式開的?

ufw 其實還有其他特別功能,叫做 app list:
zero@zero-x230:~$ sudo ufw app list
Available applications:
  Apache
  Apache Full
  Apache Secure
  CUPS
  Samba

會自動增測,並有預設的設定檔來幫你新增 rule set。來看一下「Apache Full」設定檔到底寫了什麼,打開「/etc/ufw/applications.d/」:
[Apache]
title=Web Server
description=Apache v2 is the next generation of the omnipresent Apache web server.
ports=80/tcp

[Apache Secure]
title=Web Server (HTTPS)
description=Apache v2 is the next generation of the omnipresent Apache web server.
ports=443/tcp

[Apache Full]
title=Web Server (HTTP,HTTPS)
description=Apache v2 is the next generation of the omnipresent Apache web server.
ports=80,443/tcp

預設有三個 rule sets,一個是 port 80,另一個是 HTTPS 的 port 443,亦或二者都開啟。

我們可以依樣畫葫蘆,建立自己的 app rule sets,像是我幫 Resilio Sync 湊出來的 rule set

你也可以參考 Ubuntu forum 上面的教學,建立自己需要的 rule set。

2017/04/26

尾寮山路況

今天 (2017/04/26) 到尾寮山探一下路況,上週下雨導致部份路段有落石,但感覺巡刪員已經有處理過了,除了石塊較大以外,路到 3K 左右的涼亭都是通的。

訊息就留給大家做參考,歡迎朋友更新路況上來。

2017/03/28

火線獵殺 野境 - 資源蒐集方法

除了技能點數以外,還需要有大量的反抗軍資源才能開啟技能。

個人觀察發現,「攔截運輸車」這個事件會隨機出現,但是在該省區 boss 解決掉以後,事件出現機率會掉很多。
所以比較好的方法,就是最終 boss 先不要急著打,無聊先去搶劫,把資源搶起來放。這樣 boss 打掉以後給的技能點數,馬上就可以拿來選技能,不用在去跑腿。

第三行 ....?

2017/03/15

火線獵殺 - 野境 (Ghost Recon - Wildlands) 心得

完了 Ghost Recon - Wildlands (以下簡稱 GRw) 覺得開放式地圖做的實在不錯,各地區皆有隨機事件,破關方法也可以隨個人喜好自行調整。

但還是覺得有些可惜的地方,像是:

  • 遊戲難度平衡沒有調整的很好
  • 交通工具不好操控
  • 聯合軍有開外掛的感覺
  • 休閒模式還是要練等級,才能看劇情 QQ




我完全不會開飛機 XD


=== 2017/03/17 補充 ===

玩了 35 小時,覺得「野境」裡面中,「聯合軍」的設計,真的把整個遊戲的平衡性給毀了。

攻擊聯合軍只會讓對方的強度越來越高,而且永遠不會減弱,相當於玩家不使用匿蹤的方式進行遊戲就會再見,這樣還好意思說野境是一個任玩家自由採取行動的遊戲?

2017/03/07

為 Gitlab 加上 CI runner 做自動化測試

gitlab-ci-runner 可以裝在 local 也可以跑在 docker container,我自己是安裝在 docker container
docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

上面步驟完成以後,可以先進入 Gitlab 的 Admin => Runner,這邊會顯示 runner access token:



在該頁面可以找到 token,如果要讓之前設定的 token 失效,可以先點選「Reset」換一個 acces token:


先把 access token 複製下來,接下來建立一個 runner 並連接到 Gitlab 上:
docker exec -it gitlab-runner gitlab-runner register

設定說明:
  • gitlab-ci coordinator URL:輸入欲使用 runner 的 Gitlab 網址
  • gitlab-ci token:就是你剛剛複製下來的 access token
  • gitlab-ci description:輸入 runner 的名稱,例如 runner-php56 或是 runner-php70。這個名稱會在 Gitlab 上面看到,建議填寫清楚的名稱以供辨識。
  • executor:我這邊要讓 runner 在 docker container 裡面跑,所以選擇「docker」
  • Docker image:在 docker container 執行時,要使用哪個 image 當作 base。我自己懶的自己 built,用的是「edbizarro/gitlab-ci-pipeline-php
  • gitlab-ci tags for this runner:這邊會請你輸入幾個關鍵字,假設在 project 設定中,出現這幾個關鍵字,則 Gitlab 會自動把符合的 executor on 起來跑。我自己會設定「docker」、「phptest」等等

到這邊若沒看到什麼錯誤,在 Gitlab 的 runner 頁面重新整理後,則頁面最下方可以看到剛剛設定好的 gitlab-ci description (runner name):


這頁有看到的話,可以依樣畫胡驢,在需要使用到的專案 runner 設定頁面,使用這個 runner 來跑測試。



在 Gitlab 上將 runner 設定好,接下來只要在專案上加入「.gitlab.ci.yml」,當 git push 後 Gitlab 便會檔案中的設定自動把 executor on 起來跑,設定方法可以參考 Gitlab 提供的 gitlab-ci.yml 說明

簡易的 PHP library (不包含任何 framework) project 的 .gitlab-ci.yml 大概長這樣:
image: edbizarro/gitlab-ci-pipeline-php:5.6


syntax-check:
    script:
        - "find . -name '*.php' -print0 | xargs -0 -n1 php -l"
    tags:
        - docker

unit-test:
    script:
        - composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts
        - ./vendor/bin/phpunit -v --coverage-text --colors=never --stderr
    tags:
        - docker

上面可以看到我要求 executor 一定要使用「edbizarro/gitlab-ci-pipeline-php:5.6」這個 image,不過由於 tasks 有特別設定 tags,所以這行也不是必要。

而這邊設定了二個 tasks 要求 executor 協助執行:「syntax-check」和「unit-test」。因此 executor 會先跑 syntax-check,確認沒有錯誤後,再去執行 unit-test。

完成後,只要 Gitlab 收到 commit 且就會依照 .gitlab-ci.yml 的設定下去跑。結果會自動顯示在「Pipeline」的列表當中:




Reference:

2017/03/05

Laravel 5.3 的 API routing

弄了很久才搞清楚 5.3 版的 routing 是怎麼搞的,覺得作者把事情弄的更複雜了,也少了一些彈性。

Laravel 5.3 中,routes 已經不是放在 App/Http 底下了,將設定獨立出來放在根目錄:
johnroyer@box:~/devel/laravel53$ tree routes
routes
├── api.php
├── console.php
└── web.php

有個 API 專用 routing 看了當然開心,只是怎麼樣都是不出來 api.php 這邊的設定要怎樣才能起作用。

後來找了很久才發現 Route 功能,已經在 provider 階段把 web / api 的 routing rule 寫死,所以 API 的 routing 有固定的 prefix,在網址是上必須是「http://laravel.root/api」開頭,才會吃到 api.php 的設定。該項 rule 被寫在 RouteServiceProvider 中:
    protected function mapApiRoutes()
    {
        Route::group([
            'middleware' => 'api',
            'namespace' => $this->namespace,
            'prefix' => 'api',
        ], function ($router) {
            require base_path('routes/api.php');
        });
    }


Reference:

2017/02/24

Nginx + PHP + MySQL 的 windows 懶人包

以前都是 WAMP 懶人包,現在終於看到已 Nginx + php-fpm + MySQL 為主的懶人包了:WPN-XM


WPN-XM 看起來已經有不少人在維護,新的 RC 版本也開始支援 PHP 7.x 了,看起來可以關注一下。

2017/02/17

Garmin fenix 3 HR (反串) 開箱文

買了隻 Garmin 的 fenix 3 HR 智慧手錶,按照慣例,網路上已經有不少精美的開箱文,所以按照慣例,我就來記錄一下開箱以後一些個人覺得較不喜歡的地方。


矽膠腕帶

因為 3 HR 有心律感應器,所以錶背需要貼上皮膚上,所以長時間帶會覺得悶熱 (但或許是我不習慣的關係吧)



感應器校準

3 HR 第一次啟動有數個設定需要校準,例如時間、高度計。高度計使用 GPS 訊號做校準不說,但為何時間不能透過和手機連線來設定,只能手動設定或是使用 GPS 資料設定時間?
因此,第一次啟動你必須到室外收 GPS 才能完成所有的基礎設定。


手機通知同步

其實我沒有很想要在手錶上面看到通知訊息  XD
但留意到目前 3 HR 會跳出的通知,僅限主流通訊軟體,像是 Gmail、LINE 等,但 Telegram 的通知,我目前還沒有收到過,感覺頗微妙的。

補充:經朋友告知,預設的確只有常用的 app 通知,但是可以從 Garmin 手機的 app 中,新增需要轉播到手錶的 app 通知。


按鈕

3 HR 的按鈕按鍵重量不輕,因此按按鈕一定需要在按鈕的另一側用手指頂住以免造成皮膚拉扯不舒服,5 個按鈕中,其中的 4 個按鈕另一側均有另一個按鈕,可能會導致誤觸。因此操作時並沒有非常順手。


帳號整合問題

平常有在使用 RunKeeper 當作運動記錄的輔助,但是發現 RunKeeper 要連接智慧手錶時,需要先登入 Garmin 帳號取得授權。

Garmin 設計成可以使用第三方帳號登入

但是使用 RunKeeper 連到 Garmin 登入時,卻沒有使用第三方帳號登入的選項:



已寄信至客服,希望有個好的答覆。



如果你還沒看過別人的開箱文,個人推薦以下幾篇介紹:

2017/02/15

網路語音通訊軟體整理 round 2

去年因為辦 conference 比較了一些常見的語音通訊服務,最近則是因為太常講電話講到電話費破表,所以來又找了一些服務來作比較,這次就單純比音質和穩定度吧。


Hangouts

  • 連線算是穩定,偶爾會延遲或是掉字,但不錯用
  • 音質不算特別好,但也不至於聽不出來對方講的內容
  • 聽說 Chrome 瀏覽器上支援的比較好,Firefox 好像會有點問題?


Skype
  • 連線狀況不穩,時好時壞。
  • 音質佳,還會自動過濾掉喇叭、手機的回音。


Viber
  • 連線蠻穩的,和 Hangouts 差不多,希望不是因為客戶少使品質比較好 >"<
  • 音質佳,和 skype 幾乎相同品質
  • 有時候播話對方會沒收到來電通知,不過發生次數不多


LINE
  • 嗯 ... 我個人還是把他當作貼圖買賣軟體 Orz
  • 2017/08/01 補充:現在只有剛接通時會有一些音訊延遲,之後語音還蠻順的,我覺得可以當作一對一的通訊工具了


Steam
  • 和前篇沒特別差別
  • 個人除非連線遊戲有特別需要,不然還是都會用 skype 和 viber 作為語音通訊平台


Slack
  • 連線品質不算差
  • 音質略低,但是比 Facebook Messanger 好多了。會吃到環境音,通話前建議帶耳機或是找個安靜的地方


Facebook Messanger
  • 連線品質佳,很少遇到斷斷續續的問題
  • 音質差,比一般電話的音質還要差 XD


Telegram

  • 連線品質不差 (連 2017/04 月底台灣海纜斷掉都沒啥影響)
  • 音質佳,跟 viber 有拼。但有時候會聽到自己的 echo,機會不大就是了
  • 補充:2017/04 月底對外的海纜斷掉,但對語音通訊並沒有明顯的影響




目前有測試的主要只有這幾項,歡迎各路高手分享經驗~

Flash Player 撐住啊



Flash Player 又被抓出一堆漏洞,瞄了一下還有看到 remote execution,請大家盡快留意近期的 Flash Player 更新吧。

2017/02/09

WD red 硬碟壞軌


壞在蠻前面的,badblocks 跑幾分鐘就有錯誤訊息


又壞掉了 .... 這顆還是之前送修過的回來的,在保固內 (2018 年) 又故障。之前還有一個黑標的,想說保固五年表示公司對他應該很有信心,結果用了 10 個月就故障送修。

差不多該把 WD 丟到黑名單了。但想想,剩下來可以買的硬碟選擇只有一些些了 Orz

2017/02/02

phpBB 3.2 的 nginx 的 location 設定

先說一下 phpBB 安裝工具吧,安裝程式的路徑不是在跟目錄而是在「/install」,entry point 是 app.php,而 app.php 又有自己的 route

如果只是這樣設定的話,route 會失敗:
location / {
    try_files  $uri /index.php?$uri$args;
}

所以另外對「/install」增加了一個 rule 才能正常執行安裝工具:
location /install {
    try_files  $uri /app.php?$uri$args;
}



安裝完成後,論壇系統的有二個 entry point,所以不能只單設定 index.php,還有 app.php,因此 nginx 的設定要改成下面這樣:
location / {
    try_files  $uri /app.php?$uri$args /index.php?$uri$args;  # 注意順序
}

當然,安裝完成以後就可以把「/install」的設定砍掉了。

2017/01/26

到關子嶺紅葉公園的汽車行車路線

使用 Google Map 導航取得的路線,會是一條很舊的產業道路。坡度抖,可能會擦到汽車底盤,且該路段看起來以廢棄不少時間,路面看起來不是很好走。



舊的產業道路,汽車不好走且小危險



後來向統茂大飯店的櫃台詢問,找到一條新的路線,還是新的柏油路,可以開車到紅葉公園的汽車停車場,在徒步進入公園。


左邊是統茂大飯店,走 175 再轉產業道路便可抵達紅葉公園




2017/01/18

遠距工作的感想

https://dq.yam.com/post.php?id=6763

之前在地球圖輯隊看到一篇文章:「辦公室裡沒有人」 研究:遠距工作好處多」,由於自己近幾年也算是 remove remote co-work,分享一下自己的感覺。


負責任


這好像沒啥好特別描述的,自己被分派的工作在時間內做完。如果團隊有個人不負責任,就會導致專案時程毀掉,或是需要別人盯進度,這樣就失去 remote co-work 的意義了。



主動


之前協助 COSCUP 活動其間,最怕遇到的就是被動的工作人員。假若遇到自己無法解決的問題儘早提出,這時團隊中的其他人還有機會協助解決問題;但若不主動提出問題,而是在 dead line 時才告知大家自己無法解決問題,就算請神、降佛也救不了火。



信任


如果你的伙伴可以做到上面二點,那請完全信任他吧!不要有事沒事就在那邊問進度,工程師離開 flow 以後,都要一小段時間才能重新進入 flow 進行高效率工作。

之前欲過上班要填寫各項工作所花掉的工時,單單記錄各項工作花掉多少時間,每天就花掉差不多一小實在搞這個,算一算每天有 12% 的時間就這樣掰了。



時間管理


remote co-work 不代表你可以想做事的時候才做事,而是給你彈性,讓你找到最舒服、最有效率的工作環境。

如部分工程師喜歡在夜深人靜的時候工作,因為這樣思緒、flow 最不容易被打斷;
也有些人喜歡在有背景噪音的環境下工作 (像是咖咖聽),比較不容易分心。不管什麼情境下,你成有義務分配好自己的工作時間,來達成、並交付任務,不要辜負團隊對你的信任。



良好的溝通


團隊間一定要有個好的方式可以管理事件 (issue tracing) 並記錄討論結果,有問題時也需要有個平台可以討論,且最好所有討論的內容都可以完整的保存下來。

另外必須強調溝通是雙向的,不是所有的人只聽 leader 說什麼就做什麼,若可能會遇到什麼問題就必須要討論時提出,被提出質疑時也不要認為自己被對方鄙視,而是對方尊重你,把潛在的定時炸彈提前告知,以免自己莫名其妙的被炸死。



工作更有成就感?


這個問題我持保留態度。

通常沒遇到問題時應該是爽爽過;但是開始鬼打牆,需要和同事 pair programing 或是 debug 時,就會開始覺得世界上找不到好的語音通訊工具,或是發現同事工作時段和你不同,remote 很靠北。



沒了茶水間的閒聊 生產力大增?


這個其實我個人比較反對,不管是茶水間、休閒區都應該保留下來,同事之間聊天保持一定的默契是一定要的。了解同事在想什麼、思維模式、溝通時的用語,可以增加遠距通訊時的效率,不然現在面對面的工作環境何必還要保留?

另外我自己會建議 remote co-work 的團隊,可以保持一季、一年有面對面聊天、討論的機會,畢竟文字、和語音通訊,很難表達一個人目前的情緒以及內心的感覺,面對面還是有其必要性。


同場加映:FBI教你讀心術:看穿肢體動作的真實訊息

修改 grub 開機選單等待時間 (timeout)

查了很多資料,大多都說是去修改 /boot/grub/grub.cnf 的設定,但新版的 grub.cnf 事實上是電腦自動產生的,不管怎麼改參數,數值都會被覆蓋掉。

正確解法應該是直接修改 /etc/default/grub:
GRUB_TIMEOUT=10  # wait for 10 secs

修改完畢後記得更新設定:
sudo update-grub2

詳細的解說,可以參考 Grub2 - Ubuntu community wiki 上的說明。

2017/01/13

部落格的圖床

最近在想要幫 Blogger 找個圖床。

透過 Blogger 上傳的圖片會吃掉 Google Drive 的空間,而免費帳號有容量上限,而我比較想把空間都讓給 Gmail 使用,所以不太希望用 Blogger 上傳圖片。

第三方的圖床,目前找到的好像只有 imgur,但不確定圖片到底可以存放多久。

生為一個工程師就是想要自幹 (?),所以想試試看用個簡單的界面,把圖片丟到 AWS s3 上面當作臨時的方案,順便研究一下 Lumen 怎麼用。


若有大家有不錯的方案,也請告訴我,謝謝!

2017/01/12

杉林溪三日遊

難得的長假,這次排了三天二夜的行程,跑去杉林溪呼吸新鮮空氣。

三天的行程排的很鬆,基本上路上看到什麼有趣的東西停下來晃晃都不影響到時程。第一天出發先到溪頭的妖怪村和忘憂森林。第二天則是在杉林溪散步和泡茶,順便對新買的高山瓦斯爐做壓力測試。第三天原本要把杉林溪 miss 掉的步道走完,不過因為睡眠不足的關係作廢,跑去市區亂晃。