Sentri這個產品之前在Kick starter上的熱門程度, 可說是台灣之光呀, 加上它又是有幾個優秀的前同事的加持, 因此一開始我就在Kick starter上下訂了, 直到昨天終於收到他了, 本來想說晚點再來寫這篇的, 不過現在也沒啥睡意, 就先來寫寫

可能是剛開始的第一個產品, 其實還有些未盡完善的地方吧, 也有可能有些我體驗還沒很充足, 這篇參考參考就好, 不用太認真 :P

開箱

包裝外觀還蠻用心的, 不像一般台灣3C產品的草率, 裡面也用了不少泡綿做保護, 背面則是寫滿了一堆功能性的解說, 不過這部份我比較不喜歡, 密密麻麻的字, 其實不太會想去看, 或許有一些生動的圖示, 減少一半的文字會更好一點

一打開後, 它就方方正正的(啊本來就方的)躺在中間, 配件(不多)則是在下面, 下面還有很多多餘空間, 這樣剛剛好, 也不算浪費空間, 翻到背面, 有兩個孔是可以釘牆上的, 還有一個kickstand是可以讓你立在桌上, 前者的設計其實有點怪異, 因為它必須是要接著電源的, 一般牆上掛鐘的位子比較少有插座

隱藏在腳座後面的則有USB, 網路孔, 電源開關, 跟Reset, 電源開關的設計, 是”一根”, 形狀我是覺得怪怪的, 怎不是圓圓的按鈕, 或許我比較習慣那樣 XD 不過, reset那個孔, 也太小了吧, 穿針線的針不知道會不會也太粗

軟體

一開機之後, 自然是要做設定, “Welcome Home”這段字, 看起來是特別溫馨 :D

而緊接著, 就是要設定網路跟註冊帳號, 這邊我碰到一個小小的bug, 起先我是接著Ethernet, 但忘了把另一頭接到Hub上, 然後又因為它還是提示我設定Wifi, 我就也設定了, 結果在註冊階段, 它一直說我沒連上Internet, 最後才發現網路線的狀況, 此時我並不是接上另一頭而是把它拔掉, 拔掉之後就可以連上了, 看起來它默認先走有線的, 但卻不會因為有線的連不上切換成Wifi

初始設定都是利用觸控螢幕操作, 輸入文字時我是覺得有點彆扭, 我是覺得, 如果家裡有Wifi, 手機又是連上同一個網路, 或許可以讓使用者在手機登入後就可以同步完設定了

首頁的操作介面很簡單

首先映入眼簾的當然就是時鐘跟幾個資訊, 向左滑是設定, 向右則是Alerts

攝影機是用來監控的, 也有動態偵測, 所以一開始就可以在Alerts看到我被偷拍到的照片(小偷是我?!), 比較像是一個有螢幕的Dropcam

設定上可以設Away Mode (開啟Alerts) 和 Home mode (關閉Alerts), 以及可以設定桌面主題, 美中不足的是不可以用自己照片(也沒辦法用camera拍), 手機上的app也沒辦法用自己的圖設定這塊

相機則可設定夜視模式, 除了開關還有自動, 但自動好像沒啥用處, 我把房間燈關了, 用手機遠端看, 還是一片黑暗, 但我設定成打開就可以:

夜視效果不錯

效能上, 有點失望, 隨便點功能都要等待1~2秒以上, 會以為沒反應, 然後它就又突然出來了, 可能硬體不夠好或是效能還沒調整好, 如以下影片:

https://goo.gl/photos/SUog336k8cNyXZ5E6

另外一個小缺點是沒有夜晚模式, 我把燈關了後它還是很亮, 它不適合擺臥房呀!

手機App

我目前只測了iPhone, 但這App的介面實在不像iPhone介面, 也還有點陽春, 目前還沒試太多, 但碰到幾個待改進的跟BUG

手機上的設定似乎跟Sentri不是同步的, 比如說, 我已經在Sentri上設定我是用攝氏為單位, 但手機登入後, 還是華氏

Alerts影片播放有會變成上圖那樣


小結

初感覺就比較像是有螢幕的Dropcam, 目前可顯示的資訊還不太多, 我也沒啥裝置可以跟他互動, 如果可以把它當一個比較大的Android Wear或許也會不錯, 不過目前對它還沒太多想法, 可能需要再多體驗一陣子

