OmniAICreator/Qiita-1.07M huggingface dataset:
ConoHaにVPS追加〜SSH接続するまでやってみた

備忘録も兼ねて

# 今回やること
- ConoHaにVPSを設置
- ユーザの作成
- SSH鍵の作成、クライアント側の設定
- SSH接続

# ConoHaにVPS設置
まずはVPSの設置から行います。
ConoHaアカウント未取得の方は先に取得してください。
コントロールパネルにログインし、下記を選択します。

- OSはCentOS(8.0)を選択
- プランを選択
- rootパスワード、ネームタグを入力
- オプションのSSH Keyは「使用しない」

プランは要件にあったものを選択してください。
問題なければ追加を押すとVPSが設置されます。
[![Image from Gyazo](https://i.gyazo.com/69d15d006f88d9cfb1bedcb599c9cf61.png)](https://gyazo.com/69d15d006f88d9cfb1bedcb599c9cf61)

設置が完了したら、IPアドレスをメモしてください。事項で使用します。
[![Image from Gyazo](https://i.gyazo.com/fdc61e91d08497b9909b7972ea99345a.png)](https://gyazo.com/fdc61e91d08497b9909b7972ea99345a)

# ユーザの作成
前項でメモしたIPアドレスとパスワードを使ってサーバにログインします。

```
$ ssh root@xxx.xxx.xxx.xxx -p 22
# パスワード入力
[root@xxx.xxx.xxx.xxx ~]# 
```

サーバにログインできたらユーザを作成します。

```
$ adduser hogeuser           # ユーザ作成
$ passwd hogeuser            # 作成したユーザにパスワードを設定
$ gpasswd -a hogeuser wheel  # wheelグループに追加
$ su hogeuser                # ログイン確認
```

# SSH鍵の作成、クライアント側の設定
ユーザが作成できたら、クライアントからSSH接続できるようにします。

## sshd_confを編集
```
$ sudo vim /etc/ssh/sshd_config 
```

```/etc/ssh/sshd_config 
RSAAuthentication yes                         # 追加
PubkeyAuthentication yes                      # コメントアウトされてたら外す
AuthorizedKeysFile      .ssh/authorized_keys  # コメントアウトされてたら外す
```

設定後、サービスを再起動します。

```
$ sudo service sshd restart
```

## SSH鍵の作成
サーバで作成し、クライアントに設定します。

## サーバ側
```
# まずSSH鍵を設置するディレクトリを作成
$ cd ~
$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh

# SSH鍵の作成
$ ssh-keygen -t rsa -b 4096
Enter file in which to save the key:  # 秘密鍵の名前（任意）
Enter passphrase:                     # パスフレーズ
Enter same passphrase again:          # パスフレーズの確認

# 作成した公開鍵をリネーム
$ mv id_rsa.pub authorized_keys
$ chmod 600 authorized_keys
$ cat id_rsa  # 秘密鍵の内容をコピーしておく
```

## クライアント側
```
# 秘密鍵を作成
$ cd ~/.ssh
$ vim id_rsa  # サーバでコピーした秘密鍵の内容を貼り付ける
$ chmod 600 id_rsa
```

ついでにconfigに接続情報を設定しておきます。

```~/.ssh/config
conoha
  Host xxx.xxx.xxx.xxx
  User hogeuser
  Port 22
  IdentityFile ~/.ssh/id_rsa
```

# SSH接続
```
$ ssh conoha
Enter passphrase for key '/Users/xxxxx/.ssh/conoha': # パスフレーズ入力
[hogeuser@xxx-xxx-xxx-xxx ~]$                        # 接続成功
```
本当はMySQLのアップグレードをしたかっただけだったのに

こんにちは
株式会社Diverseで働いていますpython_spameggsです。
7日目の記事になります。
[今年の自分を振り返る](https://qiita.com/python_spameggs/private/e84ad6074a17a30d364e)で書きました[mysqlのバックアップ専用サーバのマシン交換](https://qiita.com/python_spameggs/private/e84ad6074a17a30d364e#mysql%E3%81%AE%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E5%B0%82%E7%94%A8%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AE%E3%83%9E%E3%82%B7%E3%83%B3%E4%BA%A4%E6%8F%9B)についてもう少し詳しく書こうと思います。

# はじめに
これはMySQLのアップグレードを行おうとしたらバックアップ専用サーバのマシン交換をする必要になったお話です。

### サーバ構成
簡単に説明しますと `master : slave : backup = 1 : 3 : 1` です。
masterとslaveとbackupで大きく違うのはmasterとslaveはioDriveを使用していてbackupはHDDです。
バックアップ専用サーバなのでなるべく費用を抑えたいために低スペックになっていました。
MySQLと記載してしまいましたが正確にはPercona Server for MySQLのバージョンは5.5です。
MySQL5.6はMySQLです。

# 最初の計画
新しいマシンでMySQL5.6を動かしてmaster、slave、backup分追加してMHA for MySQLでフェイルオーバーして一気に切り替えてMySQLのアップグレードを予定でした。
新しいマシンのベンチマークも終わり次にレプリケーションを設定して少しだけ使うようにコードを修正し本番環境で試そうとしました。
バックアップ専用サーバのバックアップデータを使ってリストアしましてレプリケーションの設定をしようと`CHANGE MASTER TO ...`と叩いたところMASTER_LOG_FILEで指定したbinlogが見つからないとエラーになりました。(この時までレプリケーションの設定はしてませんでした)
masterサーバを確認してみると確かに指定したbinlogが無かったのと大量のrelay logが残っているのを発見できました。
どうやらバックアップ専用サーバでレプリケーション遅延が発生しているようだと思いまして`SHOW SLAVE STATUS`を叩いてみたところSeconds Behind Masterの値がえらいことになっていました。(記憶が定かじゃないので詳しい値を覚えてませんが桁がすごかったです)
これを見た時になぜアラートが通知されなかったのか驚きました。

# 調査
監視ツールを長い期間見れるように切り替えてみると去年(2018)の8月半ばからdiskサイズに小さな変化があり10月から増加が顕著になっていました。
1日単位でレプリケーションの項目を見ると遅延と復帰の繰り返しをしていたようですが実際調べてみると数十日分の遅延の状態でした。
おそらくですがデータも正しく無さそうでした。
上記でも記載したように大量にrelay logが残っており、ibdata1も肥大化していました。
過去のデータを調べてみるともともとバックアップ中にレプリケーション遅延は発生していましたが次のバックアップまでには収まっていたためか今回のような問題が発生しておらず今まで運用されていました。
ただ、レプリケーション遅延の解消が遅かったためかアラートが何度も飛び続けるのを避けるために監視設定を解除してしまったようでした。
ダウンタイムの設定が出来るのでまるっと解除してしまったのはミスでした。
なぜレプリケーション遅延が解消できなくなったのだろうか。

# なぜ解消できなくなったのか
どうもサービスで機能の追加が活発すぎてしまったためか思った以上にレコード数が増えdiskサイズが増加し始めたのが影響していました。
増加したため必要のなくなったレコードを今まで削除していなかったので削除していくように対応されました。
その時に`RENAME TABLE, TRUNCATE`を実行するのも混じっていたため整合性を保つためにmysqldumpのオプションに`single transaction`を入れていましたがテーブルがロックされたためレプリケーション遅延がどんどん膨らんでいき次のバックアップまでに解消ができなくなってしまったようでした。

# 計画変更
このマシンをこのまま使ってバックアップを取り続けるにはスペックも乏しく厳しいのでMySQLのアップグレードは延期してMySQLのアップグレードために用意した新しいマシンと交換をしようと動きました。
まずは別のMySQLサーバでバックアップをとるように設定してひとまず安心を確保。
ついでにそのMySQLサーバでmysqldumpしてdumpデータからリストアを行い新しいバックアップ専用サーバを作成しました。
それと合わせてバックアップ方法の見直しと監視の設定を行いまして解決しました。

# おわりに
今回の出来事はきちんと監視の設定をされていれば気がついてここまで大事にならずに済んだものでした。
また、監視の設定をされていないことがどこにも残ってなかったのも良くなかったことでした。
たまたま、MySQLのアップグレードをしようとして気が付きましたがそのまま気が付かないでMySQLサーバが壊れて復旧しないといけない時に今回の問題にぶち当たっていたらとても大変な目にあっていたと思います。
やはり、監視はとても大事と思い出させてもらっていい機会になりました。

明日の8日目はSAMUKEIさんになります。
ネットワーク越しにファイル差分を調べる

rsyncの話はよく見るけどdiffの話はあんまり見ない気がする（気がするだけかも）

# rsync
dry runすれば差があるファイル一覧を出力できるので便利

```
rsync -avzon {接続先:リモートパス} {ローカルパス} 
```

タイムスタンプとファイルサイズでの比較になるので、チェックサム使いたいとか、その他諸々のオプションについては、[rsyncオプション](https://qiita.com/bezeklik/items/22e791df7187958d76c1) を参照

# diff
特定のファイルの中身同士の差分を出力したい場合はdiffコマンドを使うといい。

書き方は色々あるけど

```
ssh hoge@12.345.678.90 cat /path/to/hogefile | diff /path/to/hogefile -
```
など

# 所感
ファイル転送する前に差分の内容確認したいし、rsyncにも中身のdiff表示されるオプションあればいいのにな〜って思ったりするけど転送用のコマンドなのでまぁ使い分けの範疇ってことですかね。
AWS障害発生時の問題切り分け方法の話

#１．想定読者
・AWSの環境を使ったシステムに関わっている方

#２．自己紹介
　新卒で開発者(プログラマ)としてIT業界に入り、
　Randstadの前身であるFSHD(フジスタッフホールディングス)への転職を機にヘルプデスクを経験、
　後にRandstadでインフラへ転進後、会社の色々な事情でGISを経験、
　またRandstadに戻ってきたインフラ系エンジニア。
　現在はインフラ系ITコンサルタントのようなことを行っています。

#３．はじめに
　AWSでサーバ環境を持っていて、何かしらシステムに不具合が発生した際、
　インフラ視点での問題の切り分け方法について書いてみます。
　内容が捉えやすいようポイントがどういうものか、
　私の個人的なイメージも添えて記載しますがご了承ください。
　今までの私の経験から障害対応時に注意して、まず確認するポイントを
　参考までにご紹介させていただきます。

#４．障害発生時の切り分けポイント
　**①サーバ状態の確認**
　　・サーバが正常に起動しているか
　　　まずはサーバ自体が起動していることを確認します。
　　　一番簡単なところだとICMPでサーバが起動していることを確認できれば良いですが、
　　　そもそもポートが開いていない可能性もあるため、
　　　AWS管理者にサーバの状態を確認するのが確実です。

　　・サーバ上のイベントログ等に異常はないか
　　　Windowsログを確認し、サーバに異常が無いか確認します。
　　　![01_eventviewer.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320119/e012ec37-1c0c-19b5-d45c-d5448c1543ce.jpeg)

　　・AWS自体から何かしらの不具合通知は無いか
　　　AWSコンソール画面でのアラート確認しましょう。
　　　AWS Personal Health Dashboard で AWS から通知が来ていないか確認します。
　　　たとえば、AmazonEC2インスタンスにアクセスできない場合、
　　　定期メンテナンス等を実施していてアクセスできないだけの可能性が考えられます。
　　　【参考URL】(※AWSアカウントが必要)
　　　　[https://phd.aws.amazon.com/phd/home#/dashboard/open-issues](https://phd.aws.amazon.com/phd/home#/dashboard/open-issues)
　　　　

　**②Security Groupの確認**
　　・サーバやRDS、ELBに紐付くSecurity Groupの確認
　　　私の感覚ですと対象のサーバ等から見て玄関みたいなイメージです。
　　　![02_SecurityGroup.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320119/0754daa6-c5e8-33ec-27df-1358791abaef.jpeg)

　**③VPCの確認**
　　サブネットやルーティングといった、そもそもその対象同士に関しての
　　道ができているのか？という部分になります。
　　こちらも私の感覚だとサーバ間に道があるかどうかというイメージです。
　　![03_VPC.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320119/adaad0be-7d22-a7ee-1551-d33608bd77cb.jpeg)

　**④障害を確認したクライアント周りの確認**
　　・対象サーバに対して疎通は取れているか？
　　　確認元がWindows系だと仮定した場合、
　　　簡単な疎通の確認としてはコマンドプロンプトからのICMP確認(pingコマンド)となります。
　　・名前解決はできているのか？
　　　こちらもコマンドプロンプトからnslookupコマンドによる名前解決の確認ができます。

　**⑤アプリケーションシステム自体のエラー確認**
　　上記のものがすべて問題無いとなった場合、
　　今までの私の経験上、ほぼ100％アプリケーション特有のエラーでした。
　　アプリケーション側のエラーについてはシステムによるところですので特にここでは割愛。

#５．終わりに
　この記事が少しでも障害対応の問題切り分けの助けになれば幸いです。
CSS組版でmarkdown→pdfメモ

[技術同人誌 Advent Calendar 2019](https://adventar.org/calendars/3999)の6日目です。

----
自作サービスのコンテンツ拡充をするためにpdfを作る機会があったので
vivliostyleによるCSS組版環境をざっくり組みました。
ブツをgithubに上げたのでそれについてメモを書いておきます。
https://github.com/liarnose/book_tnm/tree/new_master

## ビルド
gulpは最近下火なので何か他の方法を使ってみたかった。結局SSGをビルダ代わりに使うことに。

### [metalsmith](https://metalsmith.io/)
プラグインをパイプでつなげてそこに対象ファイルを流し込むという
gulpの兄弟のような作りの静的サイトジェネレーター。

gulpを知ってると使いやすいけどプラグインがメンテされなくなる等の
gulpの欠点を解決してる訳でもないので別にこれを使う必然性はあんまりなかった。

### [vivliostyle-savepdf](https://github.com/vivliostyle/vivliostyle-savepdf)
ローカルサーバーとかヘッドレスブラウザとか知らなくてもvivliostyleを使えてたいへん便利。

## テーマ
作ったCSSやテンプレートを何度も使いまわしたかったので
その分をテーマとして別フォルダにくくりだすようにした。

### CSS
将来的に使い続けるのが難しいのが分かってる関係上
脱ePub Adaptive Layoutしたかったのでページ周りは全部CSS Paged Mediaで書く。
と言っても、もともとAdaptive Layoutの機能を利用していたのはランニングヘッダとノンブルだけだったので

- ランニングヘッダ→文章中でヘッダ内容を書き換えるような機能をあきらめてページ背景に統合する。
- ノンブル→ページマージンボックスに移植。

とした。実は傍注はただのCSSのトリックでCSS組版の機能は使っていない。

ネストが使えるのでCSS設計自体はぞんざいだった。タイプセレクタもガンガン使っている。

#### [PostCSS](https://postcss.org/)
全部プラグインとして機能拡張するコンセプトのCSSトランスパイラ。軽いらしい。

##### [PostCSS Nested](https://github.com/postcss/postcss-nested)
セレクタをSCSSライクな記法でネストできる。&も使える。

##### [PostCSS Custom Properties](https://github.com/postcss/postcss-custom-properties)
CSSの中で定数を宣言できる。calc()と組み合わせてページサイズなんかを担当。
カラーテーマなんかにも使えるかも。

### テンプレート
vivliostyleに食わせる時点ではすでにレンダリング済みのhtmlを用意したいが、
SSRの仕組みを流用してどうのというのは流石に牛刀割鶏感あるので
ビルド手順の中にふつうのテンプレートエンジンを組み込む方向で。
使ったことのあるやつの中からhandlebarsを採用。

#### handlebars
デフォルトだとかなりシンプルな機能だけがサポートされているテンプレートエンジン。
「この項目は5文字以上だったら長体がかかる」みたいな条件分岐ですらおいそれと書けない。

## 本文
markdownだけだと表現力が足りないけどmarkdownライクに楽に書きたいので
markdownをプラグインでオレオレ拡張する方針にした。
markdown内にテンプレートを挿入する部分に至っては自前拡張。

### markdown

#### [markdown-it](https://github.com/markdown-it/markdown-it)
プラグインもりもり系markdownパーサ。
vivlioisyle界隈だと同じコンセプトでもremarkの方が注目されてるのでそっちがいいかも知れない。

##### option: { html: true }
markdown-it本体に設定できるオプションで、htmlタグをエスケープせずにそのまま出力する。
間に空行が入ると一つのブロックとして認識されなくなってしまうので、
純粋なhtmlと書き心地は違うけどないと困るやつ。

##### [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs)
ありとあらゆるmarkdown役物にクラス等を設定できるようにするプラグイン。
ただの本文のpタグにすら設定できる。
今回の本文のフォントスタイルは3種類もあったのでこれがないと使い分けができなかった。

[markdown-it-container](https://github.com/markdown-it/markdown-it-container)とどっちがいいかは趣味。

##### [markdown-it-deflist](https://github.com/markdown-it/markdown-it-deflist)
定義リストの記法を追加。
傍注の中で使ってるけどただのヘッダーとパラグラフで十分な気がする。

##### [markdown-it-statblock](https://github.com/liarnose/book_tnm/tree/new_master/markdown-it-statblock)
自前実装したmarkdown本文にhandlbersテンプレートを挿入する記法を追加するプラグイン。
本文中に```<<statblock [テンプレートのパス],[jsonデータのパス]>>```と書くと
テンプレートにjsonを食わせた結果が挿入される。

### json
テンプレートの食わせるデータは.jsonファイルの形で外付けにした。
特に専用のエディタなどは用意せずbrackets上でテキストとして編集してたが、
書式のエラーを探すのに相当時間を取られてるのでjsonLintを導入するとか何らかの対策が必要。

あと長い文章を担当する型が無いので一文ごとに分割して
配列に入れるとかしなきゃなのはいかんともしがたいものがある。

## 感想
[今CSS組版で同人誌を書くとしたら 2017](https://qiita.com/liarnose/items/886d59c60c164e7452b4)からほぼ変わらなかったので
「2年間俺は一体何を…？」と軽くショックを受けた。
Web系転職で学んだエンジニアにとってのモチベーション管理

この記事は、[SIer脱出を語る Advent Calendar 2019](https://qiita.com/advent-calendar/2019/sier)の6日目の記事です。

## 経歴
今年(2019年)の4月に大学を卒業し、地元のメーカーの社内SEとして働き始めました。
そして、今年の11月にWeb系への転職を決意しました。
その中で、プログラミングに対してのモチベーションの波があったような気がします。

今回の記事では、そのモチベーションの波を分析し、自分もしくは人間はどのようなシチュエーションに置かれるとモチベーションが高まるのかを考えていきたいと思います。

## 社内SEとして働き始めた頃
4月に入社した私は、やる気に満ち溢れていました。
今まで大学での研究などでしかプログラミングをしていなかった私は、
仕事でプログラミングをすることとなった時に、わくわくもありましたが不安な気持ちでいっぱいでした。
**その不安を消す一番の方法は、勉強すること**でした。
会社で学んだことを家で復習し、会社でそのインプットを仕事として活かす。という流れでした。
入社してから1～2か月は、モチベーションは高い状態が維持されていました。

## 入社後のモチベーション停滞期
入社して三か月が経った頃、モチベーションは落ち始めていました。
仕事にも慣れ、仕事内容としても新人に任せられる程度の仕事ということもあり、正直家で勉強するほどの仕事内容ではありませんでした。
ただ、入社してからプログラミングを本格的に勉強し、好きになっていたということもあり、
「何かを勉強したい」という気持ちはありましたが、何を勉強すればよいのかがわかりませんでした。
今思えば、**勉強をする必要性を感じていなかった**のかもしれません。

## Ruby on Railsをはじめる
先ほども書いたように、「何かを勉強したい」という欲求を満たすために、なんとなくでWeb系のプログラミングをはじめました。
HTML/CSSからはじまり、JavaScript,Ruby, Sinatra, Railsという順番です。
なんとなくで始めてみましたが、**これにハマりました。**
HTML ～ Sinatraまでは、「こんなもんか。。」という感じでしたが、Railsを始めると、
学習コストは少し高い気がしましたが、覚えると比較的簡単に自分が思い描いたアプリケーションが作れることに感動しました。
この頃は平日であれば2時間程度、休日でも４時間程度の勉強時間を取るモチベーションでした。
モチベーションの高さでいうと中の中くらいです。
この頃も、「楽しい」という感情はあったものの、仕事で使うわけではなくあくまで趣味での学習のため、
勉強に対しての「**必要性**」を感じていませんでした。

## 転職を決意
そんな中で、Web系のプログラミングにハマり、次第に社内SEとしての仕事がつまらないと感じ始めていました。
「仕事としてWeb系のプログラミングをしたい」「プリンタの設定の仕方を暗記するために会社に入ったわけではない」
そのような思いが強くなり、私は**今年の8月中旬に転職を決意**しました。
転職を決意してからの毎日の学習時間は、趣味として学習していた頃のおよそ2倍ほどになっていました。
仕事は定時に帰り寝るまで勉強、休日が大好きな野球の練習も休み1日中勉強していました。
そして、ポートフォリオとしてエンジニア向けのマッチングアプリを開発し、公開しました。
この頃のモチベーションは今までの人生の中でもトップレベルで高かったと思います。
これは、**転職をする際に必要なポートフォリオを作成しなければならないという「必要性」があったからだと感じています。**

## そして現在
ありがたいことに、Wantedlyなど求人サイトでは10社ほどからスカウトをいただき、
その中で地方でECサイトを海外向けにも開発している企業への転職を決意しました。
ポートフォリオではRuby on Railsを使っていましたが、転職先ではECサイトならではのプラットフォームや、
Node,js、Reactなどを使用します。
これらの技術も当然自分にとって必ず「必要」な技術です。

## 伝えたいこと
長々と書いてきましたが、伝えたいことは１つです。

「**モチベーションのありかはやりたいことではなくやるべきこと**」

賛否両論あるかもしれませんが、私はこうだと考えています。
エンジニアという仕事は、最新の技術に常にアンテナを張り続けなければなりません。
しかし、それを駆け出しの頃からずっと続けるのは難しいと思います。
まずは、私の転職時のように必要な技術をただひたすらに勉強をし続けることが大切です。

そして、エンジニアとなり働き始めることで、
**「最新の技術に常にアンテナを張り、努力し続けること」
これが、自分にとって「必要性」のあるものになるはずです。**

話が脱線しまくっている気がしますが、もしSlerなどでモチベーションが低下し続けているのなら、自分の人生にとって必要性の高いものを見つけ、転職なり独立をするべきです。
Slerなどでモチベーションを常に高く持ち、努力をし続けれるのならば、
最近のWeb系転職ビッグウェーブには乗らずに頑張り続けるべきだと私は考えいます。

## 最後に
最後まで読んでいただきありがとうございます。
エンジニアにとってモチベーションは本当に大切だと思います。
駆け出しの方やWeb系へ転職を考えている人の中で、モチベーションが低下してしまっている方の参考になれると幸いです。
laravel ログファイルのpermission denied 対処

原因はphp artisan経由のログはプロセスがユーザーなので更新or作成が所有者がユーザーになるが
ブラウザ経由だとapache(nginx)になるため、相互で書き込もうとすると拒否される。

## 対処１：ログファイルの出力先を変える

```config:config/logging.php
       'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel-' . php_sapi_name() . '.log'),
            'level' => 'debug',
            'days' => 14,
        ],
```

## 対処２：ログファイルの設定を変える
[ロギング Laravel](https://readouble.com/laravel/5.7/ja/logging.html)
daily、singleのパラメータにpermissionがあるのでこちらを設定する
値は`664`ではなく`0664`に

```config:config/logging.php
       'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 14,
            'permission' => 0664,
        ],
```
Slack の新書式設定とその無効化について【2019 アドカレ】

## Slack 愛好家による自己紹介

Slack 愛好家です。日常遣いに加えて、家族とのやり取りも LINE から Slack に移行し、 GitHub、 GitLab の通知もすべて Slack へ送り、 Google calendar とも連携し、個人アプリケーションのエラーログも Slack へ送り、何から何まで Slack に集約したがるマンです。

先日のこの記事にはいたく共感しちゃいます。

- [Slackはただのコミュニケーションツールじゃない、企業の技術を映す鏡だ](https://qiita.com/KizashiTakata/items/d442d4a28d147529f1b6)

これだけ Slack ラブな理由のひとつに、 Markdown ライクなマークアップ記法を採用している点があります。私はマークアップでテキストを装飾するのが大好きです。よくやるのが、別エディタでメッセージを編集してから Slack へコピペするやりかたです。

1. 別エディタで書く
1. SlackBot へコピペ送信してマークアップ記法が意図通り表示されるか確認
1. 本当に送りたい相手へコピペ送信

たまに Slack と TEAMS を比べている人がいますが、私にとっては Slack の圧勝です。 TEAMS ではメッセージ欄の中でメッセージをタイプしないとマークアップ記法が有効になりません。かといってメッセージ欄の中で複雑な内容をタイプしていると誤送信につながります。

## 新方式 メッセージ欄内で自動フォーマット

次のふたつのパターンで、メッセージ欄内で自動フォーマットが行われるようになりました。

1. マークアップ記法を含むプレーンテキストをコピペ後、フォーマットのショートカットを押下
1. メッセージ欄内でマークアップ記法をタイプ(これは TEAMS と同じ動きですね。)

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270842/aed07722-b777-6fbd-4ab7-a49ca6b9c442.png)

いちいち SlackBot を使って確認する必要がなくなりました。いいですね。しかし一方で、**フォーマットしたテキストを、元のプレーンテキストに戻すことはできません。**

## 新方式を無効にする

この新方式はワークスペースの設定欄から無効化することができます。「マークアップでメッセージを書式設定する」にチェックを入れると、旧方式に戻ります。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270842/616fd1f0-96f8-731e-c08e-9dbed974ef00.png)

今のところ私は旧方式のほうが使いやすいと感じるので、これを適用しています。新方式も良いとは思うのですが、フォーマットが不可逆的であるところがどうにも使いづらいです。ぜひとも可逆的なフォーマットの機能実装を検討してほしいところです。

今回の新方式がすこし肌に合わないことから本記事を書いてみましたが、他の愛好家のみなさんは今回の新方式についてどんな感想を持たれているのでしょう? 私気になります。
Java の Object のサイズを簡単に測定する


#コード

```java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class ObjectUtils {
	public static int getObjectSize(Object o) {
		ObjectOutput out = null;
		try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
			out = new ObjectOutputStream(bos);
			out.writeObject(o);
			out.flush();
			byte[] b = bos.toByteArray();
			return b.length;
		} catch (IOException e) {
			return -1;
		}
	}
}
```
#使い方

```java
	public static void main(String[] args) {
		{
			String o = "ABC";
			System.err.println(ObjectUtils.getObjectSize(o));
		}
		{
			Integer o = 100;
			System.err.println(ObjectUtils.getObjectSize(o));
		}
		{
			String[] o = { "ABC", "ABC", "ABC" };
			System.err.println(ObjectUtils.getObjectSize(o));
		}
	}
```

#実行結果例

```
10
81
60
```
TJBot で最初に苦労しないために

以下のリンク先の内容をキチンと実施すれば普通の人は特に苦労しないと思いますが、ちょっとした勘違いで大変苦労したのでご紹介します。皆さんには他山の石となれば幸いです。

「自作AIロボットTJBot Zeroで遊んでみる」
https://qiita.com/zuhito/items/cd9d8cfefab1fbacaf69

# TJBotを会社や自宅で動かしたい

多くの方はハンズオンで作成したTJBotを持ち帰って自分の会社や自宅などで動かしたいですよね。
そのためには、ハンズオンで設定されたIPアドレスを変更する必要があります。
そしてIPアドレスを変更するためにはTJBotにディスプレイやキーボード、マウスを接続して設定します。
その方法も上記「自作AIロボットTJBot Zeroで遊んでみる」の「おまけ3: ハンズオン向けTJBot Zeroを自宅で使う」セクションに記載されているのですが、ディスプレイの接続に苦労してしまいました。

# TJBotにディスプレイを接続する
最初からガイドの通り、「HDMI接続のディスプレイ = HDMIインターフェースを持つテレビ」に接続すればよかったのですが、泥沼にはまっていきます。
## (1) USB接続ディスプレイに接続 → x
会社でUSB接続パソコン用ディスプレイを使っている人がいて、「TJBotもUSBインターフェースがあるから接続できるかも」と思ったのですが、何も表示されません・・・。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209601/c4a448b1-7c37-1068-98e4-8bf80618295e.jpeg" width=50%>

## (2) VGA接続ディスプレイに接続 → x
やはり会社でVGAインターフェースのパソコン用ディスプレイをHDMI変換して使っている人がいて、これなら繋がるかと思ったのですが、USB-HDMI変換したためか、やはり何も表示されません・・・。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209601/c14f9dad-b530-e778-6b14-5f0ed037e80d.jpeg" width=50%>

## (3) HDMI接続ディスプレイに接続 → ◯
「待てよ、HDMIインターフェースって家のテレビにもあるよね。テレビでいいってこと？」
結局普通に自宅や会社のテレビにHDMIケーブルで接続して無事表示されました。
「パソコンのディスプレイとテレビは違う」という昭和な勘違いで無駄な苦労＆買い物をしてしまいました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209601/6d481420-abb2-0cbf-793f-db0ad30f1711.jpeg" width=60%>

# IPアドレスの設定
ディスプレイが表示されたので、USBハブ（購入）にUSB接続のキーボード（購入）とマウスを接続して、ようやくIPアドレスを設定できる準備完了です。
会社や家あるいは将来別の場所で動かすこともあるかもと思い、携帯電話のテザリング機能を利用して携帯電話とWiFi接続しています。

# おまけ：Raspberry Pi 用ディスプレイ
実は秋葉原の Raspberry Pi ショップでラズパイに接続できる小型ディスプレイも購入してます。店員さんからはバッテリーとデバイスドライバーが必要かもと言われましたが、普通に表示されます。
将来は小型モバイルテレビ付きTJBotで面白いことやってみたいです。
python 文字列の連結の工夫

pythonで変数を文字列に組み込むときにわかりやすく書ける方法を備忘録として残しておきます
例えば、通常下のような記述がありますが""や+が多く煩雑になってしまう恐れがあります。

```
name="太郎"
print("私の名前は"+name+"です")
```

これをf""で全体の文をくくり、変数を{}で表すことができます

```
name="太郎"
print(f"私の名前は{name}です")
```
こちらの方が分かりやすいのではないのでしょうか。もしよかったら使ってみてください
鳥取県東部エリアバスマップ一覧メモ

# はじめに
この記事では、鳥取県東部エリア(鳥取市・岩美町・八頭町・若桜町・智頭町)のバスマップをメモします。私的なものであり、また全てを網羅しているわけではありません。情報があれば、ぜひコメントなどでお知らせください。

# 分類について
(以下は勝手に命名したものです)

- 非地図ベース
    - 完全なデフォルメのバスマップ
    - 正確な地図と重ねた場合、どう変形させても、位置関係を似せるのが難しいもの
- 準地図ベース
    - 地理的な配置をやや意識したバスマップ
    - 正確な地図と重ねた場合、大きく変形すれば、位置関係がやや似るもの
- 地図ベース
    - 地理的な配置が非常に意識されたバスマップ
    - 背景地図の有無はここでは問わない
    - 正確な地図と重ねた場合、変形せずとも、位置関係がほぼ同じもの

# 全域、または広域的
- [「鳥取県東部バス路線系統案内図」](http://tottori-bus.or.jp/route_bus.html)
    - 作成：鳥取県バス協会
- [「鳥取交通マップ」](https://www.city.tottori.lg.jp/www/contents/1470794712160/index.html)
    - 作成：鳥取市
    - 5年おき？に更新されている、ローカル路線バスと乗合タクシーなどの総合案内図
    - 準地図ベース＋地図ベース
    - 乗り継ぎが必要な場合には利便性高い
    - 最新は2016年
- [「鳥取県東部地域広域路線バス・鉄道時刻表」](https://www.pref.tottori.lg.jp/10999.htm)
    - 作成：鳥取県東部地域公共交通活性化協議会
    - 利便性の高いバスマップ＋簡易バス時刻表＋鉄道時刻表
    - 地図ベース
    - どうやら、株式会社バイタルリード製らしい

# 観光地特化
- [「とっとりのりもの総合案内」](https://www.pref.tottori.lg.jp/207251.htm)
    - 作成：鳥取県観光局観光戦略課
    - リンク先は古く、年1回程度更新されている？がwebから到達しにくい
    - 観光地などで入手可能
    - 準地図ベース・観光客向けバスとローカル路線バスの区別あり

# くる梨関連
- [(くる梨)「ルート図」](https://www.city.tottori.lg.jp/www/genre/1187672007731/index.html)
    - 作成：鳥取市
    - 鳥取市街地を循環する、100円バス「くる梨」の3ルートを示したもの
    - くる梨車内やバス停にて配布されている
    - 準地図ベース

# ローカル路線バス関連

- [「鳥取地区バス路線図」](http://www.nihonkotsu.co.jp/bus/limousine_route/route_tottori.html)
    - 作成：日本交通
        - 鳥取の主要バス事業者2社の1つ
    - 自社のローカル路線バスを示したもの
    - 非地図ベース・系統ごとの色分け対応
- [(鳥取地区)「管内路線図」](http://www.hinomarubus.co.jp/kousoku_rosen/untin_top_t-new.html)
    - 作成：日ノ丸自動車
        - 鳥取の主要バス事業者2社の1つ
    - 非常に古いが、自社のローカル路線バスの範囲を示したもの
    - 非地図ベース・系統を区別せず

# 非市街地循環型バス(コミュニティバス)
(編集中)

# その他
- (※名称未調査)環境大学バス路線図
    - 作成：公立鳥取環境大学
    - 学休日を除く平日に、学生証のみで学生が乗車できるバス路線を示したもの
    - 学内や入学生向け資料で配布、現在は公開せず
    - 非地図ベース
- [各種観光パンフレット](http://www.torican.jp/pamphlet)
    - 作成：鳥取市観光コンベンション協会
    - バスマップではないものの、非常に見やすい準地図ベースマップ多数
    - ★★★デフォルメバスマップと組み合わせて使うと利便性がとても高い★★★

# 拙作
- [「ttrmap」](https://busroutemap.github.io/ttrmap/)
    - 作成：ことづ(busroutemap)
- [その他各種鳥取のバスマップ](https://busroutemap.github.io/tottori/index.html)
    - 作成：ことづ(busroutemap)

# おわりに
改めてまとめると、多様な主体が多様なバスマップを作成していると再認識しました。非常に喜ばしいことである反面、地域住民や観光客などに、どれだけ認知度があるのか気になります(拙作も含みます)。

なお、この記事の内容について、今後も随時更新していくかもしれません。
Rails 6でCapistranoでデプロイする際のCredentials関連エラーに対処する

Rails 6環境で、Capistranoでデプロイしようとすると、`assets:precompile`のところでエラーが発生する現象が起きた。
エラーログをみると、下記のようにある。

```
ArgumentError: Missing `secret_key_base` for 'production' environment, set this string with `rails credentials:edit`
```

production用の設定がうまくいかず、これを解決するまでに結構ハマったので、解決方法を書いておく。

# 動作環境
macOS 10.14.6
Rails 6.0.0
Ruby 2.6.2
Capistrano 3.11.2
デプロイ先 AWS Amazon Linux2

# 解決方法
production環境用にCredentialsの設定をする。

- Credentialsについては下記参照
  - https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39

Credentialsについて説明している多くの記事でcredentials.yml.encにdevelopmentとproductionの階層を作っているが、これはうまくいかなかった。
理由は、上記リンクに書いてあるように、Rails 6からは1つのCredentialsファイルに階層を作って管理するやり方ではなく、環境ごとに個別にファイルを作成するフラットな構造に変わったためだ。

Credentialsの設定はターミナルから次のように実行する。

```
EDITOR=vim rails credentials:edit --environment production
```

なお、環境変数`EDITOR`が事前に設定してある場合は指定する必要はない。
`--environment`については、`bin/rails credentials:edit --help`に書いてある。
(helpがあるのに気づかずに随分遠回りした...)

上記を実行すると、編集画面が立ち上がるので、下記を設定して保存する。

```
secret_key_base: 任意の文字列を設定
```

環境を指定しないで`rails credentials:edit`のように実行すると`secret_key_base`がデフォルトで設定されるが、今回のようにproduction等の環境を指定するとデフォルトでは設定されていないので、`secret_key_base`を項目を記述し、任意の文字列を設定する。

上記設定を完了するとproduction用のmaster.keyであるproduction.keyと、それに対応するcredentials.yml.encであるproduction.yml.encが**config/credentials**配下に作成される。

その後、生成されたproduction.keyをデプロイ先のサーバにコピーする。
ここでのポイントは、デプロイ先は**shared/config直下ではなく、credentialsディレクトリをconfigの下に作成**してそこにproduction.keyを入れることだ。
(config直下ではうまくいかなかった。)

scpでコピーする場合は、下記のような形で実行。

```
scp -i SSHの鍵ファイル user@XXX.XXX.XXX.XXX:デプロイ先のRailsのroot/shared/config/credentials
```

次に、deploy.rbに、Railsがproduction.keyを参照するためのシンボリックリンクを貼る記述を追加する。

``` config/deploy.rb
append :linked_files, 'config/credentials/production.key'
```
※appendはCapistrano 3.5以降可能な書き方。それ以前のバージョンならsetを使えば良い。

今回の動作環境では、下記は設定しなくても正しく動いたが、下記設定はmaster.key(今回はproduction.key)を使うことを保証するため、設定することが推奨されてるらしい。

``` config/environments/production.rb
config.require_master_key = true
```

上記を設定した上でCapistranoのデプロイコマンドを実行すると、失敗していた`assets:precompile`が通るようになる！
WindowsでDockerを使ってLaravel環境構築までの道のり（目次）

# WindowsでDockerを使ってLaravel環境を構築を試みます。

コマンドの都合でWindowsにLinux環境を作って開発を行ったほうがパッケージやライブラリのインストールに躓かなくて済む気がするので、再現性が高くなるように道のりをまとめます。

windowsで使えない "atp-get update" これを使ってDockerfileを書いているケースが多いため、
windowsでは、そこから先に進めない現象に出くわしました。

ということで、Ubuntuから導入します！！
下記の順番に辿っていけば、スムーズに環境構築できるはず！

- WSL導入とWSLからUbuntuインストール【[参照](https://www.atmarkit.co.jp/ait/articles/1608/08/news039.html)】


- Ubuntu起動して、初めにUbuntuのホームディレクトリの変更【[参照](https://it-blue-collar-dairy.com/change_home_directory_for_ubuntu/)】

(これより先はUbuntu上での作業です)
- proxy設定（proxy環境で作業している人だけ）【[参照](https://qiita.com/48saaan/items/47f8d9cd3321c3bcfce6)】【[補足ページ](https://qiita.com/showsuzu/items/9ee031208d38ff8ac889)】
- Dockerのインストール【[ここ参照](https://qiita.com/tkyonezu/items/0f6da57eb2d823d2611d)】
- Docker composeのインストール【途中】
- Dockerfile, docker-compose.ymlの作成
- docker-compose up -d 実行！！
環境構築完了！

という流れで行けそうなので、ひとまずメモとして残します。
【Git初心者】GitHubの初回ターミナル操作

GitHubのアカウントを作成し、
ローカルリポジトリを作成してGitHubにpushするまでのターミナル操作について備忘録です。

#前提知識
GitHubは複数人で開発を行うためのバージョン管理ツールのようなものです。
GitHub上ではプロジェクト管理やコードのレビュー等もできます。
リポジトリとは、ファイルやディレクトリの履歴を管理する場所のことです。
リモートリポジトリはGitHub上(ネット上)の場所、ローカルリポジトリは自分のPCの作業場所を指します。

#アカウント作成
- 公式サイトでGitHubのアカウントを作成しました。
    - 参考：https://github.com/

- ユーザ名変更　※アカウント名を適当につけていたので変更しました。
    - Setteing-Account-Change usernameから変更
    - Setting-Profile-nameも変更
    
#リモートリポジトリを作成
- GitHubにログインし、「New Repository」 ボタンを押して以下を入力します。
    - 「Repository name」にリポジトリ名を入力
    - リポジトリの種類「Public」か「Private」を選択
    - 「Create repository」ボタンを押す
    - リモートリポジトリのアドレスが表示される

#ローカルリポジトリを作成
- ターミナルを起動し以下を実行します

```sh

git --version             #gitのバージョン確認
cd 作業場所のディレクトリ　 #gitの作業場所にしたいディレクトリに移動
vi 作業ファイル　      　  #作業ファイルを作成・保存
git init                  #.gitフォルダが作成される
git add 作業ファイル　     #作業ファイルをステージングエリアに上げる
git commit -m "コメント"　 #コメント付きでコミットする

#リモートリポジトリのアクセス先を設定する
git remote add origin https://github.com/GitHubのユーザ名/GitHubのリポジトリ名.git　

#リモートに上げる
git push -u origin master 
#上記のように-uを付けると、次回から git push だけで origin master でpushしてくれる
```
- ユーザ名やEmailを変更したい場合は以下を実行します

```sh

git config user.name ユーザ名　　　　  #ユーザ名を登録
git config user.email メールアドレス　 #メールアドレスを登録
```
- 設定ファイルを見たいときは以下を実行します

```sh
git config --list
```

これでGitHubのページを見るとファイルがアップロードされているはずです。

#ローカルからリモートリポジトリに反映する
一度ローカルリポジトリを作成した場合、以下でリモートリポジトリにローカルの作業ファイルを反映できます。

```sh

cd ローカルリポジトリのディレクトリ　 #ディレクトリに移動
vi 作業ファイル　      　　　　　　  #作業ファイルを修正・保存
git add 作業ファイル　              #作業ファイルをステージングエリアに上げる
git commit -m "コメント"　         #コメント付きでコミットする
git push 　                       #リモートに上げる
```

#リモートリポジトリをローカルに反映する

GitHub上に既にあるリポジトリのアドレスはリポジトリのページの「Clone or download」ボタンを押すと表示されます。
Clone with SSH　のところのアドレスはSSH通信になるのでセキュリティレベルが高いです。

```sh
#作業場所にしたいディレクトリに移動
cd 作業場所のディレクトリ　     

#GitHub上リポジトリのアドレスをコピーしgit cloneのあとに貼り付け                    
git clone git@github.com:yuhoneko/sample-web.git 
```

#(参考)ブランチを作成する
ブランチはメインのプロジェクトから枝分かれして開発する仕組みです。

```sh
git branch ブランチ名　   #ブランチを作成
git branch　　　　　      #ブランチ一覧を確認する　*がついているのが現在のブランチ
git checkout ブランチ名　 #ブランチを切り替える
```


ここまで。
AWS API GatewayのHTTP API(β版)がLambda関数に渡す値が想定と違っていた話

最近 AWSのAPI Gatewayに、HTTP API(β版)が実装された。
試してみたところ、ちょっとハマったので備忘録に。


```html
<html>
  <head></head>
  <body>
   <form method="post" action="xxxxxxxx">
     <input name="userName" value="a">
     <input name="userPass" value="a">
     <button>
   </form>
  </body>
</html>
```
まずは、ありきたりなフォームを作成して、作成したHTTP APIにsubmitする。
統合先のLambda関数で確認すると、bodyの情報がREST API(Lambdaプロキシ統合を使用)のときと違う。

```javascript
// Lambda関数(Node.js 12.x)
exports.handler = async event => {
  console.log(event.body);
  // REST API(Lambdaプロキシ統合使用)の場合は 'userName=a&userPass=a'
  // HTML API(β版)の場合は 'dXNlck5hbWU9YSZ1c2VyUGFzcz1h'
};
```

どうやらBase64でエンコードされているらしい。
isBase64Encoded をデコードの判定に使おう。

```javascript
// Lambda関数(Node.js 12.x)
exports.handler = async event => {
  const bodyString = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString() : event.body;
  console.log(bodyString);
  // REST API(Lambdaプロキシ統合使用)の場合は 'userName=a&userPass=a'
  // HTML API(β版) の場合も 'userName=a&userPass=a'
};
```

良かった。
解決できた。
【Eclipse】環境設定まとめ ※随時更新

Java開発を始めてEclipseを使うようになったのですが、
設定項目が多くて迷うことがあるので備忘録として残しておきます。
※随時更新していきます。

# Java
`[ウィンドウ]`－`[設定]`の`[Java]`－`[インストール済みのJRE]`
`[ウィンドウ]`－`[設定]`の`[Java]`－`[コンパイラー]`　
※ワークスペース個別設定プロパティでは`[Javaコンパイラー]`

 **新規プロジェクト作成時に設定する場合**
`[Java プロジェクトを作成します。]`画面の「JRE」欄で`[プロジェクト固有のJRE を使用]`にチェックを入力し、任意のJRE を選択する。

 **既存プロジェクトのJavaを変更する場合**
プロジェクトを選択し、右クリックのメニューより`[プロパティ]`を選択する。
プロパティ画面の左ペインより`[Java のビルドパス]`を選択し、
`[ライブラリー]`タブの`[JRE システムライブラリー]`で任意のJRE に変更する。

# エディタ
　行番号の表示
`[ウィンドウ]`－`[設定]`の`[一般]`－`[エディタ－]`－`[テキスト・エディタ]`

　未使用のimport文を削除
`[ウィンドウ]`－`[設定]`の`[Java]`－`[エディター]`－`[保存アクション]`
「保存時に選択したアクションを実行」にチェック
「インポートの編成」にチェック

# Maven
`[ウィンドウ]`－`[設定]`の`[Maven]`－`[ユーザー設定]`
Mavenでプロキシを利用する際などにsettings.xmlの場所を指定

# その他
タスク・タグ
`[ウィンドウ]`－`[設定]`の`[一般]`－`[エディター]`－`[構造化テキスト・エディタ－]`－`[タスク・タグ]`

ローカル・ヒストリー
`[ウィンドウ]`－`[設定]`の`[一般]`－`[ワークスペース]`－`[ローカル・ヒストリー]`
ファイル保持日数・最大ファイルサイズ etc..

コード・テンプレート
`[ウィンドウ]`－`[設定]`の`[Java]`－`[コード・スタイル]`－`[コード・テンプレート]`
自動生成させるコメントやコードを設定
強化学習２９　Colaboratory+ChainerRL+Mountain_car

強化学習２８まで終了していることが前提です。
標準DQNでmountain_carを学習しようとするとうまく行きません。
最初はうまく学習できても、途中からおかしくなります。
いろいろといじりまわした結果、reward-scale-factorがややこしくなる原因のようです。
reward-scale-factorは報酬を正規化する係数のようですが、1.0にします。
つまり何もしないということのようですが。。。
途中でaverage_qが反転してしまいますが、ある程度の学習はされます。

ノートブックは、chokozainerRLに入れておきました。
mountaincar_dqn_chokozainer.ipynb
です。
また、Double DQNにも簡単に適用できそうなので、
train_ddqn_gym
も作りました。
Double DQNは、DQNの上位らしいのですが、学習速度は、Double DQNが少し遅いレベルです。
Double DQNはepsilonを0.003にしました。
GoogleMap Directions APIで150万円を溶かした話

[GCPのAutoMLを使っていたら12万の請求がきてしまった話](https://qiita.com/Yuta_Fujiwara/items/07c8f515eea542c56bef)を読み、前職の現場で似たような体験をしたことを思いました。
そこで、自分への戒め＋この記事をご覧になっている方に「同じ失敗を繰り返して欲しいくない」という思いを込めて書きます。

※ 本記事はプロダクトの特定を防ぐため、一部の情報を濁してあります


## 何が起きたか
その事件はリリース直後(お盆明け)に発生し、利用者が急増したことで発覚しました。
まずは、当時のGCPの請求金額をご覧ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165108/105f7e35-57e7-9fbf-151a-0dcb33b51909.png)
なんと1日あたりの最大請求金額は**「25万円」**を超え、月あたりの合計請求金額は**「約150万円」**の課金が発生する事態に（これが噂の「クラウド破産」と呼ばれている現象ですね）

## 原因

実装されたあるAPIに、GoogleMap Dicrections APIを利用して「ある地点～ある地点への経路情報」を取得する処理があり、Directions APIに大量のリクエストを送っていたため

## Directions APIの料金試算
現在の[GoogleMap APIの料金体系](https://cloud.google.com/maps-platform/pricing/sheet/?hl=ja)は、以下の通り
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165108/f8394476-ec41-733f-5ba5-ca3465d42910.png)

いまいちピンと来ないので、1回のリクエストあたりの日本円でいくらかかるのか計算してみました

|リクエスト回数|1リクエストあたりの料金|
|---|---|
|0～100,000回まで|**0.54円／1回** (5ドル * 108円 / 1000回)|
|100,001～500,000回まで|**0.43円／1回**  (5ドル * 108円 / 1000回)|

つまり「1回のリクエストあたり`約0.5円`」かかります。（意外とお高い...）

## 対策

現場の偉い人は、Googleに問い合わせて「Directions APIの利用に関する割引の交渉」を行っていたようですが、最終的にはRedisに「Directions APIから返却された経路情報」をキャッシュさせました

具体的には、以下のような処理を組み込みました

- Redisに「A地点からB地点までの経路情報」があれば、キャッシュさせたデータを再利用
- キャッシュされたデータなければ、Directions APIから情報を取得してRedisにキャッシュを保存  
(有効期限1ヶ月)

上記の対応後、Directions APIのトラフィック推移は以下のように変化しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165108/c775081e-2c86-2748-7a28-5699b2059d4d.png)

対応直後から、リクエストのトラフィックが激減しています。
翌日からの課金額も、一日あたり平均**1,500円**ほどに落ち着きました。

## 再発防止策

1. GoogleMap Directions APIに関わらず、課金が発生しうるサービスはドキュメントをしっかり読み、どんな請求が発生しうるかを把握しましょう

2. 利用しているサービスに関するナレッジや、先人達が体験したエピソードを読みましょう
※ GoogleやQiitaで「クラウド破産」で検索すると、面白い記事がたくさんヒットします

3. GCP管理ツールの[予算とアラート](https://cloud.google.com/billing/docs/how-to/budgets?hl=JA&visit_id=637112032436584891-2800040266&rd=1)機能を使いましょう

---

私は途中からプロジェクトに参画したことに加え、問題が起きた部分の担当箇所ではなかったため「高額課金/請求の責任」は追及されませんでしたが、皆さんも気をつけてくださいね
MACとYAMAHAのネットワーク機器

自分用にメモ

#事の始まり
##社長「事務所を移転するぞー、よろしくねー（丸投げっ）」
事務所を見つけましたー（安い！）♫
内装・引越し業者を決めましたー（安い！）♫
で、ネットワークは…？
##管理部門担当者「わからないから宜しくねー♫」
※当社ではWEBアプリケーションを内製しているためMAC端末だらけです。
事務所を移転する時にWi-Fiを再構成することにしたのだけど
ネットワーク業者「MACとYAMAHAのAccessPointの相性が悪いという実績がありまして…」
僕「でも機器を使いまわしたいの♫」

まぁ、今まで大きなトラブルがなかったのでそのまま押し切ってYAMAHAのAccessPointを使うことにしました。
#結局ネットワークは…
WLX302 ✖️ 3台
WLX313 ✖️ 3台
これをRTX1210につなぎ込んで…

WLX302は業務用途以外に来訪者の為にGuest用SSIDを用意してタグVLanで分離、セキュリティを確保しました。
##いや、ここまではなんら問題がなかったのですが…

運用を始めてみて運用状況の確認、MACアドレスフィルタリングの設定などWLX302、WLX313、RTX1210にアクセスをしようとすると…
telnetは問題はない[^1]のですがWebアクセスをすると認証は通るものの画面表示が完了しない、完了してもほかの画面に遷移しない…
Safari,Chrome,Braveとブラウザを替えたりと色々と対処してみたのですが一向に改善しない。
（ Brave ）が多少マシな動きをしたくらい[^2]。

##諦めてWindows機を用意してWindows機で運用をしていました。
が、先日ふと別件対応をする為にMACの簡単なメンテナンスをしてみました
・MACをSafeboot
・ディスクユーティリティでFirstAidを実施
これだけを実行してみました。
#MAC端末でWEBコンソールがサクサクと
気まぐれでYAMAHAの各ネットワーク機器のWeb管理画面にアクセスをしてみたら！
サクサクと動くではありませんか！！！
どのブラウザでも動きます！！！

「MACとYAMAHAは相性が悪いのかなー」くらいに思ってなんら原因追求をしていなかったのですが問題はMAC端末側だったんですねー…orz
#今日のお勉強
特にオチは用意していません、出来るだけ端末はクリーンな環境を保ちましょう:persevere:
#おまけ
##Windows8.1
何故か繋がらないんですよねーWi-Fiに。
いや、正しくはAPにはつながっているしRouterにもリーチしているのだけど何故かInternetに出られない…
今更Windows8.1を使っているのが悪いんだけど。
##MACのターミナル
[^1]: MACのターミナルからRTX1210にTelnetでアクセスをしてみると文字化けします。
　 文字化けを治すには日本語（Shift-Jis）に設定をしましょう
　 Unicode（UTF-8）に戻し忘れて他のサーバにアクセスすると？？ってなるけどね
　 ターミナル > 環境設定 > 詳細 > 言語環境：テキストエンコーディング
[^2]: WLX302のWEBコンソールはなんとか動くこともあるけどWLX313はTop画面を表示するのが精一杯でした
指先一つで立ち上げる CWL ツール・ワークフロー作成環境



# CWL 作成環境、皆さんどうやって作ってますか？
CWL の処理系である cwltool を始め、CWL 公式で提供されているツールの多くは Python 製です。そのため `pip` コマンドなどで各種ツールのインストールが可能です。

しかし、pip、pipx、pipenv、venv、conda のどれを使えばいいか(or どの組み合わせで使えばいいか)、[Python 2 が2019年で EOL](https://www.anaconda.com/end-of-life-eol-for-python-2-7-is-coming-are-you-ready/) するから Python 3 で環境構築しないといけないけど、手順は Python 2 と同じ方法で大丈夫なの…？、など環境構築の際に様々な選択・確認を迫られます。

今回はこれらの問題に終止符を打つため、cwltool などの CWL 処理系や、CWL 用の IDE 機能を提供する benten をインストールして開発環境を整える決定版の方法を説明…**しません！**

21世紀になってから、すでに20年目に突入しようとしています。人類はそろそろ環境構築の苦労から解放されるべき。

# 前提条件
残念ながら、いくつかのソフトウェアはまだ自分でインストールする必要があります。敗北感に苛まれながら以下を各自でインストールしてください。

- [Visual Studio Code](https://code.visualstudio.com)
- [Remote - Container extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) (VSCode の拡張)
- git
- Docker (Docker for mac、Docker for Windows でもいけるはず)

また、以降で説明する手順は Github アカウントを持っていることを前提としていますが、アカウントがなくても特に問題ありません。

# で、どうやるの？
VSCode の remote container 拡張を使うと、リポジトリを指定したコンテナ内に展開(厳密には volume mount)し、コンテナ内にインストールされたツールを使って開発することができます。CWL用に必要な設定を置いた[テンプレートリポジトリ](https://github.com/tom-tan/cwl-for-remote-container-template)を用意したので、今回はそれを使って開発環境の設定も含んだ新規リポジトリを作成します。

以下が具体的な手順です。

- 以下の URL にアクセスします
  - https://github.com/tom-tan/cwl-for-remote-container-template
- ページ内の `Use this template` をクリックして新規リポジトリを作成する
  - Github アカウントを持っていない方は、単純にこの工程をスキップしてください
- ローカルにリポジトリを clone する
  - Github アカウントを持っていない方は、上記の リポジトリを clone してください
- VSCode から `Remote-Containers: Open Folder in Container...` (画面左下の `><` みたいなボタンから選択できる) を使い、clone したリポジトリを開く
- できあがり！
  - ~~指先一つじゃなかった~~
  - 新規ターミナルからコンテナ内にインストールされた各種ツール (`cwltool`、`docker`、`cwltest` など)を使えます。
      - 昨日[紹介した](https://qiita.com/tm_tn/private/2c789c5b3c28e3eb3c9a) [`zatsu-cwl-generator`](https://github.com/tom-tan/zatsu-cwl-generator) もインストール済みです
  - コンテナ内にインストールされた [benten](https://github.com/rabix/benten) (CWL 用の [language server](https://langserver.org)) により、動的なエラーチェックなどがデフォルトで有効化されています。
  - Travis CI や Github Actions など、複数の CI サービス用のテンプレートが標準で提供されています。そのため、各サービスと連携するだけで、CWL の動作テストをコミットごとに自動的に行うことが可能です。
  - (詳しい人向け) Remote container は docker-compose を使った複数コンテナ環境もサポートしています。今回紹介したテンプレートでは docker-compose と `docker:stable-dind` コンテナを活用することで、コンテナ内でも通常の環境と同じように、コンテナを使用する CWL の動作確認などを行うことができます。

# FAQ
- 追加であのパッケージがほしい
  - `.devcontainer/devcontainer.json` の `postCreateCommand` フィールドに、コンテナ作成 or pull 後に実行するコマンドを指定できます。

    ```json:.devcontainer/devcontainer.json
    {
      ...
      "postCreateCommand": "apt-get update && apt-get install -y hogefuga",
      ...
    }
    ```

- この記事のフォーマット、[別の Advent Calendar](https://qiita.com/tm_tn/items/7f966c38f6f9a3820565) でも見たような…
  - 気のせいです！

# TODO
PR お待ちしてます！

- もっと便利になる設定各種

# 最後に
リポジトリにソースコードや CI 設定だけでなく、開発環境も含め配布する時代がやってきました！
VSCode で開発をしている方は、ぜひ活用しましょう！
第二回 Backbone.jsのModelについて

## 本記事の目的
* Backbone.jsのModelを理解する

---
## Modelとは
単一データを保持するためのモジュールです。

---
## Modelの属性について
`Model` のデータは `属性` として管理します。
基本的に `Model` を扱う際にはこの `属性` の取得や設定を行います。

---
## Modelの生成方法
もっとも簡単な `Model` の生成はこちら。

```javascript
const exampleModel = new Backbone.Model()
```
この状態では属性がない `Model` が生成されます。
属性を設定した `Model` を生成する場合はコンストラクタの引数で指定します。

```javascript
const exampleModel = new Backbone.Model({name: 'うる太郎', age: 30})
```
上記で生成したModelのイメージが下記になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38694/b24f998a-0330-74e2-7a10-82e042b94263.png)

---
## 属性の取得
属性の取得は `get` メソッドを使用します。

```javascript
const exampleModel = new Backbone.Model({name: 'うる太郎', age: 30})
exampleModel.get('name') // => うる太郎
exampleModel.get('age')  // => 30
```

---
## 属性の設定
属性の設定は `set` メソッド使用します。

```javascript:単一の場合
const exampleModel = new Backbone.Model({name: 'うる太郎', age: 30})
exampleModel.set('age', 31)
exampleModel.get('age') // => 31
```
```javascript:複数の場合
const exampleModel = new Backbone.Model({name: 'うる太郎', age: 30})
exampleModel.set({name: 'うる', age: 31})
exampleModel.get('name') // => うる
exampleModel.get('age')  // => 31
```

---
## Modelの初期値について
コンストラクタの引数で指定する以外にも `defaults` に属性の初期値を設定することで、初期値を持った `Model` を生成できます。

```javascript
const ExampleModel = Backbone.Model.extend({
  defaults: {name: '名称', age: 0}
})
const exampleModel = new ExampleModel()
exampleModel.get('name') // => 名称
exampleModel.get('age')  // => 0

// インスタンス生成時に指定した場合はそちらが優先される
const overrideModel = new ExampleModel({age: 30})
overrideModel.get('age') // => 30
```

---
## まとめ
* Backbone.jsのModelとは  
単一データを保持するためのモジュール
* Modelのデータは`属性`で管理している
* `属性`の取得/設定は`get`/`set`メソッドで行う
Angular で HTTP リクエスト送信時にパラメータをいい感じにエンコードする

# 問題

* Angular で HttpClient を使って HTTP リクエストを送信するとき HttpParams を使ってパラメータを指定するとパラメータの値がエンコードされていないように見える

```ts
let params = new HttpParams();
params = params.append("date", new Date().toISOString());
console.log(params.toString()); // date=2019-12-06T04:26:52.880Z
```

* それならとパラメータの値を `encodeURIComponent()` すると一見問題なさそうだが `%` が `%25` にエンコードされてしまい二重にエンコードされているように見える

```ts
let params = new HttpParams();
params = params.append("date", encodeURIComponent(new Date().toISOString()));
console.log(params.toString()); // date=2019-12-06T04%253A28%253A17.828Z
```

# なにがおこっているか

* HttpParams はエンコードをしていないように見えるが、実際には RFC3986 に従ってエンコードを行っている
* [実装](https://github.com/angular/angular/blob/master/packages/common/http/src/params.ts#L81)としては `encodeURIComponent()` したあとに `@$:,;+=?/` をデコードしている

# どうしたらいい感じにエンコードできるか

* HttpParams のコンストラクターで HttpParameterCodec を実装したエンコード用のオブジェクトを指定できるので `encodeURIComponent()` するだけのクラスを実装して指定してあげれば良い

```ts:エンコーダの実装
export class BrowserStandardEncoder implements HttpParameterCodec {
  encodeKey(key: string): string {
    return encodeURIComponent(key);
  }

  encodeValue(value: string): string {
    return encodeURIComponent(value);
  }

  decodeKey(key: string): string {
    return decodeURIComponent(key);
  }

  decodeValue(value: string): string {
    return decodeURIComponent(value);
  }
}
```

```ts:エンコーダを初期化時に指定する
    let params = new HttpParams({encoder: new BrowserStandardEncoder()});
    params = params.append("date", new Date().toISOString());
    console.log(params.toString()); // date=2019-12-06T04%3A30%3A45.959Z
```

# 参考

* https://stackoverflow.com/questions/49438737/how-to-escape-angular-httpparams
alexaスキルに課金機能（スキル内商品）を実装してみた

タイトル通り、自作のalexaスキルに課金機能（以下スキル内商品）を実装したのでわかる範囲で書こうと思います。参考にしたサイトは下にリンクを貼ってあるので参照してください。
前提として、esaに上がっている川村先輩のalexa勉強会、入門編および初級編を修了しているものとしています。

概要としては、以下の通りです。
1.スキル内商品用のインテントの作成
2.スキル内商品の実装
3.コードを書くときに使うスキル内商品用のパラメーターと応答

1.スキル内商品用のインテントの作成
![スクリーンショット 2019-12-03 13.42.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541914/2fcdc015-b215-22fd-4be4-6488a3bae450.png)
画像のように最低でも”課金をするためのインテント”と”課金を取りやめるためのインテント”の２つのインテントを用意します。”課金をするためのインテント”ではサンプル発話例として「課金をしたい」「追加機能を購入したい」といったフレーズを入れると良いかと思います。”課金を取りやめるためのインテント”では「返金して」「課金を取りやめる」といったフレーズを入れましょう。

2.スキル内商品の実装
カスタムバーの下の方にあるスキル内商品のタブを選択します。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541914/f2f30571-91f5-2bfe-108d-b04b8796f4de.png)
画面右上のスキル内商品を作成を選択し、商品の参照名と商品の種類を選択します。参照名はコードの中に組み込むものなのでユーザーには知られることはありません。設定が完了したら”スキル内商品を作成”を選択します。![スクリーンショット 2019-12-03 14.01.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541914/82346bae-1aba-02ff-69b8-712235a8b55d.png)
次に商品の内容を編集していきます。
![スクリーンショット 2019-12-03 14.03.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541914/f50715ce-bc4d-92ec-ab51-b97db9b3b8a2.png)
商品ID...あとでコードに記述することで商品とスキルを結びつけます。今は無視でOKです。
参照名...先ほど自分でつけた名前です。
サポートされる言語..."+新しい言語を追加"を選択します。自分が対応させたい言語を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541914/2aad3435-8f4a-8448-0b78-e6ce0884d7f8.png)
![スクリーンショット 2019-12-03 14.21.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541914/461da090-2010-e916-c1c2-9fda0fa07140.png)
上の画像のように必要事項を書いていきます。アイコンは持っていなければ矢印先のサイトからアイコンを作成することができます。
あとは商品の価格の設定、税金の種類、あとは審査の時の操作手順を書いていきます。価格の設定は日本でのみサービスを提供する場合はamazon.co.jpにチェックを入れて値段を設定しましょう。税金の種類は当てはまるものがなさそうだと感じたらソフトウェアでいいはずです。
全項目入力できたら保存しましょう。

3.コードを書くときに使うスキル内商品用のパラメーターと応答
コードについては以下のリンク3のgithubページを参照してください。ここではコードの中で登場するパラメーターと応答について書いていきます。詳しくはリンク2をご参照ください。
![スクリーンショット 2019-12-05 14.08.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541914/e5c7a5ff-9d19-98db-75ff-cf4f3ab68d63.png)
①productId...スキル内商品の商品Idです。
②referenceName...先ほど自分で設定したスキル内商品の参照名です。
③type...スキル内商品の種類です。（消費型or買い切り型orサブスクリプション型）
④name...商品名です。
⑤summary...スキル内商品内で規定した商品の説明です。
⑥entitled...スキル内商品が購入済みかどうかを表しています。ENTITLED(購入済み)、NOT_ENTITLED(未購入)のどちらかの値を返します。
⑦purchasable...スキル内商品がまだ購入可能かどうかを表しています。PURCHASABLE(購入可能)、NOT_PURCHASABLE(購入不可能)のどちらかの値を返します。
⑧activeEntitlementCount...ユーザーがスキル内商品を購入した回数を表します。消費型の場合はどんどん加算されていきますが、買い切りorサブスクリプション型の場合は常に1or0の値を返します。
⑨purchaseMode...テスト下での購入(TEST)か公開中のスキルでの購入(LIVE)かを表します。

購入処理後、JSONのINPUTに200が返されていれば正常に購入が完了しています。200以外の数字が返されている場合は何らかのエラーが出ています。それについても以下のリンクをご参照ください。

終わり。

リンク1: https://developer.amazon.com/ja/docs/in-skill-purchase/create-isp-dev-console.html
リンク2: https://developer.amazon.com/ja/docs/in-skill-purchase/in-skill-product-service.html
リンク3: https://github.com/alexa-labs/skill-sample-nodejs-simple-hello-world
PHPフレームワーク｢composer dump-autoload｣の重要性について

# はじめに

この記事の対象者は、｢PHPはやったことあるけど、フレームワークはあまり使ったことないよ｣って人を対象にしております。
フレームワークの構成を壊さずにプロジェクトを遂行できるように少し豆知識を。

と、言う筆者も実は昔。。。
あんまり理解せずにフレームワークの構成を壊していろいろ作っちゃっていました。。。

しっかり構成に従って効率的にコーディングしていきましょう！！！
その上で重要になるのがいろいろありますが、今回紹介するのは***composer dump-autoload***です。

フレームワークを使用せずにPHPでスクラッチ開発をしていると、よくソースの頭に書くものがありますよね？

それはコチラ！

```
require('ファイル名');
require_once（'ファイル名'）;
```

Laravelなどフレームワークを使用してコーディングする際は、上記の記述は不要です。
他のクラスを参照したくても上記の記述は書いちゃダメ。

じゃ、どうすればいいの？？ってなりますよね？

次に進みます。

# ダンプオートロード

なんかカタカナで見出し書くとダサく見える。。。
それはさておき。

よく使うコマンドとして

```
$ composer dump-autoload
```
があります。

この海のものとも山のものとも知れず何者か？
これは、わかりやすく言うと、冒頭に紹介した｢requireなんとか」のコードを不要にしてくれるものです。

例えば、何か共通的に使いたいクラスを作ったとします。
そのクラスを使いたいソースの冒頭に｢requireなんとか」と書きまくって対象のクラスを読み込む。
これが、従来のスクラッチ開発。

と、なると。。。

・クラスを削除した。
・ファイル名を変更した。
・あちこちで使いたい。

全部の「require」の記述を変更しなくてはなりません。

そこで便利なのが、｢composer dump-autoload｣
このコマンドを実行すると、Vender配下のとあるファイルに全ての*.phpファイルのパスが自動的に記述されます。
そして、何がオイシイノ？

それは、requireなんとかを使用無くても、どこからでも対象のソースやクラスを呼び出せるのです。
また、クラスを増やした、ファイルを増やした、変更した。
そんな場合も「composer dump-autoload」を打つだけです。

変に「require｣を使用するときっといつかバグるでしょう。
そしてメンテナンス性に欠けます。

そのため、｢require｣は忘れてください。
｢require｣の単語を書くのは、バリデーションチェックの定義くらいです。


# 補足
独自に`app\Logic\Sample`など各機能毎にフォルダ分けしてクラスを分けたい場合もあるでしょう。
そんなときは、`composer.json`ファイル内にある`classmap`の配列の箇所に作成したフォルダのパスを追記してください。
そうすると、独自に作成したフォルダも`composer dump-autoload`で拾ってくれます。

---
以上、｢なんかソースが無いってエラーなった｣ってときは、まずは今回紹介したコマンドを打ってみましょう。
python2と3では"1/2"の答えが違う

python2と3では整数同士の割り算の答えが違います。

```python:python2
>>> 1/2
0
```

```python:python3
>>> 1/2
0.5    
```
 

<br>
 
python2とpython3の両方で動きうるコードを設計するなら、
`1/2 = 0.5`を期待する場合：

```python:python2or3
>>> 1./2.
0.5
```

`1/2 = 0`を期待する場合：

```python:python2or3
>>> int(1/2)
0
```

こんな感じにしとけばいいですね。

## **追記**
`__future__`モジュールを使うことで、除算がpython2系でもpython3系と同じ動作をするようにできるようです。`__future__`モジュールにはpython2系とpython3系の互換性を補完する機能が備わっており、その中の`division`をimportします。


```python:python2or3

from __future__ import division

print(1/2)   # => 0.5
print(1//2)  # => 0
```

#### 参考
 - @LouiS0616 さんのコメント
 - [__future__ モジュールについて - さりんじゃーのプログラミング日記](http://salinger.github.io/python/20140211-future-module/)
[Elm] PortをTaskで定義する思考実験

[Fringe81株式会社アドベントカレンダー](https://qiita.com/advent-calendar/2019/fringe81)の6日目です。

PortをTaskで定義できたら便利だと思って調べたらプロポーザル用に作られたレポジトリがあったため紹介。

[elm-task-port-example/Main.elm at master · eirslett/elm-task-port-example · GitHub](https://github.com/eirslett/elm-task-port-example)

今回関心ある部分を抜き出してみる。

```elm
port getUser : UserQuery -> Task UserError User

type Msg = LoadUser | UserResult (Result UserError User)

getUserTask : Task UserError User
getUserTask = getUser { sessionId = "123", userId = 456 }

update msg model =
  case msg of
    LoadUser ->
      (model, Task.attempt UserResult <| getUser { sessionId = "123", userId = 456 })

    UserResult (Ok user) ->
      ({ model | currentUser = Just user, error = Nothing }, Cmd.none)

    UserResult (Err error) ->
      ({ model | currentUser = Nothing, error = Just error }, Cmd.none)
```

PortをCmdにするのではなくTaskにする
そうするとTask.attemptでMsgに結果をペイロードとするCmdを発行でき、updateで受け取りそのままcaseでパターンマッチしてコールバックを実行できる

コンパイルはもちろんエラーになるのだけど、これできるようになると便利だなと思った。
（ちなみに、過去にはPortはTaskで定義できたようなので、意図的にできないようにした背景があるのかもしれない）

```sh
$ npx elm-make Main.elm --output Main.js
-- PORT ERROR --------------------------------------------------------- Main.elm

Port `getUser` has an invalid type.

19| port getUser : UserQuery -> Task UserError User
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You are saying it should be:

    Main.UserQuery -> Task.Task Main.UserError Main.User

But you need to use the particular format described here:
<http://guide.elm-lang.org/interop/javascript.html#ports>

Detected errors in 1 module.
```

古いversionのPortの仕様について書かれた記事を紹介しておく。

[ElmのTaskについて - @nobkz | Qiita](https://qiita.com/nobkz/items/56267f565e288278d865)

以上。
Atomで新規ショートカットを割り当てたい(Auto Indent,Open In New Window)

# Atomで新規ショートカットを割り当てたい
Atomで既に割り当てられているコマンドを変更する方法はいろいろ紹介されていましたが、
新規のコマンド(操作)を登録する方法はあまりなくて困ったのでその方法を紹介します。

既に割り当てられているコマンドを変更する方法はこの辺りを参考に。

『Atomのキーボードショートカットのカスタマイズ方法』
https://takezoe.hatenablog.com/entry/2015/11/28/235755
『atomでショートカットキーを作成・変更する方法』
https://omachizura.com/2016/08/atom-shortcut.html

## 新規で登録したいコマンド
**・自動整形(Auto Indent)**
（画像では既に割り当てを行っているため右側に灰色でCtrl+Iと書かれています）

|![auto indent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507580/773d8aab-463a-9832-27f1-67d8ee0fe975.png)
|:-:|

**・新規ウィンドウで開く(Open In New Window)**
（File>New Windowとは違い、タブを右クリックした際に今開いているタブを新規ウィンドウに変更する方法です）

|![Open In New Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507580/36f0f0b3-cab4-8d62-6d06-99a4f8e61e39.png)
|:-:|

登録したかったのは上の２種類です。

## 自動整形(Auto Indent)
Auto Indentはデフォルトで割り当てがありませんでしたが、
調べたところ既にやられている方がいらっしゃいましたので
それを参考にさせていただきました。

『Atomでインデントを一括で整形する』
http://dormouse666.hatenablog.com/entry/2016/03/28/005857

基本的には変更の際と同様に、
`File>Keymap`で`keymap.cson`を開き、以下のように追記します。

```keymap.cson
# 自動インデント整形
'atom-text-editor':
  'ctrl-i': 'editor:auto-indent'
```

**それぞれの要素の説明**
'atom-text-editor' : セレクタ(Selector)
'ctrl-i' : 登録したいショートカット(Keystroke)
'editor:auto-indent' : 操作(Command)

## 新規ウィンドウで開く(Open In New Window)
基本的には上のものを応用してOpen In New Windowの
ショートカットも登録すればいいはずなのですが、
自分で決められるショートカットはともかく、
このSelectorとCommandがわかりません。

Selectorは似たようなコマンドと同じようなものになると予想し、
操作的にも似たようなところにある`Reopen Closed Tab`を
`Settings>Keybindings`で検索したところ`body`というSelectorであることを確認。

Commandは中が [ hoge : fuga ] という形式になっています。
後半はメニューに書かれている操作そのものを大文字⇒小文字に変換し、
スペースをハイフン[-]で置き換えたものだと前項から想像できます。
そのためこの場合は [ hoge :open-in-new-window] となるでしょう。
問題は前半です。これはなかなか見つかりませんでしたが、

『Atomのショートカット』
https://note.nkmk.me/atom-shortcut/

こちらでコマンドパレットの検索の仕方を知りました。
コマンドパレットは`ctrl-shift-p`で開くことができ、
Keybindingsと違いショートカットが登録されていないコマンドも検索することができます。
ここに`Open In New Windows`と検索すると候補に`Tabs:Open In New Window`と表示され、
この`Tabs`がAuto Indentにおける`editor`の部分になることが推測されます。

|![commandparett.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507580/fee2a280-385d-f457-5ca6-011d55b1c935.png)
|:-:|

これらからkeymapに追加するテキストはこのようになることが予想されます。

```keymap.cson
# 新しいウィンドウで開く
'body':
  'ctrl-N': 'tabs:open-in-new-window'
```

保存してAtomを再起動してみたところ、無事動作することが確認できました。


## 結論
今回は新規に割り当てをしたい２つのショートカットについて調べましたが、
Open In New Windowの項を読んでいただければ、それ以外でも
新規で割り当てたいコマンドのセレクタやコマンド名を調べることができると思います。
Atomで新規にショートカットを割り当てたいけどよくわからない、という方の参考になれば幸いです。
またこんな回りくどいことをしなくても調べる方法があるよ！という方も教えていただければありがたいです。