rebaseを使ってgitのツリーをシンプルにする

複数人で同一のリポジトリを使って開発していると、以下のようなツリーの状態になることが多いかと思います。

f:id:hapoon:20171102132305p:plain

ラインが入り乱れており、かなり見づらくなってしまってます。

上記の例だと、5人がそれぞれ同時期に1ブランチしか使わない想定のツリーですが、実際には開発メンバーが5人以上いたり、1人が複数案件抱えていて2ブランチ以上同時に使ったりすると、さらにツリーが見づらくなってしまいます。

rebaseを使うことによりシンプルなツリーにすることができるようになります。

細かいコミットをrebaseでまとめる

細かいコミットは git rebase -i を使って意味のある単位でコミットをまとめてしまうと良いです。
問題があったときにrevertし易い単位にしておくと楽です。

git rebase -i HEAD~2

f:id:hapoon:20171102162547p:plain
の赤枠で囲まれた部分をまとめることができます。

ブランチにmasterをマージする際にrebaseを使用する

Pull Requestを作成した際にmasterとconflictが生じてしまった際に一度masterを取り込んでからconflictを解消しますが、その際にgit mergeではなくgit rebaseを使ってmasterを取り込みます。

git rebase master

f:id:hapoon:20171102162703p:plain
の赤枠で囲まれた部分をなくすことができます。

注意点

ブランチにmasterをrebaseでマージする際、既に一度プッシュ済みのブランチだと通常のプッシュだと失敗するので git push --force-with-lease でプッシュしてください。
--force,-fだと複数人で同一ブランチを使って開発していた際に他の人が直近にプッシュした内容を消失させてしまう可能性があるので--force-with-leaseを使いましょう。

結果

上記の2点を心がけて、上記のツリーを整理すると
f:id:hapoon:20171102175037p:plain
ここまでシンプルなツリーとなる。

まとめ

  1. 細かいコミットをrebaseでまとめる
  2. ブランチにmasterをマージする際にrebaseを使用する
続きを読む

gRPCとは何か?

gRPCと英語の勉強を兼ねて
grpc.io
を翻訳。

This document introduces you to gRPC and protocol buffers. gRPC can use protocol buffers as both its IDL and as its underlying message interchange format. If you’re new to gRPC and/or protocol buffers, read this! If you just want to dive in and see gRPC in action first, see our Quick Starts.

このドキュメントでは、gRPCとプロトコルバッファについて紹介します。
gRPCは、プロトコルバッファをIDL(インターフェース定義言語)と、それによって生成されるメッセージ交換フォーマットの両方として使用できます。
gRPCとプロトコルバッファの両方もしくはどちらかを初めて使う方は本ドキュメントを読んでください!
まずはgRPCを見てみたいと思ったら、クイックスタートをご覧ください。

概要

In gRPC a client application can directly call methods on a server application on a different machine as if it was a local object, making it easier for you to create distributed applications and services. As in many RPC systems, gRPC is based around the idea of defining a service, specifying the methods that can be called remotely with their parameters and return types. On the server side, the server implements this interface and runs a gRPC server to handle client calls. On the client side, the client has a stub (referred to as just a client in some languages) that provides the same methods as the server.

gRPCでは、クライアントアプリケーションは、異なるマシン上のサーバーアプリケーション上のメソッドをローカルオブジェクトであるかのように直接呼び出すことができ、分散アプリケーションやサービスを簡単に作成できます。
多くのRPCシステムと同様に、gRPCはサービスを定義し、そのパラメータと戻り値の型でリモートで呼び出せるメソッドを指定するという考え方に基づいています。
サーバー側では、このインターフェースを実装し、gRPCサーバーを実行してクライアント呼び出しを処理します。
クライアント側では、サーバと同じメソッドを提供するスタブ(いくつかの言語では単にクライアントと呼ばれる)を持ちます。

f:id:hapoon:20170928160006p:plain
(from What is gRPC?)

