OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScript ~コレクション編~

<h2>・コレクションとは</h2>
 <b>コレクション</b>とは、値をまとめて管理するオブジェクトのことである。コレクションには、<b>Object、Array、Map、WeakMap、WeakSet</b>の５種類ある。

<h2>・Array（配列）</h2>
 <h3>・Arrayの初期化</h3>

　　`const 配列名 = [値1, 値2, ...];`　又は `const 配列名 = new Array (配列の長さ or 値1, 値2, ...);`

 <h3>・配列のメソッド</h3>

　　`配列名.push("Zoom", "Discord"...);`　配列の一番後ろに要素を追加する。

　　`配列名.unshift("Java", "JavaScript"...);` 配列の先頭に要素を追加する。

　　`let shiftVal = 配列名.shift();`  配列の先頭の要素を削除する。 shiftValに削除された値が代入される。

　　`let popVal = 配列名.pop();`　配列の一番後ろの要素を削除する。 popValに削除された値が代入される。

　　`let spliceVal = 配列名.splice(切り取り開始位置, 切り取り終了位置);` spliceValに切り取られた値がArrayとして代入

　　`let concatVal = 配列名.concat();`　配列のコピーができる。
　　　　　　　　　　　　　　　　　　　　　別の配列と合わせた新しい配列を作ることもできる。

```JavaScript:concat
    const characters = ["Makima", "Aki", "Denji"];
    const newCharacters = characters.concat( ["Power", "Yoshida"] );
    console.log( newCharacters );
    -> ["Makima", "Aki", "Denji", "Power", "Yoshida"]

    console.log( characters );
    -> ["Makima", "Aki", "Denji"] 元の配列に影響はない
```

　　`let index = 配列名.indexOf( 確認したい値 );`　最初に見つけた単語の場所を返す。

```JavaScript:indexOf
    const charas = ["Kaneki", "Yomo", "Arima"];
    console.log ( charas.indexOf("Yomo") );
    -> 1 (charasの1番目にある)

    console.log ( charas.indexOf("Ayato") );
    -> -1 見つからなかった場合は-1が返される。
```

　　`let 真偽値 = 配列名.includes( 確認したい値 )`　確認したい値が存在するかどうかtrue falseで返す。

　　`let joinVal = 配列名.join ( [値1, 値2, ...] )` 値を結合して１つの文字列にするメソッド

```JavaScript:JOIN
    const bookList = ["この本", "すごい"]
    let joinVal = bookList.join("は");
    console.log(joinVal);
    -> この本はすごい
```

　　`配列.fill( 入れたい値(, 開始位置, 終了位置) );` コレクションに入れたい値を任意の数入れることができる。指定しなければ、空いてる場所に入る。

```JavaScript:fill
    const arrayList = new Array (5); //10個のリストを作る。
    arrayList.fill("空っぽ"); //空っぽを入れる
    console.log(arrayList);
    -> ["空っぽ", "空っぽ", "空っぽ", "空っぽ", "空っぽ"]
```

　　`let flatedArray = array.flat( 平坦のレベル )` 配列の中に配列がある時に、その配列を中に入れる。

```JavaScript:flat
    const array3D = [
    "あ", ["い", "う"], ["え", ["お", "か", "き"], ["く"]
];

    const array2D = array3D.flat(); //指定しなければ配列が1つだけのを中に入れる
    console.log( array2D );
    -> ["あ", "い", "う", ["え", ["お", "か", "き"]], "く"]

    console array1D = array3D.flat(2); //2つ以下配列を中に入れる。
    console.log( array1D );
    -> [あ, い, う, え, お, か, き, く]
```

　　`配列名.reverse();`　配列の並びを反対にする。

```JavaScript:reverse
    let array = ["Time", "Apple", "Shirt", "Book"];
    array.reverse();
    console.log( array );
    -> ["Book", "Shirt", "Apple", "Time"]
```
Python で先週日曜日の日付を取得する

# はじめに
Python で先週の日曜日を取得したかったのですが、調べてもあまり良い解答が得られなかったので、忘備録として残します。
# 1. isoweekday
datetime モジュールにある date オブジェクトの isoweekday メソッド。
isoweekday は月曜日から日曜日を `1 ~ 7` として出力します。
```Python
from datetime import date, timedelta

today = date.today()
last_week_sunday = today - timedelta(7 + today.isoweekday() % 7)
```
`today.isoweekday() % 7` 部分で日曜日から土曜日を `0 ~ 6` として出力するよう変換し、先週の日曜日は今日から 7 日と何日前か計算しています。
# 2. weekday
datetime モジュールにある date オブジェクトの weekday メソッド。
weekday は月曜日から日曜日を `0 ~ 6` として出力します。
```Python
from datetime import date, timedelta

today = date.today()
last_week_sunday = today - timedelta(7 + (today.weekday() + 1) % 7)
```
`today.weekday()` に 1 を足すことで isoweekday と同じ処理を行っています。
# 3. strftime("%u")
datetime モジュールにある datetimeオブジェクト・ date オブジェクトの strftime メソッド。
strftime は日時情報を任意のフォーマットで文字列に変換できます。
フォーマット文字列に `%u` を指定すると月曜日から日曜日を `'1' ~ '7'` として出力します。
```Python
from datetime import date, timedelta

today = date.today()
last_week_sunday = today - timedelta(7 + int(today.strftime("%u")) % 7)
```
strftime では出力が文字列であるため、`int` で整数に変換した後、isoweekday と同じ処理を行っています。
# おわりに
結論としては、isoweekday を使う方法が一番簡潔に先週の日曜日を取得できるのではないかと思います。
もっと良い方法がありましたら、コメントよろしくお願いいたします。
実務未経験でHTML5プロフェッショナル認定試験 レベル2に一発合格した

HTML5プロフェッショナル認定試験 レベル2に合格したので
これまでの学習スタイルであったり、学習方法などまとめて
同じ資格試験の合格を目指している方や、
これから取得に向けて勉強を始める方の
参考になる記事になればよいなと思います。

<h2>HTML5プロフェッショナル認定試験とは</h2>
特定非営利活動法人エルピーアイジャパンが主催する民間資格です。<br>
HTML5プロフェッショナル認定試験にはレベル1とレベル2が存在し、<br>
それぞれ出題範囲が異なりますが、レベル１の説明については割愛します。

<h3>レベル２の出題範囲</h3>
2.1 JavaScript<br>
2.1.2 ES6（ECMAScript2015）以降の新機能(Ver2.5)<br>
2.2 WebブラウザにおけるJavaScript API<br>
2.3 グラフィックス・アニメーション<br>
2.4 マルチメディア<br>
2.5 ストレージ<br>
2.6 通信<br>
2.7 デバイスアクセス<br>
2.8 パフォーマンスとオフライン<br>
2.9 セキュリティモデル<br>

9つのセクションに分かれ、さらにVer2.5から
ES6以降の機能(let,const, アロー関数、Promise etc...)も範囲となります。

ここで思うのが、<strong>「これってJavaScriptの試験じゃん...」</strong>

はい、そうです。

出題される問題全てJavaScriptからなんです。

公式ページに記載された内容を見ると
試験正式名（和名）：HTML5プロフェッショナル認定試験 レベル2
ですが下に略称の記載があり、そこをみると
試験名の略称（和名）：HTML5(JavaScript) レベル2試験
堂々と(JavaScript)と書いてあります。

ここで注意したいのが、
<strong>「JavaScriptを勉強だけすればよい」</strong>
と思わないことです。

HTMLを理解していることが大前提としてあるため
ある程度抑えておく必要があります。
なのでHTMLの内容に不安がある方はまずレベル１の取得を目指しましょう
(ちなみに私は2022年8月頃にレベル１を取得しました。)




前置きはこのくらいにして本題である学習内容に移りたいと思います。

<h2>学習内容</h2>
<strong>学習期間</strong><br>
2022/11月中頃~2023/1月の約2か月間<br>
(試験日は2023/1/21日)

<p><p/>


<strong>１日の勉強時間(１日あたり３時間程度)</strong>
出勤前6:30~7:30目安 　約1時間
出勤途中(電車) 　　　　約30分
仕事終わり(電車) 　　　約30分
帰宅後21:00~22:00目安 約１時間
※土日は気が向いたり用事がない場合に限りやる程度です。

私のポリシーとして無理に根詰めをしないようにしています。
自分を操作し継続させる事が資格試験に合格するために
最も重要だと思うのでメリハリをつけるようにしました。


<strong>学習教材</strong>
・認定試験レベル2 対策テキスト&問題集
・レベル2 スピードマスター問題集<strong>(最重要)</strong>
・ポラリステーション(Webサービス) <strong>Ver2.5対応!!</strong>
の３点を利用して学習しました。

現在Ver2.5の試験のみ受験可能ですが、Ver2.0から切替え2か月くらい？(2023/1現在)
なので対策テキストがVer2.5に対応しているものがかぎりなく少ないため
Ver2.0のもので学習しましたが、さほど影響はありませんでした。
ES6以降はJSPrimerなどを利用して抑えておく程度でよいでしょう。

