OmniAICreator/Qiita-1.07M huggingface dataset:
ruby で GoogleDriveにアクセスする方法 2020年度版

GoogleDriveへのAPIアクセスがしょっちゅう変わってるので、2020年度版をご紹介。

## サマリー

- [QuickStart](https://developers.google.com/drive/api/v3/quickstart/ruby) のページだけで完結できる！
- クライアントタイプは「Desktop app」を選べ！
- 旧バージョンの方法はもはや使えないので、適当にググると死ぬ！QuickStart と公式ドキュメント以外見るな！

GoogleCloudの管理画面にアクセスして、やれプロジェクト作れだとかやれサービスアカウントを作れだとかいろいろ選択肢が多いので、「このルート」というのを用意しました。

## QuickStart のページにアクセス

https://developers.google.com/drive/api/v3/quickstart/ruby

このページの上から行くのが一番素直です。

## Enable the Drive API のボタンをクリック

本当はGoogleCloudのコンソールから通るのがいいはずなのですが、めちゃくちゃ面倒なので、QuickStartには近道が用意されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53489/3d09b626-a4ea-d889-f75c-6a7f71cf913e.png)

「Enable Drive API」をクリック（このドキュメントからしかたどるルートが見つからない謎のボタン）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53489/6cfe6b03-5bb0-784e-4e60-257d75146250.png)

プロジェクト名はなんでもいいので、そのままでNEXTをクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53489/6aa8f48a-3f46-cbfe-a4f4-c5e63bc7c385.png)

APIクライアントの選択肢が色々あるんだけど、Rubyプログラムから使うときには、「Desktop App」を選択した状態で、CREATE。

これで、credentials.json というファイルがダウンロードできる。
中身は

```credentials.json
{"installed":{"client_id":"...
```

ではじまるJSONファイル。

あとは、QuickStartの言うなりで大丈夫。

どういうAPIがあるかは、本家APIリファレンスの

https://github.com/googleapis/google-api-ruby-client

を丹念にみればOK。
タスクスケジューラからbatファイルを起動する際のbatファイル内のパス指定

batファイルを直接起動したときとタスクスケジューラから起動したときで挙動が違ったため、メモ

batファイルは設定ファイルの中身のデータを変数として外部ファイル（batと同階層に存在）から読み込むものとする。
このbatファイルを直接起動する場合、相対パス（ファイル名のみ）でも参照可能だったので以下の状態で設定

```bat:ファイル名表示.bat
@echo off
@chcp 65001

@set SettingTxt=変数設定.txt
::設定ファイルはbatファイルと同階層にあること
@if not exist %SettingTxt% goto notFileEnd
::設定ファイルがない場合、最後まで飛ばす

@for /f "usebackq delims== tokens=1,2" %%i in (%SettingTxt%) do set %%i=%%j
::設定の各種情報を外部ファイルから変数に設定
::=の前を変数名、=の後を値として記憶させる（do set %%i=%%j）

@echo %TxtNames%%extendChild%
@goto finishedTask

:notFileEnd
set karyunagi="%SettingTxt%ファイル自体なかった"

:finishedTask
set /p karyunagi="操作完了"
```

```txt:変数設定.txt
TxtNames=拾うデータ
extendChild=.txt
```
本来は生成したファイル名があるかの判定とかあるが、そこは省略

しかし、タスクスケジューラから起動するとなにも実行せずに閉じる。  
タスクスケジューラからbatファイルを開くところは起動しているので、bat内部でパスが指定できていないことになる。  
調べたところ、タスクスケジューラから起動すると、パス位置がbatファイル位置を参照せずにファイル名をローカルディスク直下のパスとして探してしまうため、起きていたようだ。

## タスクスケジューラでは・・・？
解決策を探していたら、以下のページを見つけた。

