2016年8月26日 星期五

.club 域名


同事跟我說,現在有 .club 域名,於是我嘗試搜索 robot.club 是否可以申請。在 GoDaddy 得到的結果是「可以申請」。不過,這個域名是「特別版」,索價要 HK$39,949.99。如果拿來做生意,還算可以接受吧。


同時,我也搜索了「sitachan.club」。首年索價 HK$23,之後要 HK$136。本來也想把它買回來,可是沒想到怎麼用,還是算吧。

2016年8月25日 星期四

利用 Bash 程式下載 Packt 免費電子書並上傳 Git 及發出通知

之前改編的「利用 Bash 程式下載 Packt 免費電子書」完成後,還是想做更多。要是下載後能直接上傳 GitLab、自動輸入備註、再發送電郵通知就完滿了。於是著手動工。 原本的 Bash 程式在 CentOS 下不用改也能順利執行。因此,只需要加入提交到 Git 及發送電郵便能成事:
#!/bin/bash

##----------------------------------------------------------------------------------------
##  Packt Free eBook Downloader
##----------------------------------------------------------------------------------------
##  Platform: CentOS7 + bash
##  Written by Pacess
##  Copyright 2016 Pacess Studio.  All rights reserved.
##----------------------------------------------------------------------------------------

##----------------------------------------------------------------------------------------
##  Update History:
##----------------------------------------------------------------------------------------
##  2016.08.25
##  - Added auto commit to GitLab
##----------------------------------------------------------------------------------------

##  Variables
userID="sita@chan.com"
password="Sita0310"

timeOut=5
noOfRetry=3
sleepTimeBetweenRequest=1

userAgent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" 
downloadDirectory="/Users/pacessho/MEGA/eBooks"
log="packt_igustin.log"
cookie="cookie.txt"

##----------------------------------------------------------------------------------------
function PHLog  {
    echo "$1"
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$log"
}

##----------------------------------------------------------------------------------------
##  Program start
echo "$(date '+%Y-%m-%d %H:%M:%S')"
echo "-----------------------------------------------------------"
echo "--  Packt Free eBook Downloader Version 1.10             --"
echo "--  Written by Pacess                                    --"
echo "--  Copyright 2016 Pacess Studio.  All rights reserved.  --"
echo "-----------------------------------------------------------"
echo ""

##  Move to home directory first
cd /root/PacktDownloader

##  Remove previous temp file
rm -f $cookie packt*.html

##----------------------------------------------------------------------------------------
##  Website login
PHLog "Logging in $userID..."
curl -s --retry $noOfRetry -m $timeOut -A "$userAgent" -b "$cookie" -c "$cookie" -d "email=$userID" -d "password=$password" -d "op=Login" -d "form_build_id=form-73ba86bbfb2a50719049129632c84810" -d "form_token=2f1d586bf7df196b77d0761709d03199" -d "form_id=packt_user_login_form" https://www.packtpub.com
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

curl -s --retry $noOfRetry -m $timeOut -A "$userAgent" -b "$cookie" -c "$cookie" https://www.packtpub.com/packt/offers/free-learning > packt_daily.html
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##----------------------------------------------------------------------------------------
##  Extract claim URL
claim=$(grep -oE "freelearning-claim/[0-9]+/[0-9]+" packt_daily.html)
PHLog "Claim URL: $claim"

##  Extract book title, trim and remove invalid characters
title=$(grep "dotd-title" -A 2 packt_daily.html | tail -1 | sed 's/^[^0-9A-Za-z]*//;s/[\t ]*<\/h2>$//')
title="$(echo -e "${title}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/[^A-Za-z0-9 ._-]//g')"
PHLog "eBook Found: $title"

##  Extract book ID
bookID=$(echo $claim | sed "s/.*\/\([0-9]*\)\/.*/\1/")
echo "";