gRPC clients and servers can run and talk to each other in a variety of environments - from servers inside Google to your own desktop - and can be written in any of gRPC’s supported languages. So, for example, you can easily create a gRPC server in Java with clients in Go, Python, or Ruby. In addition, the latest Google APIs will have gRPC versions of their interfaces, letting you easily build Google functionality into your applications.

gRPCのクライアントとサーバーはさまざまな環境(Google内のサーバーから各自のデスクトップに至るまで)で動作し、お互いに通信することができ、gRPCがサポートしている言語で書くことができます。
たとえば、gRPCサーバーはJavaで、クライアントはGo、PythonRubyのような構成を簡単に作成できます。
さらに、最新のGoogle APIではgRPCバージョンのインターフェースが用意されており、アプリケーションにGoogleの機能を簡単に組み込むことができます。

プロトコルバッファでの作業

By default gRPC uses protocol buffers, Google’s mature open source mechanism for serializing structured data (although it can be used with other data formats such as JSON). Here’s a quick intro to how it works. If you’re already familiar with protocol buffers, feel free to skip ahead to the next section.

The first step when working with protocol buffers is to define the structure for the data you want to serialize in a proto file: this is an ordinary text file with a .proto extension. Protocol buffer data is structured as messages, where each message is a small logical record of information containing a series of name-value pairs called fields. Here’s a simple example:

デフォルトでは、gRPCは構造化されたデータをシリアル化するためのGoogleの成熟したオープンソースメカニズムであるプロトコルバッファを使用します。(JSONなどの他のデータフォーマットでも使用できます)
ここではどのように動作するかを簡単に紹介します。
すでにプロトコルバッファに精通している場合は、次のセクションに進んでください。

プロトコルバッファで作業する場合の最初の手順は、protoファイル(.proto拡張子を持つ中身はテキストファイル)でシリアル化するデータの構造を定義することです。
プロトコルバッファデータはメッセージとして構成され、各メッセージはフィールドと呼ばれる一連の名前と値のペアを含む情報の小さな論理レコードです。
ここに簡単な例があります:

message Person {
  string name = 1;
  int32 id = 2;
  bool has_ponycopter = 3;
}

Then, once you’ve specified your data structures, you use the protocol buffer compiler protoc to generate data access classes in your preferred language(s) from your proto definition. These provide simple accessors for each field (like name() and set_name()) as well as methods to serialize/parse the whole structure to/from raw bytes – so, for instance, if your chosen language is C++, running the compiler on the above example will generate a class called Person. You can then use this class in your application to populate, serialize, and retrieve Person protocol buffer messages.

データ構造を指定したら、プロトコルバッファコンパイラprotocを使用して、プロト定義からあなたの選んだ言語でデータアクセスクラスを生成します。
データアクセスクラスは、各フィールドの簡単なアクセサ(name()やset_name()のような)を提供するだけでなく、全構造体をバイト情報にシリアライズするためのメソッドやバイト情報から構造を解析するためのメソッドを提供します。
たとえば、選択した言語がC ++で、上記の例に対してコンパイラを実行するとPersonというクラスが生成されます。
このクラスをアプリケーションで使用して、Personプロトコル・バッファー・メッセージの取り込み、シリアル化、取り出しができます。

As you’ll see in more detail in our examples, you define gRPC services in ordinary proto files, with RPC method parameters and return types specified as protocol buffer messages:

例で詳しく説明すると、通常のprotoファイルでgRPCサービスを定義し、RPCメソッドのパラメータと戻り値の型にはプロトコルバッファのメッセージを指定します。

// The greeter service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

gRPC also uses protoc with a special gRPC plugin to generate code from your proto file. However, with the gRPC plugin, you get generated gRPC client and server code, as well as the regular protocol buffer code for populating, serializing, and retrieving your message types. We’ll look at this example in more detail below.

gRPCも、protoファイルからコードを生成するために特別なgRPCプラグインとともにprotocを使います。
gRPCプラグインを使用すると、通常のプロトコルバッファのコードとともに、gRPCのクライアントとサーバーのコードが生成されます。
この例をさらに詳しく見ていきます。

You can find out lots more about protocol buffers in the Protocol Buffers documentation, and find out how to get and install protoc with gRPC plugins in your chosen language’s Quickstart.

