OmniAICreator/Qiita-1.07M huggingface dataset:
serverless v4 でAPI Gatewayのログ出力を設定するとエラーになってデプロイできない

## はじめに
serverless framework v4でAPI Gatewayのログを設定すると、```The role with name serverlessApiGatewayCloudWatchRole cannot be found. ```というエラーが出てデプロイできない不具合がありました。```serverlessApiGatewayCloudWatchRole```という名前でIAM Roleを作れば解決するのですが、初見殺しすぎるので解決方法を共有します。

## 事象
以下のようにserverless.ymlでAPI Gatewayのログを出力するように設定します。

```yml
provider:
  name: aws
  logs:
    websocket: true
```

これで```sls deploy```をすると、以下のエラーが出て、デプロイに失敗します。

>✖ An error occurred: CustomApiGatewayAccountCloudWatchRole - Received response status [FAILED] from custom resource. Message returned: The role with name serverlessApiGatewayCloudWatchRole cannot be found. See details in CloudWatch 

## 解決策
```serverlessApiGatewayCloudWatchRole```という名前のIAM Roleを作成します。
一度IAM Roleを作成すれば、そのAWSアカウント内では大丈夫です。

### 作成するIAM Role

以下の設定でIAM Roleを作成します。

* 信頼されたエンティティタイプ = AWSのサービス
* サービスまたはユースケース = API Gateway
* ユースケース = API Gateway

![iam-role-config.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26979/213478f8-6e54-bd8e-6346-466188c277c9.png)

許可ポリシーに```AmazonAPIGatewayPushToCloudWatchLogs```がデフォルトで選択されているので、そのまま```次へ```をクリック。

![スクリーンショット 2024-06-29 18.28.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26979/7d24d140-c66b-7611-bbe6-a204d6013c1b.png)

ロール名に```serverlessApiGatewayCloudWatchRole```を入力して、ロールを作成する。

![スクリーンショット 2024-06-29 18.29.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26979/0e58deb5-f6d5-4683-5ce0-9d1ed82ed899.png)

## 参考文献
API Gateway で「CloudWatch Logs role ARN must be set in account settings to enable logging」が発生するときの対処方法  
https://dev.classmethod.jp/articles/tsnote-apigw-what-to-do-when-cloudwatch-logs-role-arn-must-be-set-in-account-settings-to-enable-logging-occurs-with-api-gateway/
OpenFOAM10の実行時コードの変更点

# はじめに
Foundation版OpenFOAMのバージョン10で実行時コードが変更されたため、原因調査および対策を考えた。その結果をここに記す。

# 発生状況
境界条件（たとえばcodedMixed）で解析時刻を取得していたが、バージョン10で実行時コンパイル時にエラーが発生して計算ができなくなった。

# 原因
バージョン9までは次のコードで解析時刻を取得できていた。
```
this->db().time(). timeOutputValue() 
```
バージョン10でtimeOutputValueメソッドが存在しなくなったため、エラーが発生した。

# 対策
バージョン10では同様の機能を持つメソッドが用意されている（というか名前が変わっただけ）。
```
this->db().time().userTimeValue() 
```
バージョン10以降はuserTimeValueメソッドを使用すればよい。

# おわりに
なんでこんな変更をしたのだろう...?
(覚書)回転制御をRelative座標系で完結させたい

# 概要
アクターの回転はさておきコンポーネントの回転や移動で"Set World ○○"シリーズを多用して処理負荷を爆上がりさせてしまった経験があるので全部Relative系列でやる方法の覚書とその情報共有。

これはあくまで予測だが、例えばアクターの移動に伴うコンポーネントの移動など、平時の内部処理がRelativeかそれに準ずる方式が取られており、"Set world"シリーズを使うとそれらを全てオーバーライドする必要から追加の負荷が掛かっている(二度手間になっている)のかもしれない

この記事では主にコンポーネントをどこかワールド空間上の特定座標の方向に指向したい場合を主とした内容で記そうと思う。
(※自分は脳内計算が得意ではない都合上、直感的、視覚的に扱えるようノードを組んでいるのでmath系ノードの使用数が多少増えるかもしれないが悪しからず...)

今回はこのアクターに付いているSphereとそれに紐づけたCube2本(お察しください)を指向してみる
![SpaceCombatSB - Unreal Editor 2024_06_29 15_10_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752748/10346055-3f47-db26-4621-dd19af539f8f.png)


# 基本
とりあえず素直に特定座標を向かせる
ノード全景
![BP_Lookat-Demo 2024_06_29 15_18_53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752748/c7e6aedf-c2e6-c664-5a49-e04d6c4bd8b1.png)
処理の流れとしては、
```mermaid
graph TD;
    A[回転させたいコンポーネントから目標座標を見る方向の回転（ワールド）を取得]-->B[Inverseを使い、親のローカル（SphereのRelative）座標系に回転を変換する];
    B-->C[Set Relative Rotation]
```
となる。

回転する軸を限定する場合は算出したRelative回転を一度breakしてほしい軸のみmake rotatorに接続することになる。
動作時の様子
![trackingNormal.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752748/262f0287-9519-eada-8a67-2078a6cc0015.gif)


# 時間当たりの回転速度を制限する
即座に目標方向を向くのではなくゆっくりと向いて欲しい場合
![BP_Lookat-Demo 2024_06_29 18_02_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752748/33956e5a-fd62-9fb7-795a-aa5627075f97.png)
Relative回転は-180°～+180°で表されるため、そのままclampすると変化量を安定して制限できない。
なのでまず絶対値で"大きさ"をclampしたのち、signノードで正負の向きを戻してやる方法を取る。
そしてRelativeは自身のローカルではなく親のローカル座標系のため"差分"をそのまま使うことはできないので、差分を計算したのち現在のRelative Rotationの値と合算するしなければならない。

動作の様子
![trackingSlow.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752748/34f9c728-6a7e-ddc3-4b1e-ba3bfc063b0e.gif)



### おまけ - アクターを指向する
制御対象がアクターの場合は座標系をRelativeからワールドに戻す必要があるのでInverseした値をCompose Transformに通す。
![BP_Lookat-Demo 2024_06_29 17_01_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752748/091dc113-2cc3-7c01-1cc9-7dfac692fca9.png)
- 入力するTransformはInverseで用いたTransformと同じものを使う。

一度Transormの形を作って座標系を変換した後もう一度Rotatorに分解する必要があるので手間と面積を取るのが少々面倒なのでCompose周辺だけ関数かマクロを作っておくと吉。
Rubyのバージョン管理とgemインストール時のパーミッションエラーの解決方法

# 問題
Ruby on Railsをインストールしようとして、次のエラーが表示されました：
```bash
You don't have write permissions for the /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/gems/2.6.0 directory.
```

# 原因
このエラーは、システムにインストールされているRubyのバージョンでgemを管理しようとしているためです。システムのRubyでは通常、ユーザーに書き込み権限が与えられていないため、gemをインストールすることができません。

# 解決方法
rbenvを使用してRubyのバージョンを管理する

rbenvを使ってローカルにRubyのバージョンをインストールし、管理することで、この問題を回避できます。

```bash
$ rbenv install 2.6.6
$ rbenv global 2.6.6
```
これにより、ローカルにインストールしたRubyのバージョンがシステムのRubyより優先されるようになります。

gem installを再試行する

Rubyのバージョンを2.6.6に切り替えた後、gem installコマンドを再度実行してください。

```bash
$ gem install rails
```

これにより、ローカルにインストールしたRubyのgemディレクトリに対して適切な書き込み権限が与えられ、Railsがインストールされるはずです。

# まとめ
この方法により、システムのRubyを使用する際に発生するパーミッションエラーを回避し、rbenvを活用してローカルにRubyのバージョンを管理することで、gemを安全にインストールすることができます。

以上、Rubyのバージョン管理とgemインストール時のパーミッションエラーについての解決方法でした。他にも質問があればお気軽にどうぞ！
macOS 12.6 on arm64 で rbenv を使用して Ruby 2.6.6 をインストールする際のエラーと対策

最近、macOS 12.6 on arm64 環境で rbenv を使用して Ruby 2.6.6 をインストールしようとしたところ、以下のようなエラーに遭遇しました。

```bash
BUILD FAILED (macOS 12.6 on arm64 using ruby-build 20240612-2-g08aadf4)
```

このエラーは、特定の環境設定が必要であることを示しています。そこで、解決策として次のコマンドを使用しました。

```bash
RUBY_CFLAGS=-DUSE_FFI_CLOSURE_ALLOC arch -arm64 rbenv install 2.6.6
```

これにより、Ruby 2.6.6 を正常にインストールすることができました。

## 解決方法の詳細
このエラーは、ARMアーキテクチャ上でのRubyのビルド時に必要な特定のCFLAGS設定が不足していたことが原因でした。RUBY_CFLAGS=-DUSE_FFI_CLOSURE_ALLOC arch -arm64 を使用することで、ARM64環境向けに適切なビルドオプションが適用され、ビルドが成功しました。

