OmniAICreator/Qiita-1.07M huggingface dataset:
Azure AD B2C でのサインアップ時に招待コードを使うケースでの勘所

Azure AD B2C でのサインアップ時に招待コードを使うケースに関して検証する機会がありました。素のユーザフローと違いがあったので、ポイントをまとめていきたいと思います。

[こちらのサンプル](https://github.com/Azure-Samples/active-directory-b2c-node-sign-up-user-flow-invitation-code) を実装すれば分かるところでしたが、ポイントの頭出しの意義があると思って書きます。



# 招待コードのケース概要

こんな感じの連携とフローをイメージしています

![AzureADのフロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110482/f796f525-dbb0-b4f6-c0b9-40dea026d206.png)



# 入力を増やすためにカスタム属性を追加

このように InvitationCode 入力欄を設けるには カスタム属性 の追加が必要です。

![スクリーンショット 2021-12-23 17.35.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110482/3081d337-bfb7-62da-5102-1e8596e0b937.png)


カスタム属性を取得するには先ほど挙げたサンプルを漏らさず実行することが必要です。
カスタム属性をコード中で取得するには[ここ](https://github.com/Azure-Samples/active-directory-b2c-node-sign-up-user-flow-invitation-code/blob/main/InvitationCodeAzureFunction/index.js#L28)を読みましょう。  
以下のように環境変数からアプリ番号を入れてあげる必要があります。

```
const invitationCodeAttributeKey = "extension_" + process.env["B2C_EXTENSIONS_APP_ID"] + "_InvitationCode";
```


# 招待コードの確認には自前アプリが挟まるのでAPIコネクターが必要

招待コードの確認には自前アプリが挟まるのでAPIコネクターが必要です。
APIコネクターが利用できるタイミングは[こちら](https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/api-connectors-overview?pivots=b2c-user-flow#where-you-can-enable-an-api-connector-in-a-user-flow)を参照してください。

# 検証結果の応答の出し方

応答のアクションが 3パターンがあります。

- OK(Continue)
- 再入力を求める(ValidationError)
- 失敗(ShowBlockPage)

アクションの実行させるためのリクエスト形式がそれぞれ異なるので注意です。
特に ValidationError は癖があります。(response body に status:400 を入れるなど)

詳しくは[応答の例](https://docs.microsoft.com/ja-jp/azure/active-directory/external-identities/self-service-sign-up-add-api-connector#example-responses)を見てください。




勘所紹介は以上です。 :bow:



# 参考サンプル

招待コードのサンプル (js)

https://github.com/Azure-Samples/active-directory-b2c-node-sign-up-user-flow-invitation-code

シンプルなバリデーション(Python)

https://github.com/Azure-Samples/active-directory-python-external-identities-api-connector-azure-function-validate
Node.js環境構築に関することのメモ

個人的メモです。随時追記予定。
Raspberry pi os 64bit(多分ubuntu系)で確認しています。

## Node.jsのインストールとアップデート。


```sh:
$ sudo apt install nodejs
$ sudo apt install npm
```

nvmでNode.jsをインストールするよりaptでインストールしてnでバージョンをアップデートした方が良い気がした。

```sh:
$ sudo npm install -g n
#バージョン確認
$ n --stable
$ n --latest
#Node.jsのインストール
$ sudo n latest
#バージョン変更
$ sudo n
```

```sh:
#npmのアップデート
$ sudo npm update -g npm
```

ここで一旦シェルを再起動しましょう！

参考：https://parashuto.com/rriver/tools/updating-node-js-and-npm

## Node.jsとnpmの削除
aptでアンインストールできなければこの手で良い...かも。

```sh:コンソール
sudo rm -rf /usr/local/bin/npm 
sudo rm -rf /usr/local/share/man/man1/node* 
sudo rm -rf /usr/local/lib/dtrace/node.d
rm -rf ~/.npm
rm -rf ~/.node-gyp
sudo rm -rf /opt/local/bin/node
sudo rm -rf /opt/local/include/node
sudo rm -rf /opt/local/lib/node_modules
sudo rm -rf /usr/local/lib/node*
sudo rm -rf /usr/local/include/node*
sudo rm -rf /usr/local/bin/node*
```
参考：https://stackoverflow.com/questions/32426601/how-can-i-completely-uninstall-nodejs-npm-and-node-in-ubuntu

## 知っていると良さそうなこと
- Apache2とnode.jsの共存 https://qiita.com/ytakzk/items/e4422555549b069e3d90

## 便利なモジュール＜アプリの実行系＞

- forever アプリを起動・自動再起動等してくれる（常時起動させておくアプリに便利）
https://qiita.com/chihiro/items/24ca8ac81cb20c22b47e
- nodemon アプリのコードに変更があると自動的に再起動してくれる（アプリを作るのに便利）https://qiita.com/mitsuhiro_K/items/429ca479b4e191bfea4d

## 便利なモジュール＜？＞系

- node-canvas HTML(js)のcanvasをnode.js側（サーバー）で使える https://qiita.com/tags/node-canvas

## Playwrightを使う
Rashberry piとJeston Nano。

```sh:
$ npm install playwright-core
```

```js:example.js

const playwright = require('playwright-core');

(async () => {
    const browser = await playwright.chromium.launch({executablePath:'/usr/bin/chromium-browser'});
    const context = await browser.newContext();
    const page = await context.newPage();
    await page.goto('https://yahoo.co.jp/');
    await page.screenshot({ path: `example.png` });
    await browser.close();
})();

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702338/4a9da33e-88d1-8f53-80e2-1eb5fecd0736.png)
KH Coder を Docker で動かす(2022)

# これはなに？
この記事通りに最後までやれればたぶん KH Coder を Docker で動かすことが出来ます。でも手作業がかなり入るので大変かも。

## github から clone 
今回の成果を github においてあります。

https://github.com/sinchiba-backyard/NL2E

docker-compose.yml の内容とかを確認しておきましょう。
あとで mysql のポートはふさいだ方がいいかも。

## KH Coder のインストール

KH Coder をインストールします。パッチも当てます。自分がパッチを作った経緯は忘れてしまいました(今検証するとそもそもパッチいらなさそう)。パッチの内容は DB 名として mysql からkhcoder に変えました。mysql 8.0.27 ではセキュリティ的に厳しくなったのが理由のはずです。固定的に DB の名称を khcoder にしました。

なお、この変更の為 mysql で初期化が必要になりました。createdatabase とか create user とか grant とかね。特に grant はセキュリティに関わるので注意が必要です。

```
$ git submodule init
$ git submodule update
$ cd KHCoder/khcoder
$ patch -p1 << ../../khcoder.diff
```
[注意] あとで検証したらパッチいらないみたい。再確認したら消しちゃうよ。

## docker-compose で起動

 X-Windows が動いている環境で docker-compose で up します。
すると xeyes が動くはずです。この時点ではセキュリティの甘くなった mysql と xeyes が立ち上がっているだけです。

こんな感じで最近の mysql のセキュリティ強化を無視する設定になっているので注意してください。（他の DB と共存させない。ほかの人に触らせない)

```
[client]
loose-local-infile=1

[mysqld]
default_authentication_plugin=mysql_native_password
```

## mysql の設定
docker 内に入って mysql の設定をします。ここでもセキュリティを甘くしていることに注意。特に khcoder というユーザに全権を与えています。そして kh_coder を一旦立ち上げます。

```
$ docker cp mysql.txt nl2e_nl2e_1:/
$ docker inspect nl2e_mysql_1
$ docker exec -it nl2e_nl2e_1 /bin/bash
# mysql --host 172.XX.0.2 -u root -p < mysql.txt
# cd /KHCoder/khcoder/
# /usr/bin/perl ./kh_coder.pl
```

## coder.ini の設定
一旦 KH Coder を立ち上げると KHCoder/khcoder/config/coder.ini が作成されます。それを少し編集する。特に IP アドレス。 docker の inspect でみた IP アドレスを使うのがポイントです。

```
sql_host      172.30.0.2
```

ここで再度 kh_coder.pl を Docker 内で実行

```
# cd /KHCoder/khcoder/
# /usr/bin/perl ./kh_coder.pl
```

おめでとう。たぶん KH Coder が立ち上がっているはず。

## チュートリアルを試す。
実行時にどういうわけか Chasen になっているので Mecab にするのでそこだけ注意。日本語の入力がコピペでしかできなかったのはなぜ？

```
% mkdir KHCoder/works
% cd KHCoder/works
% wget https://khcoder.net/tutorial_data_3x.zip
% unzip -x tutorial_data_3x.zip
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99921/0bf37f07-2859-91ec-8e64-f7cfe9089dee.png)

### MeCab の設定を間違えていた。
MeCab の設定を間違えて、品詞推定させると K が複数になってしまう。以下間違えた結果。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99921/bd986d2d-c7df-c451-b361-9a08f05725b4.png)
Amazon SESで受信したメールをLINE公式アカウント配信したときのハマりどころ

基本はこのQiitaの手順通りですが、自分がハマった点をメモしときます。

https://qiita.com/Kakimoty_Field/items/4485a4e76d677d85ade0

## ドメインとアドレスの認証

上記QiitaではRoute 53経由でドメイン認証していたが、自分はムームードメインを使ってたので少しやり方がことなった。基本はTXTレコードでドメイン認証する（ムームードメインの場合はちゃんとムームーDNSを使う設定になってるか確認すること）か、DKIMのためのCNAMEレコードで認証する。

送信で使うことはないが、メールアドレスの追加も一応した。ただし「MAIL FROM DOMAIN」はメール送信したときに送信元アドレスを`amazonses.com`じゃなく自分のドメインにしたいときに使うものだから追加しなくていい。

ただMXレコードは知らぬ間に以下を設定していた。。

https://twitter.com/maztak_/status/1478546100693123072?s=20

## S3バケットとLamdaのRegionが同じか
そもそもSESを使う場合はアジアは確かダメで米国圏？のRegionにしてやる必要がある。なのでSESもS3もLamdaも全部「米国東部（バージニア北部）`us-east-1`」にしておけばOK。


## ロールに権限をアタッチしてあげる必要がある
以下のようなエラーがでる

> Access Denied
> Make sure they exist and your bucket is in the same region as this function

下記ブログの通り、アクセス権限をアタッチしてあげる。

![スクリーンショット 2022-01-05 12.29.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/240ee7c1-5b94-8b6e-f183-1b28e682876a.png)


https://umebius.com/dev/lambda-s3-getobject-access-denied-%E3%82%92%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC%E8%A8%AD%E5%AE%9A%E3%81%A7%E5%9B%9E%E9%81%BF/

## プレフィックスの指定方法

プレフィックス自体は任意の名前をつけていいが、結論、全部同じものをしておけば間違いない。先のQiitaの記事にしたがい（コメントでも指摘させてもらったけどmailbox-やmainbox-のタイポがあって混乱しちゃったけど）全部`mailbox`を入力する。LamdaのS3トリガーでオプションとしてプレフィックスを指定できるが、これも`mailbox`とした。

プレースホルダーが`images/`とスラッシュ付きなので不安になるが、S3のPUTがトリガーとなる場合、Objectの取得のためにしていするkey(ファイル名)は`mailbox/hogefuga`のようにディレクトリ名も含んだ名前になるのでスラッシュがあろうがなかろうが関係ないみたい。

プレフィックス＝ファイル名の最初に共通してつく文字列のこと、で間違いないようだ。
新しいことを学ぶためのフレームワーク

1. 全体像をつかむ
    1. 学びたいテーマについての基本的な調査を行う。
    1. 例：テーマについての本の目次、イントロダクションを読む
2. スコープを決める
    1. ダメな例：物理学を学ぶ
    1. 良い例　：二次方程式の解き方を学ぶ
    1. テーマの中の別のサブテーマを学ぶためにスコープを広げるのはNG
    1. スコープの焦点は出来るだけ絞ること
    1. このテーマを学ぶ期限を決める
3. 成功基準を決める
    1. 例：C#で主要な言語機能を利用した小さなアプリケーションを書けるようになる
4. 参考資料を見つける
    1. 本
    2. ブログ
    3. オンラインビデオ
    4. そのテーマに関する専門家
    5. ソースコード
    6. サンプルプロジェクト
    7. オンラインドキュメント
5. 学習プランを作る
    1. 最終目的（3：成功基準）に達するために必要な学習経路を作る
    1. そのテーマに関する本の目次のようなものが出来上がる
    1. 各目次はテーマを学ぶためのモジュールとなる
6. リソースをフィルターにかける
    1. （4：参考資料を見つける）で集めた資料を対象として学習プランに最も役に立つ内容を拾い出す
7. 使い始められるようにする方法を学ぶ
    1. フレームワークなら
    1. Hello Worldの書き方、開発環境のセットアップ方法を学ぶことになる
    1. 次のステップで自力で実験できるようにするために必要な最低限のことを学ぶ
    1. （3：成功基準を決める）で決めた成功基準へ繋がらない事に手を出さないように注意
8. 遊びまわる
    1. 実際に触って動かす
    浮かんだ疑問を書き出しておく
9. 役に立つことができるところまで学ぶ
    1. （8：遊びまわる）で書き出した疑問を解決する
    1. （4：参考資料を見つける）で集めた資料が役に立つ
    1. このステップの目的は遊んだ結果生まれた疑問を解くことである
10. 教える
    10. ブログを書く
    10. 動画を作る 
    10. オンラインフォーラムで質問に答える
    
    
ステップ7から10を（5：学習プランを作る）で作成したすべてのモジュールが完了するまで繰り返す。

参考：[SOFT SKILLS SOFT SKILLS ソフトウェア開発者の人生マニュアル] (https://amzn.to/32QjCB9)
TMPZ84C015其の壱

昔使っていた2400のモデムを分解したところTMPZ84C015が入っていてROMはAMDの27C512がが使われていました。TMPZ84C015はAKI80でも使われていますし、すこし前に共立電子で処分品が出ていたようです。

当初部品取りを考えたのですが、せっかく組みあがっているので、出来るだけそのままで利用する事にしました。

[MEEPROMMER](https://qiita.com/yamori813/items/14f6c28a2705ab3e9cc4)でROM読んでディスアセンブラしてみました。

I/Oポートを調べてみます。

```
 % z80dasm --origin=0 rom.bin | grep "in " | sort | uniq
Warning: Code might not be 8080 compatible!
        in a,(012h)
        in a,(018h)
        in a,(019h)
        in a,(01ah)
        in a,(01bh)
        in a,(01ch)
        in a,(01eh)
        in a,(023h)
        in a,(026h)
        in a,(028h)
        in a,(029h)
        in a,(02bh)
        in a,(02dh)
        in a,(02eh)
        in a,(02fh)
        in a,(032h)
        in a,(033h)
        in a,(03bh)
        in a,(03dh)
        in a,(0a0h)
        in a,(c)
        in b,(c)
```

outも調べてみます。

```
 % z80dasm --origin=0 rom.bin | grep "out " | sort | uniq
Warning: Code might not be 8080 compatible!
        out (010h),a
        out (011h),a
        out (012h),a
        out (013h),a
        out (018h),a
        out (019h),a
        out (01ah),a
        out (01bh),a
        out (01ch),a
        out (01dh),a
        out (01eh),a
        out (023h),a
        out (026h),a
        out (028h),a
        out (029h),a
        out (030h),a
        out (032h),a
        out (033h),a
        out (036h),a
        out (037h),a
        out (038h),a
        out (039h),a
        out (03ah),a
        out (03bh),a
        out (03ch),a
        out (03dh),a
        out (080h),a
        out (0a1h),a
        out (0a3h),a
        out (0c3h),a
        out (0f0h),a
        out (0f1h),a
        out (0f4h),a
        out (c),a
```

outは直前でaレジスタにldしている事が多いのでgrep -B 1するといいです。

TMPZ84C015の内蔵のI/O以外のポートはおそらくASICかMODEMチップへのアクセスと想像されます。

CTC

|Channel|I/O Address|
|:--|:--|
|0|#10|
|1|#11|
|2|#12|
|3|#13|

PIO

|I/O function|I/O address|
|:--|:--|
|Port A data|#1C|
|Port A Command|#1D|
|Port B data|#1E|
|Port B Command|#1F|

SIO

|I/O function|I/O address|
|:--|:--|
|Channel A data|#18|
|Channel A command|#19|
|Channel B data|#1A|
|Channel B command|#1B|

Watchdog #F0,#F1
Interrupt Priority #F4

SOP28ピンのSRAMらしき部品も実装されています。TMPZ84C015は16bitアドレスなので、27C512は64KでROMの一部はバンク切り替えになっていて、SRAMが後半にいるのではないかと思われます。

SRAMは部品番号が読めないのですが、A14が接続されているので、32KByteと思われます。

ハードウエアの仕様を確認するためのミニモニターを作って確認するのがよい気がします。
Coldfusionのカスタムタグの使い方

## どんな話？

久しぶりにColdfusionに触って、カスタムタグの使い方を忘れていたので。
公式マニュアルのこの辺の話。
https://helpx.adobe.com/jp/coldfusion/developing-applications/building-blocks-of-coldfusion-applications/creating-and-using-custom-cfml-tags.html

公式マニュアルは長いし、英語読むのも面倒だし、ざっくりと。

## カスタムタグって何だっけ？

こんな感じで書くと、

```xml:test_customtag.cfm
<cf_hogetext id="hoge_id" name="hogename">  
```

サーバ側でごにょごにょ処理が実行されて、こんなものが出力される、みたいな。
（もちろん、こんな感じで出力されるように、裏で処理を作る必要はあります）

```html:ブラウザ側への出力
<input type="text id="hoge_id" name="hogename" placeholder="ほげほげ">
```

主に画面表示出力などを共通化するための仕組みですね。
サーバ側の処理をCFMLで書いているなら、`cffunction`の代わりに使えたりもしますね。

## カスタムタグの配置場所を設定する

`cf_hogetext`タグを使ったときに呼びだされる処理は、`hogetext.cfm`に記述する必要があります。

```text:例えばこんなディレクトリ構成
- src
    - gamen
        - test_customtag.cfm
        - hogetext.cfm
```

ただ、この構成だとちょっとわかりにくいと思います。
カスタムタグは、`Application.cfc`でパスを指定することで、そこにあるファイルを読み込むことができるようになります。
（パスの記述は環境に合わせてそれらしく）

```xml:Application.cfc
<cfset this.customtagpaths = "カスタムタグを配置する場所">
```

この設定をすることで、カスタムタグの処理を記述するファイルを分けることができます。

```text:例えばこんなディレクトリ構成2
- src
    - customtag
        - hogetext.cfm
    - gamen
        - test_customtag.cfm
```

## とりあえず処理を書いてみる（Attributesの使い方とか）

`test_customtag.cfm`は[カスタムタグって何だっけ？](#カスタムタグって何だっけ)をそのまま使ってみる。

```xml:test_customtag.cfm
<cf_hogetext id="hoge_id" name="hogename">  
```

そしてカスタムタグの処理。
カスタムタグを使うときに記述されている属性（`id`とか`name`とか）は、`Attributes`から取得できます。

```xml:hogetest.cfm
<cfoutput>
  <input type="text" id="#Attributes.id#" name="#Attributes.name#" placeholder="ほげほげ"> 
</cfoutput>
```

これで`test_customtag.cfm`を呼び出せば、[カスタムタグって何だっけ？](#カスタムタグって何だっけ)と同じ結果が返ってくるはずです。

```html:ブラウザ側への出力
<input type="text id="hoge_id" name="hogename" placeholder="ほげほげ">
```

これを応用すれば、データベースから取得した情報を使ってselectタグとoptionタグを生成したり、みたいなこともできますね。
`cffunction`タグやCFScriptで関数定義したりでも似たようなことができると思いますが、状況によってはこちらの方が使いやすいと思います。

## Callerなんてものが使える（けどあまり使いたくはない）

カスタムタグの処理内で`Caller`を使うことにより、カスタムタグの呼び出し元で定義されている変数を取得したり、値を書き換えたりすることもできます。
（多用するとソースが読みにくくなりそうですが・・・）

例えばこんなカスタムタグを定義してみます。

```cfscript:hogecaller.cfm
<cfscript>
  // もちろんCFMLではなく、こんな感じでCFScriptでも処理を書けます
  Caller.hogehoge = "書き換えたhogehoge";
  Caller.fugafuga = "新たにセットしたfugafuga";
</cfscript>
```

そしてカスタムタグを使うと、カスタムタグを呼び出す前にセットした`hogehoge`が書き換えられますし、カスタムタグ内で新たにセットされた`fugafuga`の値を取り出すこともできます。

```xml:test_customtag.cfm
<cfset hogehoge = "ほげほげ">
<cf_hogecaller>

<cfdump var="#hogehoge#">  <!--- hogecallerタグによって書き換えられた値が出力される --->
<cfdump var="#fugafuga#">  <!--- hogecallerタグによって新たにセットされた値が出力される --->
```

いやでも、この仕組みはやっぱりソースの可読性が・・・
個人的には、共通の定数定義を読み込むときに使うくらいがいいような気がします。

## TODO

時間がある時にまだ書けそうなことがありますね。そのうち追記します。

- 終了タグを使った処理の書き方
Amazon Lightsail (VPS) 上の Ubuntu 内で Arch Linux を動かしてみた

# 方法
systemd-nspawnを使います。

※ dockerでもできるかもしれませんが、この記事では systemd-nspawn を使う方法を解説します。

※ 以下、本文中でVPSと記載している箇所は Amazon Lightsail を想定しています。

# 準備
ローカルで動作中のArch Linux環境上で、最小限のArch Linuxイメージを構築し、圧縮します。

`mkdir arch`
`sudo pacstrap arch base`
`tar zcvf arch.tar.gz arch`

### scpコマンド等で、VPSサーバーに転送します。

`scp -i myprivatekey.pem arch.tar.gz ubuntu@123.123.123.123:`

VPSサーバ側で `/var/lib/machines` へ展開します。ディレクトリがなければ作ります。

`sudo mkdir /var/lib/machines`
`sudo tar zxvf arch.tar.gz -C /var/lib/machines`

### systemd-container をインストールします

`apt install systemd-container`

### nspawn用設定ファイルを作成します。

``` /etc/systemd/nspawn/arch.nspawn
[Exec]
PrivateUsers=no
[Network]
VirtualEthernet=no
```

### 初期設定をするためにコンテナを起動します。

`systemd-nspawn -D /var/lib/machines/arch`

### コンテナの中で作業します。

とりあえず最小限必要なパッケージをインストールします。（エディタはお好みのものを）

`pacman -Syu`
`pacman -S sudo nano`

### sudoを使用するための権限設定を変更します。

`EDITOR=nano visudo`

``` /etc/sudoers
# ↓ この行の先頭の # を消してコメント解除します
%wheel ALL=(ALL) ALL
```

保存して終了します。（nanoエディタなら Ctrl+O Enter Ctrl+X）

### ユーザーを作成します

`useradd -m -G wheel taro`
`passwd taro`

Ctrl+D または `exit` で終了します。（何故か終了できなくなった場合は Ctrl を押しながら `]` を3回を押してみてください）

# 起動

### コンテナを起動します。

`sudo machinectl start arch`

### 作成したユーザーでコンテナにログインします。

`sudo machinectl login arch`

### コンテナ内で`sudo`を実行できるか確認します。

`sudo su`
`exit`

### ログアウトします。

Ctrl+D または `exit` でログインプロンプトに戻ります。

### 端末を終了します。

Ctrl を押しながら `]` を3回を押します。普段はこちらを使ってコンテナから抜ければ良いようです。

### コンテナを停止します。

`sudo machinectrl stop arch`

# トラブルシューティング

### Q. 端末を終了できない（ホストに戻れない）
A. 上にも書きましたが、Ctrl を押しながら `]` を3回を押します。

### Q. /var/lib/machine/arch のパーミッション値がおかしなことになっている
A. もし、`PrivateUsers=no`の設定を忘れていた場合、systemd-nspawn がホストとは別のユーザーIDを付与するようになります。

### Q. コンテナの中から外と通信できない。
A. もし、`VirtualEthernet=no`の設定を忘れていた場合、、systemd-nspawn がホストとは別の仮想ネットワークを提供します。

プライベートユーザーモードや仮想ネットワークモードを理解した上で意図的に使うのであればそれでいいのですが、お手軽に利用するには面倒だと思いますので、本記事ではユーザーIDやネットワークはホストのものを利用する方法を解説しています。

パーミッション値がおかしくなった状態で、`/etc/systemd/nspawn/arch.nspawn`を修正してから、プライベートではないモードで使いたい場合は、以下のようにしてパーミッションを修正します。

`sudo machinectrl stop arch`
`sudo chown root.root /var/lib/machines/arch -R`
`sudo systemd-nspawn -D /var/lib/machines/arch`
`passwd taro`
`chown taro.taro /home/taro -R`
`exit`

# まとめ

### メンテナンスのためにrootでコンテナに入りたい

`sudo systemd-nspawn -D /var/lib/machines/arch`

### 普段使いのためのコンテナ起動

`sudo machinectl start arch`

### 普段使いのためのコンテナログイン

`sudo machinectl login arch`

### 端末終了

`Ctrl` + `]` `]` `]`

### コンテナ停止

`sudo machinectl stop arch`
よりどりみどりのセグメンテーションモデルが使い放題というバグってるモジュールmmsegmentation　え、この最新モデルも？

#発表されたばかりの最新モデルがかんたんにつかえるPythonモジュール
かんたんなコードで「今年でた」みたいな最新モデルを使えるモジュールです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/d69c3bbd-63df-1805-a961-234571c30f35.png)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/1697d082-5101-83a6-bbfa-fbf6b7abac4a.png" width=450>

#機械学習は日々進歩を遂げているが、キャッチアップして使うのは大変そう
どんどん論文が発表され、精度はどんどん上がっていく機械学習モデル。
コードも公開されるけど、発表されるごとにGitHubを訪れてコードを実行してみるのもたいへんそう。。。

#研究ごとにコードを参照しないといけないのか
自分のサービスにはどのモデルが良いのか比較しようにも、
実行方法や実行環境や必要なモジュールなど、プロジェクトごとにコードの形式が異なることもあるので、いちいち参照するにはそれだけ時間がかかる。

#mmsegmentationなら、かんたん、モデルを選ぶだけで一発実行

mmsegmentationなら、たくさんのモデルをサポートしていて、同じ実行フォーマットで使える。
今年発表されたモデルまで、たくさんの新しいモデルをサポートしている。
しかも、実行も少ないコードで可能である。
以下のようなモデルをサポートしている。記事執筆現在、論文レベルでもっとも高精度のモデルも含まれている。対応データセットも一通りサポート。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/cc078a8f-3777-8c39-401f-9fccdfc145f3.png" width=200><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/bf450f60-71a2-081a-9cc6-347bd22a1628.png"  width=150>

#使い方
１、公式の手順に従って、mmsegmentationをインストール。pipでできる。

https://github.com/open-mmlab/mmsegmentation/blob/master/docs/en/get_started.md#installation

２、公式リポのモデル・ズーから、configファイルとcheckpointファイルを入手できる。

３、実行

```python
from mmseg.apis import inference_segmentor, init_segmentor
import mmcv

model = init_segmentor(path_to_config_file, path_to_checkpoint_file, device='cuda:0')
img = 'demo/demo.png'
result = inference_segmentor(model, img)
```

これだけである。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/2b7f96ad-65cc-2494-010f-1fe72487d44f.png width=450>

公式のサンプルコラボ：

https://colab.research.google.com/github/open-mmlab/mmsegmentation/blob/master/demo/MMSegmentation_Tutorial.ipynb

#新旧のモデルを比べて、自分のサービスに適したものがかんたんに使える。
mmsegmentationを使えば、最新のモデルにアクセスでき、自分のサービスにあったモデルを選んで使うことができる。
統一されたモジュールで使えるのは、とても便利だと思います。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
Chrome97 DevTools に新機能 Recorder 追加！🎉seleniumみたいなやつがブラウザに。

# What's Recorder ?
これ！
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">🌟 Introducing the new Recorder panel 🌟<br><br>You can now record, replay and measure user interactions with <a href="https://twitter.com/ChromeDevTools?ref_src=twsrc%5Etfw">@ChromeDevTools</a>. <br><br>See it in action - ordering coffee. ☕️<br><br>Learn more about this preview feature (available in Chrome Canary now): <a href="https://t.co/TGleZ2wo43">https://t.co/TGleZ2wo43</a> <a href="https://t.co/qgQ4vTx6Zf">pic.twitter.com/qgQ4vTx6Zf</a></p>&mdash; Chrome DevTools (@ChromeDevTools) <a href="https://twitter.com/ChromeDevTools/status/1455936412646199296?ref_src=twsrc%5Etfw">November 3, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

seleniumなどのようにブラウザ上での操作を記録、再実行、編集ができ、
Puppeteerスクリプトへのエクスポートもできる。

# 私
個人的にJavaスキーなのでselenium,selenide推し。
JavaScriptでテストするときはCypressが好き。

# Recoderの使い方

## Recorderタブを開く
Chromeで開発者ツールを開く（F12 or Ctrl + shift + i）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60858/d3fc0e62-966d-e711-2497-20184c737bf9.png)

## Recording（記録）
「start new recording」を押す。
RECORDING NAMEを入力して「Start a new recording」を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60858/cd57e8c0-d37b-d8ab-a770-ecc51b5a899d.png)

以下の画面になったら画面操作開始。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60858/de581fa8-f7af-c9d4-be1a-50010829b6c0.png)

clickやkeydownなどの画面操作が記録される。終わったら「End recording」を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60858/1f77831d-91dc-10b4-6b00-b657f205e1ab.png)

## Replay（再実行）

Replayで再実行できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60858/00f86bb2-bca8-5544-b6a7-8a03558f8595.png)

