2016年6月18日 星期六

[Golang] 一個簡單的Mongo db proxy

之前被Parse搞的半死, 一直很好奇它的API到Mongodb的request之間到底是怎樣的對應

要弄清楚這個其實也不難, 把Mongodb的profiler全打開去看log就好了(db.setProfilingLevel(2)), 但這也是有缺點, profiler會寫到system.profile這個collection去, 而它是固定大小, 不能無限制的放, 再加上它還要多寫入這段, 多多少少影響效能

我需要的是一個從外部來觀察的工具, 不會影響到DB本身, 並且也可以將網路本身所花費的時間也包含進去, 所以想到的是在中間插一個proxy server

在現成的工具找到一個叫MonoDB Proxy的工具, 這是用nodejs寫的, 勉強可以, 也證明了這個方法是可行的, 但這工具雖然有做到代理這部份, 但在log部分, 由於它並未解析bson, 所以詳細的內容並不好看, 所以就自己來寫一個

功能需求

  1. 支援mongodb wire protocol, 而不是只是單純的轉送資料
  2. 印出request跟response內JSON的內容
  3. 要能夠知道每個request所需要的時間(含網路)

成品

最後寫出的的成品在這: http://ift.tt/1UVnl1z

整個還蠻簡單的:

  1. wire.go 實作wire protocol
  2. proxy.go 實作從client收資料並轉寫到server端
  3. cmd/mp/main.go command line主程式的部分

使用方法

這個工具是用Go寫的, 所以使用之前需要先安裝go ##### 安裝 go get julianshen/mongoproxy/mp

這個步驟做完後, 就可以把mp這個指令裝好了, 確定 $GOPATH/bin是在你路徑內, mp這個檔也是在那邊

使用

mp --port=6001 --remote=mydb:27017 --response

其中:

  1. port是你這個proxy server的服務點
  2. remote是遠端的mongodb (host:port)
  3. Reponse是需不需要log回傳的部分

實作Wire protocol

本來覺得Wire protocol會蠻複雜的, 結果, 其實是蠻簡單的

所有的wire protocol request都會有一個標準的表頭:

struct MsgHeader {
    int32   messageLength; // total message size, including this
    int32   requestID;     // identifier for this message
    int32   responseTo;    // requestID from the original request
                           //   (used in responses from db)
    int32   opCode;        // request type - see table below
}