## 手順
1. rbenvのインストール: rbenvをインストールし、パスを設定します。
```bash
# rbenvのインストール
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(rbenv init -)"' >> ~/.zshrc
source ~/.zshrc
```

2. Ruby 2.6.6のインストール: RUBY_CFLAGSとarch -arm64を指定して、Ruby 2.6.6をインストールします。
```bash
RUBY_CFLAGS=-DUSE_FFI_CLOSURE_ALLOC arch -arm64 rbenv install 2.6.6
```

3. 確認: インストールが完了したら、正常にRubyが動作するか確認します。

```bash
ruby -v
```

これにより、macOS 12.6 on arm64 環境でのRuby 2.6.6のインストール手順と問題解決法を紹介しました。rbenvを使用してRubyを管理する際に同様のエラーに遭遇した場合、この方法を参考にしてください。
アウトプットは、『自分の歴史の本』になる

## はじめに
今入社3年目になり、この2年SIerにて開発をしていました。
ハードなPJもなんとか乗り越え、社会人として頑張ってきたものの、2年前の今頃具体的に何に困って、何を考えていたかを思い出すことはなかなか難しい。
なんなら、1ヶ月前の自分が何を考え、学んだかも思い出せない。

**なぜ思い出せないのか。**
原因はただ一つ、**プロセスのアウトプットをしていなかった**から。

:::note warn
もちろんPJとしての、設計書だったり、コーディングだったりのアウトプットはしてきたが、その**成果をあげるまでの分からないことや、感情などのプロセスのアウトプットを全く残していなかった**ことを後悔している。
:::


なので、今回はアウトプットの重要性について書いていこうと思う。


## なぜ今までプロセスのアウトプットを怠ってきたのか
結論から言うと、**会社から求められた成果物のアウトプットで満足してしまっていた**。
この会社から求められた成果物のアウトプットとは、設計者やコーディングなど納品に関わるもののことである。

入社3年目となり、後輩も増えてきた。
後輩に相談された時、自分が彼らと同じ立場だったとき、何が分からなくて何に困っていたのか、あまり思い出せないことに非常に焦りを覚えた。
 
:::note info
今思えば、**アウトプット = 納品関わる成果物 + 成果物作成に至るプロセスをまとめる**と言う意識を入社時から持っていられた良かったと思う。
:::

## 『プロセスのアウトプット』をするメリット①<br>〜同じ過ちを繰り返さなくて済む〜
過去に分からなかったこと、そしてその解決策を記載しておけば、すぐに振り返れる上、アウトプットした分、記憶に残りやすくなり、同じ過ちを繰り返さなくて済みます。

いわば、プロセスのアウトプットは、**『自分の歴史の教科書』**。
小学生の時の歴史の授業の内容なんて、今となればほとんど覚えていなかったりするが、歴史の教科書さえあれば、思い出したい時に見返すだけで、内容を理解することができる。

:::note info
そして、このプロセスのアプトプットを周りの人に共有すれば、**周りの人が同じことに躓いた時の参考になります**。
:::


## 『プロセスのアウトプット』をするメリット②<br>〜整理ができて、説明しやすくなる〜
このプロセスのアウトプットをしておくことで、周りの人に自分の成果物について質問された時に、説明がしやすくなるのもメリットだと思います。

自分の頭の中で考えたことをすぐに、口で説明するのは難しい。
でも、分からなかったことや、その解決方法をメモしておくだけで、一回アウトプットしている分、口頭でも説明しやすくなる。

:::note info
**丁寧に書く必要はない**と思います。
**後で自分が振り返った時に理解ができればそれでいい**。
:::


## アウトプットは、『自分の歴史の本』になる
アウトプット場所は、
社内のメモ機能だったり、このQiitaだったり、個人ブログだったり、どこでもいい。
社内でのアウトプットに加えて、私はQiitaでもっと前からアウトプットをしておけば良かったと感じている。
(Qiitaは、社外の普段は関わることのできない同業者の意見も読めて、刺激になるため。
)


:::note info
ものにも寄るが、プロセスのアウトプットは30分もあればきっと大体は書けるだろう。
**未来の自分の投資のため**にも、このアウトプットをぜひ他の人にも薦めたい。
:::
【JavaScript】画像を切り絵風に加工する


## 切り絵風とは

輪郭抽出 & 2値化

## 結論

1. 画像をCanvasに貼り付ける
1. imageDataを取得する
1. imageDataをkirieFilterに突っ込む
1. 突っ込んだimageDataをputImageDataで反映させる

```js:kirie_filter.js
function kirieFilter(imageData, outlineThreshold = 180, fillThreshold = 100) {
    // sobelフィルタによる輪郭抽出
    
    const data = imageData.data;
    const width = imageData.width;
    const height = imageData.height;

    for (let i = 0; i < data.length; i += 4) {
        if (data[i + 3] === 0) {
            data[i] = 255;
            data[i + 1] = 255;
            data[i + 2] = 255;
        }
        else {
            const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
            data[i] = avg;
            data[i + 1] = avg;
            data[i + 2] = avg;
        }
        data[i + 3] = 255;
    }

    const sobelData = new Uint8ClampedArray(width * height);

    const kernelX = [
        [-1, 0, 1],
        [-2, 0, 2],
        [-1, 0, 1]
    ];
    const kernelY = [
        [-1, -2, -1],
        [0, 0, 0],
        [1, 2, 1]
    ];

    for (let y = 1; y < height - 1; y++) {
        for (let x = 1; x < width - 1; x++) {
            let pixelX = 0;
            let pixelY = 0;

            for (let ky = -1; ky <= 1; ky++) {
                for (let kx = -1; kx <= 1; kx++) {
                    const pixel = data[((y + ky) * width + (x + kx)) * 4];
                    pixelX += pixel * kernelX[ky + 1][kx + 1];
                    pixelY += pixel * kernelY[ky + 1][kx + 1];
                }
            }

            const magnitude = Math.round(Math.sqrt(pixelX * pixelX + pixelY * pixelY));
            sobelData[y * width + x] = magnitude;
        }
    }

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const idx = (y * width + x) * 4;
            const invertedMagnitude = 255 - sobelData[y * width + x];

            if (invertedMagnitude < outlineThreshold || data[idx] < fillThreshold) {
                data[idx    ] = 0;
                data[idx + 1] = 0;
                data[idx + 2] = 0;
            }
            else {
                data[idx    ] = 255;
                data[idx + 1] = 255;
                data[idx + 2] = 255;
            }
        }
    }

    // ノイズ除去
    medianFilter(imageData);
}

function medianFilter(imageData) {
    const data = imageData.data;
    const width = imageData.width;
    const height = imageData.height;
    const copy = new Uint8ClampedArray(data);
    for (let y = 1; y < height - 1; y++) {
        for (let x = 1; x < width - 1; x++) {
            const pixels = [];
            for (let dy = -1; dy <= 1; dy++) {
                for (let dx = -1; dx <= 1; dx++) {
                    const index = ((y + dy) * width + (x + dx)) * 4;
                    pixels.push(copy[index]);
                }
            }
            pixels.sort((a, b) => a - b);
            data[(y * width + x) * 4] = pixels[4];
            data[(y * width + x) * 4 + 1] = pixels[4];
            data[(y * width + x) * 4 + 2] = pixels[4];
        }
    }
}
```

## サンプル

https://mogamoga1024.github.io/kirie/easy/
OpenFOAM9の実行時コードの変更点

# はじめに
Foundation版のOpenFOAMのバージョン9で、物理量をコンストラクタで取得することができなくなった。
原因の調査および対策を考えたので、ここに記す。

# 状況
境界条件（たとえばcodedMixed）に次のようにコードが含まれていたとする。
```
code
#{
    fvPatchField<scalar> rhop
    (
        patch().lookupPatchField<volScalarField, scalar>("rho")
    );
    fvsPatchField<scalar> phip
    (
        patch().lookupPatchField<surfaceScalarField, scalar>("phi")
    );
#};
```
これらのコードは実行時コンパイルでエラーが発生して、計算ができない。

# 原因
OpenFOAM9でコンストラクタを使用したコピーが禁止されたため。

```$FOAM_SRC/finiteVolume/fields/fvPatchFields/fvPatchFields/fvPatchField.H
196    //- Disallow copy without setting internal field reference
197    fvPatchField(const fvPatchField<Type>&) = delete;
```
```$FOAM_SRC/finiteVolume/fields/fvsPatchFields/fvsPatchFields/fvsPatchField.H
182    //- Disallow copy without setting internal field reference
183    fvsPatchField(const fvsPatchField<Type>&) = delete;
```

# 対策
ポインタを使う。

```
const fvPatchScalarField& rhop =
    patch().lookupPatchField<volScalarField, scalar>("rho");
```
```
const fvsPatchField<scalar>& phip =
    patch().lookupPatchField<surfaceScalarField, scalar>("phi");
```

テンプレートを使う方法もある。
```
const fvPatchScalarField& rhop =
    this->patch().template lookupPatchField<volScalarField, scalar>
    (
        "rho"
    );
```
```
const fvsPatchField<scalar>& phip =
    this->patch().template lookupPatchField<surfaceScalarField, scalar>
    (
        "phi"
    );
```
# おわりに
C++はどうも苦手で、コンストラクタとかポインタとか書いたが合っているのかイマイチである。
テンプレートも調べたのだが、gccのバグを避けるために使うなどの記述があるので、テンプレートを使う方法の方が良いのかもしれない。
df.iterrows()で型推論がうまく働かず、indexがHashableとして認識されてエラーになっていた件

# Pandas DataFrameのiterrows()使用時のPylance警告対処法

## はじめに

Pandasの`DataFrame.iterrows()`を使用する際、Pylanceから型についての警告が出て、
少し解決に至るまで時間がかかったため、備忘としてメモを残します。

## 問題の概要

以下のようなDataFrameがあったとして

```python
            temperature  humidity  pressure
2023-01-01          20        50      1013
2023-01-02          22        55      1012
2023-01-03          19        60      1010
2023-01-04          23        48      1015
2023-01-05          21        52      1014
```

このDataFrameに対して、以下のようなコードを書くと：

```python
data = []
for index, row in df.iterrows():
    data.append({
        "date": index.strftime('%Y/%m/%d'),
        "temperature": row['temperature']
    })
```

`index.strftime('%Y/%m/%d')`の部分で、次のようなPylanceの警告が表示されます：

```
クラス "Hashable" の属性 "strftime" にアクセスできません
  属性 "strftime" が不明です
  Pylance(reportAttributeAccessIssue)
```

どうやら、`iterrows()`の戻り値は型Hashableとして認識され、型推論がうまく働かないようです。

## 解決への試行錯誤

### 型アノテーションの追加

型アノテーションを追加しても、エラーは解消されませんでした：

```python
data = []
for index, row in df.iterrows():
    date: datetime = index
    data.append({
        "date": date.strftime('%Y/%m/%d'),
        "temperature": row['temperature']
    })
```

この場合、`index, row`部分で以下のエラーが発生します：

```
型 "Hashable" の式は、宣言された型 "datetime" と互換性がありません
  "Hashable" は "datetime" と互換性がありません
  Pylance(reportAssignmentType)
```

### 型ガードの使用

型ガードを使用すると、エラーは表示されなくなります：

```python
data = []
for index, row in df.iterrows():
    if not isinstance(index, datetime):
        continue
        
    data.append({
        "date": index.strftime('%Y/%m/%d'),
        "temperature": row['temperature']
    })
```

### 型キャストの使用

型キャストを使用しても、エラーは解消されます：

```python
from typing import cast

data = []
for index, row in df.iterrows():
    date = cast(datetime, index)
    data.append({
        "date": date.strftime('%Y/%m/%d'),
        "temperature": row['temperature']
    })
```

## 終わりに
Pythonの型推論の動き方をうまく理解できておらず、
当初は型ガードを試みても改善されないと誤解してしまい、苦戦しましたが、しかし、実際には比較的シンプルな解決方法でした。
今回は素直な型ガードや型キャストで、Pylanceの警告を解消できました。



## 参考

- [Stack Overflow: Type annotation hint for index in pandas dataframe iterrows](https://stackoverflow.com/questions/71277420/type-annotation-hint-for-index-in-pandas-dataframe-iterrows)
答えはなぜバナナなのか🍌🧐 -> すぐにわかりませんでした

## はじめに
Xで以下のようなポストを見かけました。
JavaScriptの学習中だったので原因を突き止めてやろうと意気込んで検証し始めたのは良いものの、
(案の定、) 時間を無駄に使ってしまう結果に終わりました。
そのせめてもの供養に、記録に残そうと記事にしました。

https://x.com/RyanEls4/status/1805439977557225648

:::note warn
この記事はJavaScript初心者が仮説思考も行わず無様に試行錯誤を行っただけのものです。
:::

## 検証
ポストされていたのはこのようなコードです。
```js
console.log(('b' + 'a' + + 'a' + 'a').toLowerCase());
  // banana
```
これを、PHPのマジカルインクリメントのような機能が働いているのかと3つ目の`'a'`を変えてみたり、
```js
console.log(('b' + 'a' + + 'b' + 'a').toLowerCase());
  // banana
```
なんとなく`+`の間のスペースを取り除いてみたりしましたが、
```js
console.log(('b' + 'a' ++ 'a' + 'a').toLowerCase());
  // SyntaxError
```
ヒントになるようなものは得られず、
結局適当に文字列を変えてみてようやく`NaN`が関係していることに気づきました。
```js
console.log(('b' + 'b' + + 'b' + 'b').toLowerCase());
  // bbnanb
```
```js
console.log(+ 'b');
  // NaN
```

## 結果
`+`演算子には加算だけでなく、オペランドが数値以外の場合は数値に変換する、単項プラス演算子としての役割があるそうです。

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

つまり、ポストのコードは以下のものと同義のようです。
```js
console.log(('b' + 'a' + NaN + 'a').toLowerCase());
  // banana
```

## おわりに
なぜ`toLowerCase()`を使っているのかということから仮説を立てていけば、
少なくともNaNが関係していることまではすぐにたどり着けていた気がします。
今後はプログラミング学習のスピードと質を上げるためにも、より仮説思考を意識しながら学習を進めていこうと思います。
【Python】tkinterでキーバインドを行う際に押したキーを判定する方法

# はじめに

tkinterでbind関数を使用してキーバインドを行う際に、「押したキーがどのような値としてプログラム上で認識されているか」を確認する必要があり、押したキーを判定するスクリプトを作成し便利でしたので投稿します。

#### 開発環境
・WSL2/Ubuntu環境
・Python: 3.10.12

# 押したキーを判定するスクリプト

```PressKey_sample.py

import tkinter as tk
from tkinter import Text


# Determine pressed key
def Sample_PressKey(event):
    print(f"Key: {event.keysym}")


# configure root
root = tk.Tk()
root.title("PressKey_sample")
root.geometry("800x600")

# make text
text = Text(root, wrap="word", undo=True)
text.pack(fill="both", expand=True)

# configure key-bind
root.bind("<Key>", Sample_PressKey)

root.mainloop()


```

### プログラムの動作

キーを押すと、コンソール上に押したキーが値として出力されます。
Text領域も生成するようにしているので、テキストとしても入力した文字を確認できます。


# 参考文献

本記事は以下情報を参考にして執筆しました。

https://mulberrytassel.com/tkinter-start-45/
【記録】セキュリティキャンプに応募した話

## はじめに
　先日、セキュリティキャンプに応募しました。
　結論から言うと「選考で落ちてしまった」が、その経験を振り返り、選考を通過した友人と何が違ったのか。そして次回に向けた反省点を記録しておこうと思います。

## １：応募したきっかけ
　応募のきっかけは、友人の一言でした。
「セキュリティキャンプに参加してみたら？」
　初めての挑戦でわからないことだらけでしたが、興味本位で応募してみることにしました。仮に選考を通らずとも、イベントへ応募したという事を誰かに語れるというのは良いなと思ったのもあります。

## ２：応募の流れ
　応募の手続きは以下の通りでした：

公式サイトでセキュリティキャンプの応募欄をクリック。
必要な情報を入力し、エントリー。
送られてきたメールのフォームに課題内容を記載して送信。

全体的に、エントリー自体は簡単に行えました。

## ３：ダメだった点
### ・応募が遅かった。
　私が応募したのは、締め切り直前になってしまったため、応募用の課題に割く時間が少なく、自分の満足のいくものを送れなかった点が最も大きい。
　友人は少し早めに応募していたこともあり、課題に着手するのが早かった...。

### ・何を書きたいのかわからなくなってしまった。
　私はこだわりが強く、内容についてあらかた理解していなくては書き始められませんでした。そして、文章量が増えていくにつれて、次第に何を伝いたいのかわからなくなってしまいました。内容をわかりやすくするために不要な部分をカットすることで、おおむねスッキリとさせることはできましたが、あまりいいものができたとは思えませんでした。
　何が伝えたいのかわからない「何か」が出来上がってしまったのです...。

## ：最後に
　次回の応募では、以下の点を改善したいと思います：

・余裕を持って早めに応募を始める。
・内容をシンプルにし、伝えたいことを明確にする。
・不要な部分をカットし、分かりやすい文章を心掛ける。

　この記事が、セキュリティキャンプへの応募を考えている方々の参考になり、モチベーションを高める一助になれば幸いです。
1994/04 ネットスケープ社の誕生から30年

（6月前半まで忙しかったので、3ヶ月おくれでお届けしています ^o^;;）

## Netscape社の起業から30年


1994年4月4日、当初はMosaic CommunicationsのちのNetscape Communications社が起業しました。早いもので、あれから30年です。もちろん、我々がネットスケープの名前を知るのはMosaicの後釜として1994年末のネットスケープ・ナビゲーター(Netscape Navigator)登場以降だったと思います(うろ覚え)。



## 抽象化レベルをあげた戦場を設定すれば天下が取れる


これは「抽象化レベルをあげた戦場を設定すれば天下が取れる」というブラウザの戦略に気づいた人が偉い。もっとも、ハードウエアの凸凹を埋めるためにOSが登場したのだから、次はOSの凸凹を埋めれば...というのは自然な発想ですけど、実際にそれを作るのは大変なので、やっぱりすごいよね。

戦略レベルでは正しいし、(戦術レベル=)短期決戦で決着がつけば良かったのですが、長期戦になると補給（資金力、会社の体力）で負けちゃいますね。じっさい負けたわけです。

当初、この作戦は、うまくいっていた印象ですが、OSベンダーがマヌケでないと長続きしません。「短期決戦で圧倒的シェアがとれなかった」というよりも、OSベンダーが(自社製)ブラウザをプレインストールしてきたら勝負にならない...人間心理として「あえてデフォルト値を変更したくない」ことを利用されているわけです。

これが第一次ブラウザ戦争。



## 「オープンソース」という用語を作ろう(1998/02)


3年もすると勝敗は明かになってきました。いまさら起死回生は無理だと思っていたと思うのですが、ネットスケープの最後のアガキは、やがてオープンソース運動へと進化していきました。

このへんの詳細は、めずらしく当事者の"ほぼ"リアルタイムの証言が読めるオライリーの「オープンソースソフトウェア」を参照してください。すでに日本語訳は絶版ですが、Web版は公開されつづけています。読みにくいけど;-)なんでPDF版を出してくれないんですかね;_;





