抵抗の値をslackで確認したい!!!

どうもこんにちは、最近いろいろバタバタしているはとバスです。

この記事はAizu Advent Calenderの19日目の記事になります

18日目 fatman???? さん

20日目 のあ

当日の朝に担当だったことを知り、ほぼ半日で作った適当なslackのコマンドを紹介します。

カラーコードを確認したい

最近はめっきり機会が減ってしまったんですが、電子工作が好きです。

大学一年のときから始めて、いろいろな物を作ってきました。

hatobus.hatenablog.jp

hatobus.hatenablog.jp

電子部品を使うときのあるあるなんですけど、抵抗の値って、難しくないですか?????

f:id:flying_hato_bus:20191219214131p:plain

12の色と値を暗記しなければいけないし、パッと見ただけでは分からないので調べてから使うという人もいると思います。

そんな時に、slack上で簡単に確認できたら良さそうじゃないですか?

作りました

slackのslashコマンドを作りました。

f:id:flying_hato_bus:20191220095723p:plain

/resistor [抵抗の値]と書くことで、カラーコードの画像が返ってきます。

f:id:flying_hato_bus:20191220100244p:plain

f:id:flying_hato_bus:20191220100322p:plain

実装

使っている技術としては

  • サーバー
    • GCP cloud functions
  • 言語
    • Go

です。cloud functionsをサーバーにして、リクエストに応じてGoで画像を生成、そのままslackに画像を投稿しています。

f:id:flying_hato_bus:20191220101110p:plain

ポイント

github.com

カラーコードを生成する部分です。

抵抗の値を数字だけで表現する場合は入力された文字列をint64にキャストすればいいだけですが、抵抗の値を指定するときには少し特殊なフォーマットの場合があります。4700 Ωを 4k7などに表現するやつです。このようなフォーマットで表現する時に、以下のような表現の仕方があります。

  • 1k
  • 4k7
  • 47k
  • 470k

また、k以外にもMの接頭辞のときもあります。

このように表現されたときの抵抗値も対応しています。

SI接頭辞付きの抵抗値の場合

330Ωなど、接頭辞がついてないときには、 strconv.Atoi()などを使えば、stringをintにキャストできます。まずはこれで当たってみて、接頭辞が付いているときにはエラーが返ってくるため、Splitするセクションに入ります。

上で上手くキャストできなかった場合、SI接頭辞(k, Mなど)が付いているときには、入力された文字をSplitします。Goでは strings.Splitという関数があります。

golang.org

これは文字列を指定文字で切り取ることができるという関数です。

srcstr := "a,b,c"
splitstr := strings.Split(srcstr, ",")

// splitstr -> ["a" "b" "c"]

つまり、これでk, Mの場合でSplitすれば、 4k7などは ["4", "7"] という値が返ります。Splitした値はこのようになります。

  • 1k --> ["1", ""]
  • 4k7 --> ["4", "7"]
  • 47k --> ["47", ""]
  • 470k --> ["470", ""]

補足ですが、Splitには罠が存在して、 47kのように、最後に切り取る文字が来ている場合には最後に空白が入ります。気をつけましょう。

これで上手くSplitできればできたときの文字で乗数も割り出せますね。

  • kでSplitできた --> 乗数 = 3
  • MでSplitできた--> 乗数 = 5

あとはカラーコードを割り出すまでもうちょっとです。

f:id:flying_hato_bus:20191220111435p:plain

抵抗は上2桁の数字をそれぞれの色に対応させ、3本目の線を乗数の色にします。

- 4k7の場合

4700なので 1本目は 黄色 2本目は 紫 乗数は10^2なので 赤

のように求まります。

上にある 1k, 4k7, 47k, 470k の場合は以下のようになります。 (Split済みの配列をcontainsと書きます)

- 1k
contains[0]の文字は1桁、contains[1]の文字は無し、この場合1st barは1になり、2nd barは0になる、乗数は1減るので減らしておく

- 4k7
contains[0]の文字は1桁、contains[1]の文字は1桁、この場合1st barは4になり、2nd barは7になる、乗数に変化はない。

- 47k
contains[0]の文字は2桁、contains[1]の文字は無し、この場合1st barは4になり、2nd barは7になる、乗数は1増やす必要がある。

-470k
contains[0]の文字は3桁、contains[1]の文字は無し、この場合1st barは4になり、2nd barは7になる、乗数は2増やす必要がある。

contain[0]の長さでif-elseしています。

 if len(contain[0]) == 1 {
        fv, _ := strconv.Atoi(contain[0])
        firstband = int64(fv)
        if contain[1] == "" {
            secondband = 0
        } else {
            sv, _ := strconv.Atoi(contain[1])
            secondband = int64(sv)
        }
    } else if len(contain[0]) == 2 {
        fv, err := strconv.Atoi(contain[0])
        if err != nil {
            return nil, err
        }
        firstband = int64(fv / 10)
        secondband = int64(fv % 10)
        mag += 1
    } else {
        resistor_topvalue, err := strconv.Atoi(contain[0])
        if err != nil {
            return nil, err
        }
        for i := 0; ; i++ {
            last1digit := resistor_topvalue % 10
            resistor_topvalue /= 10
            if int64(resistor_topvalue/10) == 0 {
                firstband = int64(resistor_topvalue)
                secondband = int64(last1digit)
                break
            }
            mag += 1
        }
    }

これによって、firstband, secondband, magの3つの数値が求められ、これを元に色を出しています。

色を求めて、いい感じに画像を生成しています。

cloudfunctionsについて

cloud functionsの仕様として、ユーザーが自由にファイルを書き込める場所に制限があります。

cloud.google.com

ファイル システムで書き込み可能な部分は /tmp ディレクトリだけです。このディレクトリは、関数インスタンスの一時ファイルの保存先として使用できます。

とあるので、slackに投稿する画像は /tmp以下に置かなければいけないことがわかります。

大急ぎで書いたのでクソ適当になりましたが、今回のアドベントカレンダーネタは以上になります。

来年からはもっとちゃんと書きたい。

もっと書くべき内容があったと思いますが、内容がバカでかい騒動にまで発展してしまったので書けませんでした。

