OmniAICreator/Qiita-1.07M huggingface dataset:
Slackｸｿﾃﾞｶ絵文字の作り方

# はじめに

Slackｸｿﾃﾞｶ絵文字を作るの、大変ですよね。

:::note info
### Slackｸｿﾃﾞｶ絵文字とは
複数の絵文字を使用して作成した1つの絵文字。
イラスト/画像を分割して登録することで、使用することができるよ。
例えばこんなの↓
![スクリーンショット 2024-01-07 21.16.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336887/06876e77-a3a2-00c3-68f5-371d16304c97.png)
:::

参考までに、ｸｿﾃﾞｶ絵文字を作る手順としては、

1. 画像を用意する。（縦横比が整数となるサイズがベター）
2. 画像を正方形のブロックに分割する。
3. 分割した画像に命名して保存する。
4. Slackに登録、使用する。

ですが、画像をより細分化したい時に2, 3の手順がかなり厄介なんですよね。

そこで特に骨の折れる手順2, 3を簡略化することで、ｸｿﾃﾞｶ絵文字を気軽に作れるサイト「Slack Emoji Splitter」を作ってみました。

https://slack-emoji-splitter.pages.dev/

さっそく使い方から説明を。

# 使い方

画像は自由に用意してください。
## Slack Emoji Splitter

![create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336887/783a6283-9268-e8e9-f4aa-2456860b81f8.png)

1. ①: 使用する画像をドラッグ&ドロップ、もしくはクリック・ファイル選択してアップロード
    今回は縦横比が1:2の画像を使用する。
    
2. ②③:右側のプレビューを見ながら、縦横の分割数を設定
    「Horizontal Parts」が横方向、「Vertical Parts」が縦方向の分割数を指しており、1-18個に分割できる。今回の画像は縦横比が1:2なので、横:14個・縦:7個に分割する。
    
    分割後の1絵文字が128*128ピクセルの正方形になるようにリサイズされる。
    
3. ④: 絵文字の名前を設定
    Slackに登録される絵文字の先頭の名前を設定する。
    
    | 分割数 | 絵文字名 |
    | --- | --- |
    | 横:1・縦:1 | {名前} |
    | 横:複・縦:1 | {名前}-{列番号} |
    | 横:1・縦:複 | {名前}-{行番号} |
    | 横:複・縦:複 | {名前}-{列番号}-{行番号}} |

    Slackに複数の絵文字を一括登録する場合、画像名が絵文字名となるので、入力した名前で画像が生成される。
    
4. ⑤: ダウンロード
    ZIPファイルで画像をダウンロードする。

## 登録

Slackには一括で絵文字を登録しちゃいましょう。

こちらのnoteを参考にさせていただきました。↓

https://note.com/tadanoyanco/n/n3d87f5a2f206

手順は

1.  Chrome拡張機能インストール
    https://chromewebstore.google.com/detail/neutral-face-emoji-tools/anchoacphlfbdomdlomnbbfhcmcdmjej?hl=ja
    
2. Slackワークスペースの「カスタマイズ/絵文字」を開く
    ```jsx
    https://{ワークスペースのURL}/customize/emoji
    ```
    
3. 表示されている拡張機能のボックスに、解凍したフォルダをそのままドラッグ&ドロップ
    自動的にアップロード/登録処理が走る。絵文字名は画像名が適用される。
    
## 使ってみる

![command.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336887/1f33676a-5bc3-0449-919c-c1118000f100.png)
使うには左下「Emoji Command」をコピペするだけ！

こんな感じで表示されます。行間は閉じるのでモウマンタイ。
![スクリーンショット 2024-01-07 22.11.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336887/b73b91e9-db57-bb24-515d-6a21a0160258.png)

※登録してもすぐには使用できない場合もあるので、コーヒーでも飲んで休憩タイム。理由は謎。

# 使用技術

SvelteKitでキャンバスAPI使用してサイトを構築して、Cloudflare Pagesにデプロイ・ホスティングしているだけです。

SvelteKitは「コードがシンプル・超リアクティブ・仮想DOMを使用しないので早い」などの特徴があります。

https://kit.svelte.jp/

Cloudflare Pagesは「安い・エッジサーバに配置されるので早い」などの特徴があります。

https://www.cloudflare.com/ja-jp/developer-platform/pages/

つまり「SvelteKit + Cloudflare Pages」の組み合わせは「美味い早い安い」のITエンジニアにとっての吉野家みたいなものでしょうか。

ちなみにSvelteKitで構築したサイトをCloudflare Pagesにデプロイするにあたり、adapterを設定する必要がありますが、ライブラリインストールして少し設定をイジるだけなので開発者体験も最高です。

https://kit.svelte.jp/docs/adapter-cloudflare

# 以上
![スクリーンショット 2024-01-07 23.20.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336887/542149d7-cc4e-867f-3d91-e0349550a78f.png)
※324個の絵文字を使用
TinyMCEを青空文庫エディタにする

# 青空文庫エディタ
Meryのマクロ機能を利用して青空文庫エディターというのがある、私も使っていたが、初心者向けではないのでもう少し直感的に操作するものができないかと思っていた。ウェブ用のHTMLエディタを使って、HTMLから青空文庫に変換する機能をつけたものつくった。それを青空文庫エディタにした。


https://kyukyunyorituryo.github.io/AozoraEditor/


# 仕組み
TinyMCEでHTMLを作成して、turndownを改造したhtml2aozoraで青空文庫に変換している。AozoraJavaScriptParserで青空文庫からHTMLに変換しなおしている。それぞれのHTMLタグやクラスが違うので改造して対応している。

TinyMCE　https://www.tiny.cloud/

turndown　https://github.com/mixmark-io/turndown

html2aozora　https://github.com/kyukyunyorituryo/html2aozora

AozoraJavaScriptParser　https://github.com/gearsns/AozoraJavaScriptParser

# なぜ縦書きか？
　日本語の書籍の場合は、縦書きで出版されることが多く表示と編集を同じ画面で行いたい。縦書きであっても、左側に入力画面で右側にビュワーを表示している事がある。その場合は、画面の表示内容と、実際の編集画面がずれてしまう。そうすると入力画面が小さくなり入力に集中がしづらい。

　縦書きファイルを何を目的として作るか。例えばキンドルで販売するためにEPUBファイルとして出力したい場合に、できるだけ同じCSSを使って編集したほうが出戻りが減る。つまり、エディターにEPUBのCSSを使用して同じ表示にする。エディター自体にEPUB出力機能をつければエディターだけで完結する。
 
 　エディターの場合には見たまま表現ができたほうが何かと便利なことがある。例えば、ボタンによる操作をしたい場合に、画面が分かれていると、ツールバーの表示画面が少なくなる。注記自体を覚える必要がなくなる。マークダウンであれば左側に注記を入力して右側に表示する場合がある。そうすると注記自体を暗記しないと不便。


　見たまんま編集できるWYSIWYGの問題点はデータ構造が複雑になり、編集結果と実際の表示がずれてくること。HTMLの場合などに可読性がなくなってくる。特に縦書きの場合にはhtmlに縦中横、傍点、傍線などのタグがなくclassかstyleを指定する。ルビのタグは冗長で編集がしずらくなる。

## 縦書き文章の保存形式
 縦書き文章の保存形式として、青空文庫注記があるが、パーサーや相互変換に標準のものがない。そのために、マークダウンほどHTMLと行き来することが難しい。
  web小説では、ふりがなの入力は青空文庫とその他が混ざっている。傍点をふりがなとして使っているものも多い。
  
| |ルビ|傍点|
|:----|:----|:----|
|小説家になろう|（全角または半角）\|漢字《ルビ》|｜漢《・》｜字《・》|
|カクヨム|（全角または半角）｜漢字《ルビ》|《《○○》》|
|青空文庫|（全角縦線）｜漢字《ルビ》|○○［＃「○○」に傍点］|

ここから引用

https://99nyorituryo.hatenablog.com/entry/2016/06/15/212508


 縦書きエディタの種類はそれほど多くない、しかもwebの場合はメンテナンスがされないことが多い。

関連

https://qiita.com/isari/items/b9356ddb731423f6846e
pythonで B=A は BへのAコピーではない！

### 画像データを加工していた時に ？？？？ となってしまった案件。
通常であれば
```ruby:python
a = 1
b = a
a = a + 2
c = b
print ("ans ",a,b,c)

ans 3 1 1
```
となり問題ないが、
画像データ img_a を加工する際、加工前の状態を退避させる意図で
```ruby:python
img_b = img_a
```
として画像データ img_b を加工したが、結果は画像データ img_a も加工されていた。
その時は？？？？で、原因が解らなかったが、
画像データは配列なので、つぎの例と同じ動きをしていた。
```ruby:python
a = [1,2]
b = a
a[0] = a[0] + 2
c = b
b[1] = b[1] + 5
print ("ans ",a,b,c)

ans  [3, 7] [3, 7] [3, 7]
```
この様に、bも　cも　aと同じ実体を参照・処理している。

対策として
```ruby:python
import numpy as np

a = [1,2]
b = np.array(a)
a[0] = a[0] + 2
c = np.array(b)
b[1] = b[1] + 5
print ("ans ",a,b,c)

ans  [3, 2] [1 7] [1 2]
```
として解決した。

