textlintを使ってAWS用語をチェックしてみる #aws #textlint #golang

最近のアップデート

Cloud Automator のアップデートでログイン中の操作画面にマニュアルのリンクが表示されるようになりました。

blog.serverworks.co.jp

もちろんマニュアルだけでも閲覧できますので、気になった方は無料トライアルでCloud Automator を試してみてください。

Cloud Automator – 株式会社サーバーワークス サポートページ
https://support.serverworks.co.jp/hc/ja/categories/115001305127

cloudautomator.com

ドキュメントを充実させるには

ドキュメントを充実させていくには、地道に書いていくしかないわけで・・・Cloud Automator についても開発メンバーで分担しながら作っています。

その際ちょっと気になってくるのが表記のゆれです。 これは多人数でなくても1人で書いていても、書いている時期が異なると表現が異なるとかありますしね。

細かい言い回しならそこまで気にする必要もなさそうなのですが、Cloud Automator の使い方や機能を説明していくと当然ながらAWSについても言及する必要が出てきます。

AWS用語表記のゆれが出てしまうとユーザーは気になりますし、検索する場合にヒットせず困ることも出てきそうです。

そこでAWSの公式ドキュメントに載っている日本語のAWS用語を利用して、表記のゆれをチェック行ってみます。

アマゾン ウェブ サービス : AWS の用語集
https://docs.aws.amazon.com/ja_jp/general/latest/gr/glos-chap.html

ツールを探してみる

表記のゆれをチェックできるツールとして知っているのは以下2つ。

github.com

github.com

今回は対象のファイルがMarkdownファイルであるのと、手元で手軽に動かしたたいので、npmでインストールできるtextlintを利用してみます。

また、prh形式のYAMLでルールを指定できるように次のツールも利用してみます。

github.com

ルールを作ってみる

チェックを行うためにはルールを作る必要があります。

AWS用語については公式にドキュメントとしてまとまっているので、これを利用するために次のような簡単なコマンドラインツールをgolangで作ってみました。

github.com

できることは単純で、日本語のAWS用語ページをスクレイピングしてprhで使える形式のYAMLファイルを出力します。

詳細はGitHub上のREADME.mdファイルを参照してください。

github.com

スクレイピングにはgoqueryというgolangの便利なライブラリを利用しています。

github.com

実際のYAMLファイルを見てもらえば分かりますが、単純に用語をそのまま抜き出しているものと、半角スペースで分解して単語単位で抜き出してものがあります。

github.com

たとえばAmazon Simple Workflow Serviceを登録する場合、

 - expected: 'Amazon Simple Workflow Service'
 - expected: 'Amazon'
 - expected: 'Simple'
 - expected: 'Workflow'
 - expected: 'Service'

の5種類を登録しています。

これは実際にチェックする際により多くのパターンにマッチさせたかったためで、利用してみてマッチしすぎる場合は必要のない部分を削除して使う形にしました。

作ったルールを利用してみる

作ったルールを実際に利用するには.textlintrc というtextlintの設定ファイルに、作成したaws_words.ymlファイルのパスを記載するだけです。

{
  "rules": {
    "prh": {
      "rulePaths": [
        "./aws_words.yml"
      ]
    }
  }
}

試しに次のようなMarkdownファイルに、上記の設定でtextlintを実行すると、

# AWS用語のチェック

- awsはダメ。
  - Amazon Web Serviceも間違い。
  - 日本語なので正解はアマゾン ウェブ サービス。

- 同じくAWS Management Consoleは英語なのでダメ。

のような結果になり、ルールにしたがってチェックされていることが確認できます。

$ textlint test.md

/Users/uchimanajet7/self-work/github/awr/test.md
  3:3   ✓ error  aws => AWS                                            prh
  4:5   ✓ error  Amazon Web Service => アマゾン ウェブ サービス        prh
  4:5   ✓ error   => Amazon                                            prh
  4:7   ✓ error  違い => AZ                                            prh
  4:16  ✓ error  ェブ サービス => service                              prh
  4:16  ✓ error  service => Service                                    prh
  7:6   ✓ error  AWS Management Console => AWS マネジメントコンソール  prh
  7:6   ✓ error  でダメ => AWS                                         prh
  7:10  ✓ error  同じくAWS マネジ => Management                        prh
  7:21  ✓ error  ントコンソール => console                             prh

✖ 10 problems (10 errors, 0 warnings)10 fixable problems.
Try to run: $ textlint --fix [file]

いくつか余計と思われる部分が指摘されていますが、これはルールを機械的に作り出しているために起こっているので、取り除きたい場合にはルールのaws_words.ymlファイルを編集します。

もうちょっと便利に

これでMarkdownファイルに書かれている内容について、なんとなくですがtextlintを利用してチェックできるようになりました。

しかし、実際にドキュメントを書く作業をしてみるともうちょっと便利にできそうな感じがするので試してみることにします。

私の場合ドキュメントを公開するまでに、

  1. Markdown形式でドキュメントを書く。
  2. textlintでチェックし、修正があればなくなるまで繰り返す。
  3. Zendesk Guideにドキュメントを反映するためにMarkdown形式からHTML形式に変換する。
  4. Zendesk GuideHTML形式でドキュメントを反映し、画像の追加や装飾などを行う。
  5. チームメンバーにレビューをしてもらい、指摘があればなくなるまで修正を繰り返す。

の定型作業を行っているので、この作業を効率化したいわけです。

最終的にはZendesk GuideHTML形式で記載することになります。 ですので、最初からHTML形式で書く方が効率的なの気もしますが・・・ 個人的にはMarkdown形式の方が書きやすいので、Zendesk GuideMarkdownに対応してくれるとうれしいなぁー

www.zendesk.co.jp

と言っても、そこはどーにもならないので次のような簡単なコマンドラインツールをgolangで作ってみました。

github.com

できることは単純で、Markdown形式からHTML形式に変換できます。加えて、この変換作業の前後で任意のコマンドを実行できるので、今回はtextlintを実行する形にしています。

ただし、textlintは別のプログラムなので事前にtextlintのインストールや設定は必要となります。

詳細はGitHub上のREADME.mdファイルを参照してください。

github.com

Markdown形式からHTML形式への変換にはblackfridayというgolangのライブラリを利用しています。v2への移行が進んでいますが、今回利用したのはv1になります。

github.com

出力するHTMLファイルにclassを動的に追加したいなら、v2に追加されたParseを利用して実現できそうな気がします。時間ができたら要確認かなぁ。

また、何度もチェックして変換する工程を繰り返すことが予想されるので、fsnotifyというgolangのライブラリを利用して、ファイルの変更検知をできるようにしてあります。ファイルの変更を検知してチェックと変換を繰り返し実行します。

github.com

CLI化するのには有名なので説明不要だと思われるcobraというgolangのライブラリを利用しています。

github.com

作ったものを使ってみる

せっかく作ったので使ってみるわけですが、前述したとおり変換前と変換後に外部コマンドを実行できます。

今回は変換前にtextlintを実行してAWS用語のチェックを行い、変換後にはHTMLを実行環境のデフォルトブラウザで表示してレイアウトの確認を行います。

設定ファイルには次のように実行するコマンドと置換する文字列を記載してあります。

{
    "Page": true,
    "CSS": "style.css",
    "PreCommands": [["textlint", "%INPUT_PATH%"]],
    "PostCommands": [["open", "%OUTPUT_PAGE_PATH%"]],
    "ReplaceTexts": [
        "<blockquote",
        "<blockquote class=\"is-colored\"",
        "<ol",
        "<ol class=\"list-colored\"",
        "<img",
        "<img class=\"image-with-border\"",
        "<table",
        "<table class=\"table table--bordered table--color-header\""
    ]
}

これで変更検知をする次のコマンドを実行して、ドキュメントを更新するとtextlintを実行して変換後のファイルを実行環境のデフォルトブラウザで表示できているはずです。

現状は変化前、変換後のコマンド実行でエラーがあってもそのまま実行を続ける仕様ですので、textlintで指摘があってエラーが表示されていても実行は継続します。

また、openコマンドでデフォルトブラザを開いているだけですので、ブラウザが複数立ち上がるってしまう可能性があります。

まとめ

  • textlintを使って表記のゆれをチェックできる
  • 人のレビューを受ける前に機械的にチェックできるのはありがたい
  • 頑張ってprh形式のYAMLファイルを用意すれば、任意のルールでチェック可能
  • AWS用語は公式サイトにまとめられているので利用できる
  • ただし、日本語へのローカライズで問題ありそうな文言もあるので注意が必要
  • あと、誤表記やTypoを発見したらAWSへ積極的にフィードバックしておきましょう!そのうちきっと修正してもらえるハズ

f:id:uchimanajet7:20171016000127p:plain

アマゾン ウェブ サービス : AWS の用語集 - EBSbacked
https://docs.aws.amazon.com/ja_jp/general/latest/gr/glos-chap.html#EBSbacked

  • Zendesk GuideMarkdown形式が追加されてほしい
  • そー考えるとHatena Blogすごい書きやすいんだなーとあらためて思った
  • golangは相変わらず便利、そしてちょー楽しい
  • blackfridayはv2を使っていないので今後使ってみたい
  • fsnotifyは便利だったので今後も使っていきたい
  • 当然このblogもMarkdownで書いているのでtextlintを使ってチェックした

以上になります。

Visual Studio Codeに拡張機能がインストールできない場合の対処方法 #vscode #docker

アップデートエラー

f:id:uchimanajet7:20171018011922p:plain

Visual Studio Code(以下VS Code)の拡張機能Dockerがありますが、この拡張機能0.0.19へのアップデートで

end of central directory record signature not found

というエラーが出てアップデートができなくなりました。

code.visualstudio.com

marketplace.visualstudio.com

拡張機能Dockerをアンイストールして、再インストールしようとしても同じ結果に・・・

調べてみると

GitHubにissueが上がっていて

github.com

次のissueと同様の対応をすると解決するとのことなので

github.com

解決方法が載っているというissueを読んでみると

github.com

と書かれており、つまりは拡張機能をブラウザを使ってダウンロードして、ダウンロードしたローカルファイルからインストールすれば解決すると。

さっそく試してみる

拡張機能インストールファイルのダウンロード

issueには拡張機能PythonをダウンロードできるURLが記載されていて、Google先生で調べるとこのダウンロード用のURLを自分で編集してインストールパッケージをダウンロードすると書かれたBlogが多数ヒットします。

marketplace.visualstudio.com

しかし、上記のリンクを確認すればわかりますが、拡張機能の個別ページにはパッケージをダウンロードできるリンクが存在します。

f:id:uchimanajet7:20171018013628p:plain

Download Extensionをクリックすれば、インストール用のパッケージがダウンロードされます。今回のDockerであればPeterJausovec.vscode-docker-0.0.19.vsixというファイルになります。

ローカルファイルからの拡張機能インストール

ダウンロードしたPeterJausovec.vscode-docker-0.0.19.vsixを利用して、拡張機能インストールします。

[表示] → [コマンドパレット]でコマンドパレットを表示します。コマンドパレットのメニューから拡張機能: VSIX からのインストールを選択します。

f:id:uchimanajet7:20171018015111p:plain

するとファイル選択のダイアログが表示されるので、先ほどのファイルPeterJausovec.vscode-docker-0.0.19.vsixを選択するとインストールが開始されます。

f:id:uchimanajet7:20171018015929p:plain

インストールが正常に完了すると、再読み込みをうながすメッセージが表示されますので今すぐ再度読み込むボタンをクリックして再読み込みを行います。

f:id:uchimanajet7:20171018020940p:plain

インストール済みの拡張機能一覧にDockerの表示があればインストールが正常に完了したことになります。

まとめ

  • 特に何もしていないのに急にアップデートできずエラーになった
  • 調べてみたら同じような人がいた
  • 対処はインストールパッケージをローカルにダウンロードして、ローカルファイルからインストールを実行するだけ
  • いろいろ複雑に書いてあるBlogもあるが、たぶん情報が古い
  • もし同じような症状の人がいるなら参考にしてほしい
  • 原因がわからないので再発しないといいなぁー

以上になります。

Raspberry Pi 3+Gmail APIでメールを受信して音声合成してみた #raspberrypi #gmail #golang

メールで

仕事では殆どメールを見る機会はないのですが、通知系のメールに気が付かなかったという経験をしたことがある人は多いはず。

今回はGmailAPI を使ってメールを定期的に受信して、条件に合うメールの場合は音声で通知できる仕組みを Raspberry Pi 3Gamil APIを利用して作ってみたいと思います。

Gamil API

developers.google.com

利用を開始するまでにはいくつかステップがあって、いろいろなBlogで書かれていますが上記の公式サイトにあるQuickstart で、利用する言語毎に書かれているドキュメントの通りに進めるのをおすすめします。公式ドキュメントが充実しているのと最新の情報が記載されているため、手戻りすることなく進めることができます。

今回は当然大好きなgolangを利用するので以下に沿って進めていきます

Go Quickstart  |  Gmail API  |  Google Developers
https://developers.google.com/gmail/api/quickstart/go

準備

Google Developers Console

developers.google.com

まずはGoogle Developers Consoleにアクセスして

f:id:uchimanajet7:20170904151423p:plain

Google API Consoleに移動します。

console.developers.google.com

表示されたAPIの一覧からGmail APIを選択します。

f:id:uchimanajet7:20170904152527p:plain

プロジェクトが存在しないとAPIを有効化できないので、先にプロジェクトを作成します。

f:id:uchimanajet7:20170904153616p:plain

既存のプロジェクトでAPIを有効かする場合には、当然ですが新規にプロジェクトを作成する必要はありません。

f:id:uchimanajet7:20170904163117p:plain

APIを有効化しただけでは利用ができません。認証情報を作成する必要があります。

f:id:uchimanajet7:20170904163950p:plain

OAuth クライアントIDを取得するのですが、先に同意画面の設定が必要になります。

f:id:uchimanajet7:20170904170220p:plain

クライアントIDのアプリケーションの種類はその他を選択します。

f:id:uchimanajet7:20170904174533p:plain

設定が完了すると認証に必要な情報をJSONファイルとしてダウンロードすることができるので、ダウンロードして保存します。

f:id:uchimanajet7:20170904175531p:plain

詳細は以下の公式ドキュメントに書かれています

Authorizing Your App with Gmail  |  Gmail API  |  Google Developers
https://developers.google.com/gmail/api/auth/about-auth

Implementing Server-Side Authorization  |  Gmail API  |  Google Developers
https://developers.google.com/gmail/api/auth/web-server

Choose Auth Scopes  |  Gmail API  |  Google Developers
https://developers.google.com/gmail/api/auth/scopes

golang packages

次にgolangで必要になるパッケージを以下のコマンドを実行して取得します

$ go get -u google.golang.org/api/gmail/v1
$ go get -u golang.org/x/oauth2/...

実際に取得されるのは以下のパッケージになります。

github.com

github.com

パッケージの利用方法は、それぞれのパッケージに用意されているドキュメントを確認してください。 サンプルについてもパッケージのリポジトリにあるので参考になるかと思います。

動作確認

続けて動作と認可の確認を行います。

Go Quickstart  |  Gmail API  |  Google Developers
https://developers.google.com/gmail/api/quickstart/go#step_3_set_up_the_sample

上記のサンプルコードをそのまま利用するのですが、最初の工程でダウンロードしたGmail APIのクライアントIDのJSONファイルが必要になります。

サンプルコードをビルドして実行すると、コンソールに

Go to the following link in your browser then type the authorization code:

のメッセージと一緒にURLが表示されます。このURLが認可ページのURLになるのでブラウザにコピペしてページを表示します。

godoc.org

ブラウザに表示したら認可を与えるアカウントを選択します

f:id:uchimanajet7:20170904195633p:plain

認可の内容を確認します。今回は読み取りのみを指定しています。

f:id:uchimanajet7:20170904201054p:plain

godoc.org

問題がなければ許可をして、その後の画面に表示されるコードをターミナルに貼り付けます

f:id:uchimanajet7:20170904201716p:plain

これで次回の動作からはクライアント側に保存されたtokenを利用してアクセスすることができるようになります。

作ったもの

実際に作ってみたものは以下の写真のような感じに

f:id:uchimanajet7:20170902103822j:plain

使ったのは

  • Raspberry Pi 3 MODEL B
  • USB電源スピーカー(MS-UP201BK)
  • USB電源LEDライト(100円ショップ)

ぐらいで、ラズパイはAmazon Echoもどきで遊んだ時のやつを再設定して利用しましたし、LEDライトは100円ショップで適当に買ったやつですし、唯一スピーカーが手元になかったので700円ぐらいのものを買った感じですね。

ラズパイだと情報も多いですし、選択肢もいろいろとあるんですが手間もかけずに適当に作れるのはいいですねー

Raspberry Pi 3 MODEL B

www.raspberrypi.org

特別なことは何もしておらず、普通にRaspbianのLITEをインストールしてsshで接続できるように設定しました。

hub-ctrl

USBの電源をON/OFFするために、以下を参考して

Raspberry Pi B+ turn usb power off - Raspberry Pi Forums
https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=93463

hub-ctrl をインストールしてあります。

github.com

ラズパイ3だとUSBの個別ポートで電源のON/OFFができると記載されている 記事も目にしましたが、手元のラズパイだと

pi@raspberrypi:~ $ hub-ctrl
Hub #0 at 001:000
 INFO: ganged switching.
 WARN: Port indicators are NOT supported.
Hub #1 at 001:000
 INFO: ganged switching.
 WARN: Port indicators are NOT supported.

pi@raspberrypi:~ $ lsusb -v
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass         0
  bDeviceProtocol         1
  bMaxPacketSize0        64
  idVendor           0x0424 Standard Microsystems Corp.
  idProduct          0xec00 SMSC9512/9514 Fast Ethernet Adapter
  bcdDevice            2.00
  iManufacturer           0
  iProduct                0
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           39
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower                2mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           3
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      0
      bInterfaceProtocol    255
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0010  1x 16 bytes
        bInterval               4

Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         2 TT per port
  bMaxPacketSize0        64
  idVendor           0x0424 Standard Microsystems Corp.
  idProduct          0x9514
  bcdDevice            2.00
  iManufacturer           0
  iProduct                0
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower                2mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         9 Hub
      bInterfaceSubClass      0 Unused
      bInterfaceProtocol      1 Single TT
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0001  1x 1 bytes
        bInterval              12
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       1
      bNumEndpoints           1
      bInterfaceClass         9 Hub
      bInterfaceSubClass      0 Unused
      bInterfaceProtocol      2 TT per port
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0001  1x 1 bytes
        bInterval              12

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         1 Single TT
  bMaxPacketSize0        64
  idVendor           0x1d6b Linux Foundation
  idProduct          0x0002 2.0 root hub
  bcdDevice            4.09
  iManufacturer           3
  iProduct                2
  iSerial                 1
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           25
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower                0mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         9 Hub
      bInterfaceSubClass      0 Unused
      bInterfaceProtocol      0 Full speed (or root) hub
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0004  1x 4 bytes
        bInterval              12

な感じなんですが、個別のON/OFFは残念ながらできませんでした。 USBの規格としてPer-port power switchingというのに対応していると個別のON/OFFが可能みたいです。調べた限りだと

スゴイハブ USB2-HUB4Xシリーズ 製品情報
http://www.system-talks.co.jp/product/sgc-4x.htm

が動作実績がありそうな感じでした。

AquesTalk Pi

日本語を音声合成するためのTTSとして、以下のAquesTalk Piをインストールしてあります

AquesTalk Pi - Raspberry Pi用の音声合成
https://www.a-quest.com/products/aquestalkpi.html

blog-yama.a-quest.com

今回はなるべく手軽に実現したかったのでAquesTalk Piを選択しましたが、他にも

Open JTalk
http://open-jtalk.sourceforge.net/

なんかを利用している人が多いようです。

また、クラウドサービスを使って音声合成をすることももちろん可能なのですが、今後家のネットワーク以外の例えばSORACOM Airなんかを利用したい場合を考えると、ラズパイ側で処理できるなら処理した方が良いかなーと。

クラウド側で処理する場合は

aws.amazon.com

azure.microsoft.com

www.ibm.com

あたりが定番でしょうか?

意外だったのはGoogleにはTTSのAPIがなさそということでしょうか・・・音声認識はあるので、内部的には当然あるんでしょうけど。

cloud.google.com

あとは、crontabで作ったプログラムの定期実行と起動時のUSBのコントロールを行っているぐらいです

pi@raspberrypi:~ $ crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command

# ggm
*/3 * * * * /home/pi/ggm/ggm

#set init
@reboot amixer set PCM 100%
@reboot sudo hub-ctrl -h 0 -P 2 -p 0

golang program

やっていることはGmailAPI直接ではなく、golangSDKを利用して受信しているだけです。

github.com

特に変わったこともしていないので、何の参考にもならないかもしれませんが・・・

動作の設定で記述が必要なのは.ggm/user_config.json ファイルだけです。

{
    "LastDate": 1504243346130,
    "LastTotal": 749,
    "UserEmail": "test@example.com",
    "SpeakCommands": [["/home/pi/aquestalkpi/AquesTalkPi", "-s", "120", "%s"],["aplay"]],
    "UsbCommands": [["sudo", "hub-ctrl", "-h", "0", "-P", "2", "-p", "%d"]],
    "Filters": [
        {
            "From": "user1@example.com",
            "Subjects": ["test","user1"]
        },
        {
            "From": "user2@example.com",
            "Subjects": null
        }
    ]
}

SpeakCommandsには音声合成するためのコマンドを記載しますが、配列で1つのコマンドを表して、配列を配列に入れることでパイプでつないで実行します。なので、上記の例だと

$ /home/pi/aquestalkpi/AquesTalkPi -s 120 %s | aplay

のコマンドを実行していることになります。コマンド中の%sにはGmailの受信した内容が入ります。

UsbCommandsにはUSB電源管理するためのコマンドを記載します。形式は前述の通りです。コマンド中の%dはON/OFFの数値が入ります。

Filtersには音声合成対象のメール条件を記載します。Fromには送信元のメールアドレスを、Subjectsには配列で件名を記載します。特に指定がされていない場合にはすべてのメールが対象となります。

cross compile

Raspberry Pi 3 用にgolangコンパイルする際には

Installing Go from source - The Go Programming Language
https://golang.org/doc/install/source#environment

を参考にして環境変数を指定するわけですが、$GOARMに指定する値はラズパイ上で以下のコマンドを実行すると確認できます。

pi@raspberrypi:~ $ uname -m
armv7l

どうやらv7らしいので

$ GOOS=linux GOARCH=arm GOARM=7 go build -v

とすれば、今回の利用するライズパイ上で動作するバイナリがビルドできることになります。

動作デモ

で、実際に動作するとどうなるのか?というと・・・

twitter.com

な、感じになりました。思ったよりちゃんと音声合成できていて個人的には十分かなぁーと思いました。

まとめ

  • Raspberry Pi 3 は結構サクサク動く
  • これだけ動けばgolangでちょっとしたことは余裕そう
  • 今回は簡単にやってみたかったので複雑なのは却下した
  • Gmailだとpush通知を利用した方が良いかもしれない

Push Notifications  |  Gmail API  |  Google Developers
https://developers.google.com/gmail/api/guides/push

  • SORACOM Airを利用したい場合、USBドングルを使うことになるのでUSB電源をOFFにする動作が微妙
  • 前述したPer-port power switchingに対応したUSBハブを導入して回避する
  • USBをON/OFFしている理由は、雑音が聞こえることがあるのとUSBライトを受信時にだけに光らせたいから
  • 予算や手間を気にしないならCrystal Signal Pi みたいなのを導入するのもありかもしれない

crystal-signal.com

  • 雑に扱っても大丈夫というのが1つの目的だったので自作はなるべくなし
  • golangはいろいろできて楽しい
  • 急に喋り出すので若干びっくりする
  • 特に夜中とか怖いw
  • 要望は叶えられたので便利にはなった
  • また機会があればぜひなんかやってみたい

以上になります。

Cloud Automator のAPI に後処理が追加されたのでCLIにも追加した件 #cloudautomator #golang #swx

気がついたら

Cloud AutomatorAPI後処理に対応していました。

blog.serverworks.co.jp

Cloud Automator API | /post_processes
https://cloudautomator.com/api_docs/v1/api.html#後処理

APIの詳細は上記の公式サイトを確認してもらうとして、数も多くなさそうなので作ったCLIにも追加しようと思います。

追加した

uchimanajet7.hatenablog.com

というわけでv0.1.1Cloud AutomatorAPIの後処理に対応するコマンドを追加しました。

github.com

下記のようなコマンドでsqsの後処理を新規に追加することができます。

$ ./ca post-process create \
--name "後処理テスト" \
--service sqs \
--parameters sqs_aws_account_id=1\
,sqs_queue="example-queue"\
,sqs_region=ap-northeast-1

--parametersobject型ですので、他のobject型と同様に “APIのパラメータ名=値” の形で指定して、パラメータ同士は",“で繋いで表現してください。また、配列を表現する場合は”APIのパラメータ名=値,値,値“のように値を”,“で繋いで表現してください。

まとめ

  • 数が多くないので手作業でもなんとかなったが、やっぱりAPI定義から自動で作れるような仕組みは必要
  • 今回もAPIドキュメントにTypoがあり、コピペしてそのまま使ったら404で少しハマった・・・
  • APIドキュメントのどの部分が更新されたのかわからないので、とりあえず全部目を通して変更点を探す必要があった
  • 新規追加はわかりやすいが、既存のAPIにパラメータの追加とかは数が多くなったら見て確認するのは難しい
  • テストがないので既存のコード変更後の確認が大変だった
  • 足りないところやできていないところを何とかしたい

以上になります。

OneTab のTabリストを整理するCLI をgolang で作ってみた #golang #onetab

便利な

みんな知ってるGoogle Chrome 拡張機能OneTab

chrome.google.com

ちょー便利なのでよく使うんですが、気軽に使えすぎてOneTabのリストがどんどん膨れ上がってきませんか?

f:id:uchimanajet7:20170815191634p:plain

・・・と、こんな感じでどんどん増えて行くわけですが

  • OneTab に同じURLが登録されている
  • OneTab 側にリストを整理するような個別な機能がない
    • UI上でマウスを使って移動や削除はできる
    • 数が多くなるとこの操作も大変
  • リストの登録件数が多くなると重くなる
    • PCのスペックにもよるが手元だと2,000件ぐらいから重い
    • 登録や削除が重くなる

というわけで、他に需要があるとは思えないCLIを作ってみました。 自分でも使ったのも1回きりというね・・・

作ったのは

github.com

使い方は簡単でOneTabからURLの書き出しで出力されるリストをファイルに保存して

f:id:uchimanajet7:20170815173341p:plain

コマンドラインで保存したファイルを指定してコマンドを実行するだけ

$ ./tlc run "your_file_path" -w

-wオプションでHTTPリクエストでURLがアクセス可能かどうかをチェックします。

やってること

f:id:uchimanajet7:20170815173328g:plain

すごい単純なことしかやってませんが

  • OneTabから書き出したURLリストを保存したファイルを読み込む
  • 読み込んだファイルからURLをキーにしてURL文字列が完全一致するものを削除
  • URLで削除したリストを今度は名称文字列が完全一致するものを削除
  • -wオプションが指定されていた場合、URLがアクセス可能か(status == 200)かどうかチェックする

だけなので、当然ですが

  • URL文字列が異なり同じWebページだった場合は違うとみなされる
    • 例えばSNSからのリンクがわかるようなパラメータ付きとパラメータ無しのページなど
  • 名称文字列が同一でURLが異なる場合は、同一とみなさせる
    • すべてのページで同じ名称がつけられているページなど
  • URLのアクセスチェックでステータス200以外の場合はアクセスできないとみなされる
    • ブラウザと同等の判定はしていないため、ブラウザで見れるのNGと判定される場合がある

という制限?問題点?はあります。

ダメだったこと

簡単にできそうで、できなかったことを書いておこうかと。

  1. URLからHTMLの内容を取得して、取得した内容をハッシュ値で比較
    • セッションIDや広告IDなどのアクセスするたびに異なる値がHTMLに含まれることがある
    • これによりハッシュ値が同一のページでも毎回異なる
  2. URLにアクセスできるかをブラウザと同等の判断で行う
    • ブラザと同等となるとブラザそのものでチェックした方が早い
    • 現状ではCDNでJSを使ったリダイレクトなどしていると上手く判定できない
    • リダイレクト回数が多い場合に上手く判定できない

そもそもよく考えたら、どれもダメだよねーとw

まとめ

  • とりあえず動くところまでは出来ている
  • golangって便利ですなぁ
  • リストの重複を除く仕組みをもうちょっと考える必要がある
  • 今ならGoogle Chromeのヘッドレスモードを利用できるならした方が良さそう

github.com

  • CLIにしたけどWebでできた方が手軽そう
  • というかOneTab側になんか整理する機能があってもいい気がする
  • そもそもこんな使い方している人が他にいないかもしれないw

以上になります。

GitHub のREADME にgif 画像を表示する1番簡単な方法 #github #gif

画像を

GitHubのREADMEにgif画像を貼り付けたいってことってありますよね。今回作ってみたこれ↓でも1枚だけ貼り付けたい感じになりました。

uchimanajet7.hatenablog.com

当然Google先生github readme gifとか入力して調べてみるわけですが

github readme gif
https://www.google.co.jp/search?q=github+readme+gif

どーやら↓の2つの方法が主流っぽい感じ?

  1. リポジトリにmaster branch以外の画像のbranchを切りそこに画像をアップロード
  2. GitHub Wikiリポジトリに画像用フォルダを作りそこに画像をアップロード

1の方法は確かに手軽だけど、それだけのためにbranchが残り続けるのが個人的には好きじゃないので却下。これするなら素直にmaster branchに画像ファイル追加するなぁ

2の方法は利用したこともあるし、Wiki使ってドキュメント書くならアリだと思うんですが・・・今回はファイル1個なのが迷うところ。

2と似てるけどGitHub Pagesでも同じようなことは出来ますよね。こっちもページ公開するならアリだと思うけど、今回はファイル1個・・・

もっと手軽に

f:id:uchimanajet7:20170812170547p:plain

画像1個で画像自体のバージョン管理が必要ないので、もっと簡単に出来ないかなぁーと。そこで思いついたのが以下の方法になります。

  • GitHubリポジトリにissueを起こして、そのissueに画像を貼り付ける
  • issueの画像はMarkdown記法でリンクが記述されているのでそれをコピー
  • 画像を貼りたいREADMEにこのリンクを張り付ければOK

f:id:uchimanajet7:20170812170338p:plain

今回はこの方法を利用しているので、実際にissueに貼った画像を使ってREADMEに画像を貼り付けています

github.com

github.com

この方法の良いところ

  • issueを作って画像を貼り付けるだけなので手軽
  • 余計なbranchが残り続けることもない
  • issueなので、そのissueのためにbranch切ってpull request起こせば、なんでこうなってるのかがあとからもわかる
  • そもそもREADMEを更新するのでpull requestを起こすはず
  • issueなので対応が終わったらcloseしちゃえば良い
  • 画像を差し替えたい場合も、差し変えるためのissueを起こせば同様の手順でOK
  • issueの画像リンクがMarkdown記法なので、そのままコピペできる
  • 何と言っても手軽

ということで、手軽で良い感じかと。 何かの参考になれば。

以上になります。

日経Linux2017年9月号にちょっとだけ載った件 #ITpro #swx #aws

きっかけは

先日↓退職Blogをアップしていたおねーさんが

gyori.hatenablog.com

社内Slackで
Amazon AIネタで雑誌に書いてみませんかー?締め切り近いけどw」
的な募集をかけていました。なんてゆるいw 素敵すぎる!

Amazon Pollyなら以前にアドベントカレンダーでネタにしたこともあるのでワンチャン!と思いとりあえず手を挙げてみました。

uchimanajet7.hatenablog.com

そしたらありがたいことに執筆させてもらえることになりました。

書いたのは

記事を書いたのは↓の「日経Linux2017年9月号」で、内容はAWSのAIサービスについてになります。

f:id:uchimanajet7:20170812114832j:plain

itpro.nikkeibp.co.jp

実際にはAmazon PollyとAWSの概要についてを担当しました。

aws.amazon.com

aws.amazon.com

書いてみて

f:id:uchimanajet7:20170812114910j:plain

  • 書くのにあたってAWSサイトを色々見たけど、ドキュメントが多くてしっかり書いてあるのを再認識
  • というか、これWebが見らえる環境ならわざわざ紙にする必要があるのかどうか気にするレベル
  • 規定の文字数にまとめるのは大変
  • 雑誌という限定される中で、編集の方がいろいろ工夫されているのがわかった
  • どの業界でもユーザーにどうやって価値を届けるのか?に違いはないんだなぁーと
  • こちらが雑誌という媒体に慣れてないため、何度か手間を取らせてしまった
  • 次回からもうちょっと色々考えてこちらから提案できるようにしたい
  • 知ってるつもりでも、まとめたり再度調べなおしたりすると色々と発見もあり自分でも大変勉強になった
  • とにかく良い機会だった

まとめ

  • 気になったら是非お手にとっていただければ!
  • 日経Linuxに小さいけど自分の名前が載るとかテンション上がる!
  • おねーさんと最後にお仕事っぽいことが出来てよかった!
  • 雑誌編集の人の雑誌に対する姿勢にいろいろ学べた
  • 雑誌だろうと、Webサービスだろうとやっぱりユーザー視点ってすげー大事だなと
  • もっと他の業種の人とも一緒に仕事できると、こういう気づきがありそうなので機会があれば積極的にやっていきたい
  • 文章書くのに慣れてないから時間がかかった
  • けど楽しいので文章書くのも機会があれば積極的にやっていきたい
  • こういう良い機会に関われてよかった

f:id:uchimanajet7:20170812133242j:plain

  • ↑少しですがちゃんとCloud Automatorの宣伝もしておりますw

uchimanajet7.hatenablog.com

cloudautomator.com

以上になります。