気をつけよう!!!!!!

野菜を食べる技術

早いものでもう12月ですね

今年もアドベントカレンダーの時期ですね。みなさんはいかがお過ごしでしょうか?

今回のアドベントカレンダー、僕だけ2つの記事を書くみたいになってしまって本当に申し訳ないです(見たときには前半のほうが開いていて、埋まってなかったらなんとも言えない気持ちになってしまうので急いで入れてしまった...)

その貴重な枠をこのようなポエムで汚してしまうことをどうかお許しください...

てなわけでこの記事は Aizu Advent Calendar 2019 2日目の記事になります。

adventar.org

1日目は まさちゃこさん

3日目は インターネットミームの使い手 dennougorilla くんの記事になります。

健康的な生活をしたい

定期的に言っていますが、僕は結構な デブ です。

小学校から高校まではテニス部でそれなりに汗を流していたので、大学入学時には70kgを切っていましたが、大学生活によってブクブク太っていき去年一番太っていた時期は96kgありました。

単純に30kg太ったことになります。

今は85kgあたりをウロウロしています。

切実な目標として、健康的な生活をしたいです。

そもそも健康的な生活とは...? という問題に直面しますが、WHO憲章では、その前文の中で「健康」について、次のように定義しています。

Health is a state of complete physical, mental and social well-being and not merely the absence of disease or infirmity.

公式の訳としては

健康とは、病気でないとか、弱っていないということではなく、肉体的にも、精神的にも、そして社会的にも、すべてが満たされた状態にあることをいいます。

このWHOの健康の定義、めちゃくちゃ厳しくないですか?????

この健康的な生活を目指すのは流石に厳しいので記事の中ではWHOの健康の定義からは離れ、自分が実践していたある程度健康的に暮らす方法として 効率的に野菜を摂る方法 を書こうと思います。

野菜を食べる

野菜を食べるということはビタミンやミネラルを補給でき体のバランスを整えることに繋がります。

健康的な生活をするためには不可欠です。

あと「俺は野菜を意識して食べているぞ、そんじゃそこらの人よりも偉いはず、俺は偉い偉い偉い」と他人にマウントを取れます。精神的な健康も保てるはず。

たまに二郎の上に乗っているもやしを野菜と言っている人もいますが、あれは野菜ではなく油まみれのなにかです。健康的な生活をしたいのであれば二郎を月イチくらいに抑えたほうが絶対にいいです。

効率的に野菜を食べよう

おすすめの食べ方は鍋。一人鍋用スープの素があれば片手鍋でグツグツ野菜を煮込めば放っておくだけで美味しい何かが出来上がり、野菜を摂取できます。

食材を保存する

野菜は水分が多く、すぐに傷んでしまいます。あんまり自炊をしないという人に生野菜をおすすめすることは難しいと思うんですが、冷凍することでこの問題を解決できます。

週の初めや野菜が安い時にキャベツや玉ねぎ、えのきやしめじを買っていい感じの大きさに無心で刻み、100均に売っている安いジップロックみたいなものに詰め込んでそのまま冷凍庫にぶち込んでください。

お肉も一緒に買ってきて、ラップ等で小分けにし一緒に冷凍することもでき、タンパク質も楽に摂れます。

おすすめの野菜

  • キャベツ
    • 味噌や坦々系の鍋におすすめ、よく煮込むと甘みが出てきておいしい
    • 半玉買ってざく切りにするとジップロック特大1袋くらいになる
    • 冬に買うと葉が硬いので注意する
  • 白菜
    • 鍋に使う野菜の王道
    • どんな鍋にも合う
    • 味がしみて美味しい、1/4くらいでジップロック1袋くらいになる
  • 玉ねぎ
    • 味噌汁やラーメンを作るときとかにも使える
    • 常温でも保存が効くので買い置きしてもいい
  • ニンジン
    • 短冊切りにすると鍋で食べやすい
    • ラーメンを作る時に玉ねぎ一緒に入れるだけでもかさ増しになる
  • ネギ
    • 斜めの輪切りにすれば鍋や味噌汁の実として
    • 細切りにすれば薬味としてそのまま乗せられる
    • ゆっくり煮ればトロトロになっておいしい
  • えのき
    • 意味不明なくらい安いときが多い
    • どんな料理にも合うのでハズレが少ない
  • しめじ
    • デフォルトのきのこ
    • どこのスーパーにもあって安く手に入る

お肉はウィンナーをおすすめします。

冷蔵室に置いておいてもそれなりに日持ちがするし、なんなら常温でボリボリ行けるので何か口に入れないととなった時に食った気になれます。

三等分にして冷凍しても鍋にぶちこめばおいしい出汁が出てくれますし、包丁で切るのもめんどくさいときは冷蔵庫から出して手でいい感じの大きさにちぎるだけでもいいです。

鍋を作る

素晴らしいもので、世の中には 一人鍋の素 というものがあります。

絶大な信頼を置いているプチッと鍋シリーズ

ちょっとの水に鍋の素をいれて好きな野菜をぶち込んで10分くらい煮込めば野菜の入った美味しい何かが出来上がります。

一緒に生姜を入れてあげれば手足の先の冷えの対策になります(なってほしい)

鍋の具材を食べ終わった後に冷凍のうどんや餃子を入れればシメも美味しく楽しめます。

???「ガスを使うのめんどくさい、鍋を洗わなくちゃいけないのが嫌」

エビス 電子レンジ調理用品 ブラック 1000ml

エビス 電子レンジ調理用品 ブラック 1000ml

レンジ対応の一人鍋容器でできます。

使い方としては

  1. 容器に水と鍋の素を入れる
  2. 好きな野菜と肉を入れる(肉は最初に入れないと焦げる可能性がある)
  3. 500Wのレンジで10分くらいチンする
  4. おいしい

シメにうどんやご飯を入れたいときも物を入れて5分チンすればおいしいうどんやおじやができます。

洗い物も箸と容器だけで済むので楽ちんです。

鍋という選択

鍋はめちゃくちゃ楽でオススメです。具材をぶち込んで煮るだけで美味しい鍋が出来上がり、野菜も摂れるしいいことずくめです。

ちなみに、友達が家に来たときとかにも楽で、一人鍋の素を人数分に増やせば鍋の量を調整できます。鍋のオートスケーリング(申し訳程度の技術成分)が可能です。

おすすめの鍋の素

おすすめの鍋の素をいくつか貼っておきます。スーパーならこのなかで1つは必ずあるはず。 ちなみに、ドラッグストアのワゴンセールで意味不明なくらい安いときもあるのでそういうときは狙い目です。

  • こなべっち 鶏だし生姜鍋つゆ

最高の鍋の素、生姜の香りと鶏のうまみが感じられる美味しいやつです。シメのうどんも最高にうまいのでオススメ、鍋以外の料理として茹でたそうめんを入れてにゅうめんにしても美味しいですよ。 なかなか店頭に並んでいるのを見ないので、見たら速攻で買いだめするのが吉

オススメの具材
- 白菜
- 鶏肉
- にんじん
- しめじ
- ネギ
  • プチッと鍋 寄せ鍋

寄せ鍋にしてもよし、そのままうどんのつゆにしてもよし、万能でハズレがないおいしい鍋の素 会津だと簡単に手に入る。

オススメの具材
- 白菜
- 肉(なんでも)
- にんじん
- しめじ or えのき
- ネギ
  • プチッと鍋 濃厚みそ鍋

最近ハマっているおいしいやつです、キャベツを煮込んであげると甘くておいしい。シメには業務スーパーで買った安い乾麺を入れてあげるとシメの味噌ラーメンになります。

オススメの具材
- キャベツ
- 肉(なんでも)
- にんじん
- もやし
- しめじ or えのき
- コーン

さいごに

後輩とかを見ていると、ちゃんとした食事を摂って欲しい人が数名います。

↓↓↓↓↓↓↓↓例です↓↓↓↓↓↓↓

食というのは生きる上での基本であって、栄養の偏りや不規則な食事などによる肥満や、それらが原因と考えられる生活習慣病などになっては元も子もありません。

長期的なことを考えればエンジニアも結局は体が資本であり、自身の健康は自分が作っていかなければなりません。

日頃の不摂生がたたったせいでエンジニアとして生きていけなくなるの、嫌じゃないですか?

なんか普段のツイートとは真逆のすごく意識の高い感じがして自分が嫌になったのでここらへんで失礼いたします。

みんな!!!野菜を食べて健康的になろうな!!!!!

平成最後はgRPCなサーバーを書いてハッカソンしていた話

こういうのってあとから書こうとすると時間が経ちすぎてなかなかポストできなくなりますよね。

そういうわけで書きます。

何してきたのよ

サイバーエージェントさんの 平成最後のハッカソンに出場してきました。

www.cyberagent.co.jp

4月の頭くらいからtwitter上で人事の方々がこのハッカソンについて話をしていたので、「ちょっと出てみるかぁ」みたいなノリで考えてました。

出場するまでの流れ

そんなことを考えてると、最近イキりがすごい id:NoahOrberg

id:NoahOrberg < これ、マヤミトくんと出ない?

みたいなことを言ってきました。

「プログラミングができる5歳児」ことのあくんが、インターネットで赤ちゃんをしている id:yt8492 を推していましたし、なによりもマヤミトくんと一緒に出たいなと僕も少し考えていたのでこの3人で出ることにしました。

チームの人員としては

  • プログラミングのできる5歳児 (サーバー&技術担当) のあ id:NoahOrberg
  • SNS広報担当とチームの平均体重を引っ張り上げる(サーバー) 僕 id:flying_hato_bus
  • 精神年齢生後3ヶ月(Android) マヤミト id:yt8492

この3人で蠱毒みたいなチーム作って参加登録しました。

数日後にはみんな参加できることが決定し、やっていきを高めてました。

お題が発表される

今回のハッカソンのお題は 「平成生まれの私たちが、平成を楽しく振り返ることができるサービス/モノ」というものでした。

さっそくのあくんとマヤミトくんと何を作るかを話し合うことにしました。

f:id:flying_hato_bus:20190508170237p:plain
チーム名とスクリーンネームが被ってちょっとテンションの上がるのあ

話した時に出たものはこちら

  • 小学校時代に書いた(こともある)プロフ帳を作る
  • 黒歴史を共有できるものを作る
  • spotifyでおすすめの曲をサジェスト

主に出たのはこの3つでした。

選ばれたのは黒歴史を共有するものを作るというプラン。

他の2つは

  • プログラミングのできる5歳児 (サーバー&技術担当) のあ id:NoahOrberg
  • SNS広報担当とチームの平均体重を引っ張り上げる(サーバー) 僕 id:flying_hato_bus
  • 精神年齢生後3ヶ月(Android) マヤミト id:yt8492

このチームの人員から考えても、そんなおしゃれなものを作るよりはネタに振り切ったほうがいいだろう、という考えでボツにしました。 僕達がそういうプロダクト作るのは似合わないってことですね

f:id:flying_hato_bus:20190508170904p:plain
みんなで話し合ったあとのホワイトボード

黒歴史を共有できるものということで深堀りしていき、出てきたのがこのホワイトボードのようなことです。

黒歴史 x ブロックチェーン

f:id:flying_hato_bus:20190508172051p:plain 黒歴史というものは、オタクならば結構な人たちが作ったことであろう歴史です。

  • イキリ満載のブログエントリ
  • 某動画サイトに実況動画を投稿
  • 肌にペンで傷を描いて学校に登校
  • 霊感があるキャラを装って心霊写真を捏造

こんな感じで「あの頃はこれがかっこいいと思った」「他人とは違う自分を演じたかった」という考えで突っ走ってしまう行為です(全部僕の体験談です)

黒歴史というものはあくまで「歴史」、勝手に改変されたり、なかったことにされるということはもってのほかです。

勝手にネット上で作った黒歴史を消されてはいけません。

つまり、これを恒久的に保存してあげる必要があります。

ここでブロックチェーンです!!

ブロックチェーンは情報の改ざんに強いデータベースです。