この中でおすすめしたいのが
<strong>HTML教科書 HTML5プロフェッショナル認定試験 レベル2 スピードマスター問題集 Ver2.0対応</strong>
になります。正直この１冊を網羅できれば合格できると思います。
じゃあなぜ３点利用したのかというと
①認定試験レベル2 対策テキスト&問題集については問題集を購入する前にすでに購入していたためです。
　これに関してはほぼ使いませんでした。このくらいの情報はWEB検索で十分です。
②ポラリステーション(Webサービス)については、移動中も学習をしていると上でお話しましたが
　その際、問題集を電車に忘れてしまいなくしてしまったため利用しました。
　新しい問題に触れるという点では違う視点から学べたことがあったので、不安がある方は利用をおすすめします。
　ただサービスの質については発展途上といった感じです。

あとは公式ページにあるサンプル問題を活用することです。
サンプル問題についてはいろんな方が申すように難易度が高めです。
ただし、難易度が高いということはその問題について正しく理解できているかどうかの指標にもなる為
ある程度学習が進んだあたりで、どうしても何をしてらよいか、何がわからないのかわからない問題に直面する
機会があると思います。(答えを覚えてしまって問題を解くことが作業になってしまった時など)
その時にサンプル問題を活用して、理解が乏しい部分の洗いだしを行い、より深く学習することをしていました。

学習内容については以上です。
次に試験の出題傾向について解説します。

<h2>出題傾向</h2>

出題傾向について、試験を受けた印象を述べると
「全てのカテゴリーから網羅的に出題」という印象でした。

しかしこれだと全然参考にならないってなってしまうので
アドバイスをするのであれば
2.1 JavaScript
2.2 WebブラウザにおけるJavaScript API
このカテゴリーは100点をとれるくらい学習する必要があります。

JavaScriptの知識が前提として
WebStrageであったりXMLHttpRequestなどが出題されるので
前提知識である2.1、2.2は間違いなく抑える必要があります！!

あとはイベントの理解は必須、このイベントはこういう条件で発火するまで覚えておくとよいでしょう。
・クリックイベント
・キーボードイベント
・マウスイベント
・ウィンドウイベント

その他は
DOM API, History API, ストレージからの出題が印象に残ってますが...
何度も言いますが、最終的には全体を網羅しておく必要があります。


<h2>総括</h2>
HTML5プロフェッショナル認定試験 レベル2を学習するとJSに強くなった気になれるということ！！<br>
以上
Json Server役立ちサイトメモ

https://swfz.hatenablog.com/entry/2016/12/06/024342

https://wing-degital.hatenablog.com/entry/2019/05/08/234119

https://www.cyokodog.net/blog/use-well-json-server/

https://deep.tacoskingdom.com/blog/151

https://gist.github.com/juanbrujo/efdcf6ab9eacbd5b5d69884233d0a3ce

https://silurus.dev/articles/4GtXZIAR3mqEduLkgoM1Z2
MAMPについての概要＆インストール方法（Mac）

