OmniAICreator/Qiita-1.07M huggingface dataset:
進捗管理とは具体的に何をやればいいのか

## はじめに

### 進捗管理のないプロジェクト

私の担当ではないのですが同じチーム内で取り組んでいる小規模なプロジェクトで、定例進捗会はなし、ざっくりした線引きのWBSはあるものの、あまり更新はされておらず、ふわっと進めていれば何となくうまく行くだろう的なスタンスで進んでいる隣のプロジェクトがありました。

第三者的な立場でときどき話を聞いていたのですが、稼働まで残り1か月程度になったときにこのままではうまくいかなさそうな気がしたのでちょっとだけ進捗管理することにしました。

私がうまくいかなさそうと思ったポイントは下記のとおりです。

- 担当者が目の前のタスクしか見ていない
- タスクの締め切りが明らかになっていない
- 稼働までのスケジュールとタスクが詳細化されていない
- 余裕をもった線引きがしてあるのでそこで吸収できるといつまでも思っている
- そろそろやばいなーと言いつつ、具体的なアクションプランができていない

そこで私なりに進捗管理とは何をやればいいのかというのを改めて考え直したので、それをまとめた内容になります。主に短期プロジェクトや稼働直前の話になるかもしれません。

## 進捗管理で具体的にやること

※多少進捗管理の範疇からはみ出す部分があるかもしれません。

### 1.ゴールから逆算して必要なタスクを洗い出す

ざっくりとしたマイルストーンと工程の期間だけが決まっているスケジュールしかない場合、メンバーと一緒に具体的なタスクに落としていく作業が必要です。いわゆるWBSの詳細化というやつです。

具体的なタスクに落とすときにまず考えるのは、明日稼働できるのか？ということです。
「明日稼働できるのか？」→「NO」→「では何ができていれば明日稼働できるのか？」→「〇〇ができていること」→「では〇〇ができるためには何ができていること／どういう状態になっていることが必要か。」
をひたすら繰り返して考えます。

このとき、場合によってはまだいろいろ決まっていなくて内容が詳細化できないものがあると思います。
その場合、〇〇の内容を詳細化する、というタスクを1つ設定し「〇〇の内容を詳細化するためには何ができていることが必要か。」を考えます。

この作業を明日着手するタスクが出てくるまで繰り返します。

### 2.タスクの見積とデッドラインを決定する

必要なタスクの洗い出しが終わったら、タスクの前後関係の整理と、どのタスクがいつまでに終わっていれば稼働に間に合うのかということを稼働日から逆算して決めていきます。いわゆるクリティカルパスを確認する作業です。

このとき、締め切りは〇月〇日というレベルまで決められることが望ましいです。〇月〇週目としてしまうと、その週に進捗を確認したときに遅れているのか遅れていないのかわからなくなってしまいます。1日は貴重です。

タスクにかかる期間を見積もるうえで注意しなければならないのは、営業日で見積もるということです。カレンダーで見ると一見余裕があるように見えても、土日祝日をはずすと意外と日数が少ないということがよくあります。

### 3.いつやるの？を追及する

タスクとデッドラインが決まったら、いつやるの？をひたすら追求します。
少なくとも、向こう1週間（次の進捗確認日まで）にやらなければならないタスクは日単位の粒度で決定できることが望ましいです。

顧客の回答待ちなど、誰かから依頼の結果を受け取らないといけないものについては、いつもらえるの？をひたすら追求します。いつもらえるかわからないということがありますが、デッドラインが決まっていればおのずといつまでにもらえていないといけないか、はわかるはずなのでそれを元に期限を切ってもらいます。

### 4.予定通りできたのかを確認する

いつやるかまで決まっていれば後は定期的にタスクが予定通り実行できたかを確認するだけです。

### 5.予定通り実行できなかったタスクのリカバリプランを考える

予定通り実行できなかったタスクがあった場合、その結果を踏まえてリカバリするためのタスクを設定してもらいます。

この辺がどうやればいいか非常に難しいですが、これに関して汎用的なやり方はおそらくありません。
このときとりあえず最低限考えておいたほうがよいのは

- 何故予定通りできなかったのか
- 予定通りできなかった原因・理由は継続して存在するか
- 継続して存在する場合、どうやってその原因を排除／回避するか
- 本稼働を遅延させる必要があるか
- 何か（顧客の要望、機能、品質など）をあきらめる必要があるか

あたりかと思います。

余裕があれば

- 過去に戻ってもう一度やり直せるとしたらどうすればこの問題を回避できたか
- 過去に戻ってやり直しても回避できない問題であれば、どういう備えをしておけばダメージを最小限に食い止められたか
- どういう備えをしておけば素早くリカバリできたか

を考えておくと今後の役に立つと思います。

## おわりに

文章として起こしてみると結構教科書的な内容になってしまいました。

そして記憶を掘り起こしてみるとSIer時代に先輩からだいたい同じようなことを教わった気がします。当時はそんなこと言われてもできないですよ・・・といった感想でしたが。

いくらか経験を積むと知識を実体験として消化できるということなのかもしれません。
html table セルの結合

##結論
td、th要素に`colspan`属性、`rowspan`属性を指定する。

colspan：横に結合
rowspan：縦に結合
<img width="347" alt="スクリーンショット 2019-02-09 16.53.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/311894/f55de92d-b3b4-0a28-1a65-8ee2d39fc917.png">

```html:index.html
<table frame="box" border="1">
    <tr>
        <td colspan="3">セルの横結合</td>
        <td rowspan="2">セルの縦結合</td>
    </tr>
    <tr>
        <td>セル第一形態</td>
        <td>セル第二形態</td>
        <td>完全体</td>
    </tr>
</table>
```
Jupyter Notebookのセル幅を広げたい！ 

初投稿です。
（記事作成の要領が分かっておらず、まずは備忘まで・・・）


Jupyter Notebookのセル幅が妙に狭いので、
広げられないか？と思って以下のページにたどり着きました。


[こちらのページで見つけました、ありがとうございます！](https://qiita.com/SaitoTsutomu/items/aa19a152dd8c80824d95)


結論、以下コードをJupyterのcodeに張り付け、実行するだけ。（とてもかんたん！！）



```python

%%HTML
<style>
    div#notebook-container    { width: 95%; }
    div#menubar-container     { width: 65%; }
    div#maintoolbar-container { width: 99%; }
</style>
```


デフォルト設定にできれば、もっといいんだけどなー


## 追記（190209 コメントで教えていただいたもの）

> デフォルト設定にできれば、もっといいんだけどなー

こちら、できるとのことでした！（教えていただき。ありがとうございます！　[ソースはこちら](https://github.com/dunovank/jupyter-themes)）
かんたんで、以下２STEPです。

### STEP1
コマンドプロンプト(windowsの場合)で、jupyter-themesをダウンロード

```
pip install jupyterthemes
```

### STEP2
以下を、コマンドプロンプト(windowsの場合)で実行！（ブラウザ幅95％までセル幅を広げたい場合）

```
jt -cellw 95%
```

jupyter-themesでは、ほかにも

・テーマカラーの変更（かっこいいブラックにしたり）
・文字フォントの変更

など、さまざまな設定ができるので、
Jupyter使いの方は、いろいろとお試しあれ。


こういった、Qiitaの教えていただける環境、すごく有難いですね！！
[Mac]EclipseでTomcatが起動してくれない時の対処法

#サーバーが起動できない...
プログラミングする時にEclipseを使っているのですが、
以下のようなエラーメッセージが出てTomcatを始動出来ませんでした...
「ローカルホスト の Tomcat8 (Java8) で必要な幾つかのポート (8080, 8009) がすでに使用中です。」

もう、プログラミングの練習したいのに設定でつまづきたくない:frowning2:...
という感じで、嫌々調べてやっと解決しました。

自分の備忘録と、皆さんへの共有として残したいと思います。
※使用しているPCはMacです※


# 手順
1.Macのターミナルから「lsof -i:8080」と入力する

2.PIDに記載されている数字を確認する
COMMAND  PID  USER  FD  TYPE  DEVICE SIZE/OFF NODE NAME
　　　  　　****　　　　　
　　　　　ココ！

3.ターミナルに「kill ****(←自身のPID番号)」を入力する

4.再度Eclipseからサーバーを起動する


これで解決するはずです！

このポートが使われてしまっている問題は、
Tomcatを起動した状態で、Eclipseを終了してしまうと起きるそうで、
この手順で、プロセスが終了しポートが解放されることで解決できるようになっています。


それでは、またいつかお会いしましょう:slight_smile:
デバッグについて

最後にデバッグについて。

#React Native側
ステップ実行をする方法が分からなかったので()そもそもあるのか?)console.logでの古式ゆかしいデバッグプリントで行っていました。
実行して、止めて
`react-native log-android`
を何回叩いたことか。
ChromeのDeveloper Toolも見てみましたがHTML側は見られてもJavaScriptの中は追えないようで。

何かいい方法があったら知りたいものです。


#AWS側
AWS側はLambdaの段階とAPI Gatewayの段階と分けられると思います。
Lambdaのテストは引数を渡して結果を見る、という一番スタンダードな方法でずっとやっていましたが、後半にコンソールの「モニタリング」 -> 「CloudWatchのログを表示」を知りまして。格段に作業効率が上がりました。
API Gatewayは基本的に標準のテストツールを頼りにするしかないと思いますが、curl コマンドにも大変お世話になりました。
curlはGETとPOSTの両方に対応しておりまたパラメーターもちゃんと渡せるのでどういう結果/エラーが帰ってきているか一目でわかるところが良いです。

```
curl -X POST -H "Content-Type: application/json" -d '{datetimestr:'2019-02-08-13-25-26'}' https://XXXXX.execute-api.XXXXXXX.amazonaws.com/dev/increment_like
```
という具合に。


デバッグは開発者の生命線ですね。
【新人向け】DBのインデックスについて

#はじめに
お仕事の中で、
「インデックスを張るだけで早くなった！」とか
「どこにインデックス張れば早くなりそう？」
という話を聞いたりしませんか。

正直なところ、何で速くなるかもわからないし、張って速くなるなら
予め張っておけばいいじゃないか、と思っていた時期もありました。
教育の時、説明できるように調べて話をしたら、結構ウケがよかったのでメモです。

この記事では「インデックスとは何か」と「インデックスのメリット・デメリット」を
お話ししていきたいと思います。
そもそもインデックスを知らない方や、知ってるけど具体的にイメージができていない
方の力になれたら幸いです。

#インデックスって？
データベースにはテーブルがあります。
例えば、下記のような形です。

|会員ID |名前 |生年月日 |性別 |
|---|---|---|---|
|1001  |田中 太郎  |1991/6/17  |男 |
|1002  |鈴木 次郎  |1985/4/21  |男 |
|1003  |木村 花子  |1993/5/29  |女 |

こちらのテーブルに[会員ID]にインデックスを張ると、

|会員ID |
|---|
|1001  |
|1002  |
|1003  |

このようなテーブルが裏で用意されます。
ある列に対して、専用のテーブルを作ってくれるのが「インデックス」になります。

#検索方法

テーブルを検索するとき、SELECT句を使うかと思います。
通常のテーブルにSELECT句を用いて検索すると「上から順に」ヒットするものを探しに行きます。
この検索法を**「線形探索」**と言います。

インデックスを張った状態で、[会員ID]をWHERE句に設定して検索すると「いくつかに分けて」検索します。
これを**「二分探索木」**と言います。

### 二分探索木
上から順番に検索する「線形探索」はイメージが付くかと思いますが、「二分探索木」について少し補足です。

例えば会員の数が4000人いた場合、先ほどのテーブルの会員IDは「1001～5000」が登録されていることになります。
そこで「会員IDが"3500"の人を検索したい」という場合「二分探索木」はまず、
「中央の"3000"より多いか、小さいか」を判定します。
この場合は3000より大きいので、上の分類になります。

その次に、もう一度「上の分類の中央の"4000"より大きいか、小さいか」を判定します。
4000よりは小さいので、下の分類になり「3000～4000」という範囲の中で、検索をかけることになります。

この「目的のデータは大体この辺にあるよ、絞ったからその中で探してね」というやり方が「二分探索木」です。
（書籍の目次(インデックス)のような働きをしてくれます。）


#メリット
インデックスの目的は**「検索速度を早くする」**ことです。

検索方法でご紹介した通り、
・専用のコンパクトなテーブルを作り、
・上からではなく、大まかに区分してその中で検索する
という、速度を早くするための仕組み、ロジックが工夫されているのです。

#デメリット
速くなるなら何でもかけておけばいいじゃんと思いますが、実はそうもいかず…
結構あるので、間違った使い方になっていないか照らし合わせていただければ幸いです。

### 容量が圧迫される
インデックス用の別テーブルを用意するので、当然ながら作った分だけ容量を使います。
もともと容量が少ないサーバーで、考えなしにインデックスを張るのは危険です。
余裕があるからと言って、ガンガン張っていくのも注意が必要です。


###DB更新に時間がかかる
こちらも別テーブルを用意する弊害で、インデックスに影響する列（今回の例では会員ID）に
更新が入った場合は、元のテーブルと同時に更新する必要があります。
当然インデックスを張ると、その数だけ更新する必要があるので、検索をかける側の処理が
重くなることが予想されます。


###検索結果が多くなる
あらかじめ目次を頼りに絞り込む、二分探索木という検索方法なので、1万件に対して5000行取得したい
という使われ方がほとんどの場合は、有効に働きません。
上から順に検索する、線形探索の方が早いです。
下手をするとインデックスを張ることによって、遅くなってしまうことも想定されます。


###テーブルに件数がそこまで多くない
そこまで、という表現があいまいではありますが、たった10件しかないようなテーブルでインデックスを
張るのは効果的ではありません。これも線形探索で十分です。
上記の通り、メモリを余分に使用するだけです。


###インデックスのキーに重複項目が多い
「顧客ID」や「名前」等に張るのは効果的ですが、例えば「性別」なんかはどうでしょう。
データが1万件あった、という時に2種類に分けられたところで効率的とは言えません。
これも線形探索で十分です。
一意に絞りやすいキーを設定する必要があります。

#まとめ
くどいですが、インデックスは**「検索速度を速くする」**ことです。
仕組みを理解し、デメリットを踏まえ、正しい使い方をすれば、きっと速くなります。

デメリットを踏まえると、「どこにインデックス張れば速くなるんだ」と依頼が来たら、
よくSELECTで使用されているテーブル、列名を調査すると効率がいいかもしれません。


間違いにお気づき、ご指摘等がございましたら、ご連絡いただけると幸いです。
最後までお付き合いいただき、誠にありがとうございました。
【python】思わぬ落とし穴~関数内で変数に代入されるされない~

# 背景
あれ？:thinking:
なんか、再帰関数の中で**配列**の型だと代入されて**int型**だと代入されずに処理が終わってまう(´・ω・｀)

これってなんでだっけ？、、と思ったのがきっかけ。

# 変数が代入されないとき

個人的な経験上、変数が上手く代入されないときは
1. 関数の内側か外側かのスコープの問題
2. クラスなどで扱ってる中で変数(オブジェクト)が書き換え不可能になってる
3. その他バグ(その処理が行われる前に落ちてるとか)

まぁ今回、ただの再帰関数を1つ書いてて起こった問題なので案の定スコープの問題でした。

# みんなが知ってるスコープの話

- 約束事1. ローカル変数とグローバル変数を同じと思うべからず

```python
>>> def i_to_1():
...   i = 1
... 
>>> i_to_1()
>>> print(i)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'i' is not defined
```

あれ？関数内でiで変数使って代入もしてるのになんで？？
これはもうそういうお約束なのです(´・ω・｀)
(※雑になってすいません)

- 約束事2. グローバル変数はローカル変数に書き変わらないのである

```python
>>> i = 100
>>> i_to_1()
>>> i
100
```

# だけど変数を配列にしてみると？

```python
>>> def ary_to_1():
...   ary[0] = 1
... 
>>> ary_to_1()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in ary_to_1
NameError: name 'ary' is not defined
```

配列で同じことをしようとすると、少し違う挙動をするみたいですね。
そこで、次が自分が最初に不思議に思ってた挙動です。

```python
>>> ary = [100]
>>> 
>>> ary_to_1()
>>> 
>>> ary
[1]
```

あら、変わってるではありませんか！？

# まとめ

配列だとスコープの問題を回避して関数内で代入をできると言うことが分かった。
なんでかって？...(すいませんどなたかご教示ください:sob:)

また、用語の使い方に不備があったりするかも知れないのでご指摘いただけると幸いです(ぺこ
ResponderでModuleNotFoundError: No module named 'starlette.lifespan'が表示されてしまう

## Responder実行時にエラーが出てしまう...
ModuleNotFoundError: No module named 'starlette.lifespan'

```$ pip install starlette==0.8```
をすればエラーが解決されるという記事を見ましたができませんでした。

starletteのバージョンは現在
0.1.0, 0.1.1, 0.1.2, 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7, 0.1.8, 0.1.9, 0.1.10, 0.1.11, 0.1.12, 0.1.13, 0.1.14, 0.1.15, 0.1.16, 0.1.17, 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.3.0, 0.3.1, 0.3.2, 0.3.3, 0.3.4, 0.3.5, 0.3.6, 0.3.7, 0.4.0, 0.4.1, 0.4.2, 0.5.0, 0.5.1, 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.6.0, 0.6.1, 0.6.2, 0.6.3, 0.7.0, 0.7.1, 0.7.2, 0.7.3, 0.7.4, 0.8.0, 0.8.1, 0.8.2, 0.8.3, 0.8.4, 0.8.5, 0.8.6, 0.8.7, 0.8.8, 0.9.0, 0.9.1, 0.9.2, 0.9.3, 0.9.4, 0.9.5, 0.9.6, 0.9.7, 0.9.8, 0.9.9, 0.9.10, 0.9.11, 0.10.0, 0.10.1

試しに0.9バージョンの最新版である0.9.11に設定するとエラーが解決されました。
```$ pip install starlette==0.9.11```
MTG WikiのWisdom GuildへのリンクをWiki内部にするユーザースクリプト

[MTG Wiki]の水色背景で書かれるカード説明。
そのカード名リンクはカード単体へのリンクではなくWisdom Guildへのリンクになっている。
デッキ集などのキーカード紹介では直感的にそのカードのリンクへ飛べなく、DCG(アリーナ)プレイヤーには正直Wisdomは不要なのでリンクを書き換える。

```js
// ==UserScript==
// @name         MtG Wiki wisdom to wiki link
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        http://mtgwiki.com/wiki/*
// @grant        none
// ==/UserScript==

(function() {
  'use strict';
  const URL = 'http://mtgwiki.com/wiki/'
  document.querySelectorAll('a.external[href^="http://whisper.wisdom-guild.net/card/"]').forEach(a => {
    let text = a.textContent
    let names = text.split('/').map(name => {
      return name.trim().replace(' ', '_')
    })
    a.href = URL + names[1] + '/' + names[0]
    //console.log(names)
  })
})();
```

カード名をURLに変換しているので、分割カードなど特殊には未対応


[MTG Wiki]:http://mtgwiki.com/wiki/
WindowsでLinuxのソースを保存してはいけない

Linux Kernelのsource codeには`aux.c` `aux.h`が存在します。
`git clone`してくると一応保存はできるのですが、その後が困ったことになります。
具体的に言うと、**削除すら出来なくなります**。

## どういうこと？
`aux`はMS-DOSにおける予約語の一つです。これはWindows10にも適用され、やはり使うことが出来ません。

具体的な予約語は以下のとおり。

- CON (CONSOLE)
- PRN (PRINTER)
- AUX (AUXILIARY)
- NUL (NULL)
- COM1-9 (COMMUNICATION PORT)
- LPT1-9 (LINE PRINTER: PARALLEL PORT)

これらは拡張子を付けたとしてもダメで、デバイスをファイルに見立てて操作していた名残なんだとか。

## ~~デキちゃったみたい~~ あるんだけど、どうしたらいい？
コマンドプロンプトからは、`\\.\C:\フォルダ名\`のような特殊な書式で指定することで扱えます。`rmdir`なり`del`なりできます。

## まとめ
**Windowsで他OSのkernel sourceを保存してはいけない(戒め)。**
既存のArduinoプロジェクトをCLionで開発する

環境はmacOS 10.13.6, Arduino IDE 1.8.8, CLion 2018.3.4

# TL;DR
Arduino IDEをインストールしておく。
CLionにArduino, Serial Port Monitorプラグインをインストールする。これ↓

* https://plugins.jetbrains.com/plugin/9984-arduino
* https://plugins.jetbrains.com/plugin/8031-serial-port-monitor

Arduinoプロジェクトルートで以下のコマンドで必要なファイルを落としてくる。

```
$ wget -qO - https://github.com/francoiscampbell/arduino-cmake/archive/dbd4fe372b9a0120325b429b3ed23c311ab3dc66.zip | bsdtar -xf- --include '*/cmake' --strip-components 1
```

プロジェクトルートで以下の内容のCMakeLists.txtを作る。 `<project_name>` と `<sketch_file_path>` は自分のプロジェクトに合わせて更新する。

```
cmake_minimum_required(VERSION 2.8.4)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/ArduinoToolchain.cmake)
set(PROJECT_NAME <project_name>)
project(${PROJECT_NAME})

set(${CMAKE_PROJECT_NAME}_SKETCH <sketch_file_path>)
include_directories(~/Documents/Arduino/libraries)

#### Uncomment below additional settings as needed.
# set(${CMAKE_PROJECT_NAME}_BOARD mega)
# set(${CMAKE_PROJECT_NAME}_PORT /dev/ttyACM0)
# set(mega.build.mcu atmega2560)
# set(mega.upload.protocol wiring)
# set(mega.upload.speed 115200)

generate_arduino_firmware(${CMAKE_PROJECT_NAME})
```

CLionのImport ProjectしてOpen Existing Projectを選択する。
終わり。

# 解説
要はArduinoプラグイン入れたCLionでNew Arduino Sketch Projectした時に自動で作られるファイル群を手動で作ってるだけ。新規のプロジェクトだと勝手にやってくれるからわざわざこういうことする必要ない。既存のプロジェクトをimportする機能欲しい。
CMakeList.txtは`include_directories`の行だけいじっていて、Arduino IDEでライブラリをインストールするときのディレクトリを追加してる。
`Serial` とかが名前解決されない場合inoファイルに`#include "Arduino.h"` すれば良い。
まだ静的解析が上手くできた段階でこのエントリ書いててarduinoにアップロードとかまだやってないんだけど、多分 `${CMAKE_PROJECT_NAME}_BOARD` の所は `/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/boards.txt` に書いてあるunoとかmegaの所の文字列だと思う。

このcmake周りは以下のプロジェクトが元になっているので、CMakeLists.txtのArduino周りの設定はこれのREADME読めばいいはず。

* https://github.com/queezythegreat/arduino-cmake

Arduinoプラグインで実際に使われているのは↑のforkのforkのこれ。

* https://github.com/francoiscampbell/arduino-cmake/tree/dbd4fe372b9a0120325b429b3ed23c311ab3dc66

# Trouble Shooting
色々いじってると静的解析がうまくいかなくなったりしたんだけど、cmake-build-debugディレクトリ削除してCLion再起動したりしたら直った。

# 参考

* https://www.instructables.com/id/Setup-JetBrains-Clion-for-Arduino-Development/
* https://github.com/rjuang/CLionArduinoPlugin
DynamoDBのテーブル作成について

本エントリでは作成したアプリからAWSにアップロードしたデータを管理しているDynamoDBについて記述します。
筆者はこれまでRDBしか触ったことがなく、NOSQLについても不勉強から全く無知でした。今回敢えて知らないNOSQLにトライしてみました。
先のエントリでもちょくちょく触れていて改めて記載することはそれほど多くはないのですが、DynamoDBを利用する場合はコンソールからの設定は本当に限られていて、データの追加と参照しかしないのなら何とか。でもアップデートも伴うとなるとその時点でコマンドラインに頼るしかなくなるなと思いました。確かにRDBでもGUIからの設定は限られていて細かい所はDDLでやるしかないというのと同じといえば同じですが。

今回のアプリを作成するにあたってもイイネ機能の実現のためにupdateを行うことが必要でした。ですので、最初はコンソールからテーブルを作っていましたが最終的にコマンドでテーブルを作成するようになりました。
以下が今回テーブルを作る際に使用したコマンドです(確かこれのはずです、曖昧ですいません)。

aws dynamodb create-table --table-name XXXXXXX --attribute-definitions '[{"AttributeName": "datetimestr", "AttributeType": "S"}]' --key-schema '[{"AttributeName": "datetimestr", "KeyType": "HASH"}]' --provisioned-throughput '{"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}'

一番肝要なのは--key-schemaのところで、このKeyTypeを指定するにはコマンドラインしか今は方法が無いようです。そしてこのHASHキーがないと抽出が厄介らしくて。。。DynamoDBの操作については基本的にコマンドで行うと認識して置いた方が良さそうです。

以上で今回行ったDynamoDBへの設定の説明を閉じさせて頂きたいと思います。
ドットインストール　 Ruby on Rails 5入門  #02 動作確認をしてみようでActiveRecord::ConnectionNotEstablishedエラー

[ドットインストール Ruby on Rails 5入門  #02 動作確認をしてみよう](https://dotinstall.com/lessons/basic_rails_v3/41802)
のWebサーバ立ち上げの箇所でエラーが発生しハマったので解決法を覚書として残します。

# 前提条件

以下の講座にてmacの開発環境構築とRuby on railsをインストール済であること
[ローカル開発環境の構築 macOS編 (全14回)](https://dotinstall.com/lessons/basic_localdev_mac_v2)
[Ruby on Rails 5入門 #01 Ruby on Railsを使ってみよう](https://dotinstall.com/lessons/basic_rails_v3/41801)

# 事象

Ruby on Rails 5入門  #02 動作確認をしてみよう
では以下の流れでWebサーバを立ち上げます。

```bash
$ rails new myapp  # myappディレクトリを作成
$ cd myapp # myappディレクトリに移動
$ ip a # IPアドレスの確認
$ rails server -b 192.168.33.10 -d # Webサーバをバックグラウンドで立ち上げ
```

URLに以下IPアドレスを入力、Rails初期画面が出たらOK
http://192.168.33.10:3000

しかしチュートリアル通り進めていくと、Rails初期画面は表示されず以下のエラー画面が出力されます。
![スクリーンショット 2019-02-09 13.37.15.png](https://qiita-image-store.s3.amazonaws.com/0/271038/2f8bc84c-a32e-8ac9-804d-84fe428287ed.png)

※エラー文
<font color="Red">***ActiveRecord::ConnectionNotEstablished
No connection pool with 'primary' found.***</font>

DBへのコネクションプールの接続が出来てないようであるため
rakeコマンドを用いてマイグレーションファイルを実行しDBのbuildを試みます。
すると以下のエラーが表示されました。
GemFileのsqlliteの設定部分に1.3.6以上のversionを指定しなければいけないようです。

```
$ rake db:migrate
rake aborted!
LoadError: Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.3.6), already activated sqlite3-1.4.0. Make sure all dependencies are added to Gemfile.

Caused by:
Gem::LoadError: can't activate sqlite3 (~> 1.3.6), already activated sqlite3-1.4.0. Make sure all dependencies are added to Gemfile.
```

# 解決法

myappディレクトリ直下にあるGemFileを以下のように変更しました。

```
$ vi /home/vagrant/rails_lessons/myapp/Gemfile # Gemfileを編集
```
- 変更前

```bash
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.3.1'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.2'
# Use sqlite3 as the database for Active Record
gem 'sqlite3' 
# Use Puma as the app server
gem 'puma', '~> 3.11'
以下略
```

- 変更後

```bash
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.3.1'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.2'
# Use sqlite3 as the database for Active Record
gem 'sqlite3', '~> 1.3.6' # 変更箇所(バージョンを指定)
# Use Puma as the app server
gem 'puma', '~> 3.11'
以下略
```

変更後、bundleコマンドを使用してsqlliteの再インストールを行います。

```bash
$ bundle install
```

先程立ち上げたRailsのWebサーバを停止させて再度立ち上げ直します。
バックグラウンドで立ち上げているのでプロセスIDを調べてからkillします。

```bash
$ cat tmp/pids/server.pid # プロセスIDの確認
プロセスID[vagrant@localhost myapp]$ 
$ kill -9 プロセスID # Webサーバの停止
$ rails server -b 192.168.33.10 -d # Webサーバの立ち上げ
```

URLに以下IPアドレスを入力
http://192.168.33.10:3000

Railsの初期画面が表示されました!!
![スクリーンショット 2019-02-09 13.14.27.png](https://qiita-image-store.s3.amazonaws.com/0/271038/3c8851fb-c5c7-7820-7df0-eb7c05ab02e6.png)

# あとがき
新人のプログラム初学者からの質問により今回のエラーが発生/解決しました。
今後の新人プログラマーたちに少しでも役立ててもらえれば幸いです。

# 参考URL

[Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on?エラーで困ってます](https://teratail.com/questions/172993)
あっさり味なAPI Gatewayの設定について。

本エントリでは先に作成した三つのLambda関数を公開するためのAPI Gatewayの設定ついて記載します。
API Gatewayの設定については最初かなり色々試行錯誤しましたが実は割とあっさりと済ませようと思えば済ませられるのだと今は感じています。
それは[この投稿](https://qiita.com/hazigin/items/900d196fef0d85570ca8)に書いたように基本的にJSONでやり取りすることにすれば湾パターンな設定でクリアできると思います(逆に言うとそれではこまるケースってそんなに無いかと)。
その設定について記載します。
身も蓋もないですが、以下のようで良いかと。
![Screenshot from 2019-02-09 15-59-54.jpg](https://qiita-image-store.s3.amazonaws.com/0/66198/8dfbc81f-6ee3-76a9-b11e-d4d6aee84b4a.jpeg)
これは統合リクエストのマッピングテンプレートの画面です。
基本的にJSONでやり取りを行うのであれば
Content-Typeは必然的にapplication/jsonになります。次にテンプレートですが自分で作成したり色々試しましたが結局テンプレートにある「メソッドリクエストのパススルー」がシンプルで良いと思います。この設定でLambdaの方でキー名を指定して自在にアプリからの送信内容受け取れましたので。

以上でAPI Gatewayついての篇を閉じます。

…もちろん、本当にアプリを広く公開しようとすればAPI-KEYなどの設定が要りますが、今回のは試作品なので。。。また機会があったらセキュリティをしっかり考慮したケースについても取り組んでみたいです。
Windows利用時に、LaunchyでChromeブックマークURLを開くための２つの方法

## この記事の目的
Windowsでランチャーソフト「Launchy」を使う際に、Google ChromeでブックマークしたURLがそのままでは開けないため、それを開けるように試行錯誤した結果を共有します。

※Launchy以外のランチャーも試してみましたが、MacのAlfredほどドンピシャな解決は得られず…

## 2つの方法
1. URLファイルを作って、それを呼び出す
2. Chromyプラグインを使う

### メリット・デメリット
ざっと整理すると、以下のような感じです。

|方法|メリット|デメリット|
|:---------------------|:-----------------------|:----------------------|
| 1. URLファイルを作って、それを呼び出す    |ブックマークしたファイル名通りに呼び出せる　　|Urlファイルを都度作る必要があり、手間になる　 |
| 2. Chromyプラグインを使う            |ブックマークするだけで、そのまま呼び出せる|ブックマーク名の日本語が文字化けする    |

## 方法1：URLファイルを作って、それを呼び出す
### 作業の流れ
①Chrome拡張機能を入れて、URLファイルを保存
②URLファイルのセキュリティのブロックを解除
③Launchyのカタログで指定している読み込みフォルダにURLファイルを格納

#### ①Chrome拡張機能を入れて、URLファイルを保存
最初に以下のchrome拡張機能を入れましょう。
これにより、URLファイル作成が楽になります。
　**Save as Shortcut**
　https://chrome.google.com/webstore/detail/save-as-shortcut/flehofiklehmnnolpjcamplcnmhgcbkk

インストール後、保存したいページを開いて、拡張機能を実行します。
※使い方はシンプルなので、上記リンク参考

#### ②URLファイルのセキュリティのブロックを解除
さて、保存したURLファイルをそのまま開きたいところですが、インターネットからダウンロードしたファイルという扱いのため、開く際にセキュリティの警告が出てしまいます。

防ぐには、2つのやり方があります。
**ファイルが1つもしくは少量の場合**は、URLファイルを右クリック→プロパティ→全般タブを開いて、セキュリティのブロック解除の「許可する」にチェックを入れましょう。
（下図はWindows10の場合、Windows7ならブロックの解除というボタンになると思います）
![N_Launchy_03.jpg](https://qiita-image-store.s3.amazonaws.com/0/237274/edaf85a1-c02e-e892-ce5d-e43b1271c452.jpeg)

**ファイルが大量の場合**は、対象ファイルをすべてまとめて圧縮→解凍すると、ブロックが解除された状態になります。
こちらの [複数ファイルの「ブロックの解除」を一括で行う方法](https://qiita.com/seki-moto/items/33c9f069cb846a574726) の記事が参考になります。

#### ③Launchyのカタログで指定している読み込みフォルダにURLファイルを格納
あとはLaunchyの指定フォルダに、*.urlの拡張子を読み込み対象にした上で、URLファイルを格納すれば完了です。
小技ですが、よく利用するブックマークなら、ファイル名にアルファベットでキーワードを入れておくと、検索時に呼び出しやすくなります。

## 方法2：Chromyプラグインを使う
### Chromyプラグインについて
ヘッドレスchromeのライブラリとは別物です。
Beanalby氏が作成したchromeのブックマークを呼び出せるようにするためのLaunchy用プラグインで、見つけたときは、まさに「これだ！」と思ったのですが、ブックマーク名の日本語ページが文字化けするところが残念でなりません…

### 作業の流れ
①chromyプラグインをダウンロード
②プラグインファイルをLaunchyのpluginsフォルダにコピー
③Launchyを再起動

#### ①chromyプラグインをダウンロード
http://beanalby.net/projects/chromy/
画面中部の"Download Chromy"からすぐダウンロードできます。

#### ②プラグインファイルをLaunchyのpluginsフォルダにコピー
zipファイルを解凍すると、chromy.dllとアイコン画像が入っているので、Launchy.exeと同じフォルダにあるpluginsフォルダにコピーしましょう（アイコンはplugins > iconフォルダ）

#### ③Launchyを再起動
再起動後、Launchyのプラグインタブの中に、Chromyが追加されているので、利用可能になります。
ちなみに文字化けすると、こんな感じになります。
ブックマークの仕方を工夫すれば、使えないことはないです。
![N_Launchy_04.jpg](https://qiita-image-store.s3.amazonaws.com/0/237274/6c15e6cd-09ed-a431-7dbe-9a815541bb68.jpeg)

## まとめ
私は日本語のページも開くため、方法1を採用しましたが、普段英語のページメインでブラウジングする方は、方法2だけでも十分なソリューションになるかもしれません。
今回調べて、開発中のも含め、ランチャーソフトも色々と新しいのが出ていると分かったので、便利なものが出たら、いずれLaunchyから乗り換えるのもありかなあ。
findコマンドの-nameオプションと-pathオプションの違い

# はじめに

Linux環境においてfindコマンドはよく使われるコマンドの一つですが、"-name"オプションと"-path"オプションというよく似たオプションがあります。
普段は"-name"オプションばかり使っているので、今回は両者の違いを調べてみました。

# -nameオプション

`find {検索するディレクトリ} -name {検索するキーワード}`

* "-name"オプションを付けることで、ファイル名、ディレクトリ名を指定して検索できます。
 * 検索するキーワードに"*"を付けることで、ワイルドカードを使った検索が可能です。
* ただし、**"-name"オプションの引数にスラッシュを含む場合は検索できない**ため、例えば"-name {ディレクトリ名}/{ファイル名}"とパラメーターを指定することができません。

```
[root@kumotori ~]# find /etc -name "ifcfg*"
/etc/sysconfig/network-scripts/ifcfg-eth0
/etc/sysconfig/network-scripts/ifcfg-lo
```
```
[root@kumotori /]# find / -name "/etc/sysconfig/network-scripts/*eth*"
find: warning: Unix filenames usually don't contain slashes (though pathnames do).  That means that '-name `/etc/sysconfig/network-scripts/*eth*'' will probably evaluate to false all the time on this system.  You might find the '-wholename' test more useful, or perhaps '-samefile'.  Alternatively, if you are using GNU grep, you could use 'find ... -print0 | grep -FzZ `/etc/sysconfig/network-scripts/*eth*''.
```

# -pathオプション

`find {検索するディレクトリ} -path "{パターン}"`

* "-path"オプションを付けると、パターンにマッチするファイルやディレクトリを検索できます。
 * 検索するパターンに"*"を付けることで、ワイルドカードを使った検索が可能です。
* **"-path"オプションにはスラッシュを含むパターンを指定できる**ので、ディレクトリもパターンに含めて検索できます。

```
[root@kumotori /]# find /etc/sysconfig/ -path "*network-scripts/*eth*"
/etc/sysconfig/network-scripts/ifup-eth
/etc/sysconfig/network-scripts/ifcfg-eth0
/etc/sysconfig/network-scripts/ifdown-eth

```

# まとめ

* どちらのオプションも「ほぼ同等の機能」になるので、通常の操作ではどちらかを覚えておけば十分だと思われます。
* "-path"オプションの方が検索条件の柔軟性が高いようですが、これまでの癖で"-name"オプションを使い続けそうです。
【Git for Windows】Gitをアップデートする

#Gitをアップデートする
以下のコマンドでGitをアップデートできます。

```bat
git update-git-for-windows
```

コマンドを実行すると最新バージョンのGitがダウンロードされ、インストーラが立ち上がります。
インストーラに沿ってインストールを進めましょう!

# 参考
- [[git]git for windowsのバージョンアップ](https://sevenb.jp/wordpress/ura/2018/08/14/gitgit-for-windowsのバージョンアップ)
direx でパスをコピー

[direx](https://github.com/m2ym/direx-el) は便利ですけどパスをコピーする機能がないようです。でちょっとフラストレーションが溜まってきたので適当にでっち上げてみました。

<kbd>M-w</kbd> でカーソルがある位置のファイルパスを kill-ring に入れます。<kbd>C-j</kbd> で direx を開く直前のバッファにファイルパスを insert します。

```el:init.el
(with-eval-after-load 'direx
  (defun my-direx-fullpath-at-current-point ()
    "returns a fullpath of current point in direx-mode."
    (direx:file-full-name (direx:item-tree (direx:item-at-point))))
  (defun my-direx-kill-ring-save-current-path ()
    (interactive)
    (kill-new (my-direx-fullpath-at-current-point)))
  (defun my-direx-insert-current-path ()
    (interactive)
    (let ((path (my-direx-fullpath-at-current-point)))
      (quit-window)
      (insert path)))
  (define-key direx:direx-mode-map (kbd "M-w") #'my-direx-kill-ring-save-current-path)
  (define-key direx:direx-mode-map (kbd "C-j") #'my-direx-insert-current-path))
```

私のユースケースは必要な時に direx を表示させて必要なくなったらさっと消してしまうので <kbd>C-j</kbd> は direx のウィンドウを消しています。が、常時 direx バッファを表示している人にはこれだと困るかもしれませんね。消えたら困る人は挿入先のバッファを得てそっちに insert するコードを書く必要があるでしょう。

ところで direx は GitHub でアーカイブになってしまいました。ディスコンってことでしょうかね…。
PowerShellで行列計算

[PowerShell for MathNet.Numerics](https://cyber-defense.sans.org/blog/2015/06/27/powershell-for-math-net-numerics/)でPowerShellから.NET用の数値計算ライブラリを呼び出せることを知り，Python, Fortran, F#とパフォーマンスを比較してみることにした。

コードは[numerics_test](https://github.com/tenomoto/numerics_test)に置いた。
 
## マシン

Pythonや.NETはクロスプラットフォームだし，Fortranもコンパイルし直すだけだが，今回はWindowsで。

* Intel Core i5-6500 @ 3.2 GHz 16GB RAM（自作）
* Windows 10 1803

## Python

* Official Python 3.7.1 + pipでインストールしたnumpy。`numpy.show_config()`によるとOpenBLASとリンクされている。
* MKLはcondaに作ったIntel Pythonの仮想環境。Python 3.6.5, Numpy 1.15.4, MKL 2019.2
* Pythonのみtimeitモジュールで計測

* [インテル® Distribution for Python* と Anaconda* を使用する](https://www.isus.jp/products/python-distribution/using-intel-distribution-for-python-with-anaconda/)

## Fortran

* PGI Community Editon 1810
* [Intel Math Kernel Library 2019](https://software.intel.com/en-us/mkl) update 2

MKLはネットワークインストーラを使用。インストール時に64ビット版のみ，pgiサポートありにカスタマイズ。

```
pgfortran -mp -Minfo -fast svd -lblas -llapack -o svd
pgfortran -mp -Minfo -fast -o svd_mkl svd.f90 -L"$MKLPATH" mkl_intel_lp64.lib mkl_pgi_thread.lib mkl_core.lib
```

## F#

* Visual Studio 2017でインストール。
* .NET Core 2.2 Windows

### プロジェクトの作成

プロジェクトを作成し，必要なパッケージを追加する。
パッケージは`%USERPROFILE%\.nuget\packages`にインストールされる。

```
> dotnet new console -lang F# -o fsharp
> cd fsharp
> dotnet add package MathNet.Numerics
> dotnet add package MathNet.Numerics.MKL.Win-x64
```

### コンパイル

`dotnet run`では遅かったので，`publish`で`exe`を作成。

```
> dotnet publish -c Release -r win-x64
```

### 結果
|                | mutmul |  eig  |  svd  |  inv  | det |
|:---------------|-------:|------:|------:|------:|-----|
| PowerShell     |   3369 | 15602 | 11685 | 10723 | 627 |
| PowerShell MKL |    474 |   825 |   486 |    81 |  59 |
| Python         |   2167 | 12884 |  6609 |   593 | 324 |
| Python MKL     |   2146 |  7168 |  2814 |   544 | 254 |
| Fortran        |   1840 |  1468 |   718 |   309 | 126 |
| Fortran MKL    |    539 |   950 |   583 |   225 |  76 |
| F#             |   3259 | 14538 | 10810 | 10961 | 616 |
| F# MKL         |    582 |   960 |   580 |   172 | 142 |

* 10回ずつしか試しておらず，Windowsは他のプロセスも多数動いている点は考慮する必要がある。
* なぜかPowerShell MKLが一番速い。
* OpenBLASのOfficial Pythonはmutmulでは善戦（つまりBLASは速いがLAPACKが遅い。）
* Official BLAS/LAPCKを使っていると思われるPowerShellとF#はとても遅い。
* MKLを使えばF#やPowerShellでもネイティブな速度が出る。.NETのオーバーヘッドは感じられない。
* F#はコードが短くて楽。
* fsi/fsharpiはdllをロードするのが手間（なのでここでは使ってない）。
Vue CLIでVue.jsプロジェクトをライブラリにビルドする

[Vue CLI 3](https://cli.vuejs.org/)の`vue-cli-service build`に[targetオプション](https://cli.vuejs.org/guide/build-targets.html)（ビルドターゲット）を指定することで、Vueプロジェクトをライブラリ形式にビルドできる。指定できるtargetオプションは以下の通り。

- App
  - コマンド：`vue-cli-service build (--target app)`
  - デフォルトのビルドターゲット
  - 依存ライブラリをリンクしたindex.htmlが生成される。
  - publicディレクトリの静的コンテンツもコピーされる。

- Library

  - コマンド：`vue-cli-service build --target lib [name] [entry]`
  - `[entry]`に指定したVueコンポーネントもしくはjsファイルをエントリーポイントとして、CommonJSとUMD形式で出力される。
  - Vueはバンドルされず、静的コンテンツもコピーされない。
  - 使用例

    ```html
    <script src="https://.../vue.js"></script>
    <script src="https://.../myLib.js"></script>
    <link rel="stylesheet" href="./myLib.css">
    
    <div id="app">
      <my-lib></my-lib>
    </div>
    
    <script>
    new Vue({
      components: {
        'my-lib': myLib
      }
    }).$mount('#app')
    </script>
    ```

  - IEをサポートするには、[current-script-polyfill](https://www.npmjs.com/package/current-script-polyfill)を読み込む必要がある。

- Web Component

  - コマンド：`vue-cli-service build --target wc [name] [entry]`
  - `[entry]`に指定したVueコンポーネントをエントリーポイントとして、[Web Component](https://developer.mozilla.org/ja/docs/Web/Web_Components)として出力される。
  - Vueはバンドルされず、静的コンテンツもコピーされない。
  - 使用例

    ```html
    <script src="https://.../vue.js"></script>
    <script src="https://.../my-wc.js"></script>
    
    <my-wc></my-wc>
    ```

  - IE 11以下はサポートされない。

#### おまけ：package.jsonへのビルドコマンド追加

Vue CLIで作成したプロジェクトであればpackage.jsonにビルドコマンドが記載されているため、ライブラリ用のビルドコマンドもそこに追加してしまうのがよい。

package.json記述例

```json
{
  "scripts": {
    "build:lib": "vue-cli-service build --target lib myLib",
```
タロットカードを引くSlack botを審査を通すまでにやったこと


# はじめに

少し前に、Slack botを作りました。

- [Serverless Frameworkでタロットカードを引くSlack botを作った - Qiita](https://qiita.com/ikemo/items/d2b4eccd3a33ed29cfef)

このときはまだSlackの審査が終わってない、いわゆる「野良アプリ」状態でした。今回、Slackの審査を行って無事に公開されたため、その流れを書きます。

# 公開までの流れ

以下のように、公開までに2回リジェクトされました。
最初に審査を出してからOKが出るまで10日かかりました。
ただ、そんなに難しくなかった感じです。

前準備
　↓
アプリの申請(1回目)
　↓
リジェクト(1回目)
　↓
アプリの修正(1回目)
　↓
アプリの申請(2回目)
　↓
リジェクト(2回目)
　↓
アプリの修正(2回目)
　↓
審査OK
　↓
公開

# やったこと

アプリを公開するために、以下の作業を行いました。

- プライバシーポリシーページを作る(英語)
- 概要を書く
- DMに対応
- ヘルプ機能対応

## プライバシーポリシーを作る(英語)

Google検索をすると、「プライバシーポリシージェネレータ」というものがいくつか見つかります。最初はこれを使う予定でした。

しかし今回作ったbotはシンプルなもので、保持している情報はトークンおよび、アプリが取ってるリプライのログだけです。なのでプライバシーポリシーもシンプルなもので十分だと考えました。

そこでまず、他のシンプルなbotのプライバシーポリシーを調べてみました。

例えばCatFactsというbotのプライバシーポリシーはとても簡素にできています。
書かれているのは「メッセージのために認証トークンのみ保持しているよ」というたった1文です。

- [CatFacts Privacy Policy](http://jazzychad.net/catfacts_privacy.html)

シンプルな例を見つけたので、プライバシーポリシーは自作したほうがいいと確信し、Google翻訳を使って自作しました。

- [tarot3 for Slack Privacy Policy | たろっとさん](https://tarot.ikemo3.com/apps/slack-privacy/)

## 1回目の申請

プライバシーポリシーを記載して、とりあえず1回目の申請を行いました。
1回目は「概要が不十分」と言われてリジェクトされました。

## 概要をきちんと書く

最初は「タロット引くだけのbotに書くことなんてないよ」と思い、雑に文字稼ぎをして埋めてたのですが、それだとダメだと言われました。以下の2点をきちんと書く必要があります。

- このアプリができること
- 使い方

概要は日本語で書いて問題ありません。

# 2回目の申請

概要を修正したあと、2回目の申請を行いました。
2回目は「ダイレクトメッセージに対応していない」「ヘルプ機能がない」と言われてリジェクトされました。

## ダイレクトメッセージ(DM)に対応

DMに対応するにはイベント[message.im][]をSubscribeする必要があります。

ただし来たメッセージにそのままリプライすると無限にリプライし続けてしまうため、botかどうかの判定を入れました。具体的には、イベントに含まれる `subtypes` の値が `bot_message` の場合に無視しています。

- [Message subtypes](https://api.slack.com/events/message#message_subtypes)

```json
{
  "type": "message",
  "subtype": "bot_message",
  "text": "...",
  "ts": "...",
  "user": "..."
}
```

# ヘルプ機能対応

ヘルプ機能に対応するには、テキストに応じて処理を変える必要があります。たろっとさんでは、以下の2パターンの文字列が来たときにヘルプ表示を行っています。

- テキストが `help` のみの場合(DM)
- `/^<@[\w]+> help$/` にマッチする場合(リプライ)

# 3回目の申請

3回目の申請後、レビューが完了したというメールが来ました。

以下のように書かれているので、アプリのページに移動して、"Publish App"を押すことで、アプリが公開されました。

> There’s just one last step: when you’re ready to publish your app to the App Directory, head over to your app configuration and hit “Publish App”

<img width="981" alt="6019efe14a0419a9ad9c5f5a4687fe16.png" src="https://qiita-image-store.s3.amazonaws.com/0/45169/864592de-3a6a-16c6-bbbe-6f0f2f1ce8be.png">

# おわりに

作ったけど誰も使ってくれてません(ﾉ∀`)
やっぱりTwitter Botの方が需要ありますかね・・・

[message.im]: https://api.slack.com/events/message.im
Google Chrome検索結果画像をコマンド使わず一括でダウンロードした話

タイトルの通り。忘備録。
機械学習の学習素材に使いたい大量の画像を準備するのに苦労したので。

Google Chrome拡張アプリと、Finderの名前変更機能を使います。
かっこよくpytyon書いたりとか、スクレイピングとか、一切やりません。

# 環境
macOS Mojave 10.14

# 手順
## 拡張をインストールする
こちらのChrome拡張を使います。
[Chrome拡張: Image Downloader インストールページリンク](https://chrome.google.com/webstore/detail/image-downloader/cnpniohnfphhjihaiiggeabnkjhpaldj)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/0b4df6b0-c1f9-2697-4e47-40c8e09a880d.png)


## ほしい写真を検索する
今回はサンプルとして橋本環奈さんの写真を集めてみます。
機械学習にイラストなどは不要なので、検索ツールで「顔」などと絞り込むといいと思います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/f3e16ebd-69ff-960d-43c8-e0544c215908.png)

## 写真リンク元URLの共通文字列を調べる

ページソースを検証します。
※検証は、`cmd`+`alt`+`i`で表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/303f10bf-8b5f-f4b7-d904-a3fe80165120.png)

写真リンク元のURLがなんとなくわかります。
`encrypted-tbn0.gstatic.com`って文字列かとあたりをつけます

## 一括ダウンロードの拡張を使ってダウンロード
ブラウザ右上のさきほどインストールした拡張アプリのアイコンをクリックします。

そして検証にてみつけた文字列を上から2番目のテキストボックスにいれてやります。

するとブラウザにあった余計な写真ははじかれ、無事に検索結果の橋本環奈さんだけが表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/01d49d8f-14da-6a69-01fa-bdff6b64d51f.png)

あとは`Select all`にチェックをつけてダウンロードします。

初回ダウンロード時は、英語で、「Google Chromeのデフォルトダウンロード先を指定してないと、画像の枚数分、保存先を指定するようなポップアップが出るけど大丈夫？」って警告がでるはずです。

確認のうえ、問題なければYESを押下でダウンロードが始まります。

## ダウンロードされた画像たちを作業ディレクトリに移動させる

200枚程度なら1分もかからずにダウンロードが完了するでしょう。
完了したら、ダウンロード先を確認しにいきましょう。

きっとこんな感じです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/7305bc28-b50c-9e24-9a1d-883195970442.png)

もしくはこう
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/1f34c515-8752-95bd-d5ed-a72c1d84e576.png)

101枚目以降の画像が`.com.google...`というへんてこな名前です。
まずへんてこな名前のファイルも含め、ダウンロードした画像たちを別の作業フォルダにコピーしましょう。

### `.(ドット)`から始まるファイルが表示されない方
Finderの設定を変更しましょう。
「すべてのファイル名拡張子を表示」にチェックをつけます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/99321dda-dc1c-07dd-5948-1b443593c4e6.png)


## 名前を変更する

拡張子も含めて変更します。
Finder環境設定で、「拡張子を変更する前に警告を表示」のチェックを外しておきましょう。

2段階にわけて名前を変更します。
変更は、変な名前のすべてのファイルを選択した状態で副クリックし、
`N項目の名前を変更...`を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/aea0cdce-cb91-7932-962f-8cdfd1bd2b07.png)


### 第1段階 `.(ドット)`を`-(ハイフン)`に置換する

`テキストを置き換える`を選んだ状態で、
検索文字列に`.`、置換文字列に`-`を入力し、`名前の変更`をします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/1d250629-a851-0460-6c58-5c5a357bd33c.png)

### 第2段階 拡張子`.jpeg`を指定する

`テキストを追加`を選んだ状態で、`.jpeg`を入力し、`名前の変更`をします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/e440dd53-2b70-baec-e673-b1593fc6f1c6.png)

一応ここまでで、画像としては問題ない状態になりました。

### ファイル名をフォーマットする
あとは名前に統一感をもたせたければ、全選択して、以下のようにすればフォーマットできます
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/ec7b2d7a-cbbe-efa0-d383-e00125bd6805.png)

## 完成
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/e64f5eb3-7ad4-7e20-bf80-e013e59ed693.png)

# あとがき
今回の検索テーマは、この記事を書くためだけのサンプルです。
へんなことには使用しませんのでご安心を！！

皆様、よいDeep Learning lifeを！
【初心者】Chainer でオプション価格とGreeks計算（3月限C21000)@ブラウザ

[Chainerで微分方程式を解き、オプションのGreeksを求めている記事](https://qiita.com/keisuke-umezawa/items/10e3c8b3092bc8280e49) を参考に、実際の市場データを入れてブラウザ上で試してみました。

[ブラウザ上で試したノート（colab）](https://colab.research.google.com/gist/zaq9/400ea12de17973aec73c7e5481c7f33e/bs_chainer.ipynb)

##利用した実際の市場データ
　⇒03/C21000@100 (2月9日先物価格20290)

##出力結果：
C21000 = 99.65
delta = 0.21

##コメント：
結果は（当然ながら）ほぼ一致。
ブラウザ開いて5分で試せるGoogle　Colab は素晴らしい。

##ソースコード

```python

import numpy as np
import chainer
from chainer import Variable
import chainer.functions as F

stock_price = 20290.0
strike = 21000.0
years = 1.0/12
risk_free_rate = 0.01
volatility = 0.143
n_paths = 100000
n_steps = 100

times = np.linspace(0, years, n_steps, dtype=np.float64)

r = risk_free_rate
v = volatility
k = strike
T = years
initial_stocks = Variable(stock_price * np.ones((n_paths,), dtype=np.float64))
currents = initial_stocks
for c, n in zip(times[:-1], times[1:]):
  dt = n - c
  zs = np.random.normal(0.0, 1.0, currents.shape)
  currents = currents * F.broadcast(np.exp((r - 0.5 * v * v) * dt + v * dt ** 0.5 * zs))

#call_price = F.average(exp(-r * T) * F.softplus(currents - k, beta=10)) # you should smooth the relu to calculate gamma
call_price = F.average(np.exp(-r * T) * F.relu(currents - k))  
deltas = F.sum(chainer.grad([call_price], [initial_stocks], enable_double_backprop=True)[0])

print(f'C21000 = {call_price.data:.2f}')
print(f'delta = {deltas.data:.2f}')

```
便利なconsole.xxx

JavaScriptにはconsole.log()以外にも便利なlog出力があります。
最近知ったconsole.xxxを紹介します。

# console.log()
誰もが叩くconsole.log()。devtoolsのコンソールに引数の出力結果が表示されます。

| console.log()    |
|:-----------------|
| <img width="434" alt="スクリーンショット 2019-02-09 13.14.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/114396/9a41d27a-259f-49eb-4715-86062124a720.png"> |

# console.error(), console.warn(), console.info()
表示はconsole.logと同じ。でも文字色、背景色が代わり、目立たせる事ができます。
（infoがlogと変わらないのはなぜだろう？）

| console.info()    |
|:-----------------|
| <img width="435" alt="スクリーンショット 2019-02-09 13.08.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/114396/87749715-73cc-870b-8286-a8bae6f39c4c.png"> |

| console.warn()    |
|:-----------------|
| <img width="439" alt="スクリーンショット 2019-02-09 13.09.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/114396/b3706ad7-814b-ed8f-631d-326bd5f31e5b.png"> |

| console.error()    |
|:-----------------|
|<img width="434" alt="スクリーンショット 2019-02-09 13.08.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/114396/ff10b298-5d77-a79a-e495-aa799b3cf423.png"> |


# console.table()
配列、オブジェクトのデータを表形式で表示します。
console.logで、いちいち展開するより超見やすいです。
最近無駄にconsole.table使ってます。

| console.log()   |console.table() |
|:-----------------|:------------------|
| ![log.gif](https://qiita-image-store.s3.amazonaws.com/0/114396/9efd1ca0-2c30-2818-58a9-a52805837fe5.gif)| ![table.gif](https://qiita-image-store.s3.amazonaws.com/0/114396/334ebd79-6bfa-d75f-ec8a-634a5e1a624d.gif)
|

# console.dir()
ディレクトリ形式で出力結果のメンバを表示できます。arrayやobjectなどの場合はconsole.logとあまり変わらないですが、DOMツリーなどを表示するときなど表示が異なります。

| console.log()       |console.dir() |
|:-----------------|:------------------|
| ![Feb-09-2019 12-41-44.gif](https://qiita-image-store.s3.amazonaws.com/0/114396/a8da9634-8fcc-da89-f101-470498a8c3fb.gif)          |![Feb-09-2019 12-40-15.gif](https://qiita-image-store.s3.amazonaws.com/0/114396/eb3cf9bc-3d45-7d38-48f6-eca63f763d25.gif)|

# console.time(),  console.timeLog()
処理時間を計測するのに便利です。
console.time("タイマー名")でタイマーを設定して、
console.timeLog("タイマー名")でそのタイマーを設定しからの経過時間を出力できます。

```js
let timeDemo = () => {
    // タイマー"demo"のセット
    console.time("demo")
    setInterval(()=>{
      // 1000msごとに今のタイマー"demo"の経過時間を表示
      console.timeLog("demo")
    }, 1000)}
```

実行結果

| console.time(), console.timeLog()|
|:-----------------|
| ![timer.gif](https://qiita-image-store.s3.amazonaws.com/0/114396/a45dfe44-6101-59e0-84b6-1a7a9686d518.gif) |



# console.trace()
console.trace()が呼び出されるまでの経路を出力することができます。
この関数はどこでどのように呼び出されるのか調べる時など便利です。

```js
function trace() {
    console.trace()
}

function c() {
    trace()
}

function b() {
    c()
}

function a() {
    b()
}
```

実行結果

| console.trace()|
|:-----------------|
| ![Feb-09-2019 14-37-00.gif](https://qiita-image-store.s3.amazonaws.com/0/114396/69c34946-0e5a-9e8b-bce7-05f4eccde179.gif) |

# 参考
* MDN  
https://developer.mozilla.org/ja/docs/Web/API/console/timeLog
* JavaScript コードレシピ集  
https://gihyo.jp/book/2019/978-4-297-10368-2
* Qiitaやブログのタイトルは自分で考える必要なんてなかったんだ  
https://qiita.com/YumaInaura/items/0d8427bfe2d7be476d0d
PHPでセッションの長さを変更する

セッションの長さを確認する機会があったけど、どういう仕組みで削除されるのかもわかっていなかったのでまとめました。
PHPでのセッションの使い方については[基本的な使用法](http://php.net/manual/ja/session.examples.basic.php)に記載されています。

## PHPのセッションの保持期間
調べるとデフォルトでは下記のようです。
このデフォルト値がphp.iniに定義されており、こちらを変更することでセッションの保持期間を変更できます。
> デフォルトでは、1/100の確率で、24分より古いセッションファイルが消えます。

24分よりも古くなったら自動的に削除される訳ではなく、1/100の確率でGC(ガーベッジコレクション)が動き削除を行うようです。
また、この24分の間に再度リクエストがあった場合には、有効期限は更新されます。

参考
[セッションの有効期間とか設定とか挙動とかを調べました](http://pentan.info/php/session_gc.html)

## デフォルト値の確認
念の為デフォルト値になっているかの確認を行います。php.iniの場所に関しては下記のコマンドでわかるはず。

```bash
$ php --ini | grep php.ini
Configuration File (php.ini) Path: /etc
Loaded Configuration File:         /etc/php.ini
```

確認すべき項目は4つです。

### [session.gc_maxlifetime](http://jp2.php.net/manual/ja/session.configuration.php#ini.session.gc-maxlifetime)
サーバに保存されているセッションファイルの保存期間です。

> session.gc_maxlifetime は、データが 'ごみ' とみなされ、消去されるまでの秒数を指定します。 ガベージコレクション (ごみの収集) は、 セッションの開始時に行われます

```bash
$ grep "session.gc_maxlifetime" /etc/php.ini
session.gc_maxlifetime = 1440
;       setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes):
```

### [session.cookie_lifetime](http://jp2.php.net/manual/ja/session.configuration.php#ini.session.cookie-lifetime)
ブラウザのクッキーの有効期間です。先ほどの `session.gc_maxlifetime` のみ変更をしても、デフォルトだとブラウザを閉じたらセッションが破棄されます。

> session.cookie_lifetime は、 ブラウザに送信するクッキーの有効期間を秒単位で指定します。 0 を指定すると "ブラウザを閉じるまで" という意味になります。 デフォルトは、0 です。

```bash
$ grep "session.cookie_lifetime" /etc/php.ini
session.cookie_lifetime = 0
```

### [session.gc_probability](http://jp2.php.net/manual/ja/session.configuration.php#ini.session.gc_probability)
「1/100」の1の部分ですね。基本的にこちらは変更しなくて良いでしょう。
> session.gc_probabilityと session.gc_divisorの組み合わせでgc （ガーベッジコレクション）ルーチンの始動を制御します。 デフォルトは、1 です。

```bash
$ grep "session.gc_probability" /etc/php.ini
; gc_probability/gc_divisor. Where session.gc_probability is the numerator
session.gc_probability = 1
; gc_probability/gc_divisor. Where session.gc_probability is the numerator and
```

### [session.gc_divisor](http://jp2.php.net/manual/ja/session.configuration.php#ini.session.gc-divisor)
「1/100」の100の部分ですね。こちら確認をしたら調べた環境では1000になってました。そのため、各リクエスト毎に0.1%の確率でGCプロセスが始動する状態です。

> session.gc_divisorと session.gc_probabilityの組み合わせで すべてのセッションの初期化過程でgc（ガーベッジコネクション）プロセス も始動する確率を制御します。確率は gc_probability/gc_divisor で計算されます。例えば、1/100は各リクエスト毎に1%の確率でGCプロセスが 始動します。 session.gc_divisorのデフォルトは100です。

```bash
$ grep "session.gc_divisor" /etc/php.ini
; session.gc_divisor
; when the session.gc_divisor value is 100 will give you approximately a 1% chance
; session.gc_divisor is the denominator in the equation. Setting this value to 1
; when the session.gc_divisor value is 100 will give you approximately a 1% chance
session.gc_divisor = 1000
```

## 変更を行う
検証でひとまず3日ぐらいセッションが保存されるように変更をしてみます。(日数は適当です)
クッキーの有効期限とセッションファイルの保存期間
ansibleなどを使用している場合には直接変更しちゃダメですが、そうでない人はひとまずバックアップとしてコピーしておきましょう。

```bash
$ sudo cp -pi /etc/php.ini /etc/php.ini.20190117
$ sudo vim /etc/php.ini
$ diff /etc/php.ini /etc/php.ini.20190117
1385c1385
< session.cookie_lifetime = 259200
---
> session.cookie_lifetime = 0
1432c1432
< session.gc_maxlifetime = 259200
---
> session.gc_maxlifetime = 1440
$ sudo service httpd graceful
```
ARecX6をDebianにする

ワンセグ録画サーバのARecX6をDebianにしてみました。

いろいろ調べていて気がついたのですがARecX6はOpenRD-Baseと言われるハードウエアーと酷似しているようです。

OpenRDで調べたところDebianのインストールの手順はここのページに全て書いてありました。

https://www.cyrius.com/debian/kirkwood/openrd/

USBのハードディスクにインストールしてみました。

最初インストールしたときには何故かuInitrdやuImageがCRCエラーでu-bootから起動できなかったのですが、もう一度インストールしたら問題なく起動できました。最初のインストールの時はタイムゾーンを日本にしたのですが、二度目は全てデフォルトのままでインストールしたので、これが関係していたのかもしれません。

u-bootは上記のページのバイナリを下記のページを参考にOpenOCDで焼きました。

https://web.archive.org/web/20150307014407/https://mizupc8.bio.mie-u.ac.jp/pukiwiki/index.php?OpenRD/U-Boot

u-bootを焼くと元の機能はなくなりますので注意してください。

Debianのインストールが終わって起動したら、とりあえずmrubyがビルドできるようにパッケージを入れてみました。

```
apt-get install build-essential ruby bison git
```

mrubyのコンパイルは結構時間がかかりましたが、fib(32)は9秒でした。FreeBSDの25倍遅いので、~~なんとかしなくてはなりません。~~ あきらめました。

Debianでいいじゃねーのと言われそうですが、やっぱりBSDが好きなんですね。

と思ったのですが、結構ハードル高そうなので、Debianで本来の機能を取り戻せるようにやってみるのが良い気がしてきました。

ARecX6にはSiano Mobile Siliconの地デジ受信USBモジュールが6つ入っています。

```
Bus 001 Device 008: ID 187f:0202 Siano Mobile Silicon Nice
```

DebianにはこのUSBモジュールのドライバが最初から入っていました。しかし/lib/firmware/にファームが入っていないので、初期化に失敗します。

```
[   18.822930] usb 1-1.1.1: firmware: failed to load dvb_nova_12mhz_b0.inp (-2)
```
Nice(0x0202)のfirmwareはNova B(0x0201)と共通でdvb_nova_12mhz_b0.inpの様です。

日本の放送はISDBT方式なので、isdbt_nova_12mhz_b0.inpがロードされるように設定が必要だと思うのですが、よく分かりません。

コードは

/drivers/media/common/siano
/drivers/media/usb/siano

にあるようです。
Chrome でコマンドを押しながらクリックでタブが開けなくなったのを解消した方法

## 状況
Karavinerアップデートを境にChromeでリンクをcommandを押しながらクリックしてタブで開けなくなった。

## 直し方
1. 問題の設定を削除するため `Add roule` ボタンをクリック
![スクリーンショット 2019-02-09 14.23.29.png](https://qiita-image-store.s3.amazonaws.com/0/357158/a6bd982b-6a7c-9c34-80a3-739bb74f4b69.png)
2. `For Japanese` の設定を削除する（たぶんこれのバージョンが古いのが原因）
3. `Import more rules from the Internet` ボタンをクリック
![スクリーンショット 2019-02-09 14.25.25.png](https://qiita-image-store.s3.amazonaws.com/0/357158/858fcd35-0c1a-6c0e-82fc-a6f807627c09.png)
4. International (Language Specific) > For Japanese > Import
5. インポートした新しい設定を反映したら問題解消した
AWSのS3をファイル置き場として利用する

AWSのS3は画像ファイル置き場として利用しています。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::XXXX-XXX/*"
        }
    ]
}
```
S3はもちろん設定をすればかなりの程度高度な設定が出来るのでしょうが差し当って今回は画像ファイルを配置し、また外から参照できるようになればすればよいのでシンプルです。
ポイントはActionのところで
`"s3:GetObject"`
が取得の許可。
`"s3:PutObject"`
はLambda関数からですが書き込みの許可です。
あとそんなことするのは僕ぐらいかもしれませんが、Versionは日付けではなくそのままに「バージョン」なので変更しないように。僕はそれでまた時間食ってしまいました。
S3の設定については画面からも出来そうですがネットに情報が豊富にあるのでパケットポリシーのJSONで設定した方が良さそうですね。

以上でAWSのS3についての篇を閉じます。
PHP7＋PHPUnitで自前のセッションハンドラクラスのテストを書く

* セッションハンドラを自作した
* セッションIDが更新されるかとか、古いセッションがちゃんと破棄されるかとかテストしたい
* PHPUnitの`@runInSeparateProcess`アノテーションをつければテストできるよ

サンプルコード

~~~php
<?php

class MySessionHandlerTest extends PHPUnit\Framework\TestCase
{
    /**
     * @runInSeparateProcess
     */
    public function testCreateWriteAndSave()
    {
        // TODO 初めてアクセスした時にセッションが生成されて保存されるテスト
        // @runInSeparateProcess を指定しているので、テスト終了後に自動的にsaveされる
    }

    /**
     * @runInSeparateProcess
     * @depends testCreateWriteAndSave
     */
    public function testLoadReWriteAndSave()
    {
        // @depends を指定しているので、testCreateWriteAndSave() の結果を受けてテストが実行される
        // TODO 2回目にアクセスした時に、セッションIDが付け替えられるテスト
        // TODO 前回のセッションデータがロードできるテスト
        // TODO セッションデータが上書きできるテスト
        // @runInSeparateProcess を指定しているので、テスト終了後に自動的にsaveされる
    }

    /**
     * @runInSeparateProcess
     * @depends testLoadReWriteAndSave
     */
    public function testReLoadAndClear()
    {
        // @dependsを指定しているので、testLoadReWriteAndSave() の結果を受けてテストが実行される
        // TODO 前回のセッションデータをロードしてクリアするテスト
        // @runInSeparateProcess を指定しているので、ここでプロセスが終了し自動的にsaveされる
    }

    /**
     * @runInSeparateProcess
     * @depends testReLoadAndClear
     */
    public function testDestroy()
    {
        // @dependsを指定しているので、testReLoadAndClear() の結果を受けてテストが実行される
        // TODO 前回のセッションデータがクリアされているテスト
        // TODO サーバサイドのセッションを破棄するテスト
        // @runInSeparateProcess を指定しているので、ここでプロセスが終了し自動的にsaveされる
    }

    /**
     * @runInSeparateProcess
     * @depends testDestroy
     */
    public function testDestroyed()
    {
        // @dependsを指定しているので、testDestroy() の結果を受けてテストが実行される
        // TODO セッションが残っていないことを確認するテスト
    }
}
~~~
Django で migrate をやり直す

Django で models.py を変更した時などに、migrate をやり直す方法です。
データベースは、MariaDB を使っているとします。

アプリケーション名は、app01 とし、データベース名も app01 とします。

１）　データベースを空にする
>データベース名は app01
> データベースユーザーは django とします。

```sql
drop database app01;
create database app01;
grant all on app01.* to django@localhost;
```

2) アプリの migrations を削除

```bash
rm -f app01/migrations
```

3) マイグレイション

```bash
python manage.py makemigrations
python manage.py migrate
python manage.py migrate app01
```
英語と日本語で考える、整理された RSpec

RSpec やテストを苦手とする人はかなり多いだろうと思う。
実装は瞬殺だったのに、RSpec の書き方に悩んでしまって何日もプルリクエストを出せていない。
不運にもそんな状況に陥ってしまった人に贈る。

私は理論的な背景を研究したわけでもないので、実務家としてこうだろうと理解したことをアウトプットする。

## spec は仕様という意味
wikipedia の[スペック](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%9A%E3%83%83%E3%82%AF)の説明を見て欲しい。

> スペックとは、英語で spec （specification の省略形。読みは「スペシフィケーション」）は、いわゆる仕様書のことであるが、和製英語の範疇では一般に工業製品に期待される性能のことである。俗に「カタログスペック」や「基本スペック」、「諸元」などのように表現される。自動車のカタログなどでよくみられる。

なかでも、

> いわゆる仕様書のことであるが、和製英語の範疇では一般に工業製品に期待される性能のことである。

という部分。
この和製英語の範疇で理解していた人も多いのではないだろうか。

是非とも「仕様」という意味で頭の中の定義を上書きしておいて欲しい。
仕様という言葉の意味は広くて曖昧だが、それでも我々は平気で「仕様」と口にする。そのときに想起するような意味だと思えば良い。

##　構造： 主語・主題と述語と条件節 (describe, it, context）
### it ってなんだろう
ネストの一番深くには、 `it`　や、その別名とされる `example`, `specify` がいる。これらに渡すブロックの中で実際の期待を書くのだ。


```ruby
it '文字列を返す' do
 expect(some_object.some_method(arg)).to be_a String
end

# 別の書き方
example 'それが文字列を返す' do
 expect(some_object.some_method(arg)).to be_a String
end
specify 'それが文字列を返すこと' do
 expect(some_object.some_method(arg)).to be_a String
end
```

それぞれ響き方が違う。自然な響き方をする書き方が違う。

### it は代名詞で、主語の位置にいる
辞書を引くまでもないだろう。

### 振る舞いにフォーカスする
英語話者にとって、 `it` による例は次のように響いているはずだ。

```ruby
それは '文字列を返す' do
 expect(some_object.some_method(arg)).to be_a String
end
```

「それ」が主語であり「文字列を返す」は「それ」の振る舞いである。
主語を自由に選べないという制約によって、「文字列を返す」という振る舞いの記述に焦点が当たる。
英語話者はこういう感覚でプログラミングしているのだ。

### describe: つまり「それ」ってなんなんだ
`it` が代名詞であるというのなら、その代名詞が何を指示しているのかを特定しなければならない。
それはネストのより浅いところで宣言されているはずだ。

```ruby
describe 'SomeClass' do
  describe '#some_method' do
    it '文字列を返す' do
      expect(some_object.some_method(arg)).to be_a String
    end
  end
end
```

describe は説明する・描写する・記述するという意味だが、説明する対象を目的語にとる。

「describe an apple （あるリンゴを説明する）」とあれば、
あるリンゴがどのような形で、どのような色味を帯びているかを説明するのだろう。

「そのリンゴは赤い」「そのリンゴはゴツゴツしている」

つまり、

「それは赤い」「それはゴツゴツしている」

何か繋がった感じがしないだろうか。
まとめて読んでみよう。

```
あるリンゴを説明する。
  それは赤い。
  それはごつごつしている。
```

### describe は主題を特定する
describe は記述対象を目的語に取る。
rubyとしての語順は壊れてしまうけど、例を次のように訳してみよう。

```ruby
'とあるクラス' を説明する do
  'とあるインスタンスメソッド（#some_method）' を説明する do
    それは '文字列を返す' do
      expect(some_object.some_method(arg)).to be_a String
    end
  end
end
```

「それ」が何を示しているのか、一目瞭然ではないだろうか。

「とあるクラスのとあるインスタンスメソッドは文字列を返す」
describe の度に主題の範囲が狭まっていくのがわかるだろう。

繰り返すけれど、英語話者はこんな感覚でプログラミングしてるはずだ。

### context には主題でもなく振る舞いでもないものを
主題でも振る舞いでもないものって何があるだろう。

オブジェクトの状態、メソッドがとる引数、その他依存先。

そういうものを context に書くのが良いのではないかと思う。
context は文脈や前後関係と訳せる。
前提、背景、状況。

「〇〇のとき」「〇〇であるならば」

振る舞い方がそういった外部の状況に依存しているのであれば、それはコンテクストだ。

##　まとめ
- it に主語を固定すれば振る舞いに焦点が当たる
- describe は主題を特定し、主語を明確にする
- context は依存関係

私はそんなことを意識して書いてる。もちろんいつでも適用できるわけではないけれど。
ちなみになるべく「こと」は書かない主義。