## [番外編1] IIJとネットスケープが協業できていたら？


IIJ、今年(2024年春)の新入社員が307人というの見て、（いちおう弱小でも株主だから）「え？そんなにとって大丈夫なの？」と思った春なのでした。

でも、30年前は、つぶれる寸前でした。ようやく。本業を始めることが出来るようになったのが1994春なのです。

ところで、われらが鈴木社長(の回想録)いわく、この頃、ネットスケープから「提携しないか？」という話があったそうですが、まだ本業がヨチヨチあるきの今、そこまでの余裕は無いということで、残念ながら断ったのだそうです。

「15ヶ月ほど監督省庁にイヤガラセをされ」ていなければ、我々は、専用線と一緒にネットスケープも売ってあるいていたかもしれず、日本の商用インターネットの展開が違ったかもしれません(?)(とチョッピリ思いますが、たぶん変わらなかったろうなぁ;-)。



## [番外編2] Gmail誕生からも20年


2004年4月1日にはGmailがベータリリースされました。ネットスケープの10年後がGmailだったんですね、時の流れは速いです(遠い目)。



## 参考文献


- Chris DiBona, Sam Ockman and Mark Stone, "Open Sources: Voices from the Open Source Revolution", (Oreilly, 1999); 邦訳: クリス・ディボナ(著), サム・オックマン(著), マーク・ストーン(著), 倉骨彰(訳) "オープンソースソフトウェア - 彼らはいかにしてビジネススタンダードになったのか" (オライリー・ジャパン, 1999)
- 鈴木幸一, "日本インターネット書紀 この国のインターネットは、解体寸前のビルに間借りした小さな会社からはじまった" (講談社, 2015)


## 初出情報