目前Json已經可以說是Internet上相當流行的格式了, 雖然說他缺點還算蠻多的, 但很多主流的程式語言都有成熟的parser可供使用,  在Golang則可利用內建的encoding/json這個package來達成

用“encoding/json”來解析Json其實很簡單, 基本上就是建立一個Decoder然後把json內容”解”到你對應的資料結構去, 可以參考這範例: http://golang.org/pkg/encoding/json/#example_Decoder

但在某些狀況下並不是很好的解法, 舉個例子來說, 我這兩天打算拿從Parse那邊匯出的使用者資料來做一些處理, Parse輸出給我的JSON檔大約長得像這樣: 

{
       results: [
             {
                  “objectId”:”zzreueaWq4″,
                  “username”:”julian”,
             }
       ]
}

按照這定義寫出的程式碼就類似這樣:

但這有一個很大的問題, Parse那邊輸出給我的Json檔就有400MB之多(二十多萬筆), 可想而知的, 這程式直接先因為out of memory炸掉了, Decode需要把所有內容載入到記憶體才做解析, 而且以這範例, 解析完的結果全部存到我們的資料結構內, 自然有這問題, 常常這種應用我們都不是很需要把所有內容在記憶體放一份, 而是來一個處理一個

這時候就需要用Streaming parser的作法來解決這問題了, Golang的Json package也有支援這一模式, 但這也是在最新的1.5之後才有支援這模式, 使用這方法, 程式可以改成如下:

在這邊由於我只需要results這陣列的內容而已, 因此我先用Token找到第一個”[”(以這範例來說, 第一個”[”代表的就是results的陣列了), 之後就是用迴圈一個個去解些個別的User物件, 由於這20多萬筆資料, 我也只是要印出來而已, 我也不用特地用一個大的資料結構來存, 自然記憶體的問題就比較沒那麼吃緊

最近在嘗試寫一些動態gif的應用, 所以就研究了一下怎用go去產生動態gif, 後來找到以下這篇:

Go言語で画像の減色を行う

其實這篇已經寫的蠻完整的了, 不過由它是日文(有很多日文的技術文章其實還不錯), 所以我嘗試用我自己的方法用中文再闡釋一遍

要用輸出動態gif其實go就已經支援了, 使用EncodeAll即可:

https://golang.org/pkg/image/gif/#EncodeAll

不過, 仔細看一下GIF這個struct裡的那個Image陣列, 接受的是Paletted, 也就是附有調色盤的圖(色彩較少), 而現在大部分的圖片大多是全彩的, 因此, 需要先把全彩的圖轉成Paletted, 而這部份的作法是利用image.draw裡的Draw把全彩的圖畫到一個新的Paletted去:

palImg := image.NewPaletted(img.Bounds(), palette.WebSafe)
draw.Draw(palImg, img.Bounds(), img, image.ZP, draw.Over)

由於新創一個Paletted圖, 需要給它一個調色盤, 最簡單的方法是給它預設的調色盤, 在image.color.palette裡有兩個(plan9, web safe), 這邊採用了比較通用的Web safe, 最後輸出的結果如下:

呃, 好醜…..不過這是一定的, web safe一是組比較通用標準的色盤, 但大多數的顏色跟原本的圖的色彩差異可能相當的大, draw.Draw是在調色盤找出相近色, 但有可能找出來這顏色差異就很大了

那怎麼辦?我們就必須對全彩影像找出最佳的調色盤, 從成千上萬色中找出適合的256種顏色, 這在影像處理技巧中有個叫Color quantization, 它就是用來處理這樣的狀況的

在image.draw裡也找到了一個Quantizer:

https://golang.org/src/image/draw/draw.go?s=688:910#L17

不過看來這個Quantizer只有空殼(interface)並未有實作(也就是這樣我才去找到那篇日文的參考文章), 雖說, 實作一個median cut演算法不難, 但對懶人來說, 能有現成的當然最好, 從那篇參考文章中看到了, 有人幾經寫好的(更不錯的是已經實作了Quantizer) -

https://github.com/soniakeys/quant/

使用它後, 先前得程式碼可以簡單的改成 -

q := median.Quantizer(256) //256個顏色
palImg := q.Image(img)

得到的結果會優很多:

這樣好很多了吧?不過還不是最佳的, 由於顏色數變少了, 有些漸層的地方(比如說範例裡企鵝的脖子)會變成一條條帶狀的, 所以我們還需要做dithering, 在Go的image.draw裡其實已經有實作了Floyd Steinberg演算法, 因此可以用這個來做dithering, 程式就改成:

palette := q.Quantize(make(color.Palette, 0, 256), img)
palImg := image.NewPaletted(img.Bounds(), palette)
draw.FloydSteinberg.Draw(palImg, img.Bounds(), img, image.ZP)

出來的結果是這樣:

細部的差異差不多像這樣:

第二張是有dithering的(怎感覺比較醜)

總之, Happy GIFing~~~

會寫這東西, 起因是上週跟同事聊到, 在social network上, 尤其是我們自己的ㄍservice, 似乎很多人不習慣或是會沒設大頭照, 如果有一個可以自動產生不同的大頭照的服務, 應該會不錯, 所以就用週末寫了這個小程式, 先給兒子試玩了一下, 他對改個東西就能產生變化還頗有興趣的, 以後再來教他寫, 哈 

Source code在此: github.com/julianshen/goticon

有了動機後, 突然想到, Github也是會給沒設大頭照的人設定一張方格圖像當預設大頭照, 所以第一個方向就是拷貝出一個這樣的功能:

這樣的東西並不難寫, 它只是一個5x5的方格, 我把名字用SHA512算出一個固定長度的binary string (5x5有25個方格, 我打算每格是1byte, 所以至少要有25 bytes), 每一byte如果大於某一數就填滿對應那格, 本來我的設定是128, 不過後來想說這樣如果有些極端的案例可能造成方格太多或太少, 因此這個數我取前25 bytes的中位數, 至於顏色, 我採用了一個叫go-colorful的lib去產生隨機的暖色, 以下就是我做出的結果:

不過這離有趣還有一些些距離, 所以又找到一個應用: https://github.com/matveyco/8biticon 

這是一個做8bits人偶的應用程式(open source, MIT License), 不過它是一個web app, 然後讓使用者自己拼湊, 這當然跟我懶人的目的不同, 我是希望只要有名字就自動產生, 所以就利用了它的圖, 自己來疊囉, 這比上面那個稍稍有趣點但更簡單, 只是依照對應的資料選出不一樣的圖疊起來而已:

我把這整個應用放到heroku去了(我原始碼也已經用godep整理好了, 有興趣的人也可以自行deploy到heroku去修改測試)”

有興趣的可以用以下的URL產生自己的identicon:

  1. Github style: https://goticon.herokuapp.com/i/g/julianshen (把julianshen取代成你自己名字就可以了)
  2. 8 bits style: https://goticon.herokuapp.com/i/8/m/julianshen (一樣換掉名字, 如果你是女生, 把”m”(male)換成”f”(female)就好, 像: https://goticon.herokuapp.com/i/8/f/julianshen

Azure Web App是一個還算簡單好用的PAAS, 它是基於一個open source project - Kudu, 因此除了C#外, 也支援了Java, PHP, Node.js, Python等環境, 部屬的方法也簡單到只需要用”git push”就可以了

使用node.js來開發程式的話, 免不了需要安裝許多不同的模組(module), 這對Web App來說也不是問題, 在”git push”之後, 它自動就會用”npm install”來幫你安裝package.json裡面指定的所有模組

但有時候, 用到的模組未必是放在公開的npm registry而是放在私有的registry, 那這時候就得做一點手腳了

首先在專案目錄中, 新增一個.npmrc的檔案(https://docs.npmjs.com/files/npmrc), 把private registry相關資訊(url, auth)放在這檔案, 並push上去

這時候你會看到push過程中, 雖然有找到private registry, 但會有一個錯誤產生:

Error: can’t access restricted package without auth, did you forget ‘npm set always-auth true’?

原因是你必須要先跑過”npm set always-auth true”, 不然在連接私有的registry會因為沒有認證而出錯, 那要怎樣在事前跑這指令呢? 這時候就要借助deployment script了

azure site deploymentscript –node

在你的專案目錄下跑以上那指令, 在你目錄下就會產生兩個檔案: .deployment和deploy.sh, 在deploy.sh找到下面這段:

# 3. Install npm packages

在這行下面加上:

eval $NPM_CMD set always-auth true

再把這些給push到Azure Web App上, 大功告成!