まあ、pythonではいろんな事が簡単に実現できるだけに、変数ひとつ取ってもいろんな事を考えなければならい様です。
ProtoPediaのバッジメーカー使ってみた

# はじめに

こちらやっていきます

https://yamaccu.github.io/app/20221206_protopedia-badge

# やり方

Protopediaのアカウント名を入れるだけ！

![20240107-141408-4d61013a.png](https://gachimoto-qiita-storage.s3.amazonaws.com/20240107-141408-4d61013a.png)

~~~
# posts
[![ProtoPedia posts](https://vercel-serverless-functions-henna.vercel.app/api/protopedia?username=gachimoto&post=true)](https://protopedia.net/prototyper/gachimoto)
# views
[![ProtoPedia views](https://vercel-serverless-functions-henna.vercel.app/api/protopedia?username=gachimoto&view=true)](https://protopedia.net/prototyper/gachimoto)
# good
[![ProtoPedia good](https://vercel-serverless-functions-henna.vercel.app/api/protopedia?username=gachimoto&good=true)](https://protopedia.net/prototyper/gachimoto)
~~~

# posts
[![ProtoPedia posts](https://vercel-serverless-functions-henna.vercel.app/api/protopedia?username=gachimoto&post=true)](https://protopedia.net/prototyper/gachimoto)
# views
[![ProtoPedia views](https://vercel-serverless-functions-henna.vercel.app/api/protopedia?username=gachimoto&view=true)](https://protopedia.net/prototyper/gachimoto)
# good
[![ProtoPedia good](https://vercel-serverless-functions-henna.vercel.app/api/protopedia?username=gachimoto&good=true)](https://protopedia.net/prototyper/gachimoto)

お疲れさまでした
SlackのチャンネルIDの確認方法


# ブラウザのURLから確認する方法

チャンネルを表示すると、ブラウザのURLが下記にのようになるはずなので、そこから取得できます。
```
https://app.slack.com/client/ワークスペースID/チャンネルID

https://app.slack.com/client/TXXXXXXX/CXXXXXXX
```


https://slack.com/intl/ja-jp/help/articles/221769328-Slack-URL-%E3%81%BE%E3%81%9F%E3%81%AF-ID-%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B


# チャンネル詳細から確認する方法

チャンネル名を右クリック→「チャンネル詳細を表示する」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703223/ad823b85-d9d4-a826-89fe-96eb8e463dba.png)

チャンネル情報タブの下部にチャンネルIDが表示されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703223/5ccf01d8-f733-f9ee-e6a8-21f646c08b90.png)

こちらはブラウザでもデスクトップアプリでも確認可能
なんでもテストできると思うなよ~シナリオテストでカバーできないリスクとその対処~

# はじめに
シナリオテストは自由度が高く、色々なシチュエーションや目的に対応できるとても便利な手法ですが、あらゆるケースに対応できるわけではありません。
そういったケースでは、別のテスト方法を使ってリスクを回避することが有効です

この記事では、シナリオテストでカバー出来ないリスクについて、その対処法をまとめます。


# リスクと対処法
|リスク|障害の例|対処法|
|---|---|---|
|デプロイ手順ミス|バッチが動かない など|環境構築手順書をレビューする<br>環境構築して正しく動くか確認する|
|環境変数設定ミス|指定日よりも前に活性化する など|設定ファイルをレビューする|

# シナリオテスト一本槍にならないために
どうすればシナリオテスト以外の選択肢を選べるのか、自分の経験ベースで考えてみた結果、以下の4つを意識することが重要と考えます。
- テストの目的をはっきりさせる
- プロジェクトメンバーの興味・関心事に興味を持つ
- 本番-テストでの違いを意識する
- テストのコストに興味を持つ

の３つを意識すると、プロジェクト視点で良い選択が選べるとおもいます。

(理由はおいおい書きます)

# 最後に
書いてみたものの気づいてないリスクが他にもある気がしています。
お気づきの方はコメントいただけるとありがたいです
MacでRustの環境構築

- Xcodeをインストール
```bash
xcode-select --install
```

- rustupをインストール
```bash
% curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 対話が始まるが、気にせずEnterでOK！
...
% source "$HOME/.cargo/env"

% rustup -V
rustup 1.26.0 (5af9b9484 2023-04-05)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.72.1 (d5c2e9c34 2023-09-13)`

% rustc -V
rustc 1.72.1 (d5c2e9c34 2023-09-13)

% cargo -V 
cargo 1.72.1 (103a7ff2e 2023-08-15)
```

- プロジェクトの作成
```bash
cargo new new_project
```

- フォルダをすでに作ってしまったなら中に入って初期化
```bash
cargo init
```
MLB日本人ピッチャー分析：2023年シーズンの投球データ

今季のMLB日本人選手の投球結果を確認する。<br>データは、pybaseballから取得。取得コードは以下。

*   579328　菊池
*   628317　前田
*   506433　ダルビッシュ
*   673540　千賀
*   660271　大谷
*   660261　藤浪

# データ取得のコード

    !pip install pybaseball
    from pybaseball import statcast
    import pandas as pd
    df = statcast(start_dt='2023-03-30', end_dt='2023-12-31')

    # 選手IDのリスト
    player_ids = [579328, 628317, 506433, 673540, 660271, 660261]

    # 各選手のデータを抽出
    pitchers_data = df[df['pitcher'].isin(player_ids)]

以下にグラフを表示していく。コード省略

# フォーシームFF : リリースポジション と 水平方向 pfx_x、垂直方向 pfx_z の変化量 の関係

この画像は、pybaseballライブラリを使用して、特定のピッチタイプ（この場合はフォーシーム・ファストボール、FF）に関するデータを抽出し、ビジュアライズしたものです。

ピッチの水平方向と垂直方向の動き（pfx_xとpfx_z）をビン化し、そのビンに対してリリースポジション（release_pos_xとrelease_pos_z）のboxplotを取っている

*   菊池投手　![](https://pbs.twimg.com/media/GDPbbghbYAA9mkt?format=png\&name=4096x4096)

*   前田投手 ![](https://pbs.twimg.com/media/GDPbdWmaYAAGb1d?format=png\&name=4096x4096)

*   ダルビッシュ投手 ![](https://pbs.twimg.com/media/GDPbe4absAAfUsT?format=png\&name=4096x4096)

*   千賀投手 ![](https://pbs.twimg.com/media/GDPbhCWbwAAd6at?format=png\&name=4096x4096)

*   大谷投手 ![](https://pbs.twimg.com/media/GDPbibpbIAAQZ8W?format=png\&name=4096x4096)

*   藤浪投手 ![](https://pbs.twimg.com/media/GDPbjmlbAAA3KPe?format=png\&name=4096x4096)

# スライダーSL : リリースポジション と 水平方向 pfx_x、垂直方向 pfx_z の変化量 の関係

*   菊池投手　![](https://pbs.twimg.com/media/GDPeczTbAAAjgh0?format=png\&name=4096x4096)

*   前田投手  ![](https://pbs.twimg.com/media/GDPeeg6asAEHERI?format=png\&name=4096x4096)

*   ダルビッシュ投手 ![](https://pbs.twimg.com/media/GDPet3ua8AA-wFW?format=png\&name=4096x4096)

*   千賀投手 ![](https://pbs.twimg.com/media/GDPev5taQAAIRX5?format=png\&name=4096x4096)

*   大谷投手 ![](https://pbs.twimg.com/media/GDPexScaMAANVCC?format=png\&name=4096x4096)

*   藤浪投手 ![](https://pbs.twimg.com/media/GDPeyvQbsAEYLSh?format=png\&name=4096x4096)

# スイーパーST : リリースポジション と 水平方向 pfx_x、垂直方向 pfx_z の変化量 の関係

No ST data for player 579328 - kikuchi<br>
No ST data for player 628317 - maeda

*   ダルビッシュ投手 ![](https://pbs.twimg.com/media/GDPfY1BbQAA4ash?format=png\&name=4096x4096)

*   千賀投手  ![](https://pbs.twimg.com/media/GDPfaK6aEAATwfq?format=png\&name=4096x4096)

*   大谷投手 ![](https://pbs.twimg.com/media/GDPfbobakAAb_NR?format=png\&name=4096x4096)

*   藤浪投手 ![](https://pbs.twimg.com/media/GDPfdD7bAAAdzZB?format=png\&name=4096x4096)

# フォーシームFF : 水平方向（PFX_X）と垂直方向（PFX_Z）の動き

日本人選手が投げるフォーシーム・ファストボール（FF）の特性を可視化するためのものです。具体的には、ピッチの水平方向（PFX_X）と垂直方向（PFX_Z）の動きをセンチメートル単位で分析しています。

![](https://pbs.twimg.com/media/GDPhx-bbAAAZgry?format=png\&name=large)

菊池投手だけは、左投げなのでX方向のデータが離れている

# スイーパーST : 水平方向（PFX_X）と垂直方向（PFX_Z）の動き

![](https://pbs.twimg.com/media/GDPh8HIaQAAix23?format=png\&name=large)

大谷投手よりダルビッシュ投手のほうが横滑りしている
初学者がすぐできるクエリチューニング

# SQLチューニングのクエリチューニング

**クエリチューニングについて**

つい最近MySQLを学び、少しずつデータベースの挿入・更新・取得のクエリが書けるようになってきた初学者です。
そんな状況の次に見えてきた、クエリの書き方で処理速度が変わるという目を背けられなさそうな課題ワード、SQLチューニング。しかし調べればきりがなく出てくる出てくる。そんな状態なので初学者にとってこれは取り入れやすいというものをまとめていきます。
処理速度改善の優位性よりもしっかりと、取り入れられることに優位性をもたせた内容です。
いっぱいあってなにも取り入れられないよりも、厳選してでも必ず取り入れられるものをしっかり意識した方がまだいいのではないかという考えです。

ということでSQLチューニングでもまずはすぐに実践できるクエリチューニングについてまとめようと今回の記事を作成します。

## SELECT * を乱用しない
テーブル内の特定のカラムのみが必要なのであれば、必要なカラムのみを取得する。
必要のないデータを取得すれば、単純に無駄な処理が発生する。
便利だからって甘えない！

## WHERE句でカラムの演算を利用しない
SELECT句でカラムに対して演算や関数を利用することは多々あると思います。
しかしWHERE句でインデックスが貼られているカラムに対して利用すると、インデックスをオプティマイザが判断できなくなってしまうためのようです。

:::note
SELECT * FROM テーブル　WHERE カラム名 = '大文字';
こういうときにもワイルドカードは便利w
:::

:::note warn
SELECT * FROM テーブル　WHERE UPPER(カラム名) = '小文字列など';
:::

## SQLの予約語を大文字・小文字を統一して記述する？
色々と調べるなかでこの情報が出てきたのですが、実際に処理速度が変わる時と変わらないときがあるのでクエリチューニングと言えるのか...。
しかしSQLスタイルガイドにも記述されている。そして統一した方がクエリも読み書きしやすいのでコード記述速度が改善するため取り入れたいため採用！

## テーブル名にエイリアスをつけると処理速度が早くなる？
こちらも昔のSQLのバージョンでは効果があったようです。またケースによっては、多少処理速度が改善するようでした。
私はエイリアスを利用すると、JOIN句を利用したときに読み書きしやすいと感じるため採用しました。
JOINを利用しているときには、テーブルのカラムがわかりやすくなる便利！と感じました。
一応、

:::note
SELECT  FROM テーブル名 AS テーブル略称;
:::

## サブクエリをなるべく使わない
こちらを利用すると仮テーブルとやらが作成されるため、データ量が増加することから処理が重くなるようです。
なので対応可能であれば、JOINを利用する。
こうなったときに、記述のストレスを少しでも軽減できるエイリアスの力をお借りします！

## インデックスをしっかりと活用する
こちらも結構色々なパターンが存在したので、即採用できそうなことから
- **インデックスカラムに対してSQL関数を利用すると、インデックスが効かない**

:::note warn
CAST(), SUM(), FORMAT(), SUBSTR(), UPPER() ...　など
:::

- **WHERE句の左辺側で算術演算子を使わない**

:::note
WHERE インデックスカラム　> カラム　ー　1000 ;
:::
:::note warn
WHERE インデックスカラム　　＋　 1000 　< 　カラム　;
:::


現状は、上記のクエリチューニングをしっかりと身につけて、クエリと仲良しになれた際にはもっと追加していこうと思います！！
Command CodeSign failed with a nonzero exit codeエラーを回避する

# エラー内容
iPhone実機へビルドした際に以下エラーが発生し、実機ビルドできなくなってしまった。
```
Command CodeSign failed with a nonzero exit code
```

# 対応
正直完全に何故このエラーが発生したかがまだ理解できていないが以下の手順を実施しビルドが成功する様になった。

1 ビルドフォルダーのクリーンアップ

Product > Clean Build Folderをクリックしクリーンアップ

2 Xcode再起動
3 ターミナルでプロジェクトフォルダのルート階層へ移動し、以下コマンドを入力
```
$ xattr -rc .
```

4 その後再度起動しビルドで、実機へビルドできた。


正直原因が謎だが、備忘として記録する。
「CORS」について学んだこと

Laravel学習中にCORSに触れることがありました。
「CORSってなんだ？」という状態から調べたことをまとめてみます。
私と同じような方のご参考になれば嬉しいです。

# CORSとは
**= Cross-Origin Resource Sharing**を省略したもので、
オリジンが違うプログラム同士のデータ通信のことをCORSといいます。

これだけ言ってもなんのことやら分からないと思います(私は最初頭の中がハテナでいっぱいでした。)。

## オリジンってなに？
CORSの説明にでてきたオリジンとは、ウェブコンテンツにアクセスするために使われるURLの**スキーム(プロトコル)＋ホスト(ドメイン)＋ポート番号**で構成される組み合わせのことです。
`http://example.com:80`を例に分けてみると、以下のようになります。
|スキーム(プロトコル)|ホスト(ドメイン)|ポート番号|
|:----:|:----:|:----:|
|http://|example.com|:80|

**スキーム、ホスト、ポート番号が全て一致　＝　同一オリジン
スキーム、ホスト、ポート番号が1つでも違うものがある　＝　クロスオリジン**
とされます。

アクセスする先と、アクセス元のオリジンについて、
・オリジンが同じ場合、内容にかかわらず通信が成功する
・オリジンが異なる場合(＝クロスオリジン)、**同一オリジンポリシー**という制約が発生する
という決まりがあります。

:::note info
**同一オリジンポリシーとは**
セキュリティの仕組み。簡単に言うと、
「同一オリジンであれば、リソースへのアクセスは出来るけど、クロスオリジンであればアクセスできる方法を制限するよ」
というもの。これにより、悪意あるアクセスを防ぐことができます。
:::

このようなセキュリティの為の仕組みを調整して、クロスオリジンにアクセスできるように設定することをCORS対策と言います。
簡単にいうと
**「いろんな便利なサービスを、他のところでも共有できるようにしよう!」**
ということです。

# 実際どうやって設定するの？
私が学習に使用していた、`Laravel Framework 10.39.0`での話になります。
おそらく「Laravel CORS」とかで検索すると、
```
composer require fruitcake/laravel-cors
```
でインストールする方法などが出てくると思うのですが、
**Laravel 7.0以降であれば初期状態で既にインストールされています！！**
なので、`config/cors.php`を使用してCORS対策をすればOK。
`cors.php`のデフォルトの状態はこんな感じ。CORSヘッダーを出力するパスのパターン`api/*`, `sanctum/csrf-cookie`のみを許可する設定になっている。
```php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */
    'paths' => ['api/*', 'sanctum/csrf-cookie'],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,

];

```
## それぞれの意味について
### 'paths' => ['api/*', 'sanctum/csrf-cookie']
CORSヘッダーを出力するパスのパターン、任意でワイルドカード(*)が利用OK。空だと一切のルートで機能しない。
・APIを対象にする場合: ['api/*']
・全てのルートを対象にする場合: ['*']

### 'allowed_methods' => ['*']
マッチするHTTPメソッド。['*']だと全てのメソッドを許可。
・GET,POST,PUT,DELETE のみ許可する：['GET', 'POST', 'PUT', 'DELETE']

### 'allowed_origins' => ['*']
許可するリクエストオリジンの設定。`*`かオリジンに完全一致、またはワイルドカードが利用可。

# まとめ
CORSはオリジンが違うプログラム同士のデータ通信であり、これが安全に行われる為にCORS対策が必要です。
どこまで許可するかは、セキュリティや利便性など様々な視点から設定する必要があります。
最もよく起こりうることを先に判定せよ

```Python
if condition:
    continue
else:
    something()
```

 の意味と，「最もよく起こりうることを先に判定せよ」というのは違うのではないか。
 確かに以下のような場合には　　`i < 0.8` を先に判定するほうが良いが，それとこれとは違う。

 ```python
#---
import numpy as np
from time import time
n = 100000000
x = np.random.rand(n)

s = time()
s1, s2, s3 = 0, 0, 0
for i in x:
    if i < 0.8:
        s1 += 1
    elif i < 0.9:
        s2 += 1
    else:
        s3 += 1
print(s1, s2, s3, time() - s)

        
```

    79997428 9999472 10003100 10.772604942321777



```python
s = time()
s1, s2, s3 = 0, 0, 0
for i in x:
    if i > 0.9:
        s3 += 1
    elif i > 0.8:
        s2 += 1
    else:
        s1 += 1
print(s1, s2, s3, time() - s)

```

    79997428 9999472 10003100 11.210047960281372
【swift:】'async' call in a function that does not support concurrency エラー

## 問題
以下のコードで `'async' call in a function that does not support concurrency` というエラーが出ました。
```swift
do {
	// ここでエラー発生
	let (data , _) = try await URLSession.shared.data(from: req_url)
	let decoder = JSONDecoder()
	let json = try decoder.decode(ResultJson.self, from: data)
	
	print(json)
} catch {
	print("error")
}
```

## 解決
どうやらawaitは非同期コンテンツから呼び出す必要があるらしいです。そこでTask{}で囲むことで、ブロック内の処理を非同期でひとまとまりに実行できます。以下のように変更するとエラーは消えてくれました。
```swift
Task{
	do {
		let (data , _) = try await URLSession.shared.data(from: req_url)
		let decoder = JSONDecoder()
		let json = try decoder.decode(ResultJson.self, from: data)
		
		print(json)  
	} catch {
		print("error")
	}
}
```
YOLOv8で画像認識元のパスをローカルから読み込ませたいがエラーが出る Google colaboratory


Google colaboratoryでＹＯＬＯを使おうとしたら

~~~
%cd {HOME}
# This source will be the image I want to output
!yolo task=detect mode=predict model=yolov8n.pt conf=0.25 source='xxxxxxx(ここはGoogle Driveの画像を読み込ませたくてシェア用パスを入れてました。ここが原因)'
~~~

をやった時

エラー文章



~~~
/content
Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n.pt to 'yolov8n.pt'...
100% 6.23M/6.23M [00:00<00:00, 81.2MB/s]
Ultralytics YOLOv8.0.196 🚀 Python-3.10.12 torch-2.1.0+cu121 CUDA:0 (Tesla T4, 15102MiB)
YOLOv8n summary (fused): 168 layers, 3151904 parameters, 0 gradients, 8.7 GFLOPs

[ERROR:0@6.232] global cap.cpp:164 open VIDEOIO(CV_IMAGES): raised OpenCV exception:

..
.
.
.
Failed to open https://drive.google.com/file/d/11wsHOXQKVSS-FQoh-ZOeP0LAcCumq-rZ/view?usp=sharing
~~~

がでた

## 原因

Google Colabからローカルのファイルを直接的に読み込むことはできません。Colabはクラウドベースの環境であり、ローカルマシン上のファイルには直接アクセスできない

とのこと。
つまり、Google drive内のものを直接読めるようにしないといけなくてその準備が足りなかったことになります。



# 解決方法


### Google Driveのマウント:
Google ColabでGoogle Driveをマウントすることができます。Google Driveにファイルをアップロードしておき、Colabからアクセスできるようにすることができます。

https://magicode.io/mua408905/articles/94dc6169f431479e97e77dcc880d7dc2



### 直接アップロード:
Colabのセッションにファイルをアップロードすることができます。Colabの左側のサイドバーにある「ファイル」タブから、ファイルをアップロードできます。

例えば、Google Driveをマウントした場合、以下のようにしてローカルファイルをColab上で扱うことができます。

~~~
from google.colab import drive
drive.mount('/content/drive')

### ファイルのパスを指定して読み込み
file_path = '/content/drive/My Drive/path_to_your_file.txt'
with open(file_path, 'r') as file:
    content = file.read()

~~~


# memo

Google Driveを結局自分は使いましたがＧｏｏｇｌｅＤｒｉｖｅはファイルパスを自分で手打ちしなければいけないのであまり階層深すぎたり複雑な名前にしていると大変です。気を付けましょう。
Raspberry Pi 4Bと時雨堂のmomo（2）

# 1. はじめに
以下で時雨堂のmomoのローカル動作が確認できたのでインターネット越しの動作を確認したい。

https://qiita.com/tetsuoMikami/items/30eab5bfc793ecfd784f

時雨堂が用意している無料サービスがあるので、それで試してみることにした。尚、今回はブラウザで受信のみ確認する。
https://ayame-labo.shiguredo.app/

# 2. 機材
* Raspberry Pi 4B
* UVCカメラ: Buffalo BSW500M

# 3. 動作確認
# 3.1. momoに与えるコマンド
Ayame Laboという実験に使えるサイトを使う。自分自身でサーバー立てるのは最初はしんどいのでありがたい。

* --no-audio-device はマイクがないことを示す。
* --resolution HD は最大解像度
* --framerate 30 はフレームレート
*  --fixed-resolution は解像度を固定する。固定しない場合、小さい解像度から順に上がる。
*  ayame はアヤメモードを示す。
*  --signaling-url wss://ayame-labo.shiguredo.app/signaling ここは固定
*  --room-id 0123456789 ルームIDはランダムな値を使うべき。

```
 ./momo --no-audio-device --resolution HD --framerate 30 --fixed-resolution ayame --signaling-url wss://ayame-labo.shiguredo.app/signaling --room-id 74gxi5tihdbi
```

# 3.2. Webでの確認
Webからカメラ映像を見たいだけなので、受信のみのページを開く。
https://openayame.github.io/ayame-web-sdk-samples/recvonly.html

ルームIDに、momoの起動時に設定したランダム値を指定する。映像コーデックは特に指定しなくても動作し、クライアントIDはページを開いた時からセットされている。
この状態で、「接続」を押すと映像が見られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/bc1873f3-e3f5-c3e6-3af7-fb02cb657f3e.png)
※映像の部分はモザイクしてある。大した画像でもないけど。

# 4. 今後
* 自力でayameサーバーを立てたい。
* 受信のみだけでなく双方向なども確認したい。
ACID特性についてまとめる

# まずトランザクションとは
ひとまとまりで実行されるべき1つ以上の更新処理の集まりのこと。
データベースにおける処理の確定や取り消しを管理することができる。
# ACID特性
ACID特性とは、トランザクションを定義する４つの特性のこと。**ACID**はその4つの特性の頭文字である。
1. Atomicity (原子性)
1. Consistency (一貫性)
1. Isolation (独立性)
1. Durability (持続性)
## Atomicity (原子性)
データの変更を伴う一連のデータ操作が、すべて実行される (**COMMIT**) か、すべて実行されない (**ROLLBACK**) かを保証する性質。
トランザクションが中途半端な終わり方をすることを防ぐ。
## Consistency (一貫性)
トランザクションに含まれる処理は、データベースにあらかじめ設定された制約を満たすという性質。
例えば、NOT NULLの列をNULLに更新するとエラーになり実行できなくなる。
## Isolation (独立性)
トランザクション同士が影響を受けないことを保証する性質。
一連のデータ操作が複数のユーザーから同時に行われる際に、それぞれの処理が矛盾なく行えるようになる。
## Durability (持続性)
トランザクションが COMMIT や ROLLBACK で終了したら、その時点でのデータの状態が保存されることを保証する性質。
アクシデントが起きた際に、実行記録(ログ)を使って以前の状態に復旧できるようになる。
# まとめ
また簡潔にまとめてみました。アウトプットをすることで頭に入っていくような感覚があります。次回からはもっと内容の濃いことを書けたらいいなあ。
GithubPagesの参考ページについて

GithubPagesのマニュアルについては、いかに存在して参考となるgithubの情報についても情報として`GitHub Pages サンプル コレクション`のように載っている。
https://docs.github.com/ja/pages
https://docs.github.com/ja/pages/getting-started-with-github-pages/about-github-pages

一部URLとなるが、以下のように接続すると確認をできた。
https://square.github.io/
https://yelp.github.io
https://netflix.github.io
https://jekyll.github.io
[spreadsheet] 1日の始まりの日時を求めるのに DATEVALUE を使うな！

# TL;DR (3行で要約)

- `DATEVALUE` は引数を文字列に変換してしまう
- 1日の始まりの日時を求めるのには `INT` や `FLOOR` を用いる
- もちろん `DATE(YEAR(値),MONTH(値),DAY(値))` でもよい

# はじめに

1日の始まりの日付時刻を求めるには、day.js なら以下のように書けます。

```javascript
const datetime = dayjs();
const day = datetime.startOf('day');
```

Carbon なら以下のようになります。

```php
use Carbon\CarbonImmutable;

$datetime = CarbonImmutable::now();
$day = $datetime->startOfDay();
```

# 問題点

スプレッドシートでこれを行うには、[DATEVALUE](https://support.google.com/docs/answer/3093039?hl=ja) が使えそうですが、これを行うと、一度文字列に変換されてしまうため、意図した結果にならないことがあります。[数値を切り捨てるのに parseInt を使ってはいけない](https://paulownia.hatenablog.com/entry/2016/08/31/110322)のと似たような話ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78152/3ecd7844-4fbc-312c-b7cf-d268e5aa62bb.png)

# 解決策

で、どうすれば良いのかというと、スプレッドシートの日時データはとある日からの経過日数を表すただの数値なので、`INT` や `FLOOR` で切り捨ててあげれば良いわけですね。欠点としては数式を入力した際のデフォルトの表示形式が日付にならないことですが、手動で書式設定をする代わりに `TO_DATE` で囲ってあげるという回避策もあります。

もちろん `DATE(YEAR(B1),MONTH(B1),DAY(B1))` の方が分かりやすいと思うのであればそう書いても大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78152/20a04692-ad79-c45e-55cc-6643c27e79b8.png)

ちなみに `DATEVALUE` と異なり `TO_DATE` は 時・分・秒の情報を削除しません。

# 発展問題

では0時0分を求めるにはどうすれば良いでしょうか。24を乗じて切り捨てるのが簡単ですが、誤差がどうなのか気になりますね。いつか時間があればそちらも試してみたいと思います。

# おわりに

スプレッドシートは自動での型変換が多く難しいです……。
この時代にVisual Basicの勉強をする：書籍など

# はじめに
今更ながらVB.Netを勉強することになりました。
さて、勉強するにしても何から手を付ければよいやら。
ということで書籍を当たってみました。

# 書籍検索
とりあえずKindle Unlimitedで良いものがないか検索。
Kindle Unlimitedは中身をザっと適当に見てから用途にあっているか判断をできるのが良いですね。
何冊か見たところ、以下がVB.Netを理解するのに良さそうでした。
[基礎Visual Basic 2019 基礎シリーズ Kindle版](https://www.amazon.co.jp/dp/B07Z65GXBW)


ちなみにKindle Unlimitedにこだわらないなら最新版が出てますのでそっちの方が良いでしょう。
[基礎Visual Basic 2022 基礎シリーズ Kindle版](https://www.amazon.co.jp/gp/product/B0B4HZN1L3)
2024年1月初旬、半額キャンペーンで1760円でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367457/c77e6a3b-f2c4-3020-1fc6-9f00092fd7bf.png)



# その他チュートリアル
あとはMicrosoftのチュートリアルなど見ていくのが良さそうです。

https://learn.microsoft.com/ja-jp/visualstudio/get-started/visual-basic/visual-studio-ide?view=vs-2022

https://learn.microsoft.com/ja-jp/visualstudio/get-started/visual-basic/tutorial-console?view=vs-2022

https://learn.microsoft.com/ja-jp/visualstudio/ide/create-a-visual-basic-winform-in-visual-studio?view=vs-2022

https://learn.microsoft.com/ja-jp/visualstudio/get-started/visual-basic/?view=vs-2022
M1 MacにTensorflowをインストールするときにいつもググってしまうのでもうググらないために残しておくメモ

# M1 MacにTensorflowをインストール

すでに沢山の類似記事があると思いますが、
自分の環境用に備忘録として残しておきます。

## Command Line Tools for Xcode のインストール
インストールしたらバージョンを確認

    $ xcode-select --install
    $ xcode-select -v

## 仮想環境を整える
[Miniforge] https://github.com/conda-forge/miniforge からMiniforge3-MacOSX-arm64をダウンロードする
以下を実行するとMiniforgeがインストールされる

    bash /(Miniforge3-MacOSX-arm64.shのあるディレクトリ)/Miniforge3-MacOSX-arm64.sh

その後、Tensorflowを他のQiitaの記事を参考にしてインストールしてみたのですが、どうにも動かないのでM1Mac用に最適化されたTensorflow-metalを配布してくれてる[サイト]https://developer.apple.com/metal/tensorflow-plugin/ を参考にインストール
サイトの指示通りにインストールする

    python3 -m venv ~/venv-metal
    source ~/venv-metal/bin/activate
    python -m pip install -U pip
    python -m pip install tensorflow
    python -m pip install tensorflow-metal

サイトにある以下のテストコードを実行して問題なく動いているか確認した
~~~
import tensorflow as tf

cifar = tf.keras.datasets.cifar100
(x_train, y_train), (x_test, y_test) = cifar.load_data()
model = tf.keras.applications.ResNet50(
    include_top=True,
    weights=None,
    input_shape=(32, 32, 3),
    classes=100,)

loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False)
model.compile(optimizer="adam", loss=loss_fn, metrics=["accuracy"])
model.fit(x_train, y_train, epochs=5, batch_size=64)
~~~

結果：
~~~
(venv-metal) (base) **＊＊@MacBook-Air ML_rust % python3 test_TF.py 
2024-01-07 15:36:21.721201: I metal_plugin/src/device/metal_device.cc:1154] Metal device set to: Apple M1
2024-01-07 15:36:21.721223: I metal_plugin/src/device/metal_device.cc:296] systemMemory: 16.00 GB
2024-01-07 15:36:21.721228: I metal_plugin/src/device/metal_device.cc:313] maxCacheSize: 5.33 GB
2024-01-07 15:36:21.721270: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:306] Could not identify NUMA node of platform GPU ID 0, defaulting to 0. Your kernel may not have been built with NUMA support.
2024-01-07 15:36:21.721302: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:272] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory) -> physical PluggableDevice (device: 0, name: METAL, pci bus id: <undefined>)
Epoch 1/5
2024-01-07 15:36:24.654776: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:117] Plugin optimizer for device_type GPU is enabled.
782/782 [==============================] - 490s 612ms/step - loss: 4.6229 - accuracy: 0.0816 
Epoch 2/5
782/782 [==============================] - 112s 143ms/step - loss: 4.1233 - accuracy: 0.1355
Epoch 3/5
782/782 [==============================] - 109s 140ms/step - loss: 3.7688 - accuracy: 0.1725
Epoch 4/5
782/782 [==============================] - 109s 140ms/step - loss: 4.3786 - accuracy: 0.1044
Epoch 5/5
782/782 [==============================] - 109s 139ms/step - loss: 4.1251 - accuracy: 0.1058
~~~
無事終了した
ここまで青息吐息だったので後で記事を整えます。
【Android】GoogleMap上に円や線を表示する【Kotlin】



# 線を表示

    googleMap.addPolyline(
            PolylineOptions()
                .color(R.color.red)
                .add(LatLng(35.689, 139.692), LatLng(35.666116, 139.758380))
                .width(20f)
        )


|プロパティ|内容|その他|
|:---|:---|:---|
|Points|線の頂点。線分は連続した点の間に描画される。|頂点数は最大16000まで。上限を超えた頂点は描画されない。
|width|線の幅|カメラのズームとは無関係に、一定に保たれる。デフォルトは10。
|color|線の色|デフォルトは黒(0xff000000)
|visible|地図上に表示されているかどうか、trueなら表示|デフォルトはtrue
|clickable|オブジェクトをクリックしたときのイベントをハンドリングしたい場合は、このプロパティにtrue|デフォルトはfalse
|zIndex|描画する順番|デフォルトは0

        
#  円を表示

     googleMap.addCircle(
            CircleOptions()
                .center(LatLng(35.689, 139.692))
                .radius(1000.0)
                .strokeColor(R.color.black)
                .fillColor(R.color.red)
                .strokeWidth(5f)
                .visible(true)
                .clickable(true)
        )


|プロパティ|内容|その他|
|:---|:---|:---|
|center|緯度、経度で円の中心位置|nullの場合、IllegalArgumentExceptionのエラー
|radius|メートルで円の半径|0以下の場合、IllegalArgumentExceptionのエラー
|StrokeWidth|円の輪郭線の幅|デフォルトは10
|strokeColor|円の輪郭線|デフォルトは黒(0xff000000)
|fillColor|円の塗りつぶし色|デフォルトは透明(0x00000000)
|visible|地図上に表示されているかどうか、trueなら表示|デフォルトはtrue
|clickable|オブジェクトをクリックしたときのイベントをハンドリングしたい場合は、このプロパティにtrue|デフォルトはfalse
|zIndex|描画する順番|デフォルトは0



# 参考

https://developers.google.com/maps/documentation/android-sdk/shapes?hl=ja

https://support.e-map.ne.jp/manuals/ref/Android/com/zdc/android/zms/maps/model/Polyline.html


https://support.e-map.ne.jp/manuals/ref/Android/com/zdc/android/zms/maps/model/Circle.html
ReactでHygenを活用する

## はじめに
Hygenはコードジェネレーターで、繰り返し発生するコードのテンプレートを簡単に作成し、使用するためのツールです。
開発の生産性を向上させるために利用されます。

![スクリーンショット 2024-01-07 20.37.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/5a5b18db-5055-6e7a-78af-7950487f94ed.png)

https://www.hygen.io/

## ソースコード

```shell:ライブラリのインストール
~/develop/react_template/react_firebase$ yarn add hygen --dev
```

```shell:ディレクトリ作成
~/develop/react_template/react_firebase$ tree _templates 
_templates
└── component
    └── new
        └── with-prompt.ejs.t

3 directories, 1 file
```
:::note info
設定ファイルをルートディレクトリに作成します。
hygenのファイルは下記コマンドでも作成できるため、紹介しておきます。
```ts:hygenの設定ファイル作成
~/develop/react_template/react_firebase$ yarn hygen init self
yarn run v1.22.19
$ /Users/kawamurakouji/develop/react_template/react_firebase/node_modules/.bin/hygen init self

Loaded templates: node_modules/hygen/src/templates
       added: _templates/generator/help/index.ejs.t
       added: _templates/generator/with-prompt/hello.ejs.t
       added: _templates/generator/with-prompt/prompt.ejs.t
       added: _templates/generator/new/hello.ejs.t
       added: _templates/init/repo/new-repo.ejs.t
✨  Done in 0.18s.
```
:::


## 設定ファイル作成
```tsx:_templates/component/new/with-prompt.ejs.t
---
to: src/components/<%= h.changeCase.pascal(name) %>.tsx
---
export const <%= h.changeCase.pascal(name) %> = () => {
  return (
    <div>
      {/* コンポーネントの内容 */}
    </div>
  );
};
```
→今回はReactのため、ReactのTemplateを作るコマンドを用意しました。

## 実行
```shell:コンポーネント作成

Loaded templates: _templates
       added: src/components/Component.tsx
```

```tsx:src/components/Component.tsx
export const Component = () => {
  return (
    <div>
      {/* コンポーネントの内容 */}
    </div>
  );
};

```
→できてました！！！
データベース操作 / 基本コマンドまとめ

## はじめに
《記録用》
データベースを操作するにあたって、基本的となる操作をまとめました。

## MySQL
```:起動コマンド
mysql. server start
```
  
```:MySQLにログイン
mysql --user=root --password
```
( root=ログインするユーザー名によって変更する)  
→実行後パスワードを入力。  
```
mysql >
```
と表示されたらログイン完了!

```:ログアウト
exit;
```
→Byeと表示されたらログアウト完了♪

## データベース
 まずはデータベースを作成します。
```:データベースの作成
create database データベース名;
```

```:データベースの一覧表示
show databases;
```

```:データベースの選択
use データベース名;
```

```: データベースの削除　(注意して使う)
drop database データベース名;
```
## テーブル

```:テーブルの作成
creat table データベース名.作りたいテーブル名 (カラム名 データ型, カラム名 データ型);
```
```
→ 例 : create table step2.Season (id bigint(20), program_id bigint(20));
```
- 作成したいカラムが複数ある場合は()の中にカラム名、データ型を続けて入力する。


```:テーブルの一覧表示
show tables;
```

```:テーブルのデータ削除
delete from テーブル名;
```

```:条件に一致したレコードの削除(注意して使う)
delete from テーブル名　  
where 条件式;
```
例　）"employees"テーブルから"department"が"HR"であるレコードを削除する場合
```
DELETE FROM employees
WHERE department = 'HR';
```
「ILI9341」に文字列を表示(Arduino)(STM32G071)(改)



目的
「ILI9341」を使う事によって盛り上げる
いろいろ
説明不足だけど前後から読み取ってね
正式名は、
X-NUCLEO-GFX01M1
XNGF01M1$AZ1
リセット関連の調査と改良(20240107)

![o_cop885.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/9da97044-b412-f115-c957-9a0744c0e5a6.jpeg)


```c++




//ili9341_text1_071_2

//インクルド
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

//設定
#define TFT_RST 54 //A1
#define TFT_DC 3
#define TFT_CS 4

//液晶の定義
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

//初期化
void setup() {

  //シリアルの初期化
  Serial.begin(9600);
  Serial.println("ILI9341 Test!"); 

  //液晶の初期化
  tft.begin(); 

  //画面のクリア
  tft.fillScreen(ILI9341_BLACK);
  
  //表示位置を0,0にする
  tft.setCursor(0, 0);

  //テキストの表示
  tft.setTextColor(ILI9341_RED);
  tft.setTextSize(3);
  tft.println("Hello World!");

}//setup


//無限ループ
void loop(void) {
}//loop



```
<GraphQL> graphql-codegen の設定を grpahql-configに移行する


# はじめに

[GraphQL 成熟度モデル](https://oisham.hatenablog.com/entry/2023/05/01/141829) の記事を読んで、「あ、やベェ LSP の対応していない」となったので、対応しました。と言っても、VSCode の[拡張機能](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql)を入れただけなのですが、設定ファイルが graphql-codegen と重複するため、設定ファイルを[graphql-config](https://the-guild.dev/graphql/config/docs)へ移行しました。移行方法です。

# 前提

- graphql: v16
- graphql-codegen/cli: v5
- graphql-config: v5

もともと codegen の config ファイルは`codegen.ts`という ts ファイルに存在している。

# 詳細

## 1. 拡張機能を入れる

https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql

拡張機能の説明を見ると、root の `graphql-config file` を見ると書いてあるので graphql-config file を入れていく

## 2. graphql-config

```bash
$ npm i graphql-config
```

ファイル形式は yml でも ts でも色々いけるが同じく ts に移した
参考: https://the-guild.dev/graphql/config/docs/user/usage

```bash
$ touch .graphqlrc.ts
```

## 3. 移す

```codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: [...],
  documents: [...],
  generates: {
    '<path>': {
      ...
    }
  },
}
```

`extensions.codegen`の中に移す必要があるので間違えないように

```.graphqlrc.ts
import type { IGraphQLConfig } from 'graphql-config'

const config: IGraphQLConfig = {
  schema: [...],
  documents: [...],
  extensions: {
    codegen: {
      generates: {
        '<path>': {
          ...
        }
      }
    }
  }
}
```

# 備考

schema を外部 url にしている場合は`languageService`に追加すると SDL ファイルを作ってそこを参照するみたいなことが書いてあったがうまくジャンプできなかった(?)
まだ experimental みたいなので一旦諦めた

```.graphqlrc.ts
extensions: {
  codegen: {...},
  languageService: {
    cacheSchemaFileForLookup: true, // SDL ファイルを生成
  },
}
```

https://github.com/graphql/graphiql/blob/main/packages/vscode-graphql/README.md#go-to-definition-is-not-working-for-my-url

# 参考文献

- [GraphQL Config](https://the-guild.dev/graphql/config/docs)
グリッドを渦巻き状に探索したい

# きっかけ
[ABC335: D - Loong and Takahashi](https://atcoder.jp/contests/abc335/tasks/abc335_d)でグリッドを渦巻き状に探索する必要があった.

# やりたいこと
以下の図のように, グリッドの左上から初めて渦巻き状にグリッドの中心まで探索したい.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559359/f9a002d7-364b-273d-b2c9-ea784fe9731b.png)

# 虚数の回転を使った解法
基本的に探索する方向は, 
1. →
2. ↓
3. ←
4. ↑

の順番を繰り返すので, 以下のように現在の探索している方向`direction`を虚数として管理する (座標軸のy方向とgrid上のy方向が逆転していることに注意).


1. → = `0 + 1j`
2. ↓ = `1 + 0j`
3. ← = `0 - 1j`
4. ↑ = `-1 + 0j`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559359/9d3d42da-010e-0a33-c6de-db15ca6f1519.png)

1 -> 2, 2 -> 3, 3 -> 4, 4 -> 1 と方向を変えるには, `-1j` を かければ良い.

同様に現在のマス目も虚数`now`で管理することで, 現在の地点から次の地点への移動は, `now + direction` で求めることができる.

# コード
最終的に以下のような感じになる.
```python
N = int(input())

grid = [[""] * N for _ in range(N)]
grid[N // 2][N // 2] = "T"

# h + wj
now = 0 + 0j
cnt = 1
direction = 0 + 1j

while grid[int(now.real)][int(now.imag)] != "T":
    grid[int(now.real)][int(now.imag)] = str(cnt)

    # 方向を変える必要があるのは, 既に探索済 or gridから飛び出るとき
    nh, nw = int(now.real + direction.real), int(now.imag + direction.imag)
    if (nh < 0) or (N <= nh) or (nw < 0) or (N <= nw) or (grid[nh][nw] != ""):
        direction *= -1j

    now += direction
    cnt += 1

for g in grid:
    print(*g)

```

# Verify
https://atcoder.jp/contests/abc335/submissions/49145509
kaggleの機械学習コンペ:Child Mind Institute - Detect Sleep Statesに参加しました。

先月kaggleのChild Mind Institute - Detect Sleep Statesという時系列系のコンペに参加しました。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/24d10747-5057-c5e1-5837-114e7712a233.png)

このコンペは、子どもの睡眠データ（睡眠中の体の角度、感情指標（enmo））に基づいて、入眠（onset）と覚醒（wakeup）のタイミングを予測するコンペです。こういった予測によって、睡眠パターンをより深く理解し、睡眠障害の解決に役立てることが期待されています。


私の解法と学んだことについて共有します。

一般的な機械学習の予測コンペであり、流れは以下の通りです。
1.前処理
　→特徴エンジニアリング
　→交差検証(kfold)
2.トレーニング
3.アンサンブル
　→Spec2DCNN、DETR2DCNN、CenterNet、transformers.AutoModel、DebertaV3の5つモデルを組み合わせました。


交差検証とアンサンブル、あと一部の特徴エンジニアリング（時間帯を分ける処理とか）は基本的な手法を適用しました。(これらの処理を一通り全部行えば、Top15%くらいに入ります)

今回精度が出して、特に効果的だった特徴量エンジニアリングは、「体の角度の変化量」と「感情指標の変化量」です。体の角度と感情指標それぞれ現在値と5分前、25分前、50分前よりの変化量、合計6つの特徴量を追加しました。
これらの特徴量を追加したことで、精度が大幅に向上しました（0.71⇒0.74）。
そこまですごい手法ではないと思いますが、今回のコンペでの鍵となりました。（最終的に銅メダルを獲得しました）。

ちなみに、"Polars"というライブラリが多くの方が使っていることにも気づきました。
Polarsは大量の表形式データの処理に特化したライブラリで、Pandasより処理速度が格段に速いです。
今回のデータは1億件以上ありますので、Pandasだと時間内で処理完了するのが難しいと思います。（Polarsの書き方は少し特別ですが、慣れたら見やすいと感じました。）

コンペ：

https://www.kaggle.com/competitions/child-mind-institute-detect-sleep-states?rvi=1

参考になったコード：

https://github.com/tubo213/kaggle-child-mind-institute-detect-sleep-states

Polars:

https://github.com/pola-rs/polars
支離滅裂な文章を生成するアプリ

# はじめに

GASのGASのLanguageAppクラスを使って複数回翻訳を行い、支離滅裂な文章を作成するアプリ。

案はYouTubeのラムダ技術部チャンネルから。
（丸パクリでごめんなさい！！何かあればすぐ消します！！）

[【逆翻訳】支離滅裂な文章を効率的に生成する](https://youtu.be/HBG4eHf5HxM?si=xcKkZKoswB8NnIrb)

# フロー

1. 翻訳したい文字列を入力する
2. GASで翻訳して画面に返す

# できたもの

[支離滅裂な文章を生成するアプリ](https://incoherent-sentence-generation.vercel.app/)

https://github.com/Suntory-Y-Water/incoherent-sentence-generation

YouTubeでは日本語→英語→韓国語→ドイツ語→英語→日本語の順番で翻訳していましたが、動画内にちょうど写っていたスペイン語とフランス語も噛ませばもっと支離滅裂な文章になるんじゃね？と思いドイツ語→英語→フランス語→英語→スペイン語→英語→日本語の順番で追加翻訳するように変更しました。

実際に翻訳してみたところ、気づいたことがあるのでまとめていきます。

# 気になる点

## 翻訳の精度が異なる

先述の通りGASのLanguageAppクラスを使用して翻訳を実装しましたが、スプレッドシートのGOOGLETRANSLATE関数と比べると翻訳精度が良すぎる気がします。
というかGOOGLETRANSLATE関数の方が翻訳精度が明らかに悪いです。

実際に文章を比較したところ、GOOGLETRANSLATE関数の方がトンチンカンなことを言っています。

![支離滅裂2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3351724/b2b3be48-b18d-0575-e28f-c238fb1548a0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3351724/fa5ca23f-b491-5df1-aab6-0ce5dee58797.png)


実際にイケてないと感じた人もすでにいらっしゃるので、どうやら昔からそうなってるそうです。

[Google Spreadsheet の googletranslate 関数の代わりに LanguageApp を使うワークシート関数を作ってイケてる翻訳ができるようにする - Qiita](https://qiita.com/kazinoue/items/82779a11af8a2dea0d21)

20分くらい調べた感じでは、LanguageAppクラスGOOGLETRANSLATE関数で翻訳エンジンが異なるかどうかは見つけられなかったので、そのあたりは謎です…

# おわりに

最近はshadcn/uiを使うのが楽しい。
ラムダ技術部チャンネル応援してます。
応用情報技術者試験合格するために使用した参考書・サイト一覧まとめ

# はじめに
本記事では、2023年秋期の応用情報技術者試験合格するために使用した参考書およびサイトをまとめます。
# 参考書
## 情報処理教科書 応用情報技術者 テキスト＆問題集 

まずはこの本で全体的な知識を身に付けました。
それぞれの語句などの説明も丁寧にされており、実際に午前問題にはあまり出ないようなコアな知識も載っている印象です。

この本の特徴としては、下記が挙げられます。
- 各ページの余白に「用語解説」、「間違えやすい」、「試験に出る」、「参考」などの追加の知識が説明されている。
- 各節の最後に午前問題とその解説が載っている。
- 前年度の応用情報技術者試験の過去問が収録されている。

この本を一通り読むことで、午前問題の過去問6割程度取れる知識量をつけることができました。

https://www.amazon.co.jp/dp/4798183520/


## 高度午前Ⅰ・応用情報　午前試験対策書

「情報処理教科書 応用情報技術者 テキスト＆問題集 」の次に取り組んだのはこの参考書です。
最初の参考書で身に付けた知識の復習＆この本で新たに出てきた知識を学ぶことができました。

この本の特徴としては、下記が挙げられます。
- 各節の最後に理解度チェックと午前問題が載っている。
- 用語の説明よりも問題数が多いイメージ。
- 問題の解説が「情報処理教科書 応用情報技術者 テキスト＆問題集 」よりも丁寧。

特に良いと感じたのは、「情報処理教科書 応用情報技術者 テキスト＆問題集 」に収録されていた問題よりも難しく、かつ説明が丁寧だったということです。
計算系の問題も難しいものがあり、初見では手が出しにくかった問題も詳しく解説されていたので、復習で問題を解く際はスラスラ解けるようになっていたと感じます。

https://www.amazon.co.jp/dp/486575301X

## 応用情報技術者　午後問題の重点対策

これまで説明した2冊の本は全体的な知識の習得・午前問題に慣れることを目的としていました。
午前問題についてはある程度どのような問題が出るのかを把握できたので、午後問題の解き方を学ぶことを目的として学習を進めました。

この本の特徴としては、下記が挙げられます。

- 午後試験の範囲である13の分野の演習問題とその解説が収録されている。
- 情報セキュリティ、システムアーキテクチャ、ネットワーク、データベースの4テーマは演習問題の前に説明部分もある。
- 自分が解こうと考えているテーマに絞った学習が可能。

説明がある4テーマについては、午後問題特有の問題があるため説明を設けており、その他のテーマについては演習問題を解くことを中心に力を付けていくことができるようになっています。
また、「サイト」の部分で説明する「過去問道場」には平成21年以降の午後問題が収録されていますが、解説がわかりにくいと感じるときが多々ありました。この本では選択問題の選択理由、記述問題でどのようなことを書いていればよいかなどを学ぶことができました。

https://www.amazon.co.jp/dp/4865753168/

# サイト
## 応用情報技術者過去問道場
情報処理試験を受けたことがある人は絶対に通ったことがある道なのではないのでしょうか。
午前試験は平成17年以降、午後試験は平成21年以降の春期・秋期の過去問が収録されています。
オプション項目には「計算問題を出題しない」や「計算問題のみを出題する」などがあり、自分がどのようなことを目的として学習したいかを選択する事ができるようになっています。
また、ログインすることで自分が過去に解いて、成果した問題は出題しないように設定することも可能です。この機能を活用することによって自分が間違った問題やまだ解いてない問題のみを学習することができるため、効率化を図ることが可能でした。

参考として、このサイトを私がどのように活用していたかを下記に示します。
- 毎日100題の午前問題を解く。（試験日より2ヶ月前から）
- 毎週2年分の午後問題を解く。このとき、自分が選択するしようと考えているテーマだけ取り組む。（試験日より1ヶ月前）
- 通勤時はオプション項目で「計算問題を出題しない」を選択し、知識だけで解ける問題のみに取り組む。

午前問題に関しては分野を指定して出題することができるため、自分の苦手な分野のみを集中して演習することも可能です。時間がある場合は各分野をすべて網羅しても良いかもしれません。試験では3割程度過去問から出題される傾向があるように感じており、実際に解いたことがあったからスムーズに選択できたという問題もありました。

https://www.ap-siken.com/apkakomon.php


# おわりに
テキストでは主にインプットを行いましたが、私が実際に実力がついたと感じたのは過去問道場でアウトプットし始めてからです。
テキストをすべて読破したあと過去問道場に取り組みましたが、「初めてそんな知識知ったわ...」みたいなことがしょっちゅう起こりました。
しかし、間違えた問題にチェックを付けておき、後日復習することで記憶に定着させることができたと感じています。
<br>
今回説明した内容で学習した結果、
午前問題：82.50%
午後問題：74.00%
という成績で無事に合格することができました。
心残りがあるとすれば、もう少し早く午後問題の過去問演習に取り組むべきだったと感じています。
午後問題は文章を正確に読めるかが鍵となってくるため、言葉の言い回し等に慣れておくとスムーズに解答する事ができると思います。
<br>
また、午後問題で解くテーマは必須である情報セキュリティに加えて4題の選択、合計5題のテーマを解く必要があります。余裕を持って、選択時に解答できるテーマを5題持っておくと試験で選択しようとしたテーマが難しかった場合に予備のテーマに切り替えることが可能です。
実際、私もNWが難しいと感じたために別のテーマに切り替えたところ、そのテーマが簡単で助かったという事が起きました。
<br>
2024年春期試験の申込みもあと少しで始まりますね。今回の記事が少しでも役に立てばと思います。
いまさらNext.jsのチュートリアルをやってみた際のメモ (随時更新)

- ターミナルで以下を実行
    ```bash
    npx create-next-app@latest
    ```
    - `Ok to proceed? (y)` で y を入力
    - `Error: Cannot find module 'fs/promises'`のエラーが発生 (ローカルPCのNode.jsが古すぎたっぽい(いつ入れたやつか知らないくらい古い))
        - `Run npm install -g npm@10.2.5 to update!` とNoticeが出たので実行してみる。(以下のようになったので多分大丈夫そう。再度最初のコマンドを実行)
        ```
        npm WARN EBADENGINE Unsupported engine {
        npm WARN EBADENGINE   package: 'npm@10.2.5',
        npm WARN EBADENGINE   required: { node: '^18.17.0 || >=20.5.0' },
        npm WARN EBADENGINE   current: { node: 'v13.13.0', npm: '7.19.0' }
        npm WARN EBADENGINE }
        ```
    - `SyntaxError: Unexpected token '.'` のエラーが発生（nodeのバージョンが古すぎるっぽい。13.13.0だったが、Next.jsを動かすには[18.17](https://nextjs.org/docs/getting-started/installation)以上が必要だったっぽい）
    - 仕方ないので、homebrewのアップデートからスタート `brew update` (3.3.3 -> 4.2.2 に更新)
    - nodebrewをアップデート `brew upgrade nodebrew` (1.0.1 -> 1.0.1)
    - 現在のLTS版（[20.10.0](https://nodejs.org/en)）をインストール `nodebrew install-binary v20.10.0`
        - `Error: Darwin arm64 is not supported.`のエラーが出る（M1 Macではnodebrew経由のinstallは無理っぽい。知らんかった...）
        - nvm経由のインストールにしてみる ([参考](https://qiita.com/y_sone/items/08e3f8687092173b1d2f#nvm%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB))
            - `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash`を実行しても、また`SyntaxError: Unexpected token '.'`になった...
            - 代わりに `wget` にしてみたが同じエラー(Unexpected token)になった...
            - `npm install -g npm@10.2.5` としてしまったのが原因っぽい
            - `npm uninstall -g npm`で元に戻したいけど、同じエラー(Unexpected token)になる(八方塞がり...)
            - `brew install nvm`で簡単にnvmが入った
        - `nvm install --lts`を実行して、node 20.10.0、npm 10.2.3 が入ったことを確認
- Yes/Noは以下のようにした(何が正解か知らない)
    ```bash
    ✔ What is your project named? … nextjs-tutorial
    ✔ Would you like to use TypeScript? … No / Yes
    ✔ Would you like to use ESLint? … No / Yes
    ✔ Would you like to use Tailwind CSS? … No / Yes
    ✔ Would you like to use `src/` directory? … No / Yes
    ✔ Would you like to use App Router? (recommended) … No / Yes
    ✔ Would you like to customize the default import alias (@/*)? … No / Yes
    ```
    - `Success! Created nextjs-tutorial` とコンソールに出た
    - 以下のようなツリー構造が完成した
        ![create_next_app_tree.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402725/30d9650d-dd9c-fd8a-44fe-71b7fe732a94.png)
- `npm run dev`コマンドの実行で以下の画面となることを確認
    ![02_nextjstop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402725/7ebc157a-b089-c4b4-397b-97df0a5f32e7.png)
- [こちら](https://qiita.com/masato5579/items/8a08ea9988f4fd0097e3)を参考にgithubに新しいリポジトリを作成して、ここまでの内容をpush
    - `git init`, `git add .`, `git commit`, `git remote add origin [url]`, `git push origin master` の5コマンドを実行
- [チュートリアル(Routingから)](https://nextjs.org/docs/app/building-your-application/routing)を実施
【Java・学習ログ17】コレクションについて～Mapの基本～

≪使用教材≫スッキリわかるJava入門　第3版　スッキリわかるシリーズ　『第16章』
## Mapの使い方
マップとは２つの情報を**キー**と**値**のペアとして格納するデータ構造。格納した値はキーを指定して読み書きできる。実装の中でも特に多く利用されるのは、java.util.HashMapクラス。

《HashMapが備えるメソッド》
|操作|戻り値|メソッド|意味|
|-|-|-|-|
|追加|値|put(キー,値)|マップにキーと値のペアを格納する|
|取得|値|get(キー)|キーに対応する値を取得（なければnull）|
|調査|int|size()|格納されているペア数を数える|
||boolean|isEmpty()|要素数がゼロであるかを判定|
||boolean|containsKey(キー)|指定データがキーに含まれているかを判定|
||boolean|containsValue(値)|指定データが値に含まれているかを判定|
|削除|void|clear()|要素をすべて削除する|
||値|remove(キー)|指定した内容の要素を削除する|
|その他|Set<キー>|keySet()|格納されているキーの一覧を返す|

なお、Mapでは値の重複は許されるが、キーの重複は許されない。同じキーで異なる値をput()すると、後から格納した値で上書きされてしまうので注意が必要。
```java
import java.util.HashMap;
import java.util.Map;

public class Main {
	public static void main(String[] args) {
		Map<String, Integer> prefs = new HashMap<String, Integer>();
		prefs.put("京都府", 255);
		prefs.put("東京都", 1261);
		prefs.put("熊本県", 181);
		int tokyo = prefs.get("東京都"); // キーを指定し値を取得
		System.out.println("東京都の人口は、" + tokyo);
		prefs.remove("京都府"); // 削除
		prefs.put("熊本県", 182); // 値を上書き
		int kumamoto = prefs.get("熊本県");
		System.out.println("熊本県の人口は、" + kumamoto);	
	}
}
```
【実行結果】
![スクリーンショット 2024-01-04 172630.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/5e068017-aedb-1b03-4a70-5d87a0813f66.png)

#### 中身を１つずつ取り出す
ListやSetと同様の方法で取り出そうとするとエラーが出てしまう。
マップに格納されたデータを１つずつ取り出すには、「キーの一覧を取得してから、各キーについて対応する値を取得」の２段階手続きをする方法が踏襲しやすい。
```java
import java.util.HashMap;
import java.util.Map;

public class Main {
	public static void main(String[] args) {
		Map<String, Integer> prefs = new HashMap<String, Integer>();
		prefs.put("京都府", 255);
		prefs.put("東京都", 1261);
		prefs.put("熊本県", 181);
		for(String key : prefs.keySet()) {
			int value = prefs.get(key);
			System.out.println(key + "の人口は、" + value);
		}
	}
}
```
![スクリーンショット 2024-01-04 173449.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/ec406f52-88ff-df9d-2672-a250f08e844a.png)
<hr>
Material TailwindをPhoenixで使う

# はじめに

Material-tailwindのドキュメントに、Phoenixでの使い方が載ってました。これをみながら試してみます。

https://www.material-tailwind.com/docs/html/guide/phoenix

# phoenixのインストール

Phoenixが使えるようにしておきます。

https://hexdocs.pm/phoenix/installation.html?ref=material-tailwind

# プロジェクトの作成

```
mix phx.new  --database sqlite3 mt_app
```

起動してみます
```bash
$ cd mt_app/
$ mix ecto.create
Compiling 15 files (.ex)
Generated mt_app app
The database for MtApp.Repo has been created
$ mix phx.server
```

node.jsが動作する環境が必要なので、dockerのコンテナで環境を用意します。

vscodeでAdd Dev Contaner Configuration Fileコマンドで設定ファイルを作る事ができます。

```json:/mt_app/.devcontainer/devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
{
	"name": "Node.js",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	"image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bullseye",
	"features": {
		"ghcr.io/devcontainers-contrib/features/elixir-asdf:2": {}
	}

	// Features to add to the dev container. More info: https://containers.dev/features.
	// "features": {},

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [],

	// Use 'postCreateCommand' to run commands after the container is created.
	// "postCreateCommand": "yarn install",

	// Configure tool-specific properties.
	// "customizations": {},

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}

```

/mt_app/.devcontainer/devcontainer.jsonを作成してこのプロジェクトをコンテナーで開くと、node.jsとElixirの環境が構築された状態になります。

# material-tailwindのインストール

material-tailwindのマニュアルの記述通りでうまくいきました。

yarnコマンドは、assetsのディレクトリで実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/4e88a9f2-941d-d6d1-5bb6-0b2f68c9ab7d.png)

# Tailwindの設定の修正

withMT()を呼び出すように、tailwind.config.jsを修正します。

```Elixir:/mt_app/assets/tailwind.config.js
 const fs = require("fs")
 const path = require("path")
 
-module.exports = {
+const withMT = require("@material-tailwind/html/utils/withMT")
+
+module.exports = withMT({
   content: [
     "./js/**/*.js",
     "../lib/mt_app_web.ex",
@@ -65,4 +67,4 @@ module.exports = {
       }, {values})
     })
   ]
-}
+})
```

# テストページ

`/mt_app_web/controllers/page_html/home.html.heex`ここにMaterial-tailwindの部品を置いてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/ae97dd36-4838-6332-10d8-2b922e46e120.png)

表示できました。

# まとめ

- Containerを使った開発環境の構築でNode.js/yarn/Elixir/Phoenixの環境を簡単に作ることができた。
- マニュアルに記載されてる方法で、Material-tailwindが使えるようにできた。

ソースファイル：　https://github.com/masahiro-999/mt_app
特定ブランチをローカルマージせずにPullRequestマージやっちゃいがちなあなたへ送るGit Hooks

スタートアップのエンジニアだったり、ある程度権限の強い部署にいてHotFix当てるような場面のある人だとやりがちなことといえば、他人の作業ブランチやdevelop、main、masterなどのリリース用ブランチをマージせずに自分の作業分だけgit push/mergeしてしまうということじゃあないだろうか。
私も去年数えるだけで4回はやっている。

これを反省し、commit前にマージ忘れを検知してくれるGit Hooksのpre-commitをChatGPTに教えてもらったので以下に記載しておく。
以下の例は develop ブランチなので、mainとかreleaseとかmasterとか各自の環境に合わせて変えていただきたい。

```shell:.git/hooks/pre-commit
#!/usr/bin/env bash

git fetch origin develop:develop

# 現在のブランチとdevelopブランチの共通の祖先を取得
COMMON_ANCESTOR=$(git merge-base HEAD develop)

# developブランチの最新のコミットを取得
LATEST_DEVELOP_COMMIT=$(git rev-parse develop)

# 共通の祖先がdevelopの最新コミットと同じかどうかをチェック
if [ "$COMMON_ANCESTOR" != "$LATEST_DEVELOP_COMMIT" ]; then
    echo "ERROR: Your branch is out of date with 'develop' branch. Please merge 'develop' into your branch."
    exit 1
fi
```

## Git Hooksって何？ pre-commit？

こちらに書いてありますので参考にしてください！

https://anteku.jp/blog/develop/git-%E3%83%95%E3%83%83%E3%82%AF%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/