OmniAICreator/Qiita-1.07M huggingface dataset:
Hello, World!もfizzbuzzも0バイトで作れるプログラミング言語を作ってやる

:::note
この記事も、[plaintext](https://qiita.com/kokecoco/items/098ee8a54851b1ad4107)でコーディングされています。詳しくはリンク先の記事を参照してください。
:::

# きっかけ
FizzBuzz問題を1文字で実行できるgs2というプログラミング言語があるらしいので、0バイトでFizzBuzzもHello, World!も実行できるプログラミング言語を作ってやろうということになった。

# 実行してみる
```lazylang:main.ll
```
これを実行すると、
```plaintext:実行結果
Hello, world!
```
そして、
```lazylang:main.ll
```
これを実行すると、
```plaintext:実行結果
1
2
Fizz
4
Buzz
Fizz
7
8
(中略)
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
```
となる。

**...は？**

# ネタバレ
これはインタープリタ側でコードを実行しているだけ。
インタープリタのオプションでどちらを実行するか指定して、ファイルが空なら指定した方を実行するだけである。実装はPythonで行われており、以下の通りである。
```python:lazylang.py
import sys
import argparse


def fizzbuzz():
    for i in range(1, 101):
        if i % 3 == 0 and i % 5 == 0:
            print("FizzBuzz")
        elif i % 3 == 0:
            print("Fizz")
        elif i % 5 == 0:
            print("Buzz")
        else:
            print(i)


def hello_world():
    print("Hello, World!")


def interpret_file(file_path, mode):
    try:
        with open(file_path, "r", encoding="utf-8") as file:
            code = file.read().strip()
            if code == "":
                # ファイルが空の場合は選択されたモードに応じたデフォルト動作を実行
                if mode == "fizzbuzz":
                    fizzbuzz()
                elif mode == "hello":
                    hello_world()
            else:
                # ファイルに内容があれば、そのコードをPythonコードとして実行
                try:
                    exec(code)
                except Exception as e:
                    print(f"エラー: {e}")
    except FileNotFoundError:
        print(f"エラー: ファイル '{file_path}' が見つかりません。")
    except IOError as e:
        print(f"エラー: ファイル '{file_path}' の読み取り中にエラーが発生しました: {e}")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="FizzBuzzまたはHello, World!の実行を選択できるインタープリタ"
    )
    parser.add_argument("file", help="実行するファイルのパス")
    parser.add_argument(
        "--mode",
        choices=["fizzbuzz", "hello"],
        default="fizzbuzz",
        help="デフォルト動作を選択します（デフォルトはFizzBuzz）",
    )

    args = parser.parse_args()

    interpret_file(args.file, args.mode)
```
これをpyinstallerで実行可能ファイルにし、それに--mode fizzbuzzを指定すればfizzbuzzが、--mode helloを指定すればソースコード自体は0バイトでfizzbuzzもHello, world!も実行できる。
fast API serverを起動する際の備忘録（サンプル実行編）

fast API serverを起動する際の備忘録（サンプル実行編）

> https://fastapi.tiangolo.com/

# install

venv環境を作りつつ、以下を通じてインストールする

> Create and activate a virtual environment and then install FastAPI:

```sh
pip install "fastapi[standard]"
```

venv

```sh
(recommend) use on venv
# cd (working directry)
python3 -m venv venv
source venv/bin/activate
# (deactivate)
```

# code

[https://fastapi.tiangolo.com/#example](https://fastapi.tiangolo.com/#example)

```py:main.py
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}
```

コマンドラインから実行

```sh
fastapi dev main.py
```


ブラウザから以下にアクセス
[http://localhost:8000/items/100](http://localhost:8000/items/100)

`@app.get("/items/{item_id}")`の通り、{item_id}に指定した値が出力されたら成功(今回の場合は`100`)

![スクリーンショット 2024-09-01 0.20.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/dcad6060-089f-7acf-3f53-a66eb31e508d.png)

ドキュメントも参照可能（[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)）
`Try it out`からフォームのようなものにBodyを入力してRequestを送ることができる

![スクリーンショット 2024-09-01 0.26.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/bed6ec07-e309-8d43-20a6-d7f18f15e17b.png)


# 参考

Documentation: https://fastapi.tiangolo.com
Source Code: https://github.com/fastapi/fastapi

https://apidog.com/jp/blog/get-post-difference/
rbenvで指定したバージョンに切り替わらない時の対処法

毎回出会すたびに対処法を忘れるため、残したいと思った。

### 環境
機器：Apple M1 MacBook Pro
バージョン：macOS 14.0

## 本題

rubyを使った環境構築のためバージョンを確認すると、Macデフォルトのバージョンになっている
``` zsh
$ ruby -v
```
> ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin23]

実際は3.3.0を選択している。
``` zsh
$ rbenv versions
  system
  3.2.2
* 3.3.0 (set by /Users/procrustes/.ruby-version)
```

## 対処法
`rbenv init`コマンドで設定ファイルのパスを探す
``` zsh
$ rbenv init
# Load rbenv automatically by appending
# the following to ~/.zshrc:

eval "$(rbenv init - zsh)"
```
今回の場合は`~/.zshrc`になっている。
そのパスに合わせて以下コマンドを実行する。
``` zsh
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc
$ echo 'eval "$(rbenv init -)"' >> ~/.zshrc
```
最後に以下のコマンドを実行
``` zsh
$ source ~/.zshrc
```

すると、rbenvのバージョンが適用される
``` zsh
$ ruby -v
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
```
GitHubのプロフィールを整えてみた。

いよいよ自分のGitHubのページを綺麗にする時が来たので、ちょっと見栄えを整えてみた👀
### 今日できたのはこちら
![スクリーンショット 2024-09-01 16.18.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827754/b11d6d1b-72b1-e1bc-6bbd-15d4ca423301.png)

### プロフィールにREADMEを表示する方法
```
1. 新しいリポジトリを作成する
2. リポジトリ名を自分のユーザーネームと一致させる（私の場合はhitomiuchihi）
```
### ステータスのグラフみたいなのを表示する方法
```
<p align="left"> 
  <img alt="Top Langs" height="130px" src="https://github-readme-stats.vercel.app/api/top-langs/?username=ここにユーザー名を入れる&layout=compact&show_icons=true" />
  <img alt="github stats" height="130px" src="https://github-readme-stats.vercel.app/api?username=ここにユーザー名を入れる&show_icons=ture" />
</p>
```
↑これは色をダークモードとかにもできる🌙
全然個人でプロジェクト作ってないので、なーんも表示されない（恥）
早く「No languages data.」脱せるように、コツコツ個人開発頑張ろうと思います😂
3D描画システム

WBS（Work Breakdown Structure）を描くためには、プロジェクトの各タスクを階層的に整理する必要があります。以下に、あなたのプロジェクトに基づいたWBSのサンプルをテキスト形式で示します。後で図としても可視化できます。

---

### **WBS - 3D描画システムプロジェクト**

1. **プロジェクト計画**
   - 1.1 要件定義の確認
   - 1.2 仕様書の作成
   - 1.3 WBSの作成

2. **クライアント側の開発**
   - 2.1 エクセルファイルの準備
     - 2.1.1 テーブル変数の指定
     - 2.1.2 JSON形式への変換
   - 2.2 JSheetの実装
   - 2.3 JavaScriptの開発
     - 2.3.1 クラス変数の指定
     - 2.3.2 クライアント側処理のテスト
   - 2.4 Gitでのバージョン管理
     - 2.4.1 Gitリポジトリの作成
     - 2.4.2 コードとファイルの管理

3. **サーバー側の開発**
   - 3.1 MySQLデータベースの設計
     - 3.1.1 テーブル構造の定義
     - 3.1.2 データのインポート
   - 3.2 サーバーサイド処理の実装
     - 3.2.1 データ送受信処理の作成
     - 3.2.2 サーバー側処理のテスト

4. **Unityでの3D描画**
   - 4.1 Unityプロジェクトの設定
     - 4.1.1 3Dモデルの準備
     - 4.1.2 シーンの設定
   - 4.2 C#スクリプトの開発
     - 4.2.1 データの読み込み処理
     - 4.2.2 描画処理の実装
   - 4.3 統合テスト
     - 4.3.1 クライアント側とサーバー側の連携テスト
     - 4.3.2 3D描画の動作確認

5. **テストとレビュー**
   - 5.1 システム全体のテスト
     - 5.1.1 バグ修正
     - 5.1.2 パフォーマンス最適化
   - 5.2 最終レビューと承認

6. **プロジェクトの完了**
   - 6.1 ドキュメントの作成
   - 6.2 プロジェクト報告書の作成

---

これが基本的なWBSのテキスト形式です。この内容を図としてビジュアル化することもできます。ビジュアル化したWBSが必要であれば、グラフィックを生成しますので、お知らせください。
serverless framework ローカル開発環境だけでテストする（モック不使用）

## 概要

serverless frameworkにてローカル開発環境に閉じてテストが行えるようにするまでの方法をまとめる。
今回のテストではモックを使わない。したがってaws-sdkを使ってAWSの情報を取る分は実際にリクエストが飛んでしまうので注意する。（リクエスト送信先のAWSはローカルのターミナルのaws cilのconfigに記載されているAWSにリクエストを送る。）

## 前提

下記の内容が完了していること

https://qiita.com/miriwo/items/bf274fa6af25a396f05d

## 方法

- aws-cost-notifyディレクトリで下記のコマンドを実行

    ```terminal
    serverless invoke local --function notify --data '{"source":"aws.cost","detail-type":"AWS Cost and Usage Report","detail":{"key1":"value1"}}'
    ```

- 下記のようにレスポンスが返れば一旦完了

    ```
    コスト通知イベントを受信しました: {"source":"aws.cost","detail-type":"AWS Cost and Usage Report","detail":{"key1":"value1"}}
    Cost Explorer Data: {"ResultsByTime":[{"TimePeriod":{"Start":"2024-01-01","End":"2024-01-31"},"Total":{"UnblendedCost":{"Amount":"2.3575540246","Unit":"USD"}},"Groups":[],"Estimated":false}],"DimensionValueAttributes":[]}
    
    {
        "statusCode": 200,
        "body": "{\"message\":\"コスト通知が正常に処理されました\"}"
    }
    ```
JSON構造からキーの一覧を生成する

## 仕様

### ルート

ルートハッシュは

```
$
```

### キー

```
{
  "key1": "value"
}
```

は

```
$.key1
```

### サブキー

```
{
  "key1": "value",
  "key2": {
    "key3": "value"
  }
}
```

は

```
$.key1
$.key2.key3
```


### 配列

```
{
  "key1": "value",
  "key2": {
    "key3": "value"
  },
  "key4": [
      "value",
      "value"
  ],
  "key5": [
    {
      "key6": "value"
    },
    {
      "key6": "value"
    }
  ]
}
```

は

```
$.key1
$.key2.key3
$.key4[]
$.key5[].key6
```

## スクリプト

```
import json
import sys

def list_keys(json_obj, prefix='$'):
    keys = []
    
    if isinstance(json_obj, dict):
        for key, value in json_obj.items():
            new_prefix = f"{prefix}.{key}"
            keys.extend(list_keys(value, new_prefix))
    elif isinstance(json_obj, list):
        new_prefix = f"{prefix}[]"
        if json_obj:
            for item in json_obj:
                keys.extend(list_keys(item, new_prefix))
        else:
            keys.append(new_prefix)
    else:
        keys.append(prefix)
    
    return keys

# 標準入力からJSONデータを読み込む
input_data = sys.stdin.read()

try:
    json_obj = json.loads(input_data)
    keys_list = list_keys(json_obj)

    for key in keys_list:
        print(key)
except json.JSONDecodeError:
    print("入力が有効なJSONではありません。")
```
Swift Firestore Missing or insufficient permissions.

## Swift Firestoreからデータ取得をする際にエラーになった

#### ◯ エラー内容
```
Missing or insufficient permissions.
```

英語読めないけどエラーに `permissions` って単語が入ってるのでセキュリティルールの設定が原因だろうとは思ったのですが、ルール設定についてがよく分からないのでとりあえず手探りしてみた。

#### ◯ Firestoreのデータ構造

```
コレクション
 - teams

ドキュメント
 - xxx-xxx-xxx-xxx (teamId)

フィールド
 - name
 - ownerId
 - sharedUserIds
```

#### ◯ Firestoreからの取得コード

```swift
Firestore.firestore()
    .collection("teams")
    .getDocuments { snapshot, error in
    }
```

#### ◯ 試したセキュリティルール

`試したこと1`
条件なし

```
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
  	match /teams {
    	allow read, write: if true;
    }
  }
}
```
これはエラーになりました。

##
`試したこと2`
条件なし

```
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
	match /teams/{teamId} {
    	allow read, write: if true;
	}
  }
}
```
これは成功しました。

なので試したこと1ではコレクションに対してセキュリティルールの設定をしているが、ドキュメントの取得をしようとしているので `/teams` に対してセキュリティルールを設定しても意味がないということなのかなと思いました。
とりあえず `/teams/{teamId}` へのセキュリティルールの設定で管理できることが分かったので実際にセキュリティルールを設定していきます。


##
`試したこと3`
ログインしていれば取得できるルール

```
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
	match /teams/{teamId} {
    	allow read, write: if request.auth.uid != null;
	}
  }
}
```
これも成功した。

##
`試したこと4`
データを取得しようとしたユーザーの `uid` が teamデータの `ownerId` と同じ場合

```
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
	match /teams/{teamId} {
        allow read, write: if request.auth.uid == resource.data.ownerId;
	}
  }
}
```
これは失敗した。
は？って思ってログインしているユーザーの `uid` と Firestoreに保存している `ownerId` を確認したが一致している。
ということでFirestoreのドキュメントを調べてたらこちらに記載がありました。
https://firebase.google.com/docs/firestore/security/rules-conditions?hl=ja#rules_are_not_filters

◯ 上記のリンクの記事参照

```アクセスが拒否される例.
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});
```

####


```アクセスが許可される例.
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });
```

参考コードにSwift言語での記載がなかったためweb系言語を載せていますが、
```
where("visibility", "==", "public")
```
のようにセキュリティルールに沿った条件のフィルターをかけて取得する必要がらしい。

セキュリティルールを設定すればアプリでフィルターをかけずにセキュリティルールの条件に合ったものだけが取得できるようになると思ってましたが違ったみたいです。


#### ◯ 結論

```セキュリティルール.
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
	match /teams/{teamId} {
        allow read, write: if request.auth.uid == resource.data.ownerId;
	}
  }
}
```

上記のセキュリティルールで設定した場合は、

```swift
Firestore.firestore()
    .collection("teams")
    .whereField("ownerId", isEqualTo: userId)
    .getDocuments { snapshot, error in
    }
```
のように `.whereField("ownerId", isEqualTo: userId)` を設定して、
フィールドの `ownerId` がログインユーザーの `userId` を持つドキュメントを取得するようにすると成功する。

#### ◯ まとめ

初めて記事の投稿をしてFirestoreの理解度も低い状態のため、間違えた認識や分かりずらい内容になっているかもしれないですが自分用のメモを兼ねて書いてみました。
serverless frameworkを使って毎日AWSのコストをSlackに飛ばすlambda関数を作ってみる（コードの記載）

## 概要

serverless frameworkを使ってlambda関数を定義し、AWSのコストをSlackに毎日送る仕組みを作る。
今回はメインとなるlambdaにデプロイされるコードを記載する。

## 前提

下記の内容が完了していること。

https://qiita.com/miriwo/items/ab557d0a252f361a0539

## 方法

- handler.jsを下記のように修正（「取得開始日」と「取得終了日」は2024-09-01現在は下記の値で問題無い。しかしCost Exporlerはたしか14ヶ月前までの情報しか取れなかったはずなので皆さんが体験するタイミングによってはエラーになる可能性がある。エラーが出たら当該箇所の日付だけ修正いただければ問題ないはずだ。）

    ```aws-cost-notify/handler.js
    const AWS = require('aws-sdk');
    const costExplorer = new AWS.CostExplorer({ region: 'us-east-1' });
    
    exports.notify = async (event, context) => {
      try {
        console.log('コスト通知イベントを受信しました:', JSON.stringify(event));
    
        const params = {
          TimePeriod: {
            Start: '2024-01-01', // 取得開始日
            End: '2024-01-31'    // 取得終了日
          },
          Granularity: 'MONTHLY',
          Metrics: ['UnblendedCost']
        };
    
        const data = await costExplorer.getCostAndUsage(params).promise();
        console.log('Cost Explorer Data:', JSON.stringify(data));
    
        return {
          statusCode: 200,
          body: JSON.stringify({ message: 'コスト通知が正常に処理されました' })
        };
      } catch (error) {
        console.error('エラーが発生しました:', error);
        return {
          statusCode: 500,
          body: JSON.stringify({ message: 'コスト通知の処理中にエラーが発生しました' })
        };
      }
    };
    ```

- aws-cost-notifyディレクトリで下記を実行してaws-sdkをインストール

    ```terminal
    npm install aws-sdk
    ```

- aws-cost-notifyディレクトリで下記を実行して修正内容をデプロイ

    ```terminal
    serverless deploy
    ```

- AWSマネジメントコンソールにログインし、Lambdaの今回デプロイした関数の詳細へ移動し、テストを実行
- 下記の様に200が返り、ログ出力でキーamoutのvalueで指定した期間のコストが取れていれば一旦完了

    ```
    {
      "statusCode": 200,
      "body": "{\"message\":\"コスト通知が正常に処理されました\"}"
    }
    ```
neomuttを使用してCLIでメール確認

# したいこと

メールをCLI(ターミナル)で確認・整理する

メール送信については、この記事の対象外です

# 動作環境

- OS：Mac v14.4.1
- ターミナル：[Wezterm](https://wezfurlong.org/wezterm/index.html) (zsh)
- メールクライアント：[neomutt](https://neomutt.org/)

# 導入方法

1. 必要なソフトをインストール
2. メールアカウントのパスワードをkeychainに登録
3. neomuttの設定ファイルを作成

## 必要なソフトのインストール

homebrewでneomuttを入れてしまいましょう

```
brew install neomutt
```

## メールアカウントのパスワードをkeychainに登録

パスワードを設定ファイルに平文で書くのは避けたいので、今回はkeychainに登録しておきます

```
# keychainへの登録コマンド
security add-generic-password -a アカウント名 -s パスワード名 -w パスワード
```

  
:::note warn
Gmailアカウントの注意点

Gmailアカウントの場合、パスワードはGoogleアカウントのパスワードではなく、アプリパスワードを使用します
アプリパスワードの作成手順は以下を参照してください
:::

keychainに登録したパスワードを確認する場合は、以下のコマンドを使用します

今回は設定ファイルに以下コマンドを使用することで、パスワード参照できるようにします

```
# keychainの内容表示コマンド
security find-generic-password -a アカウント名 -s パスワード名 -w
```

## neomuttの設定ファイルを作成

### neomutt全体の設定ファイル

`~/.config/neomutt/neomuttrc` ファイルを新規作成し、以下を記載します

```
# アカウント1の設定
source "~/.config/neomutt/account1"
folder-hook $folder 'source ~/.neomutt/account1'
```

今回はアカウントファイルへの参照しか記載していないですが、設定項目はたくさんあるので、リファレンスを参考に設定してみてください

- リファレンス：[https://neomutt.org/guide/reference.html#3- configuration-variables](https://neomutt.org/guide/reference.html#3-%C2%A0configuration-variables)


アカウントを複数作成したい場合は、`neomuttrc` を以下のように記載し、アカウント毎に「メールアカウント毎の設定ファイル」を作成すればOKです

```
# アカウント1の設定
source "~/.config/neomutt/account1"
folder-hook $folder 'source ~/.neomutt/account1'

# アカウント2の設定
source "~/.config/neomutt/account2"
folder-hook $folder 'source ~/.neomutt/account2'
```

### メールアカウント毎の設定ファイル

`~/.config/neomutt/account1` ファイルを新規作成し、以下を記載します

```
## 受信設定
set imap_user = "メールアドレス" # 今回はimapを使用
set imap_pass = "`security find-generic-password -a アカウント名 -s パスワード名 -w`"
set folder    = "imaps://メールアドレス@サーバ名:ポートNo"
set spoolfile = "+INBOX"
mailboxes     = "+INBOX"
set postponed = "+Drafts"
unset record

# 接続方法
set ssl_starttls      = yes # 対象のメールサーバによっては設定不要
set ssl_force_tls     = yes # 対象のメールサーバによっては設定不要
```

ちなみにですが、Gmailの場合は以下のように指定します

```
## 受信設定
set imap_user = "xxx@gmail.com"
set imap_pass = "`security find-generic-password -a アカウント名 -s パスワード名 -w`"
set folder    = "imaps://xxx@gmail.com@imap.gmail.com:993"
set spoolfile = "+INBOX"
mailboxes     = "+INBOX"
set postponed = "+Drafts"
unset record

# 接続方法
set ssl_starttls      = yes
set ssl_force_tls     = yes
```

# neomutt起動

以下コマンドで起動できます

```
neomutt
```

最初はキャッシュがないため、起動に時間がかかるかもしれません

起動するとメールの一覧画面が表示されます

動作方法に迷った場合は`?` を使用して、キーを確認すると良いと思います

# 最後に

CLIのみでメール確認できるようになり、メール整理がだいぶ早くなったように思います

今後はメール送信についてもCLIのみで完結できるように色々調べてみたいと思います

最後まで読んでいただきありがとうございました
UbuntuでDLSiteの大人なゲームをプレイしてみる

youtube を眺めていましたら、[あおぎり高校の新人さん](https://www.youtube.com/@urutoragaru0831)がデビューと同時に[フリーの18禁ゲームを発表・配布した](https://x.com/urutoragaru/status/1829898275467497863)、ということを知りまして、早速DLしてみました。
とは言えども、私の手元の環境は Lubuntu (正確には Ubuntu インストール後、 lubuntu-desktop をインストールしてデスクトップ環境を変更した)です。
Wine で実行を試みましたが、立ち上がってくれません。
ググって、なんとか正常動作にこぎつけましたので、以下に記します。

本作はRPGツクールMVで制作されています。
wineでは正常動作しませんが、 NW.js を用いて正常動作を確認しました。
注: Linuxでの動作は公式のフォロー外ですので、自己責任でお願いします。
参考サイト:
https://kakurasan.blogspot.com/2017/02/rpgmv-games-on-linux.html
https://www.reddit.com/r/RPGMaker/comments/15q78qa/nwjs_required_value_name_is_missing_or_invalid/?rdt=62349&onetap_auto=true&one_tap=true

1\. ゲームの zip ファイルを特定のディレクトリに展開。例:
```
$ mkdir ~/private
$ cd ~/private
$ unzip RJ01249360.zip
$ ls -ld Tora*
drwxrwxr-x 5 hoge hoge 4096  9月  1 14:09 ToraGame
```

2\. https://nwjs.io から NW.js をDLし、展開。例:
```
$ wget https://dl.nwjs.io/v0.91.0/nwjs-v0.91.0-linux-x64.tar.gz
$ tar xvzf nwjs-v0.91.0-linux-x64.tar.gz
$ ls -ld nwjs*
drwx------ 5 hoge hoge 4096  8月 18 03:01 nwjs-v0.91.0-linux-x64
```

3\. nano 等のエディタで、ゲームのディレクトリ内の package.json の "name" フィールドを以下のように修正する。
```
"name": "",
↓
"name": "{}",
```

4\. ゲームのディレクトリから nw を実行。例:
```
$ pwd
/home/hoge/private/ToraGame
$ ls -ld ../nwjs*
drwx------ 5 hoge hoge 4096  8月 18 03:01 ../nwjs-v0.91.0-linux-x64
$ ../nwjs-v0.91.0-linux-x64/nw .
```
参考までに、動作検証環境:
Dell Vostro 3578
CPU: Core i3-8130U
Memory: 4GB
SSD: 128GB
OS: Ubuntu 24.04 LTS
<img src="https://pbs.twimg.com/media/GWYUzo1XAAEI7Oc.png">
【個人開発, 生成AI】エンジニア面接練習用アプリを作りました（概要紹介）

## はじめに

こんにちは！[MaTTa](https://x.com/RckLVnPtRv61824)です。

この度、[**「面接シミュレータR**」](https://interview-frontend-05a5d7363eca.herokuapp.com/)というミニアプリを開発しました！

AIを活用したリアルな面接シミュレーションを通じて、未経験エンジニアや転職希望のジュニアエンジニアの皆様の**面接スキル向上**をサポートします。

## サービスURL

https://interview-frontend-05a5d7363eca.herokuapp.com/

## Githubリポジトリ

https://github.com/MaTTalv001/Interview_simulator2

## テーマ選定理由

以前、人事部門での勤務時に、数多くの面接やキャリア相談を担当させていただきました。この経験を通じて、求職者が面接で直面する特有の困難さや、準備不足による不安を目の当たりにしました。異動して現在の部署にいる今でも、その時に感じた課題を解決したいという強い思いがこのアプリの開発につながりました。具体的には以下の課題を解消したいと考えています。

1. エンジニア面接特有の難しさ
   - 技術的な質問への対応
   - 自身のスキルや経験を適切に表現すること

2. 面接練習の機会の少なさ
   - 実際の面接でしか経験できない緊張感
   - フィードバックを得る機会の不足
   - 夜型なのでCAさんと時間が合わない...

## スクリーンショット

面接練習と、フィードバック振り返りの2モード
![090101.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182380/7249b893-6eb3-5cf2-7de1-37ca9fb1d52f.jpeg)

AI面接担当者とは音声、マイクで擬似的な会話を行います
![090102.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182380/c77726a8-148b-a201-cbfd-c9f36c3a3a77.jpeg)
*面接担当者の動画は[Vidnoz](https://jp.vidnoz.com/) で生成された架空の人物です。同サービスのアバターは無料プランでも商用利用可能です。 


## アプリの特徴

### 1. リアルな面接シミュレーション

- AIによる動的な質問生成
- 音声ベースのインタラクション

3種類のAI（Chat、Text-to-Speech、Speech-to-Text）を組み合わせることで、リアルな面接環境を再現しています。この仕組みによりユーザーは音声で回答しAIの面接担当者も音声で質問するという、より実際の面接に近い体験を提供しています。なお、面接担当者の動画は音声再生中に口パクでループ再生させるという処理で代用しています。


### 2. パーソナライズされた体験

- GitHubプロフィール分析によるカスタム質問

GitHubリポジトリのREADMEデータを取得しAI面接担当者に入力することでポートフォリオ面談ができるようにしました。コードの記述自体を質問するようなこともしたいのですが、リポジトリによっては情報量が多過ぎてしまうため、現時点ではREADMEで代用しています。

### 3. 包括的なフィードバック

- 回答の質、デリバリー、技術的正確性の評価
- 具体的な改善点の提示

面接モードを終了するとAIを用いてフィードバックを聞くことができます。自身の回答も文字起こしされた上で記録されるので冷静に振り返りをすることが可能です。


## 実装しなかったこと

「実際に面接で受けた質問を共有する機能」など、就活用SNS的な構想も当初ありましたが、個人情報や個別企業に関する投稿に伴うコンプライアンスリスクの管理が難しいと判断し実装を取りやめています。あくまで個人用のアプリに閉じました。


## 使用技術

| 分類 | 技術 |
| --- | --- |
| バックエンド | Ruby on Rails |
| フロントエンド | React.js |
| データベース | MySQL |
| CSS | Tailwind CSS, DaisyUI |
| AI/ML | OpenAI API (GPT-4o-mini, Text to Speech, Speech to Text) |
| インフラ | Docker, Heroku |
| CI/CD | GitHub Actions |
| モニタリング | Google Analytics |


## 今後の展望

- 複数の面接担当者アバター追加
- 難易度設定の実装（新卒、ジュニア、シニアなど）
- フィードバック内容の充実
- 音声認識と自然言語処理の精度向上
- ユーザーの音声そのものの解析（感情、話し方など）
- VRアプリ化

## さいごに
今回はアプリの紹介まで。機能ごとの開発記録も後日書こうと思います。フィードバックやご意見がありましたら、ぜひコメントにてお寄せください。


最後までお読みいただき、ありがとうございました！

---
【この記事を書いた人のX】

https://x.com/RckLVnPtRv61824
Google Cloud Digital Leader 合格体験記

## はじめに

本日Google Cloud Digital Leaderを受験して結果画面に合格と表示されていたため体験記を残します。
試験当日の流れは別記事で作成しております。

## 前提知識
 - 新卒エンジニア2年目
 - 案件でGoogleCloudを1年使用
 - 趣味でもCloudRun,CloudFunctionsなどで遊んでる
 - 基本情報取得

## 勉強時間など
約30時間くらい？

## 勉強遍歴

2024年8月23日：勉強開始
2024年9月1日：受験 -> `合格`

## 自分の勉強ロードマップ
### 1. Youtubeで概要をつかむ
ざっと試験の項目を動画で学習しました。
https://youtu.be/UvQpx00oZy4?si=kLnxBleAxHSRhTPB

### 2. 公式の試験ガイドを見る。
あんまり見てないですが、軽く参考にしました
https://cloud.google.com/certification/guides/cloud-digital-leader

### 3. 試験問題を解く

#### 3-1 模擬試験
結構簡単めなので2回くらいしか解きませんでした。
https://docs.google.com/forms/d/e/1FAIpQLSdyQtCFqpNSlv8xJwc8goExJOzSAKxiWW2BoVhO1QWRUEUuKA/viewform?hl=ja


#### 3-2 試験問題集で演習を実施
日本語がおかしい箇所や、解説が英語などの理由からあまり使いませんでした。

https://www.jpnshiken.com/exam/Cloud-Digital-Leader-JPN-google-cloud-digital-leader-cloud-digital-leader%e6%97%a5%e6%9c%ac%e8%aa%9e%e7%89%88-13864.html#


#### 3-3 Udemyの模擬試験を実施
Udemyのセールと被っていたため少し安く購入できました。
3回分+ボーナス1回分とちょうどいい分量だったように思います。
解説がわかりやすくかなり網羅的でした。これを2周くらいしました。

:::note alert
警告
下記のコースは削除されております。ご注意ください。
:::

https://www.udemy.com/course/2023google-cloud-cloud-digital-leader-i/?couponCode=KEEPLEARNING

### 4. 理解できるまで繰り返し演習&復習
混同しそうなものを書き出して、公式のリファレンスを軽く目を通していきました。


## 本番でテンパってわからなくなったやつとか、悩んだやつ
 - Pub/Subって結局なんだっけ?
 - データウェアハウスとデータレイクの違い
 - Vertex AI 
 - Anthos　
 - MLの違い（AutoML,Cloud Bigtable ML,BigQuery ML)
 - TensorFlowって何
 - IaaS、PaaS、SaaSとは？
 - DataFlow　Data
 - GKEのstandardとpremiumの違い
 - 戦略的なクラウド導入アプローチから変革的なアプローチへの移行
 - CloudStorageのStandard,Nearline,Coldline,Archiveの保存期間の違い
 - Cloud DataflowとCloud Data Fusionの違い
 - AutoMLVisionとVisionAPIの違い
 - BigtableとSpannerの違い
 - Cloud Logging Cloud Traceの違い
 - DirectPeeringとCloudVPNの違い
 - CapEx(資本的支出)とOpEx(経費的支出)の違い　
     - 本番ではCapEx,OpExと書かれて（）内の日本語表記はありませんでした
 - パブリッククラウド、プライベートクラウド、マルチクラウドの違い
 - 認証と認可の違い
 - サービスレベル目標（SLO）とサービスレベル契約・合意（SLA）の違い
     - 本番では、SLAの日本語がSLOとほぼ見分けつかないものになっていた気がします...
 - APIをどんな場合につかうのが適当か
 - 転送されるデータは暗号化、保存データも暗号化されてる（知らなかった）
 - ベンダーロックインって何？その懸念を解消するには？
 - NoSqlって何がいいんだっけ？
 - Contact Centar AI
 - GCPの組織、フォルダ、プロジェクトの考え方（リソース階層）
 - TPUって何？GPUしかわからない
 - 可用性
 - ETL

## まとめ
かなり新たに学ぶことが多く、使ってもいないサービスのことを想像しながら勉強をするのはかなり大変でした。こんなサービスがあるのかぁとGoogleCloudの便利さを実感しました

## 本番の様子はこちらの記事から
https://qiita.com/asarashi/items/85550e02a044f8b38d3a
AWS認定ソリューションアーキテクト-アソシエイト- (忘備録)

記録メモ
学んだサービスを忘れないために、ざっくりメモとして残します。
随時更新していく。
順番は学んだ順。

# AWS DataSync

## 概要
①データの移動と同期を自動化・高速化するデータ転送サービスです。
②大規模なデータセットの移行や定期的なデータ同期に適しています。

## 対象領域
- オンプレミス　→　AWSへのデータ転送
- AWS　↔︎ AWS
- リージョン間でのデータ転送が可能
- グローバルアクセラレータと統合することで、長距離のデータ転送を最適化

## 関連するサービス
- Amazon S3
- Amazon EFS
- Amazon FSx
- AWS Storage Gateway
- AWS Snowcone
- AWS Global Accelerator
【kintone】ルックアップフィールドの自動更新(100件以上)

# はじめに

kintoneのアプリA(APP_A)の値(field_A)をアプリB(APP_B)のルックアップフィールド(field_lookupA)で参照している場合、

1. APP_Aの値を更新する
2. 1の更新結果をAPP_Bに反映するために、APP_Bのレコードを**手動**で開き、ルックアップフィールドの[取得]をクリックしなくてはいけない

さらに...
* APP_Bで更新対象になるレコードは100件以上ある（ので手動はめんどくさすぎる）
* 業務上、APP_Bで更新対象になるレコードは、別のフィールド(field_UpdateStatus)でフィルタリングが必要（一覧機能でフィルタリングはできるけど、どうせなら自動化したい）


## やりたいこと
下記の自動化
1. APP_Aの値を更新する
2. 更新されたAPP_Aの値をルックアップしている & field_UpdateStatusAPPが指定の値であるAPP_Bのレコードを検索
3. 2で見つけたレコードのルックアップを更新



# やったこと

APP_Aに下記のjsカスタマイズを追加。

```javascript:update_lookup_field.js
(() => {
  'use strict';
  const APP_B_ID = 000; //*ルックアップするアプリのIDを記載

  // 保存成功後イベント
  kintone.events.on(['app.record.edit.submit.success', 'app.record.index.edit.submit.success'], async (event) => {
    let offset = 0;
    const limit = 500;
    const updateStatus = ['00_NotStarted', '01_InProgress'];
        //*フィルタリングしたいフィールドコードを定数で設定し、指定の値を代入する
    const query = '(filed_lookupA = "' + event.record.txt_currency.value + '") and (drop_ValuationSaleStatus in ("' + updateStatus.join('","') + '"))';
    let allRecords = [];

    try {
      // ページネーションを使用しレコードを取得
      while (true) {
        const resp = await kintone.api(kintone.api.url('/k/v1/records.json', true), 'GET', {
          app: APP_B_ID,
          query: query + ` limit ${limit} offset ${offset}`,  // クエリに limit と offset を追加
          fields: ['$id']  // 必要なフィールドのみを取得してパフォーマンスを向上
        });
        
        allRecords = allRecords.concat(resp.records);
        console.log(`取得したレコード数: ${resp.records.length}, 合計: ${allRecords.length}`);
        
      if (resp.records.length < limit) {
      // 取得したレコード数が limit より少ない場合、すべてのレコードを取得したと判断
      break;
      }
        offset += limit;
      }
      
      console.log(`最終的な取得レコード数: ${allRecords.length}`);

      // レコードの更新データの準備
      const dbAppRecords = allRecords.map((record) => ({
        id: record.$id.value,
        record: {
         field_lookupA: {
            value: event.record.field_A.value
          }
        }
      }));

      // APP_Bのレコードを一括更新（100件ずつ）
      const updatePromises = [];
      for (let i = 0; i < dbAppRecords.length; i += 100) {
        const batch = dbAppRecords.slice(i, i + 100);
        updatePromises.push(
          kintone.api(kintone.api.url('/k/v1/records.json', true), 'PUT', {
            app: APP_B_ID,
            records: batch
          })
        );
      }
      
      // すべての更新処理が完了するまで待機
      await Promise.all(updatePromises);

      const message = `ルックアップの更新が完了しました。更新されたレコード数: ${dbAppRecords.length}件`;
      console.log(message);

    } catch (error) {
      const errorMessage = `ルックアップの更新でエラーが発生しました: ${error.message}`;
      console.error(errorMessage);
    }
  });
})();
```

# 参考サイト
https://cybozu.dev/ja/kintone/tips/development/customize/validation-and-assistance/update-record-lookup-using-rest-api/
https://cybozu.dev/ja/id/7b342fa8f1aa22a1bb9cca4a/#use-offset
v0とshadcn CLI：AI駆動のNext.jsプロジェクトセットアップガイド

## はじめに

本ガイドでは、v0で生成されたコンポーネントをshadcn CLIを使用してNext.jsプロジェクトに統合する方法を、実際のコマンドライン操作に基づいて説明します。この方法を使用することで、AIの力を活用した効率的な開発ワークフローを構築できます。

## デモ動画

<blockquote class="twitter-tweet" data-media-max-width="800"><p lang="ja" dir="ltr">「v0 + shadcn/ui CLI」を使ってエヴァンゲリオン NERV の戦闘情報センター (CIC)のダッシュボードをローカルで起動してみた！！<br>右往左往も含めて4分以内でできました！<br><br>＊動画は早回し＋カットしてます <a href="https://t.co/nzU4ADkmhR">https://t.co/nzU4ADkmhR</a> <a href="https://t.co/k3hLy4OHVz">pic.twitter.com/k3hLy4OHVz</a></p>&mdash; Maki@Sunwood AI Labs. (@hAru_mAki_ch) <a href="https://twitter.com/hAru_mAki_ch/status/1830120423356543015?ref_src=twsrc%5Etfw">September 1, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## v0とは

v0は、Vercelが開発した革新的なAI駆動のUIコンポーネント生成プラットフォームです。以下の特徴を持っています：

1. **AI支援デザイン**: 自然言語での説明をもとに、AIがUIコンポーネントを生成します。
2. **Reactベース**: 生成されるコンポーネントはReactベースで、最新のベストプラクティスに従っています。
3. **カスタマイズ可能**: 生成されたコードは人間が読みやすく、必要に応じて簡単に修正できます。
4. **shadcn UIとの統合**: v0はshadcn UIのコンポーネントを活用しており、一貫性のあるデザインシステムを提供します。
5. **高速プロトタイピング**: アイデアを素早くプロトタイプに変換し、開発プロセスを加速させます。

v0を使用することで、開発者はUIデザインと実装の時間を大幅に削減し、より創造的な作業に集中できるようになります。


## 前提条件

- Node.jsがインストールされていること
- コマンドラインの基本的な操作に慣れていること
- v0プラットフォームでコンポーネントを生成済みであること

## v0コンポーネントのインストール

1. 空のディレクトリで以下のコマンドを実行します：

```bash
npx shadcn@latest add "https://v0.dev/chat/b/C11bUjD?token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..zQZ10idOZPZ0HHlL.pZMP4nDJrqTjLTtrai8W4lq-AIiZjic8KYXSuVEuYXIPwbKdHJw.p51_HRRv2VYSlhc5jUTfuw"
```

2. パッケージのインストールを求められたら、`y`を入力して続行します。

## Next.jsプロジェクトの初期化

CLIが自動的に新しいNext.jsプロジェクトを作成するプロセスをガイドします：

1. プロジェクト名を入力します（例：`nerv_cic`）
2. スタイルを選択します（例：New York）
3. ベースカラーを選択します（例：Neutral）
4. CSSファイルでのテーマ設定を使用するかどうかを選択します

これらの選択により、v0で生成されたコンポーネントと調和のとれたプロジェクト構造が自動的に設定されます。

## pnpmのインストールと使用

1. グローバルにpnpmをインストールします：

```bash
npm install -g pnpm
```

2. インストールが完了したら、以下のコマンドでプロジェクトの依存関係をインストールします：

```bash
pnpm install
```

pnpmを使用することで、依存関係の管理がより効率的になり、インストール時間を短縮できます。

## プロジェクトの起動

1. 以下のコマンドでNext.jsの開発サーバーを起動します：

```bash
pnpm dev
```

2. ブラウザで`http://localhost:3000`を開いて、プロジェクトを確認します。

ここで、v0で生成されたコンポーネントがプロジェクトに正しく統合されていることを確認できます。

## トラブルシューティング

- `'pnpm' is not recognized as an internal or external command`エラーが発生した場合は、pnpmのインストールが正しく行われているか確認してください。
- Next.jsの匿名テレメトリーデータ収集に関する通知が表示されます。必要に応じて、オプトアウトの設定を行ってください。

## まとめ

このガイドでは、v0で生成されたAI駆動のコンポーネントをshadcn CLIを使用してNext.jsプロジェクトに統合する方法を、実際のコマンドライン操作に基づいて説明しました。この方法を使用することで、以下の利点が得られます：

1. AIの力を活用した迅速なUI開発
2. shadcn UIとの seamless な統合
3. 最新のNext.jsプロジェクト構造の自動設定
4. 効率的な依存関係管理（pnpm使用）

v0とshadcn CLIの組み合わせは、Reactアプリケーション開発のワークフローを大幅に改善し、開発者の生産性を向上させる可能性を秘めています。AIと人間の創造性を組み合わせることで、より迅速かつ効果的なWeb開発が可能になります。

今後のアップデートや機能拡張にも注目が集まっており、v0とshadcn CLIはReactエコシステムの発展に大きく貢献することが期待されています。この革新的なアプローチを活用することで、開発者はより創造的な側面に集中し、高品質なアプリケーションをより短期間で提供できるようになるでしょう。
Rational型の変数を分数形式のまま出力する方法

`@printf` マクロでは，分数 (`Rational` 型) をそのまま `%d` などのフォーマット指定子で書き出すことはできません。分数を出力する場合は，分子と分母を別々に取り出してフォーマットする必要があります。以下のようにすれば，`3//7` を適切に表示できます。

```julia
using Printf

x = 3//7
@printf("x = %d/%d\n", numerator(x), denominator(x))
```

これで，`x = 3/7` と表示されます。

もし，`3//7` をそのまま `Rational` 型として出力したい場合は，`@printf` マクロを使わずに `print` や `println` で出力することもできます。

```julia
x = 3//7
println("x = $(x)")
```

これにより，`x = 3//7` と表示されます。
Atcoder解いてみた AGC 010 A - Addition

# AGC 010 A - Addition 解いてみた
問題は[こちら](https://atcoder.jp/contests/agc010/tasks/agc010_a)

## 回答
```C++
#include <iostream>
using namespace std;

int main(){
  
  int N;
  int A[100000];
  
  cin >> N;
  for (int i = 0; i < N; i++) {
    cin >> A[i];
  }
  
  bool can = true;
  
  int sum = 0;
  for (int i = 0; i<N; i++){
    sum += A[i];
  }
  if (sum%2 != 0) can = false;
  
  if (can) cout << "YES" << endl;
  else cout << "NO" << endl; 
  
  return 0;
}
```
Phoenix Projectの作成からモーダル経由でのポストの作成と一覧への反映の処理の流れ part3

続いてCRUD機能を追加します

今回はphoenixに搭載されている標準的な機能であるscaffoldを利用してテンプレートを作成します
ここではmix phx.gen.liveコマンドを実行してCRUD機能を作っていきます

https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Live.html

```
mix phx.gen.live Accounts User users name:string age:integer 
```

このmix phx.gen.liveコマンドでは引数がそれぞれコンテキスト名、スキーマ名、テーブル名、テーブルのカラム名と型名という順で記述されています
今回はコンテキスト名がAccounts、
スキーマ名がUser、
テーブル名がUsers、
テーブルのカラム名と型名がそれぞれname:string age:integerとなっています

実行するとブラウザに以下の要素が追加を促されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/75c58b77-2b51-1eff-68a2-b2bcd99a823b.png)

指示通りにrouter.exにルーティングを追加します
この時前回とは違いgetでなくliveで始まっていることに注意してください

``` mix ecto.migrate ```
を行い、レポジトリをアップデートすることによりマイグレーションを行います
lib/priv/repo/migrations配下にマイグレーションファイルが生成されていることが確認できます

マイグレーションが完了したらmix phx.serverでサーバーを起動します
ブラウザ上でlocalhost:4000/usersにアクセスすると画像のようにUsers一覧にアクセスできます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/a415360b-5587-af69-8838-d2d379a60083.png)
現時点ではデータがないため何も表示されていませんがNew Userボタンをクリックするかlocalhost:4000/users/newにアクセスをしてユーザーを追加するとその情報が反映されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/875505f3-03a7-7a9c-69bf-53bbd403a5dc.png)

これでmix phx.gen.liveを使ってCRUD機能の実装ができました

## 終わりに
文中にいくつかわかりづらい単語があったかもしれません
そのため読みづらかったり単語の意味を理解しないまま読み進められた方もいるかもしれません
そういった方のために補足で単語の説明を行ってます
参考に読んでいただければお役に立てるかと思います

## 補足
scaffoldとは？
>テンプレートを自動で作成してくる、とても便利なツールで「足場」や「土台」という意味から来ています

>Rails scaffolding is a quick way to generate some of the major pieces of an application. If you want to create the models, views, and controllers for a new resource in a single operation, scaffolding is the tool for the job.

elixirドキュメントで調べてもスキャフォールドについて精確に説明されていないのでRailsのドキュメントなどを参考に解説します
テンプレートを簡単に作成してくれるコマンドのことです
この機能を使うと簡単にひな形を作れるメリットはありますが、この手の機能の課題点として細かな部分に物足りなさを感じます
万能の機能ではなくあくまで簡潔に作れるものだという意識は必要かもしれません

https://techplay.jp/column/612

https://guides.rubyonrails.org/v3.2/getting_started.html

https://hexdocs.pm/scaffolder/api-reference.html


CRUD機能についてわからないという方は以下のドキュメントを参考にしてください
> CRUD (Create, Read, Update, Delete) は、格納されたデータの操作を行う方法の頭文字をとった語

この機能が追加できれば一般的な掲示板のように内容一覧を表示し、そこへ追加したり削除したり内容の更新をかけるといった操作が可能になります

https://developer.mozilla.org/ja/docs/Glossary/CRUD
dbtをdockerで試す

# 概要
dbtをDockerで試してみたのでメモとして残す．

https://github.com/KiYuRo/dbt-on-docker


# ディレクトリ構成
```
C:.
├─dbt           # dbtのプロジェクトを格納
│  └─project    # 作成したdbtプロジェクト
└─docker        # docker環境構築関連のファイルとディレクトリを格納
    ├─database  # データベースコンテナ設定用
    │  ├─data   # データベースを永続化するためのディレクトリ
    │  └─init   # コンテナ起動時に初回実行するSQLファイルを格納
    └─dbt       # dbtサーバ用
```

# Docker環境構築
コンテナ起動
```
docker compose up -d
```

dbtコンテナ接続
```
docker exec -it dbt /bin/bash
```

postgresコンテナ内のDB接続
```
docker exec -it database /bin/bash
psql -U root
```

dbtバージョン確認
```
dbt --version
```

```
out:

Core:
  - installed: 1.8.6
  - latest:    1.8.6 - Up to date!

Plugins:
  - postgres: 1.8.2 - Up to date!
```

# dbtプロジェクト作成
プロジェクトを作成．DBの接続情報を入力していく．
```
$ dbt init

04:51:46  Running with dbt=1.8.6
Enter a name for your project (letters, digits, underscore): project

Enter a number: 1
host (hostname for the instance): database
port [5432]: 5432
user (dev username): root
pass (dev password): root
dbname (default database that dbt will build objects in): root
schema (default schema that dbt will build objects in): public
threads (1 or more) [1]: 1
05:18:37  Profile project written to /home/dbt-user/.dbt/profiles.yml using target's profile_template.yml and your supplied values. Run 'dbt debug' to validate the connection.
```

以下のようなディレクトリが作られる
```
$ cd project
$ ls
README.md  analyses  dbt_project.yml  macros  models  seeds  snapshots  tests
```

接続確認
```
$ dbt debug

...
04:53:07  All checks passed!
```

# モデル実行
サンプルのモデルを実行する
```
$ dbt run

...
04:54:16  Completed successfully
04:54:16
04:54:16  Done. PASS=2 WARN=0 ERROR=0 SKIP=0 TOTAL=2
```

テーブルが作られる
```
root=# \dt
              List of relations
 Schema |        Name        | Type  | Owner
--------+--------------------+-------+-------
 public | my_first_dbt_model | table | root
(1 row)
```

# モデルテスト
テスト実行．デフォルトでは1つ失敗する
```
$dbt test

05:22:37  Done. PASS=3 WARN=0 ERROR=1 SKIP=0 TOTAL=4
```
OpenAI API経由で画像解析する際の備忘録

OpenAI API経由で画像解析する際の備忘録です

# （前提条件）priceをご確認ください。

こちらの、`Vision pricing calculator`からpriceを事前に確認の上、APIを使用するのがよいでしょう。

https://openai.com/api/pricing/

# install

version

```
$ python --version
Python 3.12.3
```

venv環境を用意

```sh:
(recommend) use on venv
# cd (working directry)
python3 -m venv venv
source venv/bin/activate
# (deactivate)
install
```

`openai`パッケージをinstall

```sh:
pip install openai
```

コマンドラインから`OPENAI_API_KEY`を環境変数に設定
[API_KEYの作成はこちらから`CREATE_NEW_API_KEY`を実施する](https://platform.openai.com/api-keys)

```
export OPENAI_API_KEY="xxx"
```

テスト画像の準備

"75.jpg"というファイル名で保存しておく
https://www.gettyimages.co.jp/%E5%86%99%E7%9C%9F/%E6%95%B0%E5%AD%97%E3%81%AE75


# コード

```py:image-recognition.py
import openai
import base64
import os

# 画像から数値を取得する関数
# image_path: 画像のパス
# return: 数値
# 準備: OPENAI_API_KEYを環境変数に設定しておく
def image2num(image_path):
    # openai.api_key="OPENAI_API_KEY"
    api_key = os.environ.get("OPENAI_API_KEY")
    def encode_image(image_path):
      with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode('utf-8')
    base64_image = encode_image(image_path)

    response = openai.chat.completions.create(
      model="gpt-4o",
      messages=[
        {
            "role": "system",
            "content": "画像に数字が書かれています。画像を解析して、数字のみを回答してください。"
        },
        {
            "role": "user",
            "content": [
            {"type": "text", "text": "画像に数字が書かれています。画像を解析して、数字のみを回答してください。"},
            {
                "type": "image_url",
                "image_url": {
                    "url": f"data:image/jpeg;base64,{base64_image}"
                }
            }
            ]
        }
    ],
    max_tokens=300
    )
    return response

# 実行
response = image2num("75.jpg")
print("number : " + response.choices[0].message.content)
```

# 実行

```sh:
$ python image-recognition.py
number : 75
```

# 参考

https://platform.openai.com/api-keys

https://openai.com/index/openai-api/

https://www.gluegent.com/blog/2024/05/gpt-4o-api.html
Fedora39でcrondを使えるようにする

Fedora39でcrondを使おうと思ったら入っていなかったので使えるようにしました。

# パッケージを調べる
```
[root@fed ~]# dnf provides cronie
Waiting for process with pid 294 to finish.
Last metadata expiration check: 0:00:17 ago on Sun Sep  1 03:39:45 2024.
cronie-1.6.1-5.fc39.x86_64 : Cron daemon for executing programs at set times
Repo        : fedora
Matched from:
Provide    : cronie = 1.6.1-5.fc39
```

cronieというパッケージで提供されているようです。

# インストール

```
dnf install cronie
```

# サービスの登録と開始

## サービスの登録
```
systemctl enable crond
```
## サービスの開始
```
systemctl start crond
```

# タスクの登録
```
crontab -e
```

例として月初のAM03:00に再起動するように以下を入れます。
```
0 3 1 * * /sbin/shutdown -r now
```

以上です。
[Performance Indicator] 性能指標

# 一覧
|タイトル|詳細|実例|
|:--|:--|:--|
|スループット|システムが単に時間あたりに処理できる仕事量|トランザクション処理：トランザクション数<br>バッチ処理：ジョブ数|
|レスポンスタイム|入力終了から出力開始|トランザクション処理、会話処理|
|ターンアラウンドタイム|ジョブ投入から出力終了<br>ジョブ投入→入力終了→出力開始→出力終了|バッチ処理|

# 参考リンク
- [平成20年秋問31](https://www.fe-siken.com/kakomon/20_aki/q33.html)
先日作ったGo言語用モジュールを ChatGPT でコードレビューしてもらいました

また、ベタなネタなんですが。
モノは前回のコレですね↓。

[IPv4 アドレスからその所属国のカントリーコードを検索するためのGo言語用モジュールを作ってみました](https://qiita.com/suka-test/items/576746d650f25f999f28)

## レビュー講評

レビューしてくれとお願いして、モジュールの本体のソースコード（コメント入れて７００行ちょっと）を貼り付けたら、こんな答えが返ってきました。

![ChatGPT.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3872080/0e06851e-e57e-3229-6482-24de93c1ceb3.jpeg)

## 作者本人の感想

とりあえず、致命的な問題は指摘がなかったので一安心。
「ポジティブな点」も挙げてくれるのは、ちょっとうれしかったり（他愛のない）。
「改善提案」については、妥当なとこかなと思います。
特に1.〜5.は早めに修正しようと思ってます。
6.の「ユニットテストの実装」は、実装済みなんですが ChatGPT に見せなかったので、こうなったよう。ひょっとして GitHub の URL 指定して見てもらったらよかったのかも。
7.は指摘がやや具体性に欠けるので、すぐに対応はしにくいですね。今後の課題としときます。
すでに多くの方が実感しておられるように、ChatGPT でコードレビューは非常に有用だなと思いました。特に無名の個人開発だと他者の目が入りにくいので、ありがたい。今後も使っていこうと思います。
ただ、レビューしてくれとお願いしたのはこっちなのに、ChatGPT が「レビューありがとうございます」って、日本語、変だぞ（笑）。
視差データの表示方法

ステレオ計測をすると、データをどう可視化するのかという問題に出くわす。

## データの保存だけなら、*.npy　ファイルでなんとかなるだろう。
numpy を利用すること前提になるが、IEEEの不動小数点フォーマットでNaN, PosInf, NegInf を含めてデータを保存できる。

#### データを登録して管理するのは、npyファイルだけで十分
- カラー化した画像を保存するのは無駄。
- カラー化した画像はnpyファイルから簡単に作れる。
- ビューワーは簡単にアルゴリズムから切り離せる。

#### 視差それとも深度
- 視差データがよいと考える。
    - left画像とright画像から決まるのは視差データ。
    - 特定のステレオカメラの深度データは、視差データに換算できる。
    - DepthAnythingも視差データを算出する。
    - 視差こそが比較に適している。
- データの精度を考えるとき
    - 視差ベースの比較の方が、残差の比較に適する。
    - 15m、20ｍの差を5mの残差として考えるよりは, 15m相当の視差、20m相当の視差の差と考えるほうがいい。
    - 残差２乗和の最小化に適するのは、視差。
- ロボットの場合
    - 近距離の物体の方が重要。
    - 近距離での距離の精度の方が重要。

以上のことから視差データの表示ツールを作ることにした。

## 表示方法の例（最大値と最小値による正規化）

- グレースケール表示：
    - データを最大値と最小値で正規化してそれをグレースケールで表示する
    - 近い側が白、遠い側が黒の方が、視覚的に理解しやすい。
- カラーマップ表示：
    - データを最大値と最小値で正規化してそれをカラーマップで表示する
    - カラーマップを表示の画像をモノクロ印刷しても大小関係がわかるカラーマップとそうでないカラーマップがある。
考慮すべき値の範囲
- 視差ベースならば、カメラに違い側が限界を決める。
#### 欠損値の扱いをどうするか？



### 難点：
異なるフレーム間での比較、異なる手法間での比較に向かない。

#### 

plt.imshow(img, vmin=0.0, vmax=10.0)
この方法だと、フレーム間での比較が可能になる。


Jetのcolormap
利点：セグメンテーションとしてわかりやすい
難点：
colomap に対応するcolorbar が与えられていないことが多いので
深度の絶対値を知ることができない。
平面であるべきものが平面に保たれているか・歪んでいるかがわからない。


視差データ・深度データの表示の課題
よほどの理由がないかぎり、その示す値の妥当性（もっともらしさ）を人が視覚的にすることができない

### ほしい情報
- 物体表面の法線ベクトルの向きがわかる可視化手法
 そうすれば、平面であるべき領域が平面になっているのかが判定しやすい。
 シェーディングの情報によって対象物の形状の様子などがわかる。


---
[Open3D Visualization](http://open3d.org/html/tutorial/Basic/visualization.html)
から引用
```.py:
print("Load a ply point cloud, print it, and render it")
pcd = o3d.io.read_point_cloud("../../TestData/fragment.ply")
o3d.visualization.draw_geometries([pcd], zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/f4b1aea1-494c-850c-1837-31985999ea82.png)


[open3d.visualization.draw_geometries](https://www.open3d.org/docs/release/python_api/open3d.visualization.draw_geometries.html)

## 3D カメラのSDKでのサンプルコードの例
OpenGL を利用して書かれたviewerを利用している。
https://github.com/stereolabs/zed-sdk/blob/master/depth%20sensing/depth%20sensing/python/depth_sensing.py
linux で解像度を変更するコマンドをつくった

# 動機

 - 普段外部ディスプレイを使っているが、たまにmacのディスプレイを使うので、その時に解像度を楽に切り替えたい
 - macのディスプレイに合った解像度がkali linuxの初期の解像度一覧になかった

これらの問題を解決するために、kali linuxのターミナル上からコマンドを打つことによって、すぐに解像度を切り替えられるようにした。仮想環境が不調になったとき、すぐ環境を破壊してまた構築することが多いので備忘録として残しておく。

# 環境
- M2 macbook air
- macにUTMをインストールし，そこでkali linux を動かしている

# ディスプレイ情報の取得
まず、下のコマンドによってディスプレイ情報を取得する。

```
xrandr
```

コマンドを打って帰ってきた`Virtual-1 connected primary 1920x180+0+0 (normal left inverted right x axis y axis) 325mm x 203mm`みたいな部分のディスプレイ名っぽいやつ（今回の場合は`Virtual-1`）を控えておく。

参考:[Linuxで画面解像度設定を追加する](https://zenn.dev/mnod/scraps/d443ad354aab8e)

# モードラインの取得

以下のコマンドにより、モードラインの取得を行う。

```
gtf 2560 1600 60
```
今回は解像度2560x1620、リフレッシュレート60で設定している。コマンドの結果はこんな感じ。

```
# 2560x1600 @ 60.00 Hz (GTF) hsync: 99.36 kHz; pclk: 348.16 MHz
  Modeline "2560x1600_60.00"  348.16  2560 2752 3032 3504  1600 1601 1604 1656  -HSync +Vsync
```
この結果の`"2560x1600_60.00"  348.16  2560 2752 3032 3504  1600 1601 1604 1656  -HSync +Vsync`の部分を控えておく。

参考:[Linuxで画面解像度設定を追加する](https://zenn.dev/mnod/scraps/d443ad354aab8e)

# シェルを調べる

シェルは
```
which $SHELL
```

によって調べられる。自分の環境ではzshなので、.zshrcファイルを編集する。

参考:[Linuxにおける自作コマンドの作り方](https://qiita.com/ankuru/items/0501eb74a2a31bdfbcb3)

# 調べた情報を元にコマンドを作る

### シェルスクリプトをぶち込むディレクトリをつくる

[Mac（Catalina）でのzshの自作コマンドの作り方](https://wemo.tech/3949)という記事がとてもわかりやすかったので参考にした．シェルスクリプトの内容以外はぶっちゃけこの記事を見ればわかるが、一応手順を書く。

今回は参考記事に従って`mycommands`というディレクトリをホームディレクトリ直下に作って、そこにスクリプトファイルをぶち込むことにする。

### パスを通す

今回シェルはzshなので`.zshrc`に

```
export PATH=$HOME/mycommands:$PATH
```
という記述を追加する。`.zshrc`はホームディレクトリにある。ない場合は作成して上の記述を追加する。

### `.zshrc`の内容を反映させる

`source`コマンドやターミナルの開き直しで反映するっぽいが、なんか確実そうなのでおれはいつも再起動してる（本当に確実なのか？？）

### シェルスクリプトファイルを書く

先ほど作った`mycommands`ディレクトリの下にシェルスクリプトファイルをぶち込む。今回は`chreso`という名前のファイルを作った。この時拡張子は無しにする。`chreso`の内容は以下の通り。

```
#!/bin/zsh

xrandr --newmode "2560x1600_60.00"  348.16  2560 2752 3032 3504  1600 1601 1604 1656  -HSync +Vsync
xrandr --addmode Virtual-1 2560x1600_60.00
xrandr --output Virtual-1 --mode 2560x1600_60.00
```

`xrandr --newmode "2560x1600_60.00"  348.16  2560 2752 3032 3504  1600 1601 1604 1656  -HSync +Vsync`や`Virtual`は先程控えておいたものに適宜置き換える。

参考：[Linuxで画面解像度設定を追加する](https://zenn.dev/mnod/scraps/d443ad354aab8e)

### シェルスクリプトファイルへの権限の設定

`chmod`を使って権限を設定する

```
sudo chmod 755 ~/mycommands/chreso
```

# コマンドの呼び出し

あとはターミナルで

```
chreso
```

と打てば解像度が変わる！（はず）

# 最後に
読んでいただいてありがとうございました！！
はじめて書いたqiitaの記事なのでお手柔らかに…
iOS来月先月を取得する方法

来月先月を取得する方法です

# 完成イメージ
![sumplee.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/39426230-ccec-4d7c-4637-1e2849dfee30.gif)


DateComponentsを使って現在の年月を表示する

https://qiita.com/yuta317/items/e6bbf95eb3d303e030dd

こちらの記事の続きになります。

# 実装方法
```NextLastDateViewModel.swift
class NextLastDateViewModel: ObservableObject {
    @Published var text: String = ""
    var component: DateComponents
    
    init() {
        component = Calendar.current.dateComponents(in: TimeZone.current, from: Date())
        text = component.getYearMonthFormat()
    }

    func onTapNext() {
        let calendar = Calendar(identifier: .gregorian)
        let date = calendar.date(from: component)!
        let addMonth = DateComponents(month: 1, day: 0)
        let nextMonth = calendar.date(byAdding: addMonth, to: date)!
        component = Calendar.current.dateComponents(in: TimeZone.current, from: nextMonth)
        text = component.getYearMonthFormat()
    }

    func onTapLast() {
        let calendar = Calendar(identifier: .gregorian)
        let date = calendar.date(from: component)!
        let addMonth = DateComponents(month: -1, day: 0)
        let lastMonth = calendar.date(byAdding: addMonth, to: date)!
        component = Calendar.current.dateComponents(in: TimeZone.current, from: lastMonth)
        text = component.getYearMonthFormat()
    }
}
```
# コード説明
重要なところだけ説明します。
`getYearMonthFormat`については上記記載のあるリンクの前回を確認してください。
`DateComponents`を変数で持っておきます。
`onTapNext()`は来月のボタンを押したらの処理です。
`onTapLast()`は先月のボタンを押したらの処理です。
`DateComponents(month: -1, day: 0)`
`DateComponents(month: 1, day: 0)`
こちらで先月、来月にしています。
これを利用すれば来年、明日なども可能になります。
UIは自分で好きなように作成してください！
ラズパイ bookworm で WiFiパワーマネジメントを無効にする。

mac と Raspberry Pi Zero を接続して、ssh, vnc, afpで接続していますが、非常に不安定で接続がすぐ切れてしまうので、WiFiのパワーマネージメントの設定を触ってみましたが、再起動すると、
```bash
pi@raspberrypi:~ $ iwconfig wlan0
wlan0     IEEE 802.11  ESSID:"XXXXXXXXXX"  
          Mode:Managed  Frequency:2.452 GHz  Access Point: XX:XX:XX:XX:XX:XX   
          Bit Rate=52 Mb/s   Tx-Power=31 dBm   
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:on
          Link Quality=37/70  Signal level=-73 dBm  
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0
```
と、 Power Management:on になってしまう...。

試行錯誤して、いくつかの設定ファイルを操作する中で、...あ！ bookworm に変わったからか？

改めて調べ直したら、フォーラムにありました。

[Bookworm WiFi Power Save Defaults to On?](https://forums.raspberrypi.com/viewtopic.php?t=357629)
```bash
pi@raspberrypi:~ $ nmcli c modify XXXXXXXXXX 802-11-wireless.powersave 2
```
これ一発で、再起動後もめでたく Power Management:off になりました。  
`XXXXXXXXXX`はお使いの WiFi の SSID に置き換えて、最後の数字を`2`にしてください。

フォーラムにはありますが、更にリンク先の [802-11-wireless — Wi-Fi Settings](https://networkmanager.dev/docs/api/latest/settings-802-11-wireless.html) に拠れば、最後の数字は、

- 2: 無効
- 3: 有効
- 1: 無視（現在の設定に対して何もしない）
- 0: デフォルト（グローバルの設定を使う）
- その他： 予約

とのことです。
netplanのroute

### Ubuntu 24.04
# 2つのゲストOS間の通信させるためには
`ping`をしたが反応がない。

netplanのドキュメントまたはネットワークの基本を見てみることにした

### ルーティングテーブル
>ルーターによるパケットの転送のことを`「ルーティング」`と言います。ルーティングは、何をどこへ転送すればいいのかを定めた転送ルールにしがって行われており、その転送ルールを定める重要な要素が`ルーティングテーブル`です。

### ping
>pingコマンドはICMP ECHOパケットを送り、機器がそれに対して応答を返すかどうかを調べるコマンドです。

https://www.sbcr.jp/product/4797386677/

>#### from (scalar)
>
>Set a source IP address for traffic going through the route. (NetworkManager: as of v1.8.0)
>
>#### to (scalar)
>
>Destination address for the route.

https://netplan.readthedocs.io/en/stable/netplan-yaml/#:~:text=from%20(scalar),address%20for%20the%20route.


```
network:
  version: 2
  ethernets:
    enp0s3:
      addresses:
        - 10.0.3.16/24
      routes:
        - to: 10.0.2.16/24
          from: 10.0.2.0/24

~                        
```
再起動した後pingで通りました。

# 感想
当たり前のことを忘れていた。
しかし問題解決できてよかった。
エンジニアですがいまだに転職先がみつからないので、YouTubeの動画を死ぬほど解析してみた

# はじめに
いまだに転職先がみつからないので、YouTubeの動画を死ぬほど解析してみました。通常のアナリティクスでは得られないコメントの感情分析や、テキスト分析を行っています。コメント解析してみると、動画が世間からどういう反応が得られているのかわかるので面白い。データ解析の仕事とか見つかんねぇかなー。

# データ解析手法
- YouTube API V3を使って動画のデータを取得
- Google Cloud Natural Language を使ってコメントの感情分析を実施

# 解析事例
https://note.com/takurot/n/nb41d9d721535?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n6af3ba499a6b?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n775be855fab6?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n023a557591cf?magazine_key=m71f5bc73a632

https://note.com/takurot/n/ne3a906d924a5?magazine_key=m71f5bc73a632

https://note.com/takurot/n/nea5e3d0b3da8?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n204cfbc9672c?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n7629c56f5a88?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n447b2f5ca849?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n042db5e91533?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n60de992cb190?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n54dec488b358?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n5c4fc7aa5ed3?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n3934ee2f8b93?magazine_key=m71f5bc73a632

https://note.com/takurot/n/neb259a2dcf72?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n68e27e1ffb01?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n8873127b4fba?magazine_key=m71f5bc73a632

https://note.com/takurot/n/nab56143b56b2?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n033677a6e7c8?magazine_key=m71f5bc73a632

https://note.com/takurot/n/n3c483b7ce99e?magazine_key=m71f5bc73a632