# 背景
PHPを使った開発をするため、macでの環境構築が楽そうな**MAMP**を使ってみた。
今回は**MAMP**の概要とセットアップの方法について記す。
# MAMPとは
Macintosh、Apache、MySQL、PHPの各頭文字を取った略称。
Web開発に必要な上記のソフトウェアを一括でインストールし、ローカルにサーバー環境を構築することができるソフトウェアである。
# インストール方法
## ①MAMPをダウンロード
[MAMP公式サイト](https://www.mamp.info/en/mac/)から「Free Download」をクリック。
![image01.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453680/a2d9a7b8-fb62-0a55-d5bc-c584d3d03f48.jpeg)
Macに搭載されているCPUによってダウンロードするパッケージが異なる。
- Intelの場合：MAMP & MAMP PRO（Intel）
- M1/M2チップの場合：MAMP & MAMP PRO（Apple）
![image02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453680/3e81cb10-434a-b296-7f65-93d5679da7c6.png)
## ②MAMPをインストール
先ほどダウンロードしたパッケージを開き、それぞれ内容を確認した上で「続ける」をクリック。
![image03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453680/d6e9a371-7925-e40a-e4d1-c31f7e296f6c.png)
![image04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453680/7eb92002-38ff-2f97-af14-1db2bc35e7da.png)
![image05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453680/713d08f1-1852-2f99-7a84-4cf80b1eb544.png)
以下の画面で「インストール」をクリックすると、インストールが始まる。
![image06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453680/e2a2a786-db0e-f3c4-ed3f-647a1f3c0995.png)
インストール完了後、「閉じる」をクリック。
![image07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453680/acf70862-f634-61d4-527b-33ca8a18fe7e.png)
## ③MAMPを起動
LaunchpadやSpotlightからMAMPを検索すると出てくる。
起動すると、下記のような画面が表示される。
![image08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453680/68b0a23f-b364-d524-503e-57aef3c4f9d5.png)
右上のスタートボタンを押すと、起動する。
起動後にスタートボタンがストップボタンに切り替わるので、停止する際はそこをクリックする。
ちなみに左上のPrefencesは設定ボタンである。
※Apache, Nginx, MySQLのポート番号の変更やドキュメントルートの位置が変更できるようです。
GASで範囲内のセルの値が空白か判定する方法

以下のように`values[i][0] === ''`で判定する

```js
const SHEET_URL = "sheet_url";
  const SHEET_NAME = "sheet_name";
  var spreadSheet = SpreadsheetApp.openByUrl(SHEET_URL);
  var sheet = spreadSheet.getSheetByName(SHEET_NAME);
  var values = sheet.getRange("A1:A").getValues();

for (let i in values) {
    // 空白なら次に進む
    if (values[i][0] === '') { continue }
}
```

細かくは覚えてないが以下のような書き方では判定できなかった

`let in of values`
`values.classname`
`values[i] === []`
`values[i][0] === null`
`Object.keys(values[i]).length === 0`
Array Shapes/ジェネリクス記法とPHPStanを使って配列要素の型をチェックする

## PHPの配列要素の型がチェックできない問題
この、PHPの配列要素の型をチェックできない問題ですが、みなさん一度は思われたことがあるのではないでしょうか？関数やメソッドの引数や返り値、オブジェクトのプロパティにについては型はつけやすくなりましたが、配列の内部構造はまだまだです

例えば関数の戻り値に`array`を指定している場合、配列以外の型を持った値を返そうとするとエラーになりますが、配列の要素に関しては何が入ってこようとエラーは出ません。そのため、思わぬバグに繋がってしまうことがあるのです

そこで本記事ではその解決策となるテクニックをご紹介していきます

## 結論：Array Shapes/旧PSR-5形式のジェネリクス記法で記載し、PHPStanを使用して解析する
早速結論ですが、**PHPDocのArray Shapes記法とPHPStanを組み合わせて配列要素の型をチェック**します

ざっくりと言うと、Array Shapes/旧PSR-5形式のジェネリクス記法でDocコメントを記載し実装を進め、その後に静的解析（PHPstan）を実行することで、型チェックをするイメージです

## ケーススタディ

ややこしい話をするより実際にコードをいくつか見ていきます

### 旧PSR-5形式のジェネリクス記法
まずはジェネリクス記法から。下記コードのように`array<int, User>`とすることで、キーと値の型を指定します
```php
/**
 * @return array<int, User>
 */
function getUsers(): array
{
    return $this->users;
}
```
また、キーの指定が必要ない場合は
```php
/**
 * @return array<User>
 */
function getUsers(): array
{
    return $this->users;
}
```
のように記載します。

### Array Shapes記法
続いてArray Shapes記法についてです。記法が複数出てきて混乱するかもしれないですが、どちらを使っても、併用しても問題ありあせん（基本的には併用することになるかと思います）

また、仕様については下記サイトに記載してあります

- [Array types - Psalm Documentation](https://psalm.dev/docs/annotating_code/type_syntax/array_types/#object-like-arrays)

早速例題ですが、連想配列は以下のように型をつけることができます。`id`と`name`、`isJapanese`がキー名になっていて、その隣に型を記載します
```php
/**
* @return array{id: UserId, name: string, isJapanese: bool}
*/
public function getArray(): array
{
    return [
        'id'         => new UserId(1),
        'name'       => '山田花子',
        'isJapanese' => true
    ];
}
```
nullを許容する際は、`address: ?string`のように、値の先頭に`?`をつけます
```php
/**
* @return array{id: UserId, name: string, isJapanese: bool, address: ?string}
*/
public function getArray(): array
{
    return [
        'id'         => new UserId(1),
        'name'       => '山田花子',
        'isJapanese' => true,
        'address'    => null
    ];
}
```
上記の例では`address`の値はnullが入りえますが、addressを省略することはできません。キーが省略される可能性がある場合は、`address?: string`のように、キー名の最後に`?`をつけます
```php
/**
* @return array{id: UserId, name: string, isJapanese: bool, address?: string}
*/
public function getArray(): array
{
    return [
        'id'         => new UserId(1),
        'name'       => '山田花子',
        'isJapanese' => true
    ];
}
```
nullを許容とキーを省略を併用したい場合は、`address?: ?string`と記載してください

## PHPStanを実行する
ここまでで準備は整いました。あとはPHPStanを実行することで、タインプヒントのエラーを発見することができます

また、PHPStanのlevelについてですが、

> 6.report missing typehints.

下記サイトにも記載してある通り、Level6からタイプヒントのエラーをレポートするようになるので、PHPStanのlevelは6に設定するようにしましょう
- [Rule levels](https://phpstan.org/user-guide/rule-levels)

## おわりに
以上で、配列要素の型チェックができるようになります

プラスアルファとしては、PHPStanをCI(継続的インテグレーション)に組み込み、自動的にこのチェックが行われるようにしましょう。機会があればまた記事にしたいと思います

何かご指摘やご意見があればコメントお願いします！
[Next.js]error - TypeError: __webpack_require__.C is not a function

環境
Next.js v.13

# 解決法
babelの設定ファイルを追加する。
`"sorceType": "unambiguous"`の部分が重要
```json:.babelrc
{
  "presets": ["next/babel"],
  "plugins": [],
  "sourceType": "unambiguous"
}
```


# 問題
原因はよくわからんけど、ServerComponent由来？
ゼロconfigが故に設定周りのバグが起きてもよくわからん。
今回はトランスパイル時にimport<=>require間で間違って変換されたのかと思われる。。

babelは基本soruceTypeを"module"として設定しているのでESModuleとして判断する、一方"unambiguous"はimport/exportがある場合は"module"それ以外はCommonJS使用でrequireするのかと。ESModuleに寄せたんじゃなかったっけ？よくわからん。

詳しくは公式

https://babeljs.io/docs/en/options#sourcetype


# 参考
issue

https://github.com/webpack/webpack/issues/9379

Next.jsでbabelを設定する方法

https://nextjs-ja-translation-docs.vercel.app/docs/advanced-features/customizing-babel-config
Next.jsのAPI Routesを使ってSendGridでメール配信を行う(クライアントサイド)

# 進め方

- あらかじめ　`/api/hoge` のサーバーサイドのハンドリングを書いておく ([こちら](https://qiita.com/Wangchangdog/items/bd1e090f171eb2f32565))
- 自前のNext.jsサーバーの任意のエンドポイント`/api/hoge`を叩く
- `req`は任意のJSONとする

# 実装

```ts:clientsideHandling.ts
import axios from 'axios';

import { PostRequest } from 'api/v1/send/post.type';

export const sendEmail = async (req: PostRequest) => {
  axios({
    method: 'POST',
    url: '/api/hoge',
    data: req,
    headers: {
      'Content-Type': 'application/json',
    },
  })
    .then(() => {
      console.log('email success');
    })
    .catch((err) => {
      console.log('error at axios');
      console.err(err);
    });
};

```

# 結論

- [こちら](https://qiita.com/Wangchangdog/items/bd1e090f171eb2f32565)を用意しておけば、普通にaxiosで叩くだけでいける
15.フォーム応用

```index.html
<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="utf8">
  <meta name="description" content="初めてHTMLを勉強するサイトです。">
  <title>プログラミングの勉強</title>
</head>

<body>
  <header>
    <h1>プログラミングを勉強しよう！</h1>
    <nav>
      <ul>
        <li>ホーム</li>
        <li>このサイトについて</li>
        <li>プロフィール</li>
      </ul>
    </nav>
  </header>

  <main>
    <article>
      <h2>様々なフォーム</h2>
      <form action="form.php" method="post">
        <p>
          お名前:
          <input type="text" name="name" size="60" placeholder="T下純">
        </p>
        <p>
          Eメール:
          <input type="email" placeholder="shimonojun@daijin.com">
        </p>
        <p>
          パスワード:
          <input type="password">
        </p>
        <p>
          住所:
            <select name="example">
            <option value="1">北海道</option>
            <option value="2">青森県</option>
            <option value="3">岩手県</option>
            </select>
        </p>
        <p>
          お電話:
            <input type="tel" maxlength="11" required>
        </p>
        <p>
          誕生日:
          <input type="date" id="start" name="trip-start" value="2012-08-01" min="2010-01-01" max="2018-12-31">
        </p>
        <p>
          希望時刻:
          <input type="time">
        </p>

        <p>
          <b>ご利用頻度</b>
          <input type="checkbox">初めて
          <input type="checkbox">週1回程度
          <input type="checkbox">月1回程度
        </p>
        <p>
          <b>性別:</b>
          <input type="radio">男性
          <input type="radio">女性
          <input type="radio">回答しない
        </p>

        <p>
          <b>お問い合わせ内容:</b>
          <br>
          <textarea name="" id="" cols="100" rows="5" placeholder="ご意見・ご感想をお聞かせください"></textarea>
          </p>

          <p>
            添付ファイル:
            <input type="file">
          </p>
          <p>
            <input type="button" value="ボタン">
          </p>
          <p>
            <input type="submit" value="送信ボタン">
          </p>
      </form>
    </article>
  </main>
</body>
</html>
```
Next.js API Routes をうまく使ってSendGridからメール配信

# 前提

- SendGridは登録しておく(およそ1日くらいはかかるので前もってやっておく)
- あらかじめAPIキーを取得しておく


```ts:sendgrid.ts
import sgMail from '@sendgrid/mail';
import type { NextApiRequest, NextApiResponse } from 'next';

import type { PostContactRequest } from 'api/v1/contact/postContact.type';

import { adminNotificationMessage } from 'email/adminNotificationMessage';
import { userNotificationMessage } from 'email/userNotificationMessage';

/**
 * @remarks 同じ名前のジェネリクスを定義
 * @generic T - 任意のリクエスト型
 */
export type NextAPIRequest<T> = Omit<NextApiRequest, 'body'> & {
  body: T;
};

/**
 *
 * @param req NextApiRequest<リクエスト型>
 * @param res NextApiResponse<レスポンス型>
 */
const handler = (
  req: NextAPIRequest<PostContactRequest>,
  res: NextApiResponse<{
    message: string;
  }>,
) => {
  if (req.method === 'POST') {
    if (typeof process?.env?.SENDGRID_API_KEY === 'undefined') {
      res.status(500).json({ message: 'SENDGRID_API_KEY is undefined' });
      return;
    }
    sgMail.setApiKey(process?.env?.SENDGRID_API_KEY ?? '');
    const notificationMsgForUser = userNotificationMessage(req);
    const notificationMsgForAdmin = adminNotificationMessage(req);
    (async () => {
      try {
        await sgMail.send(notificationMsgForAdmin);
        await sgMail.send(notificationMsgForUser);
      } catch (
        error: any // エラー型は知らなくてもいいのでanyでOK
      ) {
        console.log('error has occurred in sendgrid');
        console.error(error);
        if (error.response) {
          console.error(error.response.body);
          res.status(500).json(error.response.body);
        }
      }
    })();
    res.status(200).json({
      message: 'success',
    });
  }
};

export default handler;
```

# 　結論

- 一日あたり15000通までなら無料で送信できる
Json Serverでモックを作る

未実装APIへの通信をテストしたい事がある。
そんな時はJson Serverで未実装APIのモックを作ると吉。
- - -
まず大前提としてnode.jsをインストールする（json serverはnpmのパッケージなので）

:::note info
npmでjson serverをインストールする時にpermission deniedエラーになる事がある。
以下サイトによると、npm公式ではnvm等のnodeバージョンマネージャでnodeを入れて欲しいとの事。
https://zenn.dev/ikeo/articles/8d0c88dcedf256b09f73
少し遠回りになるがnodeバージョンマネージャーを入れてあげると良さそう（著者はnvmを入れた）
:::
:::note info
また、著者はMacで、zshでnpmインストールを行なったが、homeに.zshrcファイルが無かったので、調べた所、以下サイトによりhomeで以下コマンドであらかじめ作っておくモノという事で解決。
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13256730643
```
touch .zshrc
```
homeで上記コマンドで作っておいてnpmインストール。
:::

https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally

https://docs.npmjs.com/downloading-and-installing-node-js-and-npm

https://kazuhira-r.hatenablog.com/entry/2021/03/22/223042

https://qiita.com/takashi0530/items/c18247e26a35662c0eda

node.jsがインストールされたら（npmもnode.jsと一緒にインストールされる）、json serverをインストールします。
（インストール方法は下記の通り、検索したら山ほど出てきますー）

:::note info
ちなみに参考サイトでは以下コマンドでjson serverを起動するとどこでも紹介されているが、著者の環境ではエラーになった。
```
json-server –-watch db.json

  \{^_^}/ hi!

  Loading –-watch
Error: Unsupported source –-watch
    at /Users/xxx/.nvm/versions/node/v18.13.0/lib/node_modules/json-server/lib/cli/utils/load.js:79:13
    at new Promise (<anonymous>)
    at module.exports (/Users/xxx/.nvm/versions/node/v18.13.0/lib/node_modules/json-server/lib/cli/utils/load.js:38:10)
    at start (/Users/xxx/.nvm/versions/node/v18.13.0/lib/node_modules/json-server/lib/cli/run.js:112:12)
    at module.exports (/Users/xxx/.nvm/versions/node/v18.13.0/lib/node_modules/json-server/lib/cli/run.js:149:3)
    at module.exports (/Users/xxx/.nvm/versions/node/v18.13.0/lib/node_modules/json-server/lib/cli/index.js:80:3)
    at Object.<anonymous> (/Users/kawashimakenichi/.nvm/versions/node/v18.13.0/lib/node_modules/json-server/lib/cli/bin.js:6:14)
    at Module._compile (node:internal/modules/cjs/loader:1218:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1272:10)
    at Module.load (node:internal/modules/cjs/loader:1081:32)
```
以下コマンドで起動した。
```
json-server db.json
```
同じエラーになる人は参考にしてください。
:::

### 参考サイト
https://blog.codecamp.jp/json-server-beginner

https://www.xlsoft.com/jp/blog/blog/2019/08/20/post-7139/

https://qiita.com/morinco/items/e2c16f55413be433a34b

https://note.com/s01r0/n/n1f6fbe5eadb2

https://kuroeveryday.blogspot.com/2017/06/test-driven-develop-with-json-server.html

https://www.ossnews.jp/oss_info/JSON_Server

https://rightcode.co.jp/blog/information-technology/json-server-rest-api-mock-server-syain
再帰によるpaint関数

指定されたバックグラウンド色の部分を、指定された色で塗りつぶすpaint関数です。
グラフィックスにはpygameを使っています。
このプログラムでは、塗りつぶし領域が広いと、すぐRecursionErrorが起きてしまうので、改良が必要です。

```paint.py
#!/usr/bin/python3
from pygame.locals import *
import pygame
import sys
import os
import random
sys.setrecursionlimit(20000)
xsize=400
ysize=400
pygame.init()    # Pygameを初期化
screen = pygame.display.set_mode((xsize,ysize))    # 200x200の画面を作成
pygame.display.set_caption("paint" )    # タイトルを作成

# ペイント関数
def paint(p,bc,pc):
    if screen.get_at(p)[:3]==bc:
        screen.set_at(p,pc)
        if p[0]+1 < xsize: 
           paint((p[0]+1,p[1]),bc,pc)
        if p[0]-1 >=0: 
           paint((p[0]-1,p[1]),bc,pc)
        if p[1]+1 < ysize: 
           paint((p[0],p[1]+1),bc,pc)
        if p[1]-1 >=0: 
           paint((p[0],p[1]-1),bc,pc)

def waitkey():
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit(0)
            if event.type == KEYDOWN:  # キーを押したとき
                k=pygame.key.name(event.key)
                return(k)

def main():
    screen.fill((0,0,0)) # clear screen

    for x in range(120):
      screen.fill((255,255,255),(random.randrange(0,400),random.randrange(0,400),50,50))
    bc=screen.get_at((3,4))[:3] #(3,4)における背景色を取得
    paint((3,4),bc,(0,255,0)) #(3,4)から、背景色bc,緑(0,255,0)でペイント
    pygame.display.update()
    key=waitkey()
    pygame.quit()
    sys.exit()

if __name__=='__main__':
    main()

```
Stripe Connectの連携アカウントのSubscriptionの更新方法（Ruby）

連携したアカウントのサブスクリプションの内容を変更する方法が分からずに少し苦労したので、変更方法についてメモを残します。

```code .rb
Stripe::Subscription.update(
    "subscription_id", # sub_××××××××××××
    {
        # 変更したい内容を記述
        application_fee_percent: "20", # サブスクリプションの手数料を20%に変更
    },
    { stripe_account: '連携アカウントのID' }  # acct_××××××××××××
)
```
MMDで既存のモデルとモーションを組み合わせる

# これは何？

MikuMikuDance（以下、MMD）と公開されているモデルやモーションをダウンロードしたのはいいけど、
拡張子がpmxのモデルファイルをMMDで開けないとか、
MMDに同梱されている拡張子がpmdのモデルファイルすら開けないとか、
カメラ位置を変更しても再生するたびにカメラ位置がリセットされてしまうとか、
そんな悩める私のための記事です。

# MikuMikuDanceをダウンロードする

[Vocaloid Promotion Video Project](https://sites.google.com/view/vpvp/)からダウンロードするわけだが、
ダウンロードすべきは「1.4 MikuMikuDance(64bitOS Ver)」である。
最初に目に入る「1.1 MikuMikuDance」は初音ミク以外のモデルは表示できない。

# 拡張子がpmxのモデルファイルをMMDで開く

プレビュー画面左下の [モデル編] ボタンをクリックするか、
pmxファイルをプレビュー画面にドラッグ＆ドロップする。pmdファイルも同じ。
メニューから [ファイル] > [開く] とやってもモデルファイルやモーションファイルは開けない。

# 拡張子がvmdのモーションファイルを開く

vmdファイルをMMDにドラッグ＆ドロップするか、
メニューから [ファイル] > [モーションデータ読込] で開く。

# カメラ位置を変更する

1. プレビュー画面左下の [カメラ編] ボタンをクリックする。これによりカメラ操作モードになる。
1. [編集] > [カメラフレーム全て選択] をクリックする。
1. [編集] > [カメラフレーム位置角度補正] をクリックする。
1. カメラフレーム位置角度補正ダイアログの右側のエディットボックス（初期値が`0.0`のほう）に適当な値を入力する。
角度Xを`45`にすれば斜め上45°から見下ろすことになり、
角度Yを`-45`にすれば斜め左45°から眺めることになる。
ここで入力した値は既存の値に加算される。リセットしたい場合は左側のエディットボックス（初期値が`1.0`のほう）を`0`にするとリセットできる。

都度 [カメラフレーム全て選択] しないと1フレームだけの変更になってしまうので注意。

# AVI出力する

[ファイル] > [AVIファイルに出力] でOKだが、
AVI出力設定ダイアログで録画フレームを指定しないと空AVIになるので注意。
neosでlogix その88

# 概要
neosでlogixやってみる。
俺コードを、発明した。
logixを、俺コードで表現してみる。

# 参考にしたページ

https://qiita.com/ohisama@github/items/80fa39199d0ce119f2db

# 俺コード

```
for i = 1, i < 100, i++ do
   if i % 15 == 0 
      then print("FizzBuzz")
      else if i % 5 == 0 
         then print("Buzz ")
         else if i % 3 == 0 
            then print("Fizz ")
            else print(i)
end
```

# forを、使わないコード

無理あるな。

```
loop do
   case c do
   0:
      i += 1, c = 0
   1:
      if i > 100 then c = 0
   2:
      if i % 15 == 0 then print("FizzBuzz"), c = -1
   3:
      if i % 5 == 0 then print("Buzz "), c = -1
   4:
      if i % 3 == 0 then print("Fizz "), c = -1
   5:
      print i
   end
   c += 1
end
```

# whileで、書いてみる。

```
i = 1
while do
   if i > 100 then break
   if i % 15 == 0 
      then print("FizzBuzz")
      else if i % 5 == 0 
         then print("Buzz ")
         else if i % 3 == 0 
            then print("Fizz ")
            else print(i)
   i += 1
end
```

以上。
【Swift】guardってむずくね

# はじめに
guard文を使用していて「！？」と思ったことがあったので記録しておきます。

# パターン1
このパターンは`url`の`nil`チェックをしています。
`nil`の場合はelse節が実行され、`nil`でない場合は下に処理が移ります。
この例では`url`は`nil`なので`print("❌: URLが見つかりませんでした")`が実行されます。
```swift
let url: URL? = nil
guard let url else { return print("❌: URLが見つかりませんでした") }
print("✅: \(url)")
```

# パターン2
このパターンは`bool`の真偽チェックをしています。
`false`の場合はelse節が実行され、`true`の場合は下に処理が移ります。
この例では`bool`は`false`なので`print("❌: false")`が実行されます。
```swift
let bool: Bool = true
guard bool else { return print("❌: false") }
print("✅: \(bool)")
```

# おわり
`let`がないだけで変わりすぎでしょ。
パターン2に関してはif文でよくないですか？
if文とどういった使い分けをするのか気になります。
【eTLD】ルートドメイン(サブドメイン除去)を抽出【Public Suffix List】

ルートドメインを簡単に抽出するAPIを作成しました。抽出できないときは、空になります。

curl https://psl.deno.dev/amazon.com
**amazon.com**

curl https://psl.deno.dev/foo.google.co.jp
**google.co.jp**

curl https://psl.deno.dev/hoge.fuga.kusatsu.gunma.jp
**fuga.kusatsu.gunma.jp**

# ソースコード
```typescript
import { serve } from "https://deno.land/std@0.155.0/http/server.ts";
import { get } from "https://esm.sh/psl@1.9.0";

serve((req: Request) => new Response(get(req.url.slice(21))));
```

# 参考

https://github.com/lupomontero/psl

https://publicsuffix.org
草莽Erlang ── 37. lists:search

口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## lists:search/2

[lists:search/2](https://www.erlang.org/doc/man/lists.html#search-2)は真理値返す関数を渡し、その関数が真を返すような値がリスト内にある場合、最初に見つかった値に対して `{value, 見つかった値}`タプルを返します。見つからない場合は `false` を返します。

```
search(fun((term) -> boolean), [term]) -> {value, term} | false
search(見つかったら真理値返す関数, リスト) -> {value, 見つかった値} | false
```

```erlang
> lists:search(fun (X) -> X rem 2 == 0 end, [1, 2, 3, 4]).
{value,2}

> lists:search(fun (X) -> X < 0 end, [1, 2, 3, 4]).
false
```

タプルのリストに対して検索する場合は[lists:keyfind/3](https://www.erlang.org/doc/man/lists.html#keyfind-3)が便利です。

## lists:keyfind/3

```
keyfind(term, integer, [tuple]) -> tuple | false
keyfind(検索ワード, タプルの要素の位置, タプルのリスト) -> 見つかったタプル | false
```

[lists:keyfind/3](https://www.erlang.org/doc/man/lists.html#keyfind-3)はタプルのリストを検索します。指定された位置の要素が検索ワードと等しいタプルを探します。該当するタプルが見つかった場合はそのタプルを、そうでない場合は`false`を返します。

要素の数え方は「１、２、３ぁっダー！」です。例えば最初の要素のインデックスは`1`となります。

https://youtu.be/AWxwmqzbOaw

https://youtu.be/FSz7N5hCltw

https://note.com/awesomey/n/n4d8c355bc8f7

```erlang
> L1 = [{"A",10},{"B",20},{"C",30},{"D",40},{"E",50}].

> lists:keyfind("E", 1, L1).
{"E",50}

> lists:keyfind(30, 2, L1).
{"C",30}

> lists:keyfind(123, 2, L1).
false
```

## lists:keysearch/3

[lists:keysearch/3](https://www.erlang.org/doc/man/lists.html#keysearch-3)という非常に似た関数がありますが、これは後方互換性のために存在しているそうですので忘れてよさそうです。

```bash
> lists:keysearch("E", 1, L1).
{value,{"E",50}}

> lists:keysearch(30, 2, L1).
{value,{"C",30}}
```

## lists:keytake/3

[lists:keytake/3](https://www.erlang.org/doc/man/lists.html#keytake-3)を使うと見つかった要素だけではなく、見つかった要素が除外されたリストも同時に取得できます。

```erlang
> lists:keytake("E", 1, L1).
{value,{"E",50},[{"A",10},{"B",20},{"C",30},{"D",40}]}

> lists:keytake(30, 2, L1).
{value,{"C",30},[{"A",10},{"B",20},{"D",40},{"E",50}]}
```

[listsモジュール](https://www.erlang.org/doc/man/lists.html)には他にもリスト処理のための関数がたくさんあります。

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
Rasberry Pi 4BにCODESYSをインストール

Rasberry Pi 4BをPLC化するためにCODESYSをインストールしました。
ネット上で色々調べながらインストールを進めたところ、Windows11orWindows10、CODESYSやRasberry Pi OSのバージョンにより違いがある。ひとつのページにそって進めているとインストールに失敗する箇所がでてきた、インストールを進めるために他のページを調べてとしてインストールを完了しました。

2023/01/25 現在私の環境でインストールに成功した手順をメモとして書きます。
PC側　　　　　Windows11 Pro 22H2
　　　　　　　CODESYS V3.5 SP18 Patch4(64bit)
　　　　　　　Rasbery Pi Imager v1.7.3
Rasberry Pi   Rasberry Pi 4B
　　　　　　　Rasberry Pi OS(32-bit) リリース日2022-09-22



----
●必要なインストーラのダウンロード
　Rasberry Pi Imager、CODESYS Development System、CODESYS Control for Raspberry Pi MC SL、CODESYS Edge Gateway for Linux をダウンロードします。

　CODESYSからインストーラや各種パッケージをダウンロードする前にCODESYSアカウントを作成する必要があります。

----
●Rasberry Pi OSのインストール、CODESYSを使うための設定
・Rasbbery Pi Imagerをインストール

・microSDカードをPCに刺し、Rasberry Pi ImagerでRassberry Pi OS(32-BIT)をインストールします。
　Rasberry Pi上で動作させるCODESYSランタイムをマルチコアで動作させるためにはRassberry Pi OSは64ビット版でなく32版を使用する必要があります。

・Rasberry Pi初回起動時に
　- ユーザ設定   ユーザ名とパスワードを設定します。
　- OSアップデートを行うためWiFiを設定しインターネットにつなげます。

Raberry PiがOSのアップデートを自動的にアップデートした後、再起動します。

　Rasberry Piが再起動され初回ログイン後の画面で
　-設定→Rasberry Piの設定→インタフェースで
　　全項目をONにしました。CODESYS開発環境よりPLCプログラムをランタイムに送る際に、いくつかをONする必要があるようですが、どれをONにすればよいか分からなかったのでとりあえず全項目をONにしました。

  -ユーザをsudoユーザにします。
　　sudo gpasswd -a <初回起動時に設定したユーザ名> sudo

　- Windowsからリモートデスクトップ接続できるようにします。
　　sudo apt-get install xrdp
　　sudo service xrdp restart

以下は優先LAN接続で運用したい時の設定です。
  -優先LANのIPアドレスの設定の仕方
　　> /etc/dhcpcd.conf を下記追記
　　　　static ip_address=xxx.xxx.xxx.xxx
　　　　static routers=xxx.xxx.xxx.xxx
　　　　static domain_name_servers=xxx.xxx.xxx.xxx

　- WiFi無効化
    > 画面右上のネットワークのマークを左クリック
　　> Turn Off WiFi 選択

・Rasberry Pi を再起動します。

・Windowsから設定したIPアドレスでラズパイにpingが通ることを確認しておきます。


----

●CODESYS　PLCプログラム開発環境のインストール
・PC側で　CODESYS Development Systemをインストールします。

・CODESYS Control for Raspberry Pi MC SLパッケージとCODESYS Edge Gateway for Linuxパッケージをインストールします。CODESYS Development Systemを起動して
　> Tools→Package Management 
  > Install釦押す
　> CODESYS Control for Rasberry PI をインストール

・CODESYSランタイムをラズパイにインストールします。CODESYS Development Systemを起動して
　>新規プロジェクト作成
  >Tool→Update Raspberry Piを選択
　>SCAN釦押下　ラズパイのIPアドレスを選択
  >Raberry Pi初回起動時に設定したUsernameとパスワードを設定
　>Install釦押下
　>Multicoreにするかどうかのダイアログが出るのでMulticoreをチェックOK釦押下

・CODESYS Development Systemとラズパイ上のCODESYSランタイムの接続
　>プロジェクトツリーでデバイス右ダブルクリック
　>ネットワークスキャンでCODESYSランタイムをインストールしたラズパイを選択
  >オンライン→ログイン

・GPIO拡張
　- 以下の記事に従っておこないます。CODESYS Development SystemでPLCプロジェクトをいくつか作ってみましたが、記事中にある「デバイスの更新」がでる時とでない時があります。
　　https://misoji-engineer.com/archives/codesys-gpio.html#:~:text=%E7%B4%B9%E4%BB%8B%E3%81%97%E3%81%BE%E3%81%99-,%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%81%AE%E6%9B%B4%E6%96%B0%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8BGPIO%E6%95%B0%E3%81%8C%E5%A2%97%E3%82%84%E3%81%9B%E3%81%BE%E3%81%99,%E5%A2%97%E3%82%84%E3%81%99%E6%96%B9%E6%B3%95%E3%81%AF%E7%B0%A1%E5%8D%98%E3%81%A7%E3%81%99%E3%80%82&text=%E3%80%8CGPIOs%20B%2B%2FPi2%E3%80%8D%E3%82%92,%E9%81%B8%E6%8A%9E%E3%81%99%E3%82%8C%E3%81%B0%E7%B5%82%E4%BA%86%E3%81%A7%E3%81%99%E3%80%82
iOS App Dev Tutorialsを読んで実際にやってみた。その4

## 前回の記事
[iOS App Dev Tutorialsを読んでみた。その3](https://qiita.com/shomiya181210/items/f9f122fab2db17f2011f)
前回の記事を読んだ後、この記事をご覧ください。
## 今回の範囲
[Displaying data in a list](https://developer.apple.com/tutorials/app-dev-training/displaying-data-in-a-list)
４回目はリストにデータを表示させる。
## 内容の要約
### 1. デイリー スクラムのリストを表示させる。
- ScrumsView.swiftという新しいSwiftUI Viewファイル作成します。
- scrumstypeという定数を追加する。
```ScrumsView.swift
let scrums: [DailyScrum]
```
- Daily Scrumを初期値にする。。
```ScrumsView.swift
ScrumsView(scrums: DailyScrum.sampleData)
```
- bodyの中のtextをListに書き換える。
```ScrumsView.swift
var body: some View {
    List {
        
    }
}
```
- 命令文forEachを使ってビューを追加する。
```ScrumsView.swift
ForEach(scrums, id: \.title) { scrum in
    
}
```
- リストの背景色を設定する。
```ScrumsView.swift
.listRowBackground(scrum.theme.mainColor)
```
### 2.各スクラムを識別可能にする。
- ScrumdingerApp.swiftのファイルを開いて、構造体DailyScrum.swiftIdentifiableを宣言する。
```ScrumdingerApp.swift
struct DailyScrum: Identifiable
```
- UUIDという定数を追加する。
```ScrumdingerApp.swift
 let id: UUID
```
- 初期化処理を追加する。
```ScrumdingerApp.swift
init(id: UUID = UUID(), title: String, attendees: [String], lengthInMinutes: Int, theme: Theme) {
        self.id = id
        self.title = title
        self.attendees = attendees
        self.lengthInMinutes = lengthInMinutes
        self.theme = theme
```
- For Eachで繰り返し文を作る。
```ScrumdingerApp.swift
ForEach(scrums) { scrum in
```
- アプリの初期ビューに設定する。
```ScrumdingerApp.swift
ScrumsView(scrums: DailyScrum.sampleData)
```
### ３.まとめ
 　今回はリストでのデータの表示を行った。次回はナビゲーション階層を設定します。
Googleプロジェクト管理：開発チーム

# はじめに

わたしが [Google プロジェクト管理:プロフェッショナル認定証で得られた素晴らしい体験][google]を、要点をまとめ小さく分割して、わかりやすく簡潔に紹介していきます。

興味があれば、ぜひ ***"Google プロジェクト管理:プロフェッショナル認定証"*** を受講してみてください。

[google]: https://qiita.com/mapami/items/317ae776a2268fd54c8f

https://jp.coursera.org/professional-certificates/google-project-management

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/1c9e3622-d11d-e6dd-1bb7-f12b3fef8845.png" width="800">

# 開発チームの規模

チームの規模は、***<font color="MediumBlue">3人から9人</font>*** です。これは、チームの規模が、軽快さを維持するのに十分小さく、かつ、各スプリント内で重要な作業を完了するのに十分大きいことを保証するものである。

チームの規模を適切に設定することは重要です。
- 小規模なチームではスキルやアイデアの多様性に悩まされる可能性があります。
- 大規模なチームでは意見やコミュニケーションの流れが多すぎるという問題に直面する可能性があります。

:::note info
3人から9人という規模は、大きなピザをシェアできる人数と同じなので、「ピザサイズチーム」</font>とも呼ばれます。
:::

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/4f2baf4f-04dc-3031-4250-1df1b175e643.png" width="500">

# クロスファンクショナル

開発チームは、必要なスキルをすべて備えているため、製品やサービスを社内で構築できるよう、クロスファンクショナルであるべきです。

# 自己組織化

開発チームは自分たちのプロセスや構造も所有します。開発チームは自己組織化する必要があり、他者からの指示には頼れません。彼らは、個人ではなくチームとして継続的に活動し、チームの目標に到達するためにお互いをサポートします。

# 顧客志向

開発チームは、最高の製品は、顧客志向で、製品を作るときにユーザーに焦点を当てたチームから生まれることを認識する。

# 働く場所

多くのスクラムチームは、同じ物理的なスペースで一緒に仕事をすることを好みます。多くの人は、チームが同じ場所にいる方が、より質の高い仕事を提供し、より速く改善されると信じている。しかし、これはすべてのチームにとって常に可能なことではありません。

チームが同じ場所にいる場合は、会議室に集まって、仕事を終わらせるか、スプリント目標に影響を与えないように仕事を調整するためのアイデアをすぐに書き出すことができます。しかし、同じ場所に座っていなかったり、異なるタイムゾーンで仕事をしていたりすると、このコラボレーションは少し難しくなり、電話や電子メールで行わなければならなくなります。

その反面、バーチャルで仕事をすることも可能な世の中になっています。品質保証のスペシャリストは、ZoomやSkypeなどのビデオ会議プラットフォームを使って、電話をかけたり、参加したりすることができるわけです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/a914fda1-135b-4a13-c116-ae2990d16146.png" width="450">

共同作業とバーチャル作業のどちらにも利点と欠点があるので、チームにとって最適な方法を選択するようにしてください。

# スクラムガイドラインより

開発チームは開発者とも呼ばれ、製品を構築するための作業を行う人々で構成される。スクラムガイドによると、開発者は

***<font color="MediumVioletRed">『スクラムチームの中で、各スプリントで使用可能なインクリメントのあらゆる側面を作成することにコミットしている人々』</font>***

である。彼らの責務は以下の通りである。

- **スプリントの計画、スプリントバックログ（次のスプリントで完成させるために選択されたプロダクトバックログ項目のセット）の作成**
- **Doneの定義に従うことで、品質を浸透させる**
- **スプリントの目標に向かって、毎日計画を修正する**
- **プロフェッショナルとして互いに責任を持つ**
- **プロダクトバックログ項目を設計、構築、テストすることでスプリントを実行する**

開発チームの特筆すべき重要な点は、クロスファンクショナルであることです。つまり、異なる分野の専門家がチームメンバーとして参加することになります。

- ソフトウェアチームであれば、ウェブデベロッパー、データベースデベロッパー、ユーザーエクスペリエンスのスペシャリストがいることを意味します。
- マーケティングチームであれば、ライター、編集者、検索エンジン最適化のスペシャリスト、ビジネスアナリストなどが含まれるかもしれません。

# おさらい

あなたのチームには常に協力し、向上することに関心のある人が必要でしょう。具体的には、フィードバックを重視し、チームに活気と楽しさをもたらし、失敗を認めてそこから学ぶことができるメンバーがいれば最高です。では、各チームメンバーがどのような特徴を持つべきかを見ていきましょう。

### プロダクトオーナー

プロジェクトの大まかな方向性、要件、目標を自信を持ってチームに提供することができますが、これらの目標を達成する方法はチームが決定することができるようにしなければなりません。あなたのチームは、製品ビジョンを推進し、顧客にとっての価値を最大化するためにプロダクトバックログに優先順位を付けるプロダクトオーナーを望んでいるはずです。これを実現するために、プロダクトオーナーは組織化され、強力なコミュニケーションスキルを持つ必要があります。

### スクラムマスター
効率的なファシリテーターとなり、対立を解決する方法を知っている交渉者となることができる、強力なリーダーシップスキルを備えている必要があります。チームは、開発チームを効果的にコーチし、イベントを促進し、チームの進行を妨げる可能性のある雑念を排除することを目的としたスクラムマスターを望んでいるはずです。

### 開発チーム

成果物を完成させ、優れた最終製品を生み出すことに集中できる人材が必要です。チームは自己組織化され、部門横断的であるため、一緒に働くことに熱心で、製品のより大きな利益のために妥協することを恐れない人を求めています。
ts-node の Unknown file extension ".ts" エラーを解決する

# 概要

ts-node で TypeScript のコードを実行しようとしたとき以下のようなエラーが出ることがある。

```bash
npx ts-node src/index.ts
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/hoge/workspace/fuga/src/index.ts
```

調べてみると、解決策の1つとして `package.json` から `"type": "module"` を消せ、というのが挙げられていることがあるが、これは消したくない。
どうしたら良いか。

# 解決策 1

そもそも、最近では ts-node ではなく tsx を使うほうが主流らしい。

```bash
npx tsx src/index.ts
```

# 解決策 2

ts-node を使いたい場合は `--esm` オプションをつけて実行する手段がある。

```bash
npx ts-node --esm src/index.ts
```

# 解決策 3

ts-node を使いたい場合は `tsconfig.json` に以下の記述を追加する手段もある。

```json:tsconfig.json
{
  // other settings...
  "ts-node": {
    "esm": true,
    "experimentalSpecifierResolution": "node"
  }
}
```

# 解決策 4

ts-node ではなく node で `--loader ts-node/esm` を指定する方法もある。

```bash
node --loader ts-node/esm src/index.ts
```
単価に見合ったRubyエンジニアを雇うために面談で使える技術的な質問

### 解決したいこと
単価に合わないRubyエンジニアを雇いたくはない。

### 解決方法
面談で技術的な質問で単価に合わないエンジニアか判断できるようにする

### 技術的な質問集
railsエンジニアの面談時の技術的な質問をまとめました↓

Q: Userモデルが複数のpostを持つ時、userモデルにどのような記述をしますか？
A: has_many :posts

Q: Userモデルが複数のPostを持つ時、Postモデルにどのような記述をしますか？
A: belongs_to: user

Q: Userモデルが複数のPostを持つ時、userのレコードが削除された時にpostsも削除されるようにするためにどのような記述が必要ですか?
A: has_many :posts, dependent: destroy
   has_manyの記述の後にdependent: destroyをつける

Q: railsで、データベースの構成を変更するために何をしますか?
A: マイグレーションファイルを作成する

Q: マイグレーションファイルを作成するコマンドは？
A: rails g migration file_name

Q: マイグレーションファイルをdbに反映するためのコマンドは？
A: rails db:migrate

Q: クラスにモジュールを読み込む時にどのように記述しますか?
A: classにinclude module_nameを入れる

Q: n+1問題とはなんですか?
A: 親モデルのレコードをeachさせた中で子モデルの取得のSQLが動いてしまい、必要以上にSQLが発行されて表示が遅くなること

Q: n+1問題をどのように解決しますか?
A: 親モデルのレコードのeachされる前に、includes(:child_model)やpreload(:child_model)などをして、事前に子モデルの内容も取得しておく。




**1年以上rubyやっている人でこれに答えたれない人は多分経歴を盛っているので気をつけて下さい。**

Q: Userモデルが複数のPostを持つ時、userのレコードが削除された時にpostsも削除されるようにするためにどのような記述が必要ですか?
Q: n+1問題とはなんですか?
Q: n+1問題をどのように解決しますか?
Googleプロジェクト管理：プロダクトオーナー

# はじめに

わたしが [Google プロジェクト管理:プロフェッショナル認定証で得られた素晴らしい体験][google]を、要点をまとめ小さく分割して、わかりやすく簡潔に紹介していきます。

興味があれば、ぜひ ***"Google プロジェクト管理:プロフェッショナル認定証"*** を受講してみてください。

[google]: https://qiita.com/mapami/items/317ae776a2268fd54c8f

https://jp.coursera.org/professional-certificates/google-project-management

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/1c9e3622-d11d-e6dd-1bb7-f12b3fef8845.png" width="800">

# プロダクトオーナーの役割

***<font color="MediumVioletRed">『プロダクトオーナーは、チームが正しいものを作っていることを保証する』</font>***

プロダクトオーナーは、チームが正しい製品やサービスを作っていることを確認するのが仕事です。効率的なスクラムチームが、ユーザーが望まない製品を作っていたら、誰の役にも立たない。

プロダクトオーナーは、スクラムチームが提供するプロダクトの価値を継続的に最大化する責任を負っています。彼らの主な活動は、チーム内で ***<font color="MediumBlue">顧客の声</font>*** として行動することです。彼らは、プロダクトバックログの所有を通じて、この声を代表し、表現します。

プロダクトバックログは、スクラムチームがプロジェクト目標を達成するために取り組む事柄の唯一の権威あるソースである。

# プロダクトオーナーの責任

- スクラムチームが自分たちの仕事が ***<font color="MediumVioletRed">なぜ全体のゴールとミッションの中で重要なのか</font>*** を理解するのを助けることも含まれます。
- 目標の達成を最適化し、顧客に価値を提供するために、***<font color="MediumVioletRed">プロダクトバックログに優先順位</font>*** を付けます。
- プロダクトバックログがすべての人に可視化され、 ***<font color="MediumVioletRed">透明性</font>*** があることを保証します。
- 製品やサービスが ***<font color="MediumVioletRed">顧客のニーズを満たしているか</font>*** どうかを確認する責任があります。

# プロダクトオーナーの特性

- ***<font color="MediumVioletRed">顧客志向</font>***　であることが求められるため、顧客のニーズとそのビジネスの業界を非常によく理解していなければなりません。
- ***<font color="MediumVioletRed">決断力</font>***　があり、優れたコミュニケーション能力を持ち、問題の両面を理解して、チームに対して自分の決断を擁護する必要があります。
- チームにとって有益な変化をもたらす新しい情報に対して、***<font color="MediumVioletRed">柔軟でオープン</font>***　でなければなりません。
- 製品ビジョンをチームに伝える以上、***<font color="MediumVioletRed">楽観的でポジティブ</font>***　でなければなりません。
- 自分たちの使命を信じるよう、***<font color="MediumVioletRed">チームを鼓舞</font>***　しなければならない。
- ***<font color="MediumVioletRed">利用可能</font>***　でなければならない。スクラムの反復的な性質は、チームが定期的に次の反復を検査し、適応し、計画するために、プロダクトオーナーを必要とすることを意味します。
- ***<font color="MediumVioletRed">協力的</font>***　でなければならない。プロダクトオーナーは、顧客のニーズを確実に満たすために、チームと協力しなければならず、そのためには、複数のステークホルダーと会い、一緒に仕事をする必要があります。

:::note info
プロダクトオーナーはスクラムマスターと同じように、プロジェクトの多くの責任を負っています。
:::

# スクラムガイドラインより

***<font color="MediumVioletRed">『プロダクトオーナーは、スクラムチームの作業から生まれるプロダクトの価値を最大化する責任がある。これをどのように行うかは、組織、スクラムチーム、および個人によって大きく異なる可能性がある。』</font>***

プロダクトオーナーは、プロジェクト期間中、顧客の声を代弁し表現することで、プロダクトの価値を最大化する。その製品が顧客の期待を満たし、顧客のニーズを満たさないのであれば、その製品は顧客にとって有用なものとはならない。

プロダクトオーナーの職務は以下の通りです。

- **プロダクトゴールの作成と明示的な伝達**
- **プロダクトバックログ項目の作成と明確な伝達 (プロダクトバックログには、プロジェクトのゴールを達成するために、成果物に関連するすべての機能、要件、およびアクティビティが含まれます)**
- **プロダクトバックログの透明性、可視性、理解度を確保すること**

# Product Owner vs. Project manager

従来のプロジェクト管理では、スコープ管理はプロジェクトマネージャの主要な責任であった。しかし、スクラムでは、スコープの定義と管理は、プロダクトオーナーに任される。逆に言えば、プロダクトオーナーはチームのパフォーマンスに対して責任を負わない、つまり、マネージャーとはみなされないのです。プロジェクトマネージャーは、プロジェクトの目的を達成するために、プロジェクトチームをリードし、タスクと進捗を監督します。

また、プロダクトオーナーとプロジェクトマネージャーの役割には、共通点があります。例えば、両者ともステークホルダー管理を任務としています。つまり、チームメンバーやステークホルダーとの効果的なコミュニケーションを実践し、促進しなければなりません。

さらに、Googleを含む多くの企業では、製品やソリューションのスコープを定義するのは、プロダクトマネージャーと呼ばれる別の役割の責任である。従って、新しい会社に入社する際には、その会社が製品定義、要件開発、ユーザー調査などの分野にどのように取り組んでいるかを確認し、何をもってプロジェクトマネージャーの領域と考えているかを理解することが重要です。

# Tips：YouTube

https://youtu.be/oAY83nu5FOg

https://www.youtube.com/watch?v=zaP3RPQc3EY
MySQLで日本語を含むレコードを挿入する際に出たエラーの解決法

# 環境
- MySQL 8.0.31
- Docker Desktop 4.4.4
- MySQL Workbench 8.0.30

# 背景
勉強目的でDockerにDBのコンテナを作り、いろいろ操作する中で日本語を含むレコードを挿入しようとしたら、エラーが出て挿入できなかった。エラーの解決に苦労したので、ナレッジとして残しておきたいと思い、記事を記載することにした。

# テーブルの定義
dummyテーブル
|  Column  |  Type  |
| ---- | ---- |
|  id  |  int  |
|  dummycol  |  verchar(45)  |

# 実行したSQL
```
INSERT INTO `dummy` (`id`, `dummycol`) VALUES ('2', 'あ');
```

# エラー内容
```
ERROR 1366: 1366: Incorrect string value: '\xE3\x81\x82' for column 'dummycol' at row 1
```
「あ」という文字列ではなく「\xE3\x81\x82」という文字列で表示されているので、文字コード関連で怒られてるっぽい。

# 原因
MySQL Workbenchで見ると、Character Setがlatin1になっていたのが原因だった。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108559/1218ed59-19b0-042d-b817-4c2b42ff3373.png)


# 解決法
Character Setをutfmb4に変えてあげると、無事SQLが通るようになった。
試してないけど、utf8でもいけるはず。
動作追従修行ゲーム【EVMC4UとUnityを用いたUSBカメラモーションキャプチャでの動作推定】

# １．はじめに
　VRみたいな〇Rが一昨年ごろから流行って，自分もそういう世界でのゲーム作りたいなぁと思ってて，ちょうどよい機会があったので作りました。

 <iframe width="560" height="315" src="https://www.youtube.com/embed/zWKT0POl-IA?si=S4iqQhMV2gx6N8Lo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
 
とにかく修行っぽくしたくて，Unityで作る世界観も朝日が上がる時間帯から修行に励む設定にしています。


# ２．準備するもの
**必要機材**
* USBカメラ
カメラの画角にほぼ全身が映るように離れないといけないため，画角が広いものだと場所をとらなくて済む！
* PC
作成時はWindows10で動作

**必要ソフトウェア**
* Unity
　制作時はEditor version2020.3.33f1で動作
* VRM形式アバタ
[BOOTH](https://booth.pm/ja)や[VRoid hub](https://hub.vroid.com/tags/CNP)からVRＭ形式の3Dアバタモデルを取得。現在はもう置かれていないようでしたが，国内NFTコレクション「Crypto Ninja Partners」のシャオランを使用させていただきました！
* ThreeDPoseTracker Ver.0.3.0(以下，3DPT)
使用フォルダをこちらからインストール⇒[ThreeDPoseTracker Ver.0.3.0](https://digital-standard.com/threedpose/ThreeDPoseTracker_Win_x64_v0_3_0.zip)
* EVMC4U
　こちらを使用する⇒[EVMC4U - EasyVirtualMotionCaptureForUnity - VaNiiShop - BOOTH](https://booth.pm/ja/items/1801535)
　ダウンロード後はデスクトップなどで解凍しておく

# ３．動作推定準備
* こちらの記事を参考に動作推定できることを確認『[USBカメラモーションキャプチャーThreeDPoseTrackerの説明](https://qiita.com/yukihiko_a/items/43d09db5628334789fab)』
* アバターを入手したVRMモデルに変更して，動作が反映されるか確認

# ４．Unityへの推定動作反映準備
* Unityを起動
* エディタの「プロジェクト」ビューで「Assets」を右クリックする
右クリックメニューから「パッケージをインポート」→「カスタムパッケージ...」をクリックし，ダウンロードしたEVMC4U内の「ExternalReceiverPack_v3_7.unitypackage」を選択して全項目をインポート
* 同じプロジェクトビューでAssets内のExternalRecieverSceanをダブルクリックでシーンを開く
* プロジェクトビューのAssetsにVRMファイルをドラッグ&ドロップする
生成された同名Prefabをヒエラルキビューにドラッグ&ドロップする
さらに，ヒエラルキビュー中のExternalRecieverを選択した状態で，インスペクタビューのExternalRecieverスクリプトにあるModelにも同Prefabを設定する!
* Unity エディタ上部中央の▶ボタンを押すことでProjectを実行し，コンソールビューでエラー有無を確認する
この時点では特に何も動かない

ここまでの過程終了後のイメージが下の画像
※私の場合，本記事内容を実行する前に背景世界を変更したりいじったりしてるので異なる点が多々あると思います。自身がダウンロードしたアバタがTポーズで配置されていればOK!
※背景世界には『[AllSky Free](https://assetstore.unity.com/packages/2d/textures-materials/sky/allsky-free-10-sky-skybox-set-146014)』を使用。無料でこのクオリティを使えるのに驚きました！
![play画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117483/89ab5dcc-1ef3-2cf6-67fa-7ab1235cc6f8.png)
* 本節の最後にUnityを実行して，3DPTでSouce Deviceにカメラを選択し，動作推定を開始する
3DPTで推定された動作がUnity上のモデルに反映されているか確認する

# ５．インタラクティブな3Dシミュレーション
## ５.１　基礎編
* オブジェクト追加
メニューバー内の「ゲームオブジェクト」から「3Dオブジェクト」→「平面」を選択
ヒエラルキビューにて「平面」を選択した状態で，インスペクタビュー上部の「位置」や「スケール」を調整し，アバタが平面上に立っていると見えるようにする
同様に「キューブ」も追加し，アバタにも平面にも接触しないように，アバタの脇に置く
![平面選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117483/72025e20-77ea-fe15-960d-ea3e80dfdd43.png)

* 物理演算と接触判定の設定
ヒエラルキビューでキューブを選択した状態で，インスペクタビュー下部の「コンポーネントを追加」をクリックし，「Physics」→「Box Collider」と順にクリック（インスペクタビューに「Box Collider」が追加されたことを確認）
同様にキューブに「Rigidbody」を追加する
Rigidbodyでは，「重力を使用」にチェックをつけ，「Is Kinematic」のチェックを外す
同様に平面にもBox Colliderを設定（Rigidbodyは不要）

* アバタの接触判定の設定


2/1以降更新予定
変更した差分だけ、rubocopでコードチェックする方法


gitとrubocopをプロジェクトに入れている時のみ使えます。


コード整形はしない場合
```shell
git diff --diff-filter=ACMR --name-only | xargs bundle exec rubocop
```

コード整形までさせる場合
```shell
git diff --diff-filter=ACMR --name-only | xargs bundle exec rubocop -a
```


# rubocop

https://github.com/rubocop/rubocop
エンジニアインターン7日目

今日はやっと自分が作ったLPページのテンプレートを本番環境に適用させた。自分がエンジニアとして初めて開発したものになる。先輩エンジニアだったらすぐに終わっていたタスクだが自分にとって初めての成果ということで達成感を感じた。wordpressにひとつひとつ設定した。同じ作業の繰り返しだったため、これもプログラミングを利用してエンジニアらしくできるのではないだろうかという発想になった。そのために引用やすいコードを書くことが大切であると思った。今日帰りにエンジニア部長にインターンはどう？と質問された。自分は実務経験を積めて自分が成長できる最高の環境だと伝えた。自分はとても運が良いと思った。自分はまだまだ足りないことだらけだが、社内のエンジニアのみなさんがとてもやさしく指導していただき、自分が成長できるために努力してくれている。自分は実務経験からどのスキルが求めれれるか、自分が今やるべき課題は何かがはっきりしていて努力するだけである。独学でプログラミングを勉強しているならインターンをやるべきだと思う。自分はスキルではとても劣っているが、将来性を考えて採用してくれる企業もたくさんある。自分がやってきたことを信じてたくさん応募して早く実務経験を積もう。
ゲームのUIのまとめ

# Exploder 
https://game-ac.com/free/pvp/exploder/
スタート画面にチュートリアルを挟む
![スクリーンショット 2023-01-25 19.21.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2897131/e0ca57cf-e889-e3e8-2c48-7c98e0d4e77e.png)
チャット機能
![スクリーンショット 2023-01-25 19.23.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2897131/4cca7e89-ee4c-d98e-76a7-be8e80ba7342.png)

# 他のゲーム
ロード画面でチュートリアルを挟む
![スクリーンショット 2023-01-25 19.28.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2897131/2148316b-daea-ba58-4650-8fd22f9a6c6f.png)

設定画面は選択キャラを見せる
![スクリーンショット 2023-01-25 20.01.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2897131/8efba89e-08e6-26cc-0aa4-dff5f721997b.png)


# 具体例なし

背景にGIF画像を入れる、プレイ画像的なものを入れる？

# 参考にしたサイト

https://game-ac.com/free/yuudou/

https://game-ac.com/free/jump/robo-exit/
【Node.js】Slack APIでメッセージを送信する方法


Node.jsでエラー時にSlackにメッセージを送信する実装をしました。

↓こちらの記事の通りに進めさせていただきました。

https://zenn.dev/kou_pg_0131/articles/slack-api-post-message

とても分かりやすかったです。ありがとうございます。
基本的にこの流れで設定できたのですが、少しつまずいた点があったのでメモしておきます。



**(1) [アプリを作成する](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message#%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)**
**(2) [スコープを設定する](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message#%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)**

ここまでスムーズにいけました。


**(3) [アプリをワークスペースにインストールする](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message#%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9%E3%81%AB%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B)**

こちらで`Install to Workspace`ボタンをクリックすると、「ボットユーザーがありません」と表示されました。

![ボットユーザーがありません.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652834/e36c952d-40ae-f437-27e6-eeba49263a35.png)
原因は、Botに名前がないからのようです。

↓こちらの記事を参考にさせていただき…

https://the-simple.jp/slack-nobotuser

`App Home`タブで`Display Name (Bot Name)`と`Default username`を設定。


もう一度`OAuth & Permissions`タブに戻って`Install to Workspace`ボタンをクリックするとい進むことができました！

**(4) [アプリをチャンネルに追加する](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message#%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B)**

こちらはスムーズにいきました。

**(5) [メッセージを投稿する](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message#%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E6%8A%95%E7%A8%BF%E3%81%99%E3%82%8B)**

↓こちらを参考に、`@slack/web-api`というパッケージを使用して送信します。

https://zenn.dev/kou_pg_0131/articles/js-slack-web-api-usage

トークンは２つあるうち、Botのほうを設定します。
（Userのトークンを使用すると、自分のアカウントからの送信となります）
チャンネル名にの先頭には「#」をつけます。

```sh:.env
SLACK_TOKEN='xoxb-**************************'
SLACK_CHANNEL='#channel_name'
```
（envファイルで設定しました）

メッセージを送信してみたところ、以下のエラーが出ました。
```sh
UnhandledPromiseRejectionWarning: Error: An API error occurred: not_in_channel
```
送信するチャンネルにSlack APIを追加しないといけないようです。

↓こちらの記事を参考にさせていただき…

https://reigle.info/entry/2022/10/23/100000

チャンネルにSlack APIを追加しました。

これで、メッセージが送信することができました！
NavigationBarのカスタムBackボタンの見た目をデフォルトと合わせる

デフォルトのBackボタン（アイコンのみ）と見た目をほぼほぼ合わせることができたのでメモ。

Backボタンタップ時にアラート表示したいときなどにBackボタンの見た目をほぼ変えずに対応できるようになります！

|  Default  |  Custom  |
| ---- | ---- |
|  ![Simulator Screen Shot - iPhone 8 - 2023-01-25 at 19.38.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179737/d346cb55-42ee-09e5-3d5a-d1796c9f45ee.png)  |  ![Simulator Screen Shot - iPhone 8 - 2023-01-30 at 14.33.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179737/97833e88-a7c3-e96d-7c2c-166937587f68.png)  |


```swift
let imageConfig = UIImage.SymbolConfiguration(pointSize: 22, weight: .medium, scale: .default)
let image = UIImage(systemName: "chevron.left", withConfiguration: imageConfig)
let buttonItem = UIBarButtonItem(image: image, style: .plain, target: target, action: action)
buttonItem.imageInsets = UIEdgeInsets(top: 0, left: -8, bottom: 0, right: 0)
navigationItem.leftBarButtonItem = buttonItem
```
ポイントは`UIImage.SymbolConfiguration`をセットするのと`imageInsets`で左の余分なマージンを消すこと。
Customのアイコンの位置が微妙に上になってしまったが`imageInsets`のtop/bottomがなぜか効かなかった:thinking: