OmniAICreator/Qiita-1.07M huggingface dataset:
Chrome拡張とGASを連携。初回の通信後は定期的に通信。

# これは何？

https://qiita.com/sakaimo/items/f1b2b8353da1e7de6e3d

↑ この投稿の「課題と対策」の課題を解決してみました。

# 課題

上の記事で「Chrome拡張機能からGASにリクエストを送って情報を取ってくる」ことが可能になりました。しかし、

* 画面が更新されるたびに(正確には`content.js` が実行されるたび)に、GASと通信が発生します
* GASから取ってくるデータ量が大きくなると`content.js` の実行完了まで時間がかかってしまいます

という問題が発生します。かつ、GAS側にある情報の更新頻度は低いとします。ですので

* 拡張機能時に一回だけGASから取得して chrome.storage.local に保存する
* 画面更新時には chrome.local.storageから情報を取ってくる
* 1時間に1回、GASから情報をとって chrome.storage.local の情報を更新する

をやってみます。


# コードを書いてみた

## GASのコード

簡単のため、固定値のJSONを返すだけのGASを作成し、デプロイし、URLを控えておきます。

```js
// 固定値のJSONを返すだけ
function doGet(e){
  const res = [{ name: "TARO", age: "17"},  {name: "JIRO", age: "15"}];

  const output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(JSON.stringify(res));
  return output;
}
```

## 拡張機能のコード

```json:manifest.json
{
    "name": "GASから情報を取ってきて何かする拡張機能",
    "version": "1.0",
    "manifest_version": 3,
    "description": "なにかします",
    "icons": {
        "16": "icon16.png",
        "48": "icon48.png",
        "128": "icon128.png"
    },
    "permissions": [
        "alarms",
        "storage"
    ],
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["content.js"],
            "run_at": "document_idle"
        }
    ],
    "background": {
        "service_worker": "background.js"
    }
}
```

↓ これがポイントっぽい。
```json
    "permissions": [
        "alarms",
        "storage"
    ],
```


    
```js:background.js
// GASからデータを取得し、chrome.storage.local に保存する関数
function fetchDataFromGAS() {
  const gasUrl = "https://script.google.com/a/macros/xxxxxxxxx/exec";

  fetch(gasUrl)
    .then((response) => response.json())
    .then((data) => {
      chrome.storage.local.set({ gasData: data }, () => {
        console.log("GASから取得した情報", data)
      });
    })
    .catch((error) => console.error("fetchでエラー:", error));
}

// 拡張機能が起動した時に実行
chrome.runtime.onInstalled.addListener(() => {
  console.log("起動時に実行: chrome.runtime.onInstalled.addListener")
  fetchDataFromGAS();
});

// 定期的に実行するためのアラームを設定。ここで更新頻度を調整可能
chrome.alarms.create("fetchData", { periodInMinutes: 60 });

// アラームが鳴った時のリスナーを設定
chrome.alarms.onAlarm.addListener((alarm) => {
  if (alarm.name === "fetchData") {
    fetchDataFromGAS();
  }
});
```



```js:content.js
function main(){
  // storageから情報を取る
  chrome.storage.local.get("gasData", function (result) {
    if (result.gasData) {
      console.log("local.storageから取った情報:", result.gasData);

      // その情報を使った処理を書く
      
    } else {
      console.log("gasData が無いよ");
    }
  });
}
main()
```

# 実行してみる

## 「Service Worker」のコンソール

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/7a04de52-bc21-230a-a3a0-09933393f7da.png)

うん。想定どおりGASと通信してますね。


## content.js のコンソール

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/69394d34-df17-44e8-c32d-f59d7759bee9.png)


こちらでも想定通り `local.storage` から取得しています。

これ以降、画面を更新してもGASとの通信は行われず、`local.storage` からの情報を取得します。
`background.js` の中にある `periodInMinutes: 1` にして実験すると、Service Worker のコンソールに1分ごとにログが出力され、定期的にアラームが実行されてGASと通信していることがわかります。


思ったより簡単に実装できました。拡張機能すごい。
安易な継承の落とし穴

継承を行った子クラスは、継承元の親クラスの一種として扱われます。
その為、一部のフィールドやメソッドのみを流用する目的で継承すると、継承されている機能の一部が、誤った用途で使用できてしまう場合があります。
このような事態を避ける為には親クラスと子クラスの関係性に注意する必要があります。

親クラスのメソッド等を子クラスで全て利用する場合は良いですが、親クラスのメソッドを一部使わない場合は注意が必要です。
Hello Worldからの復習 〜配列編〜

昔、バスケの練習で何パターンかオフェンスの練習していて、何故この動きが必要かあまり理解せずやっていたら試合で防がれ、何故防がれたかしっかり理解できず、攻め倦んで監督から怒りの〇〇を喰らった記憶がある。

実務のテストでは、配列を良く使いました。
例の如く何となくでやっていました。
問題なく動いていましたが、理解は浅く、何がどうとかいう説明は、、、

できません。。。

結構惨めな思いをしたのも前進する為の糧。

**お品書き**
+ 配列って？
+ 配列の生成
+ 配列の初期化
+ 多次元配列
----

##### 配列って？

同じデータ型の変数を複数まとめて管理するもの
配列の生成には**new**を使う。生成時にデフォルト初期値が設定される。
`(0、' '(空文字)、false)`

**データ型[] 配列名 = new データ型[要素数];**

例えば点数を3つまとめて管理するなら
`int[] score = new int[3] ;`

配列は参照型のため、変数には参照値が入る。

※作った変数scoreのイメージ図
| score |
|:-:|
| (　　)  |

new int[3]のイメージ図
| int | int | int |
|:-:|:-:|:-:|
| 0 | 0 | 0 |

newしたデータ型の値は「0」なので初期化して値を代入します。
`score[0] = 80 ;`
`[]`の数字を添え字といい0起算で何番目かを表している。
そしてデータ型の要素数が`3`なので`0から2`まで初期化する。

| 0 | 1 | 2 |  
|:-:|:-:|:-:|
| 80 | 0 | 0 |


**◆配列Sample**
-
```java:java
class Array{
	public static void main (String[] args){
		int [] score = new int[3];
		score[0] = 80;
		score[1] = 100;
		score[2] = 90;
  .
  .
  .
	}
}
```
##### 配列の初期化
**データ型[] 配列名 = { 値１, 値２,・・・}**

初期化する値は先ほど同様0番目から始まる。


```java:java
		String[] name = {"大輔","湊丞","花帆"};
		
		System.out.println(name[0] + "さん:" + score[0] + "点");
		System.out.println(name[1] + "さん:" + score[1] + "点");
		System.out.println(name[2] + "さん:" + score[2] + "点");
		System.out.println("受験者数:" + score.length + "名"); //scoreの要素数を取得
```
配列名.lengthで配列の**要素数**を取得できる。

```cmd:cmd
C:\Java\1>javac Array.java

C:\Java\1>java Array
大輔さん:80点
湊丞さん:100点
花帆さん:90点
受験者数:3名
```

**◆多次元配列**
-
配列の配列をつくる。
**データ型[][] 配列名 = new データ型[][];**

例：`int[][] allScore = new int[2][3];`
newしたデータ型の`[ ][ ]`配列は**2行3列**


まず、
allScoreという変数があって。。。
この子は**行**を見に行きます。
| allScore |
|:-:|
| (　) |

データ型が2行。。
この子たちは**列**を見に行きます。
| allScore[0] | (  ) |
|:-:|:-:|
|**allScore[1]**| **(  )** |

一瞬何番目の何番目がわからなくなる

例えばこんな感じ
|allScore[0]|[0][0]|[0][1]|[0][2]|
|:-:|:-:|:-:|:-:|
|| 80 | 100 | 90 |
|**allScore[1]**|**[1][0]**|**[1][1]**|**[1][2]**|
|| 85 | 95 | 75 |

みたいなこと。

`[]`を増やせば増やした分の多次元配列ができる。

ちなみに多次元配列の初期化するときは
`int[][] allScore = {{80, 100, 90},{85, 95, 75}};`

◆多次元配列Sample
-

```java:java
class MultiArray{
	public static void main(String[] args){
		int[][] allScore = new int [2][3];
		allScore[0][0] = 80;
		allScore[0][1] = 100;
		allScore[0][2] = 90;
		allScore[1][0] = 85;
		allScore[1][1] = 95;
		allScore[1][2] = 75;
		
		//多次元配列の初期化
		//int[][] allScore =  {{80, 100, 90},{85, 95, 75}};
		
		System.out.println(allScore[0][0] + "点");
		System.out.println(allScore[0][1] + "点");
		System.out.println(allScore[0][2] + "点");
		System.out.println(allScore[1][0] + "点");
		System.out.println(allScore[1][1] + "点");
		System.out.println(allScore[1][2] + "点");
		
		System.out.println("allScore.length:" + allScore.length);
		System.out.println("allScore[0].length:" + allScore[0].length);
	}
}
```

