OmniAICreator/Qiita-1.07M huggingface dataset:
メモ：Corsair Scimitar PRO RGBがLinux 4.9で動かなかったときの対処

BlenderやFreeCADを扱うとき、テンキーが側面についたゲーミングマウスが便利そうだから買ってみた。

- Scimitar PRO RGB 光学 MOBA/MMO ゲーミングマウス — ブラック (AP)
  - http://www.corsair.com/ja-jp/scimitar-pro-rgb-optical-moba-mmo-gaming-mouse-black-ap

でもLinux 4.9だと動かなかった。
dmesgでもエラーログがでてた。

```
[ 3155.894485] usb 1-3.3: new full-speed USB device number 10 using xhci_hcd
[ 3155.996413] usb 1-3.3: New USB device found, idVendor=1b1c, idProduct=1b3e
[ 3155.996414] usb 1-3.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 3155.996415] usb 1-3.3: Product: Corsair Gaming SCIMITAR PRO RGB Mouse
[ 3155.996415] usb 1-3.3: Manufacturer: Corsair
[ 3155.996416] usb 1-3.3: SerialNumber: 08022036AEBEA0675645A628F5001945
[ 3155.998276] input: Corsair Corsair Gaming SCIMITAR PRO RGB Mouse as /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3.3/1-3.3:1.0/0003:1B1C:1B3E.0007/input/input28
[ 3155.998442] hid-generic 0003:1B1C:1B3E.0007: input,hidraw0: USB HID v1.11 Mouse [Corsair Corsair Gaming SCIMITAR PRO RGB Mouse] on usb-0000:00:14.0-3.3/input0
[ 3155.999437] hid-generic 0003:1B1C:1B3E.0008: item 0 1 0 8 parsing failed
[ 3155.999443] hid-generic: probe of 0003:1B1C:1B3E.0008 failed with error -22
[ 3155.999480] usbhid 1-3.3:1.2: couldn't find an input interrupt endpoint
```

マウス側の識別子が壊れてるのか、そもそも新しいものなのかは専門外なのでわからない。
Linux 4.11で動くらしい。

- New Corsair Mice & Keyboards Supported By The Linux 4.11 Kernel
  - https://www.phoronix.com/scan.php?page=news_item&px=Corsair-HID-Late-4.11-Updates

でも、現時点ではDebian LinuxだとUnstableにも4.11は居ない。

パッチを作ってくださった方がいる。

- https://github.com/DamnWidget/kernel

仕方がないのでパッチを当ててカーネルのdebパッケージごと作り直す。

```sh
sudo apt-get install kernel-package libncurses5-dev fakeroot
sudo apt-get install linux-source-4.9
mkdir work
cd work
tar xvf /usr/src/linux-source-4.9.tar.xz 
git clone https://github.com/DamnWidget/kernel.git
cd linux-source-4.9
patch -p1 < ../kernel/drivers/hid/0001-HID-corsair-support-for-K65-K70-Rapidfire-and-Scimit.patch 
patch -p1 < ../kernel/drivers/hid/0002-HID-corsair-Add-driver-Scimitar-Pro-RGB-gaming-mouse.patch 
make oldconfig
make prepare
make-kpkg clean
fakeroot make-kpkg --initrd --revision=1.0.custom kernel_image kernel_headers kernel_source
cd ..
sudo dpkg -i linux-*.deb
```

カーネルをビルドするなんていつぶりだろう、、、
RubyでBase64エンコード

# RubyでBase64

参考 http://qiita.com/PlanetMeron/items/2905e2d0aa7fe46a36d4
base64_table.jsonをこちらから借ります

まずコマンドライン引数から文字列をとってきてバイナリに変換します

```
biarray = []

ARGV.each_with_index do |arg, i|
  biarray << arg.unpack("B*")
end

string = biarray.join
```

その配列をjoinさせて一つの文字列にし、6文字ごとに分割します
最後に二桁余るので0をつけます

```
binary_strings = string.scan(/.{1,6}/)

binary_strings[-1] += "0000"
```
最後にbase64変換表と照らし合わせ変換していきます
![image.png](https://qiita-image-store.s3.amazonaws.com/0/136253/2ee59bc4-35b0-167d-e3e6-b1672f929733.png)

https://gist.github.com/wakusei-meron-/d292193e35fb844c19c9
base64_table.jsonをこちらから借ります

```
file = open('base64_table.json', "r")
dictionary = JSON.load(file)
result = ""
binary_strings.each do |string|
  result += dictionary[string]
end

puts result
```

これで完成です！

最終的なプログラム

```
require 'json'

biarray = []

ARGV.each do |arg|
  biarray << arg.unpack("B*")
end

string = biarray.join

binary_strings = string.scan(/.{1,6}/)

binary_strings[-1] += "0000"

file = open('base64_table.json', "r")
dictionary = JSON.load(file)
result = ""
binary_strings.each do |string|
  result += dictionary[string]
end

puts result

```
(初心者向け)Macbookで写真のサイズを変える

Macbookで写真(jpgファイル)のサイズを変える方法です

- Finderで写真が置かれているフォルダーを開きます
![スクリーンショット 2017-06-04 9.28.20.png](https://qiita-image-store.s3.amazonaws.com/0/125842/7162dfd8-8588-a547-c206-92536cd516eb.png)

- 対象となる元のjpgファイルのサイズと確認するため、元ファイルをダブルクリックして開く 。プレビューというツールで表示されます

![スクリーンショット 2017-06-04 9.29.22.png](https://qiita-image-store.s3.amazonaws.com/0/125842/41f0fd43-0ba7-627e-78aa-1455949b842e.png)

- 画面上部の「プレビュー」メニューの「ツール」▶「サイズの調整」を開くと、元ファイル（例：pic01.jpg）のサイズを確認することができます。ここでは下記の通り、pic01.jpgのサイズは「ピクセル」という単位で測って、幅が９６０ピクセル、高さが３２０ピクセルの横長ファイルであることがわかります。このpic01.jpgを置き換える写真を用意するためには、対象の写真を同じサイズで切り出すことになります

![スクリーンショット 2017-06-04 9.32.52.png](https://qiita-image-store.s3.amazonaws.com/0/125842/46ce0f7b-d767-e7a2-d01b-828824905fb2.png)

- 「キャンセル」▶ 画面左上の赤丸ボタンで元ファイル（pic01.jpg）を閉じます
- 念のため、元になるpic01.jpgファイルをバックアップとして保存しておきます。Finderでpic01.jpgを長押しして、ファイル名が反転したら、適当な名前（例：pic01_bk.jpg)に変更しておきます
- 新しい写真ファイルを上記と同様の手順でプレビューで開きます。必要に応じて（作業を失敗してしまうなどの場合に備え）、新しい写真をコピー▶貼り付けしてバックアップを作成しておきます。
- 「ツール」▶「サイズを調整」を開き、ファイルサイズを確認します
- 表示がピクセル単位になっていることを確認し、幅を９６０ピクセルにします

![スクリーンショット 2017-06-04 9.39.39.png](https://qiita-image-store.s3.amazonaws.com/0/125842/e12624e4-5194-af5d-9945-724405c15896.png)

-スマホで撮影した写真などは縦長の場合が多いので、上記のような比率になっていることが多いです
-「OK」を押すと写真のサイズが幅９６０ピクセルに変更され、下記のような小さい表示になります

![スクリーンショット 2017-06-04 9.41.26.png](https://qiita-image-store.s3.amazonaws.com/0/125842/ca7787da-6e08-c9e0-c4e6-7c14257225cb.png)

- このままでは作業がしにくいので、いったんこの画面を閉じ、再度開き直すと画面いっぱいに表示されるようになります
- 幅９６０ピクセルに対して、高さを３２０ピクセルで切り出したいので、再度「サイズを調整」を押し、「OK」を押します。画面左上に青い点線の四角形が表示されているのを確認し、プルダウン（下向きの矢印）をクリックすると、「長方形で選択」メニューがデフォルトで選択されていることがわかります

![スクリーンショット 2017-06-04 9.44.40.png](https://qiita-image-store.s3.amazonaws.com/0/125842/5ddaa234-e9f6-506d-935c-f47ea362b75d.png)

- 写真の左の灰色の余白から、タッチトラックパッドの左側を押したまま右側をドラッグして、９６０ｘ３２０のサイズになるように画面を選択し、[command]+Cでクリップボードに保存します

![スクリーンショット 2017-06-04 9.46.25.png](https://qiita-image-store.s3.amazonaws.com/0/125842/97c9ac96-5883-d1f8-ac17-e9e06fdf1b59.png)

-「ファイル」▶「クリップボードから新規作成」を選ぶと、前のステップでクリップボードに保存した画面が新しいファイルとして表示されます

![スクリーンショット 2017-06-04 9.50.39.png](https://qiita-image-store.s3.amazonaws.com/0/125842/b48ca4b6-f0a5-cb82-c6a5-24222b94b9f7.png)

- 画面左上の赤丸ボタンを押すと、ファイルの保存画面になるので、ファイル名や保存する場所、ファイルの種類（JPGなど）を指定して保存します。先頭の「名前」欄の右側の下向きの矢印をクリックすると、保存先を指定する画面を表示させることができます

![スクリーンショット 2017-06-04 9.52.59.png](https://qiita-image-store.s3.amazonaws.com/0/125842/e1065a39-d98a-dbe0-55fb-f181923b52dc.png)

# 関連サイト
[(初心者向け)html5upを使ってみる](http://qiita.com/egplnt/items/2643c299d8540f749181)
SourceTree > 特定の人しか最新アップデートを利用できない

```txt:動作環境
Windows 7 Pro (32bit)
SourceTree v2.1.2.4
```

https://jira.atlassian.com/browse/SRCTREEWIN-7056

SourceTreeのバグ対策バージョンが特定の人にしか取得できないことが記載されている。

> Jon White
> @Geoff it's because of SourceTree's ridiculous "staged rollout" policy. A random selection of users get it early (effectively, involuntary beta testers). Everyone else has to wait.

自分が最新版を取得できたのはたまたまだったのか。

最新版のソフトウェアに自信がなく、embugの影響を減らすためにこういう仕組みを使っているのだろうか?

リリース前にソフトウェアをきちんとテストする仕組みができていないのかもしれない。

そうであれば、最新版を追うのは危険かもしれない。

ソフトを起動して「最新版を取得しますか？」というダイアログが表示されたとき、それがベータバージョンかもしれないというのはサービスとして違和感を感じる。
ダウンロードサイトで「ベータバージョン」という記載がある場合は、ユーザはベータバージョンを意識して利用できる。
Amazon Fire 2015,2017 / Fire HD8 2016,2017 にGoogle PlayStoreをインストールする方法


# Fire / Fire HD8にGoogle Playストアをインストールするには
Amazonのストアはあまりにもアプリケーションが少なすぎる、というわけでGoogle PlayStoreを導入してみました。
※内容はたまにアップデートします。
- root化不要
- PC接続不要で、Fire端末単体でインストールすることが可能
- "Amazon Fire Playストア"で検索するとTOP辺りに出てくる"rootjunky"などの、PCをUSB接続する等の複雑な手順は不要

- 参考URL1: http://blog.notfaqs.com/2017/05/android-install-google-play-store-on.html
- 参考URL2： https://forum.xda-developers.com/amazon-fire/general/how-to-install-google-play-store-fire-t3486603
- 追記：Fire HD8 (2017)で動作確認報告をいただきました。
- 追記：Fire HD 16G(2017)で動作確認しました (2017/07/13)
- 追記：Google Play Serviceを11.7.44にアップデート(2017/11/12)
- FireHD8 (2016)にて64bit版Google Play Services 11.7.44 (240-173432861)の動作を確認
- 以前のリンクが旧apkにリンクされたままだったので修正(ごめんなさい)


# 事前準備
- 好みのファイルマネージャーアプリをAmazonアプリストアからインストールしておいて下さい (File Commander, Yahooファイルマネージャー, ES File Manager等)
- 設定>セキュリティ>不明ソースからのアプリ をON にします。
- ストレージの空き容量は十分に開けておいて下さい。

# ダウンロード
Silkブラウザでもなんでもいいですが、以下のサイトの[DOWNLOAD APK] をタップしてapkファイルを適当な場所にダウンロードしてください。保存した場所は覚えておきましょう。(Silkブラウザの標準では/storage/emulated/0/Download に保存されます)


- インストールする順番があるので、保存する際にファイル名の頭に1-,2-,3-,4-と付けるとよりわかりやすくなります

以下のファイルはapkmirrorへのリンクです。
1.   [Google Account Manager, 5.1-1743759] (http://www.apkmirror.com/apk/google-inc/google-account-manager/google-account-manager-5-1-1743759-release/google-account-manager-5-1-1743759-android-apk-download/)
2.   [Google Services Framework, 5.1-1743759] (http://www.apkmirror.com/apk/google-inc/google-services-framework/google-services-framework-5-1-1743759-release/google-services-framework-5-1-1743759-android-apk-download/)
3.   [Google Play Services, 11.7.44 (230-173432861) ] (https://www.apkmirror.com/apk/google-inc/google-play-services/google-play-services-11-7-44-release/google-play-services-11-7-44-230-173432861-android-apk-download/) ※fireHD(2015/2017)用
　※ FireHD8(2016/2017)は以下の64bit版を使用して下さい
　 [Google Play Services 11.7.44 (240-173432861) ] (https://www.apkmirror.com/apk/google-inc/google-play-services/google-play-services-11-7-44-release/google-play-services-11-7-44-240-173432861-android-apk-download/)
4.    [Google Play Store, 8.4.19.V-all [0] [FP] 175058788 ] (https://www.apkmirror.com/apk/google-inc/google-play-store/google-play-store-8-4-19-release/google-play-store-8-4-19-v-all-0-fp-175058788-android-apk-download/)



# インストール
- 上記のファイルをダウンロードして適当な場所(Downloadsなど)に保存。
- 好みのファイラーから上記apkファイルを順にタップしてインストール
- AccountManager -> Services Framework -> Play Services -> PlayStoreの順です
- ファイル名だと以下の順番
    1. com.google.android.gsf.login_xx.apk
    2. com.google.android.gsf_xx.apk
    3. com.google.android.gms_xx.apk
    4. com.android.vending_xx.apk
- 4つのapkのインストールが終わったら、念のため再起動しておきましょう
- 再起動が終わったら、Google設定アプリでGoogleアカウントを設定
- have fun!

## 備考
- ~~Google Play Store 7.9.30.Q-all [0] [PR] 157075589
はまだ試せていません~~ 8.4.19.V-all [0] [FP] 175058788で再インストールして動作確認ok
- Google開発者サービス(重い)が動くので、動作がちょっと緩慢になります
- インストール後は自動的にアップデートされるようになります。
- 多分 fireHD10も上記64bit版で動くはず
[備忘録]Go言語のGOPATHやパッケージについて

すでにインターネット上に日本語の情報がいろいろありますが、自分用に備忘録として書き溜めておきます。

# GOPATHって何？
詳しくは [この記事](http://qiita.com/yuku_t/items/c7ab1b1519825cc2c06f#gopath) かgo helpを参照のこと。

```
$ go help gopath
```

外部からパッケージをビルドしたりインストールするのに必要。
go get を実行した際に参照され、 $GOPATH/src 以下にgetしたデータが入る。

例えば、以下のコマンドを実行すると、$GOPATH/src に golang.org/x/net/html のディレクトリができ、htmlパッケージに関連するデータが入る(ちなみに golang.org/x/net/html パッケージはHTMLのパースなどの機能をサポートするパッケージ)。

```
$ go get golang.org/x/net/html
```

$GOPATH が通っている箇所に入ったパッケージは、以下のようにgolangのソースファイルでインポートすることが可能。

```go
import "golang.org/x/net/html"
```

# GOPATHはどこに設定すれば良い？
どこでも良い。
調べた限りでは $HOME/go に設定している人が多そう。

```bash
$ export GOPATH=$HOME/go
```

# GOPATHは複数指定できるの？
できる。ただし1つ目に指定したもの以外は無効な場合がある。

例として、以下のようにGOPATHを指定したとする。

```bash
$ export GOPATH=$HOME/go:$HOME/golang:$HOME/workspace/go
```

指定した全てのGOPATHが有効なのは、Goコンパイラが外部のパッケージを探す場合のみである。
つまり、import文で指定したパッケージはGOPATHが通っている箇所であればコンパイラが見つけることができる(コンパイルエラーにならない)。
$HOME/workspace/go/src 以下に配置したパッケージはインポートすることができる。

逆に1つ目のGOPATHしか有効にならないのは、go get により外部のパッケージをダウンロード・インストールする場合である。
go get コマンドを使用すると外部のパッケージは必ず1つ目に指定した $HOME/go にインストールされる。

ソースは以下。
[そろそろ真面目に Golang 開発環境について考える — GOPATH 汚染問題](http://qiita.com/spiegel-im-spiegel/items/73ebc684b5807277b7e2#gopath-%E6%B1%9A%E6%9F%93%E5%95%8F%E9%A1%8C)

# 外部パッケージのインポートに相対パスを使っても良い？

```go
import "./foo"
import "../bar/baz"
```

以下の理由により非推奨。

- コンパイルのたびにパッケージ化するため、コンパイルが遅くなる
- go getが使えない

ソースは以下。
[Golangで自分自身で定義したパッケージをインポートする方法あれこれ](http://qiita.com/shopetan/items/eddcacec21cc7ea274f9#%E3%81%9D%E3%81%AE3%E9%9D%9E%E6%8E%A8%E5%A5%A8)

また、GOPATH配下では上記のような相対パスによるインポートは認められない。
PowerShellから仮想Linuxマシンにsshで接続する


# モチベーション
今までvagrantで仮想マシン立ててputtyでssh接続していた。
接続するたび思っていたのが**PowerShellでvagrant upしてからputty立ち上げるのが面倒**ということ。
調べたらPowerShellからもssh接続できるとのことだった。

こちらを参考に
https://www.eaton-daitron.jp/techblog/4627.html

# OpenSSH-Winの設定
https://github.com/PowerShell/Win32-OpenSSH/releases
からzipをダウンロード→展開→任意の場所に配置→パスを通す

これだけでvagrant sshできるようになる。
DataTimeを拡張して日本語の曜日を返すようにする


| format 文字	| 説明					| 戻り値の例	|
|:---			|:---					|:---			|
|X				| 曜日。フルスペル形式	| 月曜日		|
|x				| 曜日。1文字			| 月			|



```php:DateTimeEx.php
<?php
namespace LibEx;

class DateTimeEx extends \DateTime {
	protected $timezone = NULL;
	protected static $weekdayName = [
		'日曜日',
		'月曜日',
		'火曜日',
		'水曜日',
		'木曜日',
		'金曜日',
		'土曜日',
		'日曜日',
	];

	public function __construct($time = "now", \DateTimeZone $timezone = NULL) {
		$this->timezone = ($timezone === NULL) ? (new \DateTime())->getTimezone() : $timezone;
		parent::__construct($time);
		$this->setTimezone($this->timezone);
	}

	public function format($format) {
		$format = preg_replace("/X/", static::$weekdayName[parent::format('N')], $format);
		$format = preg_replace("/x/",
					mb_substr(
						static::$weekdayName[parent::format('N')], 0, 1, mb_detect_encoding(static::$weekdayName[parent::format('N')])
					),
					$format
				);
		return parent::format($format);
	}
}
```
### 使い方

```php
(new \LibEx\DateTimeEx())->format('Y年m月d日(x)') // => 2017年06月04日(月)

(new \LibEx\DateTimeEx("@1495983600"))->format('Y年m月d日(x)') // => 2017年05月29日(月)
```

### 補足
namespace は環境にあわせて適当に修正して下さい。

UNIXタイムを渡すと、DateTimeのコンストラクタに渡したタイムゾーンを無視するので、setTimezone()で設定し直しています。
> http://www.php.net/manual/ja/datetime.construct.php
注意:
$time パラメータが UNIX タイムスタンプ (@946684800 など) であったりタイムゾーンつきで指定した場合 (2010-01-28T15:00:00+02:00 など) は、 $timezone パラメータや現在のタイムゾーンは無視されます。

エンコードがUTF-8以外だと、mb_substr()した時に文字化けするので、わざわざ検出して指定するようなことをしています。
【要件定義】ドキュメント管理ツールを作ってみる【編集中】



▪️【計画】ドキュメント管理ツールを作ってみる
http://qiita.com/newsour/items/4e81e7f80329234493b7

DoCCS(ドックス)
Document Creation and Configuration management System

【目的】
 プロジェクトのドキュメント作成及び管理コスト削減のため

要件定義〜テストまでのドキュメントについて作成からレビュー、構成管理まで一括して行う。

【業務要件】
全ての項目には共通して以下のフォーマットで記述する
・工程のID
・要件の機能名(基本設計以降は紐付く工程のID)
・作成者
・作成日
・更新者
・更新日
・承認者

▪️新規プロジェクトの場合

要件定義書の作成
以下の項目を記載する
・機能に対してどの業務要件をシステムで解決するのか(範囲)
・機能に対してのmust,want,never
・要件詳細

レビュー
※後述

基本設計書の作成
機能設計
 単体機能毎にシステムがどこからどんな条件で何を登録/更新/参照/削除するか記載する

画面設計
　画面ごとのデザイン、イベント、紐づく機能を記載する

API設計
　・GETかPOSTか
　・環境ごとのURL
　・リクエスト・レスポンスともに物理名、論理名、型、サイズ、範囲、取得元を記載する
　・エラーについての記載
　・サンプル

バッチ設計
　・機能
　・頻度、タイミング
　・エラーについての記載

構造設計
　DB
　　テーブル物理名
　　テーブル論理名
　　テーブル概要
　　カラム物理名
　　カラム論理名
　　型
　　サイズ
　　外部キー
　　必須か否か
　　インデックス
　　データ削除周期
　キャッシュ
　　キー（ルール）
　　バリュー
　　期限
　　
レビュー
　コメント
　承認　

詳細設計書の作成
　基本設計に加えて必要であればシーケンス・フローチャート
　レビュー

テスト方針書の作成
レビュー

単体テスト仕様書の作成
レビュー

結合テスト仕様書の作成
レビュー

総合テスト仕様書の作成
レビュー

本番テスト仕様書の作成
レビュー

▪️機能追加の場合
上記フロー
＋影響範囲のドキュメント修正
レビュー

▪️不具合修正の場合
影響範囲のドキュメント修正
レビュー


【機能要件】
■設計者登録機能
　概要　：設計者としてシステムにアカウント登録をする
　Must　：メールアドレスに対して１アカウント
　Want　：Slackアカウントの紐づけ
　Never：メールアドレスの重複

 登録は以下を入力
　・ID（メールアドレス）
　・PW　8文字以上(半角英数字のみ)
　・名前　(半角英字、全角ひらがな、全角カタカナ、漢字)

■権限管理機能
　概要　：アカウント毎に閲覧、編集、出力の権限を管理する
　Must　：アカウント毎に閲覧、編集、出力の権限を管理する
　Want　：新着アカウントの通知が出るようにする
　Never：管理者以外操作ができてはいけない

　権限は以下の通り
　　・システム管理者（クライアントの追加ができる）
　　・ドキュメント管理者（クライアントの管理者、PJ追加、個人にPJのドキュメントの参照権限、編集権限、出力権限の操作が可能）
　　・設計者（ドキュメント管理者により与えられた権限でシステムを利用することが可能）


■ログイン機能
　概要　：IDとPWを使ってシステムにログインする
　Must　：IDとPWを使ってシステムにログインする
　Want　：PWの再発行
　Never：別のユーザへログインする。自分の権限でログインされる

　ログインによってシステムを利用できる。セッションは最終利用から１時間

■プロジェクト選択機能
　概要　：自分の権限で表示できるPJ一覧が出てくる
　Must　：自分の権限で表示できるPJ一覧が出てくる
　Want　：レビュー依頼、ユーザが作成途中のドキュメントの表示
　Never：自分の権限で表示できないPJ一覧が出てくる

　ログイン後ユーザの権限にあったPJ一覧を表示する
　ドキュメントを閲覧する、作成する、出力するが選択できる
　
■ドキュメント作成機能
　概要　：ドキュメントに必要な各項目を決まったフォーマットに入力することができる
　Must　：入力内容が保存されること。関連ドキュメントが紐づけられること。
　Want　：下書き状態で保存できるようにする。閲覧、出力に制限をかけられるようにする。
　Never：保存されない。間違えたものを紐づけする。

　編集権限がある場合
　業務用件を満たすフォーマットの項目ごとに入力ができる
　フローチャートなどの描画はシステムでは行わない
　画像を入稿、表示ができるといい

■ドキュメント閲覧機能
　概要　：作成したドキュメントを閲覧することができる
　Must　：作成したドキュメントを閲覧することができる。紐づいているドキュメントを開くことができる。
　Want　：コメントできるようにする
　Never：権限がないのに見れてしまう。出力できてしまう。

　閲覧権限がある場合
　ドキュメントを閲覧、欄外にコメントをすることができる
　コメントはメモと指摘に分かれ、指摘については反映後完了にできる
　編集権限がある場合、ドキュメントの修正ができる
　レビュー者として閲覧した場合、承認することができる

■ドキュメント修正機能
　概要　：作成したドキュメントを修正することができる。
　Must　：作成したドキュメントを修正することができる。
　Want　：下書き状態で保存できるようにする。
　Never：保存されない。最新ではないものが開く。

　編集権限がある場合、ドキュメントの修正ができる
　修正の差分は赤字で表示される

■ドキュメントレビューリクエスト機能
　概要　：ドキュメントの作成、修正に対してレビュー依頼を投げる
　Must　：ログインした際に、レビュー依頼のメッセージが出ること
　Want　：レビュー依頼の際にSlackに通知が行くこと
　Never：別の人に通知がいく。メッセージがでない。

　作成、修正完了後にレビューを依頼することができる
　レビュアーには通知がいく

■ドキュメント検索機能
　概要　：ドキュメントをID、キーワード、PJで検索できるようにする。
　Must　：対象のドキュメントがでてくる
　Want　：ドキュメント名、本文から検索できるようにする
　Never：権限がないのに出てきてしまう

　権限の範囲内で閲覧できるドキュメントをキーワードをもとに検索できるようにする
　検索したドキュメントに紐づくドキュメントをツリーで出すことができる

■ドキュメント出力機能
　概要　：ドキュメントをPJ単位、工程単位、ドキュメント単位で出力できるようにする
　Must　：標準の印刷画面を出す
　Want　：範囲調整をしてPDFで出力
　Never：権限がないのに出力できてしまう
　
　出力権限がある場合、ドキュメントを出力できるようでする
three.jsで画像を表示する最小サンプル

three.jsを使ってただ画像を表示したいだけなのに、手間取ったのでメモです。three.jsのバージョンは85です。

まずサーバーをたてます。簡単な方法としては、コードのあるディレクトリで以下のコマンドを実行します。サーバーをたてた上でアクセスしないとエラーになります。([参考](http://qiita.com/mo49/items/3aff014a29f3adeded5b))

```
$ php -S localhost:9000
```

そして、以下の通りにコードを書いて、ブラウザで`localhost:9000`にアクセスします。

```index.html
<html>
	<head>
		<meta charset=utf-8>
		<title>Algorithmic Visualization</title>
		<style>
			body { margin: 0; }
			canvas { width: 100%; height: 100% }
		</style>
	</head>
	<body>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>
		<script src="show_image.js"></script>
	</body>
</html>
```

```show_image.js
// シーン
var scene = new THREE.Scene();

// レンダラー
var renderer = new THREE.WebGLRenderer({alpha:true, antialias: true });
renderer.setClearColor(0xffffff,1);
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1);
document.body.appendChild( renderer.domElement );

// カメラ
var camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set(0, 0, 10);

// ライト
var light = new THREE.AmbientLight( 0xffffff );
scene.add( light );

// 画像を読み込む
var texture = new THREE.TextureLoader().load('path/to/file.jpg',
(tex) => { // 読み込み完了時
    // 縦横比を保って適当にリサイズ
    const w = 5;
    const h = tex.image.height/(tex.image.width/w);

    // 平面
    const geometry = new THREE.PlaneGeometry(1, 1);
    const material = new THREE.MeshPhongMaterial( { map:texture } );
    const plane = new THREE.Mesh( geometry, material );
    plane.scale.set(w, h, 1);
    scene.add( plane );
});

// レンダリング
function render() {
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}
render();
```
オープンフィールドなRPG風ゲームを作る 3ワールド目

# キャラクターを動かす準備

シーン内に必要なものを配置してフィールドとなるシーンを作成します

![20170603_004.PNG](https://qiita-image-store.s3.amazonaws.com/0/184526/afdee31d-8e5b-9463-b79b-c68f79dceb6e.png)
こんな感じ

GameObjectにたくさんコンポーネントをつけて動かすよりも、
1つのコンポーネント内でクラスを作成しGameObjectを動かしたほうが、
より良いパフォーマンスが出るので今回はシーン内のRootオブジェクトにのみコンポーネントをくっつけて、あとはMonoBehaviourを継承していないクラスで作成していこうと思います
こうすることで、スクリプトの更新順も管理しやすくなります

今回用意するスクリプトは以下の2つ
- FieldScene.cs
　フィールド内のオブジェクトを制御するクラス
- Player.cs
　プレイヤーキャラクターを制御するクラス

# プレイヤーが一定時間ごとにジャンプするようにする

まずはキャラクターのアニメーション制御を行えるようにしていきます
いきなり移動周りとか作り始めると大変なので、一定時間ごとに違う動きをするような簡単なところからスタート

必要な情報は
- プレイヤーのアニメーション制御 (Animator)
- ジャンプするまでの時間をカウントする何か
で大丈夫そうです

実際のコードはこんな感じ

``` Player.cs
using UnityEngine;

public class Player
{
	//!	@brief	プレイヤー作成情報
	public struct PlayerCreateParam
	{
		public GameObject	model;		//!< モデル
		public Animator		anim;		//!< アニメーション制御
	}

	private const float				SP_STAY_ANIM_TIME		= 5.0f;									//!< 特殊待機モーションを再生するまでの時間
	private static readonly int		ANIM_TRIG_SP_STAY		= Animator.StringToHash("spStay");		//!< 特殊待機モーション再生アニメーショントリガー

	//!	@brief	作成
	//!	@param	[in]	param	プレイヤー作成情報
	//!	@return	なし
	public void create(PlayerCreateParam param)
	{
		_model	= param.model;
		_anim	= param.anim;
	}

	//!	@brief	初期化
	//!	@return	なし
	public void initialize()
	{
		_stayTimer = SP_STAY_ANIM_TIME;
	}

	//!	@brief	更新
	//!	@return	なし
	public void update()
	{
		_stayTimer -= Time.deltaTime;
		if( _stayTimer < 0.0f ) {
			_stayTimer = SP_STAY_ANIM_TIME;
			setAnimTrigger(ANIM_TRIG_SP_STAY);
		}
	}

	//!	@brief	アニメーショントリガーの設定
	//!	@param	[in]	id		パラメーターID
	//!	@return	なし
	private void setAnimTrigger(int id)
	{
		if( _anim == null ) return;

		_anim.SetTrigger(id);
	}

	private GameObject		_model		= null;		//!< プレイヤーモデル
	private Animator		_anim		= null;		//!< アニメーション制御

	private float			_stayTimer	= 0.0f;		//!< 待機時間タイマー
}
```

シーンを制御するコードはこんな感じ

```FieldScene.cs
using UnityEngine;

//!	@brief	フィールドシーン
public class FieldScene : MonoBehaviour
{
	//!	@brief	開始処理
	//!	@return	なし
	void Start()
	{
		if( _playerModel != null ) {
			_player.create(new Player.PlayerCreateParam() {
				model	= _playerModel,
				anim	= _playerModel.GetComponent<Animator>(),
			});
			_player.initialize();
		}
	}
	
	//!	@brief	更新処理
	//!	@return	なし
	void Update()
	{
		_player.update();
	}

	[SerializeField] private GameObject		_playerModel	= null;				//!< プレイヤーモデル

	private Player							_player			= new Player();		//!< プレイヤー
}
```

これで、プレイヤーキャラクターが一定時間ごとにジャンプするようになりました

次回はプレイヤーキャラクターが移動等もできるように状態管理を作っていきます

# Unity-Chan LICENSE

![Light_Frame.png](https://qiita-image-store.s3.amazonaws.com/0/184526/680cc8fc-1936-b829-c40a-911bdaba35cd.png)
COM(Component Object Model)についてふわっと学習していく その2 本当に言語非依存なのか？

#前回
[その1 導入編](http://qiita.com/mintcandy/items/979a4a2669c8fc1f4f2f)　
導入編ということで、とりあえず理屈は置いておいてCOMを使ってみる、
ということを行いました。

今回は、COMが「**特定の言語に依存しない**」という点に着目して、
いろんな言語でCOMを呼び出してみたいと思います。

やることは前回と同じ、IEの起動です。

# PHP

```PHP:ComTest.php
<?php
	$ie = new COM("InternetExplorer.Application");
	$ie->Visible = true;
?>
```

これだけです。
呼び出し方はVBSとほぼ同じですね。

PHPではCOMクラスが予め用意されているので、追加のパッケージ等は必要ありません。
http://php.net/manual/ja/class.com.php

# Python

```Python:ComTest.py
import win32com.client
ie = win32com.client.Dispatch("InternetExplorer.Application")
ie.Visible = True
```

こちらもほぼ同じです。
しかし、COM呼び出し機能はデフォルトでは入っていないので、追加でインストールする必要があります。
https://sourceforge.net/projects/pywin32/

# C＃

```C#:Program.cs
using SHDocVw;
namespace ComTestByCSharp
{
    class Program
    {
        static void Main(string[] args)
        {
            InternetExplorer ie = new InternetExplorer();
            ie.Visible = true;
        }
    }
}
```

SHDDocVw名前空間のクラス、インターフェースを使用するために
参照に「Microsoft Internet Controls」を追加する必要があります。

参照マネージャ=>COM=>タイプライブラリから追加できます。

タイプライブラリについて、マイクロソフトのドキュメントでそれらしいものが
見つけられなかったのですが、いろいろなところをググッた結果、
要するにCOMのインターフェース定義が書かれているファイルのことのようです。

これを用いることで、COMで公開されているインターフェースを
呼び出し側の「型」として使用できるようになるわけですね。

VBS, PHP, Pythonの実装例では文字列からオブジェクトを生成しているので、
このあたりの仕組みが異なるようです。

# VB.NET

```vb.net:Module1.vb
Imports SHDocVw
Module Module1
    Sub Main()
        Dim ie As InternetExplorer = New InternetExplorer
        ie.Visible = True
    End Sub
End Module
```

C#の兄弟言語、VB.NETでも実装方法は変わりません。

# C++
```c++:ComTest.cpp
#include "stdafx.h"
#include <atlbase.h>
#include <exdisp.h>
#import "C:\WINDOWS\system32\shdocvw.dll"
int _tmain(int argc, _TCHAR* argv[])
{
	CoInitialize(NULL);
	{
		IWebBrowser2Ptr ie;
		CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (VOID**)&ie);
		ie->put_Visible(VARIANT_TRUE);
	}
	CoUninitialize();
	return 0;
}
```

\#importディレクティブを使用してタイプライブラリを読み込んでいます。
https://msdn.microsoft.com/ja-jp/library/8etzzkb6.aspx

これにより、C#やVB.NETと同様、固有のクラスやインターフェースが使えるようになるわけですね。
しかし、C#やVB.NETと比べるとコードがやや複雑です。

まず、COMを利用する前にCOMの初期化、利用後におよび初期化解除が必要です。
（CoInitialize(), CoUninitialize()）

IWebBrowser2PtrはIWebBrowserインターフェースのスマートポインタです。
IWebBrowserを直接使用するのではなく、スマートポインタを使うようです。
（使わなくてもできるようですが、未調査）

また、CoUninitialize()はCOMのオブジェクトが未開放の状態で実行するとエラーになるので、
ローカルスコープを一段掘ることで、
CoUninitialize()呼び出しの前にIWebBrowser2Ptrが解放されるようにしています。

CoCreateInstance()で実際のオブジェクトを生成するわけですが、引数が多いです。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms686615(v=vs.85).aspx

rclsid => クラスのID
pUnkOuter => とりあえずNULLで問題ないようです（未調査）
dwClsContext => とりあえずCLSCTX_LOCAL_SERVERで問題ないようです（未調査）
riid　=> インターフェースのID
*ppv => 生成されるオブジェクト
（戻り値はHRESULT型になっているので、オブジェクトは参照渡しで取ってくるようになっているようです）

第二、第三引数についてはよくわかっていませんが、
今後余裕があったらちゃんと調査するかもしれません。

よくわかっていないところが多くなってきましたね。
C++で特にわからないところが多いのは、よりCOMっぽい実装になっているからかと推測しています。
（他の言語ではうまくラップしているので見えていない部分をきちんと実装しないといけない）

今回の目的は「とりあえず使えること」ですので、難しいところは一旦スルーします。

# まとめ

実装方法にいくつかのパターンがありましたが、
様々な言語で実装できることを確認できました。

# 次回

[その3 COMコンポーネント実装](http://qiita.com/mintcandy/items/1833534ed6e663c16914)　
次回は、これまで「呼ぶ側」に着目していましたが、
いよいよ「呼ばれる側」を作ってみたいと思います。
phpMyAdmin install

AWS Mysql ver7.0
phpMyAdmin install中に以下のようなエラーメッセージがでます。

対処方法をご存知の方がおられましたら回答をお願いいたします。

sudo yum install -y phpMyAdmin

Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main                                                | 2.1 kB     00:00
amzn-updates                                             | 2.3 kB     00:00
1004 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package phpMyAdmin.noarch 0:4.0.10.19-1.el6 will be installed
--> Processing Dependency: php(language) < 7 for package: phpMyAdmin-4.0.10.19-1.el6.noarch
--> Processing Dependency: php(language) >= 5.2.17 for package: phpMyAdmin-4.0.10.19-1.el6.noarch
    ********** 略 **********
--> Running transaction check
---> Package php-common.x86_64 0:5.3.29-1.8.amzn1 will be installed
---> Package php-php-gettext.noarch 0:1.0.12-1.el6 will be installed
---> Package php-tcpdf.noarch 0:6.2.13-1.el6 will be installed
--> Processing Dependency: php-tidy for package: php-tcpdf-6.2.13-1.el6.noarch
--> Processing Dependency: php-posix for package: php-tcpdf-6.2.13-1.el6.noarch
      ********** 略 **********
--> Processing Conflict: php56-common-5.6.30-1.133.amzn1.x86_64 conflicts php-common < 5.5.22-1.98
--> Finished Dependency Resolution
Error: php70-common conflicts with php-common-5.3.29-1.8.amzn1.x86_64
Error: php56-common conflicts with php-common-5.3.29-1.8.amzn1.x86_64
Error: php56-process conflicts with php-process-5.3.29-1.8.amzn1.x86_64
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest
ajaxが常にエラーに入る原因と解決法

ちゃんと実行したのになぜか常にajaxのerrorのところに入ってしまう経験ありませんか
調べたら、それはjquery 1.4以降だと、jsonの返り値に対して厳しくなったせいです。
つまり、入ったJSONは正しい形じゃなかったら、全部エラーとして処理する

こんな風に書けばいい

```正解.php
  return json_encode(array("success"=>true));
  //or
  return json_encode(array("success"=>"true"));
```

他パラメーター増やしても良いが、必ず`"success"=>true`を入れること
gitをwindowsで使用する場合にsshでcloneする方法

bitbucketを用いてリポジトリを管理しているのだが少し躓いたのでメモしておく。
1. .sshディレクトリを C:\Users\userName\以下に作成する。(userNameは自分のホームディレクトリ）ここでドットが先頭に付くディレクトリは新規ディレクトリ作成で.ssh.と最後にドットを余分に付けることにより作成することができる。
2. configという名前でファイルを作成してそこに以下のように記述。

```
Host bitbucket.org
  IdentityFile C:\Users\userName\.ssh\id_rsa_bitbucket.ppk
```

(id_rsa_bitbucket.ppkは秘密鍵)
これで git clone git@bitbucket.org:hogehoge/hogehoge.git
などとやればリポジトリからファイルを取得することができる。結局ディレクトリの作成方法とPathの書き方以外はLinux/Macと同じである。

因みにうまくIdentityFileのPathが設定されていないとgit cloneした時に下記のようなエラーが表示された。

```
The authenticity of host 'bitbucket.org (2401:1d80:1010::152)' can't be established.
RSA key fingerprint is SHA256:zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1A.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'bitbucket.org,2401:1d80:1010::152' (RSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```
perlで switch vs when vs if


#まえがき
Perlには他の多くの言語にはあるSwitch文が実装されておらず、モジュールとして拡張することで一応書けなくもないが、速度が遅かったりバグが見つかったりなどが理由で利用が推奨されていないということは知識として知ってはいたが、実際に使ったことがなかったので今回物は試しにどれくらいの遅いものなのか調べてみた。

#準備
まずは `use Switch;` を使えるようにしましょう。

```sh
$ cpanm Switch
--> Working on Switch
Fetching http://www.cpan.org/authors/id/C/CH/CHORNY/Switch-2.17.tar.gz ... OK
Configuring Switch-2.17 ... OK
Building and testing Switch-2.17 ... OK
Successfully installed Switch-2.17
1 distribution installed
```

そしてどうやらPerlでもSwitch文はデフォで使える様になっていたことを知る。
ただし、switchはgiven、caseはwhenとして書く決まりのようだ。
（今まで全部if~elseで書いてたのは一体…）

こいつの速度も一緒に調べてみる。

#実験

```perl
use strict;
use warnings;
use Switch;
use feature "switch";
use Benchmark qw( :all );
use constant COUNT => -1;

my @subjects = ( "kokugo","suugaku","rika","shakai","eigo" );

my $switch_case = sub {
    for my $subject (@subjects) {
        switch ($subject) {
            case (/kokugo/) { return "Japanese"; }
            case (/suugaku/) { return "Math"; }
            case (/rika/) { return "Scinence"; }
            case (/shakai/) { return "Social Studies"; }
            else { return "something else"; }
        }
    }
};

my $given_when = sub {
    for my $subject (@subjects) {
        given ($subject) {
            when (/kokugo/) { return "Japanese"; }
            when (/suugaku/) { return "Math"; }
            when (/rika/) { return "Scinence"; }
            when (/shakai/) { return "Social Studies"; }
            default { return "something else"; }
        }
    }
};

my $if_else = sub {
    for my $subject (@subjects) {
        if    ($subject =~ /kokugo/) { return "Japanese"; }
        elsif ($subject =~ /suugaku/) { return "Math"; }
        elsif ($subject =~ /rika/) { return "Science"; }
        elsif ($subject =~ /shakai/) { return "Social Studies"; }
        else { return "something else"; }
    }
};

cmpthese (COUNT,{
        switch_case => $switch_case,
        given_when => $given_when,
        if_else => $if_else
});

```

#結果

```sh
$ perl switch_vs_given.pl
switch_case  149593/s          --        -95%        -97%
given_when  2880703/s       1826%          --        -41%
if_else     4871702/s       3157%         69%          --
```

switch文…こんなに遅いのかってくらい遅い…。
そして、一応代わりに実装されたというgiven_whenですらこの速度。
恐るべし、if_else文…。
オープンフィールドなRPG風ゲームを作る 2ワールド目

# キャラクターを準備する

今回はプレイヤーが操作するキャラクターを作成していこうと思います

かわいいキャラクターのを使ったほうが作っているときのテンションが上がるので、
プレイヤーキャラクターはSDユニティちゃんにします

公式サイトからSDユニティちゃんをDLしてきてプロジェクトに追加します
が、SDユニティちゃんにはデフォルトでたくさんのコンポーネントがついているので、
オリジナルなゲームを作っていく上で不要なものもあります

今回はユニティちゃんを扱いやすいように編集するためのプロジェクトを作成し
そこで作業をしていきます

## SDユニティちゃんを扱いやすい状態に加工していく

ここからはテスト用ブランチで作業をします

SDユニティちゃんのテスト用のプロジェクトを作成したら、
fbxをもとに新たなプレファブを作成します

アニメーションfbxには、今は不要なイベントが設定されているので、
fbxのコピーを作成し、イベントを削除していきます
![20170603_002.PNG](https://qiita-image-store.s3.amazonaws.com/0/184526/91da2134-0095-89c8-fe5d-cd4dabcb29e5.png)
↑こーゆーやつ

マテリアルやシェーダーはとりあえずデフォルトのものを使用
Animatorはとりあえず「待機状態」っぽいアニメーションのみのものを作成する
![20170603_003.PNG](https://qiita-image-store.s3.amazonaws.com/0/184526/9fd85407-383b-8f3a-4d74-9e6b9867626f.png)
こんな感じ

準備ができたら本流プロジェクトに必要なものを持っていって
本流ブランチにマージして完了

次回はSDユニティちゃんを動かす準備をしていきます

# Unity-Chan LICENSE

![Light_Frame.png](https://qiita-image-store.s3.amazonaws.com/0/184526/75bb0d24-43a0-532a-1ea2-dc08d0b395cb.png)
【書評】経験ゼロでもできるプログラミング現場の単体テスト（続編その１〜JUnit〜）

先日の初めての投稿から数週間、次の投稿をしてみました。
（先日の投稿：http://qiita.com/takumi_links/items/006777e9d5a29221dab0）

こないだ書評した「経験ゼロでもできるプログラミング現場の単体テスト」ですが、個人的に全てのサンプルを動かしてみた訳ではなかったのでイマイチ定着が薄かった…ということで、続編でもう少し単体テストについて掘り下げてみたいと思います。

#■ Javaエンジニアのお友達：JUnit
  JavaエンジニアにとってJUnitはお友達です。これまで入ったJavaの開発現場では必ず”Eclipse”（Java開発IDE）を使用してきましたが、そのEclipseで使用できるテスティングフレームワーク：JUnit。バージョンは古くなってますが、この本の後ろに”付録”という章がありまして、ここにツール・プラグイン・サンプルのセットアップ手順が書いてあります。現在のEclipseだと、標準でJunitが入ってることが多いかと思います。
## <b>＜JUnitの仕組み＞</b>
<b>① JUnitRunner</b>       →  　<b>② テストクラス</b>　　  → 　<b>③ テスト対象クラス</b>
（テスト実行クラス） （JUnitの機能で作成）　　（開発者が作成）
 　
  <b>①JUnitRunner</b> から <b>②テストクラス</b> のテストメソッドを呼び出し、そこからテストメソッドが<b> ③テスト対象クラス</b>のメソッドを呼び出して、その戻り値からテストの成否を判定するのがJUnitの仕組み。改めて確認すると…便利なフレームワークだと感心します。

####<b>＜JUnit4のアノテーションのメモ（防備録用に）＞<b>

|アノテーション|説明|
|:-------------|------------|
|@Test |テストメソッド。JUnitから呼び出される
|@Before |テストメソッドの前に実行される
|@After |テストメソッドの後に実行される
|@BeforeClass |テストクラスを実行し始めた時に1回実行される
|@AfterClass |テストクラスを実行し終了する時に1回実行される


<b>【テストクラス】</b>
![Test1.png](https://qiita-image-store.s3.amazonaws.com/0/173505/b73469d7-0bd8-93f1-adac-209f1b8d58b2.png)

<b>【実行結果】</b>
![Test2.png](https://qiita-image-store.s3.amazonaws.com/0/173505/96ac8e53-1b2a-b0b1-b610-b71dfe222532.png)


<b>＜JUnit4のメソッド＞<b>
※assert = 「〜であるはずだ」

|メソッド|説明|
|:-------------|------------|
|assertTrue(Boolean condition)|conditionがtrueであれば成功
|assertFalse(Boolean condition)|conditionがfalseであれば成功
|assertEquals(Object expected,Object actual)|期待値と実際値が等しければ成功
|assertSame(Object expected,Object actual)|期待値と実際値が等しければ成功
|assertNull(Object object)|実際値がNullであれば成功
|assertNotNull(Object object)|実際値がNull以外であれば成功
|fail()|強制的にテストを失敗にする

評価用メソッドが失敗した時は、AssertionErrorを発生させる。

JUnitも奥が深い。
現場によっては独自テスティングフレームワークがあったりして、純粋なJUnitを組むことから遠ざかっていたので、もう一回初心に戻って勉強しないとなぁとしみじみ。
CircleCIでDockerビルドしECRへpushする

developブランチにpushした時にdockerビルドし、ECRにpushする。


~~~ deploy.sh
#!/bin/sh

ECR_URI_BASE=999999999999.dkr.ecr.ap-northeast-1.amazonaws.com
TEMPORARY_IMAGE_NAME=XXX

# Build
docker build -t $TEMPORARY_IMAGE_NAME .

# ECR_URI
if [ -z "$ECR_URI_BASE" ]; then
    echo "Need to set ECR_URI_BASE"
    exit 1
fi
if [ -z "$IMAGE_TAG" ]; then
    echo "Need to set IMAGE_TAG"
    exit 1
fi
ECR_URI=$ECR_URI_BASE/$TEMPORARY_IMAGE_NAME:$IMAGE_TAG

# Login
if [ -z "$AWS_DEFAULT_REGION" ]; then
    echo "Need to set AWS_DEFAULT_REGION"
    exit 1
fi
login_cmd=`aws ecr get-login --region $AWS_DEFAULT_REGION`
eval $login_cmd

echo "Start pushing to $ECR_URI"
docker tag $TEMPORARY_IMAGE_NAME:latest $ECR_URI
docker push $ECR_URI
~~~

`deployment`で`deploy.sh`を実行するようにする。タグはコミットのrevision。

~~~ circle.yml
machine:
  timezone:
    Asia/Tokyo
  services:
    - docker

dependencies:
  override:
    - echo 0

test:
  override:
    - echo 0

deployment:
  development:
    branch: develop
    commands:
      - ./deploy.sh:
          environment:
            IMAGE_TAG: $CIRCLE_SHA1
~~~

CircleCIに以下の環境変数を設定する。

- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_DEFAULT_REGION

# 参考

https://circleci.com/docs/1.0/docker/

https://circleci.com/blog/circleci-aws-ecrecs/

https://circleci.com/blog/tame-your-test-environment-with-docker-compose/
フォームバリデーションライブラリParsley.jsでリアルタイムバリデーションを行う

JavaScriptのフォームバリデーションライブラリ[Parsley](http://parsleyjs.org/)で入力と同時にバリデーションを行う方法を、3通り紹介します。

※Parsley v2.7.2で動作確認しています。
※Parsley.jsはJSからの起動と、HTMLにデータ属性をつけての起動が選べますが、今回は後者のやりかたを前提とします。
※今回バリデーション発火のイベントとして`keyup focusout change input`の4つを設定しています。


# `<input>`等のフィールドに個別に`data-parsley-trigger`属性を設定
[公式ドキュメントのUI for field](http://parsleyjs.org/doc/#ui-classes)の項でも解説されてたり、[公式のExample](http://parsleyjs.org/doc/examples/simple.html)でも使われてたりしていて、きっと最初にたどり着く方法。

```html
<form data-parsley-validate>
    <input type="text" required placeholder="テキストを入力してください" data-parsley-trigger="keyup focusout change input">
    <input type="email" required placeholder="メールアドレスを入力してください" data-parsley-trigger="keyup focusout change input">
    <button type="submit">submit</button>    
</form>
```
[デモ](http://jsdo.it/sakai_cyk/0dqm)

# `<form>`タグに`data-parsley-trigger`属性を設定
一番目の方法だと各フィールドにそれぞれ記載する必要があり、フィールドが多いとかなり重複する記述が増えてきてしまいます。
フィールドごとに動作をわける必要がないなら`<form>`につけてしまったほうが楽です。

```html
<form data-parsley-validate data-parsley-trigger="keyup focusout change input">
    <input type="text" required placeholder="テキストを入力してください">
    <input type="email" required placeholder="メールアドレスを入力してください">
    <button type="submit">submit</button>    
</form>
```
[デモ](http://jsdo.it/sakai_cyk/udgW)

# `Parsley.options.trigger`を上書きする
フォームがサイト全体で複数個出て来るような場合、2番目の方法でも「なんだか汚いなあ」という気持ちになってきます。
Parsleyのデフォルト設定を上書きすると、上書きの記述のあるJSが読み込まれているすべてのページのフォームに対してリアルタイムバリデーションを設定できます。
[公式ドキュメントのOverviewの項](http://parsleyjs.org/doc/#overview)にちょろっとデフォルト設定への言及がありますが、このやりかたに気づくのに3ヶ月かかりました。。
記述はたったの1行。

```js
Parsley.options.trigger = "keyup focusout change input";
```
[デモ](http://jsdo.it/sakai_cyk/symx)


---

というわけで、3通りの方法を紹介しましたが、3番目で紹介した1行を、サイト全体で読み込むJSに加えるのが一番スマートなやりかたになりそうです。
AWS Lambdaを使ってインスタンスを特定の時間に停止した

AWS Lambdaを使ってインスタンスを停止する処理を作ってみました。

lambda_handlerの使い方がいまいち分かりませんが、、、
AWS Lambdaのファンクションをcronで作成して0時とかに設定しておけば幸せになれるかもですかね。

```py
from __future__ import print_function
import boto3
from boto3.session import Session

ec2 = boto3.client('ec2')
dev_list = []

def lambda_handler(event, context):
    instance_list = ec2.describe_instances(
        Filters=[{'Name': 'tag:env', 'Values': ['dev']}]
    )
    for Reservations in instance_list['Reservations']:
        for dev_instances in Reservations['Instances']:
            dev_list.append(dev_instances["InstanceId"])

    for instance_id in dev_list:
        response = ec2.stop_instances(
            InstanceIds=[
                instance_id
            ]
        )

    return dev_list
```

https://github.com/handa3/study/blob/master/aws/lambda/stop_instance.py
rippleでXRPを送金をする

# リップルの送金の流れ

ビットコインにおいては送金にUTXOが必要なのでブロックチェーンからどの入金データを使うかユーザー側が選ばなくてはならないがリップルにおいては残高ベースなので必要がない

以下のような流れとなる

* 送金データを作る
* 送金データから未署名のペイメントトランザクション（JSON）を作成する
* 未署名のペイメントトランザクションに秘密鍵で署名し、署名済みトランザクション（HEX値）を作成する
* 署名済みトランザクションをリップルネットワークに送信する

# 送金データを作る

* 通貨はXRP固定
* source_addressに送金元のアドレスを入れます
* dest_addressに送金先のアドレスを入れます
* amountにXRPの金額を入れます(0.1など単位はXRP)
* optionsには宛先タグを格納します

```
const createPaymentXRP = (source_address, dest_address, amount, options) => {
    const symbol = "XRP"
    const result = {
      "source": {
        "address": source_address,
        "maxAmount": {
          "value": amount.toString(),
          "currency": symbol,
        }
      },
      "destination": {
        "address": dest_address,
        "amount": {
          "value": amount.toString(),
          "currency": symbol,
        }
      }
    };
    if(options.destination_tag) result.destination.tag = options.destination_tag
    return result
}
```

# 未署名の支払いトランザクションを作る

送金データを作る関数を使ってトランザクションを作ります
ここで手数料などを指定します(自動で設定されるはずですがうまくいかないときもあります)
maxLedgerVersionOffsetは tefMAX_LEDGER が頻発するようなら引き上げるようにします
ここで指定した値のledgerが経過するまではtxidを見つけられなくても再送しないようにします

```
const createPaymentTransaction = (api, wallet_address, dest_address, amount, options) => {
    const instructions = {
        maxLedgerVersionOffset: 5,
        fee: '0.1',
    };
    const data = createPaymentXRP(wallet_address, dest_address, amount, options)
    return api.preparePayment(wallet_address, data, instructions)
}
```

# 支払いトランザクションに署名してネットワークに流す

* 秘密鍵が必要になります
* 署名後にトランザクションIDが取得できます

```
const secret = "secret key"
const wallet_address = "rXXXXXXXX1"
const dest_address = "rXXXXXXXX2"
const amount = "0.1"
createPaymentTransaction(api, wallet_address, dest_address, amount, {}).then(prepared => {
    const sign = api.sign(prepared.txJSON, secret)
    const tx = JSON.parse(prepared.txJSON)
    tx.txid = sign.id
    tx.hex = sign.signedTransaction
    return api.submit(sign.signedTransaction).then(res => {
        if(res.resultCode !== 'tesSUCCESS'){
            throw new Error(res.resultMessage)
        }
        return tx
    })
})
```

# エラー処理

戻り値にエラー定数があるのできちんとハンドリングする
tesSUCCESSなどのtesXXXXは検証に成功したトランザクション。実際に送金できたかどうかの確認はTXIDを台帳から調査することができる
tecUNFUNDED_PAYMENTのようなtecXXXのコードは検証に失敗したトランザクションで台帳に含まれTXIDで調査できる。
（失敗したトランザクションでもXRPの手数料は支払う必要がある）

他のステータスは結果コードから台帳に含まれるか予測困難である

送金のステータスは以下のリンクに書いてある
https://ripple.com/build/transactions/#finality-of-results

tefMAX_LEDGERはネットワークが混んでいるときに出て、取り込まれるかどうかわからない（だいたい取り込まれないが取り込まれることもある。少したってからトランザクションを確認する（maxLedgerVersionOffsetで指定したレジャー経過後））。
頻発時には以下の対応

* 手数料をあげる
* maxLedgerVersionOffsetをあげる

https://forum.ripple.com/viewtopic.php?f=2&t=15927
https://www.xrpchat.com/topic/4324-lastledgersequence-exceeded/
（余談ですがこの問題はいつもジョエルカッツさんが答えています）


LastLedgerSequenceを設定しないトランザクション（オフライン署名とか？）はtesSUCCESS以外のtesXXXXXが返却されるので注意する必要がある

成功でも失敗でもTXIDは取れるので後検知でハンドリングする機構をいれることで対応可能になる
analytics api 設定

Analytics Apiを使う時の設定。
すでに Google_Client.php とかの設定ができていると仮定。
ちなみに大文字小文字が混じっていてうまく読み出せないので require を使って読み出すこと。


```

require_once VENDORS.'google-api-php-client/src/Google_Client.php';
require_once VENDORS.'google-api-php-client/src/contrib/Google_AnalyticsService.php';


```



https://console.developers.google.com/apis/credentials

よりログイン。

#クライアントID CLIENT_ID
左メニューの認証情報 > 認証情報を作成 > OauthクライアントID > タイプその他

#サービスアカウントネーム、メールアドレス SERVICE_ACCOUNT_NAME
左メニューの認証情報 > 認証情報を作成 > サービスアカウントキー > P12 を選択 > 作成

上記で出てきた p12 ファイルをサーバーにアップロードして、KEY_FILEに指定。

#PROFILE_ID

Analyticsでお好きなビュー、プロファイルへ。
そこのURLの
https://analytics.google.com/analytics/web/#report/defaultid/a2091651w147279143p152083278/

最後の p 以降　の数字がprofile_id となる。
a2091651w147279143 p → 152083278 ←これ

以上
[Mac OS X] OpenSSLバージョンの更新

私ももれなくbrewでinstallしたopensslのパスが適用されていなかったので
手順を記しておく

## 前準備
1. openssl 自体を更新しておきましょう

```bash
$ brew update
$ brew upgrade openssl
```

入れてない人は
`$ brew install openssl`

2. opensslのパスとバージョンを確認

```bash
$ which openssl
/usr/bin/openssl
```

```bash
$ openssl version
OpenSSL 0.9.8zh 14 Jan 2016
```

上記の結果がbrewで入れたものと異なっていたら
下記手順でパスを書き換えましょう。
私は**0.9.8zh**だったので変更が必要でした。。

## 手順
1. brewで入っているもののパス確認
`brew list openssl`

```bash
$ brew list openssl
.
.
/usr/local/Cellar/openssl/1.0.2l/bin/openssl 
.
.
```

2. パスを上書き
`$ echo 'export PATH=/usr/local/Cellar/openssl/1.0.2l/bin:$PATH' >> ~/.bash_profile`
`$ source ~/.bash_profile`

3. 確認
`$ which openssl`
`$ openssl version`
Atomパッケージ管理方法メモ

## apmコマンドを使ってAtomのパッケージを管理する
- 自分がよく使うコマンドの紹介です
- 詳しく知りたければ、apm [コマンド] --help参照してね

## パッケージ一覧を表示する

apm list --installed --bare

[オプション]
___--installed___：インストール済のものを表示
___--bare___：ツリー表示しない

## パッケージリストを作成する
apm list --installed --bare > ~/.atom/my-packages.txt

- 保存場所はどこでもOK、保存したい場所のディレクトリを指定すること

# リストにあるパッケージをインストールする
apm install --packages-file ~/.atom/my-packages.txt

- 割と時間はかかるのでしばらく待ちましょう
- テキストデータだけで環境再現できるので便利

#GitHubアカウントを持っている人はスターで管理できる
- スターとはhttps://atom.io/ で管理するパッケージやテーマのお気に入りのこと
- サイトで直接管理することもできるが、以下のコマンドでより楽に管理できる

## インストールしているパッケージにスターをつける
apm star --installed

- 初回では認証が必要なので、指示に従ってAPI tokenを登録する

## スター付きのパッケージを表示する
apm stars

## スター付きのパッケージをインストールする
apm stars --install

## おまけ
- 私が入れてるパッケージ

```txt:my-packages.txt
atom-alignment@0.13.0
atom-beautify@0.32.4
atom-fuzzy-grep@0.17.2
atom-ide-ui@0.12.0
copy-path@0.5.1
file-icons@2.1.21
git-time-machine@2.0.1
highlight-selected@0.13.1
ide-java@0.8.3
ide-ruby@0.1.10
ide-typescript@0.7.6
japanese-menu@1.14.0
language-digdag@0.0.2
language-groovy@0.7.0
language-liquid@0.6.0
language-markdown@0.25.1
markdown-preview-plus@3.2.1
markdown-writer@2.7.3
maximize-panes@0.2.0
open-files@0.8.2
project-manager@3.3.5
regex-railroad-diagram@0.19.4
show-ideographic-space@1.0.2
split-diff@1.5.2
tab-switcher@1.5.6
```
xcodeコマンドでxcodeバージョンを指定

とあるプロジェクトではxcode7系だが自分のxcodeのバージョンは8系だったので
7系をインストールした際にハマったことを記載します。

旧バージョン[Apple developer](https://developer.apple.com/jp/)からダウンロードできます。

xcodebuildの時に8系でビルドされていたので、エラーが出たりしてうまくビルドがあります。

以下記載でxcodebuildの際、使用するバージョンを変更できます。

```
$ xcode-select -p 
/Applications/Xcode.app/Contents/Developer
$ sudo xcode-select -s /Applications/Xcode7.x.x.app/Contents/Developer
$ xcode-select -p 
/Applications/Xcode7.x.x.app/Contents/Developer
```

これでバージョンを指定することができました。
オープンフィールドなRPG風ゲームを作る 1ワールド目

# はじめに

Unity中級者が本格的なゲームを作っていく様をつらつらと書いていきます


# 対象読者

- Unityを使用して2D or 簡単な3Dゲームなら作ることができる
- Unityで本格的っぽい3Dのゲームを作りたい
- プログラムの知識がある
    - オブジェクト指向言語(C++ or C# or Java)が使える
- Gitを利用してバージョン管理をすることができる


# 開発環境

こんな感じの環境で作成を進めていきます

| Sofrware        | Version            |
|:----------------|:-------------------|
| Unity           | 5.6.1f1 (Personal) |
| VisualStudio    | 2017               |
| Git for Windows | 2.4.0.2            |

どれも無料で利用することができます
いい時代ですね


# さっそく作り始めよう！

まずはUnityで新しいプロジェクトを用意します
バージョン管理をしていく上で、アセットの差分がわかりやすいようにテキストで保存するように設定を変更
メニューから「Edit > Project Settings > Editor」を選択
「Asset Serialization」を「Mode : Force Text」に変更
![20170603_001.PNG](https://qiita-image-store.s3.amazonaws.com/0/184526/0c206d63-9536-1c48-947c-c43e6593f21b.png)

プロジェクトの設定が完了したので、とりあえずこの状態でコミットしておきます
バージョン管理をしていくので、こまめにコミットしていきましょう
リポジトリはここ
https://github.com/marshmallow-in-cocoa-latte/OpenFieldRPG

これでゲームを作成していく準備ができました
次回はキャラクターを操作できるようにしていこうと思います
brew services で起動したJenkinsの環境変数の設定

# Jenkins起動時にPATHに/usr/local/binを設定するようにする

```/usr/local/Cellar/homebrew.mxcl.jenkins.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <!-- ここから -->
    <key>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
    <!-- ここまで -->
    <key>Label</key>
    <string>homebrew.mxcl.jenkins</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/bin/java</string>
      <string>-Dmail.smtp.starttls.enable=true</string>
      <string>-jar</string>
      <string>/usr/local/opt/jenkins/libexec/jenkins.war</string>
      <string>--httpListenAddress=127.0.0.1</string>
      <string>--httpPort=8081</string>
      <string>-Dfile.encoding=utf-8</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>
```

## 追記するときの注意点
* 環境変数はLabelより前に定義すること
* ~/Library/LaunchAgents/homebrew.mxcl.jenkins.plistには直接編集しない。（サービスを再起動すると/usr/local/Cellar/のファイルがコピーされる。)

# brew services で起動したJenkinsだとmvnが実行できない

ターミナルから`jenkins`で手動起動していた時にはビルド実行に成功していたのですが、brew servicesから起動するように変更したところ失敗するようになりました。

コンソールを見ると「Caused: java.io.IOException: Cannot run program "mvn" : error=2, No such file or directory」とエラーを出力しており、mvnコマンドが実行でいていないようでした。

* Jenkins > Jenkinsの管理 > システム情報 > 環境変数 > PATHの値が`/usr/bin:/bin:/usr/sbin:/sbin`になっていて/usr/local/binが抜けているのが原因のよう。(brew servicesじゃなくて`jenkins`で起動した場合は、/usr/local/binが含まれている。)
* Jenkins > Jenkinsの管理 > システムの設定 > グローバル プロパティ > 環境変数 で PATHを`$PATH:/usr/local/bin`としても解消しなかった。

結局、plistに追記することでシステム情報の環境変数に/usr/local/binが表記され、mvnが実行でき、ビルドが成功しました。

# brew servicesで実行しようとした理由

Jenkinsのportを8080から変更したかったため。冒頭のplistのように8081に変更していても`jenkins`で手動起動すると8080になってしまうので、brew servicesから実行したら8081でアクセスできたから。

PATHもportも動きが違う原因は同じような気がするが、これはあくまでも自分のPCでの検証用で目的の状況は得られたのでこれ以上の調査はしない予定です。

# Jenkinsをアップデートしてもplistがコピーされなかった

今日、homebrewで2.64が公開されてたから早速upgradeして起動したら、portが8080に戻ってた。plistは自動的にコピーされないんですね。なので2.63で編集したplistを持ってきたら8081で接続できてビルドも実行されました。
cleanupする前に気づいてよかった。
外部packageへのimportを含むprotoファイルをまとめてprotocでgo_outするシェルスクリプト

```
src
  |
  |--api/
  |    |--foo.proto
  |    |
  |--bff/
  |    |--bar.proto
  |    |--empty.proto
  |    |
```

```protobuf

syntax = "proto3";

package api;

message Foo {
  uint32 id = 1;
}
```

```protobuf

syntax = "proto3";

package bff;

import "api/foo.proto";

message Bar {
  api.Foo foo = 1;
}
```

みたいな感じだとして、普通に

```bash
protoc --go_out=plugins=grpc:. bff/*.proto
```

とかしてもダメなので

```bash
#!/bin/bash
for file in `\find bff -name '*.proto'`; do
    temp="$temp $file"
done
protoc --go_out=plugins=grpc:. $temp
```

的な感じで。シェルスクリプト難しい。ちなみにgolangの場合、protocに食わせるprotoファイルはスペース区切りで一度に全指定しないとセルフインポートするコードが生成されて循環インポートでgoのbuildが死ぬ。あとprotoファイルのpackage名にハイフンがあると多分protocが死ぬ。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">protoc-gen-go should be able to compile multiple packages per run · Issue #39 · golang/protobuf · GitHub <a href="https://t.co/Ssg4NXbZM5">https://t.co/Ssg4NXbZM5</a></p>&mdash; NIL (@oubakiou) <a href="https://twitter.com/oubakiou/status/870911573002301441">2017年6月3日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">.pb.go import error: local import &quot;.&quot; in non-local package · Issue #67 · golang/protobuf · GitHub <a href="https://t.co/FzMGDgqBrI">https://t.co/FzMGDgqBrI</a></p>&mdash; NIL (@oubakiou) <a href="https://twitter.com/oubakiou/status/870944387848486914">2017年6月3日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
sqlite のコマンド集

sqlite のコマンドをまとめてみた

select文とかは、mysqlとかと同じなので、省略。

## sqlite データベース作成
```
touch database.sqlite
```

## sqlite 接続
```
sqlite3 ./database.sqlite
```

## テーブル一覧
```
.table
```
## テーブルのカラム一覧
```
.schema --indent [tablename]
```

## sqlite 切断
```
.quit
```
GoogleAppsScriptで動的に地図画像を作成して画像(のURL)を返すAPIを作る

#はじめに
GASは緯度経度情報を与えて周辺の地図画像を動的に作れます。GoogleMapsのスクショみたいな感じで、かなり便利だと思います。

ただそれをWebAPI的に使いたかったんですよね。結果としてはどうもそれは難しいっぽいです。
(アクセスしたら画像データがレスポンスでくるようにしたかった。)

ということで
・緯度経度情報から動的に地図画像を作る
・Driveにアップロードする(全体に公開する権限を付与)
・そのアップロードされた画像のURLを返す。
という苦肉の策にでました。

その話をします。

#コード

```MapImageAPI.gs
var saveImageFolderID = "セーブ先のDriveのフォルダID";

//Getリクエストが来たときに呼ばれるメソッド。
function doGet(e) {
//緯度経度をパラメータから取得
  var lat= e.parameter.lat;
  var lon = e.parameter.lon;
//MapのBlob(Binary Large Object)を作る。
  var map = Maps.newStaticMap()
  .setLanguage("ja")
  .setSize(512, 512)
  .setZoom(15)
  .setCenter(lat,lon)
  .addMarker(lat,lon)
  .getBlob();
  
//GetSavedImageID()メソッドでURLを作成し、レスポンスする。
   return ContentService.createTextOutput(GetSavedImageID(map));
}



//Blob情報から画像を特定のフォルダに公開権限をつけてアップロード
function GetSavedImageID(blob){
//フォルダのインスタンス取得
 var folder = DriveApp.getFolderById(saveImageFolderID);
//blobから画像を作成
  var file = folder.createFile(blob);
//権限付与
  file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
//アップロードが終わったらIDを取得してアクセス可能なURL化して返す。
  return "http://drive.google.com/uc?export=view&id=" + file.getId();
}

```
これだけです。

#結果
あとは公開->ウェブアプリケーションとして導入でこのスクリプトへのアクセスURLを取得します。
そして
`アクセスURL?lat=40.759011&lon=-73.984472`
のようにパラメータをつけてアクセスすると

http://drive.google.com/uc?export=view&id=hoge-fugafuga123456789

のような画像へのアクセスURLができます。

ここにアクセスすると…
![image.png](https://qiita-image-store.s3.amazonaws.com/0/88657/9f205304-38e8-cade-1aab-5acd9da59e3d.png)

このような画像が得られます。
たぶんZoom変数とかサイズとかはパラメータでカスタマイズできたほうがいいですね。

#感想
GASのMapに関するドキュメントを見ると
https://developers.google.com/apps-script/reference/maps/static-map

SetCenterでは緯度経度だけではなく、名前(文字列)を元に地図画像の中心を定義できます。
これは凄いことで、例えば.setCenterの引数を'渋谷駅'にすると

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88657/b716b425-3d9b-dea2-ed7e-4a8f35fd6058.png)

この画像のアクセスURLが取得できます。何この便利さは。

この記事はWebAPI化としたことに意義があるんですが、本当は画像を返すことができたらよかったですね…。やり方ないのかな。