OmniAICreator/Qiita-1.07M huggingface dataset:
【テトリス作成④】ブロックが下で止まるようにする実装について深掘る

こちらを元に解説しています。
https://qiita.com/hanatan079/items/3675855784e14acda119

★★★★★随時更新★★★★★
2022.11.22追記
20022.11.29追記
★★★★★★★★★★★★★★★
```
(見本)Board.cs

    //ブロックが枠内にあるのか判定する関数を呼ぶ関数
        public bool CheckPosition(Block block)
        {
            foreach (Transform item in block.transform)
            {
                Vector2 pos = new Vector2(Mathf.Round(item.position.x),Mathf.Round(item.position.y));

                if(!BoardOutCheck((int)pos.x, (int)pos.y))
                {
                    return false;
                }

                if (BlockCheck((int)pos.x, (int)pos.y,block))
                {
                    return false;
                }
            }
            return true;
        }

    //枠内にあるか判定する関数
    bool BoardOutCheck(int x, int y)
    {
    //x軸は０以上with未満　z軸は0以上    
        return (x >= 0 && x < width && y >= 0);
    }
```

解説

【(関数)ブロックが枠内にあるのか判定する関数を呼ぶ】
```
        ①public bool CheckPosition(Block block)
        {
            ②foreach (Transform item in block.transform)
            {
                ③Vector2 pos =　new Vector2(Mathf.Round(item.position.x),Mathf.Round(item.position.y));

                ④if(!BoardOutCheck((int)pos.x, (int)pos.y))
                {
                   ⑤return false;
                }
            }
            ⑥return true;
        }
```
①外から呼び出し可能、
　　　ブロックが枠内にあるのか判定する関数を呼ぶ＝CheckPositionとする
　　　引数にブロックを渡す、名前はblockとする
②Blockオブジェクトにはblockが７個（子を含む）がり、その数(transform)分だけ繰り返しループする
③変数宣言、Mathf.Round→丸める
　　　itemのxy軸を丸めてpos変数に格納する
④~~blockが脇からはみ出ていないかの判定
  もしBoardOutCheck(枠内にあるか判定する)があればtrue
　　　！もしBoardOutCheckがなければtrue　＝　枠からはみ出ていたら~~
  　通常ブロックが枠内にあるのか判断→！がついている為、ブロックが枠内にないのか判断
⑤~~！　false~~
　　　ないなら、中処理へfalse(偽)を返す
⑥全部収まっていたらtrue

bool型について
https://qiita.com/hanatan079/items/36386ae4335bb0b06c88
Mathf.Roundとは
https://learn.microsoft.com/ja-jp/dotnet/api/system.math.round?view=net-7.0
foreach
https://qiita.com/hanatan079/items/9c29d7ab61729177cbe3


【(関数)枠内にあるか判定する】
```
    ①bool BoardOutCheck(int x, int y)
    {
        ②return (x >= 0 && x < width && y >= 0);
    }
```
①bool型、　BoardOutCheck(枠内にあるか判定する)、
②x軸は０以上with未満であり、　y軸は0以上であること。全て条件が成立していればtrue

bool,int型について
https://qiita.com/hanatan079/items/36386ae4335bb0b06c88
演算子について
https://qiita.com/hanatan079/items/01530bc45bab85f3d19f

```
GameManeger.cs

//ボードのスクリプトを格納
    ①Board board;    

 //ボードを変数に格納(スタート)
   ②board = GameObject.FindObjectOfType<Board>();

 //Boardクラスの関数を呼び出してボードからはみ出ていないか確認（アップデート）
   ③if (!board.CheckPosition(activeBlock))
   {
   ⑥activeBlock.MoveUp();
   ⑦activeBlock = spawner.SpawnBlock();
   }

```
①Board型　名前board
②全てのオブジェクトからBoardコンポーネントを探してboard変数へ格納する
FindObjectOfTypeは全てのコンポーネントの中から<>を探すため重い処理。乱用注意。
③もしactiveBlockがはみ出ていなかったら。
　　　！否定false(偽)の時に中に入る。
　　　すなわち、もしactiveBlockがはみ出ていたら。
⑥MoveUp＝一つ上に戻る。→下にはみでたら上に戻す＝枠からはみ出なくなる。
⑦新しいブロックを生成してactiveBlockに格納する
①〜⑦activeBlockがはみ出たら、1つ上に戻してね。
そしたら下にブロックが着いたから次の新しいブロックをactiveBlock内に生成してね。

if文、！否定について
https://qiita.com/hanatan079/items/01530bc45bab85f3d19f
fota (nrf52840DK)


## ~~ncs~~(嘘)zephyr(正)でfotaを動かすてっとり速いサンプル(smp_svr)

- ubuntu 18.04
- Zephyr version: 3.1.99
- zephyr-sdk-0.15.1

１ビルドする
```sh
hoge@hoge-pc:~/ncs/zephyr/samples/subsys/mgmt/mcumgr/smp_svr$ west build -b nrf52840dk_nrf52840 -- -DOVERLAY_CONFIG=overlay-bt.conf
...
~~ ビルドの進捗が色々でてくる ~~
...
Enabling pin reset.
Applying pin reset.
-- runners.nrfjprog: Board with serial number 683499054 flashed successfully.
```
２フラッシュする
```sh
hoge@hoge-pc:~/ncs/zephyr/samples/subsys/mgmt/mcumgr/smp_svr$ west flash
-- west flash: rebuilding
...
~~進捗が色々でてくる~~
...
Parsing image file.
Applying system reset.
Verifying programming.
Verified OK.
Enabling pin reset.
Applying pin reset.
-- runners.nrfjprog: Board with serial number 683499054 flashed successfully.

```
準備OK

## nRF Connect Device Managerで動作確認

スマホから、ビルド済みのバイナリをble経由でアップデートする手順↓


<img width="320" alt="IMG_3881.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691828/47fd14f0-25c5-5f41-bbf3-9f3806171419.png">

デフォルトで、コンプリートローカルネームは"Zephyr"なので、選択する
<img width="320" alt="IMG_3882.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691828/bb9b6d50-fac3-8498-2927-75d7cf36473f.png">



エコーサーバーを備えているので、適当に文字を送って動作チェックできる。
<img width="320" alt="IMG_3883.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691828/1fbd917d-eedf-5496-360e-bae7313f9989.png">

- 下のメニューから、イメージをアップデートする。（イメージは予め用意しておいたもの）
- ここではzephyr/samples/basic/threadをmcuboot向けにビルドしたものをスマホにいれています。
<img width="320" alt="IMG_3884.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691828/b3156b30-c5ed-aae3-007b-153cb96b9633.png">

アップデートしてみます
<img width="320" alt="IMG_3886.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691828/09969da0-1d1b-ca9d-bdbf-d26b52ffe955.png">

以上で、nrf52840dkのLEDがチカチカして、無事アップデート完了したことがわかります。

取り急ぎ。細かいことはきりがないのですが、ぱっと動く手順です。
ubuntuの話ですが、コンソールから操作する場合はmcumgrコマンドが使えます。

[参考](https://docs.zephyrproject.org/2.6.0/samples/subsys/mgmt/mcumgr/smp_svr/README.html)
VBA要素抽出ツール

Sub 抽出()
Dim objName As String
Dim objRange As Range
Dim myObj As Range
Dim i As Long
    Set ws1 = Worksheets("抽出先")
    Set ws2 = Worksheets("抽出元")
    Set objRange = ws2.Range("A2:K61")
     objName = ws1.Cells(2, 1).Value
     Set myObj = objRange.Find(objName, lookat:=xlPart)
     ws1.Cells(2, 2).Value = ws2.Cells(myObj.Row, myObj.Column + 2).Value
 
End Sub
カレーパン好きによるカレーなるカレーパン記録Webアプリ

# また食べたいのにどこで買ったカレーパンか覚えていない
なんとなく立ち寄ったパン屋さんで、なんとなく買ったカレーパンが意外にも美味しくて、また食べたいなーってなることがよくあるのですが、また食べたいなーってなった時には、どこで買ったか忘れていることがほとんどなんですよね。
そんな悩みを解決してくれる、**カレーパンを記録するWebアプリ**を作りました。

# カレーパン記録アプリ
できあがったのがこちら。
※パン屋でさくっと使えるように、スマホから開くことを想定して作成しました。

https://chic-babka-bc9ee0.netlify.app

カレーパンの名前、店名や訪店日時、位置情報までをお店でサクッと入力。
家に帰ってカレーパンを食べたら、生地感やルー、具材の情報を入力。
保存するボタンを押せば、カレーパンの情報がばっちり記録されますﾔｯﾀﾈ!!

## 環境
Netlify
CodePen
Vue.js
bootstrap
LocalStorage
Web Sensor API

## コード紹介
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="GRGWRZY" data-user="Masaedge" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Masaedge/pen/GRGWRZY">
  カフェ記録アプリ</a> by Masahiro Nishiguchi (<a href="https://codepen.io/Masaedge">@Masaedge</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

位置情報の取得にはWeb Sensor APIを使用し、Googlemapのリンク形式で出力するようにしました。
LocalStorageを使用して、カレーパンの名前をキーに、その他入力の情報をデータとして保存します。
LocalStorageに保存した情報を読み出す際は、リスト形式でそのまま出力しているので、もっと見やすく出力する方法を模索したいと思います。

## 作って使用した感想
位置情報の取得とか、こんなに簡単に実装できるのか！！といった驚きで溢れています。
bootstrapの良さをあまり引き出せている気がしないので、まだまだ精進しなければいけないな、、と思っています。
生地感や具の情報を保存するようにしたので、食べたいカレーパンをサクッと検索できるのがいいポイントだなと思っています。
これから追加したい機能は、**画像を残す機能です**。文字だけでは思い出せない情報も、画像があればもっと鮮明に思い出せるのにな。。という感想を抱いています。
【Laravel】日付をparseできなかったとき500で落ちるのを回避したい

## 環境
Laravel v9.5.1 (PHP v8.1.3)

## パラメータに不正な日付のフォーマットで渡ってきたとき
日付が「2022-1-1」「2022/1/1」で渡ってきたら問題なく```parse```してくれるけど、「2022.1.1」などのフォーマットは```parse```できずに500エラーが返ってしまう。

500で返してもフロント側が困るので、Handlerに下記を追加。
ステータスコード400で```Carbon```のエラーメッセージをキャッチしてそのまま返すようにした。

```php
use Carbon\Exceptions\Exception;

public function register()
{
    $this->renderable(function (Exception $e) {
    $message = $e->getMessage();
    $errorMessage = [
       'message' => $message,
    ];
    
    return (new ErrorResource($errorMessage))->response()->setStatusCode(400);
}
```
JSXの中で文字列を展開するときはテンプレートリテラルを使う方が綺麗なHTMLになる

## この記事の概要

JSXを書いていてこんな感じの文字列の展開、していませんか？

```jsx
export const Text = () => {
  const text = "foo";
  return <p>{text} bar</p>;
}
```

基本的に問題は無いんですが、最終的なHTMLを綺麗にするならテンプレートリテラルにした方が良いので記事にしました。

## 現状

先ほどの内容をDev toolsで見てみましょう。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/f04b8b91-f28c-1408-a32b-e3c6252fa437.png)

描画されたHTMLは次のようになっています。

```html
<p>
  "foo"
  " bar"
</p>
```

何が起きているかというと、プレーンなテキストとJavaScriptを展開したテキストとが、別のテキストノードとして指定されてしまっています。

## 綺麗にする書き方

ひとまとめにしたい文字列を`{``}`で括り、その中で展開するだけです。

```diff_jsx
  export const Text = () => {
    const text = "foo";
    return (
-     <p>{text} bar</p>
+     <p>{`${text} bar`}</p>
    );
  }
```

Dev toolsで見てみましょう。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/6134e419-7bef-7107-7fd9-cc1247a7b5f1.png)

描画されたHTMLは次のようになっていて、整っています。

```html
<p>foo bar</p>
```

## おまけ

JSXでなく通常のJavaScriptの場合は`normalize()`をかけるだけで綺麗になります。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/43e21737-59ec-5dfc-9997-1b1ef8399d96.png)

---

最後まで読んでくださってありがとうございます！
Twitterでも情報を発信しているので、良かったらフォローお願いします！

https://twitter.com/xrxoxcxox

Devトークでのお話してくださる方も募集中です！

https://jobs.qiita.com/employers/qiita-inc/dev_talks/489
LambdaでS3の最終更新日時を取得する（Python）

# 概要
  S3の最終更新日時を取得するLambdaをPythonで書いてみた記事です。

# 前提条件
  - S3が用意されていること
  - Lambdaに必要なIAM権限が付与されていること

# 環境
  - ランタイム：Python3.9
  - リージョン：ap-northeast-1

# コード
  ```python
    import boto3
    from datetime import datetime, timedelta, timezone

    s3 = boto3.resource('s3')
    s3_bucket = <S3バケット名>
    bucket = s3.Bucket(s3_bucket)

    def lambda_handler(event, context):
        # 指定のフォルダ配下で調べたい場合はprefixを設定
        prefix = '<Prefix>/'

        # オブジェクトの取得
        objs = bucket.meta.client.list_objects_v2(
            Bucket=bucket.name,
            Prefix=prefix
        )

        first = True
        # 取得したオブジェクトを1件ずつまわす
        for obj in objs['Contents']:
            # 初回はdtに代入
            if first:
                dt = obj['LastModified']
                first = False
            # 2回目以降はdtより日時が遅ければ代入
            else:
                if dt <= obj['LastModified']:
                    dt = obj['LastModified']
      
        # 日本時間に直す
        jst = timezone(timedelta(hours=9), 'JST')
        last_modified_time = dt.astimezone(jst)
        last_modified = last_modified_time.strftime('%Y/%m/%d %H:%M:%S')

        responce = {"last_modified_time": last_modified}
        return responce
  ```

# 説明
  オブジェクトを取得した時点で一番最後に入っているものが最新と思われますが、
  実際、取得したオブジェクトはランダムに入っています。

  そのため、for文をまわして最新日時を探す必要があります。

  また、ファイルの更新に限らず、フォルダの作成など、フォルダの日時も取得します。

  フォルダやファイルが多いと、それだけfor文をまわす回数が増えるので、
  PrefixやSuffixで検索対象を絞ることをおすすめします。

# 実行結果
  - 正しく値が取れていることが分かります。
  ![result](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/3315e0a0-191f-53a9-280d-dd6725751aa4.png)
Validationについて

<h1>ファイルのアップロード時に注意すること

やりたいことなどによって変わりますが、エラー条件はしっかりした方がいいと思うのでメモしておく
例えば、csvをアップロードする処理

<h5>形式があっているか？</h5>
<ul>
    <li>csv形式意NGにする
</ul>

<h5>中身があるか</h5>
<ul>
    <li>0byteが来たら弾く
    <li>保存はするが処理はしない
</ul>

<h5>中身が大きかったら</h5>
<ul>
    <li>保存はしないで、エラーだけ返す
</ul>

<h5>中身の情報があっているか</h5>
<ul>
    <li>nameカラムの位置に、idカラムの情報が記入されていたり
    <li>余計な文字が含まれている
    <li>ハイフンがないとか…
</ul>

<h5>文字数はあっている？</h5>
<ul>
    <li>文字数制限を設ける
</ul>

必要そうなものがあれば更新すること　(2022/11/14)
【農家が作る】加湿器の自動制御（Switchbot）