つまり、この黒歴史の情報をブロックにしてしまえば、半永久的に黒歴史は保存され、歴史の改ざんも防ぐことができるようになります。

作るにあたって

作るにあたっての作業分担はこんな感じ

サーバーは Go x gPRC、ネイティブアプリは Kotlin x gRPC という感じの構成。

github.com

github.com

それぞれのgithub repositoryです。

のあくんとマヤミトくんがいろいろと頑張ってくれたので実装は早く終わりました。

gRPCを使ってみた感想

今までやってきたようなRESTfulなJSONサーバーより断然書きやすかったです。

gRPCは自動生成されたgoのファイルを見れば何を実装すればいいか一目瞭然ですし、入出力がProtocol Buffersなので、jsonを扱う時のように Marshal / Unmarshal しなくて済むというのがめちゃくちゃ楽でした。

goではstructで扱えるので変数に型があり、どういうデータなのかがすぐ分かりますし、何よりもシリアライズされたデータが行き来するので速さが出ます。

そんなわけで大体のサーバーはハッカソンの3日前には大方の実装が終わり、マヤミトくんに頑張ってもらうだけになってました。

ブロックチェーンについて

ブロックチェーンは †最強†エンジニアののあくん id:NoahOrberg が担当しました。

合意形成アルゴリズム

ブロックチェーンの中心とも言える合意形成のアルゴリズムはのあくんが独自に実装してくれました。

独自合意形成アルゴリズム HEISEI

合意形成アルゴリズムは平成を使いました。いい感じにブロックが生成されるのが "平" "成" の二文字を使った時でした。

これも前日にはのあくんがすべて実装していたのでさすがですね。

ネイティブアプリ

一人で全部実装したマヤミトくんの記事でしっかり書かれているはずです。

yt8492.hatenablog.com

学部2年生ながらここまでやってくれたマヤミトくんは煽り抜きで最強だと思います。

これで彼女がいれば敵なしですね。

ハッカソン当日

ハッカソン当日には黒歴史ブロックチェーンがある程度出来た状態で参加できました。

あとは繋ぎこみをするだけという状態です。

まあ、こういう時は大体苦労するんですよね、苦労しました。

サーバーにバグが結構残っていた

本当に申し訳がなかったです。許して、マヤミトくん、のあくん。

直前まで小さなバグがちょっとずつ出ていてそれを潰す作業をしていました。

前日まで散々イキっていたのにこのザマです。精進します。

発表のフォーマットが特殊すぎた

チームが多すぎて発表の時間が押していた結果、

「スライドは2枚、1枚は実際に動いている動画を貼り、2枚目には説明を書く」

というものになっていました。

見た目にインパクトがあるものが有利になったのかなと思います。

僕らのチームは 見た目のインパクト < 技術 & 発想力 みたいな部分があったので技術力としてはそれなりにあったと思いますが、インパクトが足りませんでした。

優勝者のチームが以前会ったことのあるはととさんだったことにも衝撃でした。

作ったものが。「マリオのゲームで平成を振り返る」というコンセプトで、web上でマリオのステージが進むごとにゲームハードが進化していくという技術力がやばいやつでした。

「Vueのちからってすげーーーーー!!!!」

まさかの発想がかぶる

黒歴史という発想は被りそうだな〜〜〜〜」

とマヤミトくんとのあくんと笑いながら話していましたが、見事に被りました。

それも同じ大学のmtのチームでした。

会津大学生は黒歴史が好きです

思わず笑い合いました。

ちなみに、他のチームとは黒歴史のネタがかぶらなかったです。奇跡かな。

さいごに

懇親会で他の参加者の方とお話をしていたら

黒歴史ブロックチェーン、僕は投票しました!」

という声を結構聞いて嬉しかったです。やっぱり他の人からフィードバックを受けるというのは気持ちがいいです。

ブロックチェーンをフルタイムで働きながらも作ってくれたのあくん

のあくんのひどい彼女イキリに耐えながら完璧なネイティブアプリをつくってくれたマヤミトくん

最後の最後でマヤミトくんがキレながらのあくんに 「は!?!?」 と言っていたのは見ててめちゃくちゃ面白かったです。

二人のおかげでとっても面白いものが作れました。ありがとうございました。

おしらせ

お仕事をください

2019春インターン振り返り ~アカツキさん編~

基本的な情報

  • 参加させていただいたところ
  • インターンの内容
    • ゲーム内仮想通貨管理サービスのサーバー周り
  • 期間
    • 3/11 ~ 3/29 (三週間)
    • 15営業日分

やったこと(細かく)

  • 課金基盤のサーバー、インフラ周りの開発

    • 使った技術
      • Go (サーバー)
      • Terraform (インフラ)
      • GCP (TaskQueue, GAE, Stackdriver)
  • shellscript, yamlファイルのlinterをCircleCIに入れ込む

    • 使った技術
      • CircleCI (CI)
      • shellcheck (linter)
      • yamllint (linter)

はじめに

自己紹介

こんにちは、飛ばすはとバスと申します。この度はアカツキさんで課金基盤のサーバサイドエンジニアとしてインターンをさせていただきました。いつも僕はGoとPythonで色々な物を作っていますが、インターンとして大きなプロダクトの中でGoを書くのはほぼ初めてのインターンになりました。

インターンに参加したきっかけ

僕は会津大学という、東京駅から行くと新幹線とローカル線で3時間ほどかかる山の中の大学で勉強をしています。会津大学は色々と珍しい大学で、公立では珍しいコンピュータ専門の単科大学です。

会津大学では、たまに企業の方々を招いてLT会を開くことがあります。

www.facebook.com

アカツキさんを知ったのは学部2年のときのLT会でした。今回のインターンでメンターをしていただいたsachaosさんがLTをしていて、「面白そうな会社だなぁ」と感じたのが当時の印象です。

Goを書き始めたのは大学三年の夏で、春休みになったしインターンでGo/サーバーの知識を深めたいと思っていたところでした。そのときにちょうどアカツキさんから「サーバーサイド(Go)のインターンに参加しませんか?」という声をかけていただけたので、参加させていただきました。

