Sunday, October 16, 2016

Snowboard再體驗, 迷人的小村莊 - 野澤溫泉, 大名鼎鼎的Skyline

我竟然繼續寫了野澤篇! 猜不透吧
一早醒來雖然天空還是陰陰的但雪已停,
感覺會是個好天氣, 而教練要帶我們去SKY LINE滑滑, 非常開心.



到了雪場沒一會兒太陽就出來了
(綠色那隻是野澤菜)
旁邊有兩個可愛的滑雪寶包也在準備中

早上還是在Paradise練動作,

天空好藍好藍...好藍

然後地越來越堅硬orz
我的S-Turn還是不見起色 囧

時間咻一下子就過去了, 中午在PopEye吃飯

吃飽之後我們就坐F纜車在接E纜車到SKY LINE滑道,

視野很寬闊可以看到遠方群山以及山腳下的村落
真的是很美啊
但我沒什麼機會拍照因為我都在努力的跟上大家的腳步
一開始還有認真的練習轉彎但是到後來的黑線真的只能落葉飄飄飄下去
腿酸到不行
(不是故意選這張有人撲街的照片啊XD 是因為這張天空比較藍)

路好窄啊逼死我




畫到黑線盡頭就轉40號KITSUNE綠線到NAKASAKA區,
回到山腳下的感覺真好啊!

這時我已快殘廢, 於是就脫隊搭了Q纜車先收工囉

回旅館的路上


[野澤系列]
- Snowboard再體驗, 迷人的小村莊 - 野澤溫泉
- Snowboard再體驗, 迷人的小村莊 - 野澤溫泉, 開滑囉! 大雪下不停~

Tuesday, September 13, 2016

沒想到上次更新網誌已是一年多前

最近常常想起以前的事
並且充滿感謝

從大家身上獲得的幫助實在太多
因為你們我成為了現在的我

我能夠毫不遲疑地說: 是的, 我喜歡這樣的自己

Monday, July 20, 2015

西班牙葡萄牙我們來惹 (9) Lisbon 里斯本舊城區閒晃

滿心歡喜的帶著蛋塔離開,
我們回到市區的無花果廣場搭黃色的28號電車前往舊城區Alfama,
電車載了滿滿的遊客一路咖噹咖噹的往山坡上爬感覺相當吃力,
我們在山坡上的教堂門口下車,
一般遊客都會在這裡拍小黃電車從教堂邊駛過的照片,
但我失敗了orz 連教堂都被我切了一角失敗中的失敗...

一路往下走有一些有趣的小店可以逛逛,
這家專門賣手工縫紉的(印象中是)布製品, 有很多抱枕擺飾都很有小巧思,

這是一面藍藍的牆,

走啊走來到瞭望台附近


這景色真是不得了啊! (實際上比我拍到的強很多! 我拿GRD3真是浪費了...)

澳門的房子跟街道跟這裡長得一毛一樣,
圖中出現了我之前一直捕捉失敗的小黃電車.


接著我們前往另一個可以俯瞰里斯本的景點: 聖喬治城堡(Castelo de São Jorge),
這座城堡在中世紀也曾經是皇宮哦!
可惜因為多次地震造成嚴重損毀, 而後才逐步修復.

在城牆邊往貝倫區的方向看, 也不就過了半個多小時天色已經變得暗沉沉了

這邊養了不少孔雀, 可惜看到相機他們都跑超快的啊Q.Q


再往裡面走到內側的城牆.


離開城堡後距離晚餐還有一段時間
我們就展開快樂的逛街行程
小大殺了兩(三!?)雙鞋而我竟然莫名奇妙地買了一件長洋裝
之後成為我喝喜酒的固定班底


另外幾張照片是隔天參觀完Pena城堡拍的
無花果廣場周邊的餐廳,

做作照來一張(襯衫是在西班牙買的, 迫不及待拿出來穿了XD)

廣場全貌(依然拍得很爛orz)


- 小大版: 葡萄牙正宗葡式蛋塔在Lisboa (有餐廳跟旅館介紹, 街景也美多了)

Wednesday, June 24, 2015

Scala筆記: 回顧Option以及認識新朋友Either

最近又開始比較仔細的研究playframework,
在追Action的時候不小心認識了Either,(這樣寫起來怎麼有點花心感XD)
就趁機整理一下啦!

Either顧名思義就是不是這個就是那個(繞口令來著)
這樣是不是會讓你想起不是有(Some)就是沒有(None)的Option呢?
以下是相關的class以及他們的繼承關係.
sealed abstract class Option[+A] extends Product with Serializable
final case class Some[+A](x: A) extends Option[A]
case object None extends Option[Nothing]
abstract final class Nothing extends Any

之前在處理error handling的時候有用過Option,
成功回傳Some,失敗就回傳None,
但其實會有些問題, 因為我們有時候會需要針對不同的失敗原因個別處理,
像是我們要從資料庫讀取某筆資料, 可能會因為網路問題, 或是資料庫過於忙碌等等因素造成失敗
或者是我們成功得到資料庫的回應但是該筆資料並不存在
把這些林林總總的狀況概括用None來表示其實會太簡略

這個情況下我們就可以使用Either,
以下是相關的class以及他們的繼承關係.
sealed abstract class Either[+A, +B] extends AnyRef
final case class Left[+A, +B](a: A) extends Either[A, B] with Product with Serializable
final case class Right[+A, +B](b: B) extends Either[A, B] with Product with Serializable
他的值可以是類型A或類型B,
通常回傳Left是用來表示失敗,用Right表示成功

因為Action的部分有點複雜, 這邊就從playframework的OAuth library貼個簡單的範例.
  def retrieveRequestToken(callbackURL: String): Either[OAuthException, RequestToken] = {
    val consumer = new DefaultOAuthConsumer(info.key.key, info.key.secret)
    try {
      provider.retrieveRequestToken(consumer, callbackURL)
      Right(RequestToken(consumer.getToken(), consumer.getTokenSecret()))
    } catch {
      case e: OAuthException => Left(e)
    }
  }
再加上Left跟Right都是case class,
所以我們抓到結果之後可以簡單地用match處理回傳值
val reqTok = retrieveRequestToken("localhost:9000/callback")
reqTok match {
  case Right(tok) => // success, continue 
  case Left(ex) => // fail to get request token, dothing
}
大概是這樣!

另外再補充一些細節,
1. sealed
被加上sealed關鍵字的類別, 只能被定義在同一個原始碼檔案的類別繼承.
2. Option[+A]
是covariance的概念, 指的是D如果是A的子類別, 則Option[D]也是Option[A]的子類別


ref:
- Either
- Left
- Option
- 探索Playframework: 如何正確使用thread pool

Sunday, March 22, 2015

西班牙葡萄牙我們來惹 (8) Lisbon 蛋塔的故鄉里斯本, 貝倫區

出發前小大問我從西班牙到葡萄牙這段路介不介意坐夜車
我毫不猶豫的說沒問題(主因是我直覺認定是坐火車, 但買票前我才赫然發現其實是坐巴士XDD)
那夜凌晨,我們坐上了Sevilla開往Lisbon的紅VAN的巴士(連電影名稱都偷來用是怎樣)
默默期待能佔兩個位子睡得舒服些, 但泡泡一下就被戳破, 出發時整車載滿滿啊~
一路上睡睡醒醒又睡睡醒醒, 不是太舒服但我撐過來了(是在驕傲什麼)!!
清晨五點多天還沒亮, 我們到達巴士終站, 不過到的時間太早地鐵還沒開吶~
昏昏沈沈的等到六點的第一班車, 要到市中心今晚住宿的旅館寄放行李

一切都安頓妥當後我們坐公車到貝倫區(Belém)
要完成在葡萄牙最重要的一件事(小大可能不見得同意XD)吃到Pastéis de Belém的蛋塔~
鄰近的修道院(Mosteiro dos Jerónimos)是蛋塔誕生的地方,
而Pastéis de Belém一直到今天都遵照古老的修道院食譜製作蛋塔哦!

兩隻早鳥不用排隊, 熱騰騰剛出爐的蛋塔真是超好吃, 酥皮酥得不可思議!
另外也點了同是酥皮褂的可頌夾火腿起司, 也是好吃~
廚房裡有好多蛋塔等著被吃掉(舞動)

填飽肚皮之後就開啓觀光模式啦! 可惜一早天氣就陰陰的Q.Q

往修道院的方向走, 先看到Lisbon的地標之一發現者紀念碑(Padrão dos Descobrimentos)
建造成船型的就是為了要紀念葡萄牙威風的航海時代

船上有很多人但我不知道他們是誰XD


天色一直霧霧的還飄著小雨, 我們就沒有多停留, 岸邊有很多人在釣魚.

路上看到了雙胞羊~

另外一個著名的地標是貝倫塔(Torre de Belém)
它也是航海時代的建築, 已被列為世界遺產囉 除了具有紀念意義外也因視野遼闊具有軍事上防禦的功能!


接著我們前往另一個世界遺產熱諾尼莫修道院(Mosteiro dos Jerónimos)
門窗柱子的華麗浮雕非常驚人!
長得很酷但我拍的很爛XD

寬廣的中庭, 在這裡停留了很久, 因為這裡的柱子跟牆壁上有好多趣味的浮雕!

這隻晃神的動物是獅子嗎!? 我覺得我們長得還蠻像的XD

這幾隻也蠻俏皮的

另外還有歌德式風格的教堂,

離開貝倫區之前我們又到蛋塔店外帶兩個稍候吃
涼掉了還是很好吃哩


小大版: 葡萄牙正宗葡式蛋塔在Lisboa

番茄大蒜香草烤雞腿

這食譜已經做了兩三次了!
只要把材料洗洗切切擺好之後送進烤箱就能等著吃囉~
可以參考廚房裡的人類學家莊祖宜的示範.


不過雖然簡單歸簡單還是有幾個小地方要注意,
雞腿一定要先擺到烤盤裡,
先放番茄容易讓雞腿底部無法泡在後來烤出來的雞汁番茄湯汁裡
雞腿會比較乾而且會沒味道!
另外就是材料不要堆到雞皮上面, 這樣皮會烤不脆.

還有香草我用的是百里香, 特別喜歡它清新的香氣啊~

最後呈盤長這樣, 馬鈴薯是蒸完在用平底鍋煎過會脆脆低
噢! 我是用去骨雞腿所以它看起來扁扁的比較沒精神啊哈哈

Friday, February 27, 2015

TrivialDrive: Sample for Google Play In-app Purchase

萬萬沒想寫了iOS in app purchase之後四年, 我會寫Google Play in app purchase, 真是造化弄人(又亂用成語)啊~~

總之就是利用官方文件提到的TrivialDrive範例跑完整個流程囉!
不囉唆直接開始

[在Google Play設定要賣的東西]
1. 申請Google Play開發者帳號
2. 設定Google Wallet帳號
3. 在Google Play開發者網站新增app
4. 產生public key
5. 上傳用release key簽章的apk
6. 發佈app到alpha或beta測試
7. 新增in app商品, 可以是一次性或能多次購買的產品, 亦或是訂閱服務
8. 產生Google group並加入之後要用來購買東西的測試帳號
9. 設定Google group為alpha或beta測試群組


細節有點繁瑣, 有幾點要特別注意.
第一是雖然你的測試app只是要進到alpha或beta測試, 一般人沒有機會接觸到, 但還是要注意著作權的問題啊!
發佈app的時需要提供正確格式的截圖跟圖示, 我偷懶直接搜尋對的解析度的圖片就拿來用.
結果設定完成快樂回家, 隔天來公司就發現app被停權了, 只好砍掉重練Q.Q
另外就是一定要發佈app之後才能測試自己上架的商品,
若還只是draft僅能測Google提供的商品, 能分別針對不同的購買情境.
Note: Previously you could test an app by uploading an unpublished "draft" version. This functionality is no longer supported. However, you can test your app with static responses even before you upload it to the Google Play store. For more information, see Draft Apps are No Longer Supported.



[從app購買商品]
1. 下載TrivialDrive範例程式, 如果是用Andriod Studio,只要有抓Google Play Service SDK就可以直接匯入
2. 更新package的名稱 (用IDE提供的refactor->rename很快)
3. 更新public key (String base64EncodedPublicKey = ...)
4. 把商品換成在play developer裡面新增的product id
5. 建置並用把app用release key簽章
6. 把apk放上google play(對應到前一段的5&6)
7. 把apk裝到手機上(不能用emulator測哦)

進到app會看到這個畫面, 大概就是模擬開車, 開車會消耗油, 油不夠就要買等等

這個畫面是點選Upgrade My Card(對應到我的一次性購買商品)之後, 會出現商品說明及價格等資訊

之後可能會需要輸入密碼才能繼續購買, 然後就成功囉~

另外一個是點Get Infinite Gas(對應到我的訂閱型態的商品)會出現的畫面,
因為我設定了七天的試用期, 所以一開始不會馬上收費


從Google Wallet的記錄可以看出來, 一直到七天以後才正式付款哦



[查詢購買狀態]
在我們提供的產品或是服務需要由server提供的情況下,
server需要有辦法能夠確認使用者的購買紀錄,
這時Google Play API就派上用場啦!

1. 申請Google developer帳號
2. 開啟新的api專案
3. APIs&auth選單: 先到API設定開啓Google Play Android Developer API
4. APIs&auth選單: 新增Client ID, 並選擇web application為應用類型, 填妥必要資訊
(也可選擇用Service Account但我卡關XD)
5. 回到Google Play的API access設定頁面, 將剛剛的api專案連結到你的帳號
6. api帳號利用OAuth取得google play帳號的權限
(拿到authorization code之後, 就可以讓server用它換到refresh token然後就無敵惹XD)
7. 查查查

OAuth的url大概是長這樣, 重點是scope還有要能offline access
https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=https%3A%2F%2Fwww.rita.inapp.com%2Foauth2callback&client_id=00000000000-xxxx.apps.googleusercontent.com

api的用法可以直接參考官方文件,
其他需要注意的是:
針對同一個app, Google Play API一天可以打得次數是有上限的, 所以最好只在必要的時候用.
(而且我們也不希望因為request量太大影響整體系統效能吧)
官方文件的建議是希望我們能把查過的訂購資料記下來,
如果是單次性購買的產品, 就只要在使用者剛買完的時候查過一次就夠了,
訂閱型的產品則是在訂閱到期的時候重新查詢狀態.

ref:
- Google Play API
- Google Play In-app Billing

Wednesday, February 25, 2015

探索Playframework: 如何正確使用thread pool

在scala的世界, 我們常會用Future來處理某些非同步的工作,
用Future, 必需要透過implict的方式提供execution context, 來執行這些工作.

白話的說就是要指定你的code要在哪個thread pool跑.

使用Playframework, 在比較單純的情況下直接用預設的thread pool就可以了.
然後再透過application.conf設定適當的參數.

import play.api.libs.concurrent.Execution.Implicits._

def someAsyncAction = Action.async {
  import play.api.Play.current
  WS.url("http://www.playframework.com").get().map { response =>
    // This code block is executed in the imported default execution context
    // which happens to be the same thread pool in which the outer block of
    // code in this action will be executed.
    Results.Ok("The response code was " + response.status)
  }
}

play {
  akka {
    akka.loggers = ["akka.event.Logging$DefaultLogger", "akka.event.slf4j.Slf4jLogger"]
    loglevel = WARNING
    actor {
      default-dispatcher = {
        fork-join-executor {
          parallelism-factor = 1.0
          parallelism-max = 24
        }
      }
    }
  }
}

import play.api.libs.concurrent.Execution.Implicits._
先來找找我們用的execution context在哪裡,
defaultContext是ActorSystem的dispatcher
而create ActorSystem用的設定是"play"這個關鍵字下面的所有屬性.
接下來就是看ActorSystem如何設定dispatcher囉~
defaultGlobalDispatcher是用DefaultDispatcherId(即akka.actor.default-dispatcher)抓到設定值

大概是這樣囉!


針對不同類型的工作, 有時候我們會不希望所有事情都塞在預設的thread pool做,
要使用其他的thread pool, 只需要先在application.conf加上一組新的設定.
再用lookup讓Akka能找到它就好.
可以直接在產生Future的時候指定execution context或是直接import讓implicit發生作用
my-context {
  fork-join-executor {
    parallelism-factor = 20.0
    parallelism-max = 200
  }
}

object Contexts {
  implicit val myExecutionContext: ExecutionContext = Akka.system.dispatchers.lookup("my-context")
}

Future {
  // Some blocking or expensive code here
}(Contexts.myExecutionContext)

or

import Contexts.myExecutionContext
Future {
  // Some blocking or expensive code here
}

當然實際上要如何設定thread pool還是要參考測試結果啦!

ref:
- playframework source code (2.3.x)
- akka source code (2.3)
- understanding play thread pools (2.3.5)