##  Claim ebook now
curl -s --retry $noOfRetry -m $timeOut -A "$userAgent" -b "$cookie" -c "$cookie" -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.5' -H 'Connection: keep-alive' -H 'Host: www.packtpub.com' -H 'Referer: https://www.packtpub.com/packt/offers/free-learning' "https://www.packtpub.com/$claim"
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##----------------------------------------------------------------------------------------
##  Download PDF version
PHLog "Downloading PDF...$title.pdf"
curl -s -L --retry $noOfRetry -A "$userAgent" -b "$cookie" -c "$cookie" "https://www.packtpub.com/ebook_download/$bookID/pdf" > "$downloadDirectory/$title.pdf"
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##  Download EPUB version
PHLog "Downloading EPUB...$title.epub"
curl -s -L --retry $noOfRetry -A "$userAgent" -b "$cookie" -c "$cookie" "https://www.packtpub.com/ebook_download/$bookID/epub" > "$downloadDirectory/$title.epub"
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##  Download MOBI version
PHLog "Downloading MOBI...$title.mobi"
curl -s -L --retry $noOfRetry -A "$userAgent" -b "$cookie" -c "$cookie" "https://www.packtpub.com/ebook_download/$bookID/mobi" > "$downloadDirectory/$title.mobi"
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##----------------------------------------------------------------------------------------
##  Job done, log out now
PHLog "Logging out..."
curl -s --retry $noOfRetry -m $timeOut -A "$userAgent" -b "$cookie" -c "$cookie" https://www.packtpub.com/logout > packt_logout.html
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##  Remove temporary file
rm -f $cookie packt*.html
echo "" >> "$log"

##----------------------------------------------------------------------------------------
##  Commit to GitLab
PHLog "Commiting to GitLab..."
git config --global user.name "Sita Chan"
git config --global user.email "sita@pacess.com"

git add *
git commit -m "Added '$title'"
git push -u origin master

##----------------------------------------------------------------------------------------
##  Send email alert
echo -e "Dear Pacess,\n\nA Packt ebook '$title' have been downloaded and commit to GitLab.  Thanks!\n\nSita-bot" | mail -r "sita@pacess.com (Sita-bot)" -s "[GitLab] Added Packt ebook '$title'..." pacess@pacess.com

2016年8月24日 星期三

用 Mailx 發送電郵

最近用多了 Bash 指令去做定時執行的工作;有些時候需要發出電郵通知本人關於運作的情況;所以特別搜索一下做法。

其中一個可以用的是 Mailx。我沒需要附加檔案,整件事很簡單。用 echo 指令打印文字串,經「|」符號把文字串引導到 Mailx 內。Mailx 後方加入「-r "發件人地址"」,如要加入親和系的名稱,則需要用()包著。然後是「-s "主旨"」,空格後加入收件人地址。


如收件人多於一位時,可用逗號分隔及接著下一地址。如:「pacess@pacess.com,sita@pacess.com,crystal@pacess.com」

2016年8月19日 星期五

DISTINCT vs GROUP BY


最近在處理公司一個項目的數據庫效能問題。由於動輒有成 60 萬筆資料,後台的顯示板得花上 18 秒時間才能順利載入。花這麼長時間,是因為當中執行了 9 項資料查詢;每筆花約 2 秒時間。我得優化這個部份。嘗試把 MySQL 查詢用的 DISTINCT 改為 GROUP BY 加 LIMIT 的效果,做了一次測試,原來目前的 DISTINCT 已經是最快。我亦嘗試調校 innodb_buffer_pool_instances 數值,但需時還是沒有明顯的縮短,得再想想辦法...。

2016年8月17日 星期三

在 iOS 下顯示完整的 HTML Select 選項


今日有同事向我查詢,問有沒有方法能在 iOS 瀏覽網頁時,顯示完整的選項名字。因為目前有個選項名字因為太長而被 iOS 把尾段變成了「・・・」。Google 一下發現在 HTML 的 OPTION 碼中加入以下句子,便能解決問題。
<optgroup label=""></optgroup>

2016年8月16日 星期二

不用密碼,直接登入