## Measure performance（パフォーマンスの計測）

「Measure performance」を押す。
操作を再実行しながら、同じみのPerformanceタブが開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60858/299a76c9-c136-2735-aa50-48893556a5a1.png)

## Edit（編集）
記録した操作を編集もできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60858/55a6aabb-9def-2b09-9f66-90d230d631dc.png)

## Export
Puppeteerスクリプトへのエクスポートができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60858/cbf7d10d-ba62-851f-acec-6ac4f79812b0.png)

# まとめ

簡単なメモ書きで終わりましたがイメージはつかめるかと。
何よりブラウザに標準搭載された、という事がまず素晴らしい。
頻繁に使っていきたい。

# 参考
[Chrome DevToolsのRecorderを試す - Qiita](https://qiita.com/konnyaku256/items/55d8b2402bf9b16aa257)
[Chrome Developers/recorder](https://developer.chrome.com/docs/devtools/recorder/#open)
Crystalのメモリに関するメモ

メモ書き程度の内容です。

## CrystalはGCにlibbcを利用している。

Crystal言語では、ガベージコレクションにlibgcを利用しています。

https://en.wikipedia.org/wiki/Boehm_garbage_collector

https://github.com/ivmai/bdwgc

## Crystalでメモリを調べる良いツールは2022年1月5日時点ではあまりなさそう

https://github-com.translate.goog/crystal-lang/crystal/issues/8788?_x_tr_sl=en&_x_tr_tl=ja&_x_tr_hl=ja

C言語の世界ではvalgrindというツールがメモリを調査する定番らしいが、crystalでそれを使うのは簡単ではない。他にKDEの[heaptrack](https://github.com/KDE/heaptrack)というツールもあるが、Crystalに必要な粒度で解析してくれるとは限らなそうな感じである。
Crystalの世界から、GCのカウンター？を参照できるようにできないだろうかという提案が出てるが、開発陣は必ずしも乗り気ではなさそう。

## いくつかの関連するコマンド

```crystal
GC.stats
# GC::Stats(@heap_size=96440320, @free_bytes=4177920, @unmapped_bytes=0, @bytes_since_gc=34869536, @total_bytes=122684688)
```


```crystal
GC.collect
```

これを呼び出すことにより、メモリの使用量を抑えることができるが、`GC.collect`を実行するのは高価らしい。
Wordpressで手動で、かつ投稿がある時のみアーカイブ表示させる方法。（カスタムフィールド/ACF）

##カスタムフィールドと、手動でアーカイブの掛け合わせ
特に新規でサービスを作るとき、下記の2つの要望はよく起こり得るケースだと思う。
・素材となる記事はまだないが、できたらすぐに反映できるようにしてほしい。
・画面に表示するのは、関連する全ての記事ではなく手動で選びたい。

このような場合に、カスタムフィールドと、手動アーカイブの組み合わせが役に立つ。具体的な方法は下記の通り。

###枠組みの作成手順
1. クライアントが要望するカスタム投稿タイプまたは投稿タイプを小ブロックという認識(後にField Type：tabで括る)で作る。
1. その小ブロックの中身のベース枠組みをカスタムフィールドで作成する。
1. 今後表示をさせたい固定ページ用のカスタムフィールドにて、小ブロックの**Field Type：Relation**として作成する。
1. 固定ページの編集画面に行き、表示させたい投稿記事（2の雛形を使い作った記事）を選択する。以上。

これにより、素材ができた場合の元の枠組みだけ完成させておき、クライアント側で記事が溜まっていざ表示させたいという時に、お気に入りのものだけピックアップして表示させることができる。

なお、非表示の方法としては、if文で

    <?php $hoge = get_field('タクソノミー名'); ?>
    <?php if($hoge):?>
として書いてやり、htmlとcssを事前に記載しておくことで、記事が溜まって選択された時にすぐに公開に持っていくことができるようになる。

if文内の参考

     <?php foreach( $hoge as $val ): ?>
     <img src="<?php echo get_field('2の中のタクソノミー名',$val->ID); ?>" alt="">


投稿アーカイブの作成方法は様々あるが、手動で選ぶ場合や、サービス立ち上げでまだ中身がない場合などの参考にしていただければと思う。
GA4でCV-コンバージョンが計測されない際の確認事項

- 先日、GA4においてコンバージョンが計測されない事象がありました。
- その後、試行錯誤のうえ、**コンバージョンが計測されない場合**の見直すべきポイントの１つを掴みましたので、共有したいと思います。
- ※2021年12月現在における事象です。もしかしたら、ご覧いただいたタイミングでは解消しているかもしれません...

# 事象の確認
- GA4において、コンバージョンが計測できていなかった。
- また、[カスタムイベント](https://support.google.com/analytics/answer/10085872#zippy=%2C%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%AE%E5%86%85%E5%AE%B9)も計測できていなかった。
- ただし、`page_location`のような[自動的に収集されるイベント](https://support.google.com/analytics/answer/9234069?hl=ja&ref_topic=9756175)は計測されていた
- その他、計測した際の条件や事象について詳しくはコチラ：[【GA4】コンバージョンとれてますか？（2021年12月現在。CVが計測されない）](https://qiita.com/tomokei5634/questions/2b5b7b72bb283c5b6ff8)

# 原因は UA → GA4
- GA4においてコンバージョンが計測できていなかった原因は、GA4の計測タグの設置方法にありました。というより、実のところサイト上にはGA4の計測タグは設置していませんでした。
- 元々サイト上にはUA（ユニバーサルアナリティクス）の計測タグ「[gtag.js：グローバルサイトタグ](https://support.google.com/analytics/answer/10220869)」を設置していました。
- UAにもGA4にも「[接続済みのタグ（タグの接続）](https://support.google.com/analytics/answer/9973999?hl=ja)」という機能があります。サイトからGA4へは、UAの「接続済みのタグ」を経由してデータを渡していました。「接続済みのタグ」機能を用いると、元々設置している計測タグを変更せずに他のプロパティへ（今ではあればUAからGA4へ）イベントを渡すことができます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283603/b8a3ae2f-7c49-252e-092f-afdfddae8531.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283603/83af3271-ac3e-98e8-4c56-6708bb7dd681.png)

- ※上記は[ユニバーサル アナリティクスと Google アナリティクス 4 プロパティ用にタグを設定する方法](https://developers.google.com/analytics/devguides/collection/ga4/basic-tag?hl=ja&technology=gtagjs)より抜粋

- 色々と実験を行った結果にわかったこと・・・UA経由では、GA4でコンバージョンが立たなかったり、カスタムイベントが反応しなかったりするようです...


# 解決策は GA4 を軸にする
- Googleの説明には `既存の gtag.js ページ スニペットにコードを 1 行追加` とありますが、なんとこの方法でもコンバージョンが計測されませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283603/c0ad64f7-8116-c224-6eb3-974e395ae96d.png)

- `1 行追加`だけではダメです。最初の行の`UA-XXXXXX-13`部分もGA4プロパティのID`G-XXXXX`へ変更しないといけません。これは結局のところ、UAタグをGA4タグに入れ替えるということになります。
- ただ、UAタグをGA4タグに入れ替えただけでは、今度はUAで計測できなくなってしまうので、以下のどちらかも行った方がいいでしょう

- - **GA4の**「接続済みのタグ」機能にUAのIDを追加する
- - **GA4の**計測タグ内に`gtag('config', 'UA-XXXXXX')`を追加する

- なぜUAに「1行追加」もしくは「接続済みのタグ」では、GA4のコンバージョンが立たないかの本当の理由は、下記の説明を理解するとわかるかもしれません（私は放棄しましたが...）
- - [[UA→GA4] UA の gtag.js が GA4 にマッピングされる仕組み](https://support.google.com/analytics/answer/9310895)
- - [[GA4] 接続済みのサイトタグについて](https://support.google.com/analytics/answer/9973999?hl=ja)

# GTMを用いた場合は？
- 今回はアナリティクスの計測タグをサイトへ埋め込んでいますが、タグマネージャー経由でアナリティクスを設置する方法もあります。
- こちらの方法は検証していませんが、「接続済みのタグ」を使わないで、UAとGA4の両方を設置した方がいい気がします

---

- 現在では、新たにアナリティクスのプロパティを立ち上げると、GA4がデフォルトです。オプションでUAも立ち上げることができますが、この際はGA4の「接続済みのタグ」にUAプロパティIDがセットされる形で連携されています。ですのでコンバージョンの計測にも影響はないと思います。
- 今回の投稿の対象となるサイトは、今までUAを用いていて、これからGA4を後付するサイトです。

- GA4を採用したが、コンバージョンが取れていない、カスタムイベントが反応していない、という場合は、サイトに設置している計測タグGA4のものであるかを、まずご確認いただければと思います。
rex0220 計算式プラグイン テーブルにCSV入力

計算式プラグインで、CSV文字列からテーブルの値に変換できるようになりました。
まとめてテーブル入力したい場合につかえるかも。
※計算式プラグイン Ver.48以降でサポート

# 概要

テーブルに計算式を指定することで、文字列複数行項目のCSV文字列をテーブルに反映できます。
![2022-01-05_11h43_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/b73d5825-0b8a-e424-0cc2-795588bb137d.png)


文字列複数行の計算式：
CSV_TVAL(CSVデータ)

※CSVデータの文字列をテーブルに反映

# CSV_TVAL 関数

- CSV_TVAL：　CSVをテーブル入力データに変換
    - CSV_TVAL(CSV項目[,TPOUT(出力先テーブル内項目),...]
    - [TPOPT] 関数で、オプションを指定　TPOPT("HEADER","N")
        - HEADER: "Y": あり、"S",: スキップ、"N": なし　：ヘッダー行の処理
        - TITLE: "code": フィールドコード、"label": ラベル　：ヘッダー行のタイトルの種類
        - SEP: 規定値 ","　：区切り文字を指定
        - QMARKS: 規定値 '"'　：引用符を指定
        - MAXROWS: 規定値　""　：最大行数
    - [TPOUT(項目[,...])]：　出力項目を指定。指定が無い場合は、テーブルの全項目
        - CSVデータの並び位置で出力項目に変換<br>
※@ を指定すると除外
    - [TPSORT(項目[,フラグ]...)]：　出力するテーブル行のソートを指定
        - フラグ：　1:　昇順、0: 降順
            - TPSORT(項目1,0,項目2)
    - [TPLABEL("ラベル"[,"ラベル"...])：　出力する項目名を変更
    - 例　CSV_TVAL(CSV文字列)
    - 例　CSV_TVAL(CSV文字列,TPOPT("TITLE","label")))
        - CSVヘッダー行のタイトルを項目ラベルとして処理
    - 例　CSV_TVAL(CSV文字列,TPOPT("HEADER","S"),TPOUT(文字列,数値),TPSORT(数値,0)
        - CSVヘッダー行をスキップして、行の先頭から「文字列」,「数値」のフィールドコードとして取得して、数値の降順でソート

# CSV入力チェック時のみCSVをテーブル変換

随時CSVをテーブル変換するだけだと、誤ってテーブルが変わってしまうリスクがあります。
CSV入力チェック時のみCSVをテーブル変換してみます。

![2022-01-05_11h54_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/b4bf2381-6cc9-9d0b-3f14-d486c93fbba8.png)

文字列複数行の計算式：
IF(IN(CSV入力,"入力"),
　CSV_TVAL(CSVデータ,
　　TPOPT("TITLE","label"),
　　TPSORT(数値,0))
)


- IF(IN(CSV入力,"入力"), ：　CSV入力が"入力"をチェック時<br>
- CSV_TVAL(CSVデータ,　：　CSVデータ<br>
- TPOPT("TITLE","label"),：　CSV のヘッダー行がラベルとして処理
- TPSORT(数値,0)))　：　数値の降順でソート

# TAB タブ区切り、日付 YYYY/M/D 形式の TSV データ入力

Excel からデータを文字列複数行にコピペすると、TAB タブ区切り(TSV)になります。
また、日付形式が kintone （"YYYY-MM-DD"）と異なり "YYYY/MM/DD" または、"YYYY/M/D"　です。

計算式プラグインで、これらを扱うためには、TSV を CSV に変換して、処理します。

![2022-01-05_16h10_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/636e7c25-bae1-502f-6ab1-ed6b4a97e005.png)

テーブルの計算式：

```
IF(IN(CSV入力,"入力"),
  CSV_TVAL(
    REPLACERE(REPLACERE(REPLACERE(REPLACERE(
      CSVデータ,
      "([^|\t])([0-9]{4})/([1-9])/([1-9]|[12][0-9]|3[01])(\t|$)","g","$1$2/0$3/$4$5"),
      "([^|\t])([0-9]{4})/(0[1-9]|1[0-2])/([1-9])(\t|$)","g","$1$2/$3/0$4$5"),
      "([^|\t])([0-9]{4})/(0[1-9]|1[0-2])/([0][1-9]|[12][0-9]|3[01])(\t|$)","g","$1$2-$3-$4$5"),
      "\t","g",","),
    TPOPT("TITLE","label"),
    TPOPT("QMARKS",""),
    TPSORT(数値,0)
   )
)
```

REPLACERE で、下記の変換を行います。
"YYYY/MM/DD","YYYY/M/D" -> "YYYY-MM-DD"
タブ区切り -> カンマ (",") 区切り
[py2rb] double splat引数 と 実行速度の検証

# はじめに
移植やってます。
( from python 3.7 to ruby 2.7 )
# double splat引数 (Python)
```python
def charge(sequence, pH, **kwargs):
# 略

class ElectrochemTest(unittest.TestCase):
    def test_charge_calculations_str(self):
        self.assertTrue(
            abs(charge('AAA', 5.0,
                       pK={'H-': [(9., 1)], '-OH': [(8., -1)]},
                       pK_nterm={'H-': {'A': [(3., 1)]}})) < 0.01)
```
`pK`や`pK_nterm`って仮引数にないのですが、実は辞書のキーでした。
# double splat引数 (Ruby)
```ruby
def charge(sequence, pH, **kwargs)
# 略
end

class TestEctrochem < Minitest::Test
  def test_charge_calculations_str
    assert charge(
      'AAA', 5.0,
        'pK' => {'H-' => [[9.0, 1]], '-OH' => [[8.0, -1]]},
        'pK_nterm' => {'H-' => {'A' => [[3.0, 1]]}}
    ).abs < 0.01
  end
end
```
```diff_ruby
def charge(sequence, pH, **kwargs)
# 略
end

class TestEctrochem < Minitest::Test
  def test_charge_calculations_str
    assert charge(
      'AAA', 5.0,
+      {
        'pK' => {'H-' => [[9.0, 1]], '-OH' => [[8.0, -1]]},
        'pK_nterm' => {'H-' => {'A' => [[3.0, 1]]}}
+      }
    ).abs < 0.01
  end
end
```
```diff_ruby
def charge(sequence, pH, **kwargs)
# 略
end

class TestEctrochem < Minitest::Test
  def test_charge_calculations_str
    assert charge(
      'AAA', 5.0,
+      **{
        'pK' => {'H-' => [[9.0, 1]], '-OH' => [[8.0, -1]]},
        'pK_nterm' => {'H-' => {'A' => [[3.0, 1]]}}
+      }
    ).abs < 0.01
  end
end
```
`{}なし`と`{}あり`と`**{}`の３つを書きましたが、この内`{}あり`はエラーが発生するので、コントリビュートチャンスだそうです。

```
ArgumentError: wrong number of arguments (given 3, expected 2)
```
https://qiita.com/fursich/items/20b35d564e62fa0530b5
# 速度の検証
こちらの記事によりますと、`double splat`は遅いらしいです。

https://qiita.com/akicho8/items/a73895690628bc7a8f7b

`minitest`の結果を参照しますと、レシーバ側は`kwargs = {}`、呼び出し側は`{}なし`が速そうです。~~`Ruby 3`　何？それっておいしいの？~~

||**kwargs|kwargs = {}|
|:--:|:--:|:--:|
|{}なし|2736.8176 assertions/s|3226.1533 assertions/s|
|**{}|3005.5192 assertions/s|3190.0239 assertions/s|

# メモ
+ Python の double splat引数 を学習した
+ 百里を行く者は九十里を半ばとす
tsv を 1行1件ずつの json にする

## コード

```js:tsv2json.jq
(env.HEADER|split("\t")) as $header
| [ $header, split("\t") ]
| transpose
| map({(.[0]): .[1]})
| add
```

```bash:tsv2json.sh
#!/bin/bash
set -ue

read HEADER
export HEADER
jq -c -R -f tsv2json.jq
```

## 適当なtsvを

```bash:bash
$ { printf "c1\nc2\nc3\n"; seq -f '%04g' 30; } | paste - - -
c1	c2	c3
0001	0002	0003
0004	0005	0006
0007	0008	0009
0010	0011	0012
0013	0014	0015
0016	0017	0018
0019	0020	0021
0022	0023	0024
0025	0026	0027
0028	0029	0030
```

## 変換

```bash:bash
$ { printf "c1\nc2\nc3\n"; seq -f '%04g' 30; } | paste - - - | bash tsv2json.sh
{"c1":"0001","c2":"0002","c3":"0003"}
{"c1":"0004","c2":"0005","c3":"0006"}
{"c1":"0007","c2":"0008","c3":"0009"}
{"c1":"0010","c2":"0011","c3":"0012"}
{"c1":"0013","c2":"0014","c3":"0015"}
{"c1":"0016","c2":"0017","c3":"0018"}
{"c1":"0019","c2":"0020","c3":"0021"}
{"c1":"0022","c2":"0023","c3":"0024"}
{"c1":"0025","c2":"0026","c3":"0027"}
{"c1":"0028","c2":"0029","c3":"0030"}
```
Exercise: Loops and Functions

## 概要

Goのチュートリアル「A Tour of Go」で、[関数とループを使って平方根の計算を実装する課題](https://go-tour-jp.appspot.com/flowcontrol/8)があったので記念に記録します。　時間的には5分程で解きました。「強い」エンジニアの」方々からしたら亀の歩みですね。

## 初期コード 

```exercise-loops-and-functions.go
package main

import (
	"fmt"
)

func Sqrt(x float64) float64 {
}

func main() {
	fmt.Println(Sqrt(2))
}

```

## 完成コード 

```exercise-loops-and-functions.go
package main

import (
	"fmt"
	"math"
)

func Sqrt(x float64) float64 {
	z := 1.0

	for i := 1; i <= 10; i++ {

		z -= (z*z - x) / (2 * z)

		countString := "回目"
		fmt.Println(i, countString, z)

		if math.Sqrt(x) == z {
			break
		}
	}

	return z
}

func main() {
	var num float64 = 2
	fmt.Println(Sqrt(num))
}
```

特に完成とかはないかと思いますが、チュートリアルで求められている内容はクリアできたかなと思います。

ニュートン法についてはよく解っていません。アルゴリズム弱者なので、2021年は一般人くらいに成長したいですね。

### 使用したパッケージ
```
import (
	"fmt"
	"math"
)
```
fmtはI/Oを整形して使うことができて、mathには数式に関する関数が詰まってます。

## まとめ

基本的にはチュートリアルの左側に説明があるので、それさえ読むことができれば問題ないかと思います。今年中にはGopherになりたいですね。
rex0220 計算式プラグイン テーブルのCSV文字列変換

計算式プラグインで、テーブルの値をCSV文字列に変換できるようになりました。
とりあえず、テーブル内容をコピペなどにつかえるかも。
※計算式プラグイン Ver.48以降でサポート

# 概要

文字列複数行項目に、計算式を指定することで、テーブルの値をCSV文字列に変換できます。
![2022-01-05_11h15_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/85e10ebf-ff24-80e7-7f5c-7eeab43fcb3c.png)

文字列複数行の計算式：
OTCSV(テーブル)

※テーブルの全項目をCSV変換

# OTCSV 関数

- OTCSV：　テーブル内項目をcsv文字列にする
    - OTCSV(テーブル[,TPOUT(区分,数量...)...])
    - [TPOPT] 関数で、オプションを指定　TPOPT("HEADER","N")
        - HEADER: "Y": あり、"N": なし　：ヘッダー行の有無
        - TITLE: "code": フィールドコード、"label": ラベル　：ヘッダー行のタイトル
        - SEP: 規定値 ","　：区切り文字を指定
        - QMARKS: 規定値 '"'　：引用符を指定
        - OTYPE: 規定値 "object"　：値の形式。"string": 配列は。「,」区切り
    - [TPFILTER(条件)]：　出力するテーブル行の条件を指定
        - TPFILTER(数量>0)
    - [TPSORT(項目[,フラグ]...)]：　出力するテーブル行のソートを指定
        - フラグ：　1:　昇順、0: 降順
            - TPSORT(項目1,0,項目2)
    - [TPLABEL("ラベル"[,"ラベル"...])：　出力する項目名を変更
        - TPLABEL("区分","金額")
    - 例 OTCSV(テーブル)
        - テーブルの全項目を CSVに変換。
        - "日付","ドロップダウン","数値"<br>
"2022-01-19","sample2","333"<br>
"2022-01-03","sample1","77799"
    - 例 OTCSV(テーブル, TPOPT("QMARKS","'"), TPOUT(ドロップダウンT, 数値T))
        - テーブルのドロップダウンT, 数値T項目を引用符「'」で変換
    - 例 OTCSV(テーブル, TPOPT("TITLE","label"), TPOUT(ドロップダウンT, 数値T))
        - テーブルのドロップダウンT, 数値T項目を項目ラベルで変換
    - 例 OTCSV(テーブル, TPOUT(日付,チェックボックス))
        - "日付","チェックボックス"<br>
"2022-01-04","[""sample2""]"<br>
"2022-01-01","[""sample1"",""sample2""]"
    - 例 OTCSV(テーブル, TPOUT(日付,チェックボックス),TPOPT("OTYPE","string"))
        - "日付","チェックボックス"<br>
"2022-01-04","sample2"<br>
"2022-01-01","sample1,sample2"

# テーブルの一部項目のみCSV文字列変換

![2022-01-05_11h22_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/a45de4f6-ac20-8044-44ac-1fd083994285.png)

文字列複数行の計算式：
OTCSV(テーブル,
TPOUT(文字列,ユーザー選択,チェックボックス))

※テーブルの全項目をCSV変換

# レコード詳細画面で、文字列複数行の縦スクロール表示

テーブル行が多いと、レコード詳細画面で文字列複数行が縦に長く表示されます。
[ちょっと便利なプラグイン](https://qiita.com/rex0220/items/45883f15ccd34a68b8af)も「F27 詳細画面で文字列複数行を縦スクロール表示」で、見やすくすることが出来ます。

![2022-01-05_11h24_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/76ae4a97-953f-4976-c1f4-708b9c136423.png)
tableauの拡張機能 #1 サンキーダイアグラムを簡単に作ってみる


### サンキーダイアグラムを簡単に作ってみる
【実行環境】 Windows10 tableau2020.2


どのような機能がtableauで実現可能なのかを学ぶために、tableauダッシュボードを構築する際に表示される拡張機能をいじっていきます。

今回はSnowMeMoreを使用して、サンキーダイアグラムをビジュアライズします。
[サンキーダイアグラムとは](https://ja.wikipedia.org/wiki/%E3%82%B5%E3%83%B3%E3%82%AD%E3%83%BC_%E3%83%80%E3%82%A4%E3%82%A2%E3%82%B0%E3%83%A9%E3%83%A0)
![SnoeMeMore.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466674/6e8669a7-2eeb-13d6-33e7-14d6b973c3d1.png)



####データセットの作成
今回は無料版なので、２つのディメンションと１つのメジャーしか対応していないようです。
と、いうことで簡単なデータセットを用意します。
Excelだとこんな感じ↓
![Dataset.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466674/89ed6b95-9169-d423-5841-00bcea3c018f.png)

「遷移元」から「遷移先」へ移行したボリュームをビジュアライズしていきます。



####ワークシートの作成
tableau desktopで上記ファイルを読み込み、ワークシートを作成します。
（拡張機能ってダッシュボードでの利用だからワークシートないと使用できないんですかね？）

![TableauSampleImage.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466674/8bb59bb3-b6b4-4880-51e2-1a1e205e473c.png)


####ダッシュボードの作成
ダッシュボードを作成し、上記で作成したワークシートをドラッグアンドドロップしたあと、「拡張」も同様にダッシュボードに設置します。
![TableauDashBoardSample.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466674/3e39b58a-7f29-f5b4-00f6-16aeacc9d7bb.png)

####SnowMeMoreでサンキーダイアグラムを作る

SnowMeMore拡張機能をギャラリーからダウンロードして、ディメンションとメジャーを指定します。
![SankeyDiagram.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466674/30f2189c-9f92-618b-cc06-39017e12860c.png)
![SankeyDiagram2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466674/f9f19a96-3f82-b5be-cad7-f048ca378292.png)

するとあら不思議
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466674/4e5ce06f-4430-9474-976f-76afcadc2fcf.png)

サンキーダイアグラムの完成です！
今回は無料版ですが、有料版だとディメンションを増やしたりフォントを変えたりもできそう

ちなみに拡張機能を使用せずに実施するにはシグモイド曲線を引くのが一番近道っぽいので、
興味がある方はぜひ↓
[TABLEAUでSANKEY DIAGRAMを作る](https://www.yarakawa.com/single-post/sankey_diagram)
ATFのクライアントエラー対処メモ

## 概要
申請フローの自動テストを作成中に承認ボタンまわりでクライアントエラーが発出。

#### エラーコード
```
This step failed because the client error 'TypeError: Cannot read properties of null (reading 'value')' was detected on the page being tested. See failing Test Logs. To ignore these errors in the next test run, use 'Add all client errors to warning/ignored list' links.
```

## 対処法

client side-UI Actionではよくテストエラーするのでwarningに変更していいです、と公式に対応が書いてあったので、その通りにして対応。
Open a existing code してから ignore error and take warning　を設定
以下二つのドキュメントが上記の説明となる。

## 参考リンク

[Identify and resolve client errors](https://docs.servicenow.com/bundle/quebec-application-development/page/administer/auto-test-framework/task/identify-and-resolve-client-errors.html)
[Allow client errors from the test logs](https://docs.servicenow.com/bundle/rome-application-development/page/administer/auto-test-framework/task/whitelist-errors-from-test-log-related-list.html)

### 補足:通用しなかった対処法
open a existing code はプラットフォームでの挙動なので、
open service portal pageにしたら承認ボタンのタップができず、うまく動作しなかった。
なので、上記のignoreが現状では動くソリューションとして書きおくこととする。
DjangoRestframeworkのModelViewSetでHTTPメソッドごとにカスタマイズする方法

# 目的
DjangoRestframeworkでModelViewSetを使ってシンプルに爆速でAPIを実装しようと思ったものの、HTTPメソッドによってはデフォルトの動作だけではなく、他の動作を追加してみたいとおもった。

# 実施環境
### ハードウェア環境
| 項目 | 情報 |
|:-:|:-:|
| OS  |macOS Catalina(10.15.7)   |
|ハードウェア   |  MacBook Air (11-inch, Early 2015) |
|プロセッサ   | 1.6 GHz デュアルコアIntel Core i5|
|メモリ   |  4 GB 1600 MHz DDR3 |
|グラフィックス   |  intel HD Graphics 6000 1536 MB |
### ソフトウェア環境
| 項目 | 情報 |
|:-:|:-:|
| homebrew  | 3.3.8 |
| mysql | Ver 8.0.27 for macos10.15 on x86_64 |
| python  | 3.8.12 |
| anaconda  | 4.10.1 |
| django  | 21.2.4 |
| pip  | 3.1.2 |

# 前提
ModelViewSetのシンプルな使い方を理解している人向け。

# 概要
```views.py
class MemberViewSet(viewsets.ModelViewSet):
    queryset = Members.objects.all()
    serializer_class = MemberSerializer
```
この部分は最低限実装することが求められており、これだけでCRUD(create,read,update,delete)が可能となっている。

しかし例えばデータの作成・登録をするときにフロントエンドから送られてきた情報に加工をしたい場合などはこれだけではもちろんできない。

これを可能にするためには
**@action→action decoratorの実装が必要となる。**
@actionを使って、

```
① httpメソッドの指定
② pk(主キー/プライマリーキー)の指定
③ クエリセットもしくはオブジェクトの取得
④ 加工・バリデーションなど(実際に何かカスタマイズする部分)
⑤ レスポンス
```
をすることでデフォルトのものとは全く異なる動作、レスポンスを行うことができる。
**urlにはデフォルトのurlに```/関数名/```を追加する**

##クエリセットとオブジェクトの違い
####クエリセット 
**オブジェクトのリスト**
(例えばgetメソッドでMember.all()などで取得する全部(もしくは一部)の情報) 
```<QuerySet [<Member: takeshi yoshimoto>, <Member: Yuto Ichihara>]>```
####オブジェクト 
**一列のレコード**
(例えばgetメソッドでpkで取得する一列の情報)   
```<Post: Sample title> ```

# 具体例

```views.py
class MemberViewSet(viewsets.ModelViewSet):
    # Membersのクエリセットを全て取得
    queryset = Members.objects.all()
    # 取得したクエリセットをシリアライズ、デシリアライズ
    serializer_class = MemberSerializer

    # getでpk有りの詳細情報を取得する際は下記実行される
    @action(methods=['get'], detail=True)
    def attach_san_to_name(self, request, pk=None):
        # Memberの指定したidのレコードを取得
        member = self.get_object()
        # memberの名前+さんをrespond
        return Response('{member.username}さん'.format(member=member))
```

このようにviews.pyを実装したのちに、
``デフォルトurl/attach_san_to_name/```でこの関数が実行される。

- methodsには対象のHTTPメソッドを記載
- detailはpkが必要な詳細データの場合はTrue, 一覧などが対象ならFalse
- get_objectは「クエリセットとオブジェクトの違い」で示したようにクエリセットならget_querysetを実装。

# 参考文献
[DjangoのORMとクエリセット](https://tutorial.djangogirls.org/ja/django_orm/)
[[Django REST Framework] View の使い方をまとめてみた](https://note.crohaco.net/2018/django-rest-framework-view/)
Visual Studio 2019 使用上の備忘録

### 文字コード utf-8

.editorconfig
https://qiita.com/magnet163/items/b1061be4fb1c1833c156

```config
root = true
[*]
charset = utf-8
```

utf-8 utf-8-bom
https://developercommunity.visualstudio.com/t/editorconfig-support-interprets-charset-utf-8-as-u/22922
「enabled a BOM is inserted on save」保存時にBOMを挿入

ソース文字セットと実行文字セットを設定
https://docs.microsoft.com/ja-jp/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170
[プロパティ ページ][構成プロパティ][C/C++][コマンド ライン][ 追加オプション] 
/source-charset:utf-8 /execution-charset:utf-8

### x64 コンパイル判別

定義済みマクロ
https://docs.microsoft.com/ja-jp/cpp/preprocessor/predefined-macros?view=msvc-170
```_M_AMD64``` x64 プロセッサをターゲットとするコンパイルの場合、整数リテラル値 100 として定義されます。
```_M_IX86``` x86 プロセッサをターゲットとするコンパイルの場合、整数リテラル値 600 として定義されます。
```_M_X64``` x64 プロセッサをターゲットとするコンパイルの場合、整数リテラル値 100 として定義されます。
```_WIN32``` コンパイル ターゲットが 32 ビットの ARM、64 ビットの ARM、x86、または x64 の場合、1 として定義されます。
```_WIN64``` コンパイル ターゲットが 64 ビットの ARM または x64 の場合、1 として定義されます。


### コンパイラ判別

```c++
#if 	defined(_MSC_VER)
// VisualStudio のコンパイラバージョン
#elif	defined(__GNUC__)
// GCC のメジャーバージョン
#elif	defined(__IAR_SYSTEMS_ICC__)
// IAR のコンパイラ(コンパイラプラットフォーム番号)
#elif	defined(__CCRX__)
// CS+ の定義済みマクロ値 (値は1)
#endif
```
Chromeシークレットを複数開く

## やりたいこと

開発を行っていて、2種類のユーザでログインして動作確認等をしたいときがあると思います。
もちろん、2種類であれば通常とシークレットで使い分ければ可能です。（あるいは別ブラウザ等）

3種類以上となるとそうもいかないので、Google Chromeでシークレットを2つ以上開く方法をメモがてら記載。

## 実行方法

user-data-dirにはChromeに関するファイルが展開されるので、あらかじめフォルダは用意して下さい。

```shell
#!/bin/sh
"${HOME}\AppData\Local\Google\Chrome\Application\chrome.exe" --user-data-dir=${HOME}/tmp/chrome1 --incognito
```

以上。
コマンドラインから.Netアプリを発行する

## 0. はじめに

Visual Studioで.Net Coreアプリを開発した際、コマンドラインからWindows・Linuxアプリを発行する必要があったので、方法についてまとめてみました。

## 1. dotnet publishコマンド

`dotnet publish`コマンドを使うことで、色々なオプションを指定して各アプリの発行ができます。
以下、オプションの指定方法について記載します。
※なお、私が必要としたオプションのみ記載しています。その他のオプションを確認したい場合は[**dotnet publish**](https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet-publish)を参照ください。

```
dotnet publish
    [<PROJECT>|<SOLUTION>] ・・・1-1. ビルド対象
    [-c|--configuration <CONFIGURATION>]・・・1-2. ビルド構成
    [-o|--output <OUTPUT_DIRECTORY>]・・・1-3. 出力ディレクトリのパス
    [-r|--runtime <RUNTIME_IDENTIFIER>]・・・1-4. ランタイム
    [--self-contained [true|false]]・・・1-5. 自己完結型か
```

#### 1-1. ビルド対象
ビルド対象となるプロジェクト、又はソリューションのパスを指定します。
指定しない場合はカレントディレクトリが対象となります。

#### 1-2. ビルド構成
ビルド構成を指定します。指定しない場合は**Debug**となります。

| 設定値 | 説明 |
|:-:|:-:|
| Debug(既定値) | Debugビルド  |
| Release  |  Releaseビルド |

#### 1-3. 出力ディレクトリのパス

アプリケーションを出力するディレクトリのパスを指定します。
指定しない場合は以下のディレクトリに出力されます。

- フレームワーク依存・・・`[project_file_folder]/bin/[configuration]/[framework]/publish/`
- 自己完結型・・・`[project_file_folder]/bin/[configuration]/[framework]/[runtime]/publish/`

#### 1-4. ランタイム
発行対象とするアプリケーションのランタイムIDを指定します。
※以下は一部のみ記載しています。指定可能なランタイムID(RID)の一覧については、[**RIDカタログ**](https://docs.microsoft.com/ja-jp/dotnet/core/rid-catalog)を参照ください。

| 設定値 | 説明 |
|:-|:-|
| win-x64 | Windows(64ビット)  |
| win-x86 |  Windows(32ビット) |
| linux-x64 | CentOS、Debian、Fedora、Ubuntuなどのディストリビューション |

#### 1-5. 自己完結型か

自己完結型で発行するか、フレームワーク依存で発行するかを指定します。指定しない場合は**自己完結型**となります。

| 設定値 | 説明 |
|:-|:-|
| true(既定値) | 自己完結型  |
| false  |  フレームワーク依存 |


## 2. 使用例

- 自己完結型でlinux-x64アプリを発行する

```
dotnet publish .\hoge.csproj -c Release -o C:\output -r linux-x64 --self-contained true
```
【Ruby on Rails】データベースを削除する方法

こんにちは！安田駿介です！

今回は「Railsでデータベースを削除する方法」というテーマで解説していきます。

# ターミナルで「rails db:migrate:reset」と入力する

これだけですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1903726/74424c26-09c3-a93b-1a9a-d9846f44a29b.png)

という結果になります。

#開発環境
・Cloud9
・Ruby 3.0.0
・Rails 6.1.3.1
・MySQL2
Power Automate でオブジェクトへの値の追加

## 経緯

単純な Key-Value のオブジェクトに値を追記していくだけ...
というのがスマートなやり方が判らずにシンプルな方法で対応しました

一般的なプログラムで行われる自己参照での値の代入ができないんですねぇ
![20211231_2_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/abdbd4a2-335c-c3ba-aa30-87e8296422bc.png)

## 対応方法

自己参照は駄目だぞっと言われているので、一時変数を用意しました

試したフローの全体はこちら
![20211231_2_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/252b31d1-f75d-ce3b-a790-421bf5b79f89.png)

最初の変数の初期化はこちら
![20211231_2_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/52d62fdb-99da-5b33-8d7b-1ce7c2382d1a.png)


Do until では、テキトーにループカウントが 10 になったら抜けるようにしています
![20211231_2_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/d25622c1-9020-effe-54d3-2b03e71136d0.png)


「Object に key, value を追加して tmpObject に格納」の値は下記のように設定されています

```bash
addProperty(variables('Object'), concat('key-',variables('Count')), concat('value-',variables('Count')))
```

addProperty の返り値はプロパティを追加したあとのオブジェクトになり、それを一時変数に
保存したあと、元の変数に設定しています

## 実行結果

想定通り追加されていることがわかります
![20211231_2_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/1b5bf561-2fc0-dee8-1a2f-b4b407e34fa0.png)


## 考察

今回は、複数回同じ SharePoint リストに問い合わせるのが勿体ない気がして、
一旦別のオブジェクトに退避できないか？ということで調べていました

他にいい方法知っている人がいたら、優しく教えてほしいです
Ruby on Railsを基本からまとめてみた【1】【概要と特徴】

##Ruby on Railsとは

Ruby on Railsはプログラミング言語「Ruby」で利用される代表的なフレームワーク。

##フレームワークとは

システムを開発するために必要な機能がまとまったものをフレームワークと呼ぶ。
文字通り「枠組み」を表し、システム開発がより簡単に行えるように便利なプログラムがひとまとまりとなったシステムを指す。

##Ruby on Railsの特徴

####MVCアーキテクチャー
Ruby on Railsは、MVCアーキテクチャーの基づいたフレームワークである。
データベースとのやり取りやビジネスロジックなどを担当するモデル(Model)、ブラウザへの表示を担当するビュー(View)、モデルやビューへの指令を与える役割としてのコントローラー(Controller)それぞれの頭文字を取ってMVCアーキテクチャーと呼ばれる。

MVCアーキテクチャーによって、機能毎の独立性が高く、開発効率・保守性ともに高いアプリケーションを構築することが可能である。

####CoC
Convention over Configurationの略称で、日本語では「設定より規約」を意味する設計思想のこと。
設定を大量に記述するのではなく、規約に沿ったプログラミングにより余計なコーディングや設定を減らそうという考え方である。

####DRY
Don’t Repeat Yourselfの略称で、日本語では「同じことを繰り返さない」を意味する設計思想のこと。
複数の場所に同一コードを記述するのではなく、1箇所に記述した内容を再利用することで保守性を高める考え方である。

####REST
Representational State Transferの略称で、同じURLでもGETメソッド・DELETEメソッド・PUTメソッドそれぞれのアクセス時に取得・削除・更新と異なる動作が実行される設計思想のこと。
RESTの思想により、Ruby on RailsではCRUDシステムを最小限のコードで実現でき、開発効率の向上が期待出来る。

####ORM
Object-Relationalmapping日本語で「オブジェクト関係マッピング」と呼ばれるもので、SQL文を記述しなくてもデータベースを操作することが出来る機能である。
Ruby on Railsでは「Active Record」というライブラリが採用されており、SQLに詳しくない開発者でもデータベース操作を簡単に行うことが可能。
[Rails] rspec(+α)のセットアップ手順

# 1. 導入
## 1.1. rspec本体のインストール
以下参考に実施

https://github.com/rspec/rspec-rails

https://qiita.com/TerToEer_sho/items/472e14df6fbb8e83ebf9

## 1.2. 関連gem(factory_bot, faker)のインストール
- factory_bot: ダミーデータのレコードを作るツール
- faker: レコード内のカラム値をランダムにセットしやすくするツール

以下参考に実施

https://qiita.com/TerToEer_sho/items/472e14df6fbb8e83ebf9

## 1.3. 動作確認
### 1.3.1. specファイル, facroryファイルが生成されること
https://github.com/rspec/rspec-rails

のUsageを参考に以下の状態になることを確認

```
# modelファイルをrails gコマンドで生成したとき
bundle exec rails g model <model> --migration-skip
=>
以下が生成されればOK
- app/models/<model>.rb
- spec/models/<model>_spec.rb
- spec/factories/<models>.rb

# rspec関連ファイルのみを生成したいとき(すでにmodelファイルが存在するときなど)
bundle exec rails g rspec:model <model>
=>
以下が生成されればOK
- spec/models/<model>_spec.rb
- spec/factories/<models>.rb
```

### 1.3.2. rspecがうまく動作すること
```
# [前提] 3.1 によってデフォルトの<model>_spec.rb が生成されている状態であること

# テストを実行する
bundle exec rspec
=>
以下のように表示されればOK(※)
Finished in 0.00552 seconds (files took 2.32 seconds to load)
1 example, 0 failures, 1 pending
```

※以下のエラーが表示される場合は、おそらくtest環境向けのDB周りが適切でない(接続設定がおかしい, test環境向けのDBがそもそも存在しない、テーブル定義が反映されていない など)ことが原因

```
An error occurred while loading ./spec/models/user_spec.rb.
Failure/Error: ActiveRecord::Migration.maintain_test_schema!

ActiveRecord::ConnectionNotEstablished:
  Can't connect to local MySQL server through socket '/run/mysqld/mysqld.sock' (2)
```

これは、``spec/rails_helper.rb``
というファイル内で、

```
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
```
という記述があり、RAILS_ENV は testになる


参考: https://shinkufencer.hateblo.jp/entry/2019/12/28/000000

# 2. 使いやすくカスタマイズ
## 2.1. Factorybot
### 2.1.1. Facrorybotのクラスメソッド名だけでのcreate

rails_helper.rbに以下を追加([参考](https://forest-valley17.hatenablog.com/entry/2018/10/03/080922))

```rails_helper.rb
  config.include FactoryBot::Syntax::Methods
```

## 2.2. rspecで使用するファイルの置き場
一般的に、**specファイル内で使用するファイル(画像とか)は、``spec/``配下に``fixture/files/``というディレクトリを作成し、配下に置いておくもの**らしい。

こうしておくと、
specファイル内で、``file_fixture('<画像ファイル名(パス不要)>')``とするだけで、``File.open('<パス>/<画像ファイル名>')``と同じ挙動となり、ちょっとシンプルに書ける。