OmniAICreator/Qiita-1.07M huggingface dataset:
Scalaのコレクション選び

結論。[公式ドキュメント](https://docs.scala-lang.org/ja/overviews/collections/introduction.html)読みましょう。以上。

# あれ？性能悪くない？
前回までの記事の通り、自分はSpark上でのグラフ風処理を実装してるわけですが、なんか処理が全然終わらない。
ただ終わらないだけじゃなく、local[8]でぶん回してる(ちなみにCPUは12コアだ)のに2コア分くらいしか働いてない。
デバッガで追っかけてみると、特定のデータ(グラフ的に言うと特定の「頂点」)の処理をずーっとやってて、他は待ちになっているようだ。

この処理では、別の頂点から受信したメッセージを、頂点に適用(計算)して、次の頂点へのメッセージを作る、ということをやってるのだけど、どうやら隣接頂点がむっちゃ多かったらしく、メッセージの構築処理をずーっとやってるようだった。

送信元が100頂点、送信先が100頂点、だと単純にメッセージ数が100×100みたいなことになっていたのだ。

にしてもいくら何でも遅くないか？というのが出発点であった。
ついでにいうと、メモリもバンバン食ってて常にGCが走ってるようなそんな感じもただよっていた。

# 原因はListの結合だった
Scalaには標準でこれでもか、ってほどの数のコレクションクラスが用意されているのだけど、大きく分けて「ミュータブル族」と「イミュータブル族」に分類され、公式な推奨は後者である[^import]。いや、後述するようにどちらが良い悪いではなくて使いどころなのだけど、イミュータブルで済むところはイミュータブルで設計すべきというのが、多分Scalaに限らずプログラミング界隈でのトレンドであろう。
ということで特に何も考えずにイミュータブルなListを使っていたのだが、、、これが間違い。

```Scala
var result = List[Int]()
for (i <- 0 until 10000) {
  result = result :+ i
}
```

こんなことをしてはいけません。
これは1万回ものListインスタンスを作っては捨て(GCに回される)を繰り返してることにほかならないので、それだけでもメモリとCPU時間の無駄な上、

[(公式)COLLECTIONS|性能特性](https://docs.scala-lang.org/ja/overviews/collections/performance-characteristics.html)

見るとわかるように、Listの末尾に要素を追加するのは線形時間がかかるのだ！
ひどい！

よって、末尾への追加が定数時間で済むものを使って解決しましたよ、というお話。こんな感じですね。

```Scala
import scala.collection.mutable.ListBuffuer

val result = ListBuffuer.empty[Int]
for (i <- 0 until 10000) {
  result += i
}
```

イミュータブルなコレクションでも末尾への要素追加が定数時間のものもあります(Queueとか)のでそっちを使うのもありですが、インスタンスは毎回作るのでやっぱもったいないなってことでミュータブルなコレクションを選択した。

# 考察 そもそもイミュータブルは銀の弾丸ではない
そゆこと。何も考えずにイミュータブルなList使ったやつが言うなって？

イミュータブルが好まれ、ミュータブルが避けられるべき理由はいくらでも文献があるので詳しくはそちらを読んでほしいが、いついかなるときでもイミュータブルが正しいわけではない。
そもそも最初の例では、イミュータブルなListを`var`なresultに格納しており、resultをどんどん書き換えていくのだから、イミュータブルである意味が全くない。
ミュータブルが避けられるべきなのは、別の誰か（別のスレッドだったり、参照渡しで呼んだ関数だったり）によって書き換えられてしまう可能性があるシーンだけなので、例のように閉じたスコープで使う分にはなんら問題ない。外に出ていくとき、例えば関数の引数、戻り値をイミュータブルにしておけば大抵はそれで充分だろう。

# まとめ
[公式ドキュメント](https://docs.scala-lang.org/ja/overviews/collections/introduction.html)読みましょう。
特に性能特性は必ず読んで頭に叩き込んでおくべき（だった・・・）

[^import]: 故にList等のイミュータブルなコレクションはデフォルトでインポートされているが、ミュータブルなコレクションは明にインポートが必要だ。
HoloLensでOpenCVしようとしたら苦戦した話

#概要
UnityでHoloLens（UWP：*Universal Windows Platform*）向けにアプリ開発をしていて、OpenCVの導入にごにょごにょと苦戦したあげく、**ネイティブプラグイン**と『**Holographic Remoting Player**』で解決した。

#はじめに
外部カメラ映像をリアルタイムで画像処理しHoloLensに投影するという、~~需要のない~~特異な仕様のアプリ開発に取り組んだ。
画像処理といえばOpenCV、でもUnityでC#でコーディングしている、どう組み込もうかと考えた。
本来であれば『[OpenCV for Unity](https://assetstore.unity.com/packages/tools/integration/opencv-for-unity-21088)』のような便利なプラグインを導入するところであるが、有料というのがネックであり、**無料で**何とかできないかと画策した。
![alt](https://assetstorev1-prd-cdn.unity3d.com/key-image/216bd91a-c3ff-418a-bca1-b7d0e61b25ed.jpg)

#やったこと
###その１. OpenCVSharpの導入
OpenCVをC#で扱えるようにした.Net Framework向けラッパーである『[OpenCVSharp](https://github.com/shimat/opencvsharp)』をNuGet経由で導入した。導入手順は、[Unity であらゆる C#(.NET) パッケージを使う（例：opencv）](https://qiita.com/kingyo222/items/11100e8f7be396b98453) を参照してください。
結果としては、**ライブラリがUWP環境に対応しておらず不動作**。CV::Matできず:cry:
ただし、普通にUnityでOpenCVする分には動作する。

###その２. OpenCVSharp-UWPの導入
OpenCVSharpのUWP向けラッパーである『[OpenCVSharp-UWP](https://github.com/Firifire/OpenCvSharp-UWP)』を導入した。
結果としては、**参照エラーが頻出し不動作**。CV::Matとか、そのレベルじゃなかった:sob:
公式のリポジトリのIssuesにもバグ報告があった。。

###その３. OpenCV-Hololensの導入
OpenCVをHoloLensで扱えるようにしたラッパーである『[OpenCV-Hololens](https://github.com/sylvain-prevost/opencv-hololens)』をネイティブプラグインとして導入した。導入手順は、[【UWPアプリでOpenCVを無料で使おう！】C#(.NET) UWPアプリへのC++ダイナミックライブラリ(dll)の組み込み方](https://qiita.com/xsmiledur/items/127abaef42c5f1126f5e)を参照してください。
この方法により、**無事HoloLensでOpenCVを使うことに成功した**。CV::Matが動く:laughing:

#課題
無事使えるようになったOpenCVで外部カメラ映像を取得し画像処理するアプリとHoloLensに乗っけた投影用のアプリの通信に、*Low-Level Native Plugin Interface*を使おうと思ったら、テクスチャの送受信でメモリがいっぱいいっぱいに。とてもじゃないけど動かせない。:innocent:

#最終的に
###方向転換
そこで、これまでのHoloLensにアプリを乗っけてテクスチャを通信でやり取りする方法ではなく、『**Holographic Remoting Player**』を使ってHoloLensに直接投影する荒業に変更した。

###Holographic Remoting Playerとは
Microsoftが公式で発表しているHoloLens向けのアプリで、LANを介しUnityと通信し、UnityのEdito画面を直接投影することができる。もともとは、開発上のビルドの手間を省き、楽に動作チェックできるという代物（？）であるが、アプリ間通信よりも動作が非常に安定している。
![alt](https://store-images.s-microsoft.com/image/apps.9794.13510798887588711.fe7cdd3a-74a5-4117-a269-78ed4e413dc3.6d7cdded-8c3a-4b17-8934-7ab6bfddfe11?w=1398&h=794&q=90&format=jpg)

###どう変わったか
HoloLensにアプリを乗っけるという枠に囚われるあまりハード・ソフトウェア依存の沼にハマっていってしまったが、Holographic Remoting Playerの導入により、**そのような依存に左右されず、さらにはビルドの必要もない開発環境に落ちつけることができた。**
HoloLens、しいてはUWP向けに開発する必要がないということは、ネイティブのOpenCVをdllとして読み込み、C++で記述したOpenCVによる画像処理をネイティブプラグインとしてC#で扱えるようになった。

#おわりに
特異な仕様ゆえにOpenCVの導入という初歩的な手順で多くの時間を無駄にしてしまった。
そもそもHoloLensにアプリを実装するには、UnityでUWP向けに開発、ビルドしVSソリューションファイルを生成、VSでx86向けにデバックし実機に乗っけるという~~非常に面倒な~~手順を踏むのだが、UnityとVSのバージョン関係でビルドが通らなかったり、ビルドが通らなかったり、はたまたビルドが通らなかったりして、多くの時間を犠牲にした。
Expressコマンドがありません（Windows）

# 一週間悩んだ・・・
```bash
bash: express: command not found
```

#ググり、そして出版会社にもメールを投げた
パスが通ってないっていうのがかなり記事としてあがっていたが、どうも違う。
出版会社に問い合わせたらnpm install -g express-generator をsudoで実行するというのもあったが、
そもそもsudoの時点でコマンドがありません。お手上げ。

#もしかしてnode.jsのバージョンが古いのでは？
一旦アンインストールし、最新版をインストールしてからnpm install -g express-generator

#そして・・・expressコマンド実行

```bash
$ express -e ex-gen-app
```

#コマンドが通った！

```
$ express -e ex-gen-app

 warning: option `--ejs' has been renamed to `--view=ejs'


   create : ex-gen-app\
   create : ex-gen-app\public\
   create : ex-gen-app\public\javascripts\
   create : ex-gen-app\public\images\
   create : ex-gen-app\public\stylesheets\
   create : ex-gen-app\public\stylesheets\style.css
   create : ex-gen-app\routes\
   create : ex-gen-app\routes\index.js
   create : ex-gen-app\routes\users.js
   create : ex-gen-app\views\
   create : ex-gen-app\views\error.ejs
   create : ex-gen-app\views\index.ejs
   create : ex-gen-app\app.js
   create : ex-gen-app\package.json
   create : ex-gen-app\bin\
   create : ex-gen-app\bin\www

   change directory:
     $ cd ex-gen-app

   install dependencies:
     $ npm install

   run the app:
     $ DEBUG=ex-gen-app:* npm start


```

#最後に
よくよく考えたら確証もってバージョンが原因とも言い切れないのでは？と思ったが
何度も最初からやり直したので今さら手順が間違っていたとは思えない。
次は解決するだけでなく原因をもっと明確にしよう。
日本語Wikipediaのデータが欲しくなった時

# 簡単に手に入るWikipediaデータ
Wikipediaの記事は基本的に、ウィキメディア財団によって簡単にダウンロードできるようになっています。

- [日本語Wikipedia記事のダウンロードページ](https://dumps.wikimedia.org/jawiki/latest/)

気ままにクローラを走らされると困るといった理由もあるみたいですが、利用させてもらう側としては手間が少なくて有り難いですね。

# データの一部説明
- `jawiki-latest-pages-articles.xml.bz2`
    - 記事一覧
    - 圧縮された状態で3GB
- `jawiki-latest-abstract.xml.gz`
    - タイトル、要約（「～とは...である」と書いてある最初の数行）など一覧
- `jawiki-latest-all-titles-in-ns0.gz`
    - タイトルのみ一覧
    - （リダイレクトされるタイトルは含まない）
- `jawiki-latest-redirect.sql.gz`
    - リダイレクト元の記事IDと、リダイレクト先などが載ったSQLデータ

# リダイレクトデータ（`jawiki-latest-redirect.sql`）の中身
***一部抜粋***

```SQL
INSERT INTO `redirect` VALUES 
...
(20541,0,'ジョジョの奇妙な冒険','','')
...
```

- 20541：リダイレクト元の記事ID
- ジョジョの奇妙な冒険：リダイレクト先の記事タイトル

を表しています。

これに対し、タイトルと要約などが記載されている`jawiki-latest-abstract.xml`を見てみると、

```XML
<title>JOJOの奇妙な冒険</title>
<ns>0</ns>
<id>20541</id>
<redirect title="ジョジョの奇妙な冒険" />
```

- 記事ID：20541
- 記事タイトル：JOJOの奇妙な冒険
- リダイレクト先の記事タイトル：ジョジョの奇妙な冒険

と、それぞれリダイレクト元とリダイレクト先が対応していることが分かります。

Wikipedia内でリダイレクトされている記事タイトルは意外と多いため、表記ゆれも含めて全タイトルを取得したい場合は

- `jawiki-latest-all-titles-in-ns0`

だけでなく、

- `jawiki-latest-redirect.sql`
- `jawiki-latest-abstract.xml`

も組み合わせて利用する必要がありそうです。
【Sass】重要用語と環境構築方法(gulp)

###はじめに
Sassを使えるように環境を構築できたので、メモとしてこちらに記しておく。
ちなみにnode-sassでコンパイルしています。タスクランナーはgulpです！
###バージョン
gulp.ver4

###対象
ターミナルに抵抗のある駆け出しデザイナーやSassについて何も知らない方
###目次
1,Sass環境構築において重要な用語・知識の説明
2,Sass環境構築の手順

##1,Sass環境構築において重要な用語・知識の説明

#node-sass
LibSassをNode.jsで動作できるようにしたライブラリ
#Node.js
JavaScriptで作られたサーバーサイド環境（現在のモダンフロントエンド開発に不可欠）。
インストールすると同時にパッケージマネージャ（npm）が使えるようになる。
#npm
npmの正式名称は、Node Package Manager。Node.jsのパッケージ（Package ）を管理する（Manager）ツール。
#タスクランナー
様々な処理を自動化してくれるツール。例えばコンパイルなどの処理。
今回はgulpで開発。他にはWebpack,Gruntなどがある。僕がgulpを使った理由は参考書に書いてあるからです笑。でも参考書によるとgulpfile.jsが書きやすいみたいです。

##2,Sass環境構築の手順
###⑴　Node.jsをインストールする。
<img width="1436" alt="スクリーンショット 2019-12-05 23.55.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496595/b57bb672-618f-5983-5a95-930391decf39.png">
こちらの左のボタンからダウンロードします。
↓こちらのコマンドを入力して正常にインストールされているか確認してみてください。

```
node -v
```
このように表示されていたら、インストール完了。

```
v6.数字.数字
```

「node: command not found」と表示されてしまう場合は、PATHが正しく設定されているか確認してみてください。
###⑵　gulp-cliをインストールする。

```
npm install --global gulp-cli
```

これで「マシン（mac）に対してgulp-cliをインストールさせる」という意味です。macにインストールをしているので、どのディレクトリ下でもgulpコマンドが使えるようになりました。

gulpがインストールされているか確認してみてください。

```
gulp -v
```
バージョンが表示されていたらインストール完了です。
「gulp: command not found」を表示される場合は正しくPATHが設定されているか確認してみてください。


###⑶　Sassを使いたいディレクトリ下でpackage.jsonの作成

```
npm init -y
```
↑こちらのコマンドでpackage.jsonの作成する。
###⑷　同じディレクトリでgulpパッケージとgulp-sassパッケージのインストール

```
npm install --save-dev gulp 
npm install --save-dev gulp-sass
```
↑こちらのコマンドでgulpパッケージとgulp-sassパッケージのインストールする。

```package.json
"devDependencies": {
       "gulp": "^4.0.2",
       "gulp-sass": "^4.0.2"
         }

```

↑するとpackage.jsonにこのように追記されるはずです。
###⑸　gulpfile.jsの作成

```gulpfile.js
var gulp = require('gulp');
var sass = require('gulp-sass');

gulp.task('sass', function() {
  return gulp.src('./sass/**/*.scss')
    .pipe(sass({outputStyle: 'expanded'}))
    .pipe(gulp.dest('./css'));
});

gulp.task('sass:watch', function() {
  gulp.watch('./sass/**/*.scss', gulp.task('sass'));
});
```

###⑹ セットアップした環境を一括でインストールする
 
```
npm install
```
このコマンドによって「node_modules」がディレクトリに追加されます。
ここでインストールしたパッケージはpackage.jsonに記述されています。（今回だとgulp,gulp-sassパッケージなど）

###おわりに
以上でSassをcssにコンパイルすることができるようになりました。
何か間違っている点がありましたら、ご指摘よろしくお願いします。
次回はタスクランナーを使う必要性について考えてみようと思います。
LinuxのコマンドをPythonで自作する

※Macでもできるかもしれないです。（未検証）
※言語はRubyとかでもできるかもしれません。（未検証）

# この記事について
この頃さまざまな用途に使われているPythonですが、ファイル操作などちょっとした作業を自動化したい時にも便利ですよね～！

[退屈なことはPythonにやらせよう](https://www.amazon.co.jp/%E9%80%80%E5%B1%88%E3%81%AA%E3%81%93%E3%81%A8%E3%81%AFPython%E3%81%AB%E3%82%84%E3%82%89%E3%81%9B%E3%82%88%E3%81%86-%E2%80%95%E3%83%8E%E3%83%B3%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%AB%E3%82%82%E3%81%A7%E3%81%8D%E3%82%8B%E8%87%AA%E5%8B%95%E5%8C%96%E5%87%A6%E7%90%86%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-Al-Sweigart/dp/487311778X) という本まで出ております。
↑アフィリエイトではないです（念のため）

この記事ではそんなPythonコードをあたかもコマンドのように実行できる方法を紹介します！

# 手順
今回はファイル一覧を表示するコマンド、```filelist```を作成しながら手順を追っていきます。（``ls``みたいなやつ）

手順を一言で紹介するなら、
**Shebangでpythonのインタープリタ（```#!/usr/bin/env python```）を指定したファイル「filelist」に実行権限を与え、保存されているディレクトリにPATHを通すと、そのファイルを```filelist```で実行できるようになる。**
といった感じです。

以下に実装の流れを示します。

### 0.前提
すでにPythonがインストールされていて、```python```コマンドで実行できるようになっていることが前提です。
インストールは「python インストール linux」などで検索すれば方法がいろいろ出てくるので参考にしながら行ってください。

### 1.スクリプトの作成
まずは、実行するためのスクリプトを作成します。
適当にフォルダを作成してその中に保存しましょう。

1.ホームディレクトリに「pycommands」ディレクトリを作成

```shell
mkdir ~/pycommands
```

2.「pycommands」ディレクトリに移動

```shell
cd ~/pycommands
```

3.ファイル「filelist」を作成し、編集画面へ

```shell
vi filelist
```

4.ファイル「filelist」を編集

```python
#!/usr/bin/env python

import os
from pathlib import PATH

# ユーザーが現在いるディレクトリ（os.getcwd()）の情報を取得
current_dir = PATH(os.getcwd())

# glob("*")でユーザーが現在いるディレクトリのファイル一覧を取得
for file in current_dir.glob("*"):
    print(file)
```

ここで重要なのが、1行目の```#!/usr/bin/env python```です。
これは**Shebang**（シェバン）とよばれ、ファイルの中身を何を使って解釈するかを指定しているものです。
ここでPythonを指定しているため、```.py```などと書かれていなくてもPythonコードが実行されるんですね。
（この部分でRubyなどを指定すると、Rubyコードも実行できると思います。）

### 2.実行権限の付与
今作ったファイル「filelist」は、まだ実行できるファイルではありません。
これを実行するためには、ファイルに**実行権限**を与える必要があります。

ファイルに実行権限を与えるには、

```shell
chmod u+x ~/pycommands/filelist
```
を実行します。
（「filelist」を```~/pycommands/```以下に作成した前提でやっています。違う場所に作成した場合は、適宜コマンドを変更してください。）

 ```chmod``` コマンドの意味はこちら：[Linuxの権限確認と変更(chmod)（超初心者向け） - Qiita](https://qiita.com/shisama/items/5f4c4fa768642aad9e06)

この状態ですでに実行自体はできます。
任意の場所で

```shell
~/pycommands/filelist
```

とコマンドを入力すると、ファイルの一覧が出力されるはずです。

次のステップで、これを```filelist```と入力するだけで実行できるようにします。

### 3.PATHを通す
次に、どこからでもこのコマンドを実行できるようにします。

ある場所に置いてあるコマンドをどこからでも実行できるようにするためには、環境変数のPATHを設定する必要があります。

※環境変数、PATHについてはこちら：[Pathを通すとは、環境変数とは - Qiita](https://qiita.com/fuwamaki/items/3d8af42cf7abee760a81)

PATHは、ざっくり言えば「**コマンド（らしきもの）を入力した時、その名前の実行ファイルを探しに行く場所のリスト**」のことです。

```ls``` コマンドを入力すると、PATHの中から「ls」という名前の実行ファイルを探しに行き、見つけたファイルを実行しているのです。
（PATHで定義されている場所リストに、前の方から一つずつアクセスしながら探している。）

とりあえず今回だけ実行するには、

```shell
export PATH='$PATH:$HOME/pycommands/'
```
を実行すればOKです。

いつも使えるようにするためには、

```shell
echo export PATH='$PATH:$HOME/pycommands/' >> ~/.bashrc
source ~/.bashrc
```
でOKです。

### 4.実行！
任意の場所で、

```shell
filelist
```

を実行すれば、ファイルの一覧が表示されます。


# 実行されない場合
### 同名のコマンドがすでにある
すでに同名のコマンドが存在した場合、この流れで作成したコマンドと同名のものがすでに存在するため、PATHで先にそっちが探されてしまい、作ったコマンドが実行されません。（PATHの最後にディレクトリを追加したため）

名前を変えるか、PATHの順番を変えて先に実行されるようにしましょう。（おすすめしない）



# まとめ
コマンドを作って作業を便利にしましょう^^
Flutter で Yahoo! JAPAN ID のログインを実装する

Yahoo JAPAN さんが[Firebase Authenticationを使ってFlutter製アプリにYahoo! JAPAN IDでログインしてみる](https://techblog.yahoo.co.jp/advent-calendar-2018/firebase-flutter-yid/)という記事を書いてくださっているので、この記事通りに進めるとFirebase Authenticationであっさり実装できますが、Flutter webであったり、Desktop に流用したいのでSDKは使わないでWebViewを介した認証方式を実装してみました。

Yahoo! ID 連携 v2 を使用して実装します。[認証の流れはHybridフローを採用しました](https://developer.yahoo.co.jp/yconnect/v2/hybrid/)OAuthの説明は書かないのでわからない方は調べてみてください。
認証の流れは

となります。

## 実装

#### 1.ユーザー認証リクエストをして、初期ページのURLを取得する

初期ページ表示のためのURLを取得します。

apiKey callbackUri はYahoo!デベロッパーネットワークに記載されています。

```Dart
Map<String, String> params = {
	'response_type': 'code token',
   'client_id': apiKey,
   'redirect_uri': callbackUri,
   'scope': 'openid profile email',
   'nonce': dtNow.toString(),
 };

String requestParams = '';
params.forEach((String k, String v) {
  if (requestParams == '') {
    requestParams += '$k=';
  } else {
    requestParams += '&$k=';
  }
  
  if (k == 'response_type' || k == 'redirect_uri' || k == 'scope') {
    requestParams += Uri.encodeComponent(v);
  } else {
    requestParams += v;
  }
});
```

#### 2.WebViewで初期ページを表示する

今回は[webview_flutter](https://pub.dev/packages/webview_flutter)を使用します

他に[flutter_webview_plugin](https://pub.dev/packages/flutter_webview_plugin)や[flutter_inappbrowser](https://pub.dev/packages/flutter_inappbrowser)もあります。

好きなプラグインで実装してください。

1で取得したURLでユーザー認証・同意画面が表示されます。

````Dart
return Scaffold(
  appBar: AppBar(title: Text('Yahoo! アカウント連携')),
  body: WebView(
  	initialUrl: 初期ページのURL,
    javascriptMode: JavascriptMode.unrestricted,
    navigationDelegate: (NavigationRequest request) async {
      /// URLの遷移をハンドリングできます
      if (request.url.startWith(callbackUrl)) {
        final accessToken = request.url.split('#').last;
        await login(accessToken);
      }
      return NavigationDecision.navigate;
    }
  ),
);
````

#### 3.アクセストークンを取得する

ユーザーが同意したら Yahoo!側から Access Token、ID Token、Authorization Code が返ってきます。この続きの処理はサーバーサイドの処理に合わせて、いい感じに処理してください。

サーバーサイドの実装の代わりにFirebase Authenticationを使うこともできます。

```Dart
Future<void> login(String tokens) async {
  Map<String, String> params = {};
  tokens.split('&').forEach((String param) {
		params[param.split('=').first] = param.split('=').last;
  });
  
  /// 認証サーバの処理に合わせて必要な情報を送信する処理を書く
}
```

後日サーバーサイドの処理の記事も書きます。
iOS13のUIActivityIndicatorViewにつまずいた

# はじめに
「この画面にインジケーター出して。白いちょいでかめのやつ。」という要望がきた。

あんまり使ったことがないけど `UIActivityIndicatorView` 使えばいいんだろうなと思い `Style` を `Large`, `Color` を `White Color` にして実装してプルリクを出した。

すぐにレビューで 「`Style` の `Large` は iOS13 からですよ」と返ってきた。:see_no_evil:

（※ Deployment Target は 12.0）

# 対応
確認すると確かになんか警告が出てる...

<img width="241" alt="warning" src="https://user-images.githubusercontent.com/34936885/70243504-08f54580-17b6-11ea-9f8b-ea750ddc3577.png">

Storyboard で設定すると `Large White` は Deprecated になってるのでこれか!と思い使ってしまった...

<img width="258" alt="style" src="https://user-images.githubusercontent.com/34936885/70243039-38f01900-17b5-11ea-99da-f0486e29f8e5.png">

Storyboard で `Style` を `Large White`, `Color` を `Default` にしてコードで下記のように設定

```swift
@IBOutlet private weak var indicator: UIActivityIndicatorView! {
  didSet {
    if #available(iOS 13.0, *) {
      indicator.style = .large
      indicator.color = .white
    } 
  }
}
```

もしくは iOS13 も `Large White` にする。

iOS13 と iOS12 未満で書き換えた場合

| iOS12 | iOS13 |
| --- | --- |
|![12](https://user-images.githubusercontent.com/34936885/70242963-13fba600-17b5-11ea-8065-0e497c9e2db5.png)|![13](https://user-images.githubusercontent.com/34936885/70247096-1e6d6e00-17bc-11ea-95ee-585a3c207ab0.png)|

微妙に中心の円の大きさが違う気がしますが OS の仕様ってことで OK:+1:

# 比較
とりあえずいろんなパターンでみてみました。
## 両方 Large White & Default Color
両方 Storyboard で `Style` を `Large White`, `Color` を `Default` に設定（とくに実行時に警告は出ませんでした）

| iOS12 | iOS13 |
| --- | --- |
|![12_large_white](https://user-images.githubusercontent.com/34936885/70243003-270e7600-17b5-11ea-9436-4789897a65a9.png)|![13_large_white](https://user-images.githubusercontent.com/34936885/70247081-17def680-17bc-11ea-8762-10fc48d8ce6c.png)|

## 両方 Large & White Color
両方 Storyboard で `Style` を `Large`, `Color` を `White Color` に設定（とくに実行時に警告は出ませんでした）

| iOS12 | iOS13 |
| --- | --- |
|![12_large](https://user-images.githubusercontent.com/34936885/70243597-3b9f3e00-17b6-11ea-9759-91def0734939.png)|![13_large](https://user-images.githubusercontent.com/34936885/70247050-0b5a9e00-17bc-11ea-98f0-03ca99c48792.png)|

勝手に iOS13 未満では `Large White` に書き換えてくれてるんでしょうか？？

# さいごに
iOS13 でちょこちょこ Deprecated になってたり追加されたりしているものがあるので気をつけましょう:smiley_cat:
Nextcloud におけるファイルスキャン速度を比較してみた

## はじめに
Nextcloud では、通常は、ブラウザ画面、デスクトップ/モバイルアプリ、WebDAV (クライアントアプリ／API) といった様々な方法でファイルのアップロードを行うことができます。

ただ、大量ファイルの移行の場合は、これらの方法ではとても時間がかかってしまうため、いったんサーバーにファイルの実体を置いてしまって、Nextcloud のファイルスキャン機能を利用して同期をとる方法により比較的短時間に移行が可能です。

Nextcloud 単体で利用する場合、ユーザーごとのローカル領域のほかに、グループフォルダと呼ばれる Nextcloud システムが保有してアクセス権限を付与するフォルダ領域を利用することができます。

ファイルスキャンの方法は以下のようにいくつか準備されております。

* ローカル領域の場合
    * `occ files:scan ［ユーザーID］` による同期。
* グループフォルダの場合
    * `occ groupfolders:scan ［グループフォルダID］` による同期。
    * 書き込み権限を持つユーザーを利用しての `occ files:scan  ［ユーザーID］ ` による同期。

今回は、ファイルスキャンの速度が方法によってどれほど違うのかを検証してみました。

## 検証の条件

### Nextcloud サーバー環境
* Nextcloud アプリケーションのバージョン
    * Nextcloud: 17.0.1
    * グループフォルダアプリ: 5.0.4
* ミドルウェアのバージョン
    * PHP: 7.3
    * MariaDB: 10.4
* サーバー構成: Nextcloud 本体、データベース等を含めた1台のオールインワン。
* サーバー環境: AWS EC2(CentOS7、M5.large)＋EBS(gp2(SSD) 50GB)

### 検証ファイル/フォルダ数
* フォルダ数: 8,355
* ファイル数: 62,780
* 合計ファイルサイズ: 615 MB
* フォルダ階層やファイル配置は基準フォルダ以外は全く同一。

### 検証方法
* テストファイル/フォルダ群を Nextcloud サーバの規定ディレクトリに配備し、 `occ files:scan [アカウント名]` コマンドでファイル/フォルダの同期を行う。
* グループフォルダの同期については、 `occ groupfolders:scan` コマンドでも同期を行うことができるので、こちらも比較対象とする。
* テストは3回行って、実行平均時間で比較する。


## 検証結果
| |実行時間 (ローカル領域)|実行時間 (グループフォルダ:`files:scan`)|実行時間 (グループフォルダ:`groupfoldes:scan`)|
|:-:|:-:|:-:|:-:|
|1|2分15秒|36分55秒|4分07秒|
|2|2分15秒|36分18秒|4分06秒|
|3|2分15秒|36分56秒|4分05秒|
|**平均**|**2分15秒**|**36分07秒**|**4分06秒**|

**⇒ ローカル領域でのファイルスキャンが最速。グループフォルダを `files:scan` する方法は圧倒的に遅い。**

## 考察、あとがき
グループフォルダでのファイルスキャンに時間がかかっているのは、グループフォルダの機能として、ファイルやフォルダ単位にアクセス権限を設定できるため、この権限設定を行っている分時間がかかっていると思われます。
さらに、グループフォルダを `files:scan` で同期する方法は圧倒的に遅いのは、スキャンごとにグループフォルダへのアクセス権限チェックが行われているためと推測します。

ファイルの移行作業にあたっては、普通は事前にテストを実施するなどして実行時間の見込みを測定したうえで移行計画を策定すると思いますが、グループフォルダ内のファイルスキャンはローカル領域よりも時間がかかる傾向、という知識は持っておいてよいと思います。
rails 総まとめ

多くのrailsについて投稿してきたので
総括としてまとめて見ようと思います。

# railsの基本
rails基本その1: [基本作成](https://qiita.com/savaniased/items/e442696c052bc7d34b07)
rails基本その2:  [データベースの作成](https://qiita.com/savaniased/items/59f5c1b8fdf118613d3e)
rails基本その3:  [投稿画面の作成](https://qiita.com/savaniased/items/de66d0a8ea43e42805df)

# rails発展
rails 発展その1:[ルートパス　ページネーション 　データの並び替え　部分テンプレート](https://qiita.com/savaniased/items/57aee81e74ba737c50a3)
rails 発展その2:[ログイン機能](https://qiita.com/savaniased/items/a7ee3cf1cd6dab4755e0)
rails 発展その3-1: [ログイン機能のリンクについて](https://qiita.com/savaniased/items/5a87241bb26573042519)
rails 発展その3-2: [マイページの作成](https://qiita.com/savaniased/items/0c3ebf9fcdbf9efa35e0)
rails 発展その4: [アソシエーション](https://qiita.com/savaniased/items/449540f4004bbfeeafcf)
rails 発展その5:[カラムの追加　単語の区切り　文字数制限](https://qiita.com/savaniased/items/5af3407dc6796a8fab57)
rails 発展その6:[n+1問題　HTTPリクエスト一覧とルーティングのコツ　 ActiveRecord::Baseメソッド一覧](https://qiita.com/savaniased/items/72475835a0e9887dbd5c)
rails 発展その7: [スクレイピング](https://qiita.com/savaniased/items/579d149e361086da0cc7)
rails 発展その8: [form_forとform_tagの使いわけ]
(https://qiita.com/savaniased/items/eb7da75343bdf0d4363f)
rails 発展その9: [数学処理](https://qiita.com/savaniased/items/052ed35766ea22ccb13f)
rails 発展その10: [レシーバ　self](https://qiita.com/savaniased/items/17f87dbb0d554b117220)
rails 発展その11: [コントローラー](https://qiita.com/savaniased/items/90f287a5395387273f73)
rails 発展その12: [カラムのデータまとめかた。](https://qiita.com/savaniased/items/f480d09bdfa998a7a133)
rails 発展その13: [画像について](https://qiita.com/savaniased/items/40236b453aad19244989)
rails 発展その14: [あいまい検索](https://qiita.com/savaniased/items/d0e55282a685c5313374)
GoでANSIエスケープシーケンスで着色されたテキストを画像に起こすコマンドを作った

# まえがき

* GoでANSIエスケープシーケンスをパースしてテキストを着色して画像に起こすコマンドを作った

# 作った経緯

* screenfetchやcczeなどで着色されたテキストを画像に起こしたかった
* ImageMagickのconvertコマンドではANSIエスケープシーケンスでの着色を画像に起こせなかった

# 成果物

[GitHub - jiro4989/textimg](https://github.com/jiro4989/textimg)

# 使い方

標準入力からANSIエスケープシーケンスと一緒にテキストを渡すと、画像を吐き出します。
端末上に垂れ流しても仕方ないので、ファイル出力か、パイプ先が存在しないときは出力しません。

```bash
$ seq 0 255 | while read -r i; do
  echo -ne "\x1b[38;5;${i}m$(printf %03d $i)"
  if [ $(((i+1) % 16)) -eq 0 ]; then
    echo
  fi
done | textimg -o 256_fg.png
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69665/388ed11f-badb-4850-cef9-45d35a4bbfde.png)

アニメーションGIFも生成できます。
1フレームに何行のテキストを使うかも指定できます。

```bash
$ echo -e '\x1b[31mText\x1b[0m
\x1b[32mText\x1b[0m
\x1b[33mText\x1b[0m
\x1b[34mText\x1b[0m
\x1b[35mText\x1b[0m
\x1b[36mText\x1b[0m
\x1b[37mText\x1b[0m
\x1b[41mText\x1b[0m
\x1b[42mText\x1b[0m
\x1b[43mText\x1b[0m
\x1b[44mText\x1b[0m
\x1b[45mText\x1b[0m
\x1b[46mText\x1b[0m
\x1b[47mText\x1b[0m' | textimg -a -o ansi_fb_anime_1line.gif
```

![ansi_fb_anime_1line.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69665/ff1e0103-9bd7-43b6-b5d2-e41d36bb7f94.gif)

絵文字も描画できるのですが、環境構築がちょっと面倒。詳細はREADME見てもらえれば。

```bash
$ echo Test👍 | textimg -o emoji.png
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69665/ec8c41d3-a2a3-e294-a003-e5557583da01.png)

# インストール

絵文字とかを描画できなくて良いのでしたら以下だけで十分です。

```bash
go get -u github.com/jiro4989/textimg
```

絵文字を描画したいなら絵文字のフォントや絵文字の画像を用意する必要があります。
用意する方法についてはREADMEに記載しているのでそちらを参照していただければ。

それらもろもろ含めたDockerイメージを用意しているのでそれを使うのもありです。

```bash
docker pull jiro4989/textimg
docker run -v $(pwd):/images -it jiro4989/textimg -h
docker run -v $(pwd):/images -it jiro4989/textimg Testあいうえお😄 -o /images/a.png
docker run -v $(pwd):/images -it jiro4989/textimg Testあいうえお😄 -s
```

# 実装

## 使用したライブラリ

* mattn/go-runewidth
* spf13/cobra
* x/image

## ロジック

ANSIエスケープシーケンスを含むテキストを以下のように分解します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69665/e5813e3b-cb21-222b-ce0a-0cfef2d4917d.png)

パースは自力でガリガリやってます。汚いですが放置してます。
https://github.com/jiro4989/textimg/blob/master/escseq/parse.go#L67

分解した要素はそれぞれテキストか、ANSIエスケープシーケンスのどちらかです。
それぞれの要素が続く限り、以下のフローで処理します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69665/a5b5e913-686f-7d0f-4ad3-12dbda29fbcf.png)

画像バッファにひたすらテキストを描画するわけですが、ANSIエスケープシーケンスのときは色の変数の更新だけで座標を更新せず、
テキストの時はANSIエスケープシーケンスを使用して画像を描画し、座標を更新するようなフローを延々続けるだけです。
https://github.com/jiro4989/textimg/blob/master/ioimage/image.go#L58

機能追加してる内に関数が肥大化して汚くなってどうしたものかな、と思ってるけれど、欲しかった機能を実装しつくしてやることがないので放置してます。

## 色のマッピング

愚直にRGB値とマッピングしてます。
https://github.com/jiro4989/textimg/blob/master/escseq/color.go#L79

# まとめ

以下の内容について書きました。

* textimgの使い方
* textimgのインストール方法
* textimgの実装

最初はANSIエスケープシーケンスを画像に再現するだけだったのですが、
気がついたらアニメーションGIFを生成できるようになっていたり、
いつのまにか色々できるようになってました。
Goで実装するの楽しいですね。

以上です。

![out.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69665/9a0c19ae-03a8-5c76-4a61-577c102369e4.gif)
BitVisorのリポジトリをgitで扱う方法

ご存知BitVisorのソースは[Bitbucketでmercurialレポジトリとしてホスト](https://bitbucket.org/bitvisor/bitvisor)されていますが，gitを使いたいという人向けの方法をいくつか紹介します．

## hg-git
[hg-git](http://hg-git.github.io/)を使うと，手元のmercurialリポジトリから`hg gexport`で`.git`が生成できます．このときmercurialのbookmarkがgitのbranchになります．ここで，生成されるのはbare repositoryなので実際にはこれを別のディレクトリにさらに`git clone`して作業します．あとはgitで作業してpushでbare repositoryを更新した後，`hg gimport`でmerucialに変更を取り込んでpushという流れになります．

## git-hg
[git-hg](https://github.com/cosmin/git-hg)を利用すると，リモートはmercurialのリポジトリのまま，手元ではgitリポジトリとしてソースを管理できます．内部的には[hg-fast-export](https://github.com/frej/fast-export)を利用してpull/pushの度に変換をおこなっています．

以下の特徴があります．

- mercurialのdefault (unnamed) branchがgitのmaster branchになります
- mercurialのbookmarkは無視されます(!)
- mercurialのnamed branchはgitのbranchになります
- gitの方で新規にブランチを作ってそれをpushすると，mercurialのdefault branchがmultiple heads (multiple roots) になります(!)

いまいち動作が分かりにくいので mercurial => git 変換として使うのが良いかもしれないです．

正直hg-git, git-hg使うのであればmercurialを直接使った方がいろいろと楽な気がします．

## 非公式ミラーを利用する
[matsu/bitvisor](https://github.com/matsu/bitvisor)にgit clone版のbitvisorがあるので，最初からこれを利用するという手もあります．自動でミラーしているのかは分かりませんが，とりあえず現状bitbucketのものと同期しています．

## ところで
来年の5月31日で[Bitbucketはmercurialのサポートを終了](https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket)するらしいです．

>  Mercurial features and repositories will be officially removed from Bitbucket and its API on June 1, 2020.

寂しいニュースですね... 来年BitVisorはどこでホストされるんでしょうか．

## 参考文献
- [version control - Git interoperability with a Mercurial Repository - Stack Overflow](https://stackoverflow.com/questions/883452/git-interoperability-with-a-mercurial-repository)
Nutanixの10年を主に外から目線で振り返る

**本記事は[Nutanix Advent Calendar 2019 #2](https://adventar.org/calendars/4014) 12/6 分の記事です。**

さて、今年はNutanixが創業してから10周年となりました。

自分は無駄にNutanixとの関りが長く、
日本法人ができる前からのお付き合いです。

そんなNutanixを主に外から目線で振り返ってみてみようと思います。
あくまで外の人目線の投稿であり、
オフィシャルな情報ではありませんので、その辺りは悪しからず。
（また、少々個人のことも書いてますが、悪しからず）

# 2011年まで
日本に入って来てないので、そもそも知ることもなく。
USでは2011年に初製品出荷でした。

# 2012年
ついに日本上陸。
と言っても、まだ（公開された）本番での顧客採用事例はなし。
勿論このころから共有ストレージを持たないアーキテクチャで、
2U4Nodeのスタイルで製品出荷をされていました。

この時はFusionIOという懐かしい製品を搭載しており、
それを活用しているので速いぜ！という触れ込みでした。

# 2013年
突如ハードウェアがQuanta製に変更され、
FusionIOを使わなくなりました。

あれ？看板の特徴は？？となりましたが、
このころから通常のSSDを上手くキャッシュ＆Hotデータ領域に活用する
アーキテクチャになっていたので、
遅くて使えないということはありませんでした。
しかしながら、まだソフトは粗削りかなぁという印象。
処理の効率化の結果、バージョンアップすると
性能が爆上げするという謎の事態が発生してました。

この年、国内での本格採用事例が登場し、
いよいよ製品が知られ始めるようになりました。
（この時、中の人を担当）

このころはコアとなるソフトの名称はNOSという呼び方でした。
AOSと呼ばれるのは、まだ先のお話。

日本法人が立ち上がっていたらしいですが、殆ど活動見えず。
まあまだ数人でしたからね。

# 2014年
少しずつ採用事例が増え始める。
この年からですね。Dell OEMが始まったのは。
OEM開始で販売数が加速し始めたようです。

所謂純正と呼ばれるハードウェアがしれっと
スーパーマイクロに戻っていました。
外からみて何か大人の事情を感じました。

また、この年にアジア最大規模の採用案件が日本で生まれました。
まだ全体的に採用が小規模でしたからね。
1案件で30+Node規模です。（中の人を担当）

そして年後半か年明けて辺りでAOS4.0が出た様な記憶。
Prismとしてかなり色々できるようになってきましたし、
ソフトウェアがだいぶこなれてきた印象。
ソフトはやはり年季が入らないと、枯れてこないですね。

まだこのころはvSANのかけらも姿は見えてませんでした。
（アーキテクチャも今売ってるものとは全く違うものでしたしね）

# 2015年
この年、爆発的に採用事例が拡大。
メディアでの取り上げも増えたので、
多くの方はこの辺りから認識されたものと思います。
フラグシップになっている事例もこの年に生まれたものが多いですね。

USで.NEXTが初めて開催されたのもこの年。
最初だったので、まだ800名くらいの規模でした。

（確か）この年にLenovoさんが国内でOEM品の提供を始めました。
（個人的には立ち上がりの頃からご一緒させてもらいました。）

# 2016年
順調に採用の事例が登場。
銀行での採用やPCI DSSに準拠した環境など、
ミッションクリティカルでセキュリティ要件が求められる領域でも、
国内での採用が決まっています。

USで第２回の.NEXTが開催。一気に2000名くらいの規模に。

この年の終わり、個人ごとですが、
2017 Nutanix Technology Championを受賞しました。
沢山携わってきたご褒美というものをここで初めて知りました。
（本記事執筆時点で、SIer在席での取得者が他にいないですね・・・）

# 2017年
いよいよAOSも5.x台へ。
Xiのサービスコンセプトを発表するなど、
大きく広がりを見せてきたのがこの年。
ハイブリッドクラウド・マルチプロダクトと、
かなり大きなターニングポイントになったのかなという年ですね。

日立さんも参入するなど、パートナーの広がりもかなり顕著になってきました。

# 2018年
Eraの発表など、ほぼ成熟してきたHCIの上で何ができるか、
というアプリケーションレイヤへの注力へシフトしてきています。

USのイベントもいよいよ6,000名くらいの規模へ。
エコシステムもだいぶ広がってきた印象。

このあたりからNutanixを担ぐSIerさんがかなり増えてきて、
Nutanixを使った複数ベンダーさんのコンペということも
普通になり始めてきた印象。
AHVも普通に提案されるようになってきて、
価値訴求の幅が広がってきました。

日本法人の人数がかなり増えてきました。

# 2019年
いよいよハイブリッドクラウドの本番として、
Nutanix on AWSな仕組みを発表。
オンプレミスを軸足としてハイブリッドクラウドを
うまく活用できる仕掛けとして、要注目です。
（後日の記事で、紹介します）

2017年頃に舵をきったポートフォリオの広がりに、
ようやく中身が揃ってきたという感じ。
ここからの仕上がりに期待が持てますね。


ということで、10年というか、
実質日本に入って来てからですが、
Nutanixのこれまでを振り返ってみました。

私ごとですが、2019年はいよいよ中の人になりまして、
このわくわくする広がりの現場に身を置くことになりました。

この先も楽しみです。

今回の投稿は以上です。
【Rails】ステータスフィード【Rails Tutorial 14章まとめ】

##ステータスフィード
自身のマイクロポストと、フォローしているユーザーのマイクロポストを表示するフィードを実装する。

###フィードの条件とテスト
フィードが満たす条件は以下の３つである。
①フォローしているユーザーのマイクロポストを含む
②自身のマイクロポストを含む
③フォローしていないユーザーのマイクロポストを含まない
これらを満たすように、まずテストを書く。

```test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  .
  .
  .
  test "feed should have the right posts" do
    michael = users(:michael)
    archer  = users(:archer)
    lana    = users(:lana)
    # フォローしているユーザーの投稿を確認
    lana.microposts.each do |post_following|
      assert michael.feed.include?(post_following)
    end
    # 自分自身の投稿を確認
    michael.microposts.each do |post_self|
      assert michael.feed.include?(post_self)
    end
    # フォローしていないユーザーの投稿を確認
    archer.microposts.each do |post_unfollowed|
      assert_not michael.feed.include?(post_unfollowed)
    end
  end
end
```

Michaelはarcherをフォローしており、lanaをフォローしていない設定である。

###フィードの実装
条件を満たすフィードの実装には、自身のIDまたはフォローしているユーザーのIDに対応するuser_idを持つマイクロポストを取得する必要がある。
試作フィードでは自身のマイクロポストのみを表示していたので、feedメソッドは以下のようだった。

```app/models/user.rb
  # 試作feedの定義
  def feed
    Micropost.where("user_id = ?", id)
  end
```
フォローしているユーザーのマイクロポストを取得するために、まずフォローしているユーザーのIDを配列の形で取得する。
そのためには、following_idsメソッドを使う。

```
>> User.first.following_ids
=> [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
```
following_idsメソッドは、has_many :followingの関連付けをした時に自動で生成される。

feedメソッドでこれを使うためには、SQLを使って以下のようにする。

```app/models/user.rb
  # ユーザーのステータスフィードを返す
  def feed
    Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)
  end
```
これでテストがGREENになる。

###サブセレクトとフィードの改良
ここまでで実装したフィードではフォロー数が膨大になるとアプリケーションの動作が遅くなる。
フォローしているユーザーのIDをデータベースから取得した後、それを使ってまたデータベースからマイクロポストを取得するという操作をしていることが原因である。
この問題をSQLのサブセレクトを使用することで解決する。

まずfeedメソッドを少し書き換える。

```app/models/user.rb
  # ユーザーのステータスフィードを返す
  def feed
    Micropost.where("user_id IN (:following_ids) OR user_id = :user_id", following_ids: following_ids, user_id: id)
  end
```

このコードでは、変更前のコードで？に代入されていた部分がハッシュのキーと値に変わっている。
？にはキーが入っている。
これは同じ変数を複数の箇所で使用するためである。

次にfollowing_idsを以下のようなSQLの文字列で置き換える。

```
following_ids = "SELECT followed_id FROM relationships
                 WHERE  follower_id = :user_id"
```
user_idが１の場合、このコードは「ユーザー1がフォローしているユーザーすべてを選択する」という意味を持つ。
これによりフォローしているユーザーをIDを経由せずに直接データベースから取得できるため、動作を高速化できる。

```app/models/user.rb
  # ユーザーのステータスフィードを返す
  def feed
    following_ids = "SELECT followed_id FROM relationships
                     WHERE follower_id = :user_id"
    Micropost.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
  end
```
following_idsにはSQLの文字列が入っているので、式展開を使っている。
ナンプレをPythonで解く（前編）

#[IPFactory Advent Calender 2019](https://qiita.com/advent-calendar/2019/ipfactory) 5日目
5日目も書かせていただきます。
IPFactory所属、ISC 1年の[pycys](https://twitter.com/PycysA)です。

下記のアルゴリズムでは、解く過程で仮置きを必要とする問題は解けないため、
参考にする際は気をつけてください。

##プログラムが受け取るデータ
![コメント 2019-12-07 011616.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286170/69cb8ca7-deae-9b9d-2b87-e63b48e8cc0f.png)


※画像の数字は添字であり、受け取るデータではありません

0から9までのいずれかの数字81個が空白区切りで渡されるものとします。
ナンプレの左上マス(0, 0)の値は1番目に、右上マス(0, 8)の値は9番目に、
左下マス(8, 0)の値は73番目に、右下マス(8, 8)の値は81番目に記述されています。
0は空白を、1から9はその数字が設定されていることを示します。

##どう解いていくか
ある数字が入る可能性のあるマスをどんどん削って少しずつ位置を確定させていきます。

- 下記のいずれかの条件を満たした場合、ある数字nの位置が確定します。
    - ある3×3枠内でnを置ける場所が1マスのみ
    - ある縦列内でnを置ける場所が1マスのみ
    - ある横列内でnを置ける場所が1マスのみ
    - あるマスに置ける数字がnのみ

ではnを置けるか置けないかの判断をするために、置ける数字を調べる処理が必要になりますね。
3次元配列内に置ける数字をまとめて入れるのが一番わかりやすそうです。
あるマスに置けない数字を削っていくので、最初に1から9までの数字を全部入れます。

3次元配列に数字を入れた後、既に位置が確定している数字を参照し、
同3×3枠内、同縦列、同横列からその数字を削ります。

上記の処理を終えたら、上で挙げた確定条件を満たしたマスがないか確認し、
条件を満たしたマスがあった場合は、参照用の2次元配列に反映後、未確定数字参照用の3次元配列から数字を削ります。

あとはチェックして反映して削っての繰り替えしで解けま...せん。

##普通に解けない例外を弾く
###例外１
これを見てください。
![コメント 2019-12-06 195406.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286170/52d7aac7-cfbd-965c-cbbb-fad3d8d07d90.png)
※小さい数字は未確定数字です。

中段の両端に4と7が、右の縦列の上下に2と3が入ることは確定しているのに、
余分な4と7があるため、状況次第ではうまく処理できなくなるかもしれません。
これは3×3マスのみならず、縦列、横列でも起こりうる事です。

上の画像を例にして、これを回避するための処理を説明します。
まず数字未確定配列の各3×3枠内で、1から9までの値のインデックスをそれぞれ収集し、
その中で、同じインデックスを持つ数字を割り出し、割り出した数字の数と、
掛け持ちしているインデックスの数が一致した場合、その内にある他の邪魔な数字を排除します。

###例外２
![コメント 2019-12-06 210825.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286170/21366388-ae34-32bb-34f4-7f6889f9a8f8.png)
画像は似ていますが、さっきの話と地続きの内容ではないので注意してください。

仮にこんな3×3枠があったとします。
マズい、大変マズいですね。
中段に4,7,8が入るため、本来ならばこの3×3枠を除く同横列の未確定マスから4,7,8を弾く必要がありますが、
この3つの数字は位置が確定していないため、その処理が行われません。

ということで、ある3×3枠のある列にある数字が入ることが確定した際に、枠外の同列各マスに存在するであろう数字候補を削ります。

まず、3×3枠の横列にあたる未確定数字マスを1列ずつset()で集合にし、
その3つの集合で排他的論理和集合を作れば、中に入っているのはいずれかの横列に入ることが確定している数字です。
あとはその数字がある列を特定して、枠外同列の未確定数字マス内にある列確定数字を排除します。
縦列も同様です。

ここまでをいくらか繰り返します。
計算量すごそう...（小並感）

こんな感じでやっていけば解けると思います　　　　　　　　　　　　　　　　　　多分。

##最後に
最後まで読んでいただきありがとうございます。
何が書いてあるのかわからなければ、理解するのを諦めてください。
私も何を書いているのかよくわからないです。

後編の方にコード載せますが、一応GitHubの方にも載せておきます。
コードは[ここ](https://github.com/pycys/Automating-Sudoku-with-python/blob/master/sudoku.py)です。

[ナンプレをPythonで解く（後編）](https://qiita.com/pycys/items/8e4f8922df083e0c4cf9#_reference-8a75eef98b97764255ee)
AWKコマンドとは?

AWK アドベントカレンダー1日目

### AWK(オーク)コマンドとは？
行と列(もしくは行のみ)でできたテキストデータを処理するためのコマンドです。
例えば、次のデータをawkコマンドで処理するとこんな結果になります。

```bash
$ cat fileA
aaa
bbb
ccc
aaa
ccc
bbb
ddd

// 重複を削除
$ cat fileA | awk -F'\n' '!a[$0]++'
aaa
bbb
ccc
ddd 
```

初めてawkを見る人が見ても何がなんだかわからないかもしれませんが、とにかく受けとたデータを行と列(上記の例だと列は使ってませんが)からできているテキストデータを一行づつ読み込んで、後ろに書いてある式を使っていい感じに加工してくれるコマンドとおぼえていただければ大丈夫かと思います。

シェル芸勉強会に出るためには必須のコマンドなので、将来シェル芸人になりたい人は頑張って覚えましょう。
私は知らないまま行ってぼこぼこにされました

なお、awkはプログラミング言語ですので、ターミナルで打つだけではなくてもちろん実行ファイルにして実行することもできます。

### awkコマンドの基本文法

awkの基本文法は、

```bash
$ awk 'パターン アクション'
または
$ awk <オプション> 'パターン アクション'
```

というような感じです。

実際に使うときにはawkに文字列を渡す必要があるので、次のような使い方を良くします。

```bash
$ awk 'パターン アクション' 対象文字列のファイル
$ awk 'パターン アクション' < 対象文字列のファイル
$ cat 対象文字列のファイル | awk 'パターン アクション'
$ echo "対象文字列" | awk 'パターン アクション'
$ <適当なコマンド> | awk 'パターン アクション'
```


### パターンとアクションとは？

パターンとアクションについて解説しますが、感のいい人だったら次の使い方を見ただけでなんとなくパターンとアクションがどんなことをしているかわかると思います。

```bash
$ cat fileA
aaaaaaaaaaaaaaaaatest
bbbbbbbbbbbbbbbbbbbbb
testccccccccccccccccc
ddddddddddddddddddddd

// testが含まれている行だけを出力
$ cat fileA | awk '/test/ {print $0}'
aaaaaaaaaaaaaaaaatest
testccccccccccccccccc

```
結果を見てわかる通り、「test」という文字列の行が、出力されていますね。

これを見てもう俺はawk完璧に理解した！！って人は飛ばしていただいて大丈夫ですが、そうでない方はパターンとアクションを理解するために処理を分解してみましょう。

#### 処理を分解
さっきの処理は次のようなことを行っていました。

1.fileAの内容がawkに渡される
2.awkが1行目の「aaaaaaaaaaaaaaaaatest」を読み込む
3.読み込んだ行をつかってパターンを評価する(/hoge/は、正規表現にマッチしているか調べる)
4.trueなのでアクションが実行される
5.「aaaaaaaaaaaaaaaaatest」が出力される($0は行の情報すべてを指す)
→1行目終了
6.awkが1行目の「bbbbbbbbbbbbbbbbbbbbb」を読み込む
7.読み込んだ行をつかってパターンを評価する
8.falseなのでアクションが実行されない
9.「bbbbbbbbbbbbbbbbbbbbb」が出力される
→2行目終了
→3行目処理...
→4行目処理...

#### あれ、これってどこかで見たことある、、、
そう、これって簡単に言うと一行ごとにif文を回してくれますよっていうことです。

同じ処理をPHPで書いてあげるとこんな感じですかね。

```
// 正規表現にマッチした行を出力する
<?php
// ファイルを読み込み
$file = fopen("list.txt", "r");

if($file){
  // ファイルを一行づつ処理
  while ($line = fgets($file)) {
    // 正規表現にmatchしたら出力
    if (preg_match("/test/", $line)) {
      echo $line."\n";
    }
  }
}
```
### まとめ
awkコマンドってこんな処理してるんだへーってなって興味を持ってくださる方がいらっしゃると幸いです。

私もまだまだawkコマンド使いにはなれてないので、今回のアドベントカレンダーで一歩でもawkerになれるように努力致します。

本日は読んでくださってありがとうございました。
今更MVP勉強したら２種類あると言われた。

## はじめに
AdeventCalendar5日目です。  
ちょっとボリューム少ないので休憩の片手間にでもどーぞ。
土日頑張るので許してください。
今回はiOSのMVPです。
## MVPとは
画面処理とプレゼンテーションロジックを分離したアーキテクチャです。
主にModel,View,Presenterに分かれています。
**Model**
データを持ったりします。API叩いたりデータベースと繋いだりするのがここです。
MVCのModelと一緒です。
**Presenter**
ViewとModelの仲介をする。
その名の通りプレゼンテーションロジックを担当する。
例えばViewでボタンが押されたとしたらそれに応じてPresenterがModelからデータ持ってきてViewに返したりなど。
**View**
viewは画面表示を担当したりユーザーからのアクション(ボタン押したとか)をPresenterに伝えます。
viewControllerとかstoryboradとかがここに入ります。
## 2種類ある
どうやら2種類あるというのはフロー同期かオブザーバー同期かということらしいです。
**フロー同期の方のMVPの流れ**
フロー同期の方の流れは下の画像のような感じで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255216/e8f74968-e5a4-6f32-8c8f-2411618d3ac4.png)
フロー同期の方だと毎回Presenterを通す必要はありますがViewが画面処理の実装しか必要なく、主な処理はPresenterに丸投げするためPresenterのテストとかがしやすくなるらしいです。
**オブザーバー同期の方**
オブザーバー同期だとModelのデータがアップデートされるとそれをViewに通知しView側でそのデータをよしなに使って表示し直すみたいな流れがあるのがフロー同期とは違う点です。
なのでデータの流れが追いやすいなどのメリットがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255216/b386b459-fbf3-f847-6ae0-c67273c2c068.png)


## 最後に
今回はとりあえずMVPは細かく分けると２種類あるということとそれぞれメリットがあるので場合によって使い分ける必要があるということが知れました。
正直ざっくりしか書けていないので説明不足感はありますがもっと知りたい方は調べてみてください。色々奥が深いです。
明日か明後日にMVP使ったアプリの記事出すのでコードの方はそちらをみてイメージつかんでください。
まあちょっと忙しくて今日はそんなに質が高くありませんでした。次回に期待してください。
もっと言い訳したいのですが「※言い訳していいわけあるか」というダジャレが頭をよぎるので言い訳はこれくらいにしておきます。

※言い訳していいわけあるか・・・週刊少年ジャンプに連載していたあの日本が誇る超有名漫画NARUTO疾風伝575話で３代目土影オオノキがうちはマダラと戦っているときに口にしたセリフである。
ParquetにしたOSMのデータをEMRでいじってみる

# 目的

昨日PBFからParquetに変換したOpen Street Mapのデータを、AWS EMRでspark-sqlを使って触ってみる。
全球データ=大きい　→　分散処理したい　→　AWS EMR

今回は、[こちら](https://georgheiler.com/2019/05/03/osm-to-spark/)と[こちら](https://georgheiler.com/2019/05/07/analyze-osm-data-in-spark/)を参考にして、データ処理していきます。

# 準備

## S3にParquetのデータをアップロード

前回作ったParquetのデータ3ファイルをS3のバケットにアップロードします。僕は簡単にAWSコンソールからアップロードしましたが、aws-cliを使うなり方法は他にもありますね。

## キーペアの用意

EMRクラスタ用のキーペアを作って、ダウンロードしておきます。使うOSやSSHクライアントに合わせて鍵ファイルを選んでください。

## クラスタの立ち上げ

AWSコンソールからEMRクラスタを立ち上げます。
ログ記録はなしで、Sparkクラスタを指定します。クラウド破産も怖いので、インスタンス数も2個くらいにしておきましょう。インスタンスタイプももっと小さいインスタンスでいい気がしますが、デフォルトで指定されているm5.xlargeをそのまま使っておきます。
「クラスターを作成」すると、しばらくしてクラスターが準備完了になります。

## セキュリティグループを設定してsshログイン

セキュリティグループがデフォルトで作成されますが、SSHが開いていないので、セキュリティグループを編集してmasterの方だけ外からのSSHを開けます。これで、先ほどのキーペアを使って手元からSSHログインできるようになります。

# spark-shellを使って処理してみる

では、立ち上がったEMRクラスタを使って、Parquetに書き出したOSMデータを処理してみます。spark-shellを立ち上げます。

```
$ spark-shell
```

データファイルを読み込みます。

```
scala> import org.apache.spark.sql._

scala> import org.apache.spark.sql.types._

scala> val sqlContext = new SQLContext(sc)

scala> val df = sqlContext.read.parquet("s3://bucket-name/Tokyo.osm.pbf.node.parquet")
```

スキーマを確認します。

```
scala> df.printSchema()
root
 |-- id: long (nullable = true)
 |-- version: integer (nullable = true)
 |-- timestamp: long (nullable = true)
 |-- changeset: long (nullable = true)
 |-- uid: integer (nullable = true)
 |-- user_sid: binary (nullable = true)
 |-- tags: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- key: binary (nullable = true)
 |    |    |-- value: binary (nullable = true)
 |-- latitude: double (nullable = true)
 |-- longitude: double (nullable = true)
```

緯度と経度だけを抜き出してみます。

```
scala> df.registerTempTable("Node")

scala> val df3 = sqlContext.sql("SELECT id,latitude,longitude FROM Node")

scala> df3.show
+--------+------------------+------------------+
|      id|          latitude|         longitude|
+--------+------------------+------------------+
|31236558|        35.6351506|139.76784320000002|
|31236561|35.635041900000004|139.76785900000002|
|31236562|        35.6379133|       139.7591729|
|31236563|35.638182900000004|       139.7585998|
|31236564|35.638516100000004|139.75823490000002|
|31236565|35.638767200000004|       139.7580599|
|31236566|        35.6390562|       139.7579335|
|31236567|35.639158200000004|       139.7579045|
|31236568|        35.6393004|       139.7578741|
|31236569|        35.6378794|       139.7589461|
|31236570|35.637997500000004|       139.7586995|
|31236571|        35.6382569|       139.7583386|
|31236572|        35.6384817|139.75812480000002|
|31236573|35.638980700000005|       139.7578382|
|31236574|35.639336400000005|       139.7577578|
|31236575|        35.6395142|        139.757745|
|31236576|        35.6347773|       139.7699528|
|31236579|35.634913100000006|       139.7705506|
|31236580|        35.6350156|       139.7709312|
|31236581|35.635654800000005|       139.7727102|
+--------+------------------+------------------+
only showing top 20 rows
```

結果をS3に保存します。

```
scala> df3.rdd.saveAsTextFile("s3://bucket-name/Tokyo.osm.pbf.node.txt")
```

# まとめ

なんかいけそう！
sass　導入手順

##sassとは？
ずばり、簡単に言うとSassはプログラムっぽくCSSを書くと言うことです。
通常のCSSでのコーディングよりはるかに作業効率が向上しますので良いことづくしです。

SassはCSSのメタ言語と言われており、より効率的に書けるようにしたものになります。

##メリット
- 関数が使える
- 四則演算ができる
- 変数で値を使いまわすことができる
- コードが見やすくなる　etc.....



sassが使えるようになると作業効率がアップされ、非常に便利なものになっておリます。
チームで開発するときも用いられているのがsassです。使えるようになるとチームでの作業も楽々と進められるようになるので、この機会に使えるようになりましょう。

##デメリット
- 環境を作るのが面倒


それくらいですかね？？
それぐらいと思うほど私はsassにはメリットがあると感じています。
しかし、sassを導入するのは確かに面倒な部分もありますが、それさえできるようになれば、便利だなと思える日がくると思うので頑張りましょう！！


##sassの環境作り
windowsとmacユーザーで導入方法が少し変わってくるのですが、あまり大差ないです。Macユーザーはデフォルトで「Rudy」が入っているので、自動でCSSをコンパイルしてくれるので、コンパイラは不要な場合が多いです。

Winユーザーは「Rudy」のインストールが必要でちょっと面倒なんですが、GUIコンパイラをインストールすれば「Rudy」のインストールは必要なく簡単にコンパイルできます。

##順序
- <a href="https://nodejs.org/en/">Node.js</a>のサイトにアクセスしダウンロードします。
- コードを開いてターミナルを開く
- npm init -yでpackage.jsonが作成される
- npm install gulpでpackage-lock.jsonとNode_modulesが作成される
- gulpfile.jsと言うファイルを作る。

```html
'use strict';
let gulp = require('gulp');
let sass = require('gulp-sass');
let cleanCSS = require('gulp-clean-css'); // minify
let sourcemaps = require('gulp-sourcemaps'); // dev toolからscssの何行目か確認
let sassGlob = require('gulp-sass-glob'); // パーシャルの一括読み込み
let rename = require('gulp-rename'); // rename
let autoprefixer = require('gulp-autoprefixer'); // ベンダープレフィックス
gulp.task('sass', function () {
  return gulp.src('./sass/**/*.scss')
    .pipe(sourcemaps.init())
    .pipe(sassGlob())
    .pipe(sass({ outputStyle: 'compact' }))
    .pipe(sass().on('error', sass.logError))
    .pipe(autoprefixer())
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./assets/css'));
});
gulp.task('minify', function () {
  return gulp.src("./assets/css/*.css")
    .pipe(cleanCSS())
    .pipe(rename({
      suffix: '.min',
    }))
    .pipe(gulp.dest('./assets/css'));
});
gulp.task('sass:watch', function () {
  gulp.watch('./sass/**/*.scss', gulp.task(['sass']));
});

```
- gulpfile.js内にこのコードを貼ってください。
- sassフォルダーを作成する。そのフォルダー内にstyle.scssのファイルを作る。
- npm install --save-dev　ライブラリー名でインストールする。これをインストールしたいライブラリー毎にインストールする。
- そして gulp sassでコンパイルするとassetsフォルダーとcssが作られる。



だいぶざっくりですが、一通りはこんな感じです。
##最後に
sassは使えたら非常に便利なので皆さんも使っていきましょう！！！！！

もし、ここが違うよとか教えていただけたら幸いです。




ポモドーロテクニックのススメ

# はじめに

QUELCODEで講師をしているalcoder(あるこーだー)です。
自分はもともと塾の先生をやってたという経歴があるので、今回のアドベントカレンダーは技術要素強めというより学習方法要素強めって感じで書こうと思います。
第一弾は「ポモドーロテクニック」についてです。

# ポモドーロテクニックってなによ？
1987年にイタリア出身のフランチェスコ・シリロ氏が学生の時にやり始めた時間管理術のことで、当時トマトの形をしたキッチンタイマーをセットして時間を区切って試験勉強をしていたことが名前の由来となっているテクニックです！
(イタリア語でトマトはポモドーロというそうで…)

「25分の集中」と「5分の小休憩」を１セットとして(この１セットを１ポモドーロという)、４セットごとに長い休憩をとるのが一般的なポモドーロテクニックとなります。
ポモドーロテクニックで大事なのは時間に厳密であることで、あとちょっとで終わるから少し伸ばそうだとか、Twitterやめらんねええええええええええええええもうちょっと休憩したろとかは×です。時間が来たら中途半端でも切り替えるのが重要です。

このテクニックを実行することで作業の効率が自分は上がりました。

ちなみに日本で広まったきっかけはメンタリストのDaigo氏の著書「自分を操る超集中力」といわれています。

# じゃあ実際どう使うのよ？
先人の知恵というのは素晴らしいものでGoogleChromeの拡張機能にこのポモドーロテクニックをお試しできる機能があります。
実際に使ってみましょう。

1. Chromeウェブストアで検索窓に「pomodoro」と入れて検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302561/bb350da0-c00b-237c-ff91-1553da3c37ce.png)

1. 一番上に出てきたやつを追加！
2. 右上においしそうなトマトが追加されていたらインストールは完了！  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302561/dafae7d9-770f-1f60-8916-46428a7dbc0e.png)

1. あとは作業をするときにトマトをクリック→時間になったら休憩の繰り返し
2. トマトを右クリックして「ポモドーロの履歴」を押すとどれくらい頑張ったか見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302561/ff0dfad7-c964-6528-1fa4-4f588e3b05fb.png)

# トマト押すだけじゃものたりないというあなたには…

こんなRPG風のもあるのでオススメ
https://www.g-g-g-g.games/

# まとめ
・ポモドーロテクニックを使って集中と休息をうまく切り替えることで効率よく学習ができる。
・集中力が長続きしない自分にもう失望しなくてもいい！
・このテクニックを使えば、書き忘れてたアドベントカレンダーもかける！
(@1110yenperhour )

というわけでいかがだったでしょうか？
それでは次回「KPTのススメ」でお会いしましょう！
バイバイ！
Chrome のコンソールに猫の足跡を並べよう

![nyan01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32871/fdbcc388-596b-731c-e003-9aad8c440b0c.png)

Chrome のコンソールに猫の足跡を並べたくなったので、並べてみました。

# ⚠注意点⚠

これは所謂「無限ループ」です。
実行したが最後、 Chrome のタブを閉じない限り実行され続けます。
閉じても問題のないタブのコンソールから実行してください。


# スクリプト全体

```js
{
  const nyanFrequency = 11;
  const nyanSize = '36';
  const nyanTime = 500;
  const nyan = '🐈';
  const footstep = '🐾';
  let nyandam;
  let nyanText = nyan;
  const nyanFunc = () => {
    nyandam = Math.round(Math.random() * 100);
    if(nyandam % nyanFrequency === 0){
      nyanText = nyanText + nyan;
    }
    nyanText = nyanText + footstep;
    console.log(`%c${nyanText}`,`font-size: ${nyanSize}px`);
  };

  setInterval(nyanFunc, nyanTime);
};
```

# 猫の足跡が増えるタイミングを変えたい

猫の足跡が増えるタイミングを変えたい場合は `var nanTime = 500;` を変更してください。
ミリ秒単位で変更可能です。

# 猫が登場する頻度を変えたい

猫が登場する頻度を変えたい場合は `const nyanFrequency = 11;` を変更してください。
数字は `1` 以上の任意の値にして下さい。
数字を増やせば猫が登場する頻度は落ちますし、数字を減らせば猫が登場する頻度が増えます。

# 猫の大きさを変えたい
猫の大きさを変えたい場合は `const nyanSize = '36';` を変更してください。
数字は `1` 以上の任意の値にして下さい。
ただし最小フォントサイズは Chrome の設定に依存します。

# 猫以外も表示したい

こちらの記号をお好みのものに変更してください。

```js
  const nyan = '🐈';
  const footstep = '🐾';
```

例えばこのように変更すると……

```js
  const nyan = '⛄️';
  const footstep = '❄';
```

冬っぽくなります。

![snow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32871/4c90bd49-faa0-3c1a-2dd8-0e90191ee5cb.png)
RSGT x 覚悟 x 成長

# はじめに

幸いなことに今年もRSGTに登壇させて頂けることとなりました．
今年は，「モブプログラミング x 行動分析学 x 教育 / Mob Programing x Behavior Analysis x Education」というタイトルで，昨年に引き続き，行動分析学をキーとした試行錯誤のお話をさせて頂こうと思っています．

そして，[Regional Scrum Gathering Tokyo Advent Calendar 2019](https://adventar.org/calendars/4413)の記事として，RSGTを通した自分自身の成長をちょっと振り返ってみたいと思います．

# RSGTの強烈な洗礼

僕にとってRSGTは，色々な意味で自分を育ててくれた場所です．
Agile / Scrumについて，今よりももっと表層的なことしか理解していなかったころに参加し，「Scrumをやろうとは言われるんだけど，クライアントがなかなか出てきてくれないんですけど，どうしたらよいですか？」といったことを質問した記憶があります．
その際に頂いた言葉は，僕にとって強烈でした．

「クライアントに，このプロジェクトって重要じゃないんですか？って確認してみたら」

といったことを言われました．

クライアントのため，よりよりゴールのため，真摯に課題に向きあい，今までやってきたことですらも真剣に疑うその姿勢が，Agileであり，その仕組みとしてScrumがあるのだなぁと気付けたきっかけでした．今までは表面的にAgileと呼ばれているものをやろうとしていただけで，Agileをこれっぽっちも分かっていなかったんだと気づかされた一言でした．

# 発表を通しての学び

今回，RSGT2020でお話をさせて頂くのは4回目になります．
思い返すと，最初に登壇させて頂いた際の内容などを考えると，恥ずかしくなってきてしまいますが，それを通して，成長できたのかなと思います．

もちろん，RSGTには色々な方が参加されているのですが，おかしいくらいに真剣に考えている方たちがいっぱいいます．毎年，参加するたびに，更なる高みはまだまだあるなということを思い知らされます．
そして，そんな凄い人たちからは，内容にはマサカリを投げられることもあるのですが，絶対に人格否定のようなことはされたことがありません．

そういう意味で，心理的安全性が担保された素晴しい場所だと思います．
そんな環境で育ててもらったのだなぁとしみじみ思います．

# 意気込み

正直に言って，RSGTでお話をさせて頂くのは怖いという思いも強いです．
凄い人たちの中で，自分の言葉にどれだけの価値があるんだろうと戸惑うこともあります．

ですが，自分自身が現時点でのベストと思うことを，間違っているかもしれないけど，自身を持って表現するという覚悟が，この場を構成しているのかなと思うようになりました．そして，その覚悟こそがAgileの一つの側面なのかもとも思っています．

RSGTに参加される方は，本当に素晴しい方が多いので，その経験を経て，そんなエンジニアになれましたなんてことはおこがましくて言えませんが，僕の経験，僕の視点でお話をさせて頂き，聞いてくださったくださった方々に何か持ち帰ってもらえるように挑戦します．

それを通して，少しでもこのコミュニティ，このイベントに恩返し(?)をさせて頂き，僕自身も成長するそんな場に貢献できればと思っています．

是非，セッションにお越しください．
【Rails】Rails⇔JavaScript間で時間データを渡す方法

## 【はじめに】
先日、こちらの記事を書きました。
[【Rails】Rails側で定義した変数をJavaScriptに簡単に渡せるgem 「gon」を使ってみた - Qiita](https://qiita.com/terufumi1122/items/943241581a4a21826af5)

ただ、時間関係の変数については**フォーマット**がRubyとJavaScriptで異なってしまい、うまく動きません。

そこでRails⇔JavaScript間で**時間データを渡す変換方法**を調べたのでまとめてみました:relaxed:

## 【この記事が役に立つ方】
- Rails⇔JavaScript間で時間データをやりとりしたい方

## 【この記事のメリット】
- Rails⇔JavaScript間で時間データをやりとり出来るようになる。

## 【環境】
- macOS Catalina 10.15.1
- zsh: 5.7.1
- Ruby: 2.6.5
- Rails: 5.2.4

## 【ポイント】
### **1000を掛ける、割る**で調整する。

---
## 【変換方法】
### 1.Ruby → JavaScript
```ruby
t1 = Time.now
=> 2019-12-05 14:11:03 +0000

t1.to_f * 1000
=> 1575555063351.479
```
Ruby側で`to_f`メソッドを使い、1000を掛けることでミリ秒に変換。
↕
JavaScript側で`new Date()`の引数にそのミリ秒を渡す。

```javascript
let d1 = new Date(1575555063351.479)

d1
// Thu Dec 05 2019 23:11:03 GMT+0900 (日本標準時)
```

---
### 2.JavaScript →　Ruby

```javascript
let d2 = new Date()

d2
// Thu Dec 05 2019 23:20:04 GMT+0900 (日本標準時)

d2.getTime() / 1000
// 1575555604.804
```

JavaScript側で`getTime()`で拾った数値を1000で割る。
↕
Ruby側で`Time.at()`の引数にその数値を渡す。

```ruby
Time.at(1575555604.804)
=> 2019-12-05 14:20:04 +0000
```
## 【参考】公式リファレンスより
###【Ruby】 Timeオブジェクト `秒`単位
> Time オブジェクトは時刻を起算時からの経過秒数で保持しています。起算時は協定世界時(UTC、もしくはその旧称から GMT とも表記されます) の 1970年1月1日午前0時です。なお、うるう秒を勘定するかどうかはシステムによります。


[class Time (Ruby 2.6.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Time.html)

###【JavaScript】 Dateオブジェクト `ミリ秒`単位
> 日付や時刻を扱うことが可能な、JavaScript の Date インスタンスを生成します。Date オブジェクトは、1970 年 1 月 1 日 (UTC) から始まるミリ秒単位の時刻値を基準としています。

[Date - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date)

## 【おわりに】
最後まで読んで頂きありがとうございました:bow_tone1:

特に**JavaScriptと他言語**は頻繁に関わってくると思いますが、言語間でエラーが出たら**そもそも前提が違う**という視点を持って対処していかないといけないですね:thinking:

## 【参考にさせて頂いたサイト】（いつもありがとうございます）
- [Ruby on RailsとJavaScriptの間の時間変換 - コードログ](https://codeday.me/jp/qa/20190203/202728.html)
- [Date - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date)
- [class Time (Ruby 2.6.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Time.html)