開發網頁或流動應用程式的伺服器接口的時候,我喜歡用 SSH 多於 FTP。有時同一時間需要處理多過伺服器,每個都有各自的登入帳號,實在記得不多。就算記到,也要輸入,總是麻煩。最好就是不用輸入,直接進去。這時 authorized_keys 幫到手。做法如下:

先在 macOS 的 Terminal 下執行「ssh-keygen -t rsa」。在 ~/.ssh 會出現 id_rsa 及 id_rsa.pub 兩個檔案。前者是密匙,後者是公匙。把 id_rsa.pub 拷到服務器的 ~/.ssh/authorized_keys 後,便能不用密碼登入。

如果一台 macOS 會連接多過一台伺服器,而又不想輸入密碼時,則要在 ~/.ssh 建立 config 檔案,並設定如下般內容:
Host 192.168.1.100
   Hostname 192.168.1.100
   PreferredAuthentications publickey
   IdentityFile ~/.ssh/centos7_vm/id_rsa

Host 54.230.73.94
   Hostname 54.230.73.94
   PreferredAuthentications publickey
   IdentityFile ~/.ssh/viu.tv/id_rsa

Host 69.58.186.114
   Hostname 69.58.186.114
   PreferredAuthentications publickey
   IdentityFile ~/.ssh/ikea.com.hk/id_rsa

2016年8月15日 星期一

利用 Bash 程式下載 Packt 免費電子書

在網上找到用 Bash 編寫的 Packt 免費電子書下載工具,實在利害。一個程式包含領取及下載,簡潔實用。我把它修改一下配合自己的需要:
#!/bin/bash

##----------------------------------------------------------------------------------------
##  Packt Free eBook Downloader
##----------------------------------------------------------------------------------------
##  Platform: macOS + bash
##  Written by Pacess
##  Copyright 2016 Pacess Studio.  All rights reserved.
##----------------------------------------------------------------------------------------

##  Variables
userID="sita@chan.com"
password="Sita0310"

timeOut=5
noOfRetry=3
sleepTimeBetweenRequest=1

userAgent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" 
downloadDirectory="/Users/pacessho/MEGA/eBooks"
log="packt_igustin.log"
cookie="cookie.txt"

##----------------------------------------------------------------------------------------
function PHLog  {
 echo "$1"
 echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$log"
}

##----------------------------------------------------------------------------------------
##  Program start
echo "-----------------------------------------------------------"
echo "--  Packt Free eBook Downloader Version 1.00             --"
echo "--  Written by Pacess                                    --"
echo "--  Copyright 2016 Pacess Studio.  All rights reserved.  --"
echo "-----------------------------------------------------------"
echo ""

##  Remove previous temp file
rm -f $cookie packt*.html

##----------------------------------------------------------------------------------------
##  Website login
PHLog "Logging in..."
curl -s --retry $noOfRetry -m $timeOut -A "$userAgent" -b "$cookie" -c "$cookie" -d "email=$userID" -d "password=$password" -d "op=Login" -d "form_build_id=form-73ba86bbfb2a50719049129632c84810" -d "form_token=2f1d586bf7df196b77d0761709d03199" -d "form_id=packt_user_login_form" https://www.packtpub.com
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

curl -s --retry $noOfRetry -m $timeOut -A "$userAgent" -b "$cookie" -c "$cookie" https://www.packtpub.com/packt/offers/free-learning > packt_daily.html
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##----------------------------------------------------------------------------------------
##  Extract claim URL
claim=$(grep -oE "freelearning-claim/[0-9]+/[0-9]+" packt_daily.html)
PHLog "Claim URL: $claim"

##  Extract book title, trim and remove invalid characters
title=$(grep "dotd-title" -A 2 packt_daily.html | tail -1 | sed 's/^[^0-9A-Za-z]*//;s/[\t ]*<\/h2>$//')
title="$(echo -e "${title}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/[^A-Za-z0-9 ._-]//g')"
PHLog "eBook Found: $title"

##  Extract book ID
bookID=$(echo $claim | sed "s/.*\/\([0-9]*\)\/.*/\1/")
echo "";

##  Claim ebook now
curl -s --retry $noOfRetry -m $timeOut -A "$userAgent" -b "$cookie" -c "$cookie" -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.5' -H 'Connection: keep-alive' -H 'Host: www.packtpub.com' -H 'Referer: https://www.packtpub.com/packt/offers/free-learning' "https://www.packtpub.com/$claim"
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##----------------------------------------------------------------------------------------
##  Download PDF version
PHLog "Downloading PDF...$title.pdf"
curl -s -L --retry $noOfRetry -A "$userAgent" -b "$cookie" -c "$cookie" "https://www.packtpub.com/ebook_download/$bookID/pdf" > "$downloadDirectory/$title.pdf"
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##  Download EPUB version
PHLog "Downloading EPUB...$title.epub"
curl -s -L --retry $noOfRetry -A "$userAgent" -b "$cookie" -c "$cookie" "https://www.packtpub.com/ebook_download/$bookID/epub" > "$downloadDirectory/$title.epub"
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##  Download MOBI version
PHLog "Downloading MOBI...$title.mobi"
curl -s -L --retry $noOfRetry -A "$userAgent" -b "$cookie" -c "$cookie" "https://www.packtpub.com/ebook_download/$bookID/mobi" > "$downloadDirectory/$title.mobi"
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##----------------------------------------------------------------------------------------
##  Job done, log out now
PHLog "Logging out..."
curl -s --retry $noOfRetry -m $timeOut -A "$userAgent" -b "$cookie" -c "$cookie" https://www.packtpub.com/logout > packt_logout.html
errorCode=$?;  test "$errorCode" -ne "0" && { PHLog "curl exit error code: $errorCode";  exit; }

##  Remove temporary file
rm -f $cookie packt*.html
echo "" >> "$log"

2016年8月12日 星期五

修復白屏 Google Glass


終於拿到 Google Glass。一直都想玩一下,可惜機會未到。現在停產後卻如願以償。

由於 Google Glass 閣在一旁不知有多久,少則一個月,相信電池不會有電,先來過充電。充電完畢後,很期待地戴上 Google Glass,打開電源。眼前出現非常細緻的畫面,比起紅米 + Google Cardboard 來得精緻很多。先出現 A 字,一會才出現完整 GLASS 字樣。可是開機過後只剩下白屏,而且還不斷發出按鍵及退出叮叮咚咚的聲音。Google Glass 傻了。我不停按拍攝鍵,偶爾會出現方框;間中能拍下照片並短暫顯示。


在網上找到解決白屏的辦法;像是長按電源鍵十五秒關機、通宵充電、降至室溫,完全沒有作用。我決定用 adb 工具作進階處理。首先要在 macOS Sierra 以「brew install android-platform-tools」指令安裝 adb。再利用「adb devices」列出接駁了的 Google Glass。可是另一個問題來了。這副 Google Glass 未連接過我的 MacBook Pro,畫面顯示「unauthorized」,需要先行授權,但 Google Glass 一直白屏,只聽其聲,看不到其影。於是我只好不停地按拍攝鍵,希望有一刻能誤撞地確認授權。幸運地,試了數分鐘便做到了。Google Glass 由「unauthorized」變成「device」,可以進行復原步驟。


利用「adb reboot-bootloader」指令把 Google Glass 推入 Bootloader 模式,再以「fastboot oem unlock」來進行刷機。可是新的問題來了,出現「ERROR: usb_read failed with status e00002eb」。刷了幾次也不行,又再另覓出路。


今次以「adb reboot recovery」指令進行復原,終於有反應。進入了修復畫面。我分別執行了「wipe data/factory reset」及「wipe cache partition」後進行重啟。開機後出現歡迎畫面。按著眼鏡的指示,一步一步學習使用及設定 WiFi,最後能變回正常的 Google Glass。

2016年8月11日 星期四

在 macOS Sierra 使用 launchd 定時執行程式

昨天完成了換領免費電子書程式,下一步是設立時間表去執行。我在 macOS Sierra 中使用 launchd 方法。做法很簡單,在 ~/Library/LaunchAgents 建立 come.pacess.cronjob.plist 檔案。內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>Label</key>
   <string>com.pacess.cronjob</string>

   <key>Program</key>
   <string>/Users/pacess/cronjob.sh</string>

   <key>StartCalendarInterval</key>
   <dict>
      <key>Hour</key>
      <integer>12</integer>
      <key>Minute</key>
      <integer>00</integer>
   </dict>

   <key>StandardOutPath</key>
   <string>/Users/pacess/cronjob.log</string>
</dict>
</plist>

以上內容是通知 macOS Sierra 在每天的中午 12:00 執行 /Users/pacess/cronjob.sh 檔案。應用程式名稱為 com.pacess.cronjob,並將輸出的內容儲存到 /Users/pacess/cronjob.log。

要不是指定時間的話,可以是指定間距,如兩小時。可以這樣做:
   <key>StartInterval</key>
   <integer>7200</integer>

利用以下指令載入及卸下 Plist 內容。如果沒有做這個動作,Plist 也會在下次登入時自動執行:
  • launchctl load ~/Library/LaunchAgents/com.pacess.cronjob.plist
  • launchctl unload ~/Library/LaunchAgents/com.pacess.cronjob.plist
     
    至於 bash 程序內容如下:
    #!/bin/bash
    now=$(date +"%D %T")
    echo "$now - Start cronjob.sh"
    
    export PATH=/usr/local/bin:$PATH
    /usr/local/bin/casperjs ~/cronjob.js
    
    now=$(date +"%D %T")
    echo "$now - End cronjob.sh"
  • 2016年8月10日 星期三

    利用 CasperJS 自動換領 Packt 免費電子書

    繼續前天的研究。既然 SimpleTest 不行,那就嘗試其他工具,因此昨天安裝了 CasperJS

    CasperJS 跟 SimpleTest 不同的是,它需要利用 Firefox 來進行協作,一些特別的處理也能完成。甚至把畫面輸出成 PNG 圖檔。經過一番嘗試,最終成功實現了目標,透過執行以下代碼「node_modules/casperjs/bin/casperjs packt.js」便能順利換領 Packt 免費電子書!
    //----------------------------------------------------------------------------------------
    //  Packt Free eBook Downloader
    //----------------------------------------------------------------------------------------
    //  Platform: macOS + PhantomJS + CasperJS + Javascript
    //  Written by Pacess
    //  Copyright 2016 Pacess Studio.  All rights reserved.
    //----------------------------------------------------------------------------------------
    
    var casper = require("casper").create();
    
    //  Load free ebook page
    var host = "https://www.packtpub.com";
    var url = host+"/packt/offers/free-learning";
    casper.start(url);
    
    //  Once page loaded, login first
    casper.then(function()  {
       this.echo("Logging in...");
       this.fillSelectors("#packt-user-login-form-respo", {
          "#email": "sita@chan.com",
          "#password": "Sita0310"
       }, true);
    });
    
    //  Once login, then extract claim URL
    casper.then(function()  {
       this.echo("Extracting claim URL...");
    
       url = "";
       var html = this.getHTML();
       var index = html.search("/freelearning-claim/");
       this.echo("Index: "+index);
       if (index >= 0)  {
    
          //  Claim pattern found
          var link = html.substring(index, index+40);
          index = link.search("\"");
          if (index >= 0)  {
    
             //  Construct complete claim URL
             url = host+link.substring(0, index);
             this.echo("Claim URL: "+url);
             casper.thenOpen(url, function()  {
                this.echo("URL: "+this.getCurrentUrl());
             });
          }
       }
    });
    
    //  If there is error, log it out
    casper.on("error", function(msg, backtrace)  {
       this.echo("### "+msg);
       throw new ErrorFunc("fatal", "error", "filename", backtrace, msg);
    });
    
    //  Run above script now!
    casper.run();