試したこと、読んだ本について書いていくブログです。

Tweetボタンでつぶやく内容を動的に変更する


はじめに

今回はWebページ設置するTwitterの共有ボタンからTweetを行う際、Tweetする内容を動的に変更する方法をご紹介します。

本文

Twitterの共有ボタンを設置するだけなら、Twitter公式サイトで生成できる以下のコードをHTMLに埋め込むことで簡単に実現できます。

<a href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-text="ハローワールド" data-show-count="false">Tweet</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

しかし、この方法だとTweetする文章を動的に変更することはできません。

そこで、JavaScriptでTweetする内容を生成して、window.openメソッドでTweet共有用のURL(https://twitter.com/share) を呼び出すことで対応します。
URLに以下のパラメータを追加することで、ハッシュタグやアカウントを含めたTweetを行うことができます。

パラメータ説明
textTweetする文章
urlTweetに含めるURL
viaTweetに含めるアカウント
hashtagsTweetに含めるハッシュタグ
relatedTweet後にフォローを勧めるアカウント

サンプルコード

以下がサンプルコードになります。
JavaScriptのコードが18行ありますが、ほとんどは現在時刻を求めているだけで、実際にTweetを行うのに必要なのは17行目のwindow.open(...);だけです。

See the Pen mQrWxz by foresukecom (@foresukecom) on CodePen.

Tweetボタンを押すと、以下のようなTweetを投稿できます。

※追記
Tweetが140文字を超えたらどうなるか確認したところ、以下のように403エラーとなりました。
実際に使うなら、文字数チェックの処理が必要ですね。

See the Pen dynamit_tweet_long by foresukecom (@foresukecom) on CodePen.

その他

最近Ultimate Chicken Horseをはじめました。
このゲームは4人対戦の2Dアクションゲームです。スタートからゴールまで早く到着したプレイヤーが勝ち、というシンプルなルールなのですが、試合ごとに足場やトラップを自由に設置できるので、後半になるほどカオスなコースになり、ワイワイと楽しむには最適なゲームです。

Read more ⟶

GAEでバッチ処理


はじめに

Google App Engine(GAE)を使って、バッチ処理が実行できたのでメモです。
GAEではcron.yamlに設定を記載することで時間を指定した処理を行うことができます。

サンプル

今回は、slackにメッセージを送信するアプリを定期的に実行させてみます。

slackにメッセージを送る部分は以下のサイトに詳しく記載されているので省略します。
CrossBridge Lab | GolangでSlackの特定のチャンネルにメッセージを送る

今回はGAE上でGolangを動かしてみましたよの構成を元に、GAEのプロジェクトを構築します。
ルートディレクトリ(app.yamlと同じ階層)にcrom.yamlを作成します。

cron.yaml

cron.yamlには、以下のように開始時刻や間隔で実行するタイミングを指定することが出来ます。

cron:
- description: "毎朝7時(日本時間)に実行"
  url: /morning
  timezone: Asia/Tokyo
  schedule: every day 7:00

- description: "毎週日曜8時(日本時間)に実行"
  url: /morning
  timezone: Asia/Tokyo
  schedule: every sunday 8:00

- description: "毎日0時を起点とし、1時間単位で実行"
  url: /morning
  timezone: Asia/Tokyo
  schedule: every 1 hours

その他のスケジュール指定方法や、HTTPリクエスト失敗時のリトライ回数は公式のドキュメントに詳しく記載されています。

注意点

GAEではdev_server.pyでローカルにサーバを立ち上げて、動作確認をすることができます。しかし、ローカル環境では、cron.yamlは動作しません。
localhost:8000 からGAEローカル環境の管理画面を開くことができます。
管理画面にcron.yamlで設定したスケジュールが一覧で表示されるので、Run nowをクリックすることで手動で実行することができます。

Cronの設定を本番環境にデプロイするときは、gcloud app deploy cron.yamlのようにcrom.yamlを指定します。
指定しないと、crom.yamlが読み込まれないため、いつまで待っても処理が実行されません。 Cronが設定されているかどうかは、コンソール画面のcronジョブから確認することが出来ます。

仮に他のユーザからHTTPでのリクエストがあった場合、想定していない時間に処理が実行される可能性があります。
そのため、GAEのcronサービスからのHTTPアクセス以外からのアクセスは除外する必要があります。
GAEのcronサービスからのHTTPアクセスにはHTTPヘッダにX-Appengine-Cron: trueが含まれているので、HTTPリクエストを受け取ったタイミングで、チェックする必要があります

例えば、GolangでGAEのcronサービス以外からのHTTPリクエストを弾くには、以下のように書きます。
(弾いた後の処理がお粗末ですが…)

// cron以外からのアクセスは弾く
if r.Header.Get("X-Appengine-Cron") != "true" {
	os.Exit(1)
}

感想

GAEはhttp(s)でのリクエストに対してレスポンスを返すだけのサービスだと思っていたので、時間指定で処理を実行してくれるのはとても意外でした。

Read more ⟶

GAEでfaviconを設定


はじめに

GoogleAppEngine(GAE)上で提供するWebページにfaviconを設定するさいに、少し迷ったのでメモに残しておきます。

faviconとは

faviconとは、ブラウザのタブやブックマークに表示されてるアレです。
最近は、スマートフォンでWebページのショートカットをホーム画面や、Windows10のスタートメニューで見かけることも増えてきました。

faviconについては、以下の資料に詳しくまとめられています。
WEBサイトが「できた」と安心する前に最終チェックすること

favicon準備

faviconの元にするイラストはこちらです。 このイラストをいい感じにfaviconとして使っていきます。

今回は、スライドで紹介されているFavicon Generatorを使ってfaviconを用意していきます。
faviconを生成すると、favicon_package_v0.16.zipがダウンロードできます。
favicon_package_v0.16.zipは以下のような中身になっています。

favicon_package_v0.16
├── android-chrome-192x192.png
├── android-chrome-384x384.png
├── apple-touch-icon.png
├── browserconfig.xml
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── mstile-150x150.png
├── safari-pinned-tab.svg
└── site.webmanifest

この中ので拡張子がpngicoは実際に表示されるイメージファイルです。
browserconfig.xmlはWindows10のスタート画面にWebページをピン留めしたときに表示される画像の設定情報です。このファイルは明示的に読み込まなくても、ルートディレクトリに置いておけば、勝手に読み込んでくれます。
safari-pinned-tab.svgはベクターというフォーマットの画像ファイルです。safariで表示するfaviconはこの画像を使っているようです。
site.webmanifestはAndroidでWebページをホーム画面に追加したときのアイコンや、タイトルを設定するファイルです。

今回はGAE上でGolangを動かしてみましたよの構成を元に、faviconを設定します。
browserconfig.xmlsite.webmanifestはルートディレクトリに配置し、その他の画像ファイルはルートディレクトリ直下のimagesに配置します。
プロジェクトのディレクトリ構成は以下の通りです。

.
├── app.yaml
├── gae_sample.iml
├── hello.go
├── index.yaml
└── static
    ├── browserconfig.xml
    ├── site.webmanifest
    ├── images
    │   ├── android-chrome-192x192.png
    │   ├── android-chrome-384x384.png
    │   ├── apple-touch-icon.png
    │   ├── favicon-16x16.png
    │   ├── favicon-32x32.png
    │   ├── favicon.ico
    │   ├── mstile-150x150.png
    │   └── safari-pinned-tab.svg
    ├── index.html
    └── js
        └── main.js

GAEで使う

GoogleAppEngineでfaviconを使用するには、HTMLファイルの<head>で読み込む以外に、Why do I get URI error for /favicon.ico?にも書かれているとおり、app.yamlにも記載する必要があります。

Read more ⟶

祝日のカウントダウンタイマー


はじめに

GoogleAppEngine(GAE)、Golangの勉強のために、祝日までのカウントダウンタイマーを表示するWebページを作ってみました。

https://shukujitsu.info

処理の内容

内閣府が祝日の情報をCSV形式で公開しているので、定期的に取得して、加工して、CloudStorageにアップロードしています。
GAEにアクセスがあると、CloudStorageから祝日情報を読み込んで、いい感じに加工して表示しています。

使ってる技術

GoogleAppEngine

インフラとしてGAEを使いました。
GAEに対応していない関数とかもあるので、ドキュメントを見ながら覚えていくしかなさそうです。
たとえば、GolangでHTTPのリクエストを行うときにhttp.Get()を使いますが、GAEでは対応していないのでurlfetch.Clientを使う必要があります。 他にも、Javaでは時刻を扱うjava.time.LocalDateというライブラリがあるのですが、同様にGAEでは使うことができません。
GAE使うなら言語に依らず注意する必要があります。

Golang

ネット上に公開されているCSVファイルを読み込んで、Cloud Storageにアップロードする部分をやってます。
もともと、Golangの勉強を兼ねたプロジェクトだったんですが、あまりGolangを使いませんでした。

Vue.js

JavaScriptで変数を書き換えると、いい感じにHTMLで表示される内容も変更されます。
まだVue.jsを使いこなせてはいませんが、低い学習コストでさっくり使うことができます。

Scrollify

マウススクロールでいい感じに画面を切り替える処理はScrollifyを使いました。
これを使うだけで今風な感じがでます。

今後の課題

データ保管場所

情報をCloudStorageに保存してるので、NoSQLを触ってみようかと考え中です。
日付と祝日名を格納するだけなのでRDBでも問題ないんですけど…

監視、ログ

なんらかのエラーが起きた場合はソーリー画面を出し、StackDriver上にログを出すようにしていますが、能動的にチェックしないとエラーに気が付きません。
エラーを検知したら通知する仕組みがほしいですね、LINEかSlackに飛ばすのが今風でしょうか…

パッケージ管理

使用しているライブラリのバージョン管理とかをしていないので、一般的に使われている(らしい)、depを使ってみようかと考え中。
次バージョンのGolangではmodulesという新たなパッケージ管理機能が正式リリース予定なので、最終的にはそっちに映る感じでしょうか。

リファクタリング

ディレクトリ階層がぐちゃぐちゃで、1つ1つのファイルも肥大化しているのでキレイにしたいです。
ある程度キレイになったらリポジトリを公開するのもアリですね。

CIツール導入

現在、dev_appserver.pyでローカル環境を立ち上げて、動作チェックが済んだらgcloud app deployで本番環境を更新する、という雑な運用をしています。
雑すぎるので、CircleCIとかを使って、PR投げたらステージング環境でテストが実行されてー、というのを導入したいです。

AltJS

「素のJavaScriptを書くのがツラい」という話を聞くことが増えてきました。
この規模なら素のJavaScriptでも問題ないですが、今後のことを考えるとTypeScriptかCoffeeScriptあたりを勉強して置き換えることを考え中です。

WPA化

WPAであれば、オンライン状態でアクセスしておけば、オフライン状態でもそのWebサイトにアクセスができるようです。
地下鉄などの電波状況が悪い場所でも祝日カウンターが使えれば素敵ですね。

見た目

レイアウト気にし始めるとキリがないので一旦リリースしてしまいました。
運用しながら徐々に変更を加える予定です。

感想

本当はcoinhive仕込みたかったけど神奈川県警に捕まったらいやなので我慢しました。
認証も、DBへのアクセスもないページですが、1人でインフラ、サーバサイド、フロントエンドの構築を行ったのでいろいろと勉強になりました。
細々としたTipsはブログに残していきたいです。 課題もたくさん出てきたので、徐々に直していきます。

欲しい機能とか、気になる箇所があれば、お気軽に@foresukecomまでご連絡下さい。

その他

ここ数年、ウィルキンソンの炭酸水をAmazonで定期購入してます。炭酸水のおかげで、ビールを飲む量がだいぶ減りました。
でも、炭酸水はウイスキーのチェイサーに最適なんですよね…割れば簡単にハイボールも作れるし…
悩ましい飲み物です。

Read more ⟶

ReactNativeを触ったお話


はじめに

お仕事でReactNativeを使うことになったので、触ってみました。

導入手順について本記事内では説明をしないので、ReactNativeの公式サイトのGetting Startedをご参照ください。
ちなみに、ReactNativeのバージョンは0.57.3です。

サンプル

今回はRESAS-APIから都道府県一覧を取得してリスト表示してみます。
react-native init projectNameを実行直後のディレクトリ構成は以下の通りになっています。

projectName
├── android
├── ios
├── node_modules
├── App.js
├── app.json
├── index.js
├── package-lock.json
└── package.json

今回はApp.jsのみを以下のように変更を加えていきます。

RESAS-APIを使うには事前に公式サイトから利用登録する必要があります。
X-API-KEYはRESAS-API登録時に発行されるキーを指定して下さい。

感想

ReactNativeは活発に開発が行われていますが、毎週のように最新バージョンが更新されているため、開発環境の構築が面倒ですね。
今回は使わかなかったから影響ないですが、ReactNativeの0.57.3ではButtonコンポーネントを使うとAndroidシミュレータで以下のエラーが発生します。
https://stackoverflow.com/questions/52784633/i-have-some-error-when-add-button-to-my-react-native-app

もう少し安定した(悪く言えば枯れた)技術を使った方が開発も運用も楽なんですが、最近はそんなことを言っていたら取り残されちゃうから、日々勉強するしかないですね。
でも…せめてLTSがあるといいな…

開発環境の構築が終われば、シミュレータ上でポンポンとテキストなりボタンなりを配置できるから面白いです。

その他

最近、フラジャイルを読み返しました。
医療漫画はいいですね。Dr.コトー診療所を読んだ時もそうですが、泣いてしまいます。特に3巻、4巻のアミノ製薬の話が好きです、火箱ちゃん可愛い。
フラジャイルはドラマ化しているみたいなので、そのうち観てみたいです。

Read more ⟶

JavaScriptでクロージャを触ったお話


はじめに

クロージャの存在は知っていましたが、ちゃんと使ったことがなかったんで使ってみました。

クロージャの詳しい説明はmozillaが公開している以下のドキュメントにわかりやすく載っているので省略します。 MDN web docs

サンプル

1から6までの整数を返す関数に追加機能として、連続して同じ値が出ないようにしてみます。 連続して同じ値が出なくなったので、ランダム感を演出できるようになりました。
実際には結果を操作してるのでランダムとは言えなくなりましたが ^^;

まずはクロージャを使わない例です。
前回の結果を保持する変数prevNumをグローバル関数として定義しているので、関数dice()以外からもアクセスが出来てしまいます。

See the Pen random_no_closure by foresukecom (@foresukecom) on CodePen.

次がクロージャを使った例です。
こちらではprevNumdice()内で定義しているので、dice()の外ではprevNumが使えなくなりました。

See the Pen random_closure by foresukecom (@foresukecom) on CodePen.

感想

クロージャを使わなくても同じ機能は実装できますが、グローバル変数の使用を抑えられるのは嬉しいところです。 今回のサンプルのような短いプログラムではありがたみも薄くなりますが、

前回と違う乱数を生成する箇所はforifを使わずに、剰余演算を使ってワンライナーできなかと一晩悩みましたが思いつきませんでした。
もっといい感じの計算式をご存知の方がいたら教えてください。

その他

最近、地元の静岡が舞台になっているローカル女子の遠吠えの4巻が発売されました。 作者の瀬戸口みづき先生も静岡出身ということで、思わず膝を連打するネタが多いです。

ただ…この漫画を読むと静岡に帰りたくなるので、転職や引越しなどの重大イベントを控えたタイミングでは読まないほうがいいでしょう。
あー、亀まんじゅう食べたい。げんこつハンバーグ食べたい。

Read more ⟶

Vue.jsで配列を扱ったお話


はじめに

Vue.jsを使っていて、配列の中身を変更したのに画面上の値が変わらないなー、となって困ったのでメモです。

本文

ボタンを押すたびに配列に格納された数値を倍にし、リアルタイムで画面上にも表示するサンプルプログラムです。

See the Pen vue_array_ng by foresukecom (@foresukecom) on CodePen.

…このサンプルだと、ボタンを押すたびに配列の中身は更新されるのですが、画面上は変化がありません。

以下のように、配列の中身を変更する箇所を修正したら想定通りに動くようになりました。

See the Pen vue_array_ok by foresukecom (@foresukecom) on CodePen.

具体的には以下のように、要素番号を指定して配列の中身を変更しても画面上の値は変化しませんが、Vue.jsに用意されているメソッドを使えは配列の中身に応じて画面上の値も変化します。

/*失敗例*/ this.num_list[i] = this.num_list[i] * 2;
/*成功例*/ this.num_list.splice(i, 1, this.num_list[i] * 2)

公式ドキュメントにも注意事項としてちゃんと書かれていました。
JavaScriptの制限じゃ仕方ないですね(´・ω・`)

JavaScript の制限のため、Vue は配列で以下の変更を検出することはできません:
1.インデックスでアイテムを直接設定するとき。例: vm.items[indexOfItem] = newValue
2.配列の長さを変更するとき。例: vm.items.length = newLength

まとめ

公式ドキュメントを読みましょう。
内容とはまったく関係ないですが、記事の中にソースコードを埋め込みたかったのでCODEPENを初めて使ってみました。 ソースコードと実行内容をまとめて埋め込めるのは便利ですね。

その他

最近はRocket Leagueにハマっています。
車でサッカーをするという天才的発想。 FPSほどの精密な操作は求められないので、お酒を飲みながら遊ぶにはピッタリです。

ワイルドスピードやバットマンに登場する車が使えるようになるDLCも多数用意されているので、自分の気に入った車で走り回ることもできます。

Read more ⟶

GAE上でGolangを動かしてみましたよ


はじめに

GoogleAppEngine上で動くwebサービスをgolangで作りはじめました。
作り始めでつまずくことが多いので自分用の最小構成メモです。 ここで説明するwebサービスは、Ajaxで非同期通信し、Golangが返した文字列を表示するだけのものです。

環境の準備

まずは、GCPの公式ドキュメントを参考にGolang、Cloud SDKをダウンロードします。
以下のようにバージョンが表示されればOKです。

$ goapp version
go version 1.9.4 (appengine-1.9.74) darwin/amd64

ちなみに、開発にはmacOS High Sierra(10.13.6)を使用しています。

構成説明

ディレクトリ構成は以下の通りです。

├── app.yaml
├── hello.go
└── static
    ├── js
    │   └── main.js
    ├── css
    │   └── main.css
    └── index.html

この中でGAE特有のファイルはapp.yamlになります。
app.yamlリファレンスに各パラメータの説明が載ってますが、最低限のパラメータだけ書いておきます。

runtime: go #Golangを使用する場合はgoを指定
api_version: go1 #最新のバージョンを使用する場合はgo1を指定

handlers: #リクエストと実行する処理をURLパターン毎に指定
- url: /
  static_files: static/index.html
  upload: static/index.html
- url: /js
  static_dir: static/js
- url: /css
  static_dir: static/css
- url: /.*
  script: _go_app

その他のファイルについては、特別なことはしていないので説明は省略します。
各ファイルはGithubに置いてあります。

ローカル環境での実行

ローカル環境にGoogleAppEngineの開発用サーバを立ち上げるには、Cloud SDKに含まれているdev_appserver.pyを実行します。
実行時のオプションはいくつも用意されていますが、サーバを立ち上げるだけならば、以下のようにapp.yamlを指定して実行すれば問題ありません。 ※dev_appserver.pyを実行するにはPython2.xがインストールされている必要があります。

Read more ⟶

英語漫画のススメ


はじめに

最近、海外ドラマを観たりオンライン英会話を受けたりして英語を勉強しています。
しかし学生時代に英語の勉強をサボっていたので、わからない単語が多すぎて会話に付いていけず苦労しています。

単語帳なんかも買ってみたのですがすぐに飽きてしまったので、英語版HUNTER×HUNTERをKindleで買って試してみました。

とりあえず飽きずに10巻まで読み進められたので、メリット/デメリットをまとめてみます。

メリット

  • なんとなく読める
    僕は日本語版のHUNTER×HUNTERを何度も読み返しているので、英語版でも100%理解しなくても読み進めることができます。
  • すぐに買える
    大型書店でないと英語版の漫画は売っていないと思います。(少なくとも僕は売っているのを見たことがありません。) 読みたい時にすぐ買えるのは電子書籍ならではです。
  • (紙版の本と比べると)安い
    1冊だいたい850円ぐらいなので、日本語版と比べれば割高になります。 しかし、英語版HUNTER×HUNTERは紙の本では1冊1,000円ぐらいします。 翻訳コストがかかるので日本語版よりも高くなるのは仕方がありませんが、紙の本と比べて1〜2割引で買えるのはありがたい限りです。

デメリット

  • 翻訳機能が使えない
    Kindleでは漫画を画像として取り込んでいるので、セリフの検索や翻訳ができません。
    しかし先日、Google I/O 2018で写真に写っているモノをAIが認識するGoogleLensというサービスが発表されました。 KindleはAmazonのサービスなので、Googleのサービスを使うとは思えませんが、こういった技術が発展すれば漫画の中の文字も翻訳対象として扱えるようになると思います。
    最終的にはNetflixの音声や字幕のように、1冊の本を買ったら自由に言語を切り替えて読める世界になるのでしょうか。
  • 英語がすべて大文字
    理由は諸説あるようですが、アメリカンコミックではセリフが大文字で書かれていることが多いようです。 英語版HUNTER×HUNTERでは作者コメントは大文字と小文字が混ざっているのですが、セリフや説明分はすべて大文字で書かれています。 慣れの問題かもしれませんが、なかなか読みにくいものです。

今後

HUNTER×HUNTERを読み終えたら、ハガレンかドラゴンボールに挑戦予定です。
ハガレンも日本語で何度も読み返しているから大丈夫でしょう。 実はドラゴンボールをしっかりと読んだことがないので、せっかくなので教養として読んでおこうかと。
3月のライオン、よつばと、ヨルムンガンドあたりもKindleで翻訳版が出てほしいのです。

Read more ⟶

Go言語でJSONを作成したときのイージーミス


はじめに

Go言語を使って構造体をJSON形式に変換しようとしたら詰まったのでメモです。
JSON形式への変換は標準パッケージに含まれているjson.Marshalを使っています。

失敗例

こんな感じで構造体のスライスをJSONにしようとしたところ、作成されたJSONの中身が空になっていました。

成功例

原因がわからなかったので色々と試行錯誤した結果、下記のコードで想定した動きを確認することができました。 失敗例では10〜12行目の構造体のフィード名の先頭文字を小文字にしていましたが、成功例では先頭文字を大文字に変えています。

原因

ここまで書けば原因がわかる方も多いと思いますが…
Go言語では変数や関数のスコープが先頭文字列が小文字か、大文字かで判定されます。 先頭文字が大文字の場合は他パッケージからの参照が可能(いわゆるpublic)、先頭文字が小文字の場合は他パッケージから参照不可(いわゆるprivate)となります。 このルールは構造体のフィードにも適用されます。
そのため、失敗例では構造体のフィードに対してパッケージ外からアクセスすることができず、作成されたJSONが空っぽになっていました。

ちなみに

作成されるJSONのKeyを先頭小文字にしたい場合、以下のようにフィードに対してタグをつけることで任意の名前を指定することができます。

おわりに

初歩的なミスでしたが原因に気づくまで時間がかかってしまいました。 前に触ったことがあるはずなんですが…先頭文字でスコープが変化するのは慣れないと忘れちゃいますね。
コンパイルエラーとかで教えてくれないかなぁ。

Read more ⟶