```cmd:cmd
C:\Java\1>javac MultiArray.java

C:\Java\1>java MultiArray
80点
100点
80点
85点
95点
75点
allScore.length:2
allScore[0].length:3
```

##### おまけ
allScore.lengthとallScore.length[0]はそれぞれの要素はというと

allScore.lengthの指し示しているのは行のallScoreだから2
allScore[0].lengthの指示しているのは列のallScore[]だから3

----

だんだん長くなってきた。
理解は深まってきたかな。
Azure DevOps にて有効期限が過ぎた個人用アクセストークン（PAT）の期限を更新する方法

## 概要

Azure DevOps にて有効期限が過ぎた個人用アクセストークン（PAT）の期限を更新できることを確認したため、有効期限の更新手順を共有します。ドキュメントにてスコープを更新する方法が提示されていますが、有効期限の更新も実施できるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/0d4ef4ee-7cf7-c429-1710-a5b8a7ee0c9a.png)

引用元：[個人用アクセス トークンを使用する - Azure DevOps | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#modify-a-pat)

## 手順

### 1. Azure DevOps にログイン後、右上の`User ettings`選択 -> `Personal access tokens`を選択  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/a8d85587-b529-2e7b-bd94-027e03d4536d.png)

### 2. `Personal Access Tokens`ページにて、`Status`を`Expired`に変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/9208cca3-016e-5cb0-b20e-bbb23e78c36f.png)


### 3. 有効期限を更新するトークンにチェックをいれて、`Edit`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/7b6b23b7-ea5b-1236-943d-e826e90431c6.png)

### 4. `Edit a personal access token`ページにて`Expiration (UTC)`の期限変更後に有効期限が更新されることを確認（例：`2022/6/5` -> `2024/5/27`）

<変更前>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/c215e7e3-c3cd-414c-547f-c7dc3ff10df3.png)

<変更後>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/a782530f-8af8-7864-2a76-07a6c3501890.png)

### 4. `Save`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/8dc02589-6d2c-a70c-59cb-d2e270e66a91.png)

### 5. `Status`が`Active`になったことを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/1cf8894c-2ccc-b02a-dcad-5c8780f0d1ac.png)
現場で使っていたgitコマンドまとめ

##概要
メモしてたやつを整理しただけです。

## git add 取り消し
```bash
git reset HEAD
```
https://qiita.com/yukure/items/89562e5eb1d03995dc5b

## ローカルとリモートのブランチ名を変更する  
```bash
git branch -m 古いブランチ名 新しいブランチ名
git push -u origin 現在のブランチ名      // $ git push -u origin HEAD とするとブランチ名を入力しなてもpushできるので便利です。
git push origin :リモートのブランチ名
```
https://qiita.com/shungo_m/items/4218e70751375b4bfeec

## 直前のコミット操作を取り消す
```bash
git reset --soft HEAD^
```

## PRでコードを埋め込みつつ、折りたたむ
<details><summary>必ず一行開けてあげる</summary><div>

```bash
```
</div></details>

```
<details><summary>必ず一行開けてあげる</summary><div>
ここにコードを各
</div></details>
```

## 操作の取り消し
```
git reflog
```
以下の様に表示される
```
02f11b7 HEAD@{0}: reset: moving to 02f11b7
0488e28 HEAD@{1}: merge develop: Merge made by the 'recursive' strategy.
6978c20 HEAD@{2}: checkout: moving from develop to master
32275f0 (develop) HEAD@{3}: commit: 制作事例を追加
0e95561 HEAD@{4}: checkout: moving from master to develop
6978c20 HEAD@{5}: commit: 3回目のコミット
0e95561 HEAD@{6}: commit: 2回目のコミット
02f11b7 HEAD@{7}: commit (initial): はじめてのコミット
```
「resetの操作をする前（1つ前）に戻したい」といった場合、コマンドは次のとおりです。
```
git reset --hard HEAD@{1}
```


## commitの修正
tigを実行し、目的のcommitの一つ前のcommti IDをコピーして
```
git rebase -i commitID
```
編集画面へ飛ぶので、対象のcommitをpick→editにしてwq
目的のファイルを編集しaddして、以下のコマンドですでにあるcommitに修正を反映させる
```
git commit --amend
```
editを完了させる
```
git rebase --continue
```


## git stash
作業中に別の作業をしたいときにコミットしていない変更を退避させるコマンド。
* 変更を退避する
```
git stash save
```
* 退避した作業一覧を見る
```
git stash list
```
* 退避した作業を戻す(listで確認してから行う)
```
git stash apply stash@{0}
```
現在checkoutしているbranchへ退避した変更が書かれる。  
変更を退避したときのbranchにも、それ以外のbranchにも戻すことができる。  
stash名を指定しない場合は、直近に退避された作業を戻す。  

* 退避した作業をstashリストから消す
```
git stash drop stash@{0}
```
* 退避した作業を戻すと同時にstashリストから消す
```
git stash pop stash@{0}
```
* 作業を退避させる時にメッセージをつける
```
git stash save "stash message"
```
https://qiita.com/chihiro/items/f373873d5c2dfbd03250

## diff
### branch間のdiff
```
https://github.com/cakephp/cakephp/compare/3.0...3.0-fix-log-scope
```  
/compare/がポイント

### commit間のdiff
```
https://github.com/cakephp/cakephp/compare/b5cbe4de58eedc1e10bb0ac06da8d134e38a1dc4...970cb81d03dc8f3db9efe7b9271f4b4e089dd3ae
```  
https://qiita.com/fantasista_21jp/items/9419ca4ab3bb8e1ee4c5


## レビューのこつ
GitlabとちがってGithub的にはPR上でReview作業を進めていくほうが楽なので、きちんとdescriotionにcheck pointなどをコメントしておく  
また、意図が伝わりづらいcode部分に注釈を入れたり、commit追加したときにも修正内容をコメントするなど、reviewrを意識して運用していくと良い  

## conflict解消
ブランチで作業してるけど、作業中に他のメンバーがマスターにマージしてマスターの情報が新しくなった！
という時に、作業中の自分のブランチにマスターの最新情報を追加して自分がマージ
した時のコンフリクトを最小限に抑えたい＆マージされた内容をもとに実装をしたい
```bash
git co master
git pull
git co 作業branch
git rebase master

# conflict箇所修正して
git ad .
git rebase --continue
```
https://qiita.com/i-to-to-to-mi/items/04cb754a148b443a715d
現場で使っていたgpgコマンドまとめ

# 概要
メモしてたやつを整理しただけです。


* gpg鍵のインポート
```bash
gpg --import sooota_pub
```

* インポートしてある公開鍵を確認
```bash
gpg --list-keys
```

* インポートしてある秘密鍵を確認
```bash
gpg -K
```

* インポートしてある公開鍵を削除
```bash
gpg --delete-keys メールアドレス
```

* 更新など
```bash
gpg --edit-key [ID]

gpg> key [NUM] # 操作対象のキー番号を指定; NUMを省略した場合はマスターキーが指定される。 1か2で副鍵が選択される
gpg> expire    # 次のプロンプトで有効期限を指定
gpg> save
gpg> exit #saveで閉じるかも
```

* エクスポート
```bash
gpg -a -o public.key --export ID
gpg -a -o private.key --export-secret-keys ID
```

* 復号化
```bash
gpg test.zip.gpg
```
tailwindcssとvuetify3の共存

結論からいうと止めたほうが良い。

### tailwindcssとvuetifyのスタイルの相性が悪い。

#### size系(width/height/margin/padding)スタイルの指定の単位が違う。

https://vuetifyjs.com/en/styles/sizing/#height

https://tailwindcss.com/docs/width

#### flexの指定方法が違う。

一部は同じものがあるから混乱のもととなる。

https://vuetifyjs.com/en/styles/flex/#enabling-flexbox

https://tailwindcss.com/docs/justify-content

### 回避策
tailwindcss側にprefixをつける方法があるが
tailwindcssベースで作られたコンポーネントとかは軒並みプレフィックス無で
実装されているため置換が必要となる。

よって両者を共存させることにメリットはなさそう。
[翻訳転載] Golang Tip #9: コンパイル時のインターフェイス検証

# はじめに

https://qiita.com/a10a/items/5063899c9f4a3bf4a2f2

本記事は以下のツイートの翻訳転載です。

https://x.com/func25/status/1729871737343643902?s=20

# コンパイル時のインターフェイス検証

`Write()`関数を持つ`Buffer`インターフェースと、
それを実装した`StringBuffer`構造体を想像してほしい。

以下のように、誤って`Write()`ではなく`Writeee()`のようにタイプミスをした関数を実装してしまった場合、