對應golang, 我定義成這樣: go type MsgHeader struct { MessageLength int32 // total message size, including this RequestID int32 // identifier for this message ResponseTo int32 // requestID from the original request // (used in responses from db) Opcode // request type - see table below }

因為一開始就可以讀到整個訊息長度的, 所以就蠻好解析的, wire protocol的實作我是有參考了dvara, 本來是有想拿它的code來改, 但看了一下發現它也沒完整實作wire protocol, 秉著自己也來了解一下這部份的想法, 就重頭自己刻了

dvara不同的地方是, 我用go的binary package來讀header而非自己刻一個, binary.Read的確是一個蠻好用的工具, 用底下的code就可以讀出header這個資料結構:

h := MsgHeader{}
err := binary.Read(r, binary.LittleEndian, &h)

另外, 除header外, 各request的所帶的欄位各自不同, 這部份的作法就是定好各個所需的資料結構, 用reflection的方式來讀取各相關資料:

v := reflect.ValueOf(req)
v = v.Elem()

// 根據資料結構內定義的每個欄位用相關的方法讀取
for i := 0; i < v.NumField(); i++ {
    f := v.Field(i)
    t := f.Type()

    if bytesRead == int(h.MessageLength) {
        break
    } else if bytesRead > int(h.MessageLength) {
        return nil, ErrorWrongLen
    }

    switch {
    case t == reflect.TypeOf((bson.D)(nil)):
        d, n, e := readDoc(bufferReader)

解析bson

這部份就沒再重新造輪子了, 直接用golang著名的mongodb driver mgo裡的bson lib: http://ift.tt/1UVniD7 , 這個bson lib已經寫的很不錯了, 直接拿來用即可

在這個package內, 泛用的bson資料結構有兩種: bson.Mbson.D

這兩個是不同用途的,仔細看一下M跟D的定義:

type M map[string]interface{}

type D []DocElem

如果你是要把解析出的資料用map來操作, M是蠻方便的, 一開始我也是依著之前我寫相關的東西的習慣用M, 不過這邊卻是不可以用M的, 這也是我碰到bug的地方

由於M解析出的是Map, 所以每個field的順序它並沒記住, 但偏偏在wire protocol裡, 尤其是 $cmd, 順序是重要的, 所以Unmarshal出的M再Marshal回去, 順序可能不是原本的順序了, 而這在這個proxy應用上, client寫什麼東西過來就要寫什麼到server才不至於出錯

測試和Debug

我是用Wireshark來驗證我的實作有沒問題, Wireshark預設會把到27017 port的資料解析成wire protocol的內容供閱讀, 當然也可以自己手動請它解析

其他應用

這樣的proxy應該可以不只應用在debug, 像是Parse open source的dvara, 它也是利用了proxy來做connection pooling, 應該也可以用在request routing和caching的應用上



from Le murmure de Julian http://ift.tt/1UDwOvO
via IFTTT

2016年6月16日 星期四

又再把Blog搬家了

一直把Blog當作紀錄一些事情用的地方, 想法, 或是學習過的一些東西, 雖然不是很頻繁的在寫, 不過也寫了好幾年了, 從以前到現在, 換過好幾次平台, 從自己架的wordpress, 到posterous, blogger, 一直到現在用的Tumblr, 這中間最喜歡的還是posterous, 不過它已經不存在了, 而Tumblr也用了好一陣子了, 雖然加減湊合著用好像還OK, 不過編輯上也一直不是那麼順手, 尤其是貼source code, 因此也一直想把它換掉

medium 呢? medium我還沒很有動力去搞懂它, 會在上面看一些文章沒錯, 但把Blog移到上面去, 好像也沒啥動力

考慮了好一陣子, 不過最後還是把整個Blog遷移了, 反正現在有一個自己的domain (blog.jln.co), 搬家不用改地址!

遷移之前, 想了幾個我的需求:

需求

  1. 有方便的編輯器可以用, 最好可以支援mark down, 打html有點麻煩, WYSIWYG編輯器通常效率也不高
  2. 貼code好貼, 也方便閱讀
  3. 模版好編輯, 至少我要能知道怎麼改模版
  4. 好預覽
  5. 能同步到各個social network, 至少Facebook, Twitter, 也能同步到我原本的Tumblr和blogger
  6. 要能夠友善支援Open graph和Twitter card, 對每次share的FB的醜醜文字版型實在不喜歡
  7. 好轉移, 好備份, 有版本控制更好!

解決方案

現成的blog service, 好的什麼都要錢(ghost, wordpress), 免費的大概也都被我用過了, 自己架, 又得管server, 後來想想, blog都是靜態的網頁, 也真的不需要一個很複雜的系統, 這時候就想到一個解決方案, 那就是Github

Github有一個Github pages的服務, 可以讓你host你的靜態網頁, 所以只要有一個方法可以把Blog轉成靜態網頁就可以了, 這個還蠻Geek的方式感覺就蠻適合我的

找到了幾個方法轉blog:

  1. Jekyll
  2. Octopress
  3. Hexo

Octopress是已經完結不再維護了, 所以就Jekyll和Hexo兩個在抉擇, 兩者都有蠻多的主題跟模版功能, 也有不少plugins

Hexo是台灣精品, 而且是nodekjs寫的, 語言上我比較熟, 要改比較好改,而Jekyll是Ruby寫的, 我跟Ruby很不熟, 但它跟Github pages結合緊密, 而且已經有tool可以從Tumblr移轉內容過來了, 最後我選擇了Jekyll, 選擇Jekyll的原因是

  1. Github page直接原生支援, 只要把md檔push上去後, 就會自動產生網頁(不過後來我還是先在自己電腦產生完再push, 後面再說原因)
  2. 找到一個適合的也不太難改的theme, 就懶得去翻Hexo的了, 而且找到的那個對Open graph和Twitter card的支援也不錯, 不用改太多
  3. 原生的Tumblr import tool

不過整個也花了不少個晚上修改, 又花了一個晚上才能寫完這篇紀錄 @@

安裝Jekyll

網路上可以找到很多安裝Jekyll的文章, 這邊就不說太多, 我試了兩個不同的作法:

作法 1

這是最基本的作法

  1. 先用 gem install jekyll 安裝jekyll
  2. jekyll new myblog 在myblog目錄產生一個基本的網站
  3. jekyll s 會在 localhost:4000 開啟一個服務, 這時就透過browser可以看看你的blog長怎樣了

這方法的缺點是, 套用主題時, 還得改一堆東西, 有點麻煩

作法 2
  1. 一樣先裝jekyll
  2. 找到一個人家做好的theme (我是用hpstr這個), clone下來改, 因為大部分的都已經把他用的plugin之類的都先寫好在config了, 就省不少事, 建議找theme要注意其對應的Jekyll版本, 像我裝的Jekyll是3, 所以找的是適合3的
  3. gem install bundler 安裝bundler
  4. bundle install 來安裝相關的plugins
  5. jekyll s 看結果

我後來採用的是作法2, 踩在人家的肩膀上比較快 :P

設定github pages

這部份沒什麼難度, 創建一個專案名稱叫做 你的名字.github.com , 把相關檔案放到這邊去就行了

Github pages支援兩種方式, 一種是純粹的靜態網頁, 就是把html跟其他相關檔案丟到這邊就好(master branch), 另一種方式就是Jekyll, Jekyll的部分只要把前一個動作的檔案放進來就好, 它會自己幫你產生對應的靜態網頁

不過第二種方法的缺點是因為Github pages只支援幾種Jekyll plugins, 而且不支援自訂的plugins(放在 _plugins 目錄下的), 就算你在你自己電腦裡面跑完把產生後的 _site 目錄一起放上去也是沒用的

從Tumblr匯入之前文章

這部份沒太複雜, 是透過jekyll-import

安裝jekyll-import一樣可以透過gem install來安裝, 但建議不要這樣做, 是因為他用的Tumblr API是JSONP但程式卻將它當一般JSON在解碼, 會出錯, 這部份在最新版的code有解決(害我還去追了source code), 所以抓source回來自己build比較安全

裝好之後執行:

#!/bin/sh
ruby -rubygems -e 'require "jekyll-import";
    JekyllImport::Importers::Tumblr.run({
      "url"            => "http://blog.jln.co",
      "format"         => "html", # or "md"
      "grab_images"    => true,  # whether to download images as well.
      "add_highlights" => false,  # whether to wrap code blocks (indented 4 spaces) in a Liquid "highlight" tag
      "rewrite_urls"   => false   # whether to write pages that redirect from the old Tumblr paths to the new Jekyll paths
    })'

它就會把文章抓回到 _post的目錄下

Open graph & Twitter card

如果把內容分享到Facebook或是Twitter上只有短短的文字, 不是很好看, 所以希望在這部份能夠至少加上一張圖

hpstr這個theme已經有在 ** _includes/head.html ** 寫好OG跟Twitter card相關的tag了, 圖片(og:image)的部分, 他的規則/順序是:

  1. Front matter 裡面設定的
  2. _config.xml 裡的logo設定

我希望是更自動一點, 而不是自己去設定, 所以找到一個plugin : jekyll-auto-image, 這個plugin聰明一點, 他的順序是:

  1. 內文內出現的第一張圖
  2. _config.xml 裡面設定的圖

但這樣還稍嫌單調一些, 我想要達成的是:

  1. 內文內出現的第一張圖
  2. 根據標籤選的對應的圖(比如說把我go語言相關的設成Gopher的圖片), 這樣不會每個都一樣, 比較有變化一點
  3. 預設的圖

再加上auto image裡面關於image的設定跟我用的theme有所衝突, 這就需要把原本的auto image改一下了

我新增一個rb檔, 放在 ** _plugins **目錄下, 內容如下:

require "jekyll"

module Jekyll

  class AutoImageGenerator < Generator

    def generate(site)
      @site = site

      site.pages.each do |page|
        img = get_image(page)
        page.data['image1'] = img if img
      end
      # Now do the same with posts
      site.posts.docs.each do |post|
        #puts "hola"
        #puts Jekyll::VERSION
        #puts post.class
        #puts post.inspect
        #puts post.data.inspect
        #puts "-----"      
        #puts post.output
        #puts "----"
        img = get_image(post)
        post.data['thumb'] = img if img
      end
    end # generate

    def get_image(page)

      if page.data['thumb']
        return page.data['thumb']
      end
      # convert the contents to html, and extract the first <img src="" apearance
      # I know, it's not efficient, but rather easy to implement :)

      if page.class == Jekyll::Document # for jekyll 3.0 posts & collections
        htmled = Jekyll::Renderer.new(@site, page, @site.site_payload).convert(page.content)
      else
        htmled = page.transform # for jekyll 2.x pages
      end

      img_url = htmled.match(/<img.*\ssrc=[\"\']([\S.]+)[\"\']/i)
      return img_url[1] if img_url != nil

      tags = page.data['tags']
      imagemap = @site.config['imagemap']
      if tags != nil && imagemap != nil
        tags.each do |t|
          if imagemap[t.downcase] != nil
            url = imagemap[t.downcase]

            if !url.match(/^http/)
              url = '/images/' + url
            end
            return url
          end
        end
      end

      return @site.config['logo'] if @site.config['logo'] != nil
      return nil
    end

  end # class
end # module

這版就有達到我想要的目的, 但這不代表問題解了, 反而是問題的開始, 前面有說過github只支援特定的plugins, 所以怎樣這段改過的plugin都不會被它執行到, 唯一能做的解法就是改用靜態網頁的方式

jekyll產生的靜態網頁都放在 _site 目錄下, 所以真的要進master branch只有這裡面的, 其他都不用, 所以要先在本地端用 jekyll b去產生相關的靜態網頁到 _site裡再上傳

那怎測試呢? 一開始為了測試方便我都以本地端的server做測試, 但如果要測試Facebook share的話則需要能夠讓Facebook 連過來抓取網頁來分析, 但這點在區網不是很方便, 所以就帶入了 ngrok 這個工具, 這工具就是提供給你一個外部的網址, 你在本地端跑了ngrok這程式後, 就有一個可以對應你本地端的server, 還蠻好用的

自動發布到社群網站

這當然是用ifttt囉, 因為有用到jekyll-feed這個plugin, 所以會產生一個feed.xml的檔案, 所以就利用ifttt的feed channel來設定觸發

結語

本來明明不想花太多功夫的, 結果不但花了很多功夫, 還花了一頁來紀錄這篇 orz



from Le murmure de Julian http://ift.tt/1OszPie
via IFTTT

2016年6月15日 星期三

Hey blog test

This is to test my own blog

header 1

header 2

console.log("111")

test test

Header1

Header2

Header3

GoH1, GoH2, GoH3



from Le murmure de Julian http://ift.tt/1UW76yv
via IFTTT

Hey blog test

This is to test my own blog

header 1

header 2

console.log("111")

test test

Header1

Header2

Header3

GoH1, GoH2, GoH3



from Le murmure de Julian http://ift.tt/1UW76yv
via IFTTT

test

test test



from Le murmure de Julian http://ift.tt/1S59cKL
via IFTTT

test222

sssss

wereetrereter ### ressr

test # 2 # 1

  1. 22
  2. 22
  3. 222


from Le murmure de Julian http://ift.tt/1YrkWia
via IFTTT

test from jekyll 2

12223

sress



from Le murmure de Julian http://ift.tt/1VYHC8M
via IFTTT

test from jekyll

==Test is test



from Le murmure de Julian http://ift.tt/1PtdADF
via IFTTT

2015年4月17日 星期五

[AngularJS] Style, ng-style和天殺的IE

收到了一個IE 10會看不到圖片的bug, 昨天看了半天, 本以為在IE10沒正確載入遠端的資料(後來覺得我怎會蠢到這麼想), debug了半天(IE 10也沒很好的tool), 結果後來發現完全不是這麼一回事, 原本的code是這樣的:



<div style="background-image: url({{mydata.getImageUrl()}})"></div>


一開始也沒想到這邊, 看起來都沒問題, 但後來下面這樣的並沒問題:



<img src="{{mydata.getImageUrl()}}"/>


才發現原來AngularJS在IE10底下, 在style裡用{{變數}}會有問題, 解決的方法是要改用ng-style, 例如



<div ng-style="mydata.backgroundStyle()"></div>


而這裡的backgroundStyle是這樣的(不是string喔)



backgroundStyle = function() {
return {
backgroundImage: this.getImageUrl()
}
}




from Tumblr http://ift.tt/1cFDiId

via IFTTT

2014年8月20日 星期三

[Android] Clean Master "遊戲"捷徑的圖標是怎做的?

著名的工具軟體Clean Master有一項遊戲加速的功能, 它會放一個捷徑在桌面上, 而它的長得就像是跟資料夾一樣:



之前沒仔細去看它, 一直以為它是個小工具(AppWidget), 但其實它只是個捷徑而已, 點選它會跳出一個透明背景的對話窗, 所以很容易誤以為是桌面上的資料夾(如圖右)


這用了個小技巧, 雖然有點唬人, 但其實不難, 以下就如法炮製一個類似的吧!



在這實驗, 就把Youtube, Google plus, Google map三個app的圖示放一起, 邊框, 麻煩就先省略



利用”com.android.launcher.action.INSTALL_SHORTCUT”這個Intent可以在桌面上創建捷徑, 應該幾乎所有的桌面軟體都有支援, 關鍵點在於這Intent裡會帶的Intent.EXTRA_SHORTCUT_ICON, 這可以帶一個Bitmap來當作這個捷徑的圖示, 沒意外的, 就是從這邊動手


因為我們需要把四個圖示畫到一個上面, 所以每個圖示變成原本的1/4, 因此, 在用BitmapFactory.decodeResource載入圖示時, 可以把sample size設成2(也就是1/4大小), 這樣可以減少一些記憶體的使用, 取得了圖示後就可以把它們畫到另一個新的Bitmap了


要注意的是, 要用INSTALL_SHORTCUT的話, 要在AndroidManifest.xml裡加上:



<uses-permission android:name=”com.android.launcher.permission.INSTALL_SHORTCUT” />



這方法的缺點是, 一旦捷徑被創建好後, 就沒機會改它的圖示了




from Tumblr http://ift.tt/1peFiu7

via IFTTT

2014年8月19日 星期二

[Android] 土製Play store API

認真說的話, 這也算不上啥非官方API, 算是一個為了抓取Play store上資訊的一個小小工具: PlaystoreUtil


現在很多網路的服務, 大多有提供開放的REST API來供人寫原生的程式使用, 當然也有非常多並沒有, 像是Play store, 目前就沒開放的API可供存取, 剛好想要有個東西可以查詢某個app在play store上是屬於啥分類的, 所以就乾脆自己自製一個囉…


現在的網頁, 大多結構性很好, 所以就算沒有REST API, 其實也不難處理, 搭配上 jsoup , 可以說輕而易舉


jsoup是一個可以用css selector來解析html的Java函式庫, 有了這個, 解析html可以不用辛苦的爬dom tree, 只要幾行簡單的程式即可:




Document doc = Jsoup.connect("http://example.com/").get;

Elements links = doc.select("a[href]"); // a with href
Elements pngs = doc.select("img[src$=.png]");

再來看看play store


先看看每個app的資訊畫面, 以Facebook為例, 它的url是 —



http://ift.tt/1vdf2kb



很明顯的, id後面是package name, 另外如果加上”&hl=”可以指定語言, 然後再看到頁面上:



在Facebook (公司名稱)下方有個分類, 可以使用Chrome的開發人員工具(我比較習慣這個), 找到這個連結的css class名稱是”document-subtitle category”,而名稱則在它底下的一個span, 這span有個屬性itemprop, 值是genre



因此, 透過以下這段code就可以取到類別名稱囉




Document doc = Jsoup.connect("http://ift.tt/OQdlpn" + packageName + "&hl=" + locale.getISO3Language()).get();
Elements elements = doc.select("span[itemprop=genre]");

當然, 這方法不只適用於play store, 其他網頁也可以嘗試用這個方法來取得資料


詳細的範例在: http://ift.tt/1oNXmMj




from Tumblr http://ift.tt/1oNXnQw

via IFTTT

2014年2月12日 星期三

馬來西亞樂高樂園

過完年, 趁著轉換工作的空檔, 去了新加坡玩, 也順便去了馬來西亞的樂高樂園(Lego Land)


這樂園算是蠻新的, 2012年的九月才開幕的, 至今也不過一年多, 地點蠻偏僻的, 但從新加坡搭巴士過去(我們是搭WTS的車, 門票也是透過他們買的)大約一小時吧, 中途要出入海關(新加坡, 馬來西亞)



論設施來說, 這樂園可能有點不及其他著名的主題樂園, 玩樂的設施比較偏年紀小的小朋友, 但對樂高迷來說, 也算是一個天堂


這邊隨處可見樂高拼成的人物, 建築, 尤其是在中間miniland的建築, 相當的逼真



像這棟馬來西亞的KLCC, 拍起來的照片真的很像如臨現場, 感覺不出來這是一片片樂高堆積起來的作品


不過這邊的缺點是, 販賣店賣得樂高其實價格偏高, 不太適合樂高迷來這掃貨




from Tumblr http://ift.tt/1m6hZCp

via IFTTT

2013年12月11日 星期三

用Spark.function()自定REST API

前一篇有提到, TINKER API提供的四個功能都是很基本的, 如果只靠那四個, 那Spark cloud的負荷會很大, 想像一下, 如果說要做一台遙控車, 把馬達控制的程式都寫在遠端, 那需要發出多少命令? 如果REST API只是負責來發前進, 後退, 轉彎, 其他如該輸出多少給馬達或哪個腳位這類的邏輯留在core上面, 這樣的設計就會顯得合理多了
所幸Spark其實有考慮到這問題, 只是目前的文件真的很殘缺, 還真很難找到相關資料, 這問題的答案就是:
Spark.function()
這函數的作用在於對應core上的函數以及自定的REST API:
這函數第一個參數是REST命令的名字, 第二個則是處理這命令的函數, 相當簡單

(From: http://julianshen.tumblr.com/post/69702065061/spark-function-rest-api)

2013年12月8日 星期日

Spark core & Spark cloud

image

Spark core跟一般Arduino不同, 它並沒有一個在PC上的IDE供你寫及編譯程式, 這動作完全是在雲端, 開發者在Web IDE上攥寫程式, 之後server會去編譯並下載firmware到Spark core端執行

明明電腦跟Spark core都在眼前, 但程式卻不是在眼前編譯反而繞了一段路從Spark cloud下來, 感覺是有點多此一舉, 但其實Spark cloud的功能不僅於此, 它還提供了一個叫TINKER的服務

TINKER分為兩部分, 一個是手機上的TINKER APP

image

這App的用途就是讓你可以在不用寫任何一行程式的情況下, 就可以測試你的Spark core, 它背後的作法就是發送REST API, 也就是另一部分, 所謂的TINKER API, 到Spark cloud上, Spark cloud在把對應的命令轉到core上面, 由於core設定只要一打開就會連上網連到Spark cloud上, 因此可以用如此的方式控制它

因為可以透過TINKER API來控制core, 加上TINKER API也是公開的REST API, 因此, 我們未必要用Arduino的程式寫法來控制core, 我們也可以透過TINKER API用自己想用的程式語言來做開發

以以下的閃爍LED當做例子:

image

以傳統Arduino的寫法, 這樣一個程式(這範例應該老到掉牙了), 應該是這樣的:

跟C有點像, 當然啦,你不用期待它有啥多執行緒(Multiple threading), 或是啥事件驅動(event driven)等等東西可以用啦, 基本上它也是編譯好跑在Spark core上, core並沒有強大的運算能力跟複雜的硬體可以搞這麼複雜的東西, 有一點要注意的是, 這樣一個程式從Spark cloud燒錄到core去, 原本的TINKER就會被取代而失效, 必須由TINKER APP重新燒錄

至於說到TINKER API, 由於是REST API, 因此你可以用你習慣的語言去包裝, 不管是java, javascript, 或是go也好, 包裝它相當容易, 基本上目前也只有四個API: digitalwrite, digitalread, analogread, analogwrite

我包裝了Node.js跟Go可以使用的版本, 需要的人可以直接取用:

  1. Node.js module: https://github.com/julianshen/SparkCoreJs
  2. Go: https://github.com/julianshen/SparkGo

如果改用了Node.js或是Go, 那這個閃爍程式該如何寫?

Node.js:

這邊就可以把原本用"delay"的方式改用javascript中的setTimeout來實作

Go:

Go這邊則就是用了Tick

Access token跟device ID其實是可以去你的Web IDE上查到的

透過TINKER API, 這樣程式就不用一定得要"on board"去執行, 而且使用的程式語言也不會有侷限, 但缺點是, 首先要考慮到網路所造成的時間差問題, 另一個問題是, 現在提供的API像是digitalread這樣的API都非常的基本, 如果所有程式全部放在遠端, 遠端程式就必須要很頻繁的透過Spark cloud來發號司令, 如果連上Spark cloud的core越多, Spark cloud的負擔就相當可觀, 如果能提供custom command或custom api的方式, 把部分常態的邏輯變成在core端執行的內儲程序被呼叫, 或許可以減輕些Spark cloud的負擔

2013年12月7日 星期六

Spark core

image
前天回家發現一包順豐快遞的包裹, 心想, 我又沒去淘寶或對岸訂啥東西, 怎會有那邊來的包裹, 拿起來仔細一看, 這不是我之前在Kickstarter上Back那個叫Spark core的project嗎? (http://www.kickstarter.com/projects/sparkdevices/spark-core-wi-fi-for-everything-arduino-compatible?ref=home_social)
雖然依稀記得前幾天收到它開始出貨的消息, 可是後來完全忘了這一回事了, 這也是目前我第一個也是唯一在Kickstarter上back的東西
這是一個很有趣的產品, 也完全開放, open source, https://github.com/spark , 一開始看到盒子就讓我有點些許驚艷的感覺, 一打開, 原來這這麼小一片(還附片麵包版, 真是貼心), 用的則是TI CC3000MOD
image
這顆Chip有個比較有趣的功能就是 Smart Config (http://processors.wiki.ti.com/index.php/CC3000_Smart_Config), 有點不是很了它背後的機制, 不過這機制讓Spark core很容易的就可以設定好Wifi, Spark core本身沒任何的介面, 所以在設定Wifi hotspot跟Wifi密碼是一個大問題, Smart Config解決了這個問題, 所以你可以在手機上很輕易的輸入你要用的hotspot跟密碼, 接著Spark core就很神奇的連上hotspot, 然後連上Spark cloud, 這之間, Spark core根本也不需要跟你的手機透過藍芽或任何方式先連線, 不過手機這時候是必須使用Wifi而不是連上3G, 對於這種小型裝置來說, 這的確是一個很方便的方式
Spark core還有一個蠻聰明的部分, 那就是Spark cloud, 當他連上wifi時, 他就會嘗試連上Spark cloud, 在第一次設定時, 會先嘗試做註冊的動作, 把Spark core跟你的Spark帳號連結在一起, 不過我一開始不是很順利, 看起來Spark core已經順利連上Spark cloud, 但卻一直沒跟我帳號連結在一起, 這動作搞了我兩天, 多虧熱心的CEO Zach耐心的幫我查問題, 最後透過手動的方式把這搞定了
Spark cloud讓你可以利用他的Web IDE去寫firmware, 然後download到Spark core執行, 甚至, 你也可以不用寫任何程式, 直接透過他的Tinker API (REST), 去對你Spark core上的腳位做如digitalWrite之類的動作, 所以是可以把複雜的邏輯放在遠端
整體來說, 這是蠻有趣的產品, 蠻期待看他的未來的

2013年10月22日 星期二

悲劇,mbpr螢幕摔破了





悲劇,mbpr螢幕摔破了




via Tumblr http://julianshen.tumblr.com/post/64842280400

2013年10月21日 星期一

2013年10月19日 星期六

[筆記] Android library project和manifestmerger.enabled

Android library project是為了解決Android開發中在不同專案間分享原始碼以及資源檔(resource)而出現的, 傳統的jar並未考慮資源檔的問題, 因此便需要靠Android library project來解決


目前, Android library project已經被廣泛運用, 舉凡ActionbarSherlock, Facebook Android SDK, 很多都已採用這形式


不過現在一般用法還是比較廣泛應用在跟UI相關這類的應用上, 這也合理, 這類的應用常需要包含原始碼和資源檔, 不過它也適合在其他應用上, 舉個例子(好吧, 這例子有點不清不楚), 我們也有可能需要讓所有使用某個library project的應用程式自動加上一個Intent Receiver, 假設這receiver實作上是固定的, 並不需要使用的應用程式自行去繼承, 或是, 我們希望某個Activity的實作是被連結到各個應用程式中, 這類應用使用Android library project也是可以辦到的


這類的應用, 通常還需要在AndroidManifest裡宣告, 除了receiver, activity, 也有可能加上一些service, 甚至是permission, 正常來說, 在建置使用了Android library project的專案時, library project裡的AndroidManifest的內容並不會合併到最後的AndroidManifest裡, 以致於, 雖然在library project內這些都被宣告了, 但成品內可能無法被使用, 這解法也很單純, 只要在應用程式(不是library project)的project.properties裡加上:


manifestmerger.enabled = true


Manifest merger似乎存在有一段時間了, 但似乎也沒看到啥正式的官方文件, 不過目前這方法是可行的就是了




via Tumblr http://julianshen.tumblr.com/post/64537710342