- 2024/04/04 ドラフト版
- 2024/06/29 qiita版、オリジナルから若干けずっている
    - [色づかないWorld Wide Webの昨日から Ep.005"1994/04 ネットスケープ社の誕生から30年"](https://technotes.fml.org/tech/history/worlds-in-mono/005_netscape-founded/)

original site: https://technotes.fml.org/tech/history/worlds-in-mono/

(qiita版も致命的な間違いやTYPOは修正しますがupdatesはoriginalのほうだけです)

Copyright (C) 2024 Ken’ichi Fukamachi, CC BY-NC-SA 4.0
Groq: PostgreSQL の SQL を作成

こちらの質問に対する Groq の一次回答です。
[生成AI で PostgreSQL の SQL を作成](https://qiita.com/ekzemplaro/items/add5ddba24d955d63a66)

```sql
DO $$
DECLARE
    rec record;
    col_name text;
    has_col boolean;
BEGIN
    FOR rec IN SELECT * FROM information_schema.columns WHERE table_schema = 'your_schema_name' AND table_name = 'A'
    LOOP
        col_name := rec.column_name;
        has_col := FALSE;
        FOR other_rec IN SELECT * FROM information_schema.columns WHERE table_schema = 'your_schema_name' AND table_name = 'B'
        LOOP
            IF other_rec.column_name = col_name THEN
                has_col := TRUE;
                EXIT;
            END IF;
        END LOOP;
        IF NOT has_col THEN
            RAISE EXCEPTION 'Column % is not found in table B', col_name;
        END IF;
    END LOOP;
END $$;
```

## 考察

次の行があり、テストができません。

```text
AND table_name = 'A'
AND table_name = 'B'
```

Groq に問題の意図が伝わっていません。
与えるのは、スキーマ名と、テーブル名が各ひとつです。
DMXで操作するプロジェクターシャッターの自作

DMXで操作できるプロジェクターシャッターを自作する記事が見つけられなかったので、記事にしてみます。

## 今回使用した部品
ほぼ秋月電子、コネクターはサウンドハウスです。ベルト・滑り止めはホームセンターで入手しました。

- マイコンボード： Arduino Uno R3（互換機）
DMX Serialライブラリが対応しているArduinoを選べば大丈夫（なはず）です。
- DMXを受信するトランシーバー：LTC485
- サーボモーター：SG-90
- ケース：TW8-4-8B
※Arduino Unoだとかなりぎちぎちになります。もし作られる際はもう少し大きめのケースをおすすめします。
- XLRコネクター メス：NEUTRIK NC3FAV1-D
- XLRコネクター オス：NEUTRIK NC3MAV-0
- スイッチング電源：家にあった12V5Aのもの。7V～12Vの2A～あれば大丈夫です。
- 配線用ケーブル：耐熱電子ワイヤー 2m×7色 外径1.22mm(UL3265 AWG24)
- DCジャック：MJ-14
- サーボホーン取付用ねじ：M2プラスチックなべ小ねじ+六角ナットセット M2×5mm:1パック20組入
- 電解コンデンサー：47μF35V105℃ ルビコンPX
- ブラックラップ（シャッター用）
- 滑り止め
- プロジェクターに固定するベルト

## 回路図
![kairozu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/848771/c5ed3b02-c636-84a1-2aec-a90aa2806bc1.png)


## ライブラリ
ServoライブラリとDMXSerialを使用しました。

[DMXSerial - Arduino Reference](https://www.arduino.cc/reference/en/libraries/dmxserial/)

DMXSerialライブラリは以下のArduinoに対応しています。

- [Arduino Micro](https://store.arduino.cc/arduino-micro)
- [Arduino Leonardo](https://store.arduino.cc/arduino-leonardo-with-headers)
- [Arduino Mega](https://store.arduino.cc/arduino-mega-2560-rev3)
- [Arduino Nano](https://store.arduino.cc/arduino-nano)
- [Arduino Nano Every](https://store.arduino.cc/nano-every-pack)
- [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
- [Arduino Uno WiFi REV2](https://store.arduino.cc/arduino-uno-wifi-rev2)
- [Arduino Yún](https://store.arduino.cc/arduino-yun-rev-2)

## スケッチ
```
#include <DMXSerial.h>
#include <Servo.h>

Servo servo;//サーボモーターのインスタンス設定
int startCh = 1;//DMXアドレス設定

void setup(){
servo.attach(9);//サーボモーターの信号線を9番ピンに接続
DMXSerial.init(DMXReceiver);
}

void loop() {
unsigned long lastPacket = DMXSerial.noDataSince();

if (lastPacket < 5000) {
byte data = DMXSerial.read(startCh);

servo.write(data / 1.41);//dataの値に合わせてサーボ角0～180度に動かす

}
}
```

基本的なスケッチは以下のサイトを参考にしました。ありがとうございました。

https://hikoleaf.hatenablog.jp/entry/2019/05/26/124746

startChでDMXアドレスを指定します。

servo.writeは、data（DMX入力値）が0~255で来るので、1.41で割って大体角度を合わせてます。もっといい方法がありそうな気がします。

## 改善したいところ
- DIPスイッチでDMXアドレスを指定できるようにする
- シャッターをアルミ板にする
- 小さなボード（Arduino Nano Everyなど）を使用する
- もう少し静かなモーターを使用する
- 直径23㎜くらいの、キャノンコネクタを取り付けるのにちょうどいいホールソーを使用する

## 実際に作ってみて
コロナ禍で時間ができたときにarduinoを触ってみてはいたのですが、はじめて形にしてみて、いろいろ学びがありました。
Arduino選びを間違えたり、その結果ケースのサイズがギリギリになったり、ケースの加工が結構大変なこととか…
でも、DMXでいろいろなものを操作できる気がして夢が広がりました。

## 参考記事
[ArduinoでDMXを受信する - Re: note (hatenablog.jp)](https://hikoleaf.hatenablog.jp/entry/2019/05/26/124746)

Arduino UnoとLTC485を使ってLチカしてます。基本のスケッチ、LTC485のつなぎ方、DMXが受信できているか確認するのに大変参考になりました。

[プロジェクターシャッターの作り方 – masa's factory blog (masa-factory.jp)](https://www.masa-factory.jp/blog/?p=3253)

大まかなつくり、Servoライブラリの使い方等参考にしています。

[TouchDesignerからDMXを使ってLEDとモーターをArduinoで制御 – Kinetic Chochin｜WaV Media (wwwavvv.com)](https://wwwavvv.com/media/kinetic-chochin/)

キネティックライト、いつかつくってみたいです。細かいことですが、DMXのIN・OUT端子ってどう繋ぐんだ？となったので、助かりました。
Goのerrors.Isとerrors.Asの使いどころ

## errors.Is

エラーチェーンの中で、特定のエラーが存在するか確認する場合に使う。

以下の場合だと、queryDatabase関数内でErrDatabaseエラーが発生していて、それをmain関数内で存在しているか確認している。

もしqueryDatabase関数でエラーがない場合は、convertData関数内のErrConvertエラーの条件に該当する。

```go
package main

import (
	"errors"
	"fmt"
)

type queryResult struct{}

// 独自エラーを定義
var (
	ErrDatabase = errors.New("database error")
	ErrConvert  = errors.New("convert error")
)

func queryDatabase() (result *queryResult, err error) {
	// なにかしらの処理をしたと仮定
	return result, fmt.Errorf("query failed: %w", ErrDatabase)
}

func fetchData() (result *queryResult, err error) {
	res, err := queryDatabase()
	if err != nil {
		// エラーをラップして返す
		return &queryResult{}, fmt.Errorf("fetchData failed: %w", err)
	}
	return res, nil
}

func convertData(res *queryResult) (result *queryResult, err error) {
	// resを変換したと仮定
	result = res
	return result, fmt.Errorf("convertData failed: %w", ErrConvert)
}

func process() (result *queryResult, err error) {
	res, err := fetchData()
	if err != nil {
		// エラーをラップして返す
		return &queryResult{}, fmt.Errorf("process failed: %w", err)
	}
	res, err = convertData(res)
	if err != nil {
		// エラーをラップして返す
		return &queryResult{}, fmt.Errorf("process failed: %w", err)
	}
	return res, nil
}

func main() {
	res, err := process()
	if err != nil {
		if errors.Is(err, ErrDatabase) {
			fmt.Println("エラーが発生しました: ErrDatabase")
		} else if errors.Is(err, ErrConvert) {
			fmt.Println("エラーが発生しました: ErrConvert")
		} else {
			fmt.Println("エラーが発生しました: ", err)
		}
	}

	fmt.Println(res)
}
```

## errors.As

エラーチェーンの中に、特定の型のエラーが存在するか確認する場合に使う。

以下の場合だと、CustomError型のエラーがあり、process関数内で使用されている。

それをmain関数内で同じエラー型が存在するか確認している。

```go
package main

import (
	"errors"
	"fmt"
)

// 独自エラー型を定義
type CustomError struct {
	Code    int
	Message string
}

func (e *CustomError) Error() string {
	return fmt.Sprintf("Code: %d, Message: %s", e.Code, e.Message)
}

func process() error {
	// カスタムエラーを返す
	return fmt.Errorf("operation failed: %w", &CustomError{Code: 404, Message: "not found"})
}

func main() {
	err := process()
	if err != nil {
		var myErr *CustomError
		if errors.As(err, &myErr) {
			fmt.Printf("CustomError: %v\n", myErr.Error())
		} else {
			fmt.Println("Other error:", err)
		}
	}
}
```
実験記録: LangGraphのグラフはmlflow.langchainフレーバーで保管できるのか？

# 先に結論

MLflow 2.14.1時点ではできませんでした。

# 実験背景

LangGraphのグラフをMLflowで実験管理したい。でもFlavorは(まだ)出ていない。
あれ、でもLangGraphのグラフってRunnable系の何かを継承していなかったっけ？ということは既にできるんじゃないか？というのが実験背景です。

mlflowのバージョンは```2.14.1```、langgraphは```0.1.1```で確認しました。

# 調査①

LangGraphのコードを見るに、最終的にコンパイルされたグラフは```CompiledGraph```のインスタンスになります。```CompiledGraph```は```Pregel```というクラスを継承しています。

https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/graph/graph.py#L385

```python
class CompiledGraph(Pregel):
```

そして```Pregel```は```RunnableSerializable```を継承しています。
```RunnableSerializable```は```langchain_core.runnables```に含まれるクラスです。

https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/pregel/__init__.py#L207

```python
class Pregel(
    RunnableSerializable[Union[dict[str, Any], Any], Union[dict[str, Any], Any]]
):
```

MLflowのlangchainフレーバーが```RunnableSerializable```をChainとして記録するようになっていれば、モデルロギングできるのでは？

# 調査②

というわけで検証実験。
[こちら](https://qiita.com/isanakamishiro2/items/39fb6822f2c991eefc41)の記事のコードでLangGraphのグラフを作成し、以下のコードで保存。

```python
# 検証コード
with mlflow.start_run():
    logged_chain_info = mlflow.langchain.log_model(
        lc_model=graph,
        artifact_path="chain",
    )
```

実行した結果、以下のようなエラーとなりました。

```:出力
MlflowException: MLflow langchain flavor only supports subclasses of langchain.chains.base.Chain, langchain.agents.agent.AgentExecutor, langchain.schema.BaseRetriever, langchain.schema.runnable.RunnableSequence, langchain.schema.runnable.RunnableLambda, langchain.schema.runnable.RunnableParallel, langchain.schema.runnable.RunnablePassthrough, langchain.schema.runnable.passthrough.RunnableAssign instances, found CompiledStateGraph
```

残念ながら対応している```runnable```モジュールのクラスの中に、```RunnableSerializable```がなく、チェックで弾かれました。

# まとめ

というわけで、現時点ではダメでした。
そりゃそうだろ、という感じですがこういうのはやってみないとわからなかったりするので。。。

MLflowのコントリビュータの方々、LangGraphの対応よろしくお願いします！（お前がやれという声が聞こえる。。。)
Gemini: PostgreSQL の SQL を作成

こちらの質問に対する Gemini の一次回答です。
[生成AI で PostgreSQL の SQL を作成](https://qiita.com/ekzemplaro/items/add5ddba24d955d63a66)

```sql
-- テーブルAの名前
TABLE_A_NAME = 'your_table_name';

-- スキーマ名
SCHEMA_NAME = 'your_schema_name';

-- 1. スキーマ内のテーブルBをすべて検索し、テーブルAのすべての列を含むものを見つける
WITH potential_table_b AS (
  SELECT table_name
  FROM information_schema.tables
  WHERE table_schema = SCHEMA_NAME
    AND table_name != TABLE_A_NAME
)
SELECT *
FROM potential_table_b
WHERE (
    SELECT count(*)
    FROM information_schema.columns
    WHERE table_schema = SCHEMA_NAME
      AND table_name = potential_table_b.table_name
      AND column_name IN (
        SELECT column_name
        FROM information_schema.columns
        WHERE table_schema = SCHEMA_NAME
          AND table_name = TABLE_A_NAME
      )
) = (
    SELECT count(*)
    FROM information_schema.columns
    WHERE table_schema = SCHEMA_NAME
      AND table_name = potential_table_b.table_name
);

-- 2. 見つかった場合、テーブルBのNOT NULL列がすべてテーブルAに含まれているかどうかを判定する
IF (FOUND_ROWS() > 0) THEN
  -- テーブルBの名前を取得
  TABLE_B_NAME = (SELECT table_name FROM potential_table_b LIMIT 1);

  -- テーブルBのNOT NULL列をすべて取得
  NOT_NULL_COLUMNS_B = (
    SELECT column_name
    FROM information_schema.columns
    WHERE table_schema = SCHEMA_NAME
      AND table_name = TABLE_B_NAME
      AND is_nullable = 'NO'
  );

  -- テーブルAにNOT NULL列Bが存在するかを判定
  COLUMN_EXISTS = (
    SELECT count(*)
    FROM information_schema.columns
    WHERE table_schema = SCHEMA_NAME
      AND table_name = TABLE_A_NAME
      AND column_name IN (NOT_NULL_COLUMNS_B)
  ) = (
    SELECT count(*)
    FROM NOT_NULL_COLUMNS_B
  );

  -- 結果を返す
  SELECT CASE WHEN COLUMN_EXISTS THEN TRUE ELSE FALSE END AS result;
ELSE
  -- テーブルBが見つからない場合はFalseを返す
  SELECT FALSE AS result;
END IF;
```

## 実行結果

```text
ERROR:  syntax error at or near "TABLE_A_NAME"
行 1: TABLE_A_NAME = 'table_a';
      ^
ERROR:  syntax error at or near "SCHEMA_NAME"
行 1: SCHEMA_NAME = 'sch001';
      ^
ERROR:  column "schema_name" does not exist
行 4:   WHERE table_schema = SCHEMA_NAME
                             ^
ERROR:  syntax error at or near "IF"
行 1: IF (FOUND_ROWS() > 0) THEN
      ^
ERROR:  syntax error at or near "NOT_NULL_COLUMNS_B"
行 1: NOT_NULL_COLUMNS_B = (
      ^
ERROR:  syntax error at or near "COLUMN_EXISTS"
行 1: COLUMN_EXISTS = (
      ^
ERROR:  column "column_exists" does not exist
行 1: SELECT CASE WHEN COLUMN_EXISTS THEN TRUE ELSE FALSE END AS r...
                       ^
ERROR:  syntax error at or near "ELSE"
行 1: ELSE
      ^
ERROR:  syntax error at or near "IF"
行 1: END IF;
          ^
```
ChatGPT: PostgreSQL の SQL を作成

こちらの質問に対する ChatGPT の一次回答です。
[生成AI で PostgreSQL の SQL を作成](https://qiita.com/ekzemplaro/items/add5ddba24d955d63a66)

```sql
WITH A_columns AS (
    SELECT column_name
    FROM information_schema.columns
    WHERE table_schema = 'your_schema_name'  -- テーブルAのスキーマ名を指定する
    AND table_name = 'A'                      -- テーブルAの名前を指定する
),
B_tables AS (
    SELECT table_name
    FROM information_schema.tables
    WHERE table_schema = 'your_schema_name'    -- テーブルBのスキーマ名を指定する
    AND table_name != 'A'                      -- テーブルA以外のテーブルを検索する
    AND table_type = 'BASE TABLE'              -- 基本テーブルのみを対象とする場合
)
SELECT 
    CASE 
        WHEN EXISTS (
            SELECT 1
            FROM B_tables b
            LEFT JOIN A_columns a ON a.column_name = ALL (
                SELECT column_name
                FROM information_schema.columns
                WHERE table_schema = 'your_schema_name'  -- テーブルBのスキーマ名を指定する
                AND table_name = b.table_name
                AND is_nullable = 'NO'                 -- Not Null 制約のカラムのみを検索する
            )
            WHERE a.column_name IS NULL
        )
        THEN 'False'    -- テーブルBのNot NullのカラムがすべてテーブルAに含まれる場合
        ELSE 'True'     -- それ以外の場合、つまり一部のNot NullのカラムがテーブルAに含まれない場合
    END AS result
```

## 実行結果

```text
 result 
--------
 False
(1 row)
```

期待値は、True です。

## 改造

スキーマ名とテーブル名を変数にしました。

```sql:hantei_chatgpt.sql
\set TABLE_SRC 'table_a'
-- \set TABLE_SRC 'table_b'
-- \set TABLE_SRC 'table_c'
--
\set SCHEMA_SRC 'sch001'
--
WITH A_columns AS (
    SELECT column_name
    FROM information_schema.columns
    WHERE table_schema = :'SCHEMA_SRC'
    AND table_name = :'TABLE_SRC'
),
B_tables AS (
    SELECT table_name
    FROM information_schema.tables
    WHERE table_schema = :'SCHEMA_SRC'
    AND table_name != :'TABLE_SRC'
    AND table_type = 'BASE TABLE'              -- 基本テーブルのみを対象とする場合
)
SELECT 
    CASE 
        WHEN EXISTS (
            SELECT 1
            FROM B_tables b
            LEFT JOIN A_columns a ON a.column_name = ALL (
                SELECT column_name
                FROM information_schema.columns
                WHERE table_schema = :'SCHEMA_SRC'
                AND table_name = b.table_name
                AND is_nullable = 'NO'          -- Not Null 制約のカラムのみを検索する
            )
            WHERE a.column_name IS NULL
        )
        THEN 'False'    -- テーブルBのNot NullのカラムがすべてテーブルAに含まれる場合
        ELSE 'True'     -- それ以外の場合、つまり一部のNot NullのカラムがテーブルAに含まれない場合
    END AS result
```

期待通りの結果ではありません。
ミーティングを円滑に進行するコツ

# ミーティングの違いを識別する。その種類ごとにゴールが異なることを意識しよう。
種類ごとに目的、性質、やるべきことが異なる。
それらに応じて、会議に招集する人を選んだり、目的を意識して自分のアクションを最適化しましょう。
| 種類 | 目的 | 性質 | 必要なアクション |
|:-:|:-:|:-:|:-:|
| 連絡会議  | 情報共有、質疑応答  | 参加者全員が同じメッセージを受け取る。議論なし。 |×   |
| 進捗会議  | 進捗報告。対応策なども共有する。  |  × |報告に必要な分野と担当者を決定する。担当者に事前に依頼事項を渡し、担当者に準備をしてもらう  |
| チームミーティング  |完了タスク、これからのタスク、抱えている問題をチームに共有する | 頻度は週1~毎朝。個人からチームメイトに共有する。  |   ×|
| 問題解決ミーティング  | 問題の明確化、実行可能な打ち手の検討、打ち手の選択、計画の確認、リスク見極め  | 必要な限りの時間を費やす。  |的外れの議論を避けるために議題の準備をする。   |

# ミーティングの進め方
## 開始直後に雰囲気づくりをする。会議の目的を話す。
- 最初の2分で**会議の目的**を明確に話すのがよいです。これにより、参加者の会議に集中するモチベーションがアップします。
例：「二度と品質の失敗を起こさないチャンスです。会議終了までに今後の方針を決めましょう」
- トータルの議題の数と各議題の時間を話します。理由は後述するように、全体の中の進捗を参加者に意識してもらうためです。

## 話し合いの流れを良くする方法
- 全体の議題の内、**どこまでが終わったかと、残り時間/残りの議題**を繰り返し伝えましょう。
- 各議題を話し合う前に**主なポイント**を伝えましょう。というのも、これが論点の前提となるからです。例：これから、「オフショア開発を行う」という施策を行うかどうかについて議論します。メリットはA、デメリットはBです...。
- 論点への**回答の選択肢や課題に対するありうる施策**を示しましょう。それにより、議論が収束しやすくなります。
- **クローズドクエスチョンとオープンクエスチョン**を目的に応じて使い分けましょう。
    - 例えば、Xについてどう思いますか?というオープンクエスチョンは良くない場合があります。というのも、それだと既に分かっていることを好き勝手に言い出し、議論が収束しづらくなるからです。一方、議論を発散させたい場合はオープンクエスチョンが良いでしょう。
			
## 本筋から外れた話をすることを防ぐ方法	
### 予防策
MTGの開始時に、本筋から外れないことに合意を得る	

### 前提として、本筋から外れていることに気づきましょう
本筋から外れていると判定する基準：
- 関連しているが、問題が大きすぎる
- 全く議題と無関連のことへ脱線	
- 前例がないため検討に時間がかかる話題		
- 詳細に立ち入りすぎ		
- 既に話した議題を誰かが蒸し返す		
	
### シチュエーションごとのリカバリー方法
細かすぎる時：	
     一人か二人で**MTG以外の場で対応することを提案**しましょう。
「大切な話題ですね、ただここでは話す時間がないようです。AとBでチームを組み、他の場で対応してはいかがでしょうか？」

既出の議題を蒸し返す時：	
- **よくわからないふりをする**
「もう合意したのでしょうか、聞きそびれたでしょうか」
- **はっきり主張する**
「魅力的ですが、今の論点とは関係がない。どうでしょう？」「時間つまり人生を無駄にするからやめよう」とはっきりと主張する

脱線する時：	
- 保留を提案する。
「重要で検討の余地がある問題です。ただ、今は時間がないので保留してもいいですか。メモをとるので、会議の最後にnext actionを再確認します。」		
- ホワイトボードで、後で話すこととして書き残す		

## 参加者の洞察力を引き出すコツーSix Hats法
### Six Hats法とは？
- 下の画像をご参照ください。
- 帽子の色は意見の視点が対応しています。
- 参加者に、いずれかの帽子をかぶって物事を検討するように依頼します。特に、会議の様子を見て、欠けている視点を把握します。そして、**欠けている視点を補えるように参加者に帽子を割り当てましょう**。例えば、会議の参加者が楽観的になりすぎている場合は、黒の帽子をかぶってもらう。議論にまとまりがない場合、白か青の帽子を誰かにかぶってもらう。議論に創造性が欠けている場合は、緑の帽子をかぶってもらう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/c5bf104b-e291-64e2-f192-2eeefe444f7b.png)

Six Hats法の参考
https://atlassian-teambook.jp/_ct/17666829#c17666829_h4_s2	
		
## 発言しない人がいたら
発言してもらいましょう。その人が持つアイデアや情報をチームが使えるようにすることが大切です。		
### 方法
- 指名する			
- 参加者が多い場合、ペアを作る。お互いの意見にフィードバックをする。その後、意見を発表してもらう

## 口頭だけでなく視覚的な情報も共有する
- 効果は、視覚化する人が、会議内の話題をコントロールできることです。というのも、視覚化する情報を選べるからです。選んだ情報が話題の中心になります。
- さらに、理解が深まります。例えば、計画は口頭よりもガントチャートで示す方が理解されやすいでしょう。			
- 加えて、記憶に残りやすくなります。例えば、計画などは概略図の方が覚えやすいかもしれません。			
- さいごに、口頭だけの場合よりも集中力が上がる傾向があります。
		
- 方法
    - オンラインのホワイトボード			
    - スライド資料			

# 参考資料
Linkedin Learning 生産的なミーティングをするコツ
https://www.linkedin.com/learning/managing-meetings-2
Elixirコーディング環境構築

# はじめに
Qiitaの以下の記事を見てElixirという言語を知り、気になったのでAzure VM上でElixirのコーディング環境を整えてみました。最後に簡単なプログラムも書いてみます。

https://qiita.com/MaxBaconPower/items/74c327322b67a5b3362b

https://sanposhiho.com/posts/2020-03-30-qiita-a66538451c145af73d5a/

# Elixirとは
- 拡張しやすくメンテナンスしやすい関数型言語
- パイプライン、パターンマッチングなどの強力な記法！
- 強い動的型付け言語
- Erlang VM上で動作する
- 2012年にRuby on RailsのチームメンバーであるJosé Valimによって開発された

# Elixirのコーディング環境を整える

## Dockerのインストール（Ubuntu 18.04）
Dockerってほんと便利だよね！
Elixir公式のdockerイメージ

https://hub.docker.com/_/elixir

[私の記事](https://qiita.com/maplejava/items/7429dfe7c8f33fa7f8eb#docker%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%ABubuntu-1804)を参照してDockerをインストールする。

## Elixirイメージの実行
Dockerがインストールされたあなたは、以下のコマンドを打つだけ！
```
docker run -it --rm elixir
```
iexという対話シェルが起動します。

# Elixirの文法

```elixir
iex(1)> 2+3

5

iex(2)> 2+3==5

true

iex(3)> 0x1f

31
```
上記のようにpythonのjupyter Notebookのような使い心地。
- やめたいときはCtrl+Cを2回押す
- Enterを押していくと数行にわたって入力できる

早速FizzBuzzでも書いてみよう！
```elixir:FizzBuzz.exs
#! /usr/bin/env elixir

defmodule FizzBuzz do
  def run(limit) do
    print(1, limit)
  end

  defp print(n, limit) when n == limit do
    cond do
      rem(n, 15) == 0 -> IO.puts "#{n}: FizzBuzz"
      rem(n, 5)  == 0 -> IO.puts "#{n}: Fizz"
      rem(n, 3)  == 0 -> IO.puts "#{n}: Buzz"
      true            -> nil
    end

  end

  defp print(n, limit) do
    print(n, n)
    print(n + 1, limit)
  end

end

input = 10

FizzBuzz.run(input);

# elixir ./fizzbazz.exs で実行
# ----
# 3: Buzz
# 5: Fizz
# 6: Buzz
# 9: Buzz
# 10: Fizz
```
ちなみに、[この記事](https://qiita.com/maplejava/items/d612f7ddea11f3d2cc10)で紹介したLispでFizzBuzzを書くと以下のような感じ。


```lisp:FizzBuzz.lisp
(defun fizzbuzz (x)
  (cond
   ((zerop (mod x 15)) "Fizzbuzz")
   ((zerop (mod x 3))  "Fizz")
   ((zerop (mod x 5))  "Buzz")
   (t x)))

(defun fizzbuzz-solver (s e)
  (unless (> s e)
    (print (fizzbuzz s))
    (fizzbuzz-solver (1+ s) e)))

(fizzbuzz-solver 1 100)
```
どちらの言語も色があっていいね！

### fileにコードを書いて実行する

fileに記載しなくてもiexモードでもdoやendを賢く認識してくれるので、複数行にわたるコーディングは可能。空白もいらない。

iexモードではタブ補完もいい感じにきく。

```elixir
elixir sample.exs
```

https://dev.to/gumi/elixir-01--2585

### コンソール出力

```elixir
IO.puts "Hello World!"
```

### 繰り返し
forやwhileはない！再帰で書くのみ！

# もっと学びたい方は
Elixir School
https://elixirschool.com/ja
C_TS422_2021 SAP Certified Application Associate SAP S/4HANA Production Planning and Manufacturing対策（21/100）

【21日目】
トピック 3：SAPS/4HANAのマスタデータ（10/22）

≪問題21≫
部品表/配合表（BOM）またはレシピでマイナス数値になるのは、以下のどの品目ですか。（３つ選択）
□廃棄物
□バルク品目
□副産物
□連産品
□継続的なフロー品目

≪解答≫
■廃棄物
□バルク品目
■副産物
■連産品
□継続的なフロー品目

≪解説≫
◆主にプロセス産業において、1つの主製品の製造時に、複数の他の製品が同時に生産される場合があります。これらの製品は、連産品、副産物、廃棄物として分類されます。
◆連産品、副産物、廃棄物は、マスタレシピのBOMにおいてマイナス数量の構成品目として設定されています。
wrtn: PostgreSQL の SQL を作成

こちらの質問に対する wrtn の一次回答です。
[生成AI で PostgreSQL の SQL を作成](https://qiita.com/ekzemplaro/items/add5ddba24d955d63a66)

```sql
SELECT table_name, table_schema
FROM information_schema.columns
WHERE table_name = (
  SELECT table_name
  FROM (
    SELECT table_name, table_schema
    FROM information_schema.columns
    WHERE column_name IN (
      SELECT column_name
      FROM information_schema.columns
      WHERE table_name = 'テーブルA'
        AND table_schema = 'public'
    )
    GROUP BY table_name, table_schema
    HAVING COUNT(DISTINCT column_name) >= (
      SELECT COUNT(DISTINCT column_name)
      FROM information_schema.columns
      WHERE table_name = 'テーブルA'
        AND table_schema = 'public'
    )
  ) AS subquery
)
  AND is_nullable = 'NO'
  AND column_name NOT IN (
    SELECT column_name
    FROM information_schema.columns
    WHERE table_name = 'テーブルA'
      AND table_schema = 'public'
  );
```

## 実行結果

```text
ERROR:  more than one row returned by a subquery used as an expression
```

## 改造

```sql:hantei.sql
\set TABLE_SRC 'table_a'
\set SCHEMA_SRC 'sch001'
SELECT table_name, table_schema
FROM information_schema.columns
WHERE table_name = (
  SELECT table_name
  FROM (
    SELECT table_name, table_schema
    FROM information_schema.columns
    WHERE column_name IN (
      SELECT column_name
      FROM information_schema.columns
      WHERE table_name = :'TABLE_SRC'
        AND table_schema = :'SCHEMA_SRC'
    ) AND table_schema = :'SCHEMA_SRC' and table_name != :'TABLE_SRC'
    GROUP BY table_name, table_schema
    HAVING COUNT(DISTINCT column_name) >= (
      SELECT COUNT(DISTINCT column_name)
      FROM information_schema.columns
      WHERE table_name = :'TABLE_SRC'
        AND table_schema = :'SCHEMA_SRC'
    )
  ) AS subquery
)
  AND is_nullable = 'NO'
  AND column_name NOT IN (
    SELECT column_name
    FROM information_schema.columns
    WHERE table_name = :'TABLE_SRC'
      AND table_schema = :'SCHEMA_SRC'
  );
```

ERROR は消えますが、まだ期待通りの結果ではありません。
背景にぼかし(Blur)をかける

# やること
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566351/c3b2fae2-40e3-e59f-5729-131d31067131.png)

こんな感じで背景画像にぼかしをかけてエモい感じにしたい

# やり方

### RenderEffect.createBlurEffectを使用する

### 実装例

・activity_main.xml

```xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
<!--背景にする画像を貼り付けるImageView-->
    <ImageView
        android:id="@+id/back_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:scrollX="80dp"
        android:src="@drawable/back" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView"
        android:name="jp.com.mycomp_module_a.StartFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>
```

・MainActivity.kt

```kotlin
class MainActivity : AppCompatActivity() {
private lateinit var b: ActivityMainBinding
    @RequiresApi(Build.VERSION_CODES.S)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.apply {
            statusBarColor = Color.TRANSPARENT
            setDecorFitsSystemWindows(false)
        }
        b = ActivityMainBinding.inflate(layoutInflater)
        setContentView(b.root)
        b.apply {
            //ImageViewにぼかし(Blur)を設定        
            backImage.setRenderEffect(RenderEffect.createBlurEffect(30f,30f,Shader.TileMode.MIRROR))
        }
    }
}
```

:::note warn
注意
RenderEffectを使用するには、APIレベル31以上が必要
:::

・直接root要素のレイアウトにエフェクトをかけると、そのレイアウトに所属する全てのViewにぼかしがかるので、背景画像用のImageViewだけに適用する

# まとめ

・背景画像にぼかしをかけるには`RenderEffect.createBlurEffect`を使用する
・全体にぼかしがかからないよう、背景画像用のImageViewを用意する

・RenderEffectを使うと他にも色々できそう
C_TS4FI_2021 SAP Certified Associate - SAP S/4HANA 2021 for Financial Accounting対策（8/100）

【8日目】
トピック 1：組織割当およびプロセス統合（8/15）

≪問題8≫
会社が事業を行っている国で、新しい消費税率15%が定義され、この税率が翌会計年度の年初から適用されます。
この条件を満たすため、新規消費税O5およびI5を登録します。翌年度以降に税関連の伝票を入力する際、ユーザに新規税コードを使用してもらうにはどうすればよいですか。
□残高繰越の実行後、関連する費用および収益G/L勘定の税カテゴリ項目に、適切な新規消費税コードを入力する。
□残高繰越の実行後、総勘定元帳を転記する権限を持つユーザに対し、新規税コードをデフォルトとして入力する。
□ユーザが新年度の転記日付で伝票を入力する際に、非推奨になった消費税コードを使用するとエラーが発行されるチェックを登録する。
□新年度の転記日付で伝票を入力する際に、非推奨になった消費税コードを関連する新規消費税コードに変更する代入を登録する。

≪解答≫
□残高繰越の実行後、関連する費用および収益G/L勘定の税カテゴリ項目に、適切な新規消費税コードを入力する。
□残高繰越の実行後、総勘定元帳を転記する権限を持つユーザに対し、新規税コードをデフォルトとして入力する。
□ユーザが新年度の転記日付で伝票を入力する際に、非推奨になった消費税コードを使用するとエラーが発行されるチェックを登録する。
■新年度の転記日付で伝票を入力する際に、非推奨になった消費税コードを関連する新規消費税コードに変更する代入を登録する。

≪解説≫
◆各選択肢に対する正誤判定は以下の通りです。
（1）選択肢1 → ×
残高繰越の実行後に前年度の転記日付で伝票を入力することも考えられますが、G/L勘定の税カテゴリ項目に新しい税コードを入力すると、伝票入力時に税コードを変更できなくなります。したがって、この方法は不正解です。
（2）選択肢2 → ×
ユーザに対する税コードのデフォルト入力が技術的に可能であっても、すべてのケースで新しい税コードを適用すべきではないため、この方法は不正解です。
（3）選択肢3 → ×
不適切な税コードの入力を防止することはできますが、正しい税コードが入力される保証はありません。したがって、この方法は不正解です。
（4）選択肢4 → 〇
新しい税コードを入力すべき場面で、その税コードが必ず入力されるようになるため、この方法が正解です。
Command-R+: PostgreSQL の SQL を作成

こちらの質問に対する Command-R+ の一次回答です。
[生成AI で PostgreSQL の SQL を作成](https://qiita.com/ekzemplaro/items/add5ddba24d955d63a66)

```sql
SELECT
    b.table_name AS table_b_name,
    a.column_name IS NOT DISTINCT FROM b.column_name AS column_match,
    a.is_nullable = FALSE AND b.is_nullable = TRUE AS not_null_mismatch
FROM information_schema.columns a
JOIN information_schema.columns b ON a.column_name = b.column_name
    AND a.table_name = 'table_a'
    AND b.table_name <> 'table_a'
    AND b.table_schema = 'your_schema_name'
WHERE a.table_schema = 'your_schema_name'
AND a.column_name = b.column_name
AND a.is_nullable = FALSE
AND (b.is_nullable = TRUE OR b.column_default IS NOT NULL)
GROUP BY b.table_name, a.column_name, a.is_nullable, b.is_nullable, b.column_default;
```

## 実行結果

```text
ERROR:  operator does not exist: information_schema.yes_or_no = boolean
行 4:     a.is_nullable = FALSE AND b.is_nullable = TRUE AS not_nu...
                        ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
```
初めて自力でエラー解決できた日

[前回の問題解決しました。](https://qiita.com/suzukidog/items/02f22db1eed87c34fcc7#%E8%A7%A3%E6%B1%BA20240629)

***
今日は初めて、エラーを見て「あれだ！」と原因を特定できた。
相変わらず勉強よりも関係ないことをしているが、ちょーっとずつ進んではいる。
頭に入っているかと聞かれたら素直に頷けないが、それでもちょーっとずつは入っている。はず。

この教材が終わったら自分のサイトを作るのに専念してみようかと思う。

自分のサイトを作るのは楽しいので経験や知識も早く身につくかもしれない！
Eclipse Console: "[32m" "[1m" 等を除外

# 実現したいこと
Eclipse Console の出力をコピペすると現れる、"[32m" "[1m" 等のテキストを除外

# 前提
以下の段落の内容は [Perplexity](https://www.perplexity.ai/) の出力を検証したうえで引用しています

# 謎のテキストの正体 : ANSIエスケープコード
- **[32m**: テキストの色を緑に設定
- **[1m**: テキストを太字に設定
- **[36m**: テキストの色をシアンに設定
- **[1;31m**: テキストを太字の赤に設定
- **[m**: すべてのスタイルをリセット

# 解決方法
1. Eclipseのメニューから「Window」 > 「Preferences」を選択
1. 「Run/Debug」 > 「Console」 > 「ANSI Support」に移動
「Put RTF in Clipboard」オプションをオフ

# 環境
Eclipse IDE for Enterprise Java and Web Developers (includes Incubating components) Version: 2023-12 (4.30.0)

# 参考
https://help.eclipse.org/latest/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Freference%2Fpreferences%2Frun-debug%2Fref-console_ansi.htm
Goのエラーチェーンでエラーが起こった流れを把握する

Goにはスタックトレース機構がないので、どういう流れで処理が行われたのかが把握できない。

そのため、一番初めの呼び出し元にエラーをラップして戻す方法で、エラーの流れを把握する。

```go
package main

import (
	"errors"
	"fmt"
)

type queryResult struct{}

func queryDatabase() (result *queryResult, err error) {
	// なにかしらの処理をしたと仮定
    // 一番最初のエラー
	return result, errors.New("database is down")
}

func fetchData() (result *queryResult, err error) {
	res, err := queryDatabase()
	if err != nil {
        // エラーをラップして返す
		return &queryResult{}, fmt.Errorf("fetchData failed: %w", err)
	}
	return res, nil
}

func process() (result *queryResult, err error) {
	res, err := fetchData()
	if err != nil {
        // エラーをラップして返す
		return &queryResult{}, fmt.Errorf("process failed: %w", err)
	}
	return res, nil
}

func main() {
    // 今までの処理のエラーがまとめて返ってくる
	res, err := process()
	if err != nil {
		fmt.Println(err)
		// 出力: process failed: fetchData failed: database is down
	}

	fmt.Println(res)
}
```

このようにすると、どういう流れで処理が行われ、どのようなエラーが起こったか把握できる。
シェルスクリプトでメニュ画面のフレーム

## シェルスクリプトでメニュー画面


### シェルスクリプトでメニュ画面を作っていました。

こういうメニューがあればだれでもできるから
あったほうがいいですね。

```

[root@docker163 ~]# cat menu.sh
top()
{
clear
echo "TOPです"

echo "番号を入力してください 1-4"


}

top2()
{

echo "1)"
echo "2)"
echo "3)"
echo "4)"
while true
do

read ANSWER
echo $ANSWER
case $ANSWER in
1) return 1 ;;
2) return 2 ;;
3) return 3 ;;
4) return 4 ;;
*)          ;;
 esac

echo "指定した番号を選んでください"

done
}

##Main


while true
do

top
top2
RETRUN_TOP=$?
#echo "あなたの選んだ番号は　${RETRUN_TOP}"


#sleep 10

if [[ ${RETRUN_TOP} = 1 ]] ; then

        echo "1111111111111"
        break

elif [[ ${RETRUN_TOP} = 2 ]] ; then

        echo "2222222222222"
        break

elif [[ ${RETRUN_TOP} = 3 ]] ; then

        echo "3333333333333"
        break

elif [[ ${RETRUN_TOP} = 4 ]] ; then

        echo "44444444444444"
        break

else

        echo "xxxxxxxxxxxxx"

fi


#top3


done
[root@docker163 ~]#
[root@docker163 ~]#

```