プロトコルバッファドキュメントプロトコルバッファに関するより詳細を知ることができ、選択した言語のQuickstartでgRPCプラグインを含めprotocのインストール方法を知ることができます。

While protocol buffers have been available for open source users for some time, our examples use a new flavor of protocol buffers called proto3, which has a slightly simplified syntax, some useful new features, and supports lots more languages. This is currently available in Java, C++, Python, Objective-C, C#, a lite-runtime (Android Java), Ruby, and JavaScript from the protocol buffers Github repo, as well as a Go language generator from the golang/protobuf Github repo, with more languages in development. You can find out more in the proto3 language guide and the reference documentation for each language (where available), and see the major differences from the current default version in the release notes. Even more proto3 documentation is coming soon.

しばらくの間、オープンソースのユーザにはプロトコルバッファが提供されていましたが、ここではproto3という新しいプロトコルバッファを使用しています。
proto3は構文がやや簡略化され、便利な新機能がいくつか追加され、より多くの言語をサポートしています。
現在、プロトコルバッファのGithubリポジトリからJava、C ++、PythonObjective-C、C#、Lite-Runtime(Android Java)、RubyJavaScriptで使用できます。
またgolang/protobufのGithubリポジトリではGo言語用のジェネレータも使用できます。
その他の多くの言語も開発中です。
proto3の言語ガイドと(使用可能な)各言語のリファレンスドキュメントを見ればより多くのことが分かります。
現行のデフォルトバージョンとの主な相違点はリリースノートを参照してください。
さらに多くのproto3のドキュメントがまもなく公開予定です。

In general, while you can use proto2 (the current default protocol buffers version), we recommend that you use proto3 with gRPC as it lets you use the full range of gRPC-supported languages, as well as avoiding compatibility issues with proto2 clients talking to proto3 servers and vice versa.

一般的にproto2(現在のデフォルトのプロトコルバッファバージョン)は使用できますが、proto3とgRPCを使用することをお勧めします。
これにより、gRPCがサポートしているすべての言語を使用できるだけでなく、proto2クライアントとproto3サーバーの互換性(その逆も)の問題も回避することもできます。

golang.tokyo #7に参加してきました

techplay.jp

に参加してきました。

会場は先月dots.(ドッツ)から名称変更されたTECH PLAY SHIBUYAでした。
techplay.jp
久しぶりに来ましたが、相変わらずお洒落な内装。

今回のトークテーマは「本番運用されている自社パッケージ紹介」です。

パーソルキャリアさん(元インテリジェンスさん、7/1に商号変更)によるお酒とピザの提供があり、お酒を飲みながらLTを楽しんだり、休憩時間にピザを食べられたりと快適でした。

LT

スポンサー枠(パーソルキャリア 吉元 裕人)

MIIDASの独自パッケージ ありがちなやつと珍しいやつ

MIIDASという転職支援サービスのWeb側の実装をHHVM/HackからGoへ移行中。
miidas.jp
Go移行開発中に以下のような独自パッケージを作成したとのこと

ありがちなもの

  • 曜日系 - 祝日、n日前、日本語の曜日を返す
  • ログ
  • 配列処理 - スライスの分割
  • 文字列処理 - 半角カナ -> 全角カナ、全角英数 -> 半角英数

珍しめなもの

  • DBからgorm用のモデルを生成

DBFluteFuelPHPのfromdbのような機能
コマンド一発で生成してくれて便利

  • HHVM(PHP)のセッションを読み込んでGoの構造体に取り込む

クッキーに出力しているFuelPHPのロジックをGo化
Cookie <-> セッション <-> Go構造体

  • Goの定数からJS/Swift/Kotlinのクラスを生成

Goで定義した定数をgo generateで読み込み、テンプレートを生成する
f:id:hapoon:20170704112754j:plain
f:id:hapoon:20170704112817j:plain

LT1(榊原 宏祐)

Go言語でffmpegのラッパーを作った話

Befyという女性向けエステアプリを最近公開し、その中で正しいスキンケア方法を動画で紹介する機能がある。