![image](https://pbs.twimg.com/media/GAG85AFaIAAvqvt?format=jpg&name=medium)

The error isn't caught until runtime. By using the trick below, the compiler will alert you with an IDE error message:
エラーは実行時まで発見されません。

しかし、以下のようにすることで、実際に実行するより前に、エディタがエラーメッセージで警告してくれます。

![image](https://pbs.twimg.com/media/GAG8308aIAAopKv?format=jpg&name=medium)

# おわりに

Goでは明示的にインターフェースの実装が示されない（良くも悪くも）ので、

``` java
// 明示的なインターフェースの実装
// StringBufferがBufferの実装であることがわかる
class StringBuffer implements Buffer
```

このインターフェースを実装するという意図がコードから読み取れるようになるので良いなと思った。
実装の定義の直下に１行足しておくだけで導入できるのも良い。
Terraformで大量のリソースを一度にimportする

# 背景
Terraformで既存リソースを管理する場合、`import`ブロックが利用可能です。

https://developer.hashicorp.com/terraform/language/import

例えばAWSのIAM Roleは、以下のようなコードでインポート可能です。
```hcl
import {
  to = aws_iam_role.developer
  id = "developer_name"
}
```

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role#import

`to`にTerraformでのリソースIDを、`id`にはIAM Role名を記述します。

この`import`ブロックですが、リソースひとつごとにブロックが一つずつ必要になります。
`for_each`も使用可能ですが、全リソースを一度にインポートしたい場合、`for_each`を書くのも大変です。

## `import`サブコマンド
インポートするだけであれば、`terraform import`サブコマンドを、スクリプトでループさせることでも可能です。

https://developer.hashicorp.com/terraform/cli/import

`import`コマンドの場合、インポートしたリソースのHCL（tfファイル）を自分で書く必要があります。
`terraform plan`で差分を確認しながら、大量のリソース定義を記述していくのは、現実的ではありません。

# 本題
Terraformは実は、HCLによるtfファイルだけでなく、JSONファイルでのリソース定義も可能です。

https://developer.hashicorp.com/terraform/language/syntax/json

`file.tf.json`のように、拡張子が`.tf.json`のファイルを読み込んでくれます。
スクリプトで一括生成するなら、HCLよりもJSONの方が簡単ですので、今回はこれを活用します。

`import`ブロックの場合、以下のような`.tf.json`ファイルを用意すればインポート可能です。

```json
{
    "import": [
        {
            "id": "role1",
            "to": "aws_iam_role.role1"
        },
        {
            "id": "role2",
            "to": "aws_iam_role.role2"
        }
    ]
}
```

## 例：AWSアカウント内のIAM Role全てをインポートする
aws cliはJSONで結果を出力してくれます。
`--query`オプションや`jq`コマンドで加工し、`import`ブロックの生成が可能です。
今回はaws cli単体で完結するよう、`--query`オプションを使用したJMespath構文で記述します。

### 1. `import`ブロックを記述した`.tf.json`を生成
まず、以下のコマンドで`import.tf.json`ファイルを作成します。

```shell
aws iam list-roles --query "{import: @.Roles[].{id: RoleName, to: join('', ['aws_iam_role.',RoleName])}}" > import.tf.json
```

ファイル名は、`.tf.json`で終わっていれば、なんでも構いません。

#### `--query`オプションでやっていること解説
```
{import: @.Roles[].{id: RoleName, to: join('', ['aws_iam_role.',RoleName])}}
```

1. Topレベルに`import`を定義
1. `id`は、Terraformのドキュメント通りIAM Role名を指定
1. `to`ではTerraform内でのリソースIDを指定するために、`aws_iam_role.`とリソースIDを結合。リソースIDはIAM Role名をそのまま使用


### 2. `.tf.json`で定義したリソースから、HCLを生成
`import`を定義した状態で`terraform plan`のオプション`-generate-config-out=ファイル名`を指定すると、terraformコマンドがHCLを自動で生成してくれます。
```shell
terraform plan -generate-config-out=generated.tf
```

### 3. `terraform apply`
あとはいつも通りの`terraform apply`でインポート完了です。

# おわりに
JSONファイルでのTerraformの記述は、制約も少なくなく、通常は使いづらいものです。
しかし、HCLと違ってスクリプトによる生成がしやすいので、API呼び出し結果などからTerraformを記述したい場合には便利です。
[Laravel10] Laravel Sailを使用せず、DockerComposeを自前で用意する

# はじめに

Laravel Sailを使用せず、自前でDocker Compose環境を構築します。

※ なお、公式ではLaravel Sailの使用が勧められております。

https://readouble.com/laravel/10.x/ja/installation.html

<font color="red">本記事は暫定版であり、今後、Laravelの実装学習が進むにつれ更新していく予定です。</font>

# Laravel Sailについて

Laravelのプロジェクトを開始するにあたり、開発環境としてLaravel Sailを使用するか悩みました。

SailのPHPコンテナのDockerfileを確認してみると、`artisan serve`経由でPHPのビルトインサーバーを使用しているようで、apacheやnginxなどのWebサーバーのコンテナは存在しませんでした。

https://www.php.net/manual/ja/features.commandline.webserver.php

>このウェブサーバーは単一のシングルスレッドプロセスしか実行しないので、 リクエストがブロックされると、PHP アプリケーションはストールします。

デバッグ作業中に中断すると、リクエストを受け付けなくなってしまうということでしょうか。機会があれば検証してみたいと思います。

webサーバー構成にも対応してほしいというのが正直なところです。

# Docker Compose 構成

Docker Composeの構成を記述します。

## サービス一覧

- app
- app_cron
- app_queue
- web
- db_pgsql
- db_pgsql_admin
- db_mysql
- db_mysql_admin
- db_redis
- db_redis_admin
- db_memcached
- db_mongo
- db_mongo_admin
- 
mail_mailhog

- mail_mailpit

### app
[php-fpm](https://hub.docker.com/_/php)で動作するアプリケーションサーバー。
LaravelにHTTPリクエストを処理させます。

### app_cron
cron用のサーバー。
Laravelのタスクスケジュール機能を動作させます。

https://readouble.com/laravel/10.x/ja/scheduling.html

### app_queue
キューを処理するためのサーバーです。
Laravelのキュー機能を動作させます。

https://readouble.com/laravel/10.x/ja/queues.html

https://readouble.com/laravel/10.x/ja/horizon.html

### web
[nginx](https://hub.docker.com/_/nginx)サーバー。
HTTPリクエストをappコンテナへとフォワード（中継）します。

### db_pgsql
[PostgreSQL](https://hub.docker.com/_/postgres)サーバー。


### db_pgsql_admin
[PgAdmin](https://hub.docker.com/r/dpage/pgadmin4)サーバー

### db_mysql
[MySQL](https://hub.docker.com/_/mysql)サーバー。

### db_mysql_admin
[phpMyAdmin](https://hub.docker.com/_/phpmyadmin)サーバー。

### db_redis
[redis](https://hub.docker.com/_/redis)サーバー。

### db_redis_admin
[redisinsight](https://hub.docker.com/r/redislabs/redisinsight)サーバー。

### db_memcached
[memcached](https://hub.docker.com/_/memcached)サーバー。

### db_mongo
[MongoDB](https://hub.docker.com/_/mongo)サーバー。

### db_mongo_admin
[Mongo Express](https://hub.docker.com/_/mongo-express)サーバー。

### 
mail_mailhog

[MailHog](https://hub.docker.com/r/mailhog/mailhog)サーバー。（MailPitを使用するため削除予定）

### mail_mailpit
[MailPit](https://hub.docker.com/r/axllent/mailpit)サーバー。

# Github

https://github.com/perilla0/laravel_v10_template
Railsアプリケーションにおける外部キー制約エラーの解決法

## エラーの概要
Railsアプリケーション開発中、以下のような外部キー制約違反のエラーに直面しました。

```
ActiveRecord::InvalidForeignKey (PG::ForeignKeyViolation: ERROR:  update or delete on table "company_business_days" violates foreign key constraint "fk_rails_... on table "company_business_hours")
```

このエラーは、`Company`モデルを削除しようとした際に発生しました。

## エラーの解消方法
問題の解決には、データベースの外部キー制約に`on_delete: :cascade`オプションを追加する必要があります。これにより、親モデルの削除時に関連する子モデルが自動的に削除されます。

前提条件のセクションを、提供されたモデルの定義に基づいて再構成します。ここで目指すのは、記事の読者が問題の文脈をより明確に理解できるように、モデル間の関係性とそれらがどのように連携しているかを詳細に説明することです。

📌 重要な参考資料 📌

▶️ 以下の記事も参考にしてください。 ◀️
[Railsで動的に営業時間入力フォームを表示させる方法（ストロングパラメータに注意！）](https://qiita.com/mathematics9973/items/fdb7eb6271d0a6c98279)

---

## 前提条件
`Company`、`CompanyBusinessDay`、および`CompanyBusinessHour`の3つのモデル間の関係性は以下の通りです。

- `Company`モデルは、`CompanyBusinessDay`と`has_many`関係にあります。これにより、一つの会社が複数の営業日（`CompanyBusinessDay`）を持つことができます。また、`dependent: :destroy`オプションが設定されており、会社が削除されると、それに紐づく営業日も同時に削除されます。
- `Company`モデルは、`CompanyBusinessDay`を介して`BusinessDay`と多対多の関係を持ちます。これにより、会社は複数のビジネスデイ（営業日）を介して複数の営業時間（`CompanyBusinessHour`）を持つことができます。
- `CompanyBusinessDay`モデルは、`Company`と`BusinessDay`に属しており、さらに`CompanyBusinessHour`と`has_many`関係にあります。これにより、一つの営業日が複数の営業時間を持つことができます。また、`dependent: :destroy`オプションがこちらにも設定されており、営業日が削除されると、それに紐づく営業時間も同時に削除されます。
- `Company`モデルは、`accepts_nested_attributes_for :company_business_days, allow_destroy: true`を使用して、ネストされた属性の削除を許可し、フォームから直接関連する`CompanyBusinessDays`とその下にある`CompanyBusinessHours`を作成または更新できるようにしています。
- `CompanyBusinessDay`モデルは、`accepts_nested_attributes_for :company_business_hours, allow_destroy: true`を使用して、同様にネストされた属性の削除を許可し、関連する`CompanyBusinessHours`の作成や更新を容易にしています。

## 詳細

### 問題の発生
アプリケーションでは、`Company`、`CompanyBusinessDay`、`CompanyBusinessHour`の3つのモデルが関連付けられており、`dependent: :destroy`オプションを用いていました。しかし、`Company`を削除しようとすると上記の外部キー制約違反エラーが発生していました。

### 原因分析
エラーの原因は、データベースレベルで`CompanyBusinessDay`または`CompanyBusinessHour`への外部キー制約が`on_delete: :cascade`オプションを持たなかったことにありました。そのため、親モデルの削除が子モデルの自動削除をトリガーしていませんでした。

### 解決策の実装
解決策として、新しいマイグレーションを作成し、外部キー制約に`on_delete: :cascade`オプションを追加しました。具体的には以下のステップを実行しました。

1. 新しいマイグレーションファイルの生成:
```bash
rails generate migration AddOnDeleteCascadeToCompanyBusinessHours
```

2. 生成されたマイグレーションファイルを以下のように編集:
```ruby
class AddOnDeleteCascadeToCompanyBusinessHours < ActiveRecord::Migration[7.0]
  def change
    remove_foreign_key :company_business_hours, :company_business_days
    add_foreign_key :company_business_hours, :company_business_days, on_delete: :cascade
  end
end
```

3. マイグレーションの適用:
```bash
rails db:migrate
```

### 結果
この変更により、`Company`モデルの削除時に`CompanyBusinessDay`および`CompanyBusinessHour`が正しく削除されるようになり、外部キー制約違反のエラーが解消されました。

### 注意点
この変更を適用する前には、必ずデータベースのバックアップを取ることをお勧めします。また、開発環境でのテストを十分に行い、本番環境への適用前に予期せず動作することがないようにしてください。
M1 Macにhomebrewでnginxをインストールした時のディレクトリ構成

迷いに迷ったのでとりあえずメモ。

MacOS 14.2.1です。

# エラーログ
```
$> ls /opt/homebrew/Cellar/nginx/1.25.4/logs/
error.log
```
configファイルに書いてみたパスのエラーログはなぜか利用されなかった。。

# Configuration Files
```
$> ls /opt/homebrew/etc/nginx/
fastcgi.conf           koi-utf                nginx.conf             servers
fastcgi.conf.default   koi-win                nginx.conf.default     uwsgi_params
fastcgi_params         mime.types             scgi_params            uwsgi_params.default
fastcgi_params.default mime.types.default     scgi_params.default    win-utf
```

# リソースファイル
```
$> ls /opt/homebrew/Cellar/nginx/1.25.4/html/ 
50x.html   index.html
```

追加するかもしれませんがとりあえずこれだけ！
【Flutter】Riveアニメーションを使って猫の目にカーソルを追わせてみた

## はじめに
Flutterの[海外のYouTube](https://www.youtube.com/watch?v=Z1KT21h4Vjw )を見ていたら面白いアニメーションライブラリが流れてきたので、真似して実装してみました。


## 今回作るもの
猫の目がカーソル（指？）を追いかけるようなアニメーションです。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/d5705efe-f88b-efd7-2698-4b92668b7c94.png" >

## 開発環境
- Flutter: 3.14.0
- Dart: 3.2.0
- rive: 0.12.4

## 1. riveのダウンロード
riveファイルをダウンロードし、します。
私は[こちら](https://editor.rive.app/preview/3920-8202-cat-following-the-mouse/802256?mode=animate&artboard=Cat&animation=State%20Machine%201)のサイトからダウンロードしました。

#### 〜ダウンロード手順〜
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/b070d4da-5cce-db3b-a701-777be579c6dd.png)

## 2. riveファイルをassetsディレクトリに移動し、pubspec.yamlに追加する
① assetsディレクトリを作成し、ダウンロードしたriveファイルを挿入します。
② pubspec.yamlに`assets/cat.riv`を追記します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/2d99e494-497b-0f72-d7aa-b5a14298c7b2.png)

## 3. riveライブラリの追加
以下のコマンドを実行するか、手動でpubspec.yamlに指定のバージョンを追記してください。
`flutter pub add rive`

https://pub.dev/packages/rive/install

## 4. コード
アニメーションを入れたい部分に以下のコードを追加してください。
#### クラス内
```dart
 StateMachineController? controller;
```
#### Widget内
```dart
      body: Container(
        width: double.infinity,
        child: RiveAnimation.asset(
          'assets/cat.riv',
          fit: BoxFit.fitHeight,
          stateMachines: const ['state'],
          onInit: ((artboard) {
            controller = StateMachineController.fromArtboard(
                artboard, 'State Machine 1');
            if (controller == null) return;
            artboard.addController(controller!);
          }),
        ),
      ),
```
以上で完成となります。
githubにコード全文を載せているので全て見たい場合はこちらをご覧ください。

https://github.com/TajimaMiho/rive_sample_app

## 最後に
遊び心でアニメーションを動かしましたが、楽しいですね！これからも色々触っていこうと思います。
new_framework_defaults_x_xを更新しても、値が反映されないことがあるので注意

Railsのアップデートの際に、新しいバージョンの config のデフォルト値を少しずつ反映させるときに `new_framework_defaults_x_x` を使うと思います。

今回、`config.load_defaults 6.1` へ上げる前に、`Rails.application.config.active_record.has_many_inversing = true`の設定をしても反映されないことがありました。

:::note
たまたま今回は has_many_inversing でハマりましたが、他の設定でも同様ですし、new_framework_defaults 以外の `config/initializers/*` での設定も同様に`Rails.application.config.xxx`の設定が反映されない可能性があるので記事にしてみました。
:::

## 結論

初期化時の読み込み順によっては、`config/initializers/*` のファイルの設定値が反映されないことがあるので、 その場合は`config/application.rb`などの`Rails.application.initialize!`を実行する前に設定する必要があるようです。

RailsにもIssueとして上がっていました。

https://github.com/rails/rails/issues/50133

## 少し解説

:::note warn
今回、具体的な原因特定はできていないので、詳しくは上記のIssueを確認してください
:::

:::note
Rails v6.1の実装の話をしますが、v7.0では少し変わっています
:::

`Rails.application.config.active_record.has_many_inversing` に値をセットすることで、`ActiveRecord::Base.has_many_inversing`に値をセットすることができます。

`ActiveRecord::Base.has_many_inversing`は内部で`invertible` かの判定に使われています[^1]
[^1]: https://github.com/rails/rails/pull/37429

今回、以下のように設定したのですが、

```rb:config/initializers/new_framework_defaults_6_1.rb
Rails.application.config.active_record.has_many_inversing = true
```

以下のように、`ActiveRecord::Base.has_many_inversing`には値が反映されていませんでした。

```rb
[1] > Rails.application.config.active_record.has_many_inversing
=> true
[2] > ActiveRecord::Base.has_many_inversing
=> false
```

ちなみに、 config/application.rb に記述したところ、反映されていました。

```rb:config/application.rb
Module Hoge
  class Application < Rails::Application
    # ...
    config.active_record.has_many_inversing = true
    # ...
  end
end
```

### 調査をしたこと

`ActiveRecord::Base.has_many_inversing`のgetterは以下で定義されています。

https://github.com/rails/rails/blob/v6.1.7/activerecord/lib/active_record/core.rb#L148

```rb
module ActiveRecord
  module Core
    extend ActiveSupport::Concern

    included do
      # ...
      mattr_accessor :has_many_inversing, instance_accessor: false, default: false
```

値をセットしているところを確認すると、以下のようになっていました。

https://github.com/rails/rails/blob/v6.1.7/activerecord/lib/active_record/railtie.rb#L204-L212

```rb
    initializer "active_record.set_configs" do |app|
      ActiveSupport.on_load(:active_record) do
        configs = app.config.active_record

        configs.each do |k, v|
          send "#{k}=", v
        end
      end
    end
```

`ActiveSupport.on_load(:active_record)`のフックは、 `ActiveRecord` がロードされると実行されるようです。

この処理が実行されるタイミングにログを仕込んでみたところ、初期化処理の`load_config_initializers`のタイミングよりも早くに実行されていることがわかりました。

おそらく、どれかのgemなどで `ActiveRecord` が読み込まれているのだと思われます。

## 今後

Rails側で、読み込みのタイミングにかかわらず、initializersで設定した内容が反映されるようになるといいですが、それまでは注意して確認する必要があります。
反映されない場合は `config/application.rb`の初期化実行前にセットする必要があります。

https://github.com/rails/rails/issues/50133

`config/initializers`でセットした内容が反映されないこともあるというのが盲点でもしかしたら他にもハマる人がいるかもしれないので、助けになると嬉しいです。

## 関連

https://railsguides.jp/initialization.html

https://railsguides.jp/configuring.html#%E3%82%A4%E3%83%8B%E3%82%B7%E3%83%A3%E3%83%A9%E3%82%A4%E3%82%B6%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%BF%E3%81%86
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

Ubuntu 20.04
XAMPP

mysql -u root -p コマンドを実行するとエラーが表示される
```
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
```

解決方法

/opt/lampp/etc/my.cnfファイルのsocketの設定値を確認する
```
socket		=/opt/lampp/var/mysql/mysql.sock
```
シンボリックリンクを作成する
```
sudo ln -s /opt/lampp/var/mysql/mysql.sock /tmp/mysql.sock
```
[AIX] カタログファイルの編集方法

### カタログファイルの編集方法
カタログファイルの編集には、dspcatコマンドとgencatコマンドを使用します。

下記はlibc.catの改行を削除するサンプルになります。
```
# dspmsg -s 1 libc.cat 2
このパス名のファイルまたは
ディレクトリーは存在しません。

# export LANG=Ja_JP
# cd /usr/lib/nls/msg/Ja_JP
# cp -p libc.cat libc.cat_bk
# dspcat -g libc.cat > libc.dspcat
# vi libc.dspcat

下記部分の\n\と改行を削除。
修正前:
2       "このパス名のファイルまたは\n\
ディレクトリーは存在しません。"

修正後:
2       "このパス名のファイルまたはディレクトリーは存在しません。"

# gencat libc.cat libc.dspcat

# dspmsg -s 1 libc.cat 2
このパス名のファイルまたはディレクトリーは存在しません。
```

### 備考
この改行の問題は下記APARで報告されていますが、FIN CloseとなっておりAIX 7.3でも修正はされていないようです。
IZ47193: JA_JP EXTRA NEWLINE IN LIBC.CAT
https://www.ibm.com/support/pages/apar/IZ47193

### 注意
製品として出荷されているファイルを編集することは正式にサポートされる手順ではないため、自己判断での実施が必要になります。
また、bos.msg.Ja_JP.rteファイルセットを更新した際に変更が元に戻るため、OSを更新した際には再修正が必要になります。
Vimで特定の行からファイルの最後までを削除する方法

Vimでファイルを開いた状態で、特定の行からファイルの末尾までのテキストを削除するには、いくつかの方法があります。ここでは、最も一般的で簡単な2つの方法を紹介します。

### 方法1: dコマンドとGコマンドの組み合わせ
1. Vimでファイルを開きます。
2. 削除を開始したい行にカーソルを移動します。
3. 削除コマンドを実行します。これを行うには、`d`を押した後に`G`を押します。このコマンドは「現在の行からファイルの最後までを削除する」という意味になります。

### 方法2: 範囲指定を使用する
Vimでは範囲を指定してコマンドを実行することもできます。この場合、削除したい範囲の開始行番号と終了行番号（この場合はファイルの終わりを意味する$）を使用して、削除コマンドを実行します。

1. Vimでファイルを開きます。
2. コマンドモードに入ります（`:`を押します）。
3. `:`[開始行番号]`,$d`と入力し、Enterを押します。例えば、5行目からファイルの最後までを削除したい場合は、`:5,$d`と入力します。

### 注意点
- Vimはモーダルエディタであり、コマンドを入力する前に適切なモード（通常はノーマルモード）にいることを確認してください。
- 削除操作は元に戻せます。間違って削除した場合は、uキーを押して元に戻すことができます。
- 大量のテキストを削除する際は、操作を実行する前に、ファイルのバックアップを取っておくことをお勧めします。

### まとめ
Vimでは、特定の行からファイルの最後までテキストを効率的に削除する方法がいくつかあります。dGコマンドの使用や範囲指定による削除は、テキスト編集の作業を迅速化する強力なツールです。これらのコマンドをマスターすることで、Vimでの編集作業がより快適かつ効率的になります。


https://www.vim.org/docs.php
円を描画する

# 関連記事

https://qiita.com/yokan/items/81eb493d177da9d96c56

https://qiita.com/yokan/items/0a2dc92f6b5876d52cd5


# 開発環境
- Windows11
- Visual Studio 2022
- DXライブラリ Ver3.24d

# 円の描画
`DrawCircle`関数を使用すると円を描画することができます。これは特定の座標に1ピクセルを描画するDrawPixel関数の機能を拡張したようなもので、指定された座標を中心として円が表示されます。

```cpp
#include "DxLib.h"

int WINAPI WinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpcmdLine, _In_ int nCmdShow )
{
    // ウィンドウモード
    ChangeWindowMode( TRUE );

    // DXライブラリの初期化
    if( DxLib_Init() == -1 )
    {
        // -1ならエラーとして終了
        return 0;
    }

    // 円を描画
    DrawCircle( 100, 100, 50, 0xFFFFFF, TRUE );

    // プログラムの一時停止
    WaitKey();

    // DXライブラリの破棄
    DxLib_End();

    return 0;
}
```

### 実行結果

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713748/935337d2-80a8-c880-64c9-0f040fbc9aa2.png)

引数は以下の通りです。

```txt:定義
int DrawCircle( int x, int y, int r, unsigned int Color, int FillFlag );
```

| 引数 | 説明 |
|:-|:-|
| int x | 描画する円のX座標 |
| int y | 描画する円のY座標 |
| int r | 描画する円の半径 |
| unsigned int Color | 描画する円の色 |
| int FillFlag | 塗りつぶしフラグ |

色の指定や塗りつぶしの有無は、[矩形を描画する](https://qiita.com/yokan/items/0a2dc92f6b5876d52cd5)際の方法と同様です。指定した色で円を一色で塗りつぶすことができ、塗りつぶしフラグをFALSEに設定することで、円の輪郭のみ描画することもできます。

```cpp
// 円を描画
DrawCircle( 100, 100, 50, 0xFFFF00, TRUE );
DrawCircle( 250, 100, 50, 0x00FFFF, FALSE );
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713748/8438b6f0-cb75-3266-8ef8-877636e30e39.png)

# 参考

- [DrawCircle](https://dxlib.xsrv.jp/function/dxfunc_graph0.html#R2N3)
Excelで正規表現を使う

Excelは正規表現を使えないというのが常識であったが、APIが公開されていた。
※とはいえMicrosoftとは書いておらず、無料のようだが機密情報や個人情報は扱わないように注意した方がよさそう

true or false型
https://excelapi.org/en/docs/language/regex-ismatch/

一致した部分を抽出
https://excelapi.org/en/docs/language/regex-match/

一致した部分を置換
https://excelapi.org/en/docs/language/regex-replace/
Laravel ログイン時に419画面へ遷移してしまう

# 現象
LaravelにBreezeで追加したログイン機能
ログインボタン押下時に419画面へ遷移してしまう。

# 環境
Laravel 10.41.0
Breeze 1.28.1

# 原因
1度目のログインボタンクリックにより、CSRFトークンが送信される。
2度目のログインボタンクリックにより、先ほどと同じCSRFトークンが送信される。
このCSRFトークンは使用済みのため、不正なトークンと判定されて419画面へ遷移してしまう。

今回自分が遭遇したケースは、breezeで自動生成したログイン機能が、ボタン連打を考慮していない作りだったのが原因と考えています。

# 解決した方法
以下のJSを追記
formのsubmitをトリガーに、ログインボタンをdisabledにするように修正

```JS
    document.getElementById('login-form').addEventListener('submit', function() {
        document.getElementById('login-button').setAttribute('disabled', 'disabled');
    });
```
# 注意
Laraveで419画面へ遷移してしまう現象の中で、今回のケースは多分稀なタイプです。
以下の記事によく遭遇しそうな内容が記述されているので、今回のケースと一致しなかった方はそちらを参考にしてみてください。
[【 Laravel】419セッションエラーの原因と対策をすべて網羅。token miss match. 419 Sorry, your session your page has expired]()


# 参考にしたURL
[Laravel】@csrfディレクティブがあるのに419エラーが発生する【Android Chrome】](https://zenn.dev/tusi/articles/4ce1b15398eab8)
[419 Login Link Expired Errors - On mobile only?](https://laracasts.com/discuss/channels/laravel/419-login-link-expired-errors-on-mobile-only)
php.iniを書き換えているのに、phpMyAdminで大容量CSVをダウンロードすると"Maximum execution time of 300 seconds exceeded in"

# 問題
php.iniのmax_execution_timeを300以上にしているのに、大容量のCSVをダウンロードすると、「Maximum execution time of 300 seconds exceeded in…」と表示されてタイムアウトする。

# 解決方法
\phpMyAdmin\libraries\config.default.phpの$cfg['ExecTimeLimit']も書き換える必要がある。

# 後書き
php.iniだけじゃ駄目なんですね…。

# 参考
https://kojikoji75.hatenablog.com/entry/2014/01/11/205736
私たち「組込屋（エンジニア）」はどこへ行く？（早速「Free沼」に ハマった編　その１）

https://qiita.com/Cente_mw/items/e3cec7e4bc9a39ea1c29

に、<b>「Free 沼」</b>（私の造語）の事を書きました。
●買って来ればFreeでキッチリ動く環境が手に入る「型にはまった開発」であれば、苦労は無いと思いますが、そこから少しでも外れたら。。。
●「型から外れた」瞬間の技術的ギャップは相当に大きくなっており、そのギャップに対応するエンジニアスキルは相当磨かれたものが必要。。。

まさか、こんな記事を書いた自分がその「Free沼」にハマるとは。。。こんなにも早く。。。

さて、FreeRTOSという組込環境がAmazonからリリースされていますので使われている方も多いのではと思います。

![FreeRTOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032022/08c531ac-86b2-b945-e282-24aeb72229fd.jpeg)

出典：https://aws.amazon.com/jp/freertos/


CenteもメインターゲットにしているITRON系のリアルタイムOSであり、セマフォやタスクなど、ITRONを知っているエンジニアには使い慣れた環境かと思います。
そして、世の中を見渡すと広報として「FreeRTOS対応」を謳っているプロセッサや評価基板などが多く出回っています。私たちもそのいくつかを入手して動作させていますが、、、最近私とエンジニアの間でこんな会話がありました。

私：「前に買ったFreeRTOSが乗った評価基板を最新の状態にしてAmazonAWSサーバーに繋がるようにして！」
エ：「色々大変なんです。新しい基板が出ているので買っても良いですか？」
私：「え？FreeRTOS対応な基板を買ったはずだからAmazonから最新コードを引っ張ってきてVerUpすればよいのでは？」
エ：「いや、それが。。。」

エンジニア曰く、

・「前に買った基板」のサンプルコードは、購入当時のFreeRTOSのバージョンがインストールされているがその後メンテナンスされていない
　→最新のものをどのように移植したら良いかを調べるところから始めないといけない。どの程度の工数なのか読めない
 
・そもそもネットワークプロトコルスタックlwIP(＊1)やブートローダーMCUBoot(＊2)など、いろいろな箇所にFreeRTOS以外のフリーソースが使われており、これらも最新にする必要があるか不明
　→ついでにネットワークプロトコルスタックはFreeRTOSが公開しているFreeRTOS-Plus-TCP(＊3)があるはずなのに、なぜ使われていないのか、lwIPから載せ替えたほうがいいのか

とか、いろいろと大変な事になる、、、という話なのです。

＊1 lwIP 組込機器向けに設計されたオープンソースの小型TCP/IPプロトコルスタック
https://savannah.nongnu.org/projects/lwip/

＊2 MCUBoot 32bitマイクロプロセッサ向けのセキュアブートローダ（オープンソース）
https://docs.mcuboot.com/

＊3 FreeRTOS-Plus-TCP FreeRTOS標準のTCP/IPプロトコルスタック
https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/index.html


え？要約すると「買ってきたまま使うには良いけど、最新にしたり、環境を変更したりするのは大変で、新しく基板ごと購入した方が安いし楽だし安心だ」という主張の様です。

え、え、え、これ、<b>「Free沼」</b>そのものでは？

私たち「自分たちが世に出した製品はしっかりサポートすること」を大事に思っている者としては、「前に買った評価基板・ソフト環境」のサポートってどうなっているのよ！　（確かに安かったけど、タダより安いものは無い！って事？？？）っと思ってしまうわけです。

結局、新しい基板（B-U585i-IOT02A）を買ってしまいましたが、、、転んでもタダでは起きんぞ！っということで深掘りします。。

![B-U585i-IOT02A_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032022/e3e56f12-c71c-8e1c-cfe3-bee8ff28acd2.jpeg)
出典：https://www.st.com/ja/evaluation-tools/b-u585i-iot02a.html


　どうして、このFree環境では基板の買い替えまで発展してしまったんだろうか？
　これからハードウェアやソフトウェアの評価を開始するときには、どんな視点が必要なんだろうか？

そんな視点で「ミドルウェア屋」の立場から書いてみたいと思います。

本記事ではここまで。続きを読んでみたいな、、、という方は、いいね！やコメントなどで反応をお願いします。調査考察して（ミドルウエアベンダーという色眼鏡をなるべく少なくして）事実をご報告していきます。



---
Cente：
https://www.cente.jp/

お問合せはこちら：
https://www.cente.jp/otoiawase/
【BizRobo!】変数をロボット内で使用しているかどうかを確認する方法

不要変数を削除したい時に、どの変数をロボット内で使用しているか？を確認する簡単な方法があります。

DSの変数一覧から試しに変数を削除してみましょう。

すると、その変数を使用しているステップで赤△の警告マークが出てきます。

ステップ内を確認すると、どの部分で変数を使用しているかが分かります。

逆に、変数を削除しても何も警告が出ない場合は、その変数はロボット内に残存している不要変数になります。

気にせず消してしまいましょう。

以上です。
QuickSightでフロアマップ上にバブル表記を行う方法

フロアマップ上にバブル表記で売上などを可視化する方法をご紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694674/8e15382a-2de2-e811-b6d2-6df110acbb1b.png)
専用のビジュアルは存在しないため、フリーフォームを使用し画像の上に散布図を配置する方法で実装したいと思います。
※地図上に表示する場合は「地図上のポイント」というビジュアルを使うことで可視化することができます。

## フロアマップの準備
フロアマップを画像形式で作成し、publicアクセス可能な場所へ配置します。
※QuickSightで画像を埋め込む場合、カスタムビジュアルコンテンツを使用する必要がありますが、publicアクセス可能なURLしか指定することができません。

## データセットの準備
今回はサンプルとして下記のCSVを作成し、QuickSightへアップロードします。
```csv
店舗名,座標X,座標Y,売上
店舗A,0,19,20
店舗B,0,12,40
店舗C,0,4,20
店舗D,4,0,40
店舗E,17,0,60
店舗F,30,0,20
店舗G,40,8,80
店舗H,40,15,30
店舗I,36,20,20
店舗J,26,20,50
店舗K,15,20,40
店舗L,6,20,20
店舗M,10,12,60
店舗N,15,12,40
店舗O,24,9,100
店舗P,12,7,30
```
## ダッシュボードの作成
### フリーフォームに設定
ヘッダーの「編集」→「分析設定」からフリーフォームを指定します。
フリーフォームに設定することで、画像の上にグラフを重ねることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694674/32094d0a-5c46-b7d6-2f13-efa8f8189852.png)

### フロアマップを挿入
カスタムビジュアルコンテンツを選択し、プロパティから画像のURLを指定します。
「イメージとして表示」のチェックもONにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694674/dde524c7-16d2-9c61-b577-35728090f4a3.png)

### 散布図の挿入
散布図を選択し、X軸に「座標X」、Y軸に「座標Y」、サイズに「売上」を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694674/e843fc2a-f233-9bfc-0264-39706bf1b709.png)

次に、散布図のプロパティから、下記項目を非表示にします。
- タイトル
- サブタイトル
- 背景
- 境界
- 選択
- X軸のタイトル
- X軸の目盛
- X軸のラベル
- X軸のグリッド線
- Y軸のタイトル
- Y軸のラベル
- Y軸のグリッド線
<br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694674/95767ec0-1148-e46d-4c72-e6bfb9b4c4d2.png)

上記の項目を非表示にすると、下記の図のような散布図ができるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694674/1b9f59dc-3bae-4973-d49d-183a502195c4.png)

### 画像の上に散布図を重ねる
画像の上に散布図を重ねると、ほぼ完成です。
バブルの位置を調整したい場合は、散布図のプロパティからX軸とY軸の上限と下限を設定してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694674/5f84906d-30a9-6119-6931-0260f3aa1eb4.png)

デフォルトのチャートの色が見ずらいため、色の変更を行えば完成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694674/75c09909-2758-f3c1-0885-6cfbddd69403.png)

## 最後に
散布図のX軸とY軸を調整し、画像の上に綺麗に配置するのは大変ですが、一度指定すれば後は売上を変えるだけでリアルタイムに売上を可視化することができます。
実際の業務でも使えると思います。

## 参考
AWS社が公開しているダッシュボードも参考になりますので、ぜひ確認してみてください。
https://democentral.learnquicksight.online/#Dashboard-FeatureDemo-Free-form-Theater-Seating
※左メニューの編集（鉛筆）アイコンで実装を確認することも可能です。
Hello Worldからの復習 〜データ型編〜

何とな〜く覚えただけで終わらせてしまうと毎回ググれカス止まりで、毎回調べて時間をロスしてしまう気がしています。

大体、毎回、いつも同じメンバーと再会。状態。

しっかり理解し、自然と使えて応用が出来て、何故この記述でこの処理なのかを分かりやすく説明できて初めて理解した状態になるんだと思う。
まだまだです。。
毎回話しの枕が長いが、今回は**データ型**の復習。

##### お品書き
+ データ型って？
+ 基本データ型Sample
+ 参照型
+ 参照型Sample

----

**データ型って？**
-
##### データ型の種類
##### ◆基本データ型
データ型は約3000種類あると言われていますが、その中で8種類が基本データ型。
なんなら**8種類しかない。**

##### ①整数型
| 型名 | サイズ | 表現可能な桁数 |
|:-:|:-:|:-:|
|**byte**|**8ビット**| -128～127   |
|**shoat**|**16ビット**|  -32.768～32.767 |
|**int**|**32ビット**| -2147483648～2147483647  |
|**long**|**64ビット**|-9223372036854775808～9223372036854775807   |
##### ➁少数
| 型名 | サイズ | 表現可能な桁数 |
|:-:|:-:|:-:|
|**float**|**32ビット**|4バイトの単精度 浮動小数点数|
|**double**|**64ビット**|8バイトの単精度 浮動小数点数|
##### ➂文字
| 型名 | サイズ | 表現可能な桁数 |
|:-:|:-:|:-:|
|**char**|**16ビット**|1文字(Unicode)|
##### ④真偽値
| 型名 | サイズ | 表現可能な桁数 |
|:-:|:-:|:-:|
|**boolean**| - |true(真)またはfalse(偽)|

数値はデフォルトで`int`と`double`
→float型の少数には`f(F)`を、long型の整数には`l(L)`をつける。
※下記にサンプル有

文字のデータは`'シングルクォーテーション'`で囲む
##### ◆参照型
基本データ型以外全て。
基本データ型か基本データ型以外か。的な。
##### ①文字列
##### ➁配列
etc...

**基本データ型Sample**
-

```java:java
class Third{
	public static void main(String[] args){
		int month = 3 ;
		int day = 21 ;
		float weight = 75.0f ; 
		double height = 171.5 ;
		char bloodType = 'A' ;  
		

		System.out.println("誕生日は" + month + "月" + day + "日です");
		System.out.println("身長は" + height + "cm、体重は" + weight + "kgです");
		System.out.println("血液型は" + bloodType + "型。");
		System.out.println("プログラミングの理解を深めていきます。");
	}
}
```

float型は値の後にf(F)をつけないとコンパイルエラーになる。

```java:java
float weight = 75.0f ;
```
```cmd:cmd
C:\Java\1>javac Third.java
Third.java:5: エラー: 不適合な型: 精度が失われる可能性があるdoubleからfloatへの変換
                float weight = 75.0 ;
                               ^
エラー1個
C:\Java\1>
```

**参照型って？**
-
型名は大文字から。値は`"ダブルクォーテーション"`で囲む
```java:java
		String name = "だいすけ" ;
```
わかりやすい説明だと、name という変数にだいすけという値が入る。みたいな説明がされる。
例えて言うならこんな感じ↓

|Saring| | 値 |
|:-:|:-:|:-:|
|name| ←代入 |だいすけ|

実際は`"だいすけ"`という文字列がメモリ上のどこにできたかというアドレスの値が格納される動きらしい↓
```mermaid
classDiagram
  class A001{
    だいすけ
    }
  A001 --> "参照"name
  class name{
  A001
  }
  name --> "格納"A001
```
文字列は作ってみないと何文字になるか、メモリがどれくらい必要かわからない。
その時々に合わせて必要なメモリを確保し、確保した場所のアドレスを変数に格納する。
これはメモリを有効に使う仕組みになっている。

そのアドレスの値を**参照値**といい、
この参照値が変数に格納されるため**参照型**という。

**参照型Sample**
-

```java:java
class Third{
	public static void main(String[] args){
		int month = 3 ;//ここから↓
		int day = 21 ;
		float weight = 75.0f ; 
		double height = 171.5 ;
		char bloodType = 'A' ; //ここまでが基本データ型 
		
		String name = "だいすけ" ; //参照型
		
		System.out.println("こんにちは！私は" + name + "といいます");
		System.out.println("誕生日は" + month + "月" + day + "日です");
		System.out.println("身長は" + height + "cm、体重は" + weight + "kgです");
		System.out.println("血液型は" + bloodType + "型。");
		System.out.println("プログラミングの理解を深めていきます。");
	}
}
```

```cmd:cmd
C:\Java\1>javac Third.java

C:\Java\1>java Third
こんにちは！私はだいすけといいます
誕生日は3月21日です
身長は171.5cm、体重は75.0kgです
血液型はA型。
プログラミングの理解を深めていきます。
```

ようするに

**基本データ型はデータそのものが変数に入り、参照型は参照値がはいる**


なるほどねぇ。
【Rails】CDNを利用してBulmaを導入する

## はじめに
**自己紹介**
　未経験からWEB系エンジニアへの転職を目指している者です。現在はRuby on Railsを学習中です。

**この記事を書いたきっかけ**
　フロントエンドとバックエンドは分けずに手軽にビューを作成したいと思い、CSSフレームワークのBummaを導入したので学習記録として記事を書きました。

## 動作環境
- mac OS Sonoma 14.2.1
- ruby 3.2.2
- rails 7.0.7

## Bulmaの導入方法を調べてみた
Bulmaの導入方法を調べたところ、以下の方法がありました。
- 公式サイトからダウンロードする
- npmなどのパッケージマネージャー使う
- CDNを利用する
- bulma-railsというgemを使う

今回は特にこだわりもなかったので、一番簡単に使えそうなCDNを利用する方法を選ぶことにしました。
以下のリンクはBulma公式サイトのスタートガイドです。

https://bulma.io/documentation/overview/start/#bulma-start

## CDNって何？
CDNを利用してBulmaを使うと決めたのですが、「そもそもCDNって何？」となったので少し調べてみました。
- CDNとは
  - "Contents Delivery Network"の略
  - 日本語では"コンテンツ配信ネットワーク"と呼ばれる
  - CDNを使うことでWebコンテンツを迅速かつ効率よくユーザーに配信することができる

本題から外れるためCDNの仕組みについてはここでは触れませんが、下記サイトにて分かりやすく解説されていたので気になる方は参照ください。

https://www.kagoya.jp/howto/it-glossary/web/cdn/

## CDNを利用してBulmaを導入する
CDNを使ってBulmaを導入する方法は簡単で、下記のように`application.html.erb`にlinkタグを1行追加するだけです。
必要なlinkタグは以下のように、Bulma公式サイトのスタートガイドに掲載されています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625095/4d67f840-109f-b63a-530d-7ec01dbabe93.png" width="50%">


```erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>HogeApp</title>
    <title>HogeHoge</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    
    <%# 下記の1行を追加する　%>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
    
    <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track": "reload" %>
    <%= javascript_importmap_tags %>
  </head>
  <body>
  </body>
</html>
```
## 動作確認
　Bulmaが問題なく導入できているか確認するため、bodyタグの中に以下の記述を追加してページを表示してみてください。
```erb
<%# `button`でボタン要素を`is-successs`で緑色を指定する　%>

<button class="button is-primary">
  Hello World!
</button>
```
下記のように、緑色の"HelloWorld!"ボタンが表示されていればOKです！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625095/6f6618fe-dff8-48a6-b4ff-d1bf7e59f94c.png" width="50%">

　BulmaはModifiersと呼ばれるクラスを追加して要素、色、大きさを指定することができます。
 詳細は参考に貼っている公式ドキュメント等を参照してください。

## 参考

https://bulma.io/documentation/

https://johobase.com/bulma-getting-started-tips/#Bulma

https://qiita.com/ochiochi/items/de1afd2d3fc8f6d3ea55#bulma%E3%81%AE%E5%9F%BA%E6%9C%AC
ABC備忘録【AtCoder Beginner Contest 342 D - Square Pair】

# はじめに
AtCoderの勉強を始めたので、備忘録がてら応用できそうで印象に残った問題の解説記事を投稿していこうと思います。
この記事では、初めて自分が参加したコンテストのAtCoder Beginner Contest 342 D - Square Pairについて解説していきます。

# 自己紹介
文系大学出身、数学は大学受験レベル、Webエンジニア3年目
Webアプリ開発とWebApi+アプリ開発を主に業務行っています。
言語はRuby,JavaScript,Swift,Go,Kotlinの経験があります。
AtCoderの勉強は始めたばかりでコンテストもABC342(2024/02/24開催)が初参加。
AtCoderではPythonを使っています。

# 問題の概要
https://atcoder.jp/contests/abc342/tasks/abc342_d

与えられた非負性数列から、積が平方数になる整数ペアの数を求める問題です
# 考えたこと

ある整数が平方数である条件は「素因数の指数が全て偶数である」と考えることができます。
例えば60は`2**2 * 3**1 * 5**1`となり2,5の指数が偶数でないため平方数ではありません。
144であれば`2**4 * 3**2`となって、全ての素因数の指数が偶数なため平方数であるといえます。
そこで今回は、与えられた非負整数配列に対して素因数分解を行い、指数を偶数にすることができるペアの数を求めるという方向で考えていきます。

# 提出したコード
```python
import sys
from collections import defaultdict


# エラトステネスの篩を用いてn以下の最小素因数を格納した配列を返す
def sieve(n):
    spf = list(range(n + 1))
    for i in range(2, int(n**0.5) + 1):
        if spf[i] == i:
            for j in range(i * i, n + 1, i):
                if spf[j] == j:
                    spf[j] = i
    return spf


# xを素因数分解する
def factorize(x, spf):
    res = []
    while x != 1:
        factor = spf[x]
        count = 0
        while x % factor == 0:
            x //= factor
            count += 1
        res.append([factor, count])
    return res


N = int(sys.stdin.readline())
l = list(map(int, sys.stdin.readline().split()))
spf = sieve(max(l))

# 奇数回出現する素因数のリスト
odd_factor_lists = []
for num in l:
    if num != 0:
        factors_with_exponents = factorize(num, spf)
        of = []
        for factor, exponent in factors_with_exponents:
            if exponent % 2 != 0:
                of.append(factor)
        odd_factor_lists.append(of)

# 奇数回出現する素因数のパターンに基づくカウント
odd_factors_count = defaultdict(int)
for odd_factors_list in odd_factor_lists:
    pattern = tuple(odd_factors_list)
    odd_factors_count[pattern] += 1

zero_count = l.count(0)
# 0と0以外の要素のペアの数と0同士のペアの数をカウント
count = zero_count * (N - zero_count) + zero_count * (zero_count - 1) // 2
# 奇数回出現する素因数のパターンに基づくペアの数をカウント
for v in odd_factors_count.values():
    count += v * (v - 1) // 2
print(count)
```

# 終わりに
最後まで読んでいただきありがとうございます。
Python、AtCoder共に初心者なので、より良い解法やコードがあればコメントでご指摘いただけると嬉しいです。
とりあえず、入茶を目指して頑張ります。

03/01追記
よりコードがシンプルになる解法があったので、それについても記事を書いています。合わせてご覧ください。

https://qiita.com/Yporon/items/1bc4ce1038271ed5346f
サーバーダウン調査報告書（2024/02/19）

# サーバーダウン調査報告書

## 目次
1. 今回使う用語
2. 前提
3. 原因
4. 何故サーバーが落ちた？
5. 再発防止策

**今回使う用語**
- Fargate
  - サーバーレスで、dockerコンテナを簡単かつ効率的にデプロイして、管理できるもの
- タスク
  - dockerコンテナを実行するための単位
  (laravelコンテナとnginxコンテナで1タスクみたいな感じ)
- タスク定義
  - タスクを起動するための定義書
  (CPUとかメモリとかdockerイメージ、アプリ内で使う環境変数とか)
- ECR
  - dockerイメージを管理するレジストリ
  (dockeer hubと同じ)
- パラメータストア
  - 環境変数とか機密情報を管理するAWSのサービス

**前提**
- 環境変数は全てパラメータストアで管理
- 検証環境のソースコードと本番環境のソースコードが一致していない
- 検証環境と本番環境では参照している環境変数名が異なる
  - 検証では`AA`を使ってるが本番では`BB`を使ってるみたいな感じ

そうなってしまっている理由
→BTの他のサービスのインフラを構築した時に考慮を忘れていた

**原因**
ECRのdockerイメージを環境毎（検証用、本番用）に分割していなかった
要するに本番環境に検証用のソースコードが使われていた

**何故サーバーが落ちた？**
タスク更新のタイミングで検証用のdockerイメージにすり替わった
> 要するに本番環境に検証用のソースコードが使われていた

ということは検証用のソースコードからは`AA`という環境変数を参照したいが本番環境には`AA`という環境変数が設定されていない
結果ビルドエラーになる

タスク起動から停止までの流れとしては
タスク起動→ビルドエラー→ヘルスチェック失敗→タスク停止→タスク起動...
なのでいつまで立ってもタスクが正常に立ち上がらずサーバーが落ちているという状況になったというのが結論

**再発防止策**
ECRのdockerイメージを環境毎（検証用、本番用）に分割する
そうすることで、検証環境と本番環境のdockerイメージが混同することを防ぐことができる。
pythonで電卓（ちょいむずめ）（解説はありません）（コードだけ）

# 電卓のコード

```python:電卓.py
import tkinter as tk
import math

class AdvancedCalculator(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Advanced Calculator")
        self.geometry("400x600")
        self.result_var = tk.StringVar()

        # エントリウィジェット
        entry = tk.Entry(self, textvariable=self.result_var, font=('Helvetica', 20), justify='right')
        entry.grid(row=0, column=0, columnspan=5, padx=10, pady=10, ipadx=8, ipady=8)

        # ボタンのレイアウト
        buttons = [
            ('7', 1, 0), ('8', 1, 1), ('9', 1, 2), ('/', 1, 3),
            ('4', 2, 0), ('5', 2, 1), ('6', 2, 2), ('*', 2, 3),
            ('1', 3, 0), ('2', 3, 1), ('3', 3, 2), ('-', 3, 3),
            ('0', 4, 0), ('.', 4, 1), ('=', 4, 2), ('+', 4, 3),
            ('sqrt', 5, 0), ('C', 5, 1), ('^', 5, 2), ('(', 5, 3),
            (')', 6, 0), ('sin', 6, 1), ('cos', 6, 2), ('tan', 6, 3),
            ('log', 7, 0), ('exp', 7, 1), ('!', 7, 2), ('π', 7, 3),
        ]

        for (text, row, col) in buttons:
            tk.Button(self, text=text, padx=20, pady=20, font=('Helvetica', 14),
                      command=lambda t=text: self.button_click(t)).grid(row=row, column=col)

    def button_click(self, value):
        current = self.result_var.get()

        if value == '=':
            try:
                result = eval(current)
                self.result_var.set(result)
            except Exception as e:
                self.result_var.set("Error")
        elif value == 'C':
            self.result_var.set("")
        elif value == 'sqrt':
            try:
                result = math.sqrt(eval(current))
                self.result_var.set(result)
            except Exception as e:
                self.result_var.set("Error")
        elif value == '!':
            try:
                result = math.factorial(int(eval(current)))
                self.result_var.set(result)
            except Exception as e:
                self.result_var.set("Error")
        elif value == 'π':
            self.result_var.set(current + str(math.pi))
        else:
            self.result_var.set(current + str(value))

if __name__ == "__main__":
    app = AdvancedCalculator()
    app.mainloop()
```
以上です☆
EC2 on EKSのワーカーノードがクラスタに参加できない

EKSのワーカーノードとしてEC2を利用する方に向けてです。
※EC2構築には起動テンプレートを利用しています

「ワーカーノードが参加できません」←このエラー、解消までかなり時間がかかりました…
同じように悩んでいる人がいたらぜひ参考にしていただきたいです！

### 起動テンプレートのユーザデータを編集する
起動テンプレートには以下の情報を含める必要があります。
 ```
#!/bin/bash
set -o xtrace
CLUSTER_CA=<認証機関情報>
API_ENDPOINT=<APIサーバーエンドポイント>
/etc/eks/bootstrap.sh <クラスタ名> --b64-cluster-ca $CLUSTER_CA --apiserver-endpoint $API_ENDPOINT --dns-cluster-ip <DNS Server IP>
```

認証機関やAPIサーバーエンドポイントについては、マネジメントコンソールでEKSに入り、対象のEKSクリックしたら出てきます。
DNS Server IPについては、EKS＞対象クラスター名＞ネットワーキング＞サービスIPv4範囲のCIDRを取得し、/16を取る＆末尾の0を10に変換で値になります。
※例えば111.20.0.0/16だったら、111.20.0.10

### それでも治らない場合
①ワーカーノード（EC2）にSSH接続する
②kubeletのログを見る
```
cd /var/log
journalctl -u kubelet
```