LT会などで、どのような物を作っているかどのような人たちがいるかというのがある程度わかった状態で参加できるので、安心して業務に携わることができました。

インターンの内容

バックグラウンド

アカツキさんでは、様々なタイトルのゲームを配信しています。その中でも特に大きな役割を持っているのは「課金」の部分です。 お金という大きなものを動かすために、安定性や信頼性が必要になります。 各タイトルで課金の部分を実装してもいいのですが、タイトルごとに課金部分の実装に違いが出てしまうと、いざ障害が出た時などに解決に時間がかかる可能性があります。

課金の機能をマイクロサービスとして切り出すことによってこれを解決しています。今まではアプリごとに作っていた課金周りの機能を基盤としてまとめることで障害の対応や、プラットフォームのストアの仕様のアップデートへの追従などの開発・運用をやりやすくしています。

参加したプロジェクト

マイクロサービス化した課金基盤の開発にジョインさせていただきました。今回の記事では課金基盤の開発についてお話をします。

サービスの裏側

このサービスでは、課金の情報をBigQueryに保存しています。

f:id:flying_hato_bus:20190328135541j:plain

タイトルが大きくなれば、必然的に課金も増え、BigQueryに入ってくる課金のデータも多くなります。

f:id:flying_hato_bus:20190328135630j:plain

BigQueryにデータをinsertする処理はレイテンシが高く、これにリソースを割いてはレスポンスが悪くなります。ここで登場するのがTaskQueueです。

f:id:flying_hato_bus:20190328135745p:plain

タスクキューを使用すると、アプリケーションは、タスクと呼ばれる作業をユーザー リクエストの外で非同期に実行できます。アプリがバックグラウンドで作業を実行する必要がある場合、タスクがタスクキューに追加されます。

cloud.google.com

つまり、処理にコストのかかるinsertをTaskQueueで非同期で処理をすることで、リクエスト内でinsertにかかる時間をなくすことができ、レスポンスの向上ができます。 また、TaskQueueは処理が失敗すると自動でQueueの末尾にTaskを追加し、何回でも再実行されます。これによってデータが闇に葬り去られることもなく、安定してデータを保存することができます。

僕がやったタスク

初日のメンターさんとの1on1で、インターンの中で僕が何をするかを決めました。内容としては、「TaskQueue内のレイテンシとリトライ回数を計測する」というものでした。

f:id:flying_hato_bus:20190328135957j:plain

実現したい理由

理由としては、時間やリトライ回数を計測することでどれくらい処理が重いかということを見たかったため。 TaskQueueに入った時間と、TaskQueueできちんと処理された時間の差分で時間を計測することにしました。

実装

TaskQueueに入っている時間を取得するためには (TaskQueueで処理が成功した時間) - (TaskQueueにそのタスクが入ってきた時間) で取得ができます。

また、リトライ数の取得についてはGAEがタスクをpushする際にヘッダに情報を込めて送ってくるので、これを取得することで可能でした。

ヘッダに込められている情報

  • X-AppEngine-QueueName
    • キューの名前
  • X-AppEngine-TaskName
    • タスクの名前
  • X-AppEngine-TaskRetryCount
    • このタスクが再試行された回数。この試行回数には、インスタンス数不足が原因でタスクが異常終了した試行も含まれる。
  • X-AppEngine-TaskExecutionCount
    • このタスクがこれまでに異常終了した回数。この回数には、インスタンス数不足が原因の失敗は含まれない
  • X-AppEngine-TaskETA
    • タスクの目標実行時間。1970 年 1 月 1 日からの秒数

cloud.google.com

この二つがStackdriver Loggingで見られるようになったので、Terraformを書きました。

TerraformはIaCの一つで、インスタンスなどをコードで管理しようというものです。 これを使って、上で作ったログから数値を拾ってきてログの指標にしたり、値が閾値を超えたらアラートを作成できるようになります。

個人の開発ではなかなか使うものではないですが、最近の流行りとして色々な企業で導入されていたり、色々なサービスがTerraformに対応をし始めたりと注目されていて、僕自身、Terraformに触れてみたいと感じていました。

どちらとも、先日のデプロイで本番環境で走ることになり、とてもいい体験になりました。

インターン中の生活

会津大学生は、夏休みや春休みなど、長期休みになると出稼ぎに東京へ来るのがよくあります。 今回のインターン中に、出稼ぎに来ている同じ大学の人とご飯に行ったり、古くからの友達と飲んだりと楽しい生活を送ることができました。

社員の方にお昼に誘っていただいたり、同じインターン生同士でご飯に行ったりと社内での交流も盛んで、働いていても毎日が楽しいインターンでした。

最後に

普通の大学生では作るor触れられないような大きなサービスの開発を経験して、とても勉強になりました。

3週間という期間の中で多くのことを学ぶことができ、それでいて楽しい毎日を過ごせたような気がします。 インターン期間中にお世話になったメンターのsachaosさん、インターンを調整してくださった人事の方々、同じチームの皆さんなど、多くの方に感謝の気持ちを込め、ここで今回の記事を閉めようと思います。

本当にありがとうございました。

年末の振り返り

どうもみなさまこんばんは、はとバスです。

今私は川崎にある友人宅でRAIZINと無人島生活をローテーションしながら、紅白で椎名林檎ユーミンを見ていたら堀口がベラトールの首を取っていたのを見逃してしまい身悶えしています。

なんかみんな年末の振り返りをしているので、かるーく振り返ります。

インターン関連

春と夏の二回行きました。

春はネオス株式会社さんにお邪魔させて頂き、機械学習系のインターンに参加。

夏は株式会社リクルートさんにお邪魔させていただきました、こちらはGolangによるサーバーサイドのインターンに参加しました。

hatobus.hatenablog.jp

最近年収が一つの単位になった方に「安定の飯インターン」と言われましたが、それ以外にもGolangの大量の知見を得られ、今に至っています。

技術力の低い私をインターンに受け入れていただいた関係者の方々には厚くお礼を申し上げます。

今後の学生生活の中で幅広く使えるような様々な知識を学ぶことができ、最高のインターンでした!

賞を受賞

夏に作った農業とITを繋げるシステム、「SmartAgri」というシステムがあります。

ビニールハウスや農場にESP32で作成したデバイスを設置、温度や湿度をサーバーに送り、AmazonのAlexaを使い情報を取得できるようなシステムです。

  • 農場に置くセンシングデバイスHANIYAMA
  • Golang+MySQLのサーバーサイドアプリ OHJIN
  • アレクサスキルの UKEMOCHI

の3つのOSSによってこのシステムは動いています。

f:id:flying_hato_bus:20181231225928j:plain
SmartAgriのシステム構成図

サーバーとスキルは全てGolangで作成、これも夏インターンで学んだことの復習も兼ねて作成したものでした。

この度、私と農家の方、そして会津にあるIT企業の方の三人で作成したシステムが

というとても栄誉のある2つの賞をいただける運びとなりました。

www.minpo.jp

f:id:flying_hato_bus:20181231230642p:plain
受賞者一覧(福島民報のサイトより引用)

ICTスタートアップ支援センター | 会津産IT技術認定会議 〜 募集案内 | NICT-情報通信研究機構

SmartAgri

一年生の時からずっとtwitterなどに投稿してきた謎の電子工作の花が開いた瞬間かなと思います。

自分の作ったシステムを実際に農家の方に使って頂き「今までのスマホアプリやデバイスにはない利便性」「無限の可能性を感じる」などのお言葉を頂き、とても嬉しかったですし、自分の持てる力をもってして、農家の方々の問題を解決することができるということを知れ、とても有意義なものとなりました。

もう少し細かく知りたい場合は公式サイトがありますのでこちらをどうぞ。

SmartAgri

色々なものを考えるのが増えた

いよいよ大学三年生にもなり、必然的に考え事や思うことが多くなりました。

後輩や自分の進退について考える1年になったかなと思います。

自分の進退

自分の進退としては、学部で就職することを決めました。

自分は進学したいという気持ちがやまやまですが、親の意向 「それ以上勉強して何になるんだというジジババのコメント」 シンプルにお金がない! も相まって就職という形を取らせていただきました。

どうしてももっと勉強したいという気持ちがあるならば、そういうサポートをしていただけるような企業に入り、大学院のほうで勉強しながら働くという道もありますし、自分で勉強ということもできます。

幸いにも、就活の方でいくつかの内定を頂くことができたので最悪の結果は避けられるかなと言う感じです。

個人的には大学で計算機科学を学ぶことができたので、この時代のIT企業のトップクラスのGoogleとかをダメ元で受けてみようかなと思います。

あとGSoCに応募もしたいです。

後輩

後輩のことについては、一年生と一緒に行ったハッカソンが大きいです。

今年の夏の石巻ハッカソンで、今年はマヤミトくんと一ノ瀬くんとで参加しました。

twitter.com

twitter.com

一ノ瀬くんは去年も一緒に参戦した現役高校生です。一方で大学に入ったばかりのマヤミトくんは今回でハッカソン初参戦という感じでした。

blog.github.com

ここでなんとマヤミトくんが所属していたチームが「ヤバイで賞」を受賞、彼自身初めてのハッカソンで、それも技術的に素晴らしいと認められての入賞です。お知り合いのフィッシュさんとの一緒のチームでの受賞でした。

この後のマヤミトくんは外部のLTへの登壇や勉強会への参加というように、怒涛の勢いで成長をしています。

彼のこのような成長や行動を見ていると

「やっぱりハッカソンに連れてきてよかったな」

と心の底から思うことができました。

このような経験や体験により「後輩のためになるような行動をしよう」「後輩に憧れられるような先輩になろう」という気持ちが生まれました。

来年入ってくる学生や、今いる学生の模範となるようなことや、後輩などのサポートをしていけたらなと思います。

改めて 来年の目標

  • 後輩のためになるようなことをする
  • GSoCに応募
  • 日々のアウトプットも忘れない

この3つを念頭に置いて行きていきたいと思います。

最後に

最近Thinkpadを買いました。お金が無いけど頑張って働きます。

それでは、良いお年を。

AzureのFace APIを使って提供目を自動生成

本日の記事はAizu Advent Calendarの15日目の記事になっています。

adventar.org




記事を書いてほしい問題

このアドベントカレンダーを作ったのは僕なんですが

f:id:flying_hato_bus:20181212194915p:plain













みなさん













f:id:flying_hato_bus:20181212200140j:plain

記事書いてなさすぎじゃないですか!?!?!?!???













この問題割と深刻で、半数近くの人がきちんと書いてないです。













f:id:flying_hato_bus:20181212194915p:plain

ちゃんと













f:id:flying_hato_bus:20181212200140j:plain

書いて

本題

最初に飛ばしまくりまくりましたがどうもこんにちは、はとバスです。

f:id:flying_hato_bus:20181212194915p:plain

この画像見飽きましたよね、これ以上は使わないので勘弁してください。

こんにちは、はとバス(twitter: @flying_hato_bus)と申します。

普段僕は意味のわからないツイートをする傍ら、朝と昼と夜にご飯を食べたり、赤べこの首を振らせたりしています。 普段はGolangPythonを使ってサーバーの作成や、研究として機械学習をやったりしています。

赤べこの首を振らせる以外にも、ビニールハウス内の情報をセンサーで取得してAlexaスキルで取ってこれるようなもので新聞社から賞を頂いたりしています。



提供目について

みなさん、"提供目"ってご存知でしょうか?

dic.pixiv.net

提供目とはアニメやドラマなどがCMに入る際、アイキャッチと共に表示される『提 供』の文字が人物の目と被っている現象を指す。

提供目というのは、上にもあるように、色々なシチュエーションと出来事が重なり、目の部分に「提供」の文字が重なるということです。

例です

f:id:flying_hato_bus:20181210143413j:plain
アイカツ!での例

今回はこのように、目の部分にちょうど「提供」の文字が覆いかぶさるような画像を生成してくれるくんを作りました。

github.com

使い方