f:id:hapoon:20170704113655j:plain
mp4からHLSへの変換はAmazon Elastic Transcoderを使っても良かったが、作り直しが頻繁に起こるのでコスト削減の為、手作業で行っている。
ffmpegは動画変換の際のパラメータ設定がコマンドライン引数で行うので見づらい&頻繁に使う設定は設定ファイルとして残しておきたいということでツール化。
Web上での記事が多い&クロスコンパイルで別環境でも動作させることができる点からGo言語で開発することを決定。

CLIツールを作成するにあたり下記のパッケージを使用。
github.com
github.com

ツール化することにより、コスト削減ができ、設定ファイルに設定を残せるので使いやすくなった。

LT2(yudppp)

外部のAPIを叩くときの話

お天気APIのような外部APIを実行して返ってきたJSONレスポンスからGo構造体を生成するツールを作成。

スライドはこちら↓
blog.yudppp.com

作成したパッケージはこちら↓
github.com

LT3(Yusuke komatsu)

GoとCouchbaseでmicroservicesを作るには?

labstack/echoを使用していたが、不満があったので自前でgo-shosa/shosaを作成。
MySQLのデータをCouchbaseに移行する際にNullableな型判定をする為にusk81/genericを作成。

スライドはこちら↓

www.slideshare.net

作成したパッケージはこちら↓
github.com
github.com

LT4(Takuma Morikawa)

水平・垂直分割に対応したパッケージとしてevalphobia/wizardを作成。
現在はgo-xorm/xormのみサポート。

作成したパッケージはこちら↓
github.com

LT中に使ってて会場で話題になってたリモコンはこちら↓
amzn.to

LT5(Akira Chiku)

PostgreSQLデータベースからデータモデルを生成するパッケージとしてachiku/dgwを作成。
knq/xoを参考にしつつ、複合主キーやカスタムテンプレートに対応。

スライドはこちら↓
speakerdeck.com

作成したパッケージはこちら↓
github.com

LT6

スピーカー不在だったようでスキップ

LT7(渋川 よしき)

C++ビルド支援ツール qtpm
社内GUIツールを作成するのにQtを使用しているが、パッケージマネージャ・ビルドシステムがいろいろつらいのでGoっぽいパッケージマネージャをGoで作成。

スライドはこちら↓

www.slideshare.net

作成したパッケージはこちら↓
github.com

LT8(@dxhuy,@huydx)

HTTP APIクライアントの独自パッケージの話

  • HTTP ClientとHTTP Transportを分割
  • RESTリソースをサービスに分割
  • 複数サービスに対してひとつのクライアントを使いまわせるようにしている

LT9

急遽追加になったLT

HTTPテストからドキュメントを生成するパッケージmercari/go-httpdocと構造体の任意のフィールドにアクセスできるパッケージtenntenn/gpath

作成したパッケージはこちら↓
github.com
github.com

まとめ

データモデルあたりはどこも苦労している印象。
うちも結局自前で作っちゃったし。

ちょうど今動画生成まわりでパッケージを作成中だったので、開催がもう少し後ろだったら紹介したかったな。

AWS Summit Tokyo 2017に参加してきました

5/31〜6/2に行われたAWS Summit Tokyo 2017に参加してきました。

会場は品川のグランドプリンスホテル新高輪
www.princehotels.co.jp

同日にAWS Dev Day Tokyo 2017も近くの品川プリンスホテルアネックスタワーで開催。
www.princehotels.co.jp

参加してきたセッションをざっくり説明すると

最新 IoT デザインパターン 〜AWS IoT と AWS Greengrass を用いた構築パターン〜

http://www.awssummit.tokyo/summit/index.html#D3T2-1
AWS IoT, GreengrassおよびIoTデザインパターンに関してのお話。
AWS IoTのルールエンジンの機能説明とデータ収集・活用のユースケースとしてバッチデータストアパターン、QoS2エミュレートパターン、リアルタイム異常検知パターン、ファームアップパターン、インテリジェントシャドウパターン、テンポラリトークン取得パターンを紹介。
データ収集のアンチパターンやデータ送受信におけるIoT,Kinesis,S3の使い分けも紹介。
Greengrassの機能紹介とデータアグリゲーションパターン、センシティブ情報マスキングパターンの紹介。

