OmniAICreator/Qiita-1.07M huggingface dataset:
ActiveModelSerializerのserializerとeach_serializerの違い


# ActiveModelSerializerとは
***RailsでAPIを作る時、 JSON形式(わかりやすく）にしてくれるgem***のことです。

# serializeを使うとき

例えばstaff一覧をコントローラーで取得する時
これはあくまで例です。

```rb
def index
      @staff = Staff.new
      render json: staff, serializer: StaffSerializer
    end

```
serializerと書くとStaffSerializerを呼び出してくれる。
これはstaff１人を呼び出す時に使う。

# each_serializeを使うとき
staff詳細を取得する時

```rb
def show
      @staffs = Staff.all
      render json: staffs, each_serializer: StaffSerializer
    end

```
each_serializerを使うときは、複数取得したいときに使います。

他にもcreateやupdateで１人ではなく複数を取得するときに使います。

簡単な記事だったのとコードはあくまで一例ですのでご了承ください。


⚫︎参考資料
https://lhiroki1205.hatenablog.com/entry/2019/08/25/151413
https://stackoverflow.com/questions/53587217/active-model-serializer-each-serializer-vs-serializer
https://qiita.com/Hashimoto-Noriaki/items/91c2bb94bce87495193e
まだLaTeXでラクしてるの？大学のレポートをしっかりWordで書いてがっつり消耗しよう！

[Overleaf](https://www.overleaf.com/)や[Cloud LaTeX](https://cloudlatex.io/ja)のように手軽に使えるオンラインLaTeX環境が充実した令和の時代とは言え、LaTeXが使えない時代錯誤な環境、あるいはWord文書ファイルでの入稿という劣悪な労働条件で仕事をこなさなければならないことが人生にはある。LaTeXはお前の心の甘えだ。


## 相互参照可能な数式番号を入れる

いろいろ方法はあるが、結局、表を使うのが一番よさそう。

1. 1行×3列の表を挿入する。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/a7116ba4-a920-53cc-18e1-2b875723bac3.png)

1. 挿入した表のプロパティを表示する。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/2407d7bd-5cb1-34cf-5852-1600e85fe113.png)

1. 表の幅をページ幅の100%に指定する。 
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/aeb2171c-0d34-2ab5-9896-13b35e657373.png)

1. 列の幅をそれぞれ、10%、80%、10%に指定する（合計が100%であればよい）。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/b1f1c623-b867-088d-22ca-2e34e8c4eebd.png)
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/e7f52c6b-d6bf-ac6c-63b1-6bd0372cea31.png)
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/bc363b07-0f0f-7e2b-bc7b-6e7801cfc680.png)

1. 「OK」をクリックすると、こんな感じの表になる。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/3cebcfc2-9247-914e-b704-97b80723b76f.png)

1. 好きな数式を真ん中のセルに挿入する。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/bb7a3afd-eccc-f992-1127-7315f0fbd149.png)

1. 表の外に式番号を図表番号として挿入する。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/286f7ec9-d142-4513-b84f-50bf78a483f7.png)

1. お好みで`()`などに入れたりするとよい。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/d45c9a12-a2fa-501f-fa46-50c32506c375.png)

1. 切り取り&貼り付けで右のセルに式番号を移動する。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/015e20c3-1787-5458-bedb-4b7e11acd266.png)

1. 右のセルの配置を中央揃え（右）にする。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/4a7d12bd-262a-a882-0d77-d0b8f90afc33.png)

1. 表を枠なしにする。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/5fcdc83e-ac5b-e5ab-6005-69257717d933.png)

1. 完成。悪くないだろう。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/83042d60-1924-c282-224f-82900633ef3a.png)

1. 式番号は相互参照できる。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/b2f26bcd-f562-ecbb-6e94-aa2f3a141581.png)

1. できた数式入りの表を好きなところにコピー&貼り付けで増殖してもよいし、数式ギャラリーに保存しておいても便利である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43042/4734d774-bb9a-5acc-f87b-092a82eeac08.png)


## 以後、追記するかもしれないもの

- 文献目録のスタイルのカスタマイズ：BibTeXならBSTファイルを変更するだけで簡単に参考文献のスタイルが編集できるが、WordではXMLファイルを変更する必要がある。


## 参考にしたもの