使い方ですが、必要なのはGolangの実行環境とAzureのFaceAPIキー。Golangのインストールは各自の課題だとして、Azure FaceAPIの有効化について説明します。

Azure FaceAPIの有効化

まず必要なのはAzureのアカウント登録、みなさんが持っているメールアドレスで登録できるので登録しちゃいましょう。ちなみに、今メールアドレスを登録すると20000円分のクレジットが付いてくるので、これを使って有料のプランも自分のおサイフを痛めないで使用することができます。

次にFaceAPIの有効化、アカウント登録した後にAzureのポータルで有効化できます。

AI + machinelearning をクリックして、Faceを選びます。

f:id:flying_hato_bus:20181212211633p:plain

必要な情報を色々入れればデプロイが開始されます。デプロイが終わると、FaceAPIが使えるようになります。

ここでサブスクリプションキーが生成されているので、FaceAPIのコンソールからKeyをクリックし、サブスクリプションキーを確認します。このキーが後々必要になります。

f:id:flying_hato_bus:20181212213212p:plain

githubからレポジトリを持ってくる

go getを使おう

コードの方はgithubで管理しているんですが、git cloneで持ってくるよりはgo getで取得してくる方を推奨しています。

理由なんですが、git cloneは、任意の場所にレポジトリを持ってくることができる一方でgo getではある程度決まった位置にレポジトリを持ってくるという性質からです。

go getをしてレポジトリを持ってきたときには、よっぽどで無い限り

GOPATH/src/github.com/hatobus/Teikyo

に僕のレポジトリがクローンされてきます。git cloneでは、任意の場所にクローンされるので、画像までのパスなどを解決する必要になります。go getを使えば一定の場所にインストールされるのでその心配はいらず、パスの設定などをせずにそのままで動かすことができます。

.envファイルの設定

クローンしてきたファイルの中には.env.sampleというファイルがあると思います。これはサブスクリプションキーなどを管理するためのファイルで、このファイルを.envというファイル名でコピーして、その中に先ほど取得したサブスクリプションキーを記載していきます。

URL=
KEY1=
KEY2=

ファイルの中身はこのようになっていますが、KEY1,2には、さきほど取得したサブスクリプションキーを入れます、URLはリソースを作成した場所で微妙に違いますが以下のようにすればいいでしょう。

URL=https://[location].api.cognitive.microsoft.com/face/v1.0/
KEY1=XXXXXXXXXXXXXXXXXXXX
KEY2=YYYYYYYYYYYYYYYYYYYY

実際に動かしてみる

.envファイルを書き終えればとりあえずできるはずです。

go run server.go

で動かしてみましょう。何もなければサーバーがlocalhostの8080番ポートで動いてくれるはずです。

もし8080が別プロセスなどで使用されているときには、server.goの r.Run(":8080")の部分を任意のポートに置き換えてください。

ポートが使われているかどうかを調べるには

lsof -i:[ポート番号]

で調べられます。

きちんと動いたことを確認してから、リクエストを投げます。リクエストの例です。

curl http://localhost:8080/detect -F "upload[]=@/path/to/picture1.jpg" -F "upload[]=@/path/to/picture2.jpg" -H "multipart/form-data"

このAPIでは複数の画像に対応するためにヘッダをmultipart/form-dataで処理をしています。(このためにちょっとしためんどくさいことになったりしたけど)また、jpeg画像でなければ弾かれてしまうので注意。

処理がきちんとされればpicture/output/output[n].pngに画像が生成されています。

f:id:flying_hato_bus:20181212203646p:plain f:id:flying_hato_bus:20181214192130j:plain

プログラムの解説

ここからは今回のプログラムを解説していきます。とは言っても本当に必要な部分のみになりますが。

画像フォーマットを取得する

画像のフォーマットはjpegのみを受け付けている、ファイルの終わりが.jpgになっているかなどで考えてもいいが、これだと.pngファイルの拡張子だけを.jpgに変更しただけのファイルなどの場合に死んだりする。ちゃんとやるときには、ファイルのバイナリを解析したりするのが良いみたいですが、それをよしなにしてくれるのが image.DecodeConfig

image.DecodeConfigは写真のカラータイプ、フォーマットを返すメソッド。これを使えば画像がjpegなのか、またはそれ以外のフォーマットなのかがわかります。

f, err := file.Open()
defer f.Close()

// 一回DecodeConfigでファイルをいじるとファイルが壊れるために
// 別のbufにコピーをして回避しておく
io.Copy(b, f)

_, format, err := image.DecodeConfig(b)
if err != nil {
    errch[file.Filename] = err.Error()
    b.Reset()
    break
} else if format != "jpeg" {
    errch[file.Filename] = "Filetype must be jpeg"
    b.Reset()
    break
}

画像のフォーマットを取得する部分はここ。ちなみになぜ別のbufにコピーをしているかと言うと、image.DecodeConfigの内部実装にファイルを読み込む部分があるため。一回ファイルが読み込まれているので、あとでファイルの中身を扱おうとした時にEOF errorで落ちてしまう。そのために一度バッファにコピーしておくことでそれを回避しています。

画像をデコードする

FaceAPIに画像を投げるときには、画像をデコードしないといけない、そのためにデコードする処理を挟む。

buf := new(bytes.Buffer)
// どうやらファイルの先頭までシークをしなければいけなかったっぽい
// https://stackoverflow.com/questions/32193395/golang-io-reader-issue-with-jpeg-decode-returning-eof
fstream.Seek(0, 0)

img, err := jpeg.Decode(fstream)
if err != nil {
    // シークしないとunexpected EOFで落ちる
    return buf.Bytes(), err
}

if err = jpeg.Encode(buf, img, nil); err != nil {
    return buf.Bytes(), err
}

ファイルのシーク操作ですが、画像のデータをバッファにコピーした時に、先頭の位置からずれるようです。 そのために、Seek関数を用いてファイルの先頭まで持ってきます。

提供をかぶせる部分の座標を作成

f:id:flying_hato_bus:20181212201214p:plain