# はじめに
収穫したトマトは鮮度を保つため、保冷庫（冷蔵庫）に保管します。[完熟トマトの適正温度は8～10℃、湿度は85～90%](https://www.naro.affrc.go.jp/org/nfri/yakudachi/optimalstorage/index.html)とされていますが、保冷庫内に設置された加湿器は湿度制御ができないためスイッチボットで自動化します。

# 用意するもの
1. [SwitchBot 温湿度計（約1,800円）](https://amzn.asia/d/03CfXpb)
2. [SwitchBot プラグミニ スマートプラグ（約1,800円）](https://amzn.asia/d/geMJ3Rs)
3. [SwitchBot Hub Mini（約4,200円）](https://amzn.asia/d/emdU0r0)
4. [日東工業 プラボックス P12-1525A（約830円）](https://amzn.asia/d/fF27t4e)
5. [パナソニック コンセント WK1013WP（約250円）](https://amzn.asia/d/1BIcpLj)
6. [パナソニック スナップキャップ WH4021BP（約200円）](https://amzn.asia/d/aP9SCcC)
7. [ELPA VVFケーブル 1.6mm*2芯 1m VA-1AH（約190円）](https://amzn.asia/d/0bfFI0D)
8. [ワゴ ワンタッチコネクター WFR-2BP（約630円）](https://amzn.asia/d/0cPXxLT)

:::note 
No.4以降は電気配線用の部材です。コンセント接続の場合は不要です。
:::



# 設置
残念ながらコンセント接続ではなかったので、2次側の配線にコンセントを設置してスイッチボットのプラグミニを接続します。常時接続する機器をコンセントで接続する点は悩みましたが、消費電力が少ないこととプラグミニのメンテナンス性（交換）を考慮し分解設置は避けました。

>接続概要
>　[ブレーカー] － [コンセント]**[プラグミニ]**[プラグ] － [加湿器]

保冷庫はハウス内になるのでウオルボックスに入れ、簡単に撤去できるようワゴのワンタッチコネクタでユニット化し接続します。
![IMG-1702.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951500/30eac365-f5a3-69a4-8b80-e058243e0e7d.jpeg)

ユニット化したので加湿器のVVFケーブルをワゴのワンタッチコネクタに接続すれば設置完了です。
![IMG-1704.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951500/29d24dc4-bdca-4ea3-3c79-09adb69d5e47.jpeg)

:::note alert
接続場所や接続方法によって電気工事士の資格が必要になります。資格が不要な場合でも火災の危険性などリスクがあります。
:::


<br>
プラグミニが設置できたら温湿度計を保冷庫内に設置します。保冷庫内はwifiの電波が届きにくいので、ハブミニの設置場所は注意が必要です。私はハウス内の30mほど離れた場所に設置していますがギリギリの感じです。



# 設定
ハブミニ、温湿度計、プラグミニをアプリに登録すると「シーン」で自動制御を登録できます。私の場合は湿度80%で加湿器ON、90%でOFFの2つのシーンを登録しました。
![IMG-1705.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951500/80554261-f1dd-7bcb-cc88-d4ec0f2a6d0c.jpeg)

温度/湿度、高い/低い、度数/パーセントで簡単に設定できます。
![IMG-1706.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951500/f6b91221-5fee-0d9e-b397-9a621e2ad82b.jpeg)




# 結果
設定湿度での自動制御が実現できました。前途のシーンで設定できるアプリのプッシュ通知は若干タイムラグがありますが、動作が安定しているので通知自体使っていません。

またスマートプラグのメリットは、消費電力のモニタリングも可能です。グラフ表示も可能なので動作ログとしても活用できます。
![IMG-1707.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951500/e5a2620a-93b5-d0b7-aa45-79a76bd09c8a.jpeg)


# おわりに
安価でプログラミングも不要で自動制御が実現できるスイッチボットは非常に魅力的です。iFTTTを経由すれば簡単にLINE通知なども可能なのでモニタリング装置としても有用です。

今後ボットを使った保冷庫の自動制御も検討中です。
QAチームの目標管理制度


**QAチーム目標管理**もしくは**エンジニア目標管理**は難しいものがあり、**「OKR」**　**「MBO」**　**「KPI」**　のうちどの目標管理制度を用いるべきか考察してみます。

ただ**目標管理**するのではなく、**「今後のキャリアビジョン」**　にも少なからず影響が出てくるので。

先を見据えたものが必要となります。


※今回は上記の中から　**「OKR」**　**「MBO」**　にフォーカスいたします。

# OKR

OKRとは  **「Objectives and Key Results」** の略であり、日本語では **「目標と主要結果」** と言う内容となります。

**主な結果（Key Results）の基準**が設定。
**Key Results**を知ることにより現在の進捗を把握できる。**Objectives**に対しての評価にもつながる。

**MBO**と**OKR**は、組織目標を基準とし個人の目標を設定するという面では同じ。ですが、**評価頻度**や**計測**、**目標共有**そして**最終目的・達成数値**がMBOとの違いです。

### XXXXXQA Team　OKR

| 項目 | 内容| 例|
|:-----------|:------------:|:------------:|
| 評価頻度     | 月に1回から3カ月に1回ほど       |  QA Team内で月に1回 1on1 もしくは 2on1で状況を評価    |
| 計測は？    | 定量的（Key Results）    |  1.不具合の問い合わせの数が前回より○％減少|
|    | 定量的（Key Results）    |2.QA Engineerを1名内定受諾|
| 目標共有の範囲    | 全体・部内       |  開発部内・QA Team内（会社の組織・規模によります）   |
| 最終目的は    | 業務品質の向上、業務スキルの向上       | 事業品質定義をクリアし、必要とされるテストカバレッジも担保  |
| 達成数値   | 60%〜70%     | QA Teamでは今期65％達成でき、来期につなげていきます。   |


# MBO

「Management By Objective」の略で、日本語では **「目標管理」** という意味になります。

評価者である　**QA Manager** と被評価者である **QA Engineer**・**QA Tester**が、日々コミュニケーションを把握しつつ、**エンジニア目標・チーム目標**を設定。
**達成・貢献度**を元に評価するシステムです。

### XXXXXQA Team　MBO

| 項目 | 内容| 例|
|:-----------|:------------:|:------------:|
| 評価頻度     | 半年に1回から1年に1回ほど     |  QA Managerが半年に一回評価する   |
| 計測は？    | 定量的 ・定性的・選択するのは企業による。      | 業務で用いているテストツール「MagicPod」のメンテナンスができるようになる    |
| 目標共有の範囲    | 上長と本人の2人      |  QA ManagerとQA Engineer|
| 最終目的は    | 昇給や役職がつくとか       | QA Leaderになり1万円の昇給となる    |
| 達成数値   | これは全てクリア（100%）     | 「MagicPod」のメンテナンスが可能。一人でできるようになりました。  |


## 最後に
どの目標管理制度にするかは、**プロダクトや組織**によるところもありますが
きちんと評価できる制度であることが一番です。特にQAというのは、評価するのが難しい部門でもあり、もしくは業務であり、今後の課題でもあるかと思います。

※QAエンジニアの業務もしくは、0→1でTeamビルディングを行う業務に対して**どのように評価すべき**かが課題となるのか。

## 余談
・事業フェーズで考えると、**Churn Rate（解約率）**　であったり **MRR（月次経常収益）** ではあるが、QAとどう紐づいているのかきちんと検証が必要。

・開発フェーズで考えると、**不具合の検出率**・**テストレベルでの不具合検出**（レベル分けをし、損失コストに換算したり）/ **Pdmが作成した仕様書のレビュー内容を点数化**したり、その点数を目標管理に利用とか。

・業務全体で考えると、**QAエンジニアの採用**だったり/**ツールの導入により以前と比較し良くなった**/ドキュメントの作成/更新/削除などに点数を与えて。あと、QAイベント開催計画/実行/振り返りも。
（プロセスにも点数を与えて、目標管理に紐づけることも必要なのかな。）

色々と思いつきますが、QAと紐づく数値で測らないと評価の意味がなく、事業規模や対象プロダクトとの相談も必要です。
PagerDuty 設定ガイド (動員編1) - 概要: 通知を受けるまでの設定の流れ

PagerDuty設定ガイドは、主に管理者がどのようにPagerDutyを設定・管理できるかについて説明します。管理者ではない、PagerDutyを利用してインシデント対応を行うユーザー(Responder)の方は、こちらの [PagerDuty利用ガイド - Responder編](https://qiita.com/ymotomu/items/42f825accbfca287464a) をご覧ください。

## PagerDutyとは
2009年に米国で創業した「インシデント対応ソリューション」という分野を創った会社です。システム障害などの「インシデント」が発生した際に、AIや自動化を駆使して速やかな復旧と運用担当者の負担軽減を実現します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2777160/a7909ce5-3c50-5198-2511-39636dd6f5ea.png)
様々な監視ツールやコミュニケーションツール、チケット管理ツール等が混在していたとしても、PagerDutyと連携させることでインシデントがシステム全体のどこに影響しているのか、リアルタイムで共有することができます。
また、対応履歴やMTTA/MTTRなどの運用指標が可視化されるため、継続的に運用プロセスを見直して改善するサイクルを回せるようになります。


## 本記事「動員編」の位置づけ
この「動員編」では、PagerDutyから通知を受けるために必要な、基本的な設定をまとめます。PagerDutyの検証およびProduction環境の構築を行う際は、まずこの章の設定項目から手を付けることをおすすめします。

PagerDutyの機能の中では、以下中央の「動員」にあたる部分になります。
![PD_Overview-Mobilize.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2777160/33a14f42-fd7f-1549-28f0-858ba9544834.png)



### 「動員編」を完了すると、できるようになること
1. モバイルアプリ・電話・SMS・Email・チャット(Slack等)を組み合わせて、通知を行うことができる
1. Service/Escalation Policy/On-call Schedule/Usersの関係性と役割がわかる
1. Serviceをどのような単位で定義すればいいのかわかる
1. 通知テスト(PagerDutyコンソールからインシデントを起票して、通知を受ける)ができる*
1. Chatツール(Slack/MS Teams/Google Chat/Cisco WebEx等)で通知を受けたり、ChatツールからPagerDutyを操作できる

*監視ツール等からのアラートをサービスに紐づけ、インシデントを自動作成する方法については「[検知編](https://qiita.com/ymotomu/items/f9e8de2dfa94394df54c)」を参照ください。
## PagerDuty設定ガイド 目次
[検知編](https://qiita.com/ymotomu/items/f9e8de2dfa94394df54c) | [トリアージ編](https://qiita.com/ymotomu/items/1a40022feabae53e85c9) | **[動員編](https://qiita.com/ymotomu/items/e6d13e5284a62e3a1100)** | 解決編 | 学習編
1. [概要: 通知を受けるまでの設定の流れ] << イマココ
1. [ユーザーの追加と通知設定](https://qiita.com/ymotomu/items/b67758adf6c55a948386) - 通知を受ける担当者と通知方法を設定する
1. [On-call Scheduleの作成](https://qiita.com/ymotomu/items/66c7157c2330d23d576f) - (Optional) 担当者がローテーションを組む場合には、On-call Scheduleを作成する
1. [Escalation Policyの作成](https://qiita.com/ymotomu/items/728461b1a63cf56594a3) - どのような順番で担当者をインシデントにアサインするか設定する
1. [Serviceの作成](https://qiita.com/ymotomu/items/3cb2d8898857cdcbab02) - Serviceを定義し、Escalation Policyを紐付ける
1. [通知テストの実施](https://qiita.com/ymotomu/items/4f26d5ec1d713387aff9) - PagerDutyコンソールからインシデントを起票し、通知を受ける
1. [Slack等との連携](https://qiita.com/ymotomu/items/04afd0da5f0bf0863727) - ChatツールでPagerDutyの通知を受けたり、ChatツールからPagerDutyを操作する

## 参考リソース
* [PagerDuty利用ガイド - Responder編](https://qiita.com/ymotomu/items/42f825accbfca287464a)
* [Trial Account Onboarding](https://support.pagerduty.com/main/lang-ja/docs/trial-account-onboarding)
* [The Onboarding Checklist](https://community.pagerduty.com/pagerduty-user-onboarding-13/the-onboarding-checklist-418)
* [システム障害を未然に防ぐ「インシデント管理・対応」とは](https://www.pagerduty.co.jp/blog/what-is-incident-response)
* [PagerDuty - 14日間 無料トライアル](https://www.pagerduty.co.jp/lp/free-trial/)
DynamoDBのレコードを主キー以外で取得するLambda

# 概要
  LambdaからDynamoDBのレコードを主キー以外で取得する方法を紹介します。

# 前提条件
  - DynamoDBにテーブルが作成されており、データも登録されていること
  - 必要なIAM権限が付与されていること

# 環境
  - ランタイム：Python3.9
  - リージョン：ap-northeast-1

# コード
  ```python
    import boto3
    from boto3.dynamodb.conditions import Attr

    dynamoDB = boto3.resource("dynamodb")
    table_name = <DynamoDBのテーブル名>
    table = dynamoDB.Table(table_name)

    def lambda_handler(event, context):
        column = <検索に使うカラム名>
        data = <検索に使う値>
        
        responce = table.scan(
            FilterExpression = Attr(column).eq(data)
        )
        
        return responce
  ```

# 説明
  scan関数内の FilterExpression で Attr を指定することで、主キー以外でのレコード取得が実現できます。

  2行目の import に Key を加え、scan関数内の FilterExpression で Key を指定すると、主キーでのレコード取得になります。

  また、.eq() は .ne() にすると、指定した値以外のレコードを取得可能です。

# 実行例
  - コード
  ![code](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/b915c3b3-a6dd-7dc7-cd80-18ef379d9d37.png)

  - 結果
  ![result](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/84fc3b4a-f299-26ad-9c14-992f02aeebba.png)
業務でよく使用したPHP関数、Laravelヘルパ関数

## はじめに
本記事は[アイレット株式会社 22新卒 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/iret-22)の記事となります。

私は最近初めてLaravelを使い、開発を行うようになりました。この記事を書いている時点では、Laravelを使い始めて約5ヶ月になります。
この記事では、これまでよく使用したり、混乱しがちであったPHP関数、Laravelヘルパ関数について、書いていきたいと思います。
記事を書くのが初めてなので、至らぬ点も多いかとは思いますが、温かい目で見守って頂けますと幸いです。

## empty(), is_null(), isset()
null判定を行う際、どの関数を使って良いのかわからなくなる事が多かったので、まとめました。

### empty()
null, 0, "0", false, 空配列である時にtrueを返します。

例
```
$value = 0;

empty($value)　;  // true
```

### is_null()
nullである時のみtrueを返します。

例
```
$value = null;

is_null($value)　;  // true
```

### isset()
定義されていて、かつnullではない時にtrueを返します。

例
```
$value = '';

isset($value)　;  // true
```

各関数の結果を表にまとめました。
|  | empty() | is_null() | isset() |
|:-:|:-:|:-:|:-:|
| 空文字('')  | true  | false   | true  |
| 空配列([])| true  | false  | true  |
| 0  | true  | false  | true  |
| '0'  | true  | false  | true  |
| null  | true  | true  | false  |
| 'null'  | false  | false  | true  |
| false  | true  | false  | true  |
| 'false'  | false  | false  | true  |


## blank(), filled()
blank()は、指定された値が「空白」であるかどうかを判別します。
filled()はblank()と逆の動作をする関数です。


```
blank('');
blank('   ');
blank(null);
blank(collect());

// true

blank(0);
blank(true);
blank(false);

// false

-----------------------------

filled(0);
filled(true);
filled(false);

// true

filled('');
filled('   ');
filled(null);
filled(collect());

// false
```

## 配列関係の関数
配列関係の関数もよく使用しました。中でも特によく使用したものの使用法についてまとめます。

### Arr:first()
条件にマッチする最初の要素を取得します。
```
$array = [50, 100, 150, 200];

$first = Arr::first($array, function ($value, $key) {
    return $value >= 80;
});

echo $first;  // 100
```

### Arr::get()
ネストされた配列をドット記法で取得できます。
```
$array = ['products' => ['pc' => ['price' => 200000]]];

echo Arr::get($array, 'products.pc.price'); 　　　　// 200000

//値が存在しない場合のデフォルト値も指定できる
echo Arr::get($array, 'products.pc.weight', 0); 　　// 0
```

### Arr::has()
連想配列のキーが存在するかドット記法でチェックします。
```
$array = ['products' => ['name' => 'pc', 'price' => 200000]];

Arr::has($array, 'products.name');  // true

Arr::has($array, ['products.price', 'products.weight']);  // false
```

### Arr::set()
深くネストした配列にドット記法で設定できます。
```
$array = ['entry' => ['user' => ['name' => 'sato']]];

Arr::set($array, 'entry.user.name', 'tanaka');

// ['entry' => ['user' => ['name' => 'tanaka']]]
```

### in_array()
配列の中に指定した値が存在するかをチェックします。
```
$array = ['red', 'blue', 'green'];

in_array('blue', $array);  // true
in_array('yellow', $array);   //  false


// 第三引数にtrueを渡して、検索する値のデータ型までチェックする
$array = ['1', 10, '100'];

in_array(10, $array, true);   // true
in_array('10', $array, true); // false
```


## 最後に
以上、私がよく使用したり、混乱しがちであったPHP関数、Laravelヘルパ関数についてまとめてみました。
普段PHPやLaravelを使用している人にとっては当たり前な内容だったと思いますが、まだ使用した事がない人や、私と同じく初学者の方の参考に少しでもなれば幸いです。
記事を書くのは初めてでしたが、アウトプットをすることで、より理解を深める事ができたと思います。
まだまだ勉強中の身ですが、これからより専門的な記事が書けるように頑張っていきたいです。
最後までお読みいただきありがとうございました。
MFC から SVG の基本図形（2/2）

## 四角形
四角形は MFC も SVG も描画開始点と横幅、縦幅を指定して描画します。
SVG では角の円い四角形は rect の属性値 rx, ry を指定すれば描画できます。
MFC で描く場合はパスを利用することになりますが SVG の出力で簡単に描けてしまいますので追加する関数では角の径を指定するようにしておきます。

```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddRect(double dX, double dY, double dWidth, double dHeight,
+                double dRx, double dRy, int nDepth = 0);
}
```
```cpp:SvgImage.cpp
void SvgImage::AddRect(double dX, double dY, double dWidth, double dHeight,
                       double dRx, double dRy, int nDepth)
{
	SvgTag *svgPath = new SvgTag();
	svgPath->m_strName = L"rect";
	svgPath->m_nDepth = nDepth + 1;
	svgPath->m_bOne = TRUE;
	mdPoint point;

	CString csStr;
	csStr.Format(_T("%lf"), dX - m_rectAll.left);
	svgPath->m_arrAttr.Add(L"x");
	svgPath->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%lf"), m_rectAll.bottom - dY);
	svgPath->m_arrAttr.Add(L"y");
	svgPath->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%lf"), dWidth);
	svgPath->m_arrAttr.Add(L"width");
	svgPath->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%lf"), dHeight);
	svgPath->m_arrAttr.Add(L"height");
	svgPath->m_arrAttrValue.Add(csStr);
	// 角の径は負の値をとらない
	if ((dRx > 0) || (dRy > 0))
	{
		dRx = !(dRx > 0) ? dRy : dRx;
		dRy = !(dRy > 0) ? dRx : dRy;

		csStr.Format(_T("%lf"), dRx);
		svgPath->m_arrAttr.Add(L"rx");
		svgPath->m_arrAttrValue.Add(csStr);
		csStr.Format(_T("%lf"), dRy);
		svgPath->m_arrAttr.Add(L"ry");
		svgPath->m_arrAttrValue.Add(csStr);
	}

	m_arrayTag.Add(svgPath);
}
```

## 円、楕円
MFC で円や楕円を描く場合、四角形の頂点を指定し、その内側いっぱいに円が描画されます。
SVG で楕円を描く場合、中心点の座標と X 方向の径と Y 方向の径が必要になります。
四角形と同じく、楕円も SVG の描き方に合わせた関数にします。

```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddEllipse(double dCx, double dCy, double dRx, double dRy, int nDepth = 0);
}
```
```cpp:SvgImage.cpp
void SvgImage::AddEllipse(double dCx, double dCy, double dRx, double dRy, int nDepth)
{
	SvgTag *svgPath = new SvgTag();
	svgPath->m_strName = L"ellipse";
	svgPath->m_nDepth = nDepth + 1;
	svgPath->m_bOne = TRUE;

	CString csStr;
	csStr.Format(_T("%lf"), dCx - m_rectAll.left);
	svgPath->m_arrAttr.Add(L"cx");
	svgPath->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%lf"), m_rectAll.bottom - dCy);
	svgPath->m_arrAttr.Add(L"cy");
	svgPath->m_arrAttrValue.Add(csStr);
	// 径は負の値をとらない
	if ((dRx > 0) || (dRy > 0))
	{
		csStr.Format(_T("%lf"), dRx);
		svgPath->m_arrAttr.Add(L"rx");
		svgPath->m_arrAttrValue.Add(csStr);
		csStr.Format(_T("%lf"), dRy);
		svgPath->m_arrAttr.Add(L"ry");
		svgPath->m_arrAttrValue.Add(csStr);
	}

	m_arrayTag.Add(svgPath);
}
```
Rails7をDockerfileとdocker-composeを使って立ち上げる

Ruby on Rails7を簡単に立ち上げるファイル群をGithubにあげました。

DockerでRailsのイメージを使うのが一番簡単な方法ではありますが、イメージの方に色々入れたい派の人間なので、昔ながらのDockerfileとdocker-composeを使います。

ということでDockerの環境があれば、以下のファイルをClone→実行することでRailsのスタートページを簡単に立ち上げることができます。

手順は以下の通りです。

1. もってくる
```
$ git clone https://github.com/hatoPoPoPoPo/rails7.git
```

2. ディレクトリ移動
```
$ cd rails7/
```

3. Docker Buildを実行
```
$ docker-compose build --no-cache
```

4. コンテナ起動
```
$ docker-compose up -d
```

5. DBの作成

```
$ docker-compose run --rm rails rake db:create
```

6. ブラウザを使って起動を確認🎉
```
http://192.168.33.10:3000/
```

以上です。
エラー出るのは多分bundle installの実行中のためだったりするので待ってくださいね🔰

お役に立ったようであれば、いいね👍いただけると嬉しいです😃
AppSyncのリゾルバーでUUIDの発行

# 概要
  この記事では、AppSyncのリゾルバーでUUIDを発行しDynamoDBに登録する方法を紹介します。

# 前提条件
  - AppSyncのスキーマができていること
  - DynamoDBが用意されていること

## リゾルバー

### リクエストマッピングテンプレート
  ```
  {
    "version": "2017-02-28",
    "operation": "PutItem",
    "key": {
      "id": $util.dynamodb.toDynamoDBJson($util.autoId())
    },
    "attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input),
      "condition": {
      "expression": "attribute_not_exists(#id)",
      "expressionNames": {
        "#id": "id"
      }
    }
  }
  ```

  ``$util.autoId()``でUUIDを発行できます。

### レスポンスマッピングテンプレート
  ```
  $util.toJson($ctx.result)
  ```

# 実行
  - クエリを実行する
    - 画面左が実行クエリ、画面右が実行結果
    ![クエリ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/d4171eeb-01a3-9d62-43bc-5a91f6926d69.png)
  - DynamoDBにデータが登録されていることの確認
    ![DynamoDB](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/7139a4cf-0e27-0863-e01a-2d7dbc61d0ed.png)
floorメソッド

# はじめに
floorメソッドの存在を知っておくための議事録です。

## floorメソッドとは
小数点の切り捨てを行うメソッド。
.to_f（整数を小数にするメソッド）のfもfloorの略と考えられる。
以下使い方。

    irb(main):001:0> 3.1.floor
    => 3
    irb(main):002:0> 3.9.floor
    => 3
質問の事前準備について

# 質問がたくさん思いついたとき
業務を進める中で、複数の質問を一度にまとめて聞く際にこのようなことないでしょうか。
・質問に至るまでに自分が取り組んだことを説明しきれない。
・質問した次の日にメモを見返しても、何に対する質問の回答だったか思い出すのに時間がかかる。
これらの問題は、質問前の事前準備やメモのルールを作るだけで改善することがあるので共有します。

## 書き出すこと、文字色を変えること
やることは３つだけ。
取り組んだこと、取り組んだ上で分からないこと、質問の回答を書き出す。
取り組んだことは水色、取り組んだ上で分からなかったことは紫色、質問の回答を黒色などでそれぞれ色分けする。

自分は普段BIツールを使用してデータ分析のサポートをする業務に携わっているのですが、計算式を考える際に躓くことが多いです。
その際は、一旦思いついた計算式を水色文字でスプレッドシートに書き出しています。
計算式で疑問点や不明点が残るポイントは文字色を水色から紫色に変更。疑問点と不明点も紫色文字で言語化する。

この手順を踏むことで、紫文字を辿れば質問の要点が一目で分かりますし、水色文字を辿れば質問に至るまでの経緯がまとめられていて便利です。

質問が一通り済んで計算式が確定した箇所は黒にしています。
黒色文字を読み返すことで質問に対する回答を後でまとめて読むことができます。

## 最後に
上記はあくまで一例ですが、質問は事前準備やメモのルールを決めると改善ことがあるかと思います。
参考にしていただけると幸いです。
サクラエディタで行ジャンプのショートカット

# やり方

1. Ctrl + J 。
1. 画面が出てくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/407768da-ade0-eb61-f025-d852f7e588ed.png)
1. 行番号入力してエンター。

**JUMP（ジャンプ）** の **J** と覚える。

# 存在しない行番号の場合

負の値ならエラー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/0c00059f-f606-4c87-23a5-babdfddac397.png)

0なら先頭行。

60行までなのに999行にジャンプするような指定は、最終の60行目。

# 参考サイトさん

https://pasomaki.com/sakuraeditor-rownum-jump/

# バージョン

Windows 10 Pro 21H2 OSビルド 19045.2251
サクラエディタ   v2.4.1.2849 32bit (tag v2.4.1)
Timeメソッドについて

# はじめに
Rubyの標準ライブラリであるTimeメソッドについて忘れないように記録に残す。

## Timeメソッドとは
TimeクラスはRubyの標準ライブラリにあり、時刻を表すクラスです。
以下のように利用します。

    # 現在時刻
    time = Time.new
    p time
    p time.year        #年
    p time.month       #月
    p time.day         #日
    p time.hour        #時
    p time.min         #分
    p time.sec         #秒
    p "曜日番号:#{time.wday}" #日曜日を0とした曜日番号
    p "timeの年の1月1日から何日経過したか:#{time.yday}" #timeの年の1月1日から何日経過したか
    p "タイムゾーンの確認:#{time.zone}" #タイムゾーンの確認

    # 実行結果
    2017-07-24 16:47:04 +0900
    2017
    7
    24
    16
    47
    4
    "曜日番号:1"
    "timeの年の1月1日から何日経過したか:205"
    "タイムゾーンの確認:JST"

    # 曜日の出力
    days = ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"]
    puts = "#{days[time.wday]}です"
    
    puts %w(日 月 火 水 木 金 土)[time.wday] + '曜日です' 
    これは%w記法といい、%w(日 月 火 水 木 金 土)という記述でweek = ["日","月","火","水","木","金","土"]と同じ意味になる。
Amazon SESを前知識0から構築してみた

# この記事は何？
新卒一年目が前知識０からAmazon SES(以下SES)でメールサーバーを構築した話の振り返りのようなもの。
その中で「なるほど」と思ったことを残します。
※構築の手順書ではないです

# 構築前のAmazon SESのイメージ
AWSのメール送信ができるサービス。

# Amazon SES とは
以下公式より引用となります。
> Amazon SES は、一括 E メール送信用の任意のアプリケーションに統合できるクラウド E メール サービスプロバイダーです。
トランザクションメールを送信する場合でも、マーケティングメールを送信する場合でも、使用した分だけ料金が発生します。
Amazon SES は、専用 IP アドレス、共有 IP アドレス、所有 IP アドレスなど、さまざまなデプロイもサポートしています。
送信者統計に関するレポートと到達率ダッシュボードは、企業がすべての E メールを活用するのに役立ちます。

https://aws.amazon.com/jp/ses/

SESってどんなサービス？を一言で表すと、「Amazonが所有しているメールサーバーを借りてメールの送信ができる。」ですね。
その中で、「従量課金ですよ〜」とか「マネージドサービスなので信頼性・可用性が高いですよ〜」とか、自前でサーバーを用意する際の懸念点をカバーしてくれています。

# 構築してみて始めて知ったこと
「構築してみて始めて知ったこと」と見出しで書いていますが、「前知識0」なので初めから最後まで知らないことばかりでした。。。
流石に全部は書ききれないので、大きくハマったところについて2つ書こうと思います。

## IAMユーザーの作成 ・ SMTP認証情報の取得
SESでは認証された送信元の登録として、ドメインorメールアドレスを登録します。
ここで登録したドメインorメールアドレスからしか、メールは送信できません。
さらに、SESにはメール送信方法として「SMTP接続を使う方法」、「Amazon SES APIを使用する方法」の二通りがあります。

メールサーバーの仕組み・設定方法すら知らなかった私は「送信元として使いたいメールアドレスを登録しておしまい！」と考えていました。
しかし、メールアドレスを登録するだけではもちろんメールの送信はできません。（テスト用としてごく簡単なメールは送信できます）

今回担当した案件の要件では「メール送信はメーラーからSESに接続する」ことだったため、上記で挙げた送信方法のうち「SMTP接続を使う方法」を使ってSESのメールサーバーに接続する方法を採用しました。

### IAMユーザーの作成
SES では 「Amazon が所有しているメールサーバーを借りる」ため、そのサーバーへ接続する認証情報が必要になります。
そのため、メールサーバーへ接続可能なロールを持ったIAMユーザーを払い出す必要があるんですね。

SES のコンソールを使えば、そのIAMユーザーを払い出しが簡単にできます。
手順書ではないため詳細は省きますが、下記の四角で囲んだボタンから、IAMユーザー名を入力するだけで作成ができます。
![smtp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953286/7101d577-4981-3a01-85e6-db243198a04d.png)

IAMユーザーの作成が完了すると「ユーザー名」と「パスワード」が発行されるので、「メールサーバーの名前（エンドポイント）」「ポート番号」と合わせて、メーラーに接続情報を渡してあげることで、無事メーラーからメールの送信ができるようになりました。

## パスワードの文字数が多すぎる
こちらは実際に顧客からお問い合わせがあり、対処できるかそうかでハマった問題です。

上記の「IAMユーザーの作成」で発行したパスワードは40字以上の英数字で構成されていました。
このパスワードの長さにメーラーが対応しておらず、短くできないかを調査することとなりました。

まずは、AWS公式のドキュメントを確認してみます。下記の記述が確認できました。
>SMTP パスワードを変更する場合は、IAM コンソールで既存の SMTP ユーザーを削除します。次に、前の手順を完了して、新しい SMTP 認証情報のセットを作成します。

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/smtp-credentials.html

要は、SMTP認証で使うパスワードを変更したいときは、ユーザー削除して再作成してね。ということのようですね。
パスワードの長さを短くできるかどうかについての明確な記載は確認できませんでした。
他技術者様の記事等も複数拝見しましたが、結論は見つからず。
![nayamu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953286/901a18a3-33ea-0549-83b0-e473abc0ba12.png)

解決の糸口が見えないまま悩んでいましたが、ことの最後は意外とあっさり解決しました。
グループミーティングで「SMTP認証で使うパスワードが短くできるかどうか、悩んでるんですよね」と相談させていただいたところ、チームの方から「短くはできないみたいですね」と根拠付きで教えていただきました。
答えは AWS re:Post にありましたね。。。

https://repost.aws/questions/QUeJBtQdcySviABnACETPayQ/ses-smtp-password-length

この件に関しては「調べる力」がまだまだだな、と痛感する良い機会となりました。
同時に調べる力持っている方のすごさを体感しました、

# おわりに
Qiitaに記事を投稿するには初めてでしたが、学んだ技術やハマったことはアウトプットすることで、自分自身の経験を振り返る良い機会になるなと感じました。アドベントカレンダーという形で記事投稿の機会をくれた @Michinosuke ありがとう:clap:
function Layout({ children }) ...の{ }って？

# この{}はなにか
ES6で追加された分割代入という書き方です。
オブジェクトから特定のプロパティの値だけを取り出せます。
# JSではこんなふうに書けます
以下の例では引数にとったobjectのproperty1の値だけを取り出しています。
```javascript
const obj = {
    property1: "hoge",
    property2: "huga",
    }

const isHoge = ({property1}) => {
    return property1 === "hoge"
}

isHoge(obj)
// true
```
# JSXではこんなふうに書けます
Reactでも、引数自体はオブジェクトとして渡ってきており、そのchildrenプロパティだけ取り出しているわけですね。


そのため
```jsx
export default function Border({ children }) {
    return (
        <div style={{ border: "solid" }}>
            {children}
        </div>
}
```
は、分割代入を使わずに
```jsx
export default function Border(props) {
    return (
        <div style={{ border: "solid" }}>
            {props.children}
        </div>
}
```
と書くこともできます。
すぐ思いつく分割代入の利点は、children以外のプロパティはいらないんだな、とひと目でわかることでしょうか。
# 蛇足
今まできちんと理解せず「children使うときはこうやるんだ〜」って書いてました。反省。
# 参考
https://ja.stackoverflow.com/questions/81080/%E5%BC%95%E6%95%B0%E9%83%A8%E5%88%86%E3%81%AB%E3%81%82%E3%82%8B%E6%B3%A2%E6%8B%AC%E5%BC%A7%E3%81%AF%E3%81%A9%E3%81%86%E3%81%84%E3%81%86%E6%84%8F%E5%91%B3%E3%81%A7%E3%81%99%E3%81%8B

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

https://ja.reactjs.org/docs/components-and-props.html
【文字検出_備忘録】OpenCV X Python 画像の読み込みとグレースケール化

産休にはいって、出産まであと1ヶ月切ったので、子供を産まれるまで、どこまでできるかチャレンジ。
私のスペック
・情報工学、学部卒（なのでたかが知れてる）
・とあるメーカー　設計・開発業務 5年目、主にマネジメントしかしてない
・子供１人、２歳（まだ夜泣きもするし、寝るのもへたっぴなので夜はほぼ活動してない）

いや、多分こんな文字検出なんかね、どこでも載ってるんだけど、色々やってみたいので、お勉強兼ねて少し、鈍臭くやった備忘録を書きます。
鈍臭くっていうのは、データの中身をちゃんとみたり、どうしたらAPIやライブラリを使用せずに組んでみたりするってこと。です。



# 前提条件

## 開発環境
OS macOS Monterey
ハード iMac (21.5-inch, Late 2015)
Memory 8GB


## 今までやってきたこと
・開発環境整備
　Python, OpenCVI(Numpy含む), Matlabplotlib
・エディタ SublimeText

## やりたいこと
・画像から文字検出

## 考えてるステップ
Step0 画像の読み込み
Step1 ２値化を実施
Step2 輪郭を抽出
Step3 のエッジを検出し、文字を切り抜き


# 進捗
## Step0 画像の読み込み
まず、いろんなライブラリの読み込み。
必要なのは、cv2(画像処理のライブラリ）、numpy(行列計算系,行列のプロットに役に立つ）,matplotlib(画像処理結果を、画像で教えてくれる）
だと思う、今のところ。

```
import cv2
import numpy as np
import matplotlib.pyplot as plt

#ファイルパス
IMG = ".../apple.png" #処理対象
IMG_file_path = ".../apple_photo_text" #読み込んだnpyファイルパス＋名前
IMG_GRAY_file_path = ".../apple_photo_text_gray" #2値化した後のnpyファイルパス＋名前
```
🌾最初グレースケール化で遊んでたので、GRAYが入ってマス。めんどくさいのでそのまま。

続いて、画像の読み込み
```
img = cv2.imread(IMG) 
np.save(IMG_file_path,img)
```
IMG_file_pathのファイルに保存してみた。せっかくなので中身を見てみよう・・

```
934e 554d 5059 0100 7600 7b27 6465 7363
7227 3a20 277c 7531 272c 2027 666f 7274
7261 6e5f 6f72 6465 7227 3a20 4661 6c73
652c 2027 7368 6170 6527 3a20 2836 3837
2c20 3835 3629 2c20 7d20 2020 2020 2020
2020 2020 2020 2020 2020 2020 2020 2020
2020 2020 2020 2020 2020 2020 2020 2020
2020 2020 2020 2020 2020 2020 2020 200a
fbfb fbfb fbfb fbfb fbfb fbfb fbfb fbfb
....
```

うーんなるほど。**わからん**
どうやら、16bitの何からしい。

こういう時は、定義をみましょうね。
Imreadの定義

https://docs.opencv.org/3.4/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56


どうやら、cv::Mat型で返してるらしいのでそっちをみる
CV:Mat型の定義

https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html

..わかんないので、先に行こう。

https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/

どうやらこれが参考になりました。BGR値で返しているらしく、3次元配列（一つのセルに３つ値が紐づく状態）を、numpy.ndarrayで出力しているそう。
なるほど・

numpu.ndarrayとは


https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html

ということで、以下でデータの中身を見るお手伝いをしてみた。
```
print(img.shape)
#(687, 856, 3)
print(img.dtype)
#uint8
```
なるほど。つまり、y軸 687pixel x軸 856pixel, dimention(次元）が3次元の配列、各要素はUINT8型の行列式なのである。ちゃんと理解するために、ここでちょっと遊んでみようと思う。

参考
https://qiita.com/sino20023/items/ec7e0ac77547f3b6484b

```
print(img[200:203,200:205])" #img[Y,X]らしい

```

出力結果。

```
[[[134 113 247]
  [134 112 248]
  [134 112 248]
  [134 112 248]
  [134 112 248]]

 [[134 113 247]
  [134 112 248]
  [134 112 248]
  [134 112 248]
  [134 112 248]]

 [[134 113 247]
  [134 112 248]
  [134 112 248]
  [134 112 248]
  [133 111 247]]]
```

なるほど、めちゃめちゃわかったぞ。
１セルめのBGR値が[134 113 247]
X=0(1行目)が、以下。これがy軸方向に3行続いてるってことだね！なるほどね！！
```
[[[134 113 247]
  [134 112 248]
  [134 112 248]
  [134 112 248]
  [134 112 248]]
```


参考記事


https://note.nkmk.me/python-numpy-image-processing/


ということは、2値化するためにはどまずはBGR値だとすこぶるめんどくさいのでグレースケールに落とし込みます。

グレースケール化は、cvtColorでやりました。imreadでもできるらしいんで、どっちでもいいと思います。

```
#グレースケール処理
img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
```
実は、これをやったあと、255 = 黄色,0 = 緑っぽく出てきて、ちょっと困惑したんですが、とりあえず、BGR値から解放されてるっぽいのでいいでしょう。
何でかはわからんが、いかを試したら、グレースケールになりました。まぁね、何色かはどうでもいいから。

https://qiita.com/Daiki_P/items/844bc3a4b271e6ae179b
FPGAとかQuartusってなんなのか

# 授業でFPGAを使った程度の大学生による振り返りを含めた紹介記事
(すみません！いつの間にか１２月１日になってました…。論文書いたりで思ったより時間が取れなくて想定以上の悪い記事になってしまいました．申し訳ございません。）

初めまして！2022年の12月1日，こんにちは，おはようございます。たまたまメールを見ていたら，Qiitaに記事書いて豪華景品！みたいな感じに流れてきたので，カレンダー一覧を眺めていたら『FPGA』という単語が目に入りました。ちょっとだけ触ったことがあるので，AirPodsPro欲しさに記事を投稿します。


**きっと間違ったことを書いていたらアドカレの明日以降のすごい方々が指摘してくださると思います…。（間違い過ぎててやばかったら消えるかもしれません…)**
- 本記事に含まれないこと
    - 技術的な詳細
    - 技術的な知見
- 本記事に含まれること
    - 経験談

技術的な凄みのあることは書けないので，あえて1日目をもらって，FPGAってなんなの？みたいな話をざっくりと書きます。
そうして，FPGA知らない人が2日目以降の記事を読むときにちょっとでも役に立てばいいな～と思います。

自己紹介とか，FPGAにあんまり関わらない内容も挟んでいるんで読みたいところだけ読んでくれたらうれしいです。
## 自己紹介(FPGAとの出会いとか)
- なまえ
　名前は「にぼし」とか「nibosea」とか「瑞々しぃにぼし」とか，『にぼし』っぽい名前で活動しています。Twitterは変なことしか書いてないので，ブログのリンク張っておきます…
https://iloveconviniboshi.hatenablog.com/entry/2019/11/24/012952 
(ちなみに，[リンク](example.com)って形にすると，URL見えなくて嫌いな人いるっぽいのでURL直接貼ってます）
- 何している人？
    - 卒業研究で苦しんでいる人。
        - 論文投稿締め切りとアドカレを同時進行させられています。つらいです。
    - 競技プログラミングをしている人。
    - PCで銃撃つゲーム（CS：GOとかValorantとかApeXとかOverwatchとか）をしている人（プロではない）
- 職業
　情報系の大学の学部4年生です．もうすぐ卒業します。
FPGAは，大学3年の後期（つまり去年の今頃）の授業で触りました。『実験ちょめ』という名称の授業で，パワハラ・アカハラで一時期話題になっていた（らしい）授業です。うちの学部学科の一番大きな闇と言われています。（言われていました）。

ちなみに，この授業では，FPGAを使ってCPUを作る！みたいな趣旨でした。内容としては面白いと思うんですよね。実際，結構面白かったし。

何が良くないって，闇の印象を学生が植えつけられ過ぎていて，それが周りにも伝染してたのが良くなかった。
## FPGAって何？
『FPGA（英: field-programmable gate array）は、製造後に購入者や設計者が構成を設定できる集積回路であり、広義にはPLD（プログラマブルロジックデバイス）の一種である。現場でプログラム可能なゲートアレイであることから、このように呼ばれている。』(https://ja.wikipedia.org/wiki/FPGA より)

- アルバム漁ってたんですけど当時使ってたFPGAボードが見つからなかったので，適当なFPGAボードの画像貼ります
    - こんな感じで，スイッチとか，LED表示する場所とか，ボタンが付いているやつです！　
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568898/47fcc6aa-4713-14ea-1db3-9c557381e795.png)
        - 画像は秋月電子通商さんからお借りしました．(https://akizukidenshi.com/catalog/g/gM-08634/)

自分としての理解を述べます。
要は，回路図を好き勝手書き換えられるもの。みたいな感じでとらえています．
1. ソフトウェア（例えばQuartus)で回路図Aを作ります。その回路図AをFPGAにインストールします。これで，回路図AがFPGAに書き込まれました。
1. 実際にFPGAを動かしてみます。うまく動きません。
1. ソフトウェアで回路図Bを作ります。回路図BをFPGAにインストールします。これで回路図BがFPGAに書き込まれました。
1. さて，もう一度FPGAを動かしてみます。うまく動きました！

こんな感じで，自由に書き換えられるから，プログラマがコード書くときみたいに自由に実験出来ていいね！とかそんな感じです。
もっとハードっぽいものだと，回路作る=半田付けとかする，みたいな感じで，一回はんだつけたら作り直すの大変だけど，FPGAなら作り直しが簡単！っていうイメージです。

## Quartusって何？
- 回路を製作するソフトウェアです
- Quartusで回路を作成　→　FPGAに流し込む（インストールする）　
FPGAはものによってはスイッチが付いているのですが、QuartusでFPGAの型番を指定することで、FPGAの物理的にここのスイッチを上（On）にしたら「１」（電気信号0/1の１です）を流すようにする。みたいなことも設定できます。

同時に、FPGAのLEDライトをQuartus内で指定してあげることで、回路の演算結果が1ならこのLEDライトを光らせる！みたいなこともできます。

## CPU作るって何？？？
- FPGAでCPUを作るってなんなんだ！？って感じですが，うちの大学でやっていたこととしては，
    - ALU（算術論理ユニット）を作る
    - 命令セットを用意して，命令デコーダを作る
    - レジスタとか，メモリアクセスの制御の仕方とかを頑張る
こんな感じです（もっと色々とやってたと思う）．

命令セットって何かというと，MOVとか，ADDとかそういう．
```
ADD R1 R2
```
見たいな命令を入れたときに，（実際にはADD　R1,R2を入れるのではなく，それを01に変換した機械語を入れていました）どういう挙動をするのかっていうのを回路に落とし込んでいきます．
クロックを入れたら，プログラムカウンタを+1するとか，メモリをReadモードにするとか，そういうこまごまとしたことをします．

そんな感じで（めちゃくちゃ大変な作業を乗り越えたら）なんか完成します…。

## FPGA，Quartusについて周りの人に聞いてみ（たかっ）た
FPGAやQuartusに対するヘイトとか，授業通じてここ面白かったな～みたいなこと，聞いてみました。
- すみません，卒論で忙しいのであまり聞いている余裕がありませんでした．
rollup.jsでpreserveModulesを有効にしつつファイル名や拡張子を変える

## この記事の概要

[rollup.js](https://rollupjs.org/guide/en/)を使っていて、アウトプット先を複数ファイルに分ける際にファイル名や拡張子を変更するのに手こずったので記事にしました。

## 背景

今回の悩みにぶつかった経緯は以下の流れです。

- `preserveModules`をtrueにしたい
- CJSとESMを両方含むパッケージを作りたい→拡張子を`cjs`と`mjs`の2つ用意したい
- `{具体的なモジュール名}.js`になっているファイル名を`index.js`に統一したい
    - ただし、最終的にこの内容は無くなった

## やること

- `rollup.config.js`の`output.entryFileNames`を追加する
    - デフォルトの`entryFileNames`は`[name].js`が定義されているので、オーバーライドする

```javascript:名前を変えたいときの例
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    entryFileNames: 'index.js', // デフォルトだと「{ファイル名}.js」と出力されるのが、すべて「index.js」になる
    preserveModules: true,
  }
};
```

```javascript:拡張子を変えたいときの例
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    entryFileNames: '[name].mjs', // デフォルトだと「{ファイル名}.js」と出力されるのが「{ファイル名}.mjs」になる
    preserveModules: true,
  }
};
```

## 感想など

単一ファイルを出力する際はどうとでもなりますが[^1]、複数ファイルでもうまく指定できるように用意されているのが助かりました。
とは言え、1つの`output`指定では1つのルールしか指定できないので、複雑なことをやろうと思ったら複数の`output`を作成する必要があります。

[^1]: `entryFileNames: 'super-awesome-file-name.js',`でもなんでも、具体的に指定できます

オプションでは`[name]`以外に`[format]`と`[hash]`も使えますが、あまり使い道が分かっていないです。
`assetFileNames`や`chunkFileNames`の使い方もピンときておらず、そのあたりが原因かもしれません（オプション内容がそれぞれ似ているけど違いがよくわかっていません）。
`[format]`で指定できる形式は`cjs`と`es`だけど、拡張子として使いたいのは`cjs`と`mjs`で、微妙に対応が取れておらず苦戦しました。

## 参考資料

https://rollupjs.org/guide/en/#outputentryfilenames

---

最後まで読んでくださってありがとうございます！
Twitterでも情報を発信しているので、良かったらフォローお願いします！

https://twitter.com/xrxoxcxox

Devトークでのお話してくださる方も募集中です！

https://jobs.qiita.com/employers/qiita-inc/dev_talks/489
いまさらAI学んでみた（第２回）

# はじめに
こんにちは、株式会社ジールの[@Suguru-Terouchi](https://qiita.com/Suguru-Terouchi)です。

[いまさらAI学んでみた（第１回）](https://qiita.com/Suguru-Terouchi/items/9fdd86bde61658d06e2d)の第２回目になります。
前回、AIとはという形で概念的なことを書かせて頂きましたが、
今回はAIの仕組みの部分にあたる機械学習に焦点を当てていきたいと思います。

# 機械学習ってなに？
前回、人間が↓の画像を見てネコであると判断できるという話をしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1963640/51ab5a42-2eef-d8b8-1d88-abfd63c2f9b7.png)

これを機械学習に照らし合わせて言うとINPUTされた画像データを分析した結果、ネコと判定されるということですね。
では「INPUTされた画像データを分析した結果」の部分でなにが行われているのでしょうか。

# 画像分析の仕組み
この仕組みを理解するために、この二人のAIさんに先ほどの画像をINPUTした場合、ネコと判定してくれるでしょうか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1963640/09ae8112-ee7c-9f91-0a58-03eec5b77ac6.png)

うーん、ベテランAIさんは余裕そうですが、生まれたてAIちゃんは厳しそうですね。（注：画像はあくまでイメージです）
では、どうすれば生まれたてAIちゃんがネコと判定できるようになりそうでしょうか？

いっそ答えを教えちゃいましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1963640/640cc8af-bb11-6658-33df-a6ca2fa93065.png)
あれ？ダメっぽいですね、なにがいけなかったと思いますか？
お父さんの教え方が悪い？それとも物覚えが悪い？もしくはちょっと調子悪かっただけ？

なぜ「ナルホド、よう分からん。」となってしまうんでしょうか？
それは「ネコ」と一言で言われても色や柄が違ったり、それこそ色んな向きやポーズをしているから
なんとなく、「こいつら似てるんやけどな。。。」となっていそうです。

この「似てる」というのが結構重要で、分からないなりに特徴を掴んで来ているから「似てる」となる訳です。

特徴といえば・・・
　色・・・今のところ同じ色のヤツいないな
　顔・・・三角の耳が上にあって、目と口、ヒゲもあるな
　体・・・大きさはみんな同じくらいで、足は4本、しっぽもあるな

でも、実際は耳が曲がっているやつとか、足やしっぽも短いのとかいますよね。
ということは「ネコ」と判断するための情報が少なかった可能性ありますね。

それならもっといろいろな「ネコ」を教えていけば良い訳ですね。
ついでに「イヌ」も教えていって、しばらくすると「ネコ」なのか「イヌ」なのかをほぼ間違えずに見分けられるように成長していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1963640/1d0faad5-2a1b-cec4-aa0c-b23dea3e3da9.png)

今回は答えを教えていったことで正確に画像を判別できるようになりましたが、
機械学習の仕組みとしては以下のようなことが行われています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1963640/495d50a9-78c7-0b5b-50cc-32317ce2cbdc.png)
「ネコ」と教えられたデータの特徴を探して、「ネコ」カテゴリに分類します。
これを繰り返し、行うことでいろいろな種類のネコにも対応できるようになっていきます。

機械学習ではこのモデルをより精度の高いものにしていくことがとても重要になります。

# まとめ
最後に少しだけここまでの流れを整理させてください。【】内は機械学習の用語です。
　１．データ（今回は画像）と「ネコ」という答え【目標値 or ラベル】をセットで教える
　２．１を繰り返し、データから規則性を探し出す【学習】【学習済みモデル】
　３．新しい【未知の】「ネコ」データをINPUTされた時に「ネコ」と答える【推論】

このようにデータと答えを用いて学習する方法を【教師あり学習】と言います。

# おわりに
いかがでしたでしょうか。
今回は分かりやすさを優先しているのでパラメータ等は触れていないので、
気になった方はご自身で調べてみてください。

次回は教師あり学習以外の学習方法について記載したいと思います。

# データ活用をサクッと始めるなら！
株式会社ジールでは、「ITリテラシーがない」「初期費用がかけられない」「親切・丁寧な支援がほしい」「ノーコード・ローコードがよい」「運用・保守の手間をかけられない」などのお客様の声を受けて、オールインワン型データ活用プラットフォーム「ZEUSCloud」を月額利用料にてご提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
 
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_zeuscloud_content-area
Ubuntu20.04でBluetoothをオンにできないときの対処法

M5StickCplusを使って遊んでいたら，
突如Bluetoothをオンにできなくなってしまった．
（なんか，ubuntu20.04ではBluetoothが接続できない問題が多発してるたしい）

そんなときの対処方法を記録しておきます．

##　方法

```sh:ターミナル
mv ~/.config/pulse/ ~/.config/pulse.old
systemctl --user restart pulseaudio
rm -rf ~/.config/pulse.old
sudo reboot
```

どうやらコンフィグファイル周りが原因らしいです．

## 参考
今回紹介した方法そのままです．
ありがたや．
[【まとめ】Ubuntu 20.04でBluetoothに接続できないときの対処法](https://takabot.com/howtofixbluetoothisnotworkingofubuntu/)
【Ruby on Rails】Factorybotでのインスタンス生成方法

### フォルダーの作成
「spec」フォルダー内に「factories」フォルダーを作成

### ファイルの作成
「factories」内に「モデル名（複数形）.rb」ファイルを作成。

例えば、
>「spec/factories/users.rb」

### ファイルに以下記載

以下、例
```ruby:spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name {Faker::Name.last_name}
    email {Faker::Internet.free_email}
    password {Faker::Internet.password(min_length: 6)}
    password_confirmation {password}
  end
end
```

### データ型の選び方
公式ページを参照
https://github.com/faker-ruby/faker

#techcamp136期
領域拡張による物体認識のPython実装

# 用途
領域拡張による物体認識のPython実装
領域拡張：指定したピクセルの周囲をみて、同じモノかどうかを判断して認識を広げる。同じような場所にいつも認識したいオブジェクトがある場合に有用。

# Code
- Python / 3.10.5
- Install packages/ openCVなど画像処理系

 ## Code：点と画像を与えて領域を求める
```py
def regionGrow(gray, seeds, thresh, p):
    seedMark = np.zeros(gray.shape)
    #Eight neighborhoods
    if p == 8:
        connection = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1)]
    elif p == 4:
        connection = [(-1, 0), (0, 1), (1, 0), (0, -1)]
    #The growth stops when there is no element in seeds
    while len(seeds) != 0:
        #Stack top element out of stack
        pt = seeds.pop(0)
        for i in range(p):
            tmpY = pt[0] + connection[i][0]
            tmpX = pt[1] + connection[i][1]

            #Detect boundary points
            if tmpY < 0 or tmpX < 0 or tmpY >= gray.shape[0] or tmpX >= gray.shape[1]:
                continue

            if abs(int(gray[tmpY, tmpX]) - int(gray[pt])) < thresh and seedMark[tmpY, tmpX] == 0:
                seedMark[tmpY, tmpX] = 255
                seeds.append((tmpY, tmpX))
    return seedMark
```

引数について
- gray: グレースケールの画像
    - openCV形式で挙動確認。Pillowで動かなければ[変換](https://qiita.com/derodero24/items/f22c22b22451609908ee)するとよさげ。
- seeds: 探索基準にしたいピクセル座標
    - [(横,縦)] のようなタプルで入ったリスト形式
        - 複数あるなら、[(a1,b1), (a2,b2)] 
- thresh: 閾値
    - 2とか一桁の数字からパラメータ探索
- p: どの方向のピクセルを見るか
    - 4なら上下左右、8なら斜めも加えた8方向

出力は、
入れた画像と同じ大きさのバイナリー画像

## subCode:
### 自分のseedが会っているか確認用
```py
def seeds_check(img,seeds,size=5):
    _img = img.copy()
    for seed in seeds:
        y,x = seed
        _img[y-size:y+size,x-size:x+size] = 255
    plt.imshow(_img); plt.title("check seed"); plt.show()
```

自分の指定したseedsの位置を画像で確認する用
見にくければよしなにsizeを変える

# その他
- ざっくり解説
    1. seedsの座標の一つを取り出し、周囲ピクセルとの輝度値の差をみる
    1. その差が閾値以下であれば、その座標をマスク領域にしつつ、seedsに追加
    1. この操作をseedsの中身がなくなるまで繰り返す
- コツ
    - pは8に固定して、threshを色々試して行くといい
    - 前処理で平坦化しすぎるとエッジがなくなるので、[バイラテラルフィルタ](https://imagingsolution.net/imaging/bilateralfilter/)とかがよさげ
    - 認識箇所が複数だったり、ムラがある画像の場合はseedに複数点を入れておくとよさげ
Outlookマクロで送信アドレスチェック



```vb
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)

Dim s As String
s = Item.SenderEmailAddress '差出人

If s <> "xxx@xxx" Then
    MsgBox ("xxx@xxxで送信してください。")
    Cancel = True
End If

End Sub
```

「ByVal Item As Object」　は多分　MailItem
goでパッケージ更新

## 概要
goで更新可能なパッケージを調べて、個別に更新する方法。

## 依存パッケージの確認
### 依存パッケージを全て出力

```bash
go list -f '{{join .Deps "\n"}}'
```

### 標準パッケージ以外の依存パッケージを出力

```bash
go list -f '{{join .Deps "\n"}}' | xargs go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}'
```

## 更新可能なパッケージの確認
### 全パッケージ
indirect(間接利用)のものも出力される。

```bash
go list -m -u -mod=readonly all
```

### indirectでないパッケージのみ
直接利用しているパッケージのみ出力。
出力結果の先頭にgo getを付けて出力することで、出力結果を使いやすくする。

```bash
go list -m -u -mod=readonly -f '{{if (and .Update (not .Indirect))}}go get {{.Path}}@{{.Update.Version}}{{end}}' all
```

以下のように、最新のバージョンが出力されるので、go getを実行し更新する。

```bash
go get github.com/aws/aws-sdk-go@v1.44.136
go get github.com/labstack/echo/v4@v4.9.1
go get gorm.io/gorm@v1.24.1
...
```

## indirect(間接利用)のパッケージのみを更新する
NodeJSのpackage.jsonでいうresolutions。

直接利用のpackageがindirectで利用しているpackageに脆弱性が出ているが、その直接利用のpackageに対策versionが出ていない場合、indirectのpackageのみを直接versionを上げることで対策する。

```
go get {indirect package名@version}
go mod tidy
```

## Refs
- [go listで依存パッケージを一覧する。-tagsで依存パッケージを切り替える #go](https://budougumi0617.github.io/2018/09/21/package-dependencies-with-go-list-and-build-tags/)
- [Goのモジュールを個別に更新する](https://daisuzu.hatenablog.com/entry/2021/11/15/142702)
【品質管理】ソフトウェアの品質を担保！コードにおける7つの大切なチェック観点

# 7つの設計原理
7つの設計原理について本記事では記載する。
尚、解説時には、以下の3つの形式に分けて解説する。

* what??
* why??
* how??

# 7つの設計原理とは？？
## what??
障害を作り込まないために考慮すべき、コードの構造上の7つの核心観点のこと。
①単純原理
②同型原理
③対象原理
④階層原理
⑤明証原理
⑥安全原理
⑦線形原理

## why??
7つのチェック観点によって、コードレビューに一貫性を持たせて、ソフトウェアの品質を担保するため。

## how??
* コードレビュー時に共通の観点として持っておく。
* コードを作り込むときにも考慮。

# ①単純原理

## what??
* シンプルにこだわるという原理。
* 局所的な完全性を重視。


## why??
シンプルで見通しの良いコードを書くことで、障害を発生させないため。

## how??
* コードを単純で小さいままで保つ。
* 高級なコードを書きたいという誘惑に負けない。


# ②同型原理
## what??
同じことは同じように扱うことにこだわるという原理。

## why??
* 違うものを際立たせることで、障害を発見しやすくするため。
* コードの可読性を上げるため。

## how??
独創的なコードを書きたいというエゴに耐え、コードに一貫性を持たせる。

# ③対称原理
## what??
あるものの「対」になるものを用意するという原理。

## why??
* 可読性の向上。
* 条件漏れの防止。

## how??
* 「条件」があれば「反条件」にもこだわる。
* 例外的な状況を考慮しつつ、極力それを排除する。
* 対称性を持った命名を行う。

# ④階層原理
## what??
構造を階層関係にすることを常に意識し、整理された関係性を維持するという原理。

## why??
* コードの可読性向上のため。
* バグの発生の減少のため。

## how??
* コードの各々について、抽象レベルを意識して、階層構造を構築する。
* 1つの階層は同じ抽象レベルのものだけで構成する。

# ⑤線形原理
## what??
処理の流れは直線的であることにこだわるという原理。

## why??
* 可読性の向上。
* 改善のしやすさの向上。

## how??
* 特殊な処理の振る舞いを、主処理に混ぜて書かないようにすることで、処理の分岐を少なくする。
* 保守時に複雑化しすぎたものは、再構築も考慮する。

# ⑥明証原理
## what??
一見して明らかに正しいコードを書くという原理。

## why??
可読性向上のため。

## how??
* 明らかに誰でも理解できるようなコードを書く。
* 既存のコードを再利用する際は、動作仕様、文脈をきちんと確認してから流用を心がける。

# ⑦安全原理
## what??
ありえないという条件をあえて考慮して、コードを書くという原理。

## why??
サービスの継続、データ破壊の防止のため。

## how??
必要性が曖昧なところ、必要のないところに関しても、あえて条件を考慮してコードを書く。
ただし、人によってブレがあってはいけないので、ある程度規約として定めておく。