- [How do you easily add equation numbers to Microsoft Word 2010 equations?](https://superuser.com/a/594560)
ヨーダ記法はインデックスの夢を見るか

## 前文
```SQL
WHERE	(Col1 = 1 OR Col2 =1)
```

上記のようなクエリは以下のように正規化（？）することができる。

```SQL
WHERE	1 IN (Col1, Col2)
```
少しだけ単純になる。「仕様変更に強い」かは置いといて。
面白いのは結果として、所謂 [ヨーダ記法](https://ja.wikipedia.org/wiki/%E3%83%A8%E3%83%BC%E3%83%80%E8%A8%98%E6%B3%95 "ヨーダ記法 - Wikipedia") になること。
ヨーダ記法の是非はここでは論じない。それよりも問題はインデックスが効くのかこれ？ という素朴な疑問。クエリである以上。
ざっとぐぐったところ答えが見つからなかった（クエリでヨーダ記法なんて普通書かないだろうし）ので確認した次第。

## 環境
| SQLServer | SQLCMD |
| ---- | ---- |
| 2017 | 14.0.1000.169 |
設定はデフォルト。

## 結論
効く。

そもそも IN句とは、OR で連結した等式の [シンタックスシュガー](https://ja.wikipedia.org/wiki/%E7%B3%96%E8%A1%A3%E6%A7%8B%E6%96%87 "糖衣構文 - Wikipedia")。

```SQL
WHERE	Col1 IN (1, 2)
```
よく IN句の説明で、上記のクエリは以下のクエリと同じ、みたいな説明を見かける。

```SQL
WHERE	(Col1 = 1 OR Col1 = 2)
```
同じも何も、IN句は内部的には後者のように展開される。IN句を直接解釈できる DB なんて自分が知る限り存在しない。（多分）
IN句の括弧の中身が SELECT文のケースを除き、値がリストとして列挙されている場合、機械的に OR で連結した等式に置き換えることができるから。
そうすれば後は通常のクエリとして処理することができるし、わざわざ IN句専用の実行プランを実装する必要はない。

余談ついでに。
長年三項演算子（条件演算子）的な機能が求められていた SQLServer。
よく掲示板でも、SQLServer で三項演算子みたいなことを行いたい場合は？ といった質問に対して、CASE式で代用してくださいというやり取りが定番だった。
それが 2012 から [IIF関数](https://docs.microsoft.com/ja-jp/sql/t-sql/functions/logical-functions-iif-transact-sql?view=sql-server-ver15 "IIF (Transact-SQL) - SQL Server _ Microsoft Docs") が追加された。でもこれって恐らく内部的には CASE式に展開されているんだよね。つまり、CASE式のシンタックスシュガー。
システムとして用意されたのは有難いけど。

で、話をヨーダ記法に戻す。実行プランを確認したら以下だった。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/614ea67c-4d78-0b44-883e-30062e8dd209.png" width=50%>

そもそも `1 = Col1` でもインデックスは効くんだね。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/919f22df-5d8b-70b1-8f48-d2b585f22a3b.png" width=50%>

因みに上記は `Col1` が主キーだけど、キーが張られていない場合は以下だった。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/863751bf-e8cc-f877-444a-1216b1cdcc57.png" width=50%>

OR で連結した等式に置き換えるだけではなく、列名を左に置き換てくれるんだね。一種の正規化処理といえるのかな。
つまり場合によっては、

```SQL
WHERE	1 IN (Col1, Col2)
```
と書いたところで、結局一周周って以下に展開されるというね。

```SQL
WHERE	(Col1 = 1 OR Col2 =1)
```

主キーの有無によって展開のされ方が微妙に異なるのは興味深い。因みに Oracle でも確認したところ同様だった。恐らく大抵の DB で同じと思われ。
May the Force be with you.
Python(Flask)とA3RT Talk APIを使ってLINEのチャットボットを作る


##概要
FlaskとMessaging API、あとリクルートが無料で配布しているA3RT Talk APIを使用して、LINEのチャットボットを作成しました。

##実装

###各種API KEYの発行

A3RT Talk API
https://a3rt.recruit-tech.co.jp/product/talkAPI/

LINE Developers
Messaging API
https://developers.line.biz/ja/


###各モジュールをインストール

```
pip install python-dotenv
pip install flask
pip install flask_ngrok
pip install line-bot-sdk
pip install pya3rt
```

###設定ファイル

```tex:各種キーを.envファイルに設定する（.envは必ず.gitignoreする）
A3RT_API_KEY = XXXXXXXXXXXXXXXXXXXX
CHANNEL_ACCESS_KEY = XXXXXXXXXXXXXXXXXXXX
CHANNEL_SECRET_KEY = XXXXXXXXXXXXXXXXXXXX
```


###Pythonのソースコード
flask_ngrokモジュールをインストールすることで一時的なURLが発行され、
ローカル環境でもAPI通信の実装ができるようになる。

```python
from flask import Flask, request, abort
from flask_ngrok import run_with_ngrok
from dotenv import load_dotenv
from linebot import LineBotApi, WebhookHandler
from linebot.api import LineBotApi
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
import pya3rt
import os

app = Flask(__name__)

run_with_ngrok(app)
load_dotenv()

A3RT_API_KEY       = os.environ['A3RT_API_KEY']
CHANNEL_ACCESS_KEY = os.environ['CHANNEL_ACCESS_KEY']
CHANNEL_SECRET_KEY = os.environ['CHANNEL_SECRET_KEY']
linebot_api = LineBotApi(CHANNEL_ACCESS_KEY)
handler = WebhookHandler(CHANNEL_SECRET_KEY)



@app.route('/callback', methods=['POST'])
def callback():
  signature = request.headers['X-Line-Signature']
  body = request.get_data(as_text=True)
  try:
    handler.handle(body, signature)
  except InvalidSignatureError:
    abort(400)
  return 'OK'



@handler.add(MessageEvent, message=TextMessage)
def handle_massage(event):
  ai_message = talk_api(event.message.text)
  linebot_api.reply_message(event.reply_token, TextMessage(text=ai_message))



def talk_api(word):
  client = pya3rt.TalkClient(A3RT_API_KEY)
  replay_message = client.talk(word)
  return replay_message['results'][0]['reply']


if __name__ == '__main__':
  app.run()

```

##gitHub
https://github.com/ysk/python_lineBot

取り急ぎ自分の忘備録として書きなぐった状態ですが、
誰かの参考になるかもしれないので、この状態で公開します。

上記ソースコードに色々機能を加えていこうと思う。
特定のセルだけ表示する方法

結論から言うと、高さを限りなく0にすることで実装が可能です。
そしてソースコードはこちら。
　

    func tableView(_ newsTable: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if ここに条件 {
            // 表示したい条件の場合
            return 25
        } else {
            // 消したい条件の場合
            return 0.1
        }
        return 0.1
    }

　
該当のコードを加える前
![スクリーンショット 2021-09-28 0.37.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/88ae84b6-85e8-ce7e-1513-397b1c92c534.png)
　
該当のコードを加えた後
![スクリーンショット 2021-09-28 0.37.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/3e24bf65-7eda-56ce-6ab5-9a0e4e9063bf.png)

必要のないセルは非表示にすればいいんじゃないかと思い、cell.isHidden = trueで消そうとしたんですが、セルの中の文字が消えるだけでセル自体が消えなかったので、こちらの方法を取りました。

特定のセルだけ表示する方法が知りたい方は参考にしていただけたら幸いです。
CCNA　VLAN 

今回はVLANについてアウトプットしていこうと思います。
VLANとはVirtual Local Area Networkの略で、
L2スイッチの技術の1つです。
VLANを使用することで、スイッチ内部でネットワークを仮想的に
分けることができます。

メリットが3つあります。
1つ目のメリットは端末の物理的な配置に依存しない
ネットワークを構築できることです。

本来ならネットワーク毎にスイッチが必要になります。
しかし、VLANを使用するとスイッチの内部で仮想的に
ネットワークを分けることができます。
スイッチを管理するために管理VLANが存在し、
デフォルトでVLANが管理VLANで設定されています。

2つ目のメリットはブロードキャストドメインを分割することです。
IPアドレスを変更してもブロードキャストドメインは分割されません。
これをVLANを分けることでブロードキャストドメインを分割することができます。

3つ目はセキュリティ対策になります。
VLANを使用しない時、IPアドレスを変更しただけで他のネットワークに
アクセスすることができます。
しかし、VLANを分けると他のそれを防ぐことができます。

では、VLANに関する言葉を覚えていきましょう。
まずは1つのVLANに所属しているポートをアクセスポートと言い、
アクセスポートに繋がっているリンクをアクセスリンクと言います。
しかし、複数のポートに所属しているとトランクポートと
トランクリンクに変わります。
このVLANを割り当ては、手動のポートベースVLAN(スタティックVLAN)と
自動のダイナミックVLANに分かれます。
このMACアドレスが登録されていない時は受信したポートと同じ
VLANに属する全ポートから転送します。

ではトランクポートを通る際にどのVLANかが分からない状況になります。
これを防ぐためにVLANの目印をつける必要があります。
その目印は2種類あります。1つ目はCisco独自のISLフレームです。
これにはISLヘッダ(26バイト)とISLFCS(4バイト)を付けることで目印にしています。
２つ目はIEEEのフレームです。これは本来のフレームにタグ(４バイト)を付けます。
そして、FCSを再計算します。これにより送りますが、
トランクリンクの両サイドでトランキングプロトコルを合わせておく必要があります。
また、ネイティブVLANの方法もあります。
これはトランクポート毎に1つだけ設定できるもので、
これにはVLANを識別するタグが付加されません。
管理トラフィックを通し、お互いのネイティブLANを合わせておく必要があります。
WindowsからCodeCommitをSourceTreeで利用

`The requested URL returned error: 403`にハマりました

HTTPSだとWindowsの認証情報ヘルパーがうまく機能しないようで
認証情報ヘルパーを使用しない設定でGit for Windowsを再インストールするといいとのことですが
後日また同様のエラーがでて安定してくれませんでした。

結果、SSHで対応しました。

秘密鍵はこちらを参考に生成してみてください

https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/setting-up-ssh-windows.html

SSHキーの秘密鍵ファイルのパスは
`ツール>オプション>全般`から設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178806/b9f8db94-eb97-cb77-a02e-823ad1c675dc.png)


cloneする際のURIへIAMのアクセスキーIDを含めるようにします

IAMユーザーの認証情報タブ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178806/49afb259-8e13-dfe5-78fd-5feedc888a3d.png)

`ssh://<アクセスキーID>@git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/HogeHoge`

※クローン後にURIを変更したい際は
リポジトリの右上の`設定>リモート>設定ファイルを編集`から
エディタで`config`ファイルを開き、以下を編集

```
[remote "origin"]
	url = ssh://<アクセスキーID>@git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/HogeHoge
```

参考
---
https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/troubleshooting-ch.html#troubleshooting-windowshttps

https://www.netarium.jp/p-251/

https://qiita.com/A-Kira/items/0f5334919e330a95f198
WordPressバージョンアップ後にRedirectの無限ループの解決手順

`require_once ABSPATH`より前に以下を入れるだけ。SSLを使っているのでHTTPのアクセスがあれば強制的にHTTPSにする設定も入れておく。

```rugy:wordpresをインストールしたディレクトリ/wp-config.php
/** wp-admin access error */
define('WP_HOME','http://あなたのドメイン/wp');
define('WP_SITEURL','http://あなたのドメイン/wp');

/** HTTPS強制を正しく有効化 **/
define('FORCE_SSL_ADMIN', true);
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
     && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' )
{
    $_SERVER['HTTPS']='on';
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';
```
RealmSwift いつでも使える様に書き残し（保存、取得、削除）

#今回の内容

* Realmにデータを保存、取得、削除する関数を簡単に書き残しておきます。

#コード

##Model

```Swift:
import RealmSwift

class RealmDatasModel:Object{
    
    @objc dynamic var realmDataOne = String()
    @objc dynamic var realmDataTwo = String()
    
}
```

##class作成

```Swift:
import RealmSwift

class RealmCRUDModel{
    
    var readResultRealmDataArray:[[String:String]] = []   
}
```

##保存

```Swift:
extension RealmCRUDModel{
    
    func createRealmData(createContentOne:String,createContentTwo:String){
        
        do{
            let realm = try Realm()
            let realmDatasModel = RealmDatasModel()

            realmDatasModel.realmDataOne = createContentOne
            realmDatasModel.realmDataTwo = createContentTwo
            
            try realm.write({
                
                realm.add(realmDatasModel)
            })
            
            print("createRealmData\(realm.objects(RealmDatasModel.self))")
        }catch{
            
            //エラー処理
        }
        
    }
}
```

##取得

```Swift:
extension RealmCRUDModel{
    
    func readRealmData(){
        
        do{
            
            let realm = try Realm()
            
            readResultRealmDataArray = []
            
            realm.objects(RealmDatasModel.self).forEach { realmData in
                
                readResultRealmDataArray.append(["realmDataOne":realmData.realmDataOne,
                                                 "realmDataTwo":realmData.realmDataTwo])

                print("readRealmData\(readResultRealmDataArray)")
            }
        }catch{
            
            //エラー処理
        }
    }
    
}
```


##削除

```Swift:
extension RealmCRUDModel{
    
    func deleteRealmData(){
        
        do{
           
            let realm = try Realm()
            
            try realm.write({
                
                realm.delete(realm.objects(RealmDatasModel.self))
            })
            
        }catch{
            
            //エラー処理
        }
    }
}
```


#終わり
ご指摘、ご質問などありましたら、コメントまでお願い致します。
STM32 チャタリング処理 その3

チャタリング処理をさらにいろいろ考えた。

いわゆる de-bounce 処理をするだけじゃなく，それを受けとるプログラム側でもいろいろな工夫の余地があって，ニーズによって対応のさせ方が違うはず。たとえばこのボタンはオフトリガーダブルクリック対応，こっちはオントリガー，リピート有りみたいな。

趣味で全部作るのは辛いので，さしあたり必要なものを作るにとどめることにした。

ダブルクリックは面白そうだが，作る苦労を考えると保留でいい。とりあえず複数押しに対応させよう。リピートも面倒そうなので却下。

複数押しとオントリガーなら同時対応できそうだ，ということで作ってみた。

https://github.com/numeru55/NUCLEO-F303K8_PushButtons

```cpp:main.c
	Button_Init(GPIOA, GPIO_PIN_11); // bit 0
	Button_Init(GPIOB, GPIO_PIN_0);  // bit 1
```

で定義するのは前回とほぼ同じ。32個まで対応。

```cpp:main.c
		uint32_t k = Button_Loop();
```

で複数ボタンの情報を一気に取るようにした。チャタリング処理込みで，「同時に押された」と判定したビットが立っている感じ。

```cpp:main.c
	while (1) {
		/* USER CODE END WHILE */
		/* USER CODE BEGIN 3 */
		uint32_t k = Button_Loop();
		if (k) {
			Button_Clear();
			// （中略 ボタンが押された時の処理）
			}
		}
	}
	/* USER CODE END 3 */
```

「取りこぼし」を防ぐため，ライブラリー側では「押された」情報をクリアしない。そのかわり，mainループで `Button_Clear()` してクリアする。（実際はさらにde-bounce処理してボタンを離すのを待っている）

使ってみた。少し離れた2個ボタンの同時押しはちょっと難しいかも。でも簡易的に使うにはいいかなあ。そもそもがお客様にがっつり使ってもらう部分じゃなくて，自分で回路の確認で使うだけだし...（言い訳モード）
さらに今さらSTM8でLチカ　(STM8は、すべてにおいて理想的に設計されたCPUだが?)



Stm8は、理想的に設計されたcpuだが
AL(アキュムレーター)が1つしかないために現実には遅いく
ALは、一つだろうとつこみたく気持ちもわかるが他のCPUは、
汎用レジスターがある
ロシアや中国でなぜか使われている100円以下のCPU、周辺は、32ビットと同じ
今となっては、16Mhzと遅い、水晶の絡みで当時しては、正しい、倍速回路無
最適化しづらい　ほぼ失敗
学習にはいいcpu マイナー系cpu
最後は、遅さに怒って捨てられる運命 (ぷんぷん丸)
全ての処理がAL経由でしかも8ビット
16ビットの足し算で感想としては
20,30アセンブラステップかかり
最適化出来ない　コンパイラ作りは簡単
ビットが立っていないためにシリアルで書き込めない
メリットは、st-linkで書きこめる
開発環境が整備されている
大量に余っている<-ここ重要　10年以上不良在庫
　アタリショックもびっくり!!　砂漠に埋めるレベル
  半導体不足でもちょっとは、大丈夫　と、言う理由もある
ほぼ68系、ファミコン、アップルII、FM7
学習コストが0
どうだ「すごいだろー」

リンク

https://qiita.com/kotetsu_yama/items/97c8020f6ffd980d710b


勝手に応援



STM8S103F3P6ボードを試してみる



https://qiita.com/sat0ken/items/3d4c6bd29a0d6689e3a8






目的
stm32f103が目的?
とりあえずSTM8でLチカ


![o_con23.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/f01011ea-8b44-9360-7989-329ae3f53cca.jpeg)



arduinoIDE

STM8S-Discovery ボード

若松通商で約700円で調達

なぜか書き込めないので
ハードをいろいろ改造

SB2,SB1の半田を吸って切り離す

中華ST-LINKに
SWIM - SWIM
リセット - リセット
を接続
当然　中華ST-LINKのリセット改造ずみ


1.[ファイル]-[環境設定]


```c++


,https://github.com/tenbaht/sduino/raw/master/package_sduino_stm8_index.json



```

2.[ツール]-[ボード]-[ボートマネージャー]- STM8

3.[ツール]-[ボード]-STM8S Boards-STM8S105C6 Discovery Board

4.external St-Link/V programmer

5.次のプログラム



```c++


void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(200);
  digitalWrite(LED_BUILTIN, LOW);
  delay(200);
}


```

6.マイコンボードに書き込む　を　クリック

7.おしまい
Slack-sdk準備編（slack-sdkインストールとbotの準備）

この記事ではSlack-sdkのインストール方法を説明します。
pipとcondaの両方の方法がありますが、いずれも多くのライブラリ同様に1行コマンドを叩くだけで実行されるので特に難所はありません！

# Slack-sdkのインストール
### 必要な環境
- Python 3.6以上  
以上

### pipでインストールする
```
pip install slack_sdk
``` 
[公式Git](https://github.com/slackapi/python-slack-sdk#installation)ではpipを利用してインストールするように指定されています。

### condaでインストールする
```
conda install -c conda-forge slack-sdk
```
公式ではpipが推奨されていますが、自分はAnaconda環境使っていてpipしたくないという人もいるでしょう。そういった人も安心してください。conda-forgeに準備があるためこちらのコマンドを利用することでcondaでインストールできます。
筆者もこちらで実施しました[^1]。
[参考URL](https://anaconda.org/conda-forge/slack-sdk)
[^1]: Windows10, python3.9で実行

# Slack側でのappの準備
Slack-sdkから投稿するためにはSlack側のappの設定も必要なので設定をしていきます。

### Slack appを作成する  
[api.slack.com](https://api.slack.com/apps?new_granular_bot_app=1)からSlack appを作成します。リンク先に飛ぶと2つの記入欄（AppNameとDevelopmentSlackWorkspace）があるので設定します。  

https://api.slack.com/apps?new_granular_bot_app=1

- __AppName__
アプリの名前を入れましょう。ここで登録した名前が今後作成するコードを実行した結果される投稿の際の投稿者名になります（今回はtestbotにしました）。  

- __Development Slack Workpace__
作ったappを利用したいSlackのワークスペースを設定します。プルダウンメニューで自分の参加しているワークスペースの一覧が表示されるので、その中から投稿したりしたいチャンネルを選択すればOKです。

最後にCreate Appボタン（緑のボタン）を押せば完了です。



![slackapp作成画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373771/d442a0a1-87a9-b52f-8c36-e86ac37f0dc3.png "OAuth & Permissionの場所")

### Permissionの設定  
次に作成したappの__Permission__を設定していきます。前ステップのCreateAppボタンを押して出てくる画面のサイドバーにある__OAuth&Permissions__から設定します。
![OAuth&Permissions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373771/755f0436-9803-4ea6-5e8f-41d968e4f4b5.png)

OAuth&Permissionsの画面中程の__Scopes__の__Bot Token Scopes__で具体的にappに何の実行を許可するかを設定していきます。
今回は、チャンネルへの投稿が目的のため__chat:write__をScopeに追加します。__Add an OAuth Scope__とかかれたボタンを押すと追加可能なScopeの一覧とその説明がプルダウンメニューで表示されるので、そこから追加したいものをクリックすれば完了です。追加できると下の画像のように追加されたScopeが一覧で表示されます。
![20210920_Scopes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373771/81b9b96d-e2e7-9472-5cb0-6e7a67c33e96.png "Scope登録画面")


### ワークスペースへのappのインストール
最後に作成したappをワークスペースへインストールします。
OAuth&Permissionsの最上部の__OAuth Tokens for Your Workspace__にある__Install to Workspace__をおします。
![20210920_install.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373771/25dd38f6-11d6-e641-d1cc-3a60cc236c0d.png)


次の画面では__許可する__を押します。これで完了です。
![20210920_install2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373771/0fa2a010-5615-3da7-0328-c767ecab50fa.png)


追加できているかを念の為確認します。今回作成したappを追加したワークスペースを見ると…
![20210920_install_complete.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373771/42744cca-6148-bc6f-12ec-8de77005faa5.png)

Appにtestbotがいますね！これで無事追加できたことが確認できました。
　　　

# おしまい
Slack-sdkのインストールとSlack側の準備
は以上です。
次回はインストールしたSlack-sdkをつかってSlackへ投稿を投げてみます。
Ruby 「nilの場合に○○を行わない」【イディオム】


## 改良前：if文を使って「nilの場合は行わない」
サンプルコードは、文字列長を求めるメソッドを作成しました。
こんなメソッドを普通には作ることは無いでしょうが、サンプルなので分かりやすさ重視です。

__サンプルコード__

```rb:length.rb
def get_length(text)
    if text # nil.sizeだとエラーになってしまうため回避。
        text.size
    end
end

puts get_length('abcde') # > 5
puts get_length('あいうえおかきくけこ') # > 10
puts get_length(nil) # > nil
```

## 改良後：safe navigation operator(&.)を利用する
__safe navigation operator__は`オブジェクト&.メソッド`でメソッドを呼び出すと、「オブジェクトがnilの時nilを返す」という演算子です。
これを使って先ほどのコードを改良します。

```rb:length.rb
def get_length(text)
    text&.size
end

puts get_length('abcde') # > 5
puts get_length('あいうえおかきくけこ') # > 10
puts get_length(nil) # > nil

```

以上。
Slack-sdkから新しい投稿をする

# 環境変数を設定する
実コードを作成していく前に、環境変数にappのトークンを登録します。

1. スラックのアプリ設定ページのOAuth&Permissionsのページ最上部の__Tokens for Your workspace__の__Bot User OAuth Access Token__にトークンが発行されていているのでコピーします。
1. 自分の環境変数に追加します。

以上で環境変数の設定は終了です。

#投稿する
それでは早速投稿していきます。コードは下記のとおりです。

```Python
from slack_sdk import WebClient

client = WebClient(token=os.environ['SLACK_BOT_TOKEN'])
client.chat_postMessage(channel='#random', text="Hello world!")
```
- 1行目
    - ライブラリのインポート

- 2行目
    - 投稿先の設定のためのおまじない。
    - 上で設定した環境変数の登録先にパスが通っていないとエラーになる
- 3行目
    - 投稿を実行している。
    - channel：投稿先のチャンネル名を指定。
    - text：投稿内容を指定。通常の文章の他に、:リアクション名:とすることで普段使っているリアクションを投稿することができる。


# おわり
この記事ではSlack-sdkから新しい投稿をする方法を紹介しました。
Nuxtコンポーネントマトリョーシカ問題🪆

PM「Nuxtで作ってるプロジェクトのhogeっていうページなんだけど、不具合があって、ちょっと見てくれない？」

ワイ「わかりました」

ワイ「pages/hogeを見てみるか」

```
<template>
<Hoge />
</template>
```

このHogeコンポーネントって他でも再利用してるのかな？
→してない

とりあえずHogeコンポーネントを開いてみるか

```
<template>
<HogeHeader />
<HogeContents />
<HogeFooter />
</template>
```

このコンポーネントって他でも再利用してるのかな？
→してない

不具合のあるコンポーネントはどれかな？
一個一個開いて確認しなくては

```
<template>
<HogeBlock />
<HogeImage/>
<HogeButton /> 
</template>
```

ワイ「いつになったら問題のコードにたどり着くんや」

## コンポーネントマトリョーシカ設計

こう言うコンポーネントマトリョーシカ🪆についてどう思いますか？

**コンポーネントは再利用性があるもの**
**機能的に分離して疎結合にし、コードの可読性を高めたいもの**

に限って使いたい派なので、このようなとりあえずなんでもかんでもコンポーネントにしろ、的な設計はうーんって感じます。

プロジェクトの規模にもよると思いますが。

そう思う
これでいい

などコメント欄やSNS引用で広くバトルしていただけたらと思います。
EC2 (プライベートサブネット) を Systems Manager で管理する設定

#環境

環境は以下の通り。
SSM エージェントが必要となるため、Amazon Linux 2 を使用。

| パラメータ | 値 |
|:------------:|:------------:|
| VPC       | 10.0.0.0/16 |
| AMI       | Amazon Linux 2 |

#SSM 用の IAM ロールのアタッチ

以下にある通り、`AmazonSSMManagedInstanceCore` が含まれた IAM ロールを作成し、EC2 にアタッチする。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/setup-instance-profile.html


#VPC エンドポイントの作成

以下の VPC エンドポイントを作成する

・com.amazonaws.region.ssm
・com.amazonaws.region.ec2messages
・com.amazonaws.region.ssmmessages

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224973/108412c1-ff46-9fc9-e151-7f3f81678144.png)

その際に、作成するセキュリティグループは以下の通り。

・HTTPS
・VPC の CIDR (今回は 10.0.0.0/16)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224973/7fa5f5ba-caab-9039-8889-0b65320edcce.png)


ここまですると、以下の通り、Systems Manager の管理下に入った。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224973/b1ad9575-569b-eec4-087c-2061c94840b3.png)


#参考資料

https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-systems-manager-vpc-endpoints/


https://dev.classmethod.jp/articles/tsnote-private-ec2-ssm-vpc-endpoint/
カプセル化をわかりやすく

##前提として
本記事は私自身の備忘録として執筆しています。
ですので間違っていたらご指摘いただけますと幸いです。
少々わかりにくい部分や表現がありますことをご了承ください。

※そもそもカプセル化という言葉自体、抽象的な言葉で本記事では実際にprivateを使ったケーススタディを紹介しています。

##イメージ
まず「カプセル化のイメージ」について
・何かに包まれている
・外から守られている
・カプセル化を崩すとあまりよろしくない　等

こちらが私が最初に聞いた時のイメージです。
結論から言うと、これらは概ね正解と言えるでしょう。

##どこから守るのか
カプセル化についてはオブジェクのデータやメソッドについて使われることが多いようです。

一言で言うと「オブジェクト内にあるデータ」を外部からの不正アクセスから守ると言うことになります。

すごく簡単に言い換えるとこうです。
「そのオブジェクトやメソッドに対する外からのデータアクセスを拒否する」
と言うことです。

##なぜ守るのか（カプセル化の必要性）

目的は大きく分けて２つです。
・外部から不正なアクセスから守る
・外部から意図しない変更をさせない

これらより、カプセル化を実装しないとコードの保守や可読性が落ちてしまい、予期せぬエラーやコンパイルが通らないことも起こり得ます。
また、後でコードに微修正を加えたい場合にも思わぬところで時間を取られてしまい生産性が低下しますのでチームで開発する場合は必ず実装しなければなりません。

##ではどのようにしてカプセル化するのか

実装については簡単です。
データアクセスを制限すればよいのでその言語に使われる「アクセス修飾子」を用います。
※アクセス修飾子については[こちら](https://qiita.com/GATA/items/90341f56a56ff584e756)を参考

しかしこれらの修飾子全てをカプセル化に使うということではありません。
基本的にはこの中でも「private」を使います。そりゃそうですよね。アクセスを制限するのですから。。
privateを使うことでclassなど宣言内でしかアクセスできなくなります。

###余談
これらのカプセル化をちゃんと実装していて、
他の人がコードを読み”カプセル化されていないオブジェクト”を発見すると、
「あ！このオブジェクトは外部から変更が加わるものなんだな」と言うことが一瞬でわかります。

###追記
僕自身カプセル化の知識についてまだまだ勉強不足だったところがあり、
厳密いうとこれがカプセル化の全てではありません。しかし言葉のイメージとして伝わっていただけますと幸いです。
ABC199 C - IPFL が解けた

https://atcoder.jp/contests/abc199/tasks/abc199_c

![abc199_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/1bd34349-9639-9b9a-0035-1fb9264ba390.png)
![abc199_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/9b69cd8e-08d0-2e9a-bb45-843595afaa9c.png)
![abc199_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/838f30b3-e9b0-753d-72d5-5ff8e15fc080.png)

出来たが、WA x2 を引いてしまった。

```IPFL.py
n = int(input())
S = input()
front = list(S[:n])
rear  = list(S[n:])
Q = int(input())

for _ in range(Q):
    t,a,b = map(int,input().split())
    if t == 1:
        if a <= n and b <= n:
            front[a-1], front[b-1] = front[b-1], front[a-1]# <= ココ 1
        elif a <= n and b > n:
            front[a-1],rear[b-n-1] = rear[b-n-1],front[a-1]
        elif a > n and b > n:
            rear[a-n-1],rear[b-n-1] = rear[b-n-1], rear[a-n-1] # <= ココ 2 
    else:
        front,rear = rear,front
        #print(front, rear)

print("".join(front+rear))
```

コメントにある ココ 1 , ココ 2 を考える事が出来なかった。
diff 茶色最弱問題ではあるが、なんだかスッキリしない終わり方だった。
Next.js(ver.11.1.2 )でImageタグを使用しての画像表示できない場合の対処法

#はじめに
Next.jsでの開発中に画像を表示しようとしたところ表示できずに困ったのでメモ

#問題
以下のコードではダメだった

```

<Image src=/public/sample.png width={100} height={100} />

```

#解決法
以下のコードで解決した

```
const image = require(../../public/sample.png);

...

<Image src={image} width={100} height={100} />

```

#追記(2021/09/29)
公式のドキュメントを読んでいたら, 以下のコードで画像を取得できることがわかった。

```
import image from "../../public/sample.png";
```
この時,  importする名前は適当で良い。
Brave開発環境構築時の「fatal: repository 'undefined' does not exist」を解決できる(かもしれない)方法

Braveブラウザ(正式名称はBraveだったことを執筆時に知りました....)の開発環境構築時に壁にぶつかったので記録として。
## きっかけ
Braveのデザインや技術が気になっていた&ネッ友が日本語の文献が少ない状況で環境の構築方法等を
日本語で書き起こしていたため。
感謝しかありません....🙏


## 問題の発生する環境
筆者が確認できたのは
・Windows11(Build22000.194)
・Node.jsが現時点の最新版(16.10.0)の環境
・npm(ver.5)
だけです。（他に同様の問題が発生する環境がある場合お知らせください

## 解決法
Node.jsをWindowsから完全に削除することで解決しました。
# 手順
・コマンドプロンプト(この場合はWindows ターミナル)で
```npm cache clean --force```
を入力する。
・以下のフォルダを削除する
```C:\Program Files (x86)\Nodejs
C:\Program Files\Nodejs
%APPDATA%\Roaming\npm
%APPDATA%\Roaming\npm-cache
%USERPROFILE%\.npmrc
%APPDATA%\Local\Temp\npm-*```

これを実行した後、Node.jsの再インストールを実行する。

これだけ!

## この記事を書いて
Qiitaの記事書いてる人ってすごいんですね....。
これを書くだけで数時間悩んでしまいました
これからも拙い文章ではありますが新しい発見があり次第記事にしていきたいと思います。
よろしくお願いします。

## 参考🙏
ネッ友が書いた有難い記事
https://qiita.com/surapunoyousei/items/d113c5fa39f206e25c6c
fluent-bitを使ってログをLog Analyticsに転送する サイドカー編

作業環境が必要なのでAKSのクラスタを作ります。

```bash
az aks create \
    --resource-group $RESOURCE_GROUP \
    --name $CLUSTER_NAME \
    --node-count 2 \
    --generate-ssh-keys \
    --node-vm-size Standard_B2s \
    --network-plugin azure
```

クラスタができたら、kubectlを使えるようにします。

```bash
az aks get-credentials --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP
```

ワークスペースIDとワークスペースKeyを指定して以下のYAMLをデプロイします。

```yaml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.3-perl
        ports:
        - containerPort: 80
        volumeMounts:
        - name: log-volume
          mountPath: /var/log/nginx
      - name: fluentdbit
        image: fluent/fluent-bit:1.5-debug
        command: ["/fluent-bit/bin/fluent-bit",  "-i", "tail", "-p", 'path=/var/log/nginx/*.log', "-o", "azure", "-p", "customer_id=ワークスペースID", "-p", 'shared_key=ワークスペースのID', "-m", '*' ,"-f", "1"]
        volumeMounts:
        - name: log-volume
          mountPath: /var/log/nginx
      volumes:
        - name: log-volume
          emptyDir: {}
```

curlを2, 3回たたいて10分ほど待つと、反映されると思います。

```bash
kubectl exec -it nginx-deployment-676dfb48c7-6x888 -c nginx -- curl "http://localhost"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16609/5b32b635-57f2-9bff-a968-3727f39bcee3.png)
React 入門道場　~ES6できることのまとめ~

#はじめに
以前、ES5,ES6の違いについて学習しました。しかしながら、ES6でできることに関して纏めていなかったので今回勉強したことをアウトプットしていきたいと思います。

https://qiita.com/kinoshitaken123/items/3d9a56fcfc0d219f45de

#ES6(ES2015)

* 変数宣言はvarからletに
* 定数宣言(const)
* 関数宣言でアロー関数が使用できるように
* Class構文が使える
* モジュール機能の導入
* 便利な配列メソッドの実装
→ forEach,map,filter,find,every,some,reduce
* Promise, async/await(非同期通信)

#アロー関数

アロー関数とは　その名の通り、　=>(矢)を使って関数リテラル。

#便利な配列メソッドの実装

__forEachメソッド__

ES5,ES6それぞれの違い書き方には下記の通りです。

```javascript:エディター
// ES5
var foods = ['pizza', 'beef', 'bread'];

for(var i = 0; i < foods.length; i ++) {
    console.log(foods[i]);
}

// ES6
foods.forEach(function(food){
    console.log(food);
});
```

```javascript:エディター
// ES5
for(var i = 0; i < foods.length; i ++) {
    console.log(foods[i]);
```

ES5のforループの構文って変なとこにセミコロンあるし、書き方・順番間違えても変な挙動してしまうんですよね〜
                                                                                  
一方、ES６については可読性も向上した記載方法になります。

```javascript:エディター
// ES6
foods.forEach(function(food){
    console.log(food);
});
```   

foodsの配列に対してforEachメソッドを呼んでいます。この中に匿名関数を入れることができる。
配列に対して一つずつ実行される関数となる。結果、 foodの中身が表示される。

わかりやすく図表化したものがこちらになります。
![IMG_6830 2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1572216/044bf648-d1a2-773e-20d4-56757ecfcc48.jpeg)

コールバック関数とは、先ほどのコードのこの部分に該当します。

```javascript:エディター
// ES6
function(food){
    console.log(food);
});
```   

一連の流れとして、foodsの配列の中の'pizza', 'beef', 'bread'が一個ずつ渡させて処理が実行される流れとなります。

#最後に
最近、Reactの学習ができていなかったので再度学習していきたいと思います。
【基本情報技術者試験対策】2進数の論理演算方法確認シート

基本情報技術者試験で出てくる2進数の論理演算問題の解き方で毎回混乱するので、

* [AND](#and)
* [OR](#or)
* [NOT](#not)
* [XOR](#xor)
* [NAND](#nand)

の解き方をいつでも確認できるようにまとめておく。

# 前提知識
コンピュータは電気のオン・オフで動くので、データを「0」「1」の2種類の値で扱っている。

* 0→OFF（false）
* 1→ON（true）

コンピュータがデータを計算をすることを「論理演算」といい、その論理演算には「AND」、「OR」、「NOT」、「XOR」、「NAND」といった種類がある。
これらの計算問題が試験で出題される。

参考：[【5分で覚えるIT基礎の基礎】あなたは論理演算がわかりますか？　第1回 | 日経クロステック（xTECH）](https://xtech.nikkei.com/it/members/ITPro/ITBASIC/20020731/1/)
> 論理演算と四則演算の大きな違いは，論理演算が2進数の1けた（＝1ビット）を対象としていることと，演算結果が決してけた上がりしないことです。

ちなみに2進数は8桁で表されるので、試験問題において8桁に満たないときは8桁になるまで頭に0が付く。（0埋めされる）

# AND
A, Bともに「1」のときのみ「1」を返す。

* 1かつ1の場合：1
* 上記以外：0

### 例題
A = 00101000(10進数で40)
B = 00100111(10進数で39)
のとき、A AND B は？

### 解説
2つの2進数の同じ桁同士を比べる。

| 8桁目 | 7桁目 | 6桁目 | 5桁目 | 4桁目 | 3桁目 | 2桁目 | 1桁目 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 |
⇒ 00100000 となる。

# OR
A, Bの少なくとも一方が「1」のとき「1」を返す。

* 片方に1がある場合：1
* どちらにも1がない場合：0

### 例題
A = 00101000(10進数で40)
B = 00100111(10進数で39)
のとき、A OR B は？

### 解説
2つの2進数の同じ桁同士を比べる。

| 8桁目 | 7桁目 | 6桁目 | 5桁目 | 4桁目 | 3桁目 | 2桁目 | 1桁目 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 |
⇒ 00101111 となる。

# NOT
逆を返す。
1なら0に、0なら1に反転。

### 例題
A = 00101000(10進数で40)
のとき、NOT A は？

### 解説
単純に反転させれば良いので、
11010111 となる。

# XOR
A, Bのどちらか一方だけが「1」のとき「1」を返す

* 2つの値が異なる場合：1
* 2つの値が同じ場合：0

### 例題
A = 00101000(10進数で40)
B = 00100111(10進数で39)
のとき、A XOR B は？

### 解説
2つの2進数の同じ桁同士を比べる。

| 8桁目 | 7桁目 | 6桁目 | 5桁目 | 4桁目 | 3桁目 | 2桁目 | 1桁目 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 |
⇒00001111 となる。

# NAND
NOT AND なので、ANDの逆を出せば良い。
試験ではNANDが大量に入った演算をさせられるけど、落ち着いて以下で計算するかANDの逆を出せばOK。

* 1かつ1の場合：0
* 上記以外：1

### 例題
A = 00101000(10進数で40)
B = 00100111(10進数で39)
のとき、A NAND B は？

### 解説
2つの2進数の同じ桁同士を比べる。

| 8桁目 | 7桁目 | 6桁目 | 5桁目 | 4桁目 | 3桁目 | 2桁目 | 1桁目 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 |
⇒11011111 となる。

ANDから計算する場合は、まずANDが

> * 1かつ1の場合：1
* 上記以外：0

なので、 00100000 となる。
その逆を求めれば良いので、 11011111 となる。
Rubyのハッシュ関連のメソッドをまとめ

## keys ハッシュのキーを配列で返す

__サンプルコード__

```rb:hash.rb
country_code = { japan: 'JP', australia: 'AU', canada: 'CA' }
puts "keys: #{country_code.keys}"
```

__実行結果__

```
keys: [:japan, :australia, :canada]
```

## values ハッシュの値を配列で返す

__サンプルコード__

```rb:hash.rb
country_code = { japan: 'JP', australia: 'AU', canada: 'CA' }
puts "values: #{country_code.values}"
```

__実行結果__

```
values: ["JP", "AU", "CA"]
```

## has_key?, key?, include?, member?

__サンプルコード__

```rb:hash.rb
country_code = { japan: 'JP', australia: 'AU', canada: 'CA' }
puts country_code.has_key?(:japan)
puts country_code.has_key?(:ua)
```

__実行結果__

```
true
false
```

## merge 2つのハッシュを結合する

__サンプルコード__

```rb:hash.rb
country_code_asia = { japan: 'JP' }
country_code_oceania = { australia: 'AU' }
country_code_asia_oceania = country_code_asia.merge(country_code_oceania)
puts "country_code_asia: #{country_code_asia}"
puts "country_code_asia_oceania: #{country_code_asia_oceania}"
```

__実行結果__

```
country_code_asia: {:japan=>"JP"}
country_code_asia_oceania: {:japan=>"JP", :australia=>"AU"}
```

## **でハッシュを展開することも可能

__サンプルコード__

```rb:hash.rb
country_code_asia_oceania_asta = { **country_code_asia, **country_code_asia_oceania}
puts "country_code_asia_oceania_asta: #{country_code_asia_oceania_asta}"
```

__実行結果__

```
country_code_asia_oceania_asta: {:japan=>"JP", :australia=>"AU"}
```

## **で他のキーワード引数を受け取ることができる

__サンプルコード__

```rb:hash.rb
def order_subwey(main, bread, cheese: false, tsuna: false, **other_topping)
    puts "main: #{main}"
    puts "bread: #{main}"
    if cheese
        puts "cheese"
    end
    if tsuna
        puts "tsuna"
    end
    puts "other_topping #{other_topping}"
end
order_subwey("BLT", "Sesame", cheese: true, tsuna: true, bacon: true, avocado: true)
```

__実行結果__

```
main: BLT
bread: BLT
cheese
tsuna
other_topping {:bacon=>true, :avocado=>true}
```
Slack Bolt for Pythonを使ったBot作成のハマりどころ

色々とやってきた中で、ちゃんとドキュメント読めばわかるけど、なんとなくで実装してるとハマっちゃうよねというネタをちょこちょこと追加していくページ

## ログに何も流れてこないとき
スコープの理解が浅いときに起こりがちな奴。
コード的には問題なくても、スコープが適切に振られていないと全くデータを読み取れません。
[この部分](https://github.com/geeorgey/vue_flask_template/blob/8ded48898c7cda79bc8743f29984859f59e6a1c4/.env#L12)をしっかりと設定してから、インストールしましょう。

自社アプリの場合は管理画面インストールしてしまうので意識する必要ほとんどないのですが、他のワークスペースへのインストールができる様な実装にするときちんと実装しないと動きません。

スコープ自体はアプリ管理画面のここで追加します。
![Slack_API__Applications___Leave_a_Nest_Co__ltd__Slack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/bb578118-2d28-b606-49ef-87e2a9ef8f9a.png)

よく使いそうなものをまとめたもの

```
export SLACK_SCOPES=chat:write,users:read,users:read.email,channels:history,groups:history,im:history,mpim:history,channels:join,groups:write,im:write,mpim:write,channels:read,app_mentions:read
```

環境変数に格納してから、botのインストールをしないと動きません。注意しましょう。

## botへのメンションからモーダルは呼び出せない
メンションというか、Event APIからは呼べません。
モーダルを使う条件は以下の通り

>ショートカット実行、ボタンクリック、セレクトメニューの選択、スラッシュコマンドなどのようにユーザーからの能動的なアクションに同期的に応答する場合のみ trigger_id が発行され、それを使ってモーダルを開くことができます

ということなので、実装する場合はこれらを使った実装にするか、メンション→chat.postEphemeralでボタンブロック付きのpostを送信→ボタンクリックでモーダル呼び出し
のような実装になります。

## モーダルのsubmitボタンを押した後にclient.views_updateは使えない
[このページを見ているとできそうに見える](https://slack.dev/bolt-python/ja-jp/concepts#updating-pushing-views)のですが、実際はできません。
Submitボタンを押した後にモーダルを更新する場合は
ack()
で空のレスポンスボディで応答するのではなく、
ack(response_action="update", view={})
という形式でresponse bodyを更新します。
ack()で応答する＝モーダルを閉じるという意味になるので、[ここに書いてある形で](https://slack.dev/bolt-python/ja-jp/concepts#updating-pushing-views)実装すると、body: {‘ok’: False, ‘error’: ‘not_found’}が返ってきて、モーダルが閉じて何も起こりません。
ack(response_action="update", view={})
のviewの中身を更新した情報で埋めてあげると、更新がうまくいきました。

### 逆に、モーダル内のボタン等による遷移の場合
こちらについてはviews_updateで更新する

## タイムスタンプの取得方法
スレッドにchat.postMessageしたい時にはthread_tsを取得する必要があります。
この際に検討すべき状態には3種類あり

- スレッドが紐付かない単体のpostの場合
- スレッドが紐付いた、親postの場合
- スレッドが紐付いた、スレッド内postの場合

となっています。
この3パターンにおいて、thread_tsを取得するのですが、その方法はこれです。


```python
try:
    conversations_replies = client.conversations_replies(
        channel=event['item']['channel'],
        ts=event['item']['ts']
    )
except SlackApiError as e:
    print("Error fetching conversations_replies: {}".format(e))
if conversations_replies["messages"][0].get("thread_ts") is not None:#スレッドにpostが存在する場合
    ts = conversations_replies["messages"][0]["thread_ts"]
else:#スレッドが紐付かない単体のpostの場合
    ts = conversations_replies["messages"][0]["ts"]
```

vent['item']['channel']とevent['item']['ts']はそれぞれの場所で取得方法が変わってきますので適宜置き換えて下さい。
スレッドが紐付かない単体のpostの場合にはthread_tsが存在しません。そのためtsで取得します。
一方、スレッドにメッセージが存在する場合は、親postにもthread_tsが存在します。これはtsと同じ値が入っています。
PAD: あるフォルダの最新ファイルを開く

# 目的

- 困ってる人がいたのでその手助けの為のSample

# 概要

1. 特定のフォルダのExcelファイルの一覧を更新日付でソートして取得
1. 最新（一番最初のファイル）を開く

そう、非常に単純ですね。

## PAD

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/73fcb235-1bbf-6c8c-2ce1-b27737d6d779.png)

### 補足

- フォルダー内のファイルを取得
    - ファイルフィルター：Excelに限定したい場合は拡張子で指定したほうが良いね
    - 並び替え基準：最新ファイル拾いたいってことで。
- Excel の起動
    - ドキュメントパス：↑で取得した一覧の最初を取得する為の記述 <coce>%Files[0]%</code>

```text:コピペ用PAD
Folder.GetFiles Folder: $'''C:\\Users\\hoge\\OneDrive\\ドキュメント\\LINQPad Queries\\CodeIQ''' FileFilter: $'''*.xlsx''' IncludeSubfolders: False FailOnAccessDenied: True SortBy1: Folder.SortBy.LastModified SortDescending1: True SortBy2: Folder.SortBy.NoSort SortDescending2: False SortBy3: Folder.SortBy.NoSort SortDescending3: False Files=> Files
Excel.LaunchAndOpen Path: Files[0] Visible: True ReadOnly: True LoadAddInsAndMacros: False Instance=> ExcelInstance
```
railsチュートリアル第6章 セキュアなパスワードを追加する

##セキュアなパスワードを追加する
ユーザー属性の「名前」と「メールアドレス」に対してバリデーションを追加したので、最後に「```セキュアなパスワード```」に取り掛かります。セキュアパスワードという手法では、各ユーザーにパスワードとパスワードの確認を入力させ、それを```ハッシュ化```したものをデータベースに保存します。
いきなりハッシュ化と言われると少し困惑してしまうかもしれません。
ハッシュとはRubyのデータ構造であると説明しましたが、今回の「ハッシュ化」とはそういった構造ではなく、ハッシュ関数を使って、入力されたデータを```元に戻せない（不可逆な）データ```にする処理を指します。

ユーザーの認証は、```パスワードの送信```、```ハッシュ化```、```データベース内のハッシュ化された値```との比較、という手順で進んでいきます。
比較の結果が一致すれば、送信されたパスワードは正しいと認識され、そのユーザーは認証されます。
ここで、生のパスワードではなく、```ハッシュ化されたパスワード同士を比較```していることに注目してください。
こうすることで、生のパスワードをデータベースに保存するという```危険なことをしなくても```ユーザーを認証できます。
これで、仮にデータベースの内容が盗まれたり覗き見されるようなことがあっても、```パスワードの安全性```が保たれます。

###ハッシュ化されたパスワード
セキュアなパスワードの実装は、```has_secure_password```というRailsのメソッドを呼び出すだけでほとんど終わってしまいます。
このメソッドは、Userモデルで次のように呼び出せます。

```rb
class User < ApplicationRecord
  .
  .
  .
  has_secure_password
end
```
上のようにモデルにこのメソッドを追加すると、次のような機能が使えるようになります。

セキュアにハッシュ化したパスワードを、データベース内の```password_digest```という属性に保存できるようになる。
2つのペアの仮想的な属性（passwordとpassword_confirmation）が使えるようになる。
また、```存在性と値が一致```するかどうかのバリデーションも追加される。
```authenticate```メソッドが使えるようになる（引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド）。
この魔術的な```has_secure_password機能```を使えるようにするには、1つだけ条件があります。
それは、モデル内に```password_digest```という属性が含まれていることです。
ちなみにdigestという言葉は、```暗号化用ハッシュ関数```という用語が語源です。
したがって、今回の用途では```ハッシュ化されたパスワード```と```暗号化されたパスワード```は類義語となります。
今回はUserモデルで使うので、Userのデータモデルは次の図のようになります。

データモデルにするために、まずは```password_digest```カラム用の適切なマイグレーションを生成します。
マイグレーション名は自由に指定できますが、次に示すように、```末尾をto_users```にしておくことをオススメします。
こうしておくと、usersテーブルにカラムを追加するマイグレーションがRailsによって```自動的に作成```されるからです。```add_password_digest_to_users```というマイグレーションファイルを生成するためには、次のコマンドを実行します。

```
$ rails generate migration add_password_digest_to_users password_digest:string
  # テーブルにカラムを与えるために引数にカラムとそのデータ型をしている
```

上のコマンドでは```password_digest:string```という引数を与えて、今回必要になる属性名と型情報を渡しています。
usersテーブルを最初に生成するとき、```name:string```や```email:string```といった引数を与えていたことを思い出してください。
そのときと同様に```password_digest:string```という引数を与えることで、完全なマイグレーションを生成するための十分な情報をRailsに与えることができます（リスト 6.36）。

```rb
cclass AddPasswordDigestToUsers < ActiveRecord::Migration[6.0]
 def change
    add_column :users, :password_digest, :string
    # genalateによって生成された絡むとそのデータ型
    # 追加されたカラム
  end
end
```
リスト 6.36では、add_columnメソッドを使ってusersテーブルpassword_digestカラムを追加しています。
これを適用させるには、``データベースでマイグレーション```を実行します。

```
ubuntu:~/environment/sample_app (modeling-users) $ rails db:migrate
== 20210926142302 AddPasswordDigestToUsers: migrating =========================
-- add_column(:users, :password_digest, :string)
   -> 0.0138s
== 20210926142302 AddPasswordDigestToUsers: migrated (0.0145s) ================
```
また、```has_secure_password```を使ってパスワードをハッシュ化するためには、最先端のハッシュ関数であるbcryptが必要になります。
パスワードを適切に```ハッシュ化```することで、たとえ攻撃者によってデータベースからパスワードが漏れてしまった場合でも、Webサイトにログインされないようにできます。
サンプルアプリケーションでbcryptを使うために、bcrypt gemをGemfileに追加します。

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

gem 'rails',      '6.0.3'
gem 'bcrypt',         '3.1.13'
gem 'bootstrap-sass', '3.4.1'
.
.
.
```

```
$ bundle install
```
Gemfileを編集したら実行する
cronで動かない時の対策

パスは合っているはずなのに何故かcronが動かない！ということは
誰にでも１度はあると思います。
そんな時はどこに着目すればいいか、順番に説明します。
#１.もう１度パスを確認しよう。
慌てずにとりあえずもう１度パスを確認しましょう。
ちなみに色んなサイトに書かれているようにパスは相対パスではなく
絶対パスを書いた方がいいです。
#２.python?　python3?
先程の続きになりますがcronで実行コマンドのパスを記入する時に
「時間の設定　python /home/pi/〇〇.py」と記入する人は
このpythonがpython3じゃないと動かない場合があります。
(でも基本的に両方動くと思う。)
ただ、試してみる価値はあると思います。
#３．ターミナルで動くか確認してみよう。
それでも無理な人はターミナルで実行コマンドをしてみよう。
(２番のやつより先にやっていいかも。)
ターミナルで

```
$python3 /home/pi/〇〇.py　#パスを記入
```

と実行してみてください。
ここで私は
「～(モジュール名)がインストールされていません。」
みたいなエラーコードが出てしまいました。
スクリプト内で実行したらできたのに！

結論から言うとそういう時は

```
$pip install “表示されたモジュール名”　-user 
```

と書いてみてください。多分解決できます。
AtCoderログ：0126 - ABC 220 に参加しました

この記事は 2021年09月26日(日)21:00-22:40 に開催された [AtCoder Beginner Contest 220 (ABC 220)](https://atcoder.jp/contests/abc220) に参加した記録です。

https://atcoder.jp/contests/abc220

# 結果
- 得点：600 (=100+200+300)
- 時間：92:17 (= 67:17 + 05:00 × 5)
- 順位：5392 / 7469
- パフォーマンス：235
- レーティング：336 → 323 (-13)
- 段級位：9級

![2021-09-26_abc220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1589302/c5e1882d-de12-7f24-a813-c51e0f5f87ba.png)

# 詳細
|問題|得点|時間|提出コード|復習|
|:--:|:--:|:--:|:--:|:--:|
|[ABC 220 A](https://atcoder.jp/contests/abc220/tasks/abc220_a)|100|24:10|[○](https://atcoder.jp/contests/abc220/submissions/26142798)|[AtCoderログ：012*]()|
|[ABC 220 B](https://atcoder.jp/contests/abc220/tasks/abc220_b)|200|67:17(4)|[○](https://atcoder.jp/contests/abc220/submissions/26158899)|[AtCoderログ：012*]()|
|[ABC 220 C](https://atcoder.jp/contests/abc220/tasks/abc220_c)|300|61:57(1)|[○](https://atcoder.jp/contests/abc220/submissions/26157430)|[AtCoderログ：012*]()|
|[ABC 220 D](https://atcoder.jp/contests/abc220/tasks/abc220_d)|400|---|---|---|
|[ABC 220 E](https://atcoder.jp/contests/abc220/tasks/abc220_e)|500|---|---|---|
|[ABC 220 F](https://atcoder.jp/contests/abc220/tasks/abc220_f)|600|---|---|---|
|[ABC 220 G](https://atcoder.jp/contests/abc220/tasks/abc220_g)|600|---|---|---|
|[ABC 220 H](https://atcoder.jp/contests/abc220/tasks/abc220_h)|600|---|---|---|

# 感想
- A, B, C を完答しました。
- B はなぜかはまってしまい、スクラッチから書き直すことで正答。
- D を解いていたところで時間終了となりました。
- レーティングは微減でした。誤答だらけだし、D が解答できそうなほど簡単(そう)だったので、当然でしょう。
- 仕事の山場を越えた気がするので、リハビリを開始したいです。
 
# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0125 - AGC 011 A](https://qiita.com/RoadLynton/items/d16dce3180a9d90db9e3)
server can't find [domain]: NXDOMAIN　取得したドメインに関連付けができない

#はじめに

お名前.comにてドメインを取得し、Route53を使用して、IPアドレスと取得したドメインを関連付けを行いました。

一度成功したのですが1週間後何故が使えなくなってしまったのでその時対応した内容を投稿します。

ドメイン取得は下記の記述を参考にしました.


https://qiita.com/Yuki_Nagaoka/items/3020f02d3fd74c8572a0#-%E7%AC%AC8%E7%AB%A0-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E5%8F%96%E5%BE%97

#どのようになったか

ターミナルでネームサーバの確認をしました。

```:EC2
[ec2-user@ip() ~]$ nslookup
>set type=ns #自分で入力
>(取得したdomain)　#自分で入力

Server:		10.0.0.2
Address:	10.0.0.2#53

** server can't find [取得したdomain]: NXDOMAIN
```

本来ならば下記のようになります

```:EC2
[ec2-user@ip() ~]$ nslookup
>set type=ns #自分で入力
>(取得したdomain)　#自分で入力

Server:		10.0.0.2
Address:	10.0.0.2#53

Non-authoritative answer:
(取得したdomain)	nameserver = 
(取得したdomain)	nameserver = 
(取得したdomain)	nameserver = 
(取得したdomain)	nameserver = 
```

このようにネームサーバが反映をずっとされませんでした。

#解決した方法

解決方法は**メールでした。**

お名前.comに登録したメールアドレスに**「ご利用制限解除 お手続きのご案内」**というメールが来ていましたが無視をしていました。これには下記の内容が記載されてました。

>メールアドレス有効性確認のお手続きが確認できないため、
当該ドメインのご利用を制限させていただいております。
以下URLのクリックをお願いします。
間もなくドメインがご利用可能な状態になります。

このメールのurlをクリックするだけで先程のコマンドを打つと解決しました。
（40分ほどで浸透しました）
AtCoderログ：0125 - AGC 011 A

# 問題

https://atcoder.jp/contests/agc011/tasks/agc011_a

## 問題文
> 高橋空港には，毎日飛行機で $N$ 人の乗客が到着します．$i$ 番目の乗客は時刻 $T_i$ に到着します．
> 高橋空港に到着する乗客は全員バスで市内へ移動します．どのバスも定員は $C$ 人であり，$C$ 人以下の乗客を乗せることができます．飛行機の乗客は，飛行機の到着時刻よりも早く出発するバスには乗ることができません．また，飛行機の到着時刻から $K$ の時間が経過した後にもバスに乗れていないと，怒り出してしまいます． そのため，$i$ 番目の乗客は，出発時刻が $T_i$​ 以上 $T_i+K$ 以下であるようなバスに乗れるようにしないといけません．
> この条件のもとで，うまくバスの出発時刻を定めるとき，必要なバスの数の最小値を求めてください．ただし，バスの出発時刻は必ずしも整数である必要はなく，同じ時刻に出発するバスが複数あってもかまいません．

## 制約
> ・$2 \le N \le 100000$
> ・$1 \le C \le 10^9$
> ・$1 \lw K \le 10^9$
? ・$1 \le T_i \le 10^9$
> ・$C,K,T_i$ は整数

## 収録されている問題セット
- [[精](https://qiita.com/drken/items/fd4e5e3630d0f5859067)] [AtCoder に登録したら次にやること](https://qiita.com/drken/items/fd4e5e3630d0f5859067) [第09問類題](https://qiita.com/drken/items/fd4e5e3630d0f5859067#%E7%AC%AC-9-%E5%95%8F--abc-049-c---daydream-300-%E7%82%B9)

# 回答
## 回答1 (AC)
バスの受付になったつもりで考えるとわかりやすいでしょう。すると乗客の到着時刻は時刻順になっていて欲しいと思うのは当然で、そう仮定します。実際、到着時刻をソートすることでこの仮定は簡単にクリヤできます。受付は、最初の乗客の到着時刻 $T$ をチェックし、到着時刻が $T+K$ 以内の乗客をバスに乗せていきます。ただし途中でバスの乗客者数が $C$ 人になった場合にはそこで打ち切り、バスを発車させた後、残った乗客の先頭の到着時刻をチェックするところから繰り返します。また、途中で到着時刻が $T+K$ 以内の乗客がいなくなった場合もバスを発車させ、その後に残った乗客の先頭の到着時刻をチェックするところから繰り返します。これらの繰り返しによって、全員の乗客をバスに乗せることができます。計算量を調べると、ソートに $O(N log N)$、バスへの割り振りに $O(N)$ が必要ですが、$N \le 10^6$ よりこれらは処理可能です。コードは以下のようになりました。

```C++:agc011a-1.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int n, c, k;
  cin >> n >> c >> k;
 
  vector<int> t(n);
  for ( int i=0; i<n; i++ ) {
    cin >> t.at(i);
  }
  sort(t.begin(),t.end());
  
  int index = 0, pnumber = 0, bnumber = 0;
  while ( index<n ) {
    int tk = t.at(index)+k;
    while ( index<n && t.at(index)<=tk ) {
      pnumber += 1;
      index += 1;
      if ( pnumber%c==0 ) {
        bnumber += 1;
        pnumber =  0;
        break;
      }
    }
    if ( pnumber>0 ) {
      bnumber += 1;
      pnumber =  0;
    }
  }
  
  cout << bnumber << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/agc011/tasks/agc011_a/editorial) → [コンテスト全体の解説](https://atcoder.jp/img/agc011/editorial.pdf)
回答1と同じ方針でした。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0124 - ABC 158 B](https://qiita.com/RoadLynton/items/55253b2bf3522a7e07a0)
エンジニアにオススメのポエムまとめ（現役・未経験問わず）

## はじめに

個人的にオススメなエンジニア向けポエムを集めてみました。

（著者は2020年4月に異業種からエンジニアに転職した者です）


## 一部上場企業のトップエンジニアから教わった『エンジニアの心構え』

https://qiita.com/Cocot-RH/items/967ba54f2198789dbd13

## エンジニアの劣等感との付き合い方

https://qiita.com/karamage/items/771b633c3243989418a2

## 良い質問をして自己成長に繋げるためのあれこれ

https://qiita.com/morry_48/items/86ce93c34e5789f38be3

## 技術記事を書く人を大事にしよう

https://zenn.dev/kaityo256/articles/save_the_earth

## 「あれ、プログラミングが楽しくない…」【すべてのエンジニアへ】

https://qiita.com/mio256/items/eb70d6d2239acc2ce94c

## 読み手をイライラさせない技術記事などを書くために最低限守ったほうがいいこと

https://qiita.com/freddi_/items/fe8e878187f315d80d87

## 採用市場に中堅エンジニアがほぼ居ない／どこに行ったのか目撃情報を集めてみた

https://note.com/makaibito/n/n289c9de14b53

## 最後に

他にも発見できないけど素敵なポエムがあるかもしれないのでご存知の方はもしよかったらコメントで教えてください♪
ShellSpecでカバレッジを収集する

# はじめに

Shellspec でカバレッジを収集できるということだったので、カバレッジを収集してみる。
そもそも、ShellSpecとはシェルスクリプト用のBDDスタイルのテストフレームワークです。  
[ShellSpec - シェルスクリプト用のBDDテスティングフレームワークを作りました](https://qiita.com/ko1nksm/items/77388d75b8c1f18c0058)

ShellSpecのリポジトリはこちら
[ShellSpec](https://github.com/shellspec/shellspec)

# 環境

カバレッジの収集を実施する際の環境は以下のとおり。

| OS / MW | Version |
| ------- | ------- |
| CentOS  | 7.6.1810 |
| Bash | 4.2.46(2)-release |
| Shellspec | 0.29.0-dev |
| kcov | v37-65-g48a3 |

# 準備

Shellspec でカバレッジを収集するためには、kcovコマンドが必要になる。
そのため、事前にkcovをインストールする。

## kcovのインストール

Shellspecでカバレッジを収集するために、kcovが必要なので、kcovのインストールをする。

```
$ sudo yum install -y elfutils-libelf-devel libcurl-devel binutils-devel elfutils-devel cmake gcc gcc-c++ openssl-devel python3
$ git clone https://github.com/SimonKagstrom/kcov.git
$ mkdir -p kcov/build
$ cd kcov/build
$ cmake ..
$ make
$ sudo make install
```

# Shellspecでカバレッジを取得してみる

--kcovオプションをつけて実行するとcoverageフォルダが生成され、coverageフォルダ配下にカバレッジのデータが保存される。  

```
$ shellspec --kcov --kcov-options "--include-path=../shell --include-pattern=.sh"
```

| オプション | 内容　|
| -------- | ---- |
| --include-path | ,(カンマ)区切りで、カバレッジを取得する対象のスクリプトファイルがあるディレクトリを指定 |
| --include-pattern | ,(カンマ)区切りで、収集対象のシェルの拡張子を指定 |

実際に実行すると標準出力でカバレッジの情報も出力される。

```
Code covered: 53.85%, Executed lines: 14, Instrumented lines: 26
```

coverage配下に出力されたindex.htmlを表示すると以下のようにカバレッジの結果が表示される。
![スクリーンショット 2021-09-27 21.40.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112271/32da85c0-99d9-8c3f-d826-df36d1902134.png)

対象シェルスクリプトの実行詳細。
![スクリーンショット 2021-09-27 21.41.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112271/17f67de4-bdc0-0394-adb2-dfede0fa0b40.png)

# まとめ

シェルスクリプトのテストでもカバレッジが収集できたことで試験が実施しやすくなり、単体テストのエビデンスの１つとして使用できるので良いと思います。  
カバレッジに限らず、Shellspecには多くの機能が実装されてので、学習コストがかかるかと思います。  
ただ、シェルスクリプトのテストフレームワークとしては利用する価値のあるフレームワークだと感じました。  
今後、Shellspecを使って、シェルスクリプトの単体テストができるように学習しておきたいと思いました。