Face APIのレスポンスには、顔のパーツの座標を返してきます。目、口、鼻のみならず、眉などの情報を持っています。 Golangは構造体を定義し、それを元にjsonをパースします。返ってくる情報は膨大な量があるのですが、本当に必要な情報だけに変換する処理を噛ませています。

func (fp FaceParts) ToLandmark() *Landmark {
    LM := &Landmark{}

    LM.EyeRight.TopX = fp.FaceLandmarks.EyebrowRightInner.X
    LM.EyeRight.TopY = fp.FaceLandmarks.EyebrowRightInner.Y

    LM.EyeRight.BottomX = fp.FaceLandmarks.EyebrowRightOuter.X
    LM.EyeRight.BottomY = fp.FaceLandmarks.EyeRightBottom.Y

    LM.EyeLeft.TopX = fp.FaceLandmarks.EyebrowLeftOuter.X
    LM.EyeLeft.TopY = fp.FaceLandmarks.EyebrowLeftOuter.Y

    LM.EyeLeft.BottomX = fp.FaceLandmarks.EyebrowLeftInner.X
    LM.EyeLeft.BottomY = fp.FaceLandmarks.EyeLeftBottom.Y

    return LM
}

見て分かると思うんですが、実は提供の字をかぶせているのは眉の情報を元にしています。 これから説明していくんですが、文字だけではわかりづらいと思うので

f:id:flying_hato_bus:20181214193017j:plain

千鳥のノブで説明します。

まず、やりたいこととしてはこういうことにしたい。 目の上にいい感じに乗せてあげたいです。

f:id:flying_hato_bus:20181214193628j:plain

しかし、Face APIは賢いんで、目に関してはこんな感じで情報を返してきます。

f:id:flying_hato_bus:20181214194058j:plain





賢すぎるんじゃあ!!!!!





このまま提供を重ねてしまうと、

f:id:flying_hato_bus:20181214195501j:plain

まあ、うん... 間違いとは言えないけどちょっと違うよね... もっとこう... 目の全体を覆うように...

どうしようかと思った時に、返ってくるのは目の情報だけではないことに気づきました。

そう、眉の情報も使えば良い

f:id:flying_hato_bus:20181214194955j:plain

こう考えれば良いんです。

そういうわけで

提の字の始まり(左上の点) = (左眉の外側の点, 左眉の一番低い点)
提の時の終わり(右下の点) = (左目の内側の点, 左目の一番下の点)

供の字の始まり(左上の点) = (右眉の内側の点, 右眉の一番低い点)
供の時の終わり(右下の点) = (右目の外側の点, 右目の一番下の点)

という4つの点で「提供」の字をかぶせています。

図で示すとこんな感じ

f:id:flying_hato_bus:20181214201623p:plain

さらにこれで画像を書き出すとこんな感じになります。

f:id:flying_hato_bus:20181214201146p:plain

アルゴリズム的にはこんな感じで目のところにかぶせているというものでした。

最後に

これを作ったのが今週の頭くらいで、「作ったよ〜」みたいなノリでtwitterにあげてみました。

ちょっとバズった。

中には僕のガバガバ英文がお気に召してくれた方がおり

みんなの心温めるコンテンツレーベルになれたかなと思います。

ちなみにこれのライセンスは SUSHI-WARE なので、何か使いたいときがあれば僕に寿司をおごってください。

github.com

参考にさせていただいたサイト

画像をリサイズする

[http://dempatow.hatenablog.com/entry/2016/11/17/画像をリサイズしてDBへ保存する/golang:embed:cite]

Seekしないと落ちる問題

stackoverflow.com

デコードした後にファイルがぶっ壊れる問題

suguru03.hatenablog.com

以上です、悪ふざけにお付き合い頂きありがとうございました。

go-xormを使ってスキーマからstructの自動生成

Golangは静的型付け言語なのでjsonをパースするときとかにはけっこう骨が折れる。

何行もstructを書かなくてはいけないのは結構めんどくさくて、JSON-to-Goとかでjson用のstructを自動生成して書きがち。

DBとかのスキーマも同じで、structの後ろの属性等で色々と設定しなくてはいけないことが多々ある。

別に 俺は全部手書きでやってやらあ!!! という人はいいんですが、僕はめんどくさがり屋なので色々と自動生成してくれる君を使うことが多い。

今回は、そのようなスキーマからstructを自動生成してくれるものの使い方を自分のメモ代わりに書く。

使うもの

go-xormのコマンドラインツールを使う。

xormはGolangのORMモデルの一つで、エウレカさんが作った、マッチングアプリのペアーズなどでも実際に使われているある程度メジャーなもの。

今回はコマンドラインツールの方を使う。

インストール

$ go get github.com/go-xorm/cmd/xorm

これで基本はOK。

もし以前にgo-xormを入れていて、

 cannot use "github.com/go-xorm/cmd/xorm/vendor/github.com/go-xorm/core".LOG_UNKNOWN (type "github.com/go-xorm/cmd/xorm/vendor/github.com/go-xorm/core".LogLevel) as type "github.com/go-xorm/core".LogLevel in argument to engine.Logger().SetLevel

みたいなエラーが出た際には、

cmd/xorm/vendor/github.com/go-xorm/

を消して、またインストールしなおせば行けるはず。

go-xormでの同様のissue

入ったら後はやるだけ。

なお、対応しているDBは

の5種類のみ、個人的に使っているのはmysqlのみなのでいいかなという感じ。

ちなみに、Golang以外にもC++に対応している模様。

実際に使う。

使う際にはテンプレートファイルをコピーしてくる。

プロジェクトルートとかで

$ cp -r $GOPATH/src/github.com/go-xorm/cmd/xorm/templates/goxorm/ ./xorm-template

上記のコマンドを打ち、テンプレートファイルを手元に持ってくる。

テンプレートファイルから自動生成してくれるっぽい。

mysqlでの例

mysqlをローカルホストの3306で動かしていて、ユーザー名 root パスワードpasswordにしている時に、hogedbのスキーマのモデルを得るは以下のようにする。

xorm reverse mysql "root:password@tcp(localhost:3306)/hogedb" xorm-template

これでディレクトリ直下に models/hogedb.goというファイルが生成されているはず。