[[Windows]タスクスケジューラで作業フォルダを指定する方法](https://delightmode.com/win-taskscheduler/)

タスクスケジューラ内の「開始（オプション）(I)」にbatファイルフォルダのパスを設定すると動くらしい。

実際試してみたら動いた。

・・・

いや、まぁ動いたけどこれ
batファイルの位置が固定で変化しない前提だよね・・・

普通は変更掛からないはずだけど、
事情があって変更みたいなことを考えると、絶対参照で書きたくはない

しかも、固定でない場合は変更がかかるたびに2か所もいちいち修正しなくてはならなくなるから、めんどい・・・
（ここ以外にも起動するbatファイルパスをタスクスケジューラの「プログラム/スクリプト(P):」も修正する必要がある）

## bat側で指定する

よくよく考えてみたら、batのパスをbat内で指定すればいけるんじゃないかと思い、




```bat
@set pathes=%~d0
@set SettingTxt=変数設定.txt
::設定ファイルはbatファイルと同階層にあること
@set SettingTxt="%pathes%%SettingTxt%"
```
のように一部追加変更した。
最後の SettingTxt の "" は、
パス内に半角空白が入っていた時の対策のために入れている。半角空白があるとその先はコマンドが区切られているとして解釈し、ファイル名として読み取れなくなってしまう。

<br><br>

が・・・変わらない。

と思ったら、ドライブしか拾えてなかった。

```bat:d&nbsp;のみだとドライブしか拾えない
@set pathes=%~d0
```

上記の指定だと、ドライブしか指定していないため、ドライブしか参照できていない。
ファイル名を除いたパスを指定する場合、「p」も指定する必要がある。

ということで、設定ファイルのパス取得に追加

```bat:設定ファイルに&nbsp;dp&nbsp;指定（&nbsp;pd&nbsp;でも可）
@set pathes=%~dp0
@set SettingTxt=変数設定.txt
::設定ファイルはbatファイルと同階層にあること
@set SettingTxt="%pathes%%SettingTxt%"
```
実行できた。

バッチ内で自パスを拾うので、<b>疑似相対パス参照</b>はできた。

~~もっとも自パスの1つ上階層内の別フォルダ指定は試してみたが、できなかった（というかできない？）ので、batのみで同一階層下以外の相対パス参照は無理っぽい？~~

20/08/03 追記

コメントいただいたもので`pushd`を用いてみたところ、相対参照もできた。

```bat:設定ファイルパスに&nbsp;pushd&nbsp;指定、1つ上階層のtestフォルダ参照
@set pathes=%~dp0
pushd %pathes%..\test\
@set pathes=%cd%
@set SettingTxt=変数設定.txt
::設定ファイルはbatファイルの1つ上階層のtestフォルダ内にあること
@set SettingTxt="%pathes%\%SettingTxt%"
```

ただし、`%~dp0`から遡る都合か、
`%~dp0`時にあった最後の`/`は存在しなくなってしまうので、
変数結合時（最後の`SettingTxt`）に追加している。


##参考
[パス名の文字列を自在に切り取る - 知識ゼロからのwindowsバッチファイル超入門](https://jj-blues.com/cms/wantto-cutstringpathname/)
[バッチファイルでの「スペース」を含んだ文字列の取り扱い - 知識ゼロからのwindowsバッチファイル超入門](https://jj-blues.com/cms/column-spaceinbatfile/)
[.bat（バッチファイル）のforコマンド解説。 - Qiita](https://qiita.com/plcherrim/items/67be34bab1fdf3fb87f9)
【Windows】ファイルの新規作成ならniコマンドが簡単

# コマンド操作で任意のファイルを新規作成する方法

VSCodeのターミナルなどコマンドラインからファイルを新しく追加したいときがあります。
Macであれば`touch`コマンドで実行することができますが[^1]、Windowsでは`touch`は使えません。
そのような時、ウィンドウ左のエクスプローラーから手動で新規作成してもいいのですが、
コマンドラインから`ni`コマンドを使っても同じことができます。

## niコマンド

例えば`sample.txt`というテキストエディタを作成するときは次のようにします。

```shell
> ni sample.txt
```

さらに、ひとつ下の階層`sub`に`sample.txt`を新規作成したい場合は次のようにします。

```shell
> ni ./sub/sample.txt
```

作成されたファイルの中身は空です。
`.txt`に限らず`.py`や`.md`などもこの方法で新規作成できます。

## おわりに

ファイルを新規作成するコマンドは他にもあるようですが、
`ni`が特にシンプルでいいなと思い使っています。

[^1]: [Macのターミナルコマンド一覧（基本編）](https://qiita.com/ryouzi/items/f9dee1540a04a0bfb9a3)
【AWS-SAA】VPC関連用語の備忘録

#はじめに
AWS-SAAにおいてVPCの理解をきちんとしなければ、合格することは難しいだろう。その一方でVPC関連用語が多く、似たような機能が多いので覚えづらく感じる。本稿では特に覚えづらいVPC関連用語の理解を深めるため、備忘録としてまとめていきたい。

#VPC関連用語
<h2>VPC</h2>
VPCとは？
・ユーザーが定義した仮想ネットワーク環境。

概要
・ネットワーク、サブネットの範囲、ルートテーブル、ネットワークゲートウェイなどの設定ができる。

<h2>VPCエンドポイント</h2>
VPCエンドポイントとは？
・VPC内からVPC外へ接続するための、接続点を作るためのサービス。

概要
・VPCに対応しているサービスと対応していないサービス、どちらも連携するために接続。

<h2>Private Link</h2>
Private Linkとは？
・Amazonのネットワーク内で、VPC、AWSのサービス、オンプレミスアプリケーション間のプライベート接続が可能になるサービス。

概要
・Private Linkを使うことでインターネットに出る必要がなくなる。これによりファイアウォール、インターネットゲートウェイやVPCピア接続などのネットワークの設定が不要になる。またインターネットを経由しないため、ブルートフォース攻撃や DDoS攻撃などの脅威に晒される危険を軽減し、セキュリティ面でも効果がある。

<h2>VPCピアリング</h2>
VPCピアリングとは？
・VPC同士を接続する方法。
概要
・自分のVPC間、別のAWSアカウントのVPCとの間、または別のAWSリージョンのVPCとの間に作成可能。

#参考
AWS　仕組みと技術がしっかりわかる教科書
[VPC](https://aws.amazon.com/jp/vpc/)
[VPC エンドポイント](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-endpoints.html)
[Private Link1](https://devlog.arksystems.co.jp/2018/05/11/4896/)
[Private Link2](https://aws.amazon.com/jp/privatelink/)
[VPC ピアリング](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-peering.html)
Intel Usbblaster, FPGA書き込み設定@Ubuntu20.04

#開発環境

・Ubuntu　20.04 LTS
・FPGAボード DE0-CV
・FPGA　Cyclone V(5CEBA4F23C7)
・IDE　Quartus Prime lite


#やったこと
[こちら](http://cellspe.matrix.jp/zerofpga/inst_quartus.html)のHPにしたがってQuartus Prime liteのインストール実施。
DE0-CVはオンボードのUSB-BにFPGA書き込み用のusbblasterが載っているので、動作確認のためにandロジックをUSB-Bポートから給電しフラッシュ試みるもfail。
色々試したが結論としては51-usbblaster.rulesファイルの記載内容を変更することで解決した。
.rulesファイルに記載する内容がUbuntuでは[IntelのHP](https://www.intel.co.jp/content/www/jp/ja/programmable/support/support-resources/download/drivers/dri-usb_b-lnx.html)に記載のRedHat linux用から修正が必要。

#変更手順
下記コマンドで51-usbblaster.rulesを新規作成。

```bash
sudo vi /etc/udev/rules.d/51-usbblaster.rules
```

下記をコピペ。

```
# USB Blaster
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6001", MODE="0666", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", RUN+="/bin/chmod 0666 %c"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6002", MODE="0666", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", RUN+="/bin/chmod 0666 %c"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6003", MODE="0666", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", RUN+="/bin/chmod 0666 %c"

# USB Blaster II
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6010", MODE="0666", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", RUN+="/bin/chmod 0666 %c"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6810", MODE="0666", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", RUN+="/bin/chmod 0666 %c"
```

そのままフラッシュ試みるもうまく行かず、念の為PCを再起動し再度フラッシュ試みたところ書き込み成功。
JSを使ったiframe内のページ内リンク

結論から言うと、JavaScriptの```window.location.href```でアンカーリンクが簡単に実装できるよという話です。

## はじめに
iframe外からiframe内へのアンカーリンクで困る、というのはよく目にします。
今回はiframe内で完結しているコンテンツにおいて、アンカーリンクが正常に作動しなかったときのメモです。
滅多にないと思いますが、ちょっと特殊なケース（今回ならGAS）で同じような問題に遭遇した際の代替案として今後役立てばと思います。
また、JSで手軽にページ内リンクが設定できる個人的な発見でもあったので記録します。

## Google Siteで困りました
始まりはGoogle Siteでページを作成する中で、GASのApps Scriptガジェットを埋め込んだときのことです。
埋め込んだガジェット部分はiframeとして処理され、作成したコードは全てiframe内に組み込まれるわけですが
例えば、ガジェット内で下記のようにページ内リンクをさせたかったとします。

```
<a href="#hoge">リンク</a>

<div id="hoge">
　　「リンク」クリックでここにジャンプさせたい
</div>
```
私の想定ではいつも通り```id="hoge"```までピュンと飛んでくれるはずだったのですが
なぜだか別ページに移動してしまいます。
たぶんなのですが、GASでリンクを貼る場合は絶対パスでないと自動でURLを補完するようで、全く別ページのURLの末尾に```#hoge```が追記されたものに置き換わってしまうのです。
これを機能させるにはiframe内のURLを知る必要があるということ…？
iframe内のURLって…？

### 試したこと
わざわざ段落を設けるまでのことはしていないのですが、調べると```id="hoge"```を```name="hoge"```に変えたらいいという解決策が複数出てきたので試しました。だめでした。

## 対処法 onclick="window.location.href='ID'"
主にHTMLとCSSばかり触ってきた人間なので、```<a href="#ID"></a>```のみを使ってきましたがJSでも簡単に実装できるということを今回学びました。

方法は簡単で、クリックさせたいタグに```onclick="window.location.href='飛ばしたい先のID'"```を足すだけです。
先ほどの例になぞればこんな感じ。

```
<a onclick="window.location.href='#hoge'">リンク</a>

<div id="hoge">
　　「リンク」クリックでここにジャンプさせたい
</div>
```
aタグ以外にも使える上、手軽で、さらにIDを持つ要素の位置情報を確実に取得し移動してくれるので万能そうです。
ReactでsetStateをしても画面表示が切り替わらない問題の解決方法メモ


# はじめに
## 概要
Reactでフロントエンドのツールを作っている時に、`state`の中に設定されているjson形式のデータを、HTMLのテーブルとして表示する機能を作りました。

その際に、表示の基となるデータを変更しても、テーブル内に表示される値は切り替わらないというエラーに出会ったため、簡単な解決方法をここにメモしておきます。
## TL;DR
Reactを使うときに、イテラブルなオブジェクトを基に画面表示をする場合は、各要素ごとにidが振られていないと、同オブジェクトの値が変わっても画面表示が切り変わらないことがあるようです。
# やりたかったこと
`state`に登録されているjsonの配列形式のデータを、HTMLの`<table>`要素の中に上手く表示させることがしたかったです。
具体的には、`state`には以下のようなデータが登録をされていました。

```javascript
this.state.dummyData = [
  {
    "key":"aa",
    "value":"bb"
  },{
    "key":"aa",
    "value":"bb"
  },{
    "key":"aa",
    "value":"bb"
  }
]
```
こんな感じで、単純なオブジェクトの配列になっていました。
これを基に画面表示をする、概略化したコードは、以下のような感じです。

```react
render(){
  // 省略
  <table>
    <tbody>
      {this.state.dummyData.map((d,i) => 
        <tr>
          <td>{d.key}</td>
          <td>{d.value}</td>
        </tr>
      )}
    </tbody>
  </table>
  // 省略
}
```
配列の中身の数だけ`<tr>`を生成して、その中の`<td>`に値を表示しているだけです。
しかしこれだと、`this.state.dummyData`の値が変わっても、テーブルの中身は変わらない場合がありました。
# 解決方法
解決方法のヒントは、Reactの開発モードの時に出るコンソール内のwarningにちゃんと出ていました。

```
Warning: Each child in a list should have a unique "key" prop.
```
Reactで、リストを基に画面に要素を複数個表示する場合は、各要素に`key`を設定することが推奨されています。そのため、以下のように変更をしました。

まず、表示基の`state`内のオブジェクトの各項目には、idを振るようにしました。

```javascript
this.state.dummyData = [
  {
    "id":001,
    "key":"aa",
    "value":"bb"
  },{
    "id":002,
    "key":"aa",
    "value":"bb"
  },{
    "id":003,
    "key":"aa",
    "value":"bb"
  }
]
```
そして、画面表示をする際は、`<tr>`に`key`としてidを設定します。

```react
render(){
  // 省略
  <table>
    <tbody>
      {this.state.dummyData.map((d,i) => 
        <tr key={d.id}>
          <td>{d.key}</td>
          <td>{d.value}</td>
        </tr>
      )}
    </tbody>
  </table>
  // 省略
}
```
こうすることで、表示基のオブジェクトが変更されたときに毎回render関数が走るようになり、きちんと画面が切り替わりました。

# まとめ
Reactを使うのは初めてだったので、単純なところで引っかかってしまいました。

「React 配列　展開」とかでググって出てくるサンプルコードの多くは、`map`関数の中でHTML要素に`key`を設定していなかったのですが、表示内容が変更される可能性がある場合には、きちんと`key`を設定しなければならないようです。
L2スイッチの冗長化について

仮想基盤追加に伴いL2スイッチを導入する必要があって、冗長化について検討したので備忘録兼ねて。
結局リンクステートトラッキング同等の技術を導入した。
以下適当です。

#スパニングツリープロトコル
BPDU(Bridge Protocol Data Unit)というフレームをLANスイッチ間でやりとりし、優先度が一番小さいLANスイッチをルートブリッジに決定。ルートブリッジから最も遠いものをブロッキングポートとする機能。

・メリット
実績、対応機器が多い

・デメリット
設定、運用が難しい(一から設定ならともかく、追加となると。。。)
![STP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624314/bcc364dc-6085-bd4a-4791-8b180924929f.png)

#リンクステートトラッキング
アップリンクポートが切断された際に、自動的にダウンリンクポートをシャットダウンする機能。
・メリット
設定、運用が簡単
ブロッキングポート不要

・デメリット
対応機器が限られる
ループ構成にはできない（下記図だと右側のスイッチ同士をつながない）
![lst.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624314/f28c7903-4899-d974-780c-f6fc3e0ac031.png)

#フレックスリンク
2つのポートのうち一方をアクティブリンクとして、もう一方をバックアップリンクとする機能。
・メリット
設定、運用が簡単

・デメリット
対応機器が限られる
スタック構成が必須
![flexlink.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624314/8c9a2872-6b71-4fd9-da9e-d925ee55b2d4.png)

#vPC(MC-LAG)
複数のスイッチでLAGを構成する機能。
・メリット
設定、運用がやや簡単
帯域を増やせる

・デメリット
上位機種の高いやつしか対応していない
![MLAG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624314/6a35193b-ca4f-1c27-416f-82a6fca1e9bc.png)




#番外
すべてL3構成とする。ありな気がする。
アジャイル開発を簡単にまとめる

### アジャイル開発が生まれた経緯
始まりは2001年の2月にユタ州のスキー場にあるロッジに、従来型のソフトウェア開発のやり方とは異なる手法を実践していた17名のソフトウェア開発者が集まり、それぞれの主義や手法についての議論を行い、自分たちの提唱している考え方の共通項を探すという試みから始まりました。

**この集まりでアジャイルという言葉が使われるようになり、アジャイルの価値と原則について定義されました。**

そして、それらを宣言として公開したのが以下の２つの文書になります。

後述でまとめているので、急ぎの方は飛ばしてもらって構いません。

### アジャイルソフトウェア開発宣言

**アジャイルソフトウェア開発宣言** は、アジャイル開発を行ううえで重視してするべき「マインドセット」についてまとめられています。



> 私たちは、ソフトウェア開発の実践
> あるいは実践を手助けをする活動を通じて、
> よりよい開発方法を見つけだそうとしている。
> この活動を通して、私たちは以下の価値に至った。
>
> プロセスやツールよりも個人と対話を、
> 包括的なドキュメントよりも動くソフトウェアを、
> 契約交渉よりも顧客との協調を、
> 計画に従うことよりも変化への対応を、
>
> 価値とする。すなわち、左記のことがらに価値があることを
> 認めながらも、私たちは右記のことがらにより価値をおく。

[アジャイルソフトウェア開発宣言](https://agilemanifesto.org/iso/ja/manifesto.html)



## アジャイル宣言の背後にある原則

**アジャイル宣言の背後にある原則** は **アジャイルソフト ウェア開発宣言** で表明されているマインドセットを実現するため に、従うことが望ましい原則について書かれています。



>*私たちは以下の原則に従う:*
>
>顧客満足を最優先し、
>価値のあるソフトウェアを早く継続的に提供します。
>
>要求の変更はたとえ開発の後期であっても歓迎します。
>変化を味方につけることによって、お客様の競争力を引き上げます。
>
>動くソフトウェアを、2-3週間から2-3ヶ月という
>できるだけ短い時間間隔でリリースします。
>
>ビジネス側の人と開発者は、プロジェクトを通して
>日々一緒に働かなければなりません。
>
>意欲に満ちた人々を集めてプロジェクトを構成します。
>環境と支援を与え仕事が無事終わるまで彼らを信頼します。
>
>情報を伝えるもっとも効率的で効果的な方法は
>フェイス・トゥ・フェイスで話をすることです。
>
>動くソフトウェアこそが進捗の最も重要な尺度です。
>
>アジャイル･プロセスは持続可能な開発を促進します。
>一定のペースを継続的に維持できるようにしなければなりません。
>
>技術的卓越性と優れた設計に対する
>不断の注意が機敏さを高めます。
>
>シンプルさ（ムダなく作れる量を最大限にすること）が本質です。
>
>最良のアーキテクチャ・要求・設計は、
>自己組織的なチームから生み出されます。
>
>チームがもっと効率を高めることができるかを定期的に振り返り、
>それに基づいて自分たちのやり方を最適に調整します。

[アジャイル宣言の背後にある原則](http://agilemanifesto.org/iso/ja/principles.html)



### つまり何が言いたいの？

上記２点がアジャイル開発の全てといっても過言ではありませんが、非エンジニアの方や、アジャイル開発に触れたことのない方には、少し難しい文章になっていると思います。



僕なりに、アジャイルソフトウェア開発宣言とアジャイル宣言の背後にある原則を簡易的にまとめてみました。



#### アジャイル開発を行う上で必要なマインドセット（アジャイルソフトウェア開発宣言）

1. プロセスやツールよりも **個人と対話** を重視
2. 包括的なドキュメントよりも **動くソフトウェア** を重視
3. 契約交渉よりも **顧客との協調** を重視
4. 計画に従うことよりも **変化への対応** を重視



#### マインドセットを実現する為の原則（アジャイル宣言の背後にある原則）

1. 顧客満足を最優先に考える
2. 変化を味方につける
3. 短い時間間隔で品質の改善を行う
4. ビジネス側も開発者も共通の目標を持つ
5. 意欲に満ちた人々でチームを作る
6. Face to Faceでの対話を重視
7. 動くソフトウェアこそが最も大切
8. 無理のないペースを一定に保ち続ける
9. 負債を負わないように品質を追求する
10. 無駄を徹底的に省く
11. 良いモノは良いチームから生まれる
12. 定期的に振り返りを実施し、チームの成長を止めない。


## Don't DO Agile, BE Agile

上記では、**アジャイルソフトウェア開発宣言** と **アジャイル宣言の背後にある原則** を簡易的にまとめました。

ですが、アジャイル開発において最も大切はことは

**価値を追い求めるために、常に考え続け、改善し続けていく姿勢** 

だと思います。
これに従えは良いという正解があるわけではなく

**原則を基に組織に対して柔軟に適応していくこと**

それこそが、アジャイルの本質であると僕は思っています。


## さらに詳しく知りたい方は

本記事で興味を持って頂いた方は、情報処理推進機構が提供している書類を見てみてください。
かなり詳しく噛み砕いて説明しているので、更に理解が深まると思います。

[アジャイルソフトウェア開発宣言の 読みとき方](https://www.ipa.go.jp/files/000065601.pdf)



## 参考文献

[スクラム開発のメリットとデメリットについて](https://www.high-performer.jp/engineer/trend/features-and-merits-of-scrum-which-is-a-methodology-of-agile-development/#:~:text=4.-,スクラム開発のメリットとデメリットについて,変更に対応しやすい。)
[アジャイル宣言の背後にある原則](http://agilemanifesto.org/iso/ja/principles.html)
[アジャイルソフトウェア開発宣言](https://agilemanifesto.org/iso/ja/manifesto.html)
[正しく理解しようアジャイルとスクラム](https://tech.recruit-mp.co.jp/scrum/about-agile-and-scrum/)
ORACLEユーザーアカウント

#ORA-28000: アカウントがロックされています



#解除の手順
1) 管理権限ユーザー（sys等）でログインする

```
$ sqlplus / AS SYSDBA
```

2) dba_users テーブルでステータスを確認する

```
SQL> select username, account_status, profile from dba_users where username = 'USER_NAME';

USERNAME  ACCOUNT_STATUS PROFILE
--------- -------------- -------
USER_NAME LOCKED(TIMED)  DEFAULT

```
対象ユーザーがロックされていることを確認。

3) ロック解除コマンドを実行

```
SQL> alter user USER_NAME account unlock;
```

4) 解除されているか確認

```
SQL> select username, account_status, profile from dba_users where username = 'USER_NAME';

USERNAME  ACCOUNT_STATUS PROFILE
--------- -------------- -------
USER_NAME OPEN　　　　　  DEFAULT
```

OPENになっていたら無事に解放されている。
【Windows10版】Virtualbox × Vagrant LaravelとHomesteadで仮想環境を作ってみた。

##【開発環境】
Windows 10 HOME
VirtualBox 6.0
Vagrant 2.2.9


【仮想環境側】
laravel (v6.0.2)
homestead version ^11.0 
ubuntu-20.04-amd64-disk001

##【目次】

|  | 　　項目　　　　　|
|:----:|:-------------|
| - | [はじめに](#はじめに) |
| - | [やってみた](#やってみた) |


#はじめに

ローカルで仮想環境を作ってみようと調べていたら
HomesteadとLaravelを簡単にインストールできる
PHPファイルで作成した人がいたのでそれを使ってみた。

[【Laravel】ワンアクションでプロジェクト毎にLaravelとHomesteadをインストールしてくれる「Larastar」](https://qiita.com/sola-msr/items/5f6df1d94224fcc37a45)



#やってみた

Larastar-masterをDLして解凍後、
Laravelのプロジェクトを作るフォルダに設置。

```ruby:Larastar-master/larastar.php
<?php
//----------- config -------------

const VERSION = "6.0.*";
const DIRECTORY_NAME = "";
```
インストールしたいLaravelのバージョンを記載。

```ruby:powershell
PS C:\Larastar-master> php larastar.php
```
powershellにて
larastar.php　があるフォルダに移動してphpを実行します。


```ruby:powershell
【Notice】Confirm 'to' of 'folders' in 'Homestead.yaml'. And 'vagrant reload' please.

--------- Laravel & laravel homestead installed! -------------

---------【 Laravel & laravel homestead セットアップバッチ「ララスター☆彡」 終了 】-------------
```
暫くするとインストールが完了します。
下記のURLにアクセスすると

http://homestead.test/

#No input file specified

```
No input file specified.
```
訳すと
「指定されたファイルがありません。」

nginxのエラーログを見てみると、

```powershell:/var/log/nginx/homestead.test-error.log
Unable to open primary script: /home/vagrant/code/public/index.php
```

ここにファイルが無いよ　と出ています。

じゃあここにファイルを作ればエラーは解消できるのか検証してみます。

```ruby:powershell
vagrant@larastar-master:~$ cd /home/vagrant/code/
vagrant@larastar-master:~/code$
vagrant@larastar-master:~/code$ mkdir public
vagrant@larastar-master:~/code$ cd public
vagrant@larastar-master:~/code/public$ vi index.php
```
code/public/　にindex.phpファイルを作成します。

```ruby:powershell
<?php
echo "hello world";
```
hello world　と記載。
ブラウザを再度見ると、

```
hello world
```
表示されました。
これでディレクトリのズレを解消できれば
Laravelのプロジェクトを表示出来そうです。

```ruby:index.php
<?php
var_export($_SERVER);
```
先ほど作成した「index.php」に
$_SERVERというグローバル変数を記載すればサーバー側の情報を
どこからでも呼ぶことが出来ます。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/140a9775-4c05-d24c-d716-1b46e2ddb45a.png)


```
'DOCUMENT_ROOT' => '/home/vagrant/code/public'
```
その中のドキュメントルートは上記になっています。


```ruby:Larastar-master/Homestead.yaml

sites:
    (×)    to: /home/vagrant/code/public 
　　　　　↓
    (〇)   to: /home/vagrant/code/laravel/public
```

Homestead.yamlファイルの「sites　to」の部分を
$_SERVERで見たディレクトリでは無く、
laravelの表示したいプロジェクトのディレクトリに修正します。


```ruby:powershell
vagrant provision
```
ファイル修正後に上記のコマンド実行。
詳しくはこちらをどうぞ。　[Vagrant Provisionとは](https://qiita.com/wakky_404/items/710f08c865969e72df73)

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/e489fc39-30b3-04c2-45d4-c5e1cc18ce1c.png)


http://homestead.test/

でLaravelの画面が表示出来ました。
PHPで指定桁数の最大値を取得する

もっとスマートな書き方がある気がしているので、ご教示いただきたいです。
→ (2020/07/30) コメント頂いたので、追記させていただきました！

## 指定桁数の最大値を取得

- ※ 整数のみ対応
- ※  **PHP_INT_MAXを超える桁数を$lengthに指定しないこと！**

### A1: str_repeat()を使う
```php
$length = 6; // 6桁
$max = (int)str_repeat(9, $length); // 999999
```

### A2: 累乗する
@vf8974 さんからコメント頂きました。確かにこちらの方が考え方がスマートです。

```php
$max = 10 ** $length - 1;
```

## 注意点
当たり前なんですが、桁数`$length`に100など大きい桁を入れるとオーバーフローしますので、PHP_INT_MAX を超えない桁を指定して下さい。
https://www.php.net/manual/ja/language.types.integer.php#language.types.integer.overflow
> integer型の範囲外の数を指定した場合、かわりに floatとして解釈されます。また、結果が integer型の範囲外の数となるような計算を行> うと floatが代わりに返されます。

もしそれより大きい桁が欲しいときは、string型で取得するしかありません。

```php
$length = 30; // 30桁
$max = str_repeat(9, $length); // string(30) "999999999999999999999999999999"
```

## (応用) 指定桁数までのランダムな整数値を取得

```php
$rand_int = random_int(1, $max);
```
ビジネスプロセスフローで「次のステージ」が表示されない？？


# 概要
既存のCDSからビジネスプロセスフローを作成したときに「**次のステージ**」が表示されないことはありませんか？
私はこれに悩まされました…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/37635ec2-ba63-7ce2-5a38-5a9495ea7f2b.png)

# 原因
Power Automateから作ったエンティティのリレーションシップ
![Power Automateリレーション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/3e787858-6aef-1a01-ddcd-49927db72158.png)
Power Appsから作ったエンティティのリレーションシップ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/aa8f6b73-3d9c-2fdb-ab72-0022b2ce7c5c.png)

Power Appsのエンティティから作るとリレーションに**プロセス**がない！！

# 対応
とゆうことで**「リレーションシップの追加」で「多対一」の「プロセス」**を追加！

1.リレーションシップの追加→多対一
![多対一.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/6ca77184-f139-dc74-e39e-d4763eabb2c0.png)

2.プロセス→完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/90419424-9319-f3e4-cff1-df35ca1814ef.png)

# まとめ
・一つのエンティティでビジネスプロセスフローを作成するとリレーションシップにプロセスがないから追加しないといけない。
・しかし…複数のエンティティ・リレーションをしているうえでビジネスプロセスフローを作ると違う問題が…
仮説を検証するために、小さなコードを書いて結果を確かめよう

# 概要

エンジニアが現実的に直面する問題は、複雑に入り組んでおり、何が原因となっているのかがわからないことが多い。「考えたらわかるのではないか」という発想に陥りがちであるが、経験主義では行動して確かめることを重要視する。（参考：[情報を生み出す考え方～経験主義と仮説思考・システム思考～](https://qiita.com/flyaway/items/67f5577390bc7bf02eb1))

このため、立てた「仮説」を一つ一つ「事実」に確定させていくための行動が必要となる。
エンジニアの場合、その方法として「小さなコードを書いて、結果を確かめる」というスキルが基本となる。

# こんなときにやってみよう

- コードが期待通りに動かない。しかし、どこが悪いのかがわからない
- APIのドキュメントや参考記事・資料を読んでも、わからないところがある

# 具体例

## 問題

指定要素の文字色を赤色に変えるCSSを書いたつもりだが、期待通りに反映されない。
記事などをいろいろ調べてみても、なぜうまくいかないのかが、結局のところよくわからない。

```css
div .item {
  color: red;
}
```

## 解決策

実際に自分で小さな例を書いて試すとよい。
この場合、下記のようなhtmlファイルを作成し、ローカルに保存してブラウザから開き、動作を確かめることができる。

```html
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
<!--
div .item {
  color: red;
}
-->
</style>
</head>
<body>

<div class="item">この文字色が変わると思う</div>

<div>
  <div class="item">これも変わると思う</div>
</div>

<div>
  <div>
    <div class="item">この場合も変わると思う</div>
    <div>これは変わらないと思う</div>
  </div>
  <div class="item">
    <div>これも変わらないと思う</div>
  </div>
</div>

</body>
</html>
```

[実行結果](https://jsfiddle.net/flyaway/p1m0y4wx/latest)を確認すると、自分の仮説と事実との間に、違いがあったことがわかり、一歩前進することができる。

# [参考] ブラウザ上でコードの動作を確認できるサービス

[codepen](https://codepen.io/)や[jsfiddle](https://jsfiddle.net/)など、ブラウザ上でこのようなコードの動作をサクッと確認することができるサービスもある。

ただし、注意して利用しないと **自分の書いたコードが全世界に公開された状態になる** ものもある。
このため、企業に所属している場合は、業務上でこれらを利用する前にはそのポリシーを確認する必要があるし、プロダクトのソースコードの一部をそのままコピー＆ペーストして試すなどは、厳禁だ。
【Rails 5.0】モデルにカスタムバリデーターを実装する

## はじめに
Railsのバリデーションですが、自分で作ることができます。

## モデル内に自作する
Personのname属性に"ウンコ"という文字列が含まれていたらDBに登録できないようにします。
下品な名前は許しません()

```person.rb
class Person < ApplicationRecord
  before_save :include_unko

  private
  # Personモデルでしか使わないのでPrivateメソッドにしておく
  def include_unko
    if name.include?("ウンコ")
      errors.add(:name, "に下品な言葉が含まれています")
    end
  end

end

# キャンチョメとウンコティンティンをPersonに登録してみましょう。
person_1 = Person.create(name: "キャンチョメ")
person_1.valid? # => true
person_1.erros # => nil

person_2 = Person.create(name: "ウンコティンティン")
person_2.valid? # => false
person_2.errors.full_message
# => ["Name に下品な言葉が含まれています"]
```

## カスタムバリデーターの戻り値について
valid?(もしくはinvalid?)メソッドを使って、バリデーションを手動でトリガできます。
バリデーションメソッドを実行した後、オブジェクト(今回ではperson_1とperson_2)にエラー(errors)がない場合はtrueが返され、そうでなければfalseが返されます。 
したがって、カスタムバリデーターを実装したら必ず`errors.add`を用いてエラーを格納するようにします。
`true`や`false`を返すメソッドではないということに注意しましょう。

## 参考
[Active Record バリデーション \- Railsガイド](https://railsguides.jp/active_record_validations.html#valid-questionmark%E3%81%A8invalid-questionmark)
DDDとは結局何なのか  オニオン(クリーン)アーキテクチャなどとの関係は? 1

# この記事について
- DDDを個人的に勉強し、自分で納得がいくように理解できたのでその知見を紹介しようと思います
- あくまでも個人的な理解なので、参考程度に留めてください
- なるべく難しい言葉を使わないようにし、自分の言葉でまとめるようにしました


# DDDとは結局何なのか
- かなり広い概念を表していると思いました。大きく3つの考えが合わさっていると思います。
    1. 何はともあれドメインが中心の世界。ドメインとはそのソフトウェアで解決したい問題、活動の領域。このドメインを中心にプロダクトを作ろうという話。
    1. 開発者は1人でプロジェクト立ち上げから、ソフトウェア開発、マーケティングなどの業務をこなすことはまずないです。そのときに、各部署やチーム内でプログラム言語などの専門的用語を知っている人は少ないです。また、逆に開発者はビジネス用語やマーケティング用語に疎いです。これでは円滑なコミュニケーションが測れないため、**ユビキタス言語**や**コンテキスト**を導入します。 
    1. 開発していく中で、プログラマーが1人でないとしたら、引継ぎや役割分担などを円滑に行える必要があります。また、テストや修正が入ることもしばしばあります。そのために**アーキテクチャ**を導入します。
 

#### この3つの考えを統合していくのがDDDの思想なのだと思います。
- 先に主に参考にした文献を紹介します。
    - DDDがパターンを紹介しているにすぎないことが書いてあります　[リンク](https://www.ogis-ri.co.jp/otc/hiroba/technical/DDDEssence/chap1.html)
    - もう少し細かくDDDについて触れています [リンク](https://little-hands.hatenablog.com/archive/category/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88%28DDD%29)

### DDDの勘違いしやすいポイント
- DDDとは何か具体的なコードの書き方を示したものではなく、**答えはない**。つまりDDDとは単なる**概念、思想**である
- 一発でユーザーのニーズや用件を満たせるコードがかければ良いに越したことはないが、DDDはそのようなものを目指してはおらず、**トライアンドエラー**や**アジャイル**的に開発していく


# 発案者の言葉も確認
- 発案者はEric Evansというお方だそうです。本人自身も定義は難しいと前置きを置いた上で以下のように発言しています。

> **What is Domain Driven Design?**
1. Focus on the core complexity and opportunity in the  domain
2. Explore models in a collaboration of domain experts and software experts
3. Write software that expresses those models explicitly
4. Speak ubiquitous language within a bounded context

- [こちら](https://little-hands.hatenablog.com/entry/2017/09/27/014403)には分かりやすい意訳がありました。
- あえて私なりの言葉で訳すと、
  1. アプリケーションの対象(ドメイン)の複雑さと機会に焦点を当てる
  2. 開発者とドメインについての専門家が共に関わり、最良なモデルを探索する
  3. 開発者はこのモデルを明確に表現する
  4. 決められた範囲(コンテキスト)の中で共通理解のある言語(ユビキタス言語)を使って話す

- 個人的には初めて文章を読んだときにドメインという言葉が、URLのドメインを表しているのかと思ったのですが、**そういうわけではなくて、現実世界のマーケティングの対象となる範囲を示しているのかもしれない**と感じました。さらに、どの場面でもとあるユビキタス言語で話すのかと思っていましたが、**チームごとにとか、部署ごとに違うユビキタス言語を使って良い**んだと思いました
- 開発者の本領が発揮されるのは3の部分で、ここに**オニオンアーキテクチャやクリーンアーキテクチャが関わってくる**ようです。この3だけを取り上げると、軽量DDD(戦術的DDD)と言うそうです。Qiitaにはこの軽量DDDの記事が多いと思います(技術的な要素がここに詰まっているので仕方ないとは思います)

# 終わり
- 自分なりの言葉でDDDをまとめてみました。軽量DDDでよく出てくるアーキテクチャやエンティティ、値オブジェクトについても時間があれば書いてみようと思います(書き次第[ここに](https://qiita.com/takassh/items/be6990eb95f8ee3b4c52)追記します。)ただ上にあげた文献がとても分かり易かったので、そちらをみた方が良いかもしれません
- 誰かの理解の助けとなれば幸いです
[Next.js + Storybook] RouterのMockを作成

```
Cannot read property 'pathname' of null
```

RouterのMockを作成せずに、
Material-UIの `<Link>` を使うと上記エラーがでる。

その対処法。


```.storybook/nextRouterMock.js
import * as nextRouter from 'next/router'

nextRouter.useRouter = () => ({
  route: "/",
  pathname: "/"
});

nextRouter.router = {
  push: () => {},
  prefetch: () => new Promise((resolve, reject) => {}),
};
```

```.storybook/config.js
import './nextRouterMock';
```

参考
 https://gist.github.com/novascreen/f1c44ead31e5a494556793be2c408840
Gmailで別の送信元アドレスを設定し、さらにGmailのSMTPを使って送る方法

# やり方
- Gmailの設定
- アカウントとインポート
- 名前（Gmailを使用して他のメールアドレスからメールを送信します）で「他のメールアドレスを追加」をクリック
- エイリアスとして扱いますはチェックを入れたまま
- SMTP Server: smtp.gmail.com
- Port: 465 or 587
- Username: <yourgmailaddress>@gmail.com
- Password: yourpassword（2段階認証を使用している場合は[アプリ パスワード](https://support.google.com/accounts/answer/185833?hl=ja)を使用）
- 保存

# 参考
https://support.google.com/a/answer/1710338?hl=ja
https://support.google.com/mail/answer/7126229?hl=ja
https://support.google.com/accounts/answer/185833?hl=en
【Gmail】メールの宛先から自分のメールアドレスを取り除く

## 経緯
なぜかGmailには再送する機能がないので、定例のメールを楽にするべく自動作成用のツールを作って利用していた。[^tool]
そしてせっかく作ったので共有しようとした。

そこで、例えば自分の所属するチーム全員に定時で送るメールがあったとして、そのひな形をみんなで使いまわせるようにしたいとする。
宛先を自分も含めチーム全員にするなら、いちいち自分にも送られてきて邪魔だ

ということで、メールアドレスのリストから自分のアドレスを取り除くための関数を作った。[^needs]


## 作った関数[^static]


```javascript
/**
 * 宛先のアドレスから実行ユーザーのアドレスを削除するための関数
 * @param {string} emails - csv形式のメールアドレス
 * @return {string} csv形式のメールアドレス 引数から実行ユーザーのアドレスを取り除いたもの 
 */
function removeActiveUserEmail(emails){

    // ユーザーのアドレスを取得
    const activeUserEmail = Session.getActiveUser().getEmail();

    // 正規表現をもちいるため、探したいアドレスのピリオドをエスケープする。
    const escapedEmail = activeUserEmail.replace(/\./g, "\\.");

    // 後述のメールのフォーマットに合うような正規表現の文字列を作成
    let pattern = "^\s*(?:" + escapedEmail + "|.+<" + escapedEmail + ">)$";
    let re = new RegExp(pattern);

    // カンマで区切られた文字列を配列にし、自分のアドレスのみ取り除き他は元のcsv形式に戻す。
    // replace は改行の半角スペースへの置き換え。ひな形を Spreadsheet で管理しており、その視認性の関係で改行を入れていることがあるので
    const splitedEmails = emails.replace(/[\r\n]/g, " ").split(",");
    let resultEmails = [];
    for (const email of splitedEmails){
      if(!email.match(re)){
        resultEmails.push(email);
      };
    };
    return resultEmails.join(",");
  };
```

---
以降は補足
といっても処理についてはコメントにある通りなので、

## 補足
### メールの宛先（CC）のフォーマット
メールのあて先は以下のようなcsv風な形式になっている。（Gmailの宛先をコピーして確認）
`山田太郎 <yamada.taro@example.com>, 山田花子 <yamada.hanako@example.com>, noname@example.com`
名前の情報がある人は `名前 <アドレス>`、ない人は `アドレス`そのままで、宛先が複数ある場合はカンマで区切られているらしい。

おそらく正規表現で直接置換をすることも可能だとは思うが、今回はそこまで正規表現にこだわる理由もなかったので、先にカンマ区切りで配列に分け、そこから1件ずつテストして、ヒットした要素だけ除外するという処理にした。

## 参考
[正規表現 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions)
[Googleスプレッドシートでの改行方法と、改行の検索 ＆ 置換方法 | WWWクリエイターズ](https://www-creators.com/archives/127)
[GAS で呼び出し元のアカウントを判定して処理を振り分ける - Qiita](https://qiita.com/yuuhu04/items/e18bff654d8b7e100d42)

[^tool]: Spreadsheetに書いたテンプレから毎日Gmailの下書きを作成するというもの。こういうのは探せばいくらでも記事が出てきそうなのでこれについては省略。
[^needs]: どのみ現状では「お疲れ様です、〇〇です」みたいな文頭の挨拶とか署名は手動で追加するか、ツール自体をコピーして自分用に書き換えてもらう必要があるのでこの関数の必然性はかなり怪しいのだが...。Contact経由でユーザーの名前も取ってこれればいいのだが未検証。
[^static]: 実際の運用では関数ではなく自作の'DraftTemplate'クラスの静的メソッドにして呼び出している。
NuxtJSでgenerate時のみmicroCMSのAPIキーを隠す

microCMSが来てるとのことで、
NuxtJS + microCMS で、 Jamstackなサイトを作っていたら気になるツイートが。。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">NuxtのJamstack構成においてAPIキーの扱い方について書きました。<br>process.env.API_KEYではブラウザからソースコード上で見えてしまうのでご注意ください。<br>privateRuntimeConfigを用いる方法を紹介しています。<a href="https://t.co/0eNZgJSWLW">https://t.co/0eNZgJSWLW</a> <a href="https://twitter.com/hashtag/microcms?src=hash&amp;ref_src=twsrc%5Etfw">#microcms</a></p>&mdash; 柴田 和祈｜microCMS (@shibe97) <a href="https://twitter.com/shibe97/status/1285142239501406208?ref_src=twsrc%5Etfw">July 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

**おお、やばい、、ほんとにむき出しになってる。。悪戯されるやん。。**

上記の記事のおかげで事なきを得ましたが、１点問題があり、上記のみの設定だと、
開発中にAPIの認証が出来なくなってしまうんですよね。

<img width="554" alt="スクリーンショット 2020-07-28 20.46.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30049/ee38839d-4181-ee35-b746-2f21b464eec1.png">

## とりあえず公式のブログ見る

https://ja.nuxtjs.org/blog/moving-from-nuxtjs-dotenv-to-runtime-config/#the-new-runtime-config-values-are

#### privateRuntimeConfig
サーバーサイドで公開される、publicRuntimeConfigを上書きする。

#### publicRuntimeConfig
フロントエンドで公開される

**「publicRuntimeConfig」を使えばいいんじゃない、、？**

## 設定してみる

```:.env
MICROCMS_API_KEY=@@@@@@@@@@@@@@@@@@@@@@
```

```js:nuxt.config.js
require('dotenv').config()
const { MICROCMS_API_KEY } = process.env
const isDev = process.env.NODE_ENV === 'development'

module.exports = {
  mode: 'universal',
  target: 'static',
  [isDev ? 'publicRuntimeConfig':'privateRuntimeConfig'] : {'apikey': MICROCMS_API_KEY },
  // 以下省略
}

```

とりあえずこれで、
ローカルで開発中=> 無事にAPIにアクセス出来て、
公開時（generate）=> APIkeyを隠蔽出来た。

みんなどうしているのだろうか。
教えてください。
【備忘録：javascript】HTMLcollectionでのforEach

# document.getElementsByClassNameで取得したクラスが回せなかった
```javascript:hoge.js
let elem = document.getElementsByClassName('m-hoge');
```
上記のように特定のクラスを取得しそのテキストを手に入れたかったのですが、

```javascript:hoge.js
let elem = document.getElementsByClassName('m-hoge');

elem.forEach(function(item) {
  console.log(item.innerHTML);
});
```
このようにforEachをしても取れませんでした。

## HTMLcollectionは配列ではない
参考にさせていただいたページが分かりやすかったのですが、**HTMLcollectionはそもそも配列ではない**とのことです。
取得しているときは配列っぽいですが、配列でないため、配列で使用するメソッド（今回でいうとforEach）が使用できないのです。

## 対策
対策として、Array.prototypeを使用して対応することができました。

```javascript:hoge.js
let elem = document.getElementsByClassName('m-hoge');

Array.prototype.forEach.call(elem, function(item) {
  console.log(item.innerHTML);
}
```
## まとめ
分からないことがたくさんあるので、しっかり理解して進めて行きたいと思います。


## 参考ページ
https://hacknote.jp/archives/21892/
Pytorchを使うと強制再起動する謎問題の解決法

# 概要
Pytorchで学習及び識別を行っていたところ、再起動を繰り返す謎の問題が発生した。この問題を解決すべく、あらゆる手を尽くし調査を行い、解決にまでこぎつけたので備忘録として残しておく。

# 前提
前提条件を記す。

## マシン構成
・マザーボード: WS-X299 SAGE系
・CPU: i9-9920X

## 調査内容
突然と再起動を繰り返すため以下の調査を行った。

・Pytorchを実行すると急にPCが再起動を始める。(1回目は動作するが2回目は必ず落ちる等)
・CPU温度に異常なし `$ watch -n 0.1 sensors`
・CPU使用率及びファンの回転に異常なし `$ top`
・GPU使用率及び温度に異常なし `$ nvidia-smi`
・ジャーナルログに異常なし `$ journalctl`
・再起動ログに異常なし　`$ last reboot`
・GUI系に異常なし　`$ less /var/log/xorg.0.log`
・syslog系に異常なし　`$ less /var/log/syslog`
・message系(syslog)に異常なし　`$ less /var/log/message`
・kernel系に異常なし　`$ less /var/log/kern.log`
・kernel panic off `$ kernel.panic = 0`
・電源系変更 (物理)
・電圧系監視 (物理)
・消費電力監視 (物理)
・GPU配線変更 (物理)
・CUDA 9.x系～11.x系で発生
・Pytorchのバージョンも関係ないようである

どのログにも異常は見られなかった。
一体私が何をしたっていうんだ。

# 解決方法
解決法…それは「ターボモードをソフトウェア上でオフ」にする。

``` bash
$ sudo su root
$ echo "1" > /sys/devices/system/cpu/intel_pstate/no_turbo
```
これにより、かなり発生頻度を下げることができる。なんじゃこれは…

# 原因
どうやら問題はX299ボード及びi9-9920Xの構成の際に、高負荷を掛けるとX299に搭載されたターボモード(Turbo Boost Max Technology 3.0)が働き、その不具合で落ちるそうである。なお、BIOSでターボモードを切っても意味がないという徹底ぶり。
ElasticsearchのScriptを使用して検索を行おう！


## はじめに

Elasticsearchでは、Search APIで色々検索ができます。
Scriptを使用せずとも大体の検索が可能です。

ただ、時々一筋縄ではうまく行かないようなことがあります。

例えば、特定の時間(10~11時まで)のデータを取りたい,文字列を操作してから検索をかけたい
などがあるかなぁと思います。
(↑ index作成時にHourカラムを作成すれば簡単にできますが、timestampがあるのにわざわざ作りたく無い)

## データ構造
mappingが以下のような物とします。
indexがarticle 
fieldがtopicとtimestamp(epoch_second)という単純な物です。

```
{
  "article" : {
    "mappings" : {
      "properties" : {
        "topic" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
        "timestamp" : {
          "type" : "date",
          "format" : "epoch_second"
        }
      }
    }
  }
}
```

## やること
時間範囲でarticleを検索する。(例 : 全データ中の10~11時のデータだけ取得する。
これは、Search APIのrangeでは実現できません。(非連続時間のため)

上記の理由から、Scriptを使用します.

## 実行
下記は毎日の10~11時のデータを取得するqueryです。

```
{
    "query": {
        "bool" : {
            "filter" : {
                "script" : {
                    "script" : {
                        "source": """
                        ZonedDateTime zdt = doc.timestamp.value.withZoneSameInstant(ZoneId.of('Asia/Tokyo'));
                        int hour = zdt.getHour();
                        return hour >= params['min'] && hour <= params['max'];
                        """,
                        "lang": "painless",
                        "params": {
                          "min" : 10,
                          "max" : 11
                        }
                     }
                }
            }
        }
    }
}
```

## 説明
paramsでsourceで使う変数を設定しています。今回の場合は、10~11時のデータを取得するので10,11が設定されています。
sourceで、painlessというスクリプトでfilter条件を指定しています。

```
zdtでtimestampフィールドの値を取得&TZをJSTに変更しています。
hourで何時かの情報を取得しています。
return文でhourが条件に適しているかを判断しています。
```
Amazon Linux 2でGoをインストールする

## EC2にインストール

### 利用できるバージョンの確認

```
# amazon-linux-extras list | grep golang
 29  golang1.11=latest        enabled      \
```

### インストール

```bash

amazon-linux-extras install golang1.11
```

### GOPATHの追記

```bash
export GOPATH="$HOME/go"
export PATH=$PATH:$GOPATH/bin
```

### インストール確認

```
# go version
go version go1.13.4 linux/amd64
```
【JavaScript】ライブラリ化しておく便利な3つの自作共通関数を記録

## 前提
- *※記載の共通関数は、各環境によって動作しない場合がある。  
→ES2015からES2019で利用できるメソッドも利用しているため*

## 1. chunk
- **指定の数に応じて、対象配列を分割する関数**

### コード

```javascript:lib.js
const chunk = (arr = [], size = 3) => {
	return Array.from({
		length: Math.ceil(arr.length / size)
	}, (v, k) => arr.slice(k * size, k * size + size))
}
```

### 使い方

```javascript:index.js
import { chunk } from './lib.js'

// 対象配列定義
const target = [1,2,3,4,5,6];

// 利用 : chunk(対象配列, 分割サイズ)
console.log(chunk(target,2));
console.log(chunk(target,4));

/*
出力結果: 
[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]
[ [ 1, 2, 3, 4 ], [ 5, 6 ] ]
*/
```

### 内容
- 処理内容としては下記。
  - 1. 引数から受け取る値から、対象配列の分割数を求める。
  - 2. 求めた分割数からlengthプロパティを持つ配列風オブジェクトを作成
  - 3. 作成した配列風オブジェクトの各値に対して、from処理で反復slice処理と変換を行う。

## 1. diff
- **指定の各配列の差分を求める関数**
- つまり、**重複していない一意の値を求める。**

### コード

```javascript:lib.js
const diff = (...manyArgs) => {
  const targetArr = manyArgs.flat();
  const map = new Map();
  targetArr.forEach(a => map.set(a, (map.get(a) || 0) + 1));
  return targetArr.filter(a => map.get(a) === 1);
}
```

### 使い方

```javascript:index.js
import { diff } from './lib.js'

// 対象配列定義
const first = [1,2,3,4,5];
const second = [1,2,3];
const third = [5,6,7];

// 利用 : diff(対象配列1, 対象配列2, ...)
console.log(diff(first,second));
console.log(diff(first,second,third));

/*
出力結果: 
[4,5]
[4,6,7]
*/
```

### 内容
- 処理内容としては下記。
  - 1. 可変引数で受け取った二次元配列をflat処理で一次元に変換
  - 2. map定義して、反復処理で各値に存在確認処理を行った値を格納していく。
  - 3. 格納したmapの値によって、一次元化した配列に対してfilter処理を行う。

## 1. filterObj
- **指定の条件で対象のオブジェクトを選別(フィルタリング)する関数**

### コード

```javascript:lib.js
const filterObj = (target,condition) => {
  return Object.fromEntries(Object.entries(target).filter(condition))
}
```

### 使い方

```javascript:index.js
import { filterObj } from './lib.js'

// 対象オブジェクト定義
const obj = {
  id: 11,
  name: '',
  score: 89,
  hasSkill: false
}

// 利用 : filterObj(対象オブジェクト, 条件)
console.log(filterObj(obj, ([key,value]) => value === 11));
console.log(filterObj(obj, ([key,value]) => !!value)); // 値が正のものを抽出

/*
出力結果: 
{ id: 11 }
{ name: 't-o-d', score: 80 }
*/
```

### 内容
- 記載している処理内容としては下記。
  - 1. 第一引数で受け取ったオブジェクトをentries処理で配列へ変換。
  - 2. 変換した配列に対して、第二引数で受け取った条件式でfilter処理を行う。
  - 3. fromEntries処理で、再度オブジェクトへの変換処理を行う。


## 参考
- https://stackoverflow.com/questions/39599036/javascript-remove-unique-elements-from-array
- https://stackoverflow.com/questions/44025984/how-to-filter-an-object-with-its-values-in-es6
Unity 3D入門 #8 [ライトの実装&一人称視点 ]

ホラーゲームによくあるライトの実装をします。

まずは懐中電灯の実装ということで、下のURLを参考に行なっていきます。

参考URL：https://gametukurikata.com/light/flashlight

Unityに初めからついているDirection Lightがついているとライトの機能の確認が難しいので、チェックを外して世界を暗闇にします。

また、そのままだと、懐中電灯によるSpot Lightのみが光源となってしまうため、下のURLにあるPoint Lightをプレイヤーの場所に設置します。
ライトの種類参考URL：https://creator.cluster.mu/2020/04/15/unity-light/

<img width="834" alt="スクリーンショット 2020-07-29 13.07.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670403/d6ebff6d-c464-1008-fef9-513ecba00f12.png">

ホラーゲームっぽくなってきました。

次に、カメラを今の3人称視点から一人称視点に変更します。

参考URL：https://codegenius.org/open/courses/24/sections/117

<img width="818" alt="スクリーンショット 2020-07-29 13.13.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670403/d4e97a16-5f5c-4c40-72fb-30b9b84f8e63.png">

とりあえず一人称視点とすることができました。あとはMain Cameraを基準としたプレイヤーの動きの変更とカメラアングルの変更コードを書いていきます。

```
Vector3 tmp = player.transform.position;  // Playerの位置情報を取得
Vector3 cam = new Vector3(tmp.x, tmp.y + 1.2f, tmp.z);
this.transform.position = cam;
```

ここで、参考URLではプレイヤーとカメラに親子関係を持たせていますが、このゲームでの実装ではカメラとプレイヤーを別々のオブジェクトとして、カメラは単純にプレイヤーの位置を追従するようにします。

```
Vector3 angle = this.transform.eulerAngles;  // 現在のカメラアングル
if (Input.GetKey(KeyCode.D)) { angle.x += Time.deltaTime * _positionStep; }
if (Input.GetKey(KeyCode.A)) { angle.x -= Time.deltaTime * _positionStep; }
if (Input.GetKey(KeyCode.E)) { angle.y += Time.deltaTime * _positionStep; }
if (Input.GetKey(KeyCode.Q)) { angle.y -= Time.deltaTime * _positionStep; }
this.transform.eulerAngles = angle;  // カメラアングルの変更
```

カメラアングルの変更はDAEQで行うようにしました。

また、一人称にするとプレイヤーがチラチラカメラに写ってしまい目障りなので、プレイヤーオブジェクトはカメラに映らないようにします。
参考URL：https://teratail.com/questions/155158

原因不明ですが、SubCameraを使用すると十字キーでプレイヤーを移動した時に床をすり抜けるバグが発生したので、Main Cameraを一人称視点にしました。

また、Main CameraにSpot Lightを親子関係にしたらうまく動作しなかったので、Spot Lightは個別のオブジェクトとしてプレイヤーの位置とカメラの角度を追うようにしました。

```
private GameObject cameraObject;
private GameObject player;
void Start() {
    cameraObject = GameObject.Find("Main Camera");
    player = GameObject.FindWithTag("Player");
}
void Update() {
    Vector3 tmp = player.transform.position;
    Vector3 light = new Vector3(tmp.x, tmp.y + 1.2f, tmp.z);
    this.transform.position = light;
    this.transform.forward = cameraObject.transform.forward;
}
```

これで、できたものが以下となります。

![ezgif-4-b66f47b780e3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670403/e2628cd5-611e-96e5-cc53-c6c83827cbb6.gif)

割と不具合が多く大変でした。
#macOS Homebrewのアンインストールでシェルがぶっ飛んだ時の対処法

[Homebrewをアンインストールする手順](https://weblabo.oscasierra.net/homebrew-uninstall/)は正しい記事[^1]ですが、これをこの通り実行する前に確認しなければいけないことがあります。
[^1]: [公式のアンインストール方法](https://github.com/homebrew/install#uninstall-homebrew)はbashに切り替わってました。

それは、__homebrewによってシェルをインストールしてないか？__です。
その場合はシェルを一度Macのデフォルトに戻さないといけません。

私はCatalinaがzshを基本シェルに採用する前からzshを使ってましたが、これがhomebrewを使用してインストールしたものであったため、アンインストールのタイミングで一緒に消えてしまいました。

ターミナルが`$ chsh`を受付なくなったときは詰んだと思いました。ええ、過去形です。

ではどうすれば良いのか？それは

#ターミナルの新規コマンドから`chsh`と打つ

です。
<img width="385" alt="スクリーンショット 2020-07-29 15.20.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10766/2277d945-21ad-1794-8549-0dfa23fb0ba6.png">
<img width="518" alt="スクリーンショット 2020-07-29 15.21.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10766/f76301b4-2a4b-cfa4-848d-a64c160cbdda.png">

これで、自分のパスワードを聞かれますので正しく入力し、シェルの絶対パスを書き換えることができました。
<img width="637" alt="スクリーンショット 2020-07-29 15.25.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10766/639e4987-7dca-8b7b-ac1a-324d4a1df634.png">

一時は本当に詰んだと思いTime Machineから再起動も視野に入ったのでコマンド一発で直ったのは大きいですね。
同じ境遇の人のところにこの記事が届けば幸いです。
NuxtJSで Formrunで作ったフォームがうまく動かない時の対処方

## 注意
この記事を書いている時の
formrunのsdkはバージョン v2.2.0 です。
サービスのアップデートによって仕様が変わる可能性があるので、
ご注意ください。

## 問題

formrun (フォームラン)
https://form.run/ja

で、今流行りの「Jamstack」のフォームを作ろうと思い、
NuxtJSでゴリゴリ実装していると、とある問題に直面しました。

#### ◎ contactページに直接飛んだ場合
→ 例えば、空欄にして、submitを押すと、ちゃんとバリデートが動きます。
<img width="751" alt="スクリーンショット 2020-07-29 14.40.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30049/2211be36-b60a-335e-4345-b3c0035d80f9.png">


#### × TOPページ ⇨ contactページと「nuxt-link」タグで遷移した場合

→ フォームが空のままでもそのままsubmit出来てしまう。

<img width="704" alt="スクリーンショット 2020-07-29 14.47.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30049/6187107d-0285-a9f0-2636-d8dbdb275c98.png">

## 原因
NuxtJSでは、静的にhtmlを生成させているはずなのに、、preloadが原因なのか。
通常のページ遷移と違って、formrunのsdkを読み込んだ時に、フォームのhtmlが無いからとか？
この辺が曖昧だが、多分読み込みの順序の問題だと思う。
SPAとか非同期遷移のサイトでも同じ問題が起きる気がする。（知らないけど）

## 問い合わせる
formrunカスタマーサポートに問い合わせる。
夜に送ったら翌日すぐ返信くれました。

#### 自分
*他のページから非同期でアクセスした際は、バリデートがうまく動作しません。(nuxt.jsで構築しております)。そのようなページの場合、どうすれば正常に動作するでしょうか？ページ遷移の際に専用のメソッドを叩く、等ありましたらご教授いただけますでしょうか？*

**良く考えたら非同期じゃないけど、これの方が伝わりやすいから結果オーライ**


#### 運営からのご回答

*こちらにつきましては、
動的に生成されたフォームに
バリデーションを利用する方法といたしまして、
下記の方法にて、動作を確認していただけますと幸いです。*

```
(1). ページロード完了するまでに待ち
(2). `window.Formrun._reset()` を実行し、formrun.jsのリセットを行う。
(3). `window.Formrun.init('.formrun')` を実行し、formrun.jsの再適応を行う。
```

**なるほど〜**

## 解決コード

これで直った。

```js:pages/contact.vue

export default {
  mounted() {
    if (process.client) {
      this.loadFormrunScript()
    }
  },
  methods: {
    initFormrun() {
      window.Formrun._reset() // (2)の処理
      window.Formrun.init('.formrun') // (3)の処理
    },
    loadFormrunScript() {
      if (window.Formrun) { // 一度アクセスしたら、window.Formrunがあるので、(2),(3)の処理を呼んで終わり
        console.log('repeat init')
        this.initFormrun() 
        return 　// 2回目からはここで終わり
      }
　　　// 初回のみ SDKを ロードする
      new Promise((resolve, reject) => {
        // (1). 該当スクリプトを動的にロード
        const script = document.createElement('script')
        script.addEventListener('load', resolve)
        script.addEventListener('error', reject)
        script.src = 'https://sdk.form.run/js/v2/formrun.js'
        document.head.appendChild(script)
      }).then(() => {
        console.log('init!') 
        this.initFormrun() // (2),(3)の処理を呼ぶ
      })
      .catch(() => {
        console.log('err')
      })
    },
  },

```

## 最後に
多分、ReactでSPAを構築する時などにも同じ問題が起きそうな気がしますので、試す価値ありかと。
Jamstackが流行ってくると、PHPでフォームを作るのではなく、「formrun」のような、クライアントサイドのみで完結するフォームのサービスが流行ってくる気がします。
Bazaarの初期設定

# Bazaarとは
分散バージョン管理システムです。
ブランチやマージが簡単にできるように設計されています。
詳細な説明や歴史的な背景は下記サイトが詳しいです。

_公式HP_
https://bazaar.canonical.com/en/

_Wikipedia_
https://ja.wikipedia.org/wiki/Bazaar

>「Gitがデファクトスタンダードになりつつある一方、Bazaarは月に2,3のコミットがあるだけでほぼ死んだ状態にある」（Wikiより抜粋）

なおRHEL8からはbzrパッケージは配布されなくなったようです（死亡確認・・・）

特別な理由がなければ、素直にGitを使うのがいいと思いますが、
本記事では何らかの理由からｂｚｒを使わなければならなくなった人のために
とりあえず使い始めるまでの初期設定を記載します。

# 設定方法

Linuxの場合、yum(dnf等)で取得できるならそれでOK。

```
$ sudo yum install bzr
```

初期設定としてbzrにユーザー情報を登録します。

```
$ bzr whoami "USER_NAME <MAIL_ADDRESS>"
```

# QBzrプラグインの追加
QBzrプラグインを追加すると、qdiffやqlogなどのグラフィカルな機能が使えるようになり、便利です。
こちらもyumで入れておきましょう。

```
$ sudo yum install qbzr
```

http://doc.bazaar.canonical.com/explorer/en/guide/index.html

# まずはじめに、レポジトリの登録

まず最初に管理したいプロジェクト（ソースコード）をレポジトリに登録する必要があります。
やり方は簡単で、管理したいプロジェクトのディレクトリにてbzr initコマンドを実行します。
そのため、新期プロジェクトごと実行する必要があります。

サンプルとして/tmp/projectを作ります。

```
$ mkdir /tmp/project
$ cd /tmp/project
$ bzr init 
```
これにより.bzrディレクトリが作成され、「project」以下のツリーが
bzrで管理できるようになります。

# ファイルを追加
bzr addコマンドで変更を記録したいファイルを追加します。
ここではREADMEファイルを追加してみます。

```
$ touch README (project配下にモジュールを配置)
$ bzr status  （ステータス表示）
unknown
  README

$ bzr add README（READMEを追加する）
$ bzr status   　（ステータス表示）
added:
  README
```

# ファイルを変更する、変更を確認する
bzr diff や bzr qdiff コマンドで変更内容を確認します。

```
$ emacs README   　（例として「HELLO!WORLD!」と書いてみた）

$ bzr status   　（ステータス表示）
modified:
   README

$ bzr diff   　（diffを表示）
=== modified file 'README'
--- README   1970-01-01 00:00:00 +0000
+++ README   2019-12-27 14:23:29 +0000
@@ -0,0 +1,1 @@
+HELLO!WORLD!
```


# リモートのレポジトリサーバーにコミットする
ローカルPCからリモートのレポジトリサーバーにコミットしてみます。

```
$ bzr commit   （ローカルにコミット）
$ bzr push bzr+ssh://<USER>@<SERVER:PORT>/home/bzr/project
               （リモートのレポジトリサーバーにコミット）
```

上記のように毎回2段コミットするのは面倒なので、bind設定すると便利です。
以降、bzr commitはリモートへのコミットになります。

```
$ bzr bind bzr+ssh://<USER>@<SERVER:PORT>/home/bzr/project
$ bzr commit   （リモートにコミット）
               （ローカルにコミットしたい場合は--local）
```

bzr は SSH, HTTP, SFTP 等を使用してブランチにアクセスすることができます。
上記の例は、bzr+sshの場合を記載しています。

以上です。

より詳細な使い方はチュートリアルをご参照ください。
http://doc.bazaar.canonical.com/latest/ja/index.html

#余談
以下のブログで、Bazzarの開発者の失敗談がご紹介されていました。
エンジニア目線で見ると、なかなか趣深い内容です。

_Bazaar-NG: 分散バージョン管理システムを7年ハックしてきて_
https://cpplover.blogspot.com/2014/01/bazaar-ng-7.html?m=1
docker-machine active 切り替え

# Machine がアクティブにならない・・・。

```
$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER      ERRORS
default   -        virtualbox   Running   tcp://192.168.99.102:2376           v19.03.12
```

入力コマンド

```
$ DOCKER_HOST=tcp://192.168.99.103:2376
```

結果

```
$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER      ERRORS
default   *        virtualbox   Running   tcp://192.168.99.102:2376           v19.03.12
```

おっけい！
ほかにやり方あった気がする。教えて。


参考文献
https://stackoverflow.com/questions/33211767/how-is-a-docker-machine-marked-as-active
dreddで認証付きのAPIをテストする

しばらく書いてなかったけどメモ程度に

# dreddとは

[dredd](https://dredd.org/en/latest/index.html)は[openapi(swagger)](https://swagger.io/)や[API Blueprint](https://apiblueprint.org/)の定義を読み込んでテストを実行してくれる便利なツールです。
例えば `localhost:8080` でAPIサーバを動かして

```sh
dredd openapi/schema.yaml http://localhost:8080/v1/
```

のようにすればschema.yamlに定義されたAPIの定義に従ってリクエストを送り、レスポンスが仕様に従っているかテストしてくれます。

が、ログインしてtokenを貰ってそのtokenでアクセスするというようなAPIはそのままではテストできません。
[hooks](https://dredd.org/en/latest/hooks/index.html)という仕組みを使うと、レスポンスからtokenを取得して以後はそれを使う、といった動作が可能になります。

# dredd hooks

[ドキュメント](https://dredd.org/en/latest/hooks/index.html)にある通り、hooksは様々な言語で書くことができますが、とりあえずdreddと同じnode.jsでやってみます。
（なぜかと言うと、dockerのコンテナ一つで完結させたい場合に処理系を複数入れるのが面倒だから）

## schema

例えばこんなschemaがあるとします。（端折っているのでこのままでは動きません）

```schema.yaml
openapi: 3.0.2
info:
  title: login api sample
  version: 1.0.0
servers:
  - url: http://localhost:8080/v1
    description: development env
paths:
  /sign_in:
    post:
      description: Sign In
      operationId: signIn
      requestBody:
        required: true
        content:
          application/json; charset=utf-8:
            schema:
              $ref: '#/components/schemas/AuthRequest'
            example:
              email: "foo@bar.jp"
              password: "password"
      responses:
        '200':
          description: successfully authorized
          content:
            application/json; charset=utf-8:
              schema:
                $ref: '#/components/schemas/Auth'
components:
  schemas:
    Auth:
      type: object
      description: authorized response
      properties:
        token:
          type: string
          example: "abcdefgh12345678"
    AuthRequest:
      type: object
      properties:
        email:
          type: string
        password:
          type: string
      required:
        - email
        - password
```

## hooks

hooksは任意のディレクトリに置けますが、 `test/hooks/sign_in.js` に置くものとします。

```sign_in.js
var hooks = require('hooks');
var stash = {};

// hook to retrieve session on a login
hooks.after('/sign_in > POST > 200 > application/json; charset=utf-8', function (transaction) {
  stash['token'] = JSON.parse(transaction.real.body)['token'];
});

// hook to set the session cookie in all following requests
hooks.beforeEach(function (transaction) {
  if(stash['token'] != undefined){
    if (transaction.expected.statusCode != "401"){
      transaction.request.headers['Authorization'] = "Bearer " + stash['token'];
    };
  };
});
```

## 実行

```sh
dredd openapi/schema.yaml http://localhost:8080/v1/ --hookfiles="test/hooks/*.js"
```

すると最初に `/sign_in` にアクセスした時のレスポンスから `token` を保存し、以降はAuthorizationヘッダに埋め込んでくれます。
ただし `401` のテストの場合は除外するようにしています。

# 注意点

* テストはschemaの順番に実行されるので、先頭に `/sign_in` を書いておかないとそれより前のテストは失敗します。
* APIの実装によりますが、 ログアウト時にtokenを無効化するようなAPIの場合、ログアウトは最後に書かないと途中でtokenが無効化して以後は失敗します。

その他、hooksを上手く使うと404などの異常系もテストできて便利です。

# おわりに

swaggerもdreddも最近使い始めたばかりなので、間違い等ありましたらご指摘ください。
他にもTIPSありましたら教えてくれると嬉しいです。