DevSecOps on AWS - Policy in Code

http://www.awssummit.tokyo/devday/index.html#D3T7-2
devsecopsに関するお話。
Security Automation,Proactive Monitoring Lifecycle,Security at Scaleについて紹介。

Amazon Redshift テーブル設計詳細ガイド –分散スタイルとソートキーの決定方法–

http://www.awssummit.tokyo/summit/index.html#D3T1-5
クエリー性能を向上させる為のソートキーの選択基準や最適な分散スタイルの選択基準について紹介。

Amazon EC2 Systems Managerによるハイブリッド環境の管理

http://www.awssummit.tokyo/summit/index.html#D3T3-6
System Managerの機能や料金紹介。

AWS Cloud Adoption Framework で作成するクラウド導入ロードマップ

http://www.awssummit.tokyo/summit/index.html#D4T1-1
クラウド導入にあたり各ステークホルダーに必要なスキルとプロセスを整理する為のフレームワーク
Cloud Adoption FrameworkとCloud Discovery Workshop(CDW)を紹介。

AWSにおけるマルチアカウント管理の手法とベストプラクティス

http://www.awssummit.tokyo/summit/index.html#D4T2-2
マルチアカウントを採用する際の利用ケースとIAMロールによるクロスアカウントアクセス方法、マルチアカウントの一元管理に役立つAWS Organizationsの紹介とベストプラクティスの紹介。

サーバレスで王道 Web フレームワークを使う方法

http://www.awssummit.tokyo/devday/index.html#D4T7-3
サーバレスでのフレームワークの中でExpress.js on ServerlessとSprint on Serverlessの紹介を中心に、CodeStarも軽く紹介。
AWS CodeStar – アプリケーションをすばやく開発および構築して AWS にデプロイ

もう悩まない!AWS SAM で始めるサーバーレスアプリケーション開発

http://www.awssummit.tokyo/devday/index.html#D4T7-5
Serverless Application Model(SAM)の紹介。

AWS マネージドサービスで実現する CI/CD パイプライン

http://www.awssummit.tokyo/summit/index.html#D4T2-6
CodeStarの機能とAWS上で構築する継続的デリバリー構築の紹介。

という感じです。

IoT,DevSecOps,サーバーレスとどれも面白いものでした。
後日、自分でも試した上で記事を書こうかなと思ってます。


各セッションの間は20分間の休憩時間なのですが、AWS Summitの会場とAWS Dev Dayの会場とがそこそこ距離があり、20分での移動がなかなか厳しいものでした。

Video Intelligence APIのデモを試してみた

Video Intelligence API面白そうだったのでさっそくいくつか動画をアップして試してみました。

cloud.google.com

まずは先日に見に行ったイルミネーションの動画をCloud Storageにアップして、Video Intelligence APIで解析させてみました。

まずは全体のラベルから

f:id:hapoon:20170310161742p:plain

うん、まぁ間違ってない。
ほぼイルミネーションしか映ってないからね。

次にシーンが切り替わるごとのショットラベル。

f:id:hapoon:20170310162214p:plain

f:id:hapoon:20170310162240p:plain

これだけだと微妙なので、他の動画も試してみました。

渋谷のスクランブル交差点の動画。

f:id:hapoon:20170310173115p:plain

流石にここからじゃ人だとは認識できない様子。
右下に映る建物や市街地だということは認識できている。

f:id:hapoon:20170310173317p:plain

信号が変わって、車が映るようになると、ちゃんと車を認識できている。

f:id:hapoon:20170310173444p:plain

手前に映る自転車はしっかり認識できている。
奥の電車は残念ながら、輸送手段の乗り物としか認識できてない。

f:id:hapoon:20170310173657p:plain

少し後のこちらのシーンだとしっかり電車であることを認識できている。

f:id:hapoon:20170310173820p:plain

キュウリ、パプリカ、ズッキーニが認識できてる。


最後にAPIについて。

まず
ボディに

{
  "inputUri": "gs://hapoon-sample-1/movie/sample.mp4",
  "features": [
    "LABEL_DETECTION",
    "SHOT_CHANGE_DETECTION"
  ]
}

をつけて

https://videointelligence.googleapis.com/v1beta1/videos:annotate?key=YOUR_API_KEY_HERE

にリクエストをすると、

{
  "name": "asia-east1.4905105012973219553"
}

という形でレスポンスが返ってくるらしい。

レスポンスで返ってきた値を利用して

https://videointelligence.googleapis.com/v1/operations/asia-east1.4905105012973219553?key=YOUR_API_KEY_HERE

にリクエストを送ると、以下のようなレスポンスが返ってくる。

まだドキュメントが見れないので、確かなことはわからないけど、doneがtrueになったら解析完了ってことなのかな。
おそらくmetadata.annotationProgressで進行度が分かるからクライアント側の表示に使うことを想定している感じ。
そして肝心のラベルはresponse.annotationResultsに羅列されている。
全体のラベルかショットのラベルかはlevelで判定。
ショットラベルは開始時間と終了時間のオフセットがあって、それでどのショットのラベルかを判別する感じ。
ショットがいくつかなどの情報はshotAnnotationsに格納されている。

{
  "name": "asia-east1.4905105012973219553",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.videointelligence.v1beta1.AnnotateVideoProgress",
    "annotationProgress": [
      {
        "inputUri": "/hapoon-sample-1/movie/sample.mp4",
        "progressPercent": 100,
        "startTime": "2017-03-10T06:58:12.237347Z",
        "updateTime": "2017-03-10T06:58:51.115711Z"
      },
      {
        "inputUri": "/hapoon-sample-1/movie/sample.mp4",
        "progressPercent": 100,
        "startTime": "2017-03-10T06:58:12.237347Z",
        "updateTime": "2017-03-10T06:58:42.977887Z"
      }
    ]
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.videointelligence.v1beta1.AnnotateVideoResponse",
    "annotationResults": [
      {
        "inputUri": "/hapoon-sample-1/movie/sample.mp4",
        "labelAnnotations": [
          {
            "description": "Christmas Day",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.5487966,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.6992136,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.6354697,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Christmas decoration",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.7745933,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.839413,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.7971116,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Christmas lights",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.9219488,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.8843523,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.93007386,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "35266722",
                  "endTimeOffset": "62900063"
                },
                "confidence": 0.8422565,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "62933344",
                  "endTimeOffset": "85733388"
                },
                "confidence": 0.66912746,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.8855732,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Christmas ornament",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.44660938,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Christmas tree",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.72451514,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.5763006,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Cityscape",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.4499087,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Fir",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.45190096,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Glitter",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.40361568,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "35266722",
                  "endTimeOffset": "62900063"
                },
                "confidence": 0.40361568,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "62933344",
                  "endTimeOffset": "85733388"
                },
                "confidence": 0.58243823,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Landscape lighting",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.66704077,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.46998933,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.4731566,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Light",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.83027405,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.62223655,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.83027405,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "35266722",
                  "endTimeOffset": "62900063"
                },
                "confidence": 0.75799024,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "62933344",
                  "endTimeOffset": "85733388"
                },
                "confidence": 0.62978107,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.4503784,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Light-emitting diode",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.47539055,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.47539055,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Lighting",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.85093576,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.7995617,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.8676851,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "35266722",
                  "endTimeOffset": "62900063"
                },
                "confidence": 0.7995617,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "62933344",
                  "endTimeOffset": "85733388"
                },
                "confidence": 0.7142249,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.683655,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Metropolis",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.45952943,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Neon",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.56372297,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.48607495,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.6263982,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "35266722",
                  "endTimeOffset": "62900063"
                },
                "confidence": 0.56372297,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Night",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.7992863,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.86590075,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.80786514,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "35266722",
                  "endTimeOffset": "62900063"
                },
                "confidence": 0.49436265,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.8034352,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Psychedelic art",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "62933344",
                  "endTimeOffset": "85733388"
                },
                "confidence": 0.51594055,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Tourism",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "startTimeOffset": "-1",
                  "endTimeOffset": "-1"
                },
                "confidence": 0.52742225,
                "level": "VIDEO_LEVEL"
              },
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.67389864,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "14766651",
                  "endTimeOffset": "35233313"
                },
                "confidence": 0.63670295,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.49774462,
                "level": "SHOT_LEVEL"
              }
            ]
          },
          {
            "description": "Tourist destination",
            "languageCode": "en-us",
            "locations": [
              {
                "segment": {
                  "endTimeOffset": "14733370"
                },
                "confidence": 0.4517945,
                "level": "SHOT_LEVEL"
              },
              {
                "segment": {
                  "startTimeOffset": "85766669",
                  "endTimeOffset": "90333334"
                },
                "confidence": 0.4342352,
                "level": "SHOT_LEVEL"
              }
            ]
          }
        ],
        "shotAnnotations": [
          {
            "endTimeOffset": "14733370"
          },
          {
            "startTimeOffset": "14766651",
            "endTimeOffset": "35233313"
          },
          {
            "startTimeOffset": "35266722",
            "endTimeOffset": "62900063"
          },
          {
            "startTimeOffset": "62933344",
            "endTimeOffset": "85733388"
          },
          {
            "startTimeOffset": "85766669",
            "endTimeOffset": "90333334"
          }
        ]
      }
    ]
  }
}

プライベートβのAPIが触れるようになったら組み込んで何か作ってみたいところ。

gsutilでのCloud Storageの操作メモ

久しぶりのGCP

gsutilでCloud Storageの操作方法のメモ。

バケットの一覧確認

% gsutil ls gs://
gs://hapoon-sample-0/
gs://hapoon-sample-1/

バケットの作成

バケット名だけ指定

% gsutil mb gs://hapoon-sample-1
Creating gs://hapoon-sample-1/...

% gsutil ls -L -b gs://hapoon-sample-1
gs://hapoon-sample-1/ :
	Storage class:			STANDARD
	Location constraint:		US
	Versioning enabled:		None
	Logging configuration:		None
	Website configuration:		None
	CORS configuration: 		None
	Lifecycle configuration:	None
	Time created:			Fri, 10 Mar 2017 03:45:02 GMT
	Time updated:			Fri, 10 Mar 2017 03:45:02 GMT
	ACL: 〜
	Default ACL: 〜

クラスとロケーションの指定なしだと、クラスはSTANDARD、ロケーションはUSになる。

https://cloud.google.com/storage/docs/storage-classesのドキュメントによると、

注: API でバケットを作成し、デフォルトのストレージ クラスを指定しないと、バケットは Standard Storage クラスに割り当てられます。このクラスは、バケットの場所設定に応じて Multi-Regional Storage または Regional Storage と同等になります。

とある。

ストレージクラスを指定

% gsutil mb -c nearline gs://hapoon-sample-2
Creating gs://hapoon-sample-2/...

% gsutil ls -L -b gs://hapoon-sample-2
gs://hapoon-sample-2/ :
	Storage class:			NEARLINE
	Location constraint:		US

指定できるストレージクラスはhttps://cloud.google.com/storage/docs/storage-classesを参照。

ちなみに regional を指定した時は、ロケーションを指定しないとエラーになります。

% gsutil mb -c regional gs://hapoon-sample-2
Creating gs://hapoon-sample-2/...
BadRequestException: 400 The combination of locationConstraint and storageClass you provided is not supported for your project

指定できるリージョンはhttps://cloud.google.com/storage/docs/bucket-locationsのリージョンのロケーションを参照。

ロケーションを指定

マルチリージョンを指定した場合
% gsutil mb -l asia gs://hapoon-sample-1
Creating gs://hapoon-sample-1/...

% gsutil ls -L -b gs://hapoon-sample-1
gs://hapoon-sample-1/ :
	Storage class:			STANDARD
	Location constraint:		ASIA
	Versioning enabled:		None
	Logging configuration:		None
	Website configuration:		None
	CORS configuration: 		None
	Lifecycle configuration:	None

ストレージクラスはSTANDARDと表示されますが、これは内部的にはmulti_regionalです。

リージョンを指定した場合
% gsutil mb -l asia-east1 gs://hapoon-sample-1
Creating gs://hapoon-sample-1/...

% gsutil ls -L -b gs://hapoon-sample-1
gs://hapoon-sample-1/ :
	Storage class:			STANDARD
	Location constraint:		ASIA-EAST1
	Versioning enabled:		None
	Logging configuration:		None
	Website configuration:		None
	CORS configuration: 		None
	Lifecycle configuration:	None

こちらのストレージクラスは内部的にregionalです。

ファイルの転送

コピー

% gsutil cp sample.txt gs://hapoon-sample-1/dir1/
Copying file://sample.txt [Content-Type=text/plain]...
/ [1 files][   16.0 B/   16.0 B]
Operation completed over 1 objects/16.0 B.

% gsutil ls gs://hapoon-sample-1/dir1
gs://hapoon-sample-1/dir1/sample.txt

移動

mvコマンド同様に元のファイルはなくなります。

% gsutil mv sample.txt gs://hapoon-sample-1/dir2/
Copying file://sample.txt [Content-Type=text/plain]...
Removing file://sample.txt... B]

Operation completed over 1 objects/16.0 B.

% gsutil ls gs://hapoon-sample-1/dir2/
gs://hapoon-sample-1/dir2/sample.txt

バケットの使用量確認

% gsutil du -ch gs://hapoon-sample-1
16 B        gs://hapoon-sample-1/dir1/sample.txt
16 B        gs://hapoon-sample-1/dir1/
16 B        gs://hapoon-sample-1/dir2/sample.txt
16 B        gs://hapoon-sample-1/dir2/
32 B        total

トータルだけでよければこちらでも。

% gsutil du -sh gs://hapoon-sample-1
48 B        gs://hapoon-sample-1

ファイルの確認

% gsutil cat gs://hapoon-sample-1/dir1/sample.txt
This is sample.

ファイルの情報

% gsutil ls -L gs://hapoon-sample-1/dir1/sample.txt
gs://hapoon-sample-1/dir1/sample.txt:
    Creation time:          Fri, 10 Mar 2017 05:16:37 GMT
    Update time:            Fri, 10 Mar 2017 05:16:37 GMT
    Storage class:          STANDARD
    Content-Language:       en
    Content-Length:         16
    Content-Type:           text/plain
    Hash (crc32c):          S+gJjg==
    Hash (md5):             0oY8xUSLSc/Qq0ncsJNqiQ==
    ETag:                   CKrjkrqXy9ICEAE=
    Generation:             1489122997088682
    Metageneration:         1

バケットの削除

% gsutil rb gs://hapoon-sample-1
Removing gs://hapoon-sample-1/...

ちなみにバケット内が空でないと

% gsutil rb gs://hapoon-sample-1
Removing gs://hapoon-sample-1/...
NotEmptyException: 409 BucketNotEmpty (hapoon-sample-1)

とエラーが出る。

その場合は

% gsutil rm -r gs://hapoon-sample-1/
Removing gs://hapoon-sample-1/dir1/sample.txt#1489122997088682...
Removing gs://hapoon-sample-1/dir1/sample2.txt#1489124267892632...
Removing gs://hapoon-sample-1/dir2/sample.txt#1489123188704896...
/ [3 objects]
Operation completed over 3 objects.
Removing gs://hapoon-sample-1/...

で中身のファイルごと削除する。


手入力がめんどくさい。
aws-cliみたいに補完機能ってないのかな?

やる気を引き出してみた

Qiitaで下の記事を見て、面白そうだったので、OpenAim を使ってみました。

qiita.com

機能はシンプル。

今日、達成したい目標を入力するだけ。

f:id:hapoon:20170215235235p:plain

達成したら、チェックボックスにチェックを入れる。

すると、経験値をもらえてレベルアップするというもの。

f:id:hapoon:20170215235603p:plain

毎日ひとつずつでも目標を達成していければ、成長を実感できて充実しますね。