這是一面藍藍的牆,
廣場全貌(依然拍得很爛orz)
這是一面藍藍的牆,
廣場全貌(依然拍得很爛orz)
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
兩隻早鳥不用排隊, 熱騰騰剛出爐的蛋塔真是超好吃, 酥皮酥得不可思議!
另外也點了同是酥皮褂的可頌夾火腿起司, 也是好吃~
廚房裡有好多蛋塔等著被吃掉(舞動)
這幾隻也蠻俏皮的
細節有點繁瑣, 有幾點要特別注意.
第一是雖然你的測試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.comapi的用法可以直接參考官方文件, 其他需要注意的是: 針對同一個app, Google Play API一天可以打得次數是有上限的, 所以最好只在必要的時候用. (而且我們也不希望因為request量太大影響整體系統效能吧) 官方文件的建議是希望我們能把查過的訂購資料記下來, 如果是單次性購買的產品, 就只要在使用者剛買完的時候查過一次就夠了, 訂閱型的產品則是在訂閱到期的時候重新查詢狀態. ref: - Google Play API - Google Play In-app Billing
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)
完全照著做就挺成功的.
為了要快速消耗花生醬我完全沒用芝麻醬(其實家裡也沒有啦XD)
雞絲有特別撕大塊一點吃起來比較過癮
感覺雞絲有點乾乾的就把它泡在蒸出來的雞汁裡放涼覺得效果還不錯
而且老乾媽辣椒的確是有必要, 畫龍點睛啊!
剩下的醬汁用醬油跟醋稀釋(也加強鹹度酸度)後就拿來拌麵也很好吃哦!
走啊走到了終於到了電扶梯的起點,
沒圖沒真相XD
很類似香港中環到半山的電扶梯的感覺, 不過不是階梯的
經過了不算短的距離之後終於到達雪場囉!
我們先到裝備出租店面搞定雪板鞋子等等東西.
再來熱身完畢就開滑囉!
早上我們都待在日影(HIKAGE)滑道,
馬克教練帶著大家滑瞭解我們的程度同時糾正跑掉的動作,
時隔一年連下纜車都好緊張! 深怕會跌倒害纜車停住那超丟臉搭.
雪越下越大,
中午我們就在雪場入口附近的餐廳吃吃,
毫不猶豫就選擇了摩斯XD
下午我們搭日影Gondola滑天堂(PARADISE)滑道
超大雪所以也沒拍照了
總之就是持續練習S-turn為明天的SKYLINE作準備啦!
用晚餐照結尾
這是一開始上桌的畫面之後又來的炸物等等東西吃好飽啊!
[野澤系列]
- Snowboard再體驗, 迷人的小村莊 - 野澤溫泉
身為布丁控, 焦糖布丁是一直我很想嘗試自己做的甜點,
但都處在萬事俱備只欠東風(明明就只是懶)的狀態.
在2014年的最後一天晚上,
發現好不容易搶到的初鹿鮮乳再幾個小時就要過期.
就憑著一股衝勁開工囉!
主要是參考松露玫瑰部落格上貼的LADURÉE食譜.
照著做大致上算是挺順利, 只有幾個步驟小小卡關,
一開始取香草籽放到牛奶鮮奶油混合液稍微加熱後,
香草籽始終無法均勻的分散開來, 造成最後的成品香草籽顆粒太大不好看.
不知道這步驟有沒有什麼訣竅.
另外是不太明白做焦糖最後鍋子離火放到冷水中,
焦糖加熱水攪拌是為了什麼.
我加熱水完全攪不動 囧
只好再放回爐火上重新回到焦糖狀態,
但這次就直接把焦糖倒入小容器中冷卻了, 參不透其中的奧祕啊~
這個食譜做出來的焦糖布丁超厲害啊!
布丁非常的綿密柔滑, 吃第一口的時候我整個人有點嚇到.
最後的叮嚀就是, 把布丁倒出來的時候不要偷懶啊! 用的刀要夠利夠薄.
要不然邊邊就會跟下面這張圖一樣像是狗啃搭~