OmniAICreator/Qiita-1.07M huggingface dataset:
MaplatEditorで不正確な古地図をマッピングする（２）画像登録

Maplat Advent Calendar 17日目ですが、ギリ12月17日以内に投稿できなさそうです...が、少し過ぎても頑張ります。

本題に入る前に、この1人で頑張っているMaplat Advent Calendarが、[tomowarkar](https://qiita.com/tomowarkar)さんの「[おひとり様カレンダーランキング【2019/12/17 17時更新】](https://qiita.com/tomowarkar/items/c3939c0985c36929b35a)」記事で採り上げていただきました！
ありがとうございます！
せっかくなので、MaplatEditorで今日以降サンプルマッピングする地図画像、奈良あたりのパブリックドメインな古地図画像使うつもりだったのですが、方針を変えて、tomowarkarさんの数日前の記事、「[Goで地形生成ツールを作る](https://qiita.com/tomowarkar/items/1645c4443a18c6948a59)」で生成されたランダム地形地図を使ってみることにしました！
ノリで事前承諾取らずやってますが、画像の著作権...とかは、tomowarkarさん大目に見てくれるものと信じています...すみません...。
![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_235435_b461ba79-eaeb-c26f-33ce-3b388eae9894.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/927196d5-61e7-3de8-4398-c74b85e408f4.png)
これが件の自動生成地図ですね。
これを、だいたいイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/c8c2a69a-4dde-06dd-d571-206e98cff2b8.png)
ぐらいの感じで現実の地図と重なり合うようにマッピングできたら面白いかなと思いました。
（明日実際にマッピングしてみて、歪み過ぎてて無理だったら微調整します）

というわけで、この画像をMaplatEditorに登録してみましょう。
昨日の要領でMaplatEditorを起動して、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/edeac53d-b122-4816-04ec-6b1dd18d40fb.png)
この「新規作成」のボタンを押してみます。
すると、
![スクリーンショット 2019-12-18 0.02.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/6224f850-366f-69ca-b256-491d2627bc2e.png)
こういう画面になります。

ここで、右上の方にある「地図アップロード」と書かれている部分、これわかりにくいですけど実はボタンなので押してみると、
![スクリーンショット 2019-12-18 0.05.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/5940acc4-45d6-de2d-a7dd-1ab26058532b.png)
こんな感じでアップロードする地図画像のセレクト画面が出てきます。

ここで、用意した地図画像をアップロードしてやると、しばらく待たされたのち、アップロードが完了します。
アップロード完了後、エディタのタブで左から2番目、「対応点設定」のタブを選んでやると、
![スクリーンショット 2019-12-18 0.09.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/438bcf3f-c629-33e3-ac1d-6f73bd6d77cc.png)
こんな感じになっていて、地図のマッピングができる状態になっているのがわかります。

ですが、マッピングは明日に回して、今日はこの状態をセーブしましょう。
「メタデータ」のタブに戻ってやります。
セーブするには、メタデータをいくつかデータ入力してやらないといけません。

必須なのは「地図ID」「地図名称（表示用）」「地図画像コピーライト」の3つです。
まずは地図IDですが、自分のエディタ内で一意な半角英数字のIDならなんでも構いません。
とりあえずは`tomowarkar_map`とでもしてやって、一意性を確かめるために「一意性確認」のボタンを押します。
ちゃんと一意なIDであれば、下記のように一意だと確認するダイアログが出てきます。
![スクリーンショット 2019-12-18 0.14.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/6e042c04-cb81-a496-2675-54dcdf8e262d.png)
あとはその他のデータを埋めていくだけですが、必須なものだけでなくとりあえず入れられるところを入れてみましょう。
たとえば、こんな感じです。
![スクリーンショット 2019-12-18 0.17.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/1e879e0a-d96f-4850-ffad-b274015f5153.png)
これだけ埋めると、エディタ右上の「保存」ボタンが押せる状態でアクティブになっているはずです。
「保存」を押してみましょう。
![スクリーンショット 2019-12-18 0.19.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10108/c5f310dd-f007-675a-9f51-811088c3a2d9.png)
保存してOKかどうかを尋ねるダイアログが出て、そこでOKを選ぶと、上のようなダイアログが出て保存が完了するはずです。

これで、一旦エディタを落としても再度編集を再開できるようになりました。
続きは明日以降、いよいよマッピングに移りたいと思います。
[Dart]map は動かないが、for in だと動く場合に確認すべきこと

## 結論
mapでtoListを呼び忘れている。

## 説明
Dartがmapで返すものはIterableであり、これは即座に実行結果を返すものではない。

```dart
final list = ['hoge', 'fuga', 'piyo'];
list.map(print); // Iterableを返却しているだけで、printは実行されない。
```

`toList()`が実行されたときに、渡してきた関数が実行される。

```dart
final list = ['hoge', 'fuga', 'piyo'];
list.map(print).toList(); // toList()が呼ばれたときにmapで渡したprintが実行される。

// 上と下は同じ結果になる。

for (var el in list) {
  print(el);
}
```

## 終わりに
Dart使いはじめたときに、map動かないのに、for in動くなーとか思っていたらこれだったので書きました。
TS書いたあとに、Dart書くと忘れてやらかす。


## 参考
* [Why is map not working but foreach is?](https://stackoverflow.com/questions/44299842/why-is-map-not-working-but-foreach-is)
* [map<T> method](https://api.dartlang.org/stable/2.7.0/dart-core/Iterable/map.html)
* [toList method](https://api.dartlang.org/stable/2.7.0/dart-core/Iterable/toList.html)
しりとりは正規表現で勝ちなさい

#はじめに

はじめまして。営業からRuby on RailsのWebエンジニアになったたっきー(半年)と言います。
僕は文系出身で開発は全くの未経験ですが、一念発起してJOBチェンジした者です。
とても優しく指導して下さっている先輩たちのもと、コツコツと勉強を進めているのですが、やはり分からない事も多く、先輩たちの時間を頂くことが多い恐縮な日々を過ごしています。。

とりあえずRubyを触って半年経ちました。
formの動きとか基礎的なものはようやく動かせるようになりましたが、まだまだ半人前。
そんなちょっとやそっと触っただけで、できる甘い世界ではないですね。

家はシェアハウスに住んでいて住人達から黒魔術ってタイトルのQiita記事をネタにされてブラックマジシャンって呼ばれてます。

#しりとりの戦略

「勝つことは偶然なんかじゃない...!」

以下のサイト曰く、しりとりには戦略があるらしい。
http://shiritorinet.o-oku.jp/hissyouhou.html

サイトの中を見てみると、やはり縛り戦略が有効みたいだ。
しりとりでだいたい小学校高学年から中学校くらいでこの戦略が出てくる。
初めてこの戦略にぶち当たった時は面を喰らうものだ。

[単語別戦略]
「ず」攻め：「ず」で終わる言葉は多いが、始まる言葉が少ない
「ぷ」攻め：カタカナ依存の単語になる・純単語が意外と少ない
「る」攻め：「る」で終わる言葉が多く、「る」から始まる言葉が少ない
「り」攻め：派生語依存度が高い
「ぬ」攻め：受け側の語彙数が限定的である
「う」攻め：●●学校やう終わりの単語が多い

純単語：あなたや私など後に単語をくっつけにくい単語
派生語：プロ●●や●●図などいくらでも前後につけて派生できる単語

しりとりの場合

#しりとりの本質とは

パターンで検索するということ。
例えば、こういったやりとりがあったとします。

＿人人人人＿
＞　還付　＜
￣Y^Y^Y￣
　　　　＿人人人人人人人人＿
　　　　＞　プロ野球選手　＜
　　　　￣Y^Y^Y^Y^Y^Y^Y￣

＿人人人人人人人＿
＞　シュリンプ　＜
￣Y^Y^Y^Y^Y^Y￣

　　　　＿人人人人人人人人＿
　　　　＞　プロ卓球選手　＜
　　　　￣Y^Y^Y^Y^Y^Y^Y￣


勿論、しりとりしててPC使えないじゃんなんて正論をここのコメントに書くことは
そもそも論点が違うのでやめてくれよな。

これらのことから・・・
しりとりがゲームの性質上、縛りの法則が有効な戦略であり
それでいかに相手の語彙力を限界値に持っていくかというのが
しりとりというゲームの本質ということになる。

つまり・・・

{相手の単語の語尾}+●●●+{自分が相手に言わせたい単語}をどれだけ多く作っていくか
ということがこのゲームの戦略である。

#正規表現

さて、勝つための法則がわかった。
ただしりとりをしながら、広辞苑を開くなんて面倒なことはしたくない。
ただ、スマホに単語を入れて予測変換したとしても語尾は決められない。

ここで役に立つのが、正規表現という概念である。

正規表現とは、「メタ文字」(超すごい文字)を使って呼び出す方程式みたいな存在。
DCコミックがバッドマンとかの事をメタヒューマンって呼称してるのはすごい人間って意味だから！

メタ文字一覧　.   ^   $   [   ]   *   +   ?   |   (   )

例えば、相手が「めかぶ」って単語をいってきて、こっちは「く」で勝負したいなって時は
普通にやると頭の中で単語を探しと思う。

ブックとかブラホック、ブラックマジックとかね。

これを正規表現で表すならば、例えば下記のケースなどだ。
ブ*****クとかで検索すると、正規表現という方程式が登録したデータの中から該当する前後のワードが入った単語を出力してくれるのだ。

※一個一個の説明は今回省くから、興味があったら下記URLを見ておいてほしい！
https://www.mnet.ne.jp/~nakama/

#周りの事務仕事してる人にはとても貴重な情報

事務仕事って、意外とロットナンバーとか商品コードとかBCCD00000001111みたいななんの暗号それ？みたいな世界で仕事をしていてctrl+Fとかで検索できるのは知ってるけど、正規表現まで使っていなかったり、調べたけどなんかわからなかったから辞めたって人は多いと思う。

周囲にもしITそんなに強くないよっていう人がいたら、いきなりパソコンの話をするのも疲れるし、しりとりの話題からこういう話題をしてみるのはいかがでしょうか！
Selenium つれづれ2019

今年もテンプレート通りに書きます！（これで何年のりきれるかな・・）

#公式

何は無くともとりあえず本家
http://www.seleniumhq.org
ドキュメントを整備していく　というお話があった通り、綺麗なサイトになってますよ
いろいろな資料が見やすくなってますね。

## Webdriver

今年の最終バージョンは　3.141.59
あれ？変わってない？！いえいえ、最新のSelenium 4 は　Alphaバージョン-3　へと
開発進んでます。くわしくは　@takeya0x86　さんが　[3日目](https://qiita.com/takeya0x86/items/e9052739c0c98bca5a7d)に書かれてますね



##SeleniumIDE
今年の最終バージョンは　3.16.1　
[公式](https://github.com/SeleniumHQ/selenium-ide)

- レコーダーの役割に向けてか、各言語へのエクスポートが精力的に行われましたね
- プラグインでいくかアプリか、みたいな話があったかと思うけどあれはどうなったんだっけ・・・・




## appium
v1.15.1が最新バージョン
http://appium.io

- 内容がIOS、Androidともにテクニカルなところを毎回更新されてますね
- モバイル系のテストではメインストリームなんですかね（自分がやってないのでわかってません）

## WinAppDriver
 v1.2のリリース候補版がでています

- こちらはseleniumと同じプロトコルを使ってwindowsアプリを操作するためのものですが、ＭＳが提供するPowerAutomationでも使われるとのことで、これからも更新されそうです


##selenese-runner
- 旧seleniumIDEで記録したテストケースをコマンドラインから実行する（Jenkinsで実行する場合などですね）SeleniumRCモードで実行しているかたはまだまだいらっしゃるかも。そんな方に向けてメンテナンスを続けていらっしゃいます。今年の最新バージョンは　　3.27.1
 
[selenese-runner](https://github.com/vmi/selenese-runner-java)　


##selenide
Java用のwebdriverラッパー　最新は　v5.5.1
http://selenide.org/

## Geb
- 今年は3.2が最終バージョン 

http://www.gebish.org

##chromeDrive
- 今年の最新は 79.0.3945.36
- 去年からナンバリングが変わって、ブラウザーと連動するようになったのでわかりやすいですね

http://chromedriver.chromium.org/downloads

## Edge Driver 
- 今年の最新は　バージョン：81.0.366.0　ですかね
- Microsoft Edge（Chromium）ようのドライバーが提供されています

[Microsoft WebDriver](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/)

##geckodriver
- こちらは　0.26.0　が最新
- リリースは２回と少し寂しい状態　

https://github.com/mozilla/geckodriver

# コミュニティー

## SeleniumConf

今年のカンファレンスは何と言っても日本で初開催！　
http://seleniumconf.com/

内容は　YouTubeにも　アップされています
[SeleniumConf Tokyo](https://www.youtube.com/channel/UCyK-OuysmEZX6a54rfXFPEQ)

そしてロンドンで、開催でした。
日本からも参加されたtmasuharaさんが　昨日の記事でレポートされてますね
[Selenium Conference London参加レポート](https://note.com/tmasuhara/n/nd1ae95372e3b)


また、日本での開催があるといいな〜


##日本Seleniumユーザーコニュミティー
- あれ？今年どうだっけ・・・
 
[システムテスト自動化カンファレンス2019](https://testautomationresearch.connpass.com/event/144768/)



## slackチャンネル
-　こちらも2回開催されていろいろな話題が飛び出しました

3月に　第14回 Selenium談話会 in Slack
9月に　第15回Selenium 談話会 in Slack
https://seleniumjp.slack.com/


#ツール
##pitalium
Ver 1.2.4のままですね。安定？

https://www.htmlhifive.com/conts/web/view/pitalium/

##sitoolkit
3.0.0-beta.2 になってますね。Java11 そして　SeleniumIDE3　対応と気になる文字が並んでいます
https://sitoolkit.org/sit-wt.html

#書籍
- 今年は直接的な内容となる書籍はなかったような。


# えーっと
- Ｗ３Ｃで標準化されこの流れていくか？とおもいきや、testcafeといったwebDriverを使わないものが出て来たり。。。
- RPAの下回りの技術として使われていたりと、おもてみには見えないけれど技術として安定して来た現れですかね。

以上、seleniumについて、今年もつれづれに書いてみました。
bundle経由で入れたfastlaneがcommand not foundと仰るならrbenv使ってはどうだろう

## 要点
環境構築で、bundle経由でfastlane等をinstallしたが、

```sh
$ bundle exec fastlane dev
```
を叩いたところ、`command not found`とerrorが出た。

bundle 2.1.0による問題らしいが、それを知らずに自己解決した話。
同じ問題にぶち当たって、解決方法を求めている人は、`maybe resolved`、`advice1`、`advice2`あたりだけ見ればいいと思う。

## ready
さぁ環境構築しよう！

```sh
$ bundle install

・・・

Bundle complete! 3 Gemfile dependencies, 90 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
```
よし成功だ！

## deploy
開発したので、bundle経由で入れたfastlaneで配信するぞ！

```sh
$ bundle exec fastlane dev

・・・

bundler: command not found: fastlane
Install missing gem executables with `bundle install`
```

はっ？
なんでー？どうしてー？

```sh
$ bundle list
Gems included by the bundle:

・・・

  * fastimage (2.1.7)
  * fastlane (2.134.0)
  * fourflusher (2.3.1)
 
・・・

Use `bundle info` to print more detailed information about a gem
```

ちゃんとあるじゃん？でもコマンド叩くと`command not found`ってでるじゃん？

## maybe resolved
もう普通に`gem install fastlane`したりとか色々ググって出たものをかたっぱしから試したけど解決しないの。

最終的にRubyのversionか？Catalinaが悪いか？systemのRuby使ってるのがいかんのか？とか思って、次のコマンドの順で叩いてたぶん解決した。(たぶんというのは、fastlaneで別のエラー出て、他の作業をやり始めたので、deployされるまで確認していないため。)

長いのでコマンドだけ羅列していく。

```sh
$ brew install brew install rbenv ruby-build
$ rbenv install 2.6.5
$ rbenv global 2.6.5
$ rbenv exec gem install bundler
$ rbenv rehash
$ rbenv exec bundle install
$ rbenv exec bundle exec fastlane dev

・・・

[✔] 🚀 
[11:11:10]: ----------------------------------------
[11:11:10]: --- Step: Verifying fastlane version ---
[11:11:10]: ----------------------------------------
[11:11:10]: Your fastlane version 2.134.0 matches the minimum requirement of 2.68.0  ✅
[11:11:10]: ------------------------------
[11:11:10]: --- Step: default_platform ---
[11:11:10]: ------------------------------
[11:11:10]: Driving the lane 'ios dev' 🚀
[11:11:10]: -----------------------
[11:11:10]: --- Step: cocoapods ---
[11:11:10]: -----------------------
・・・
```

ζ*'ヮ')ζ < ｷﾏｼﾀﾜｧ!

## advice1
どうもbundleの最新版2.1.0に問題があるらしい…
それをたまたま踏み抜いてた模様。

<追記#2019-12-18_12:45>
・ bundler version 1.17.3でも自分の環境では同様に発生しているので、versionが問題ではなさそう。

<blockquote class="twitter-tweet" lang="ja">Twitter<a href="https://twitter.com/mt_hodaka/status/1206932841012981760?s=20"></a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

bundleが入ってない状態から入れて起きたし、アップデートしたわけじゃないから気づくの無理っす。
ただ、bundleのissueは見逃していた気がするので、issue建てにいくか見に行けよってのが最短だったかもしれない。疑わしいとこ多すぎるのもつらいな。

## advice2
bundlerのversionが問題なら、version下げたものをinstallしたらいいじゃん。との助言。

<blockquote class="twitter-tweet" lang="ja">Twitter<a href="https://twitter.com/yutailang0119/status/1206964269910085632?s=20"></a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

自分の環境は色々ためしすぎたせいか、`gem install bundler:2.0.0`とかだとPermission errorが出て、`sudo gem install bundler:2.0.0 -n /usr/local/bin`でローカル環境にinstalは
成功するのだけど、`bundle --version`でversion確認すると`2.1.0`って出てうまく入らない…。
bundleをuninstallしてからやれば上手くいくのだろうか？
よく使うGitコマンドまとめ

ここではよく使うGitのコマンドを**こういう状況で使う**という背景と共にまとめました。
自分用のメモでありますが、もしどなたかの手助けになればと思います。
間違いなどありましたらご指摘ください。今後も随時追加、編集していきます。

#### STASH 一時避難
タスクAを作業中に、タスクBを優先するように言われてしまった。。でもタスクAはまだ全然途中。。そんな時はSTASHをして、自分の書いたコードを一時避難しておけます。

```
git stash save “タイトルを書く”
```

これで書きかけのコードはSTASH（一時避難）されて、コードはブランチは切った状態（作業する前）に戻ります。

さて、タスクBは無事に終わり、タスクAの作業を再開。STASHしておいたタスクAのコードを元に戻す時はまずこのコマンドでSTASHの一覧を確認しましょう。

```
git stash list

そうすると、こんな風に新しい順にリストが出ます。↓

stash@{0}: On branch_name: タスクA作業途中
stash@{1}: On branch_name: タスクC担当変更のため保留
```

該当するSTASH、この場合は`stash@{0}`なので、このSTASHを適用します。

```
git stash apply stash@{0}
```
これで一時避難しておいた書きかけのコードを元に戻す事ができます。

でもこれは既存のファイルを修正していた場合で、新規のファイルを作った場合はGitは監視していないので、STASHしても一時避難されません。なので、新規ファイル、画像を含む場合はこうしましょう。

```
git stash --include-untracked
```
`git stash -u`でも大丈夫という記事も見かけますが自分は`git stash --include-untracked`じゃないとダメでしたので、こちらを推奨します。

ちなみに、STASHしてしばらく経ってリモートブランチと差分が出てしまった場合はConflictすると思うので、その場合はConflict解消してください。

---

#### 未マージのリモートブランチをローカルに取り込む
チームメンバーのプルリクエストのレビュー依頼が来たけど、コード読んだだけじゃわからない、自分の環境に取り込んで動作の確認がしたい時。

まずリモートのブランチを取り込む。

```
git fetch
```

そしてgit branch -aでリモートのブランチも全て表示させます。
`-a`をつけないとローカルのブランチだけが表示されます。

```
git branch -a

ブランチ一覧が出てきて、リモートのブランチ名は赤色で出てきます。
リモートのブランチ名は大体こんなんだと思います。（ちなみに現在のブランチは緑色）
remotes/origin/team_member_branch
```
そして、そのブランチをローカルにPULLしつつ、新しいブランチも同時に切るのがこのコマンドです。GitHubのPRからコピペしてしまっても同じです。

```
git checkout team_member_branch
```

こうしたら自分の環境でチームメンバーの書いたコードを確認しつつ、動作のチェックもできます。

---

#### Pushしたものに余計なファイルを入れてしまってた。。消したい。。

```
git reset --soft HEAD^ 
これで直前のCommitを取り消して、ステージング状態（git add した状態）まで戻る
Commit文をミスった時もこれで取り消せます。
```

```
git status 
これでステージングにあるファイルの一覧が見れますので、不要なファイルのパスをコピーして、resetします。

git reset ファイル名
```
あとはもう一回commit、pushするだけ。
Commitを増やしたく無い場合は、これで強制プッシュすると前回のCommitに上書きしてくれるので、不要にCommitを増やさずに済みます。

```
git push -f
```

---

#### マージの取り消し

PR出して無事にマージされたけど、バグが見つかった。。。
すぐに修正したいけど、難しい時、一旦マージを取り消したい。。
 
まず、プルリクページのRevertボタンをクリック
下の方にあります。
![unnamed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/46b572c7-b41d-4814-7f68-76e761495a11.png)

打ち消しのプルリク発行ページに飛ぶので、いつも通り普通にプルリクを発行。タイトルも内容もブランチ名も自動で生成されるので、基本このままでいいと思います
（ローカルルールがある場合はそれに従いましょう）
![unnamed-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/559426ae-a854-600c-39bd-ae1a2cdbbd6e.png)

あとはレビュー依頼など出して、これをマージしてもらえばOK

![unnamed-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/de6dda91-e200-7355-fd3b-eb00cf97a742.png)

一連の流れをまとめるとこうです。

```
↓ 元のコード
↓ 修正してプルリクエスト
↓ マージ
↓ やっぱり外して元のコードに戻したい。。
↓ Revert＝元のコードをプルリクエスト
↓ これがマージされると元のコードに戻るという事です
```
---

#### あのコミットした時に戻りたい。。
理由は色々あると思いますが、コンフリクト解消とかでなんかうまくいかなくて、一旦あのコミットした時まで戻したい。。という時あると思います。

```
// まずはコミット履歴を確認ます。
git log
```

```
するとこんな感じでコミットの履歴がでてきますので、commit（英数字の文字列がID）をコピーします。
commit aebb2dc5055f32cf1a952168b8a394c4d2b03fe2
Author: Hisashi Matsui <mail@address.com>
Date:   Tue Jan 14 13:02:46 2020 +0900

    コミットした時のメモが表示される
```


```
// これでこのコミットをした状態に戻ります！
git reset --hard aebb2dc5055f32cf1a952168b8a394c4d2b03fe2
```
SATySFiで強制的に改ページする

TeXでは`\newpage`等で強制改ページができます。
SATySFiでも同じことができないか調べていたんですが、なかなか見つからず...

Twitterで調べてみるとそれっぽい記述が見つかりました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">let-block ctx +clear-page = clear-page<br>で定義した+clear-pageを、必要な場所に入れれば良いのではないでしょうか（若干アドホックな方法ですが）</p>&mdash; ぷりにゃん (@puripuri2100) <a href="https://twitter.com/puripuri2100/status/1162143602291593216?ref_src=twsrc%5Etfw">August 15, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

やったぜ！

ということで別ファイルで定義していきます。
なお使用しているバージョンは`0.0.3`(2019/12/18現在の最新版)です。

```local.satyh
let-block ctx +newpage = clear-page
```

ここらへんの詳しい話は[The SATySFi​book（Web公開版 第1版）](https://booth.pm/ja/items/1127224)等を見るのがいいと思いますので割愛します。

あとはインポートして使うだけです。

```main.saty
@require: stdjareport
@import: local

document(|
  title = {すごい論文};
  author = {論文 書男};
|)'<
  +newpage;

  +chapter {第1章} <
    +p {
      \SATySFi; で書いたすごい論文。
    }
  >

  +newpage;

  +chapter {第2章} <
    +p {
      hogehoge
    }
  >
>
```

引数のないブロックコマンドなので`{}`や`<>`は書かず最後に`;`だけつけます。
これで無事改ページできました。

[![Image from Gyazo](https://i.gyazo.com/db5dc2ef61f7c8cea0f0f2ee107a0dac.gif)](https://gyazo.com/db5dc2ef61f7c8cea0f0f2ee107a0dac)
（っていうか`clear-page`て何者なんだ...）

時間できたらちゃんとSATySFibookの3章以降も読みます。
おつかれさまでした。
個人的によく使う kubectl のコマンドをまとめてみた

# はじめに
個人的にkubernetesを触るときによく使用するkubectlコマンドについて、簡単にまとめてみました。

# 献立
- コマンドの構文  
構文ごとにグループ化を勝手にしてみて、だいたい以下にまとまりました。

# コマンドの構文

```
# グループ1
# 一覧を取得する
kubectl -n [namespace] get [node/namespace/pod/service/deployment/pvc/pv(*)] [左で指定した実体の名前]
# * pvは、namespaceの指定は不要

# グループ2
# 実行しているpodの一覧 + podのホストのIPアドレスも表示する
kubectl -n [namespace] get [pod] [pod名] -o wide

# グループ3
# 詳細を表示する
kubectl -n [namespace] describe [node/namespace/pod/service/deployment/pvc] [左で指定した実体の名前]

# グループ4
# ログを表示する
kubectl logs -n [namespace] [pod名] -c [コンテナ名]

# グループ5
# yaml形式で表示する
kubectl -n [namespace] get [node/namespace/pod/service/deployment/pvc] [左で指定した実体の名前] -o yaml

# グループ6
# yamlファイルに定義した内容をapply/deleteする
kubectl apply -f <yamlファイル名>
kubectl delete -f <yamlファイル名>
```

# その他
kubernetesの環境構築したら、実行例も追加しようかなと思います。

# 参考にさせていただきました
- [kubernetes : kubectlコマンド一覧](https://qiita.com/suzukihi724/items/241f7241d297a2d4a55c)
Rails のバグ報告テンプレートがすごい！

# この記事は

[ruby-jp](https://ruby-jp.github.io/) の #rails チャンネルで知った Rails のバグ報告テンプレートが目からウロコだった話をします。[bug_report_templates/active_record_gem.rb](https://github.com/rails/rails/blob/v6.0.2/guides/bug_report_templates/active_record_gem.rb) の存在を知らない方向けです。

# 概要

## 気軽に ActiveRecord の動作を確かめたい

ちょっと ActiveRecord の動作を確かめたい。でも手元にちょうといい Rails プロジェクトがない。rails new するのは面倒だ……。マイグレーションも書かなきゃ……。

そんなとき、Rails のリポジトリに含まれている次の Ruby スクリプトが役に立ちます。Rails のバグ報告テンプレートだそうです。

https://github.com/rails/rails/blob/v6.0.2/guides/bug_report_templates/active_record_gem.rb

```active_record_gem.rb
# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  # Activate the gem you are reporting the issue against.
  gem "activerecord", "6.0.0"
  gem "sqlite3"
end

require "active_record"
require "minitest/autorun"
require "logger"

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :posts, force: true do |t|
  end

  create_table :comments, force: true do |t|
    t.integer :post_id
  end
end

class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

class BugTest < Minitest::Test
  def test_association_stuff
    post = Post.create!
    post.comments << Comment.create!

    assert_equal 1, post.comments.count
    assert_equal 1, Comment.count
    assert_equal post.id, Comment.first.post.id
  end
end
```

## 解説

このスクリプトは次のことを行っています。

* [bundler/inline](https://github.com/bundler/bundler/blob/v2.1.0/lib/bundler/inline.rb) を使って Ruby スクリプト上で bundle install を行っている。
  * ~~`gemfile` メソッドの第 1 引数に `true` を渡すことで、まだインストールしていない Gem をインストールする。~~ ※ 引数を渡さない場合、bundle install の出力は画面に出ませんがインストールはされていました。`gemfile(true, quiet: true)` の場合と違いが分かっていません :sob:
  * (Bundler のバージョンが 2.1.0 以上の場合) `gemfile` メソッドの第 2 引数に `quiet: true` を渡すと bundle install 時のログ出力を抑制できる。
  * `BUNDLE_PATH` は無視する。つまり Gem は必ずグローバルにインストールされる。
* [ActiveRecord::Base.establish_connection](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionHandling.html#method-i-establish_connection) の database オプションに `:memory:` を渡すことで、SQLite のデータベースをメモリ上に作成している。
* [ActiveRecord::Schema.define](https://api.rubyonrails.org/classes/ActiveRecord/Schema.html#method-c-define) を使うことで、スクリプト内でテーブルを定義、作成している。
* スクリプト内でモデルを定義している。
* Minitest::Test で単体テストを実行している。

いろんなテクニックがシンプルに詰まっていて、いいスクリプトだなと思いました :relaxed:

# 参考

* Bundler
    * [bundler/inline should ignore BUNDLE_PATH and install gems to GEM_HOME by robuye · Pull Request #7154 · bundler/bundler](https://github.com/bundler/bundler/pull/7154)
        * bundler/inline での `BUNDLE_PATH` の扱いについて
* SQLite
    * [In-Memory Databases](https://www.sqlite.org/inmemorydb.html)
        * インメモリのデータベースについて
SATySFiのoption型を扱おう

これは「[SATySFi Advent Calendar 2019](https://adventar.org/calendars/3929)」の17日目の記事です。

16日目は[bd_gfngfnさん]()でした。18日目は[monaqaさん]()です。


# はじめに

この記事ではSATySFiのoption型について解説します。

対象はSATySFiの初心者ですが、The SATySFibookを読み終わっていることを仮定します。


# option引数の使いどころ

option型は答えが無いときがあるときによく使われます。

答えが無いときとは、例えば「リストの先頭を取り出す関数に空リストを与えた時」など、回復不能で致命的なエラーではないが適切な値を設定できないときのことです。

こんなものを使えてどう嬉しいかと疑問になるかもしれませんが、適切な値がわからなかったときに安易にエラーを返すと、単純になる代わりにすぐにエラーが出てなかなかコンパイルできないパッケージ・文書ができてしまいます。

また、関数の型から失敗する可能性のある操作を行う関数であるということがすぐにわかることも魅力の一つです。
失敗する可能性があることがわかればそれについて事前に初期値を用意しておくなどの対応が可能になります。

option型を返す関数は多くの場所で定義されており、[satysfi-baseのlist-extパッケージ](https://github.com/nyuichi/satysfi-base/blob/master/list-ext.satyg)ではなんと14個も定義されています。

使えると非常に便利で汎用性も高まるのでぜひマスターしましょう。

# option型の中身

option型は`int option`や`string option`などのように`型名 option`という形をしており、どんな型（ユーザーが独自に定義した型であっても）にでも対応できます。

さて、この万能感あふれるoption型はこのような形をしています（実際は内部で定義されているのですが、もしパッケージの形で実装するならこうなるでしょう）。

```
type 'a option = None | Some('a)
```

何もないことを表す`None`とそれ以外の場合の値を保持する`Some(v)`という二通りだけです。単純ですね。

例えば、さきほど例で出した「リストの先頭を取り出す関数（`head`）」に値を与えてみて結果を見てみましょう。

```
head [1;2;3;4]

=> Some(1)

head [`1`;`2`;`3`]

=> Some(`1`)

head []

=> None
```


なんとなくわかってきたと思います。


# option型の中身の取り出し方

さて、このままでは`Some(v)`という形で囲われてしまっていてそのままでは単純な足し算すらできません。なのでこの中身の`v`を取り出すことにしましょう。

しかし、単純に取り出そうとしてもその値が`None`である時のことも考慮しないといけません。そこで、ここで「パターンマッチ」という構文を使います。

詳しくはThe SATySFibookの46ページを読んで欲しいのですが、

```
match expr with
  | pattern_1 -> expr_1
  | pattern_2 -> expr_2
  .
  .
  .
  | pattern_n -> expr_n
```

という風にして値などの中身に応じて処理を変えることができる便利機能です。
例えば、「1のときには`` `1` ``を、2のときには`` `2` ``を、それ以外では`` `n` ``を返す関数」は

```
let f n =
  match n with
  | 1 -> `1`
  | 2 -> `2`
  | _ -> `n`
```

と書けます。ここで最期に使っている`_`はワイルドカードと呼ばれる「それ以外全てのとき」を表せるパターンです。

if文でも書けるような内容ですが、複数の場合を書き分けるときに重宝します。

さて、これを使ってoptionの中身を取り出しますが、これは単純に、

```
match opt with
| Some(v) -> v_1
| None -> v_2
```

というようにして`Some(v)`のときと`None`のときで場合分けをするだけです。

さて、「`head`関数で`int list`の先頭を取り出すが、もし空リスト出会ったら`0`を返す」という関数`f`を定義しようとするとどうなるでしょう。


答えはこうなります。

```
let f lst =
  match head lst with
  | Some(n) -> n
  | None -> 0
```

# option型を扱うための関数

標準ライブラリに含まれているopiton.satygファイルで以下の3つの関数が提供されています（モジュール名は`Option`）。

  - `map : ('a -> 'b) -> 'a option -> 'b option`
  - `from : 'a -> 'a option -> 'a`
  - `bind : 'a option -> ('a -> 'b option) -> 'b option`


  - `map`関数は中身が`None`のときはそのまま`None`を返し、`Some(v)`だったときは`v`に対して最初に受け取っていた関数を適用します。
  - `from`は中身が`None`だったときには最初に受け取っていた初期値を返し、`Some(v)`だったときにはその`v`を返す関数です。
  - `bind`は`map`関数とほとんど同じですが、受け取る関数自体もoption型を返します。


標準ライブラリ以外にも[satysfi-baseのoption-extパッケージ](https://github.com/nyuichi/satysfi-base/blob/master/option-ext.satyg)でも多くの関数が用意されています。


# おわりに

option型の扱い方がわかったと思います。

上手く使いこなすと非常に便利な機能ですのでぜひ活用していってください。

本当はオプション引数についても触れられればよかったのですが、またの機会ということで。
Rails6 Bootstrap link_toを使ってmethodとclassを両方とも指定しよう

# 目的

- ログアウトボタンを作る時にlink_toを使用して`method`と`class`を指定する際に若干詰まった内容をまとめる

# 結論

- methodとclassを個々に中括弧でくくるのではなく一緒に定義する。

    ```erb
    <!-- NG -->
    <li class="navbar-item"><%= link_to("ログアウト", "/logout", {method: "delete"}, {class: "nav-link"}) %></li>

    <!-- OK -->
    <li class="navbar-item"><%= link_to("ログアウト", "/logout", {method: "delete", class: "nav-link"}) %></li>
    ```
# 情報

- header内をBootstrapを使用して書いている。
- 今まで`method`を指定していなかったのでそのままaタグを使用してheaderメニューを書いてた。
- aタグを`link_to`に置き換えたい。

# 困ったこと

- `link_to`を使用して個々の中括弧で`method`と`class`を指定すると構文エラーが出た。
- 下記にエラーが出た時のコードを記載する。

    ```erb
    <li class="navbar-item"><%= link_to("ログアウト", "/logout", {method: "delete"}, {class: "nav-link"}) %></li>
    ```

# 解決法

- 同じ中括弧内で`method`と`class`を指定すれば良い。
- 下記に正常に表示された時のコードを記載する。

    ```
    <li class="navbar-item"><%= link_to("ログアウト", "/logout", {method: "delete", class: "nav-link"}) %></li>
    ```
React-Bootstrapを使えるようにする

初めにreactのプロジェクトを作る

```
npx create-react-app my-react-project
```

<br>
プロジェクトのroot直下に移動して

```
cd my-react-project
```

<br>
インストールして

```
npm install react-bootstrap bootstrap
```

<br>
index.htmlに以下を記載して

```
<link
  rel="stylesheet"
  href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
  integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
  crossorigin="anonymous"
/>
```


<br>
使いたい要素をインポートして使う
App.js

```
import React, { Component } from 'react';
import Button from 'react-bootstrap/Button';

class App extends Component {
    render() {
        return (
            <div>
                <Button> ボタンだよ </Button>
            </div>
        );
    }
}
export default App;
```

↓実行結果
<img width="276" alt="スクリーンショット 2019-12-17 23.55.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552903/9009c512-729c-e703-c43c-b8052621d79a.png">

macで`の打ち方初めて知った。[ option + Shift + _ ]

参考サイト
[本家](https://react-bootstrap.github.io/getting-started/introduction)
Kotlinの関数型言語を利用したモデルソート

関数型言語を利用して、モデルのソートを行いたい時に、意外と探しても見つからない。単体でのソートは？複数ソートは？モデルをソートしてみる。

### 準備
アカウントのデータモデルを用意する

```kotlin
data class Account (
    val id: Int,
    val name: String,
    val age: Int
)
```
上記のデータモデルをリストに追加する。

```kotlin
import java.util.*

fun main() {
    // 初期化
    var list = ArrayList<Account>()
    list.add(Account(1,"一郎", 35))
    list.add(Account(4,"四郎", 41))
    list.add(Account(3,"三郎", 23))
    list.add(Account(5,"五郎", 41))
    list.add(Account(2,"二郎", 19))

    // ※１　ここにソートのコードを書く

    //　結果表示
    list.forEach{println(it)}
}
```
実行結果は、ソートを実行してないため、リストに追加した順番で表示される。

```
Account(id=1, name=一郎, age=35)
Account(id=5, name=五郎, age=41)
Account(id=3, name=三郎, age=23)
Account(id=4, name=四郎, age=41)
Account(id=2, name=二郎, age=19)
```



### 単体ソート（昇順）
ageの情報で、単体ソートの昇順を行う。下記のコードを準備の※１に追加する。

```kotlin
list.sortBy { it.age }
```
実行結果
ソートの値が同等の場合は、リストの追加した順番になる

```
Account(id=2, name=二郎, age=19)
Account(id=3, name=三郎, age=23)
Account(id=1, name=一郎, age=35)
Account(id=5, name=五郎, age=41)
Account(id=4, name=四郎, age=41)
```

### 単体ソート（降順）
ageの情報で、単体ソートの降順を行う。

```kotlin
list.sortByDescending { it.age }
```
実行結果
ソートの値が同等の場合は、リストの追加した順番になる

```
Account(id=5, name=五郎, age=41)
Account(id=4, name=四郎, age=41)
Account(id=1, name=一郎, age=35)
Account(id=3, name=三郎, age=23)
Account(id=2, name=二郎, age=19)
```

### 複数ソート（全て昇順）
第一ソートをageの昇順にして、第二ソートにはidの昇順を設定する。

```kotlin
list.sortWith(compareBy({ it.age }, { it.id }))
```
実行結果

```
Account(id=2, name=二郎, age=19)
Account(id=3, name=三郎, age=23)
Account(id=1, name=一郎, age=35)
Account(id=4, name=四郎, age=41)
Account(id=5, name=五郎, age=41)
```

### 複数ソート（昇順と降順の混在）
第二を降順にしてみよう。

```kotlin
list.sortWith(compareBy<Account>{ it.age }.thenByDescending{ it.id })
```
実行結果

```
Account(id=2, name=二郎, age=19)
Account(id=3, name=三郎, age=23)
Account(id=1, name=一郎, age=35)
Account(id=4, name=四郎, age=41)
Account(id=5, name=五郎, age=41)
```

### 最後に
ソートも色々なパターンが可能になっている。また、直感的に何をしたいのか理解ができるので、ソースをみて判断することが容易になる。ソート条件が第二までのみですが、第三以降作る時も指定キーを追加すれば問題ない。
【Python】PillowライブラリのExifTags名前一覧を取得

##経緯
・PythonのPillowライブラリを用いて、画像が持っている情報（撮影時刻、緯度経度などのメタ情報。いわゆる**Exif**）を取り出したい。
・Pillowの使い方について調べていたところ、検索ヒットした記事は、Exifの**"id"**（2～5桁の数字）を取得するスクリプトが多いが、その**"id"**の名前（何を意味しているか）を取得するスクリプトは見当たらなかった。
・基本的すぎることだからかもしれないが、自分用にメモ

##手順と結果
１　以下のコードによりExifTagsの名前一覧を取得可能
`from PIL.ExifTags import TAGS`
`print(TAGS)`
{11: 'ProcessingSoftware',
 254: 'NewSubfileType',
 255: 'SubfileType',
 256: 'ImageWidth',
 257: 'ImageLength',
 258: 'BitsPerSample',
 ...

２　上記、`TAGS`はディクショナリ(dict class)であるため、get()メソッドで対応する名前を呼び出すことが可能
例：
`from PIL import Image`
`im = Image.open('test.jpg')`
`exif = im._getexif()`
`for id, value in exif.items():`
　　　`print(id, TAGS.get(id), value)`

３　スクリーンショット（コマンドプロンプト画面例）
・iPhoneで撮影された画像
![cmd_screenshot.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433560/65f82aab-0569-9471-7ed2-14dabe8b7abc.png)

##各メタデータの解説（参考）
・『Exiv2 - Metadata reference tables』（https://www.exiv2.org/tags.html ）
…Standard ExifTagsと書いてあるが、Standard以外のタグもあるのだろうか。
状態遷移表ライブラリcushionの話

# 概要

- スライド： [Cushion - 状態遷移表ライブラリ](https://www.slideshare.net/monoshoo/cushion-152603936)
- [7年前に公開した記事](https://qiita.com/mono_shoo/items/5c37c16e550880f6dfc6)の状態遷移表ライブラリを独立させ、[dubパッケージのライブラリとして公開](https://code.dlang.org/packages/cushion)
- 通信のハンドシェイク、画面遷移、イベント管理なんかに最適


# どんなライブラリか？
状態によってふるまいが変わるプログラムの設計・実装の補助を行うためのライブラリです。

以下の表は状態遷移表の一例です。各記号は、わかりやすさのためにつけてあり、□で表の名前、▽で状態、〇でイベント、・で処理を表現しています。

| □音楽プレイヤー | ▽停止                   | ▽再生                  | ▽一時停止                 |
|:---------------|:------------------------|:------------------------|:------------------------|
| 〇開始ボタン    | ▽再生<br>・音楽を再生する | ▽一時停止<br>・音楽を停止する | ▽再生<br>・音楽を再生する |
| 〇停止ボタン    |                         | ▽停止<br>・音楽を停止する<br>・最初に戻る | ▽停止<br>・最初に戻る |

▽▽▽な状態で、〇〇〇なイベントが起こったら、・・・な処理を実行して、次の状態になることを示す表□□□というイメージです。

この表を、CSV形式で作成し、直接D言語のコードに変換してしまうのが、状態遷移表ライブラリcushionです。

# 使い方

dubのプロジェクト設定に`dependencies`と、`stringImports`を追加します。

```json
{
	"//" : " ...",
	"dependencies": {
		"cushion": "~><current-version>"
	},
	"//" : " ..."
}
```

次に、状態遷移表を書きます。
例： https://github.com/shoo/cushion/blob/master/examples/stmtest/views/MusicPlayer.stm.csv

表は、CSV形式で、1つのセルに改行を含む、UTF-8形式の文字コードで保存します。
状態遷移表を書く時は、表計算ソフトを使うといいと思います。EXCELでやる場合は、[サンプルに挙げたxlsmファイル](https://github.com/shoo/cushion/blob/master/examples/stmtest/STM.xlsm)を使うといいかもしれません。UTF-8でCSVにエクスポートするVBAを書きました。(クソが…ッ

状態遷移表は、状態遷移を記載する表と、自然言語(日本語)→D言語の変換表の2部構成です。

変換表は以下のようなイメージ。

| 日本語          | 変換後のD言語         |
|:----------------|:--------------------|
| 〇開始ボタン     | onStart             |
| ・音楽を停止する | player.stopMusic(); |

例： https://github.com/shoo/cushion/blob/master/examples/stmtest/views/MusicPlayer.map.csv

ソースコードの内部でcushionをimportして、以下のようにします。

```d
import cushion;
mixin(loadStmFromCsv!"MusicPlayer");
auto stm = makeStm();
```

ここで作られる`stm`というオブジェクトに、イベント`stm.put(Event.play)` って感じに伝えてあげることで、状態遷移表に記載した処理が動作します。

# 中身はどうなってるの？

おおざっぱに言うと、以下のようなことをしています。コンパイル時に。

1. CSVをstd.csvでパース
2. 状態遷移表を日本語からD言語のコードに置換表で置換
3. 状態とイベントのenumを作成
4. 状態×イベントの「遷移先の状態」テーブルを作成
5. 各セルごとに1つ関数を作成
6. 状態×イベントの関数テーブルを作成

あとは、状態×イベントごとに呼び出すテーブルの列×行を変えています。

このような、外部ファイルに保存したDSLをコンパイル時にパースしてD言語に置き換えてstring mixin、みたいなのは、D言語だからこそできる仕組みといえるかもしれませんね。

ちなみに、これを行っているのは[このファイル(CSVのパース)](https://github.com/shoo/cushion/blob/master/source/cushion/csvdecoder.d)と[このファイル(コード生成)](https://github.com/shoo/cushion/blob/master/source/cushion/stmgen.d)です。

# 今後の展望
特に考えていません。
アイデア自体は7年以上前に固まっており、今回単品で使えるようにしただけで、割と枯れています。
私が一人で使用している分には、特に問題なく使えていますし。
ただ、いつまでもバージョン0.0.0というわけにもいかないと思うので、適当なところで1.0.0にしたいと思います。
「こんな使い方したいのだけど・・・」みたいな相談や、できないことがあったら[Issue](https://github.com/shoo/cushion/issues)に登録してください。日本語でOKです。

# 余談
[イキってフォーラムでアナウンスしたら、`@trusted`警察に絡まれました。](https://forum.dlang.org/thread/lxggrxkbwppaqazpnxzh@forum.dlang.org)
状態遷移表に記載したコードがunsafeであっても、`@trusted`によって握りつぶされてしまうというものですが、今のところこれにまじめに取り組むつもりはありません。(メリット以上に利便性を損なうと考えているため)
今後D言語がデフォルトで`@safe`になった場合に改めて考えます。
Rust 1.40.0でtuple構造体とenum variantのコンストラクタがconst fnになる

この記事は[Rustその2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/rust2)の17日目の記事です。

この記事は2019年12月17日時点の[rust-lang/rust/blob/master/RELEASES.md](https://github.com/rust-lang/rust/blob/master/RELEASES.md)の内容に基づいて書かれています。

# Rust 1.40.0でtuple構造体とenum variantのコンストラクタがconst fnになる
12/19にリリース予定のRust1.40.0でtuple構造体とenum variantのコンストラクタがconst fnになります。

## tuple構造体のコンストラクタ
下記コードのコンパイルが通るようになります。

```rust
pub struct Point(i32, i32);

const ORIGIN: Point = {
    let constructor = Point;

    constructor(0, 0)
};
```
`constructor`は関数です。(これをなんと呼ぶべきかわからないため関数と表記しています。経緯はこの記事のコメントを確認してください)
上記のコードはconst変数の初期化ですがconst fnの中でも同じように使うことができます。

```rust
const fn origin() -> Point {
    let constructor = Point;
    constructor(0, 0)
}
```


## enum variantのコンストラクタ
今までも可能だった

```rust
Some(0);
(Option::Some)(1);
```
に加えて

```rust
let f = Option::Some;
f(2);
{Option::Some}(3);
<Option<_>>::Some(5);
```
が可能になるそうです。


と書いてありますがプルリクエストに書いてある下記のコードのコンパイルは通りませんでした

```rust
const fn make_options() {
    // These already work because they are special cased:
    Some(0);
    (Option::Some)(1);
    // These also work now:
    let f = Option::Some;
    f(2);
    {Option::Some}(3);
    <Option<_>>::Some(5);
}
```
[コンパイル結果](https://play.rust-lang.org/?version=beta&mode=debug&edition=2018&gist=f5a0086792cc288efb8c11087f044173)

<details><summary>エラー内容</summary><div>

```rust
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/lib.rs:8:6
  |
8 |     {Option::Some}(3);
  |      ^^^^^^^^^^^^ expected (), found fn item
  |
  = note: expected type `()`
             found type `fn(_) -> std::option::Option<_> {std::option::Option::<_>::Some}`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.
```
</div></details>


エラーが出ているのは8行目の

```rust
{Option::Some}(3);
```
の部分で

```rust
let o = {Option::Some}(3);
```
のように変数に代入するときには問題なくコンパイルが通ります。

## おわりに
正直自分が書くコードにはあまり影響がない部分だとは思いますがconst fnでできることが増えていくことはいいことだと思います。
これからもどんどんconst fnが使いやすくなっていくと良いですね。
年末まで毎日webサイトを作り続ける大学生 〜60日目 Closureを学ぶ〜

##はじめに
こんにちは！@70days_jsです。

Closureを学びました。

60日目。(2019/12/17)
よろしくお願いします。

##サイトURL
https://sin2cos21.github.io/day60.html

##やったこと
結論から。
Closureとは？
**変数が定義された環境を保持する仕組み**
という解釈が一番しっくりきました。

間違っていたらコメントよろしくお願いします。

とてもシンプルなカウンターを作りました。(gif)↓

![test3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/e3f2f703-68da-4941-0fc7-9ee6132d3f03.gif)

html↓

```html
  <body>
    <h1>Closure</h1>
    <input type="button" id="button" value="+" />
    <input type="button" id="button2" value="-" />
    <div id="displalyCount"></div>
  </body>
```

JavaScript↓

```javascript

function countApp() {
  let count = 0;
  return function plusCount() {
    count++;
    return count;
  };
}

function countApp2() {
  let count = 0;
  return function plusCount() {
    count--;
    return count;
  };
}
let button = document.getElementById("button");
let button2 = document.getElementById("button2");
let displalyCount = document.getElementById("displalyCount");
let counter1 = countApp();
let displalyCount2 = document.getElementById("displalyCount2");
let counter2 = countApp2();

button.addEventListener("click", function() {
  counter1();
  displalyCount.innerHTML = counter1() + counter2();
});

button2.addEventListener("click", function() {
  counter2();
  displalyCount.innerHTML = counter1() + counter2();
});
```

countApp関数のなかのcountは常に保存された状態です。

> function countApp() {
  let count = 0;
  return function plusCount() {
    count++;
    return count;
  };
}

なので、この先countApp関数を使おうと思えば、

> let hoge = countApp();

のようにしてhogeを経由すれば、先に行っていたカウントは消されずに済みます。

今回、押した回数の数え方はここで行っています。

>   counter1();
  displalyCount.innerHTML = counter1() + counter2();

>  counter2();
  displalyCount.innerHTML = counter1() + counter2();

##感想
Closureは分かったような、まだ分かり切れていないような。。。
何だろう。わかってるのだろうか・・・？

最後まで読んでいただきありがとうございます。明日も投稿しますのでよろしくお願いします。

##参考
1. [JavaScript中級者への道【5. コールバック関数】](https://qiita.com/matsuby/items/3f635943f25e520b7c20)
[ブレイクスルーJavaScript フロントエンドエンジニアとして越えるべき5つの壁―オブジェクト指向からシングルページアプリケーションまで](https://www.amazon.co.jp/dp/B00V9M5R8S/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)(← 本を借りました。リンクはamazonページです)
iPhoneのアプリにPCからファイルを入れたいとき

## 背景

iPhoneにCSVとかのテキストデータをPCから入れたいときに、
どうやってXcodeの設定やるんだろーってことがあったのでそのメモ。

## 設定方法

`Info.plist` に以下の項目を設定してあげると、

```
Application supports iTunes file sharing
Supports opening documents in place
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113439/d5de50f9-86ab-fe2c-1553-f3d7aa31d155.png)

MacはFinderからこんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113439/bd69dd9d-1fcc-c202-c677-43b69d4c958c.png)

WindowsはiTunesからこんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113439/df4987bd-5de7-c44a-b797-12590d217b5a.png)

でファイルの送受信ができるようになった。

## 参考

https://qiita.com/ShingoFukuyama/items/e85d34360f3f951ca612
Error 1292: Incorrect datetime value: '0000-00-00' に対してのGORMでの対処

# 背景

Go×Ginでwebアプリケーションを作成時 userを新規登録する際に対処したことを残す。

バージョン
Go 1.13
MySQL 5.7系

## 起こったこと

以下のような user modelを作成

```
type User struct {
	UserID int64 `gorm:"primary_key" json:"user_id" form:"user_id"`

	FirstName string `gorm:"first_name" json:"first_name" form:"first_name"`

	LastName string `gorm:"last_name" json:"last_name" form:"last_name"`

	PhoneNumber string `gorm:"unique;not null" json:"phone_number" form:"phone_number"`

	Gender string `gorm:"type: enum('male', 'female', 'unspecified'); default: 'unspecified';" json:"gender" form:"gender"`

	Birthday time.Time `gorm:"birthday" json:"birthday" form:"birthday"`

	Zipcode string `gorm:"zipcode" json:"zipcode" form:"zipcode"`

	Prefecture string `gorm:"column:prefecture" json:"prefecture" form:"prefecture"`

	City string `gorm:"column:city" json:"city" form:"city"`

	AddressLine string `gorm:"column:address_line" json:"address_line" form:"address_line"`

	UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at" form:"updated_at"`

	CreatedAt time.Time `gorm:"column:created_at" json:"created_at" form:"created_at"`
}

```

これを利用してuserを作成する機能をgormを使用して実装していていざ実装の際に
例えば以下のような形で電話番号を持たせて新規登録する際に

```
	db := mysql.DB
	tx := db.Begin()

	user := models.User{PhoneNumber: phoneNumber, UpdatedAt: time.Now(), CreatedAt: time.Now()}
	fmt.Println(user)
	if err := tx.Create(&user).Error; err != nil {
		log.Fatalln(err)
		return "db"
	}

	tx.Commit()
```

```
Error 1292: Incorrect datetime value: '0000-00-00' for column 'birthday' at row 1
```

調べるとmysqlのsql modeの記事がたくさん出てくる

選択肢としては

`該当カラムにポインタを割り当てNullをMySQLに入れる`
又は
`SET GLOBAL sql_mode = 'ALLOW_INVALID_DATES';`

今回は開発環境だったので（今後変更はあり得る）

```
Birthday *time.Time `gorm:"birthday" json:"birthday" form:"birthday"`
```

という形で対応した。
初めてGoに触る人は引っかかるポイントだと思ったので参考になれば幸いです

### 参考記事

https://qiita.com/mgoldchild/items/52abb8422d62ccd9f5dc
https://www.digitalocean.com/community/tutorials/how-to-prepare-for-your-mysql-5-7-upgrade
【Unity】オブジェクトに衝突判定とトリガー判定を実装

#やりたいこと
![アイテムのバウンドと取得.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527025/4c6ebd6e-3b04-4488-84f0-0cbd41512ee5.gif)

- オブジェクトが床をすり抜けない
- プレイヤーが触れると消える（トリガー判定で消す）

##環境
- Unity version 2018.3.3f1

##前提
- 2D
- 床にはBoxCollider2Dが設定されている
- 対象オブジェクトにRigidBody2DとBoxCollider2Dを追加

##問題点
対象オブジェクトが床をすり抜けなくするためにBoxCollider2DのIsTriggerを外すが、これだとTrigger系判定が起動しなくなる
Collision系判定でやりたいことを実現することもできるけど、引っかかるような動きになってしまう

##対応策
BoxCollider2Dを二つ付ける
![衝突判定とトリガー判定02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527025/d55f9977-8819-0385-5a11-9f72322e1da0.jpeg)
片方のcolliderのIsTriggerを設定、もう片方は外す。
IsTriggerを設定していないcollider（床をすり抜けなくしている方）の範囲は小さくしておくとよさげ。
![衝突判定とトリガー判定03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527025/3dd37ccc-39f4-0d60-bd80-ad8a01d4121b.jpeg)
こんな感じ。

##課題
**圧倒的な力業感**
もっとスマートなやり方はないのかしら。
調べてもいい解決方法が見つからず。別の方法で実現できれば追記します。
React＋ReduxにおけるContainerの役割

10月から入社した会社でReactを使い始めましたので、まだ２ヶ月です。その前はNuxt.jsを使ってました。

Containerについて学びがあったので、備忘録としてまとめます。

もともとContainerはComponentとReduxをつなぐ役割（MapStateToProps, MapDispatchToPropsをしてStateとActionを渡す）だと解釈していましたが、詳しく調べてみると少し違ったみたいです

ReduxとReactを同時に使うアプリケーションでは、Componentを`表示のPresentational Component`と`ロジックのContainer Component`に分離するアプローチが理解しやすく、Componentの再利用性も高まって良い。（Redux公式ドキュメントから抜粋）

つまり、ContainerもComponentだったのです。

以下[Redux公式ページ](https://redux.js.org/basics/usage-with-react#presentational-and-container-components)から抜粋。

**Presentational Component:
受け取ったデータをもとに、その名の通りプレゼンテーション（表示）する事を担当**
- Reduxの変更を検知：NO
- データ参照：containerからprops
- データ書換：containerからprops

**Container Component:
Storeを監視したり、アクションを発行したりロジックに関する事を担当**
- Reduxの変更を検知：YES
- データ参照：Subscribe to Redux state
- データ書換：Dispatch Redux actions

という具合にComponentを表示とロジック２種類に分ける事がNuxt.jsでは無い考え方だったので最初は慣れませんしたが、１ファイルにまとめると閲覧性が落ちやすくなるので、この手法は慣れると便利だと思います。
DeepStreamとAkka Streamsを使ったEdge AI 用サーバ構築

こんばんは！ Go や Python が勢いがある中、社内でも頑なに Scala を使っている @rkyymmt@github です。ダイバーシティ重要！

今回は、今年、Edge AI な PoC 案件で構築した、Edgeサーバで仕様した技術について少し説明したいと思います。

# HW
ハードウェアは次のような構成です。

深度センサー（Intel RealSense）はJetson Nano経由で、他の比較的プリミティブなセンサーはM5CameraのGroveコネクタに繋げてWi-Fi経由で、取得したデータをEdge AIサーバの NVIDIA Jetson AGX Xavier に流し込む構成にしました。
深度センサーの深度情報は一次処理をJetson Nano上で行った後、検知情報のみXavierに送りました。

<img width="1013" alt="HW構成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21380/1aecc0d7-e6d7-f197-cd50-840e524ee4a8.png">

# SW
ソフトウェアは次のような構成としました。
M5Cameraからの映像ストリーミングはマルチプラットフォームのストリーミングフレームワークであるGStreamerベースのSDKであるNVIDIA DeepStreamでパイプ的な加工・フィルタ・AI処理を行った後、Kafkaに流し込み、Alpakka経由でScalaから操作しました。
また、他のセンサー情報はJSONをAkka StreamsのHTTP実装である Akka HTTPで受け取る形を取りました。

<img width="987" alt="スクリーンショット 2019-12-18 0.00.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21380/d48630fe-b19e-f170-9eab-b23ddaa79646.png">

例えば、上記のJSONを受け取るWebサーバ部分は、次のようなコードになります。

```Scala
import java.io._
中略
import akka.event.Logging

final case class Value(
  sensor_data: Int
)

final case class Sensor(
  timestamp: String,
  uid: String,
  `type`: String,
  values: Array[Value]
)

trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
  implicit val valueFormat = jsonFormat1(Value)
  implicit val sensorFormat = jsonFormat4(Sensor)
}

trait Service extends Directives with JsonSupport {
  val route: Route = post {
    extractLog { implicit log =>
      entity(as[Sensor]) { sensor =>
        val timestamp = sensor.timestamp
        val uid = sensor.uid
        val `type` = sensor.`type`
        val values = sensor.values
中略
        complete(StatusCodes.OK)
      }
    }
  }
}

object Main extends Service {
  implicit val system: ActorSystem = ActorSystem()
  implicit val materializer: ActorMaterializer = ActorMaterializer()

  def main(args: Array[String]): Unit = {
    Http().bindAndHandle(route, "localhost", 8080)
  }
}
```

# 最後に
Goもよいけど、Scalaもよいぞ。
Next.jsでenvファイルを使う

## やること
envファイルをNext.jsで使えるようにする。

### 必要パッケージインストール
dotenvをインストール

```
yarn add dotenv
```

### .env作成

```
TEST = HOGEHOGE
```

### next.config.js作成

```next.config.js
require('dotenv').config()

module.exports = {
  env: {
    TEST: process.env.TEST,
  },
}
```

### 読み込む

```pages/index.js
export default () => <p>process.env.TEST:{process.env.TEST}</p>
```

<img width="479" alt="スクリーンショット 2019-12-17 23.40.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533593/6207e88d-4906-7426-e45e-2fbe078acae9.png">



## おわり
Next.jsの記事が少ないと感じているので、ちょっとしたことでも投稿していこうと思った。
Power BIダッシュボードの基本操作

#はじめに
Power BIダッシュボードを閲覧・操作するユーザーのための基本操作をまとめてみました。
Microsoft Power BI Communityで公開されているVideo Game Salesのダッシュボードを例に操作してみます。

リンク先をクリックするとブラウザ上でダッシュボードが見れます。
https://community.powerbi.com/t5/Data-Stories-Gallery/Video-Game-Sales/td-p/602233
#基本操作

###フォーカスモード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/1f3b9db4-9b63-b0f1-d2bf-4c6b8a6c0e94.png)
ビジュアルの右上にあるフォーカスモードのアイコンをクリックすると、ビジュアル全体を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/7311181e-d680-b14e-fe6f-364adfc53885.png)
「レポートに戻る」ボタンで、元に戻ります。

###ドリルダウン・ドリルアップ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/d3abe1d1-4874-d18c-b80e-3e3a3f348ee9.png)
「階層内で１レベル下をすべて展開します」をクリックすると、
年ごと⇒四半期ごと⇒月ごとの集計へと変化します。（ドリルダウン）
↑ボタンで、月ごと⇒四半期ごと⇒年ごとに変化します。（ドリルアップ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/d2e0b7c0-1e69-029a-1be1-b35baf65e427.png)

↓ボタンをクリックし、ドリルダウンモードをオンにすると、クリックしたポイントでドリルダウンします。
もう一度↓ボタンをクリックすると、ドリルダウンモードをオフになります。
↑ボタンで上の階層へ上がると元に戻ります。
（この操作に最初は戸惑いました:sweat_smile:）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/dd86f095-1119-2cf3-9dda-654ae625f21b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/25a35f98-2d15-9434-fb69-ce51a6c326f8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/d49305b1-793e-f52f-e777-2449d7fd0693.png)

###ツールヒント
グラフのポイントで、マウスカーソルを置くと、関連するビジュアルや情報が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/a9cdadc5-06c5-d6d3-52a8-2b91d358f53f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/d9422142-7da4-834b-5688-4cf9eed6cf5e.png)
###ドリルスルー
グラフのポイントで右クリックし、ドリルスルーが表示されている場合、そのデータを対象にした関連するビジュアルへ移動します。
←ボタンで元に戻ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/1978553d-bfea-529d-f9b1-fd9bd33b1d12.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/cd494b19-56ac-9e16-ce06-ea42bfd7403b.png)
###スライサー（フィルター）
Consolesをクリックし、Consoles Reportのタブへ移動します。
メーカーのロゴを選択すると、選択したメーカーにフィルタをかけることができます。
（ここでは、チェックボックスの代わりに分かりやすくするため、アイコンが使われています。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/46a1ac40-f345-754c-08a2-57f93f6ff789.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/58f12311-76cd-fb99-f5e5-759b3fd8c27f.png)

ビジュアルのポイントや凡例をクリックして、フィルターをかけることもできます。
この場合、フィルタをかけたところが濃い色で表示されます。
（あまり適当なところをクリックすると、何が起きているのか理解に苦しむこともあります:worried:）
ビジュアル内で、何もないところをクリックすると元に戻ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/2f962bd2-65b6-1bb4-36a6-205847347119.png)

#参考
Microsoft Power BI Communityのギャラリーには、インターラクティブなデータビジュアライゼーションのサンプルが多数あります。:sunglasses:
https://community.powerbi.com/t5/Data-Stories-Gallery/bd-p/DataStoriesGallery
ローカルブランチがプッシュできない問題の解決

#はじめに

ローカルブランチがプッシュできない問題があったので、他の人たちや、自分の備忘録のために書いておきます。


#エラー

```
The Remote branch '' (Local branch = 'sprints/Mycompany_sprint-1') is invalid. Ref names must follow git ref-format rules: https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html Completed with errors, see above.
```

だったり

```
The リモートブランチ '' (ローカルブランチ = 'gnome') is invalid. Ref names must follow git ref-format rules: 
```

だったり、ブランチをプッシュするときにエラーが起きます。


#解決方法

こちらのページを参考にしました。

https://stackoverflow.com/questions/58918906/error-pushing-changes-on-git-ref-names-must-follow-git-ref-format-rules


こちらのページの回答には

```
This seems to be a bug affecting SourceTree for Windows version 3.3.4: 
https://jira.atlassian.com/browse/SRCTREEWIN-12593

A workaround until the bug is fixed is to untick and
 retick the branch checkbox in the push dialog.
```

と書かれています。
翻訳すると

```
これは、Windowsバージョン3.3.4のSourceTreeに影響するバグのようです：
https://jira.atlassian.com/browse/SRCTREEWIN-12593

バグが修正されるまでの回避策は、
プッシュダイアログのブランチチェックボックスを選択解除および再選択することです。
```


となっていました。
![SnapCrab_NoName_2019-12-17_23-26-29_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276381/c2233e13-af42-7f49-f635-7a86c2550d11.png)




上の画像の一番左のチェックボックスをすべて外し、その後選択し直します。(一つずつの場合のみ確認済み。すべて選択/解除は未確認)
すると何かしらの設定が走るのか、無事pushに成功しました。


#終わりに

参考にしたページには3.3.4のバグと書かれておりましたが、3.2.5.3517でも発生が確認できました。
[Alibaba Cloud] 機械学習プラットフォームのPAIをさらっと触れてみる

# この記事の目的
Alibaba Cloudの機械学習プラットフォーム、PAIを触ってみました。
PAIの正式名称は、```Machine Learning Platform for AI```です。
PAIでプロダクト検索してもコンソールペインでは検索がヒットしません。

簡単に触れて見た結論、MaxComputeやDataworksと組合わせられる点がPAIのわかりやすい利点かなと思います。

# PAIの3つのPAI機能

- ① ビジュアライゼーション・モデリング
    - 一般的な機械学習アルゴリズムを提供しながら、リッチな可視化のためのコンポーネントを用意している。利用者は簡単にモデルをドラッグ&ドロップで作れる。（We provide common machine learning algorithms and rich visualization components. Users can train model by dragging and dropping easily.）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/f1c872e6-bbeb-4476-303e-57858408a9d4.png)


- ② データサイエンス・ワークショップ
    - いわゆるJupyter Notebookの環境
    - yumコマンドが通ったので、CentOSベースで作られている模様
    - 必要なモジュールなどはターミナルからpipでインストール可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/2c989b82-ce1d-a3a6-76cd-8fbf0a0731aa.png)

- ③ エラスティック・アルゴリズム・サービス
    - 作成したモデルの共有やバージョン管理をできる機能だと思われる
  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/8cbdeb4a-a901-bffa-6eb2-2e7ff60b4e24.png)



# コンソールからたどり着く方法
PAIは、Machine Learningというプロダクト名でインデックスが引けます。
PAIの正式名称は```Machine Learning Platform For AI```で、プロダクト名称としてヒットしません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/be5063c1-2b9f-6d8b-1de6-1b4614cbafcb.png)




## ビジュアライゼーション・モデリングを覗いてみる

ペインの右側にある```Machine Learning```からモデリングの画面を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/b6f02fb0-9958-737c-502d-803d99de2784.png)


起動時にTensorFlowやCaffeがインストールされるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/c6cda647-f7b8-a5d1-7816-814bb3f3cbe1.png)

サンプルでワークフロー図が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/c23e05d9-d48a-a720-66cf-fb774b11ad62.png)


# Data Science WorkShopを覗いてみる

画像の```Open```から作成したNotebookを開くことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/638cc0c4-4997-bfdc-d68b-645407485f6b.png)

見慣れたJupyterNotebookの画面ですね。
右側のペインにインスタンスのCPUとメモリ（内存）の閾値を表示させられます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/977b217e-ea12-c6f1-dc64-e587103f304e.png)


ターミナルからpipやcondaで外部モジュールをインストールできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/65aa8b2f-62cc-ed56-1e4f-a584d40ea7d4.png)
seq2seqモデルの出力を比較するコマンド

## 問い
モデルの出力を比較するために次の形式のファイルを作りたい。

```
SOURCE  May the Force be with you.
TARGET  フォースと共に在らんことを。
BASE    フォースがあなたと共にいるように。
PROP    フォースがあなたと共にありますように。

SOURCE  ...
TARGET  ...
BASE    ...
PROP    ...
...
```

## 答え
`paste` → `awk` で終わり。

```
paste source.txt target.txt base.txt prop.txt \
      | awk -F'\t' '{printf "SOURCE\t%s\nTARGET\t%s\nBASE\%s\nPROP\t%s\n",$1,$2,$3,$4}'
```
`BASE`と`PROP`の差分だけを見たいときはこっち。

```
paste source.txt target.txt base.txt prop.txt \
      | awk -F'\t' '$3!=$4{printf "SOURCE\t%s\nTARGET\t%s\nBASE\%s\nPROP\t%s\n",$1,$2,$3,$4}'
```