OmniAICreator/Qiita-1.07M huggingface dataset:
RubySilverに合格できたお話

## はじめに
初めまして、@jinta_02と申します。
未経験からエンジニアに転職して、早3ヶ月が経ちましたが、業務をする上で、「これ何してんだ？、どんな書き方？」と思おうことが多々あったので、RubySilverを受験してきました。
これから受験される方の参考になればと思ったので、受験記録を残します😀

## スキルレベル
- エンジニア歴3ヶ月（未経験からWebエンジニア）
- 転職前に、10ヶ月ほどプログラミングスクール受講（主に、Ruby, Railsを学習）
- 以下のポートフォリオを作成できるレベル
[個人開発】服好き・カフェ好きのためのショップ検索サービス「服カフェ」をリリースしました](https://qiita.com/jinta_02/items/329abd44056277a17d739)

## 受験のきっかけ
エンジニアに転職して実際にサービス開発に携わる中で、チームメンバーが書いているコードを理解できない部分があったので、もう少しRubyの文法だったりライブラリについて学ぶ必要があると感じたからです。また、学習するなら何か形に残るものにしたかったのと、RubySilverを取得することで、Rubyエンジニアとして最低限のレベルはあると証明できるかなと思ったからです。

## 学習時間・教材
学習期間 ： 6/2〜7/5（約1ヶ月）
学習時間 ： 30時間ほど

学習教材 ：
私は、基本的にREXで問題を解いて、間違えたところをRubyのリファレンスを読んだり、実際にirbやRubyファイルにスクリプトを書いて実行することで挙動を確認していました。
ただ、試験前日になって、以下の記事を見つけてしまったことで、「REXだけじゃ対策不足？」となって焦ったので、対策本も買いました😓
結果的に対策本の問題集を解いたことで、REXだけでは理解できていなかったところも理解できたので対策本は買うのをオススメします。意外とお高めなので、古本やメルカリで購入するのもいいかなと思います。
[模擬試験ガチで1問も解けなかった私がRuby Silverに合格したお話](https://miyamizu.hatenadiary.jp/entry/ruby_silver)

1. [REX](https://rex.libertyfish.co.jp/)
REXは合計で12回解いて、最初は36点でしたが、最終的に90点代を取れるようになりました。
毎回2割の問題が変わるとはいえ、結構同じ問題が出てくるので、答えを覚えてしまいがちですが、しっかりと挙動を理解した上で、回答することが大切かなと思います。

2. [最短突破 Ruby技術者認定試験（Silver/Gold対応） 公式テキスト](https://www.amazon.co.jp/%E6%9C%80%E7%9F%AD%E7%AA%81%E7%A0%B4-Ruby%E6%8A%80%E8%A1%93%E8%80%85%E8%AA%8D%E5%AE%9A%E8%A9%A6%E9%A8%93%EF%BC%88Silver-Gold%E5%AF%BE%E5%BF%9C%EF%BC%89-%E5%85%AC%E5%BC%8F%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-%E4%BF%8A%E7%94%B7/dp/4297142163/ref=pd_lpo_sccl_1/357-8789650-9094204?pd_rd_w=RtwwL&content-id=amzn1.sym.855d8f70-df76-4181-80b0-56e48ae3bb9b&pf_rd_p=855d8f70-df76-4181-80b0-56e48ae3bb9b&pf_rd_r=ANGQZNTYWV0Z71DYZ5M1&pd_rd_wg=xXhYc&pd_rd_r=afcd6e35-7807-41d8-b830-39218aedf020&pd_rd_i=4297142163&psc=1)
対策本は、前日に購入したので、Rubyの基礎問題30問とRubySilver対策50問だけを解きました。
試験当日の問題は、7割くらいは対策本と同じような問題が出題されていたような気がしました。
REXだけで受からないこともないかとは思いますが、対策本は買った方が無難。。。

## 学習記録 
学習したことは、Zennのスクラップにまとめたので、気になる方は見ていただければです。
[Zenn Ruby Silver 受験記録](https://zenn.dev/jin_shimo/scraps/1bdc51c3a3071e)

## 受験結果
受験日 ： 7/6
点数 ： 76点（合格点75点）

結果は、かなりギリギリでしたが、なんとか合格できました😅

## 最後に
Rubyの資格試験とはいえ、選択式なので、受験勉強のような作業感があって苦痛に感じることもありましたが、問題を解いて分からないところはリファレンスを見て挙動を確認する癖が付きましたし、
何よりRubyについて以前より詳しくなれたので、受験して良かったなと思います。
書籍やUdemyでなんとなく学習するより、「RubySilver合格」という目的意識を持って学習をすることで、理解度も格段に上がると思うので、気になっている方は受験することをオススメします！

学習方法については、たくさんの方が記事を書いてらっしゃるので、検索して自分に合う学習方法を見つけるといいかなと思います。

RubySilver受験のための学習をすることで、Rubyについて少し詳しくなれるよというお話でした！

最後まで見ていただきありがとうございました😀
[CDK For Terraform]null providerを利用する

# CDK For Terraform null providerを利用したい

利用したい経緯としてはLambdaでLayersのビルドを行う際に
CDK For Terraform（以降CDKTF）での実装を行いたいためです。

https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource?lang=typescript
を参照しながら行ったのですが、
試行錯誤が結構必要になったので自身の備忘録的に残しておこうと思います。



## 元々の運用

言語としてはpython


```sh
echo 'psycopg2-binary' > requirements.txt
```

- LambdaのVerisonが3.9なので3.9にする。

```sh
docker run -v "$PWD":/var/task "public.ecr.aws/sam/build-python3.9" /bin/sh -c "pip install -r requirements.txt -t python/lib/python3.9/site-packages/; exit"
```

とローカルで予めBiildしCDKTFでzip化しアップロードするようにしていました。

最終的なLambdaでの実装方法は別途紹介したいと思います。

## null providerを利用する

以下のように`NullProvider`を追記します。

```typscript
import { Construct } from "constructs";
import { App, TerraformStack } from "cdktf";
import { S3Backend } from 'cdktf';
import { AwsProvider } from "@cdktf/provider-aws/lib/provider";
import * as fs from 'fs';
import * as path from 'path';
import { NullProvider } from '@cdktf/provider-null/lib/provider';

```

- サンプルコード

AwsProvider同様にNullProviderを追記します。

```typescript
class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    // Define AWS provider
    new AwsProvider(this, 'aws', {
      region: 'ap-northeast-1', // Example: 'us-west-2'
      defaultTags: [{
        tags: {
          environment: id,
          IaC: 'cdktf',
        }
      }]
    });

    // Nullプロバイダーのインスタンスを追加
    new NullProvider(this, 'null', {});



  }
}

const app = new App();
new MyStack(app, `${process.env.ENV_ID}`);
app.synth();

```

## null_resourceの実装

変数は利用しておらず、ハードコード祭りになってますが、  
requirements.txtのファイルが変更された場合のみ  
layerをBuildするようにしています。

```typescript
import { Construct } from 'constructs';

import * as nul from "@cdktf/provider-null";

export function lambdaSqlExec(scope: Construct,
) {

	// null_resourceを使用してDockerビルドとzip作成を実行

	new nul.resource.Resource(scope, `LambdaLayerBuild-${id}`, {
		triggers: {
			on_change: `\${filesha1("./lambda/layers/psycopg2/requirements.txt")}`, // 特定のファイルが変更された場合にのみ実行されます

		},
		provisioners: [
			{
				type: 'local-exec',
				command: `
				docker run -v ./lambda/layers:/var/task "public.ecr.aws/sam/build-python3.12" /bin/sh -c "pip install -r psycopg2/requirements.txt -t lib/python ; exit"`,
			},
		],
	});

}
```


## CDKで実装する場合

こんな感じの実装でいいみたいです。今回はCDKTFで実装する場合にはどうするのがいいのかを
確認してみたかったためnull providerを利用する方式にしましたが、
L2コンストラクトは便利だなと思いました。

```typescript
    const psycopg2Layer = new pyLambda.PythonLayerVersion(this, 'Psycopg2Layer', {
      layerVersionName: `sample-psycopg2`,
      entry: './lambda/layers/psycopg2',
      compatibleRuntimes: [lambda.Runtime.PYTHON_3_12],
    });
```

## まとめ

terraformでの`null_resource`を利用する記事はよくみかけるのですが
CDKTFで実行する方法はあまり見当たらなかったので紹介してみました。
教師は重要なことを説明する前にプリントを配らない - ユーザーに情報を届けるタイミング再考

[これからの情報伝達手段の在り方について考えてみよう！](https://qiita.com/official-events/a1b1a6dd87105eb2bb92)参加記事になります。

## 教師は説明する前にプリントを配らない？

学校教員をやっている友人から聞いた話で印象に残るものがありました。
クラスでプリントを配っている最中や、配った直後に説明した話を、生徒はまるで聞いていないと。
先にプリントを配ってしまうと、生徒の意識はそのプリントに向いてしまうため、前で先生がしゃべっていることが耳に入らない。
そのため、聞かせたいことは必ず先に説明し、配布物はその後に配るのだということでした。

己を顧みると、たとえばビデオ会議での企画プレゼン・資料のレビューであっても、導入の前にいきなり資料を画面共有してしまうと、参加者の意識はすでに画面の資料に移っており、そこからこの場で決めたいことは云々と導入の話を始めても受け取ってもらえない、というのはあるあるです。

これらは、ユーザーにいかに必要な情報へフォーカスさせるかという話にも通じるものがあるなと思います。

## 必要になるまで見せないということ

テレビゲームでも、最初は限られたことしかできない状態でスタートし、ゲームが進むにつれて新たな機能がアンロックされるという作りはよくあります。

レベルアップの報酬を段階的に得られるというメリットだけでなく、プレイヤーが最初に何をすればいいか明確にわかるというのも重要なポイントです。

同じように、たとえばWebサービスをリリースし、新規ユーザーに使ってもらう場合でも、最初から多機能なツールが用意されていると便利かと思いきや、何をすればいいかわからないUIではそもそも使ってもらう前に離脱を招きます。

まずは基本的な使い方にフォーカスさせ、「○○ができたらいいのにな」と思わせたタイミングで、初めてそのための機能を見つけられるようになっているのが理想的です。

従来、たとえば基本設定の数を極力減らし、意図的に開かないと見えない詳細設定に発展的な機能を閉じ込める、といったアプローチがとられてきました。

![gmailのクイック設定と詳細設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2903443/6b819c79-e941-c1d7-3075-36879d71938d.png)

これからのより高度なアプローチとして、ユーザーの使い方をもとにAIが設定のカスタマイズを提案してくれるとか、ゲームのように自動で必要な機能を段階的にアンロックしていくような仕組みがあっても面白いと思います。

## ユーザーからのコンタクトの入り口を明確にする

ユーザーから企業にコンタクトを取りたいと思った場合にも、電話・メール・問い合わせフォーム・SNSなど、複数の手段が用意されていると、かえってどれを使うのが適切かわからず、問い合わせへの心理的ハードルが上がってしまう可能性があります。

最近の企業サイトなどでよく見かけるように、画面右下にbotや担当者とのチャットをすぐに開始できるアイコンがあったりすると、まずそこに送ってみようという気になるので、問い合わせ開始までのハードルは低くなると思います。
（従来は使い物にならないチャットbotが多かったので、かえって離脱を招いていた気もしますが…）

複数のコンタクト手段があること自体は、コンタクトしたくてもできないユーザーを取りこぼすことの防止にはなりますが、かえってコンタクトの導線をわかりづらくしてしまっていないかというのを気にしておく価値はあります。

## 以上

よかれと思って最初から情報を増やすことが、必ずしもユーザーにとってプラスにはならないという例をいくつか紹介しました。

ソフトウェア開発の文脈でいえば「KISS原則」や「YAGNI」にも通じるものがありますね。
LLMからより良い応答を得る方法


## Prompt Engineering手法の解説
プロンプトエンジニアリングとは、AIに対し特定の出力を促すための質問や指示を設計することです。しかし、複雑な作業に対する効果は限定的で、試行錯誤に時間がかかります。

============================================================
### 公式手法

1.明確な指示を書く
- 詳細を含める
- ペルソナを割り当てる
- 入力文の異なるパーツの間を明確に分ける
- タスクの完了に必要な手順を指定する
- 例を提示する
- 求める回答の長さを指定する
- 参考テキストの提供する

2.参考テキストを提供する
- リファレンステキストを使って回答するように指示する
- リファレンステキストからの引用を添えて解凍するように指示する

3.複雑なタスクをシンプルなサブタスクに分割する
- インテント分類を使ってユーザのクエリに関連性の高い指示を特定する
- 非常に長い会話を必要とする対話アプリケーションでは以前の対話を要約またはフィルタリングする
- 長い文書は断片的に要約してから再帰的に全体の要約を構築する

4.モデルに考える時間を与える
- 結論に飛びつく前モデル自身が解決策を見つけるように指示する
- インナーモノローグや一連のクエリを使ってモデルの推論プロセスを隠す
- 前のパスで何か見落としがなかったかモデルに尋ねる

5.外部のツールを使う
- embeddings ベースの検索を使って効率的な knowledge retrievel を行う
- code execution を使ってより精確な計算や外部 API 呼び出しをする
- モデルに特定の function へのアクセスを与える

6.システマティックに変更をテストする
- ゴールドスタンダードの答えを参考にモデルの出力を評価する


### 非公式手法(論文、参考文献など)
- Chain-of-Thought(COT)：複数ステップのタスクを処理   
- Zero-shot Learning：サンプルなしでの学習 
- Few-shot Learning：少数のサンプルでの学習 
- Many-shot Learning：多数のサンプルでの学習  
- COT ＋ Few-shot ： COTとFew-shot Learningを組み合わせ 
- Self-Taught Reasoner(STaR)：モデル自身が生成した推論から学習することで、モデル自身を向上させることができる

============================================================
## Fine-tuning手法の解説
ファインチューニングとは、事前学習を基にさらなる訓練し、特定のタスクのパフォーマンスを最適化します。しかし、大量のデータとコンピューティング・リソースが必要です。

============================================================

## Retrieval-Augmented Generation(RAG)手法の解説
検索拡張生成とは、外部データベースから関連情報を取得（Retrieval）し、質問やプロンプトに対する回答を生成（Generation）する手法です。しかし、外部の知識ベースに依存するため、スピードと効率性に問題を生じる可能性がある。
【Go】 環境構築手順　（mac）

## Goのインストール
最新バージョンの記載は[GoのWebサイト](https://go.dev/dl/) に記載があります。
```
$ brew install go
```
以下のようにバージョンが正しく表示されれば成功です。
```
$ go version
go version go1.22.5 darwin/amd64
```
## パスを通す
```
$ vim ~/.bash_profile
```
下記を追記
```:.bash_profile
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
export PATH=$PATH:/usr/local/go/bin
```
.bash_profileを反映
```
$ source ~/.bash_profile
```
docker-compose up時のKeyError: 'ContainerConfig'

dockerのバージョンアップ後、`docker-compose up -d --build`などでコンテナを再起動しようとした際に以下のようなエラーが発生
```
Traceback (most recent call last):
  File "docker-compose", line 3, in <module>
  File "compose/cli/main.py", line 81, in main
  File "compose/cli/main.py", line 203, in perform_command
  File "compose/metrics/decorator.py", line 18, in wrapper
  File "compose/cli/main.py", line 1186, in up
  File "compose/cli/main.py", line 1182, in up
  File "compose/project.py", line 702, in up
  File "compose/parallel.py", line 108, in parallel_execute
  File "compose/parallel.py", line 206, in producer
  File "compose/project.py", line 688, in do
  File "compose/service.py", line 581, in execute_convergence_plan
  File "compose/service.py", line 503, in _execute_convergence_recreate
  File "compose/parallel.py", line 108, in parallel_execute
  File "compose/parallel.py", line 206, in producer
  File "compose/service.py", line 496, in recreate
  File "compose/service.py", line 615, in recreate_container
  File "compose/service.py", line 334, in create_container
  File "compose/service.py", line 922, in _get_container_create_options
  File "compose/service.py", line 962, in _build_container_volume_options
  File "compose/service.py", line 1549, in merge_volume_bindings
  File "compose/service.py", line 1579, in get_container_data_volumes
KeyError: 'ContainerConfig'
```

### version
docker 20.10.9 -> 27.0.2に上げてから発生
```
docker : Docker version 27.0.2, build 912c1dd
docker-compose : docker-compose version 1.29.2, build 5becea4c
```

## 原因
どうやらコンテナを一度立ち上げたままの状態で再度upしようとすると発生している様子？
-> downしてから再度upすることで解決
`--rmi all --volumes --remove-orphans` : down + image,volume,未定義コンテナの削除
```
# docker-compose down --rmi all --volumes --remove-orphans
# docker-compose up -d --build
```

ref : https://askubuntu.com/questions/1508129/docker-compose-giving-containerconfig-errors-after-update-today
Pythonで行う正規QQプロット

正規QQプロット（Normal Quantile-Quantile Plot）は、観測データが正規分布に従っているかを調査する方法です。
下記に正規QQプロットについて説明します。



### 正規QQプロットの数式

1. **観測データの分位数（Sample Quantiles）**:
   観測データの分位数を小さい順に並べます。  
   並べた観測値を下記にようにします。
   $$ Q_{\text{observed}} = \{ q_{(1)},q_{(2)}, \ldots, q_{(n)} \} $$ ここで、$q_{(k)}$ は観測データの中で $k$ 番目に小さい値です。 $n$でデータ数です。
2. **理論的な分布の分位数（Theoretical Quantiles）**:
 各データの分位点(累積確率)を算出します。
 $p_{(k)} = \frac{k}{n+1}$を用いて、それぞれの分位点を算出します。
 正規分布の確率密度関数の逆関数$F^{-1}(x)$を用いて期待値を算出します。 $$Q_{\text{theoretical}} = \{ F^{-1}(p_{(1)}), F^{-1}(p_{(2)}), \ldots, F^{-1}(p_{(n)}) \}$$ 
3. **正規QQプロットの作成**:
   正規QQプロットは、 $Q_{\text{theoretical}}$を横軸に、 $Q_{\text{observed}}$を縦軸にとり、これらの対応関係を散布図としてプロットします。理想的には、両者が一致する場合、データは対象とした理論分布に従っていることになります。

### 解説

- **観測データの分位数 $q_{(k)}$** は、実際に観測されたデータの中で小さい順に並べた値です。これにより、データの分布全体の形状を示します。
  
- **理論的な分布の分位数 $F^{-1}(p_{(k)})$** は、比較したい理論的な確率分布 $F$ の逆関数を用いて計算されます。これにより、理論分布がどのように観測データに適合するかを示します。

- **正規QQプロットの対角線** は、完全な一致を表す参照線であり、もし観測データが理論分布に完全に従っていれば、点はこの線上に分布します。

Pythonで表示する場合は、下記のように作成することでも可能です。
statsmodelsというライブラリを用いることで調べることができます。
今回の記事で利用しているバージョンは0.14.0です。

```
$ pip install statsmodel
```

また、今回は実際のデータではなく、乱数を用いて作成した正規分布に従う値を用いています。

```python
import statsmodels.api as sm
from matplotlib import pyplot as plt

np.random.seed(0)
data = np.random.normal(loc=0, scale=1, size=1000)
fig = sm.qqplot(data, stats.t, fit=True, line="45")
```
実行した際に下記のようなグラフが出力されます。
赤色の直線にデータが当てはまれば正規分布に従っていると言えます。

![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508498/3c55a76d-6666-d6f0-f0f5-a60f3eb92535.png)
BackgroundMusicとLadioCastを使ってMacで自分の音声とPC音源の両方をGoogle Meetにて共有する (随時更新予定)


# 記事のモチベーション

ミーティングにて自分の音声＋ PC の音声を共有する方法について、いろいろな方法はあると思いますが、最もシンプルな方法についてまとめていきます。他人に向けた記事というより備忘録の意味合いが強いです。環境は以下の通りです

機種：MacBook Air (M1, 2020)
OS：macOS Sonoma (14.5)

# 事前準備

BackgroundMusic のインストール：[GitHub](https://github.com/kyleneideck/BackgroundMusic)
BlackHole のインストール：[Homebrew](https://formulae.brew.sh/cask/blackhole-16ch)
LadioCast のインストール：[Apple Store](https://apps.apple.com/jp/app/ladiocast/id411213048?mt=12)

# 手順

## 1. BackgroundMusic

BackgroundMusic は、Mac の音声出力を管理するアプリです。特に初期設定はいじっていませんが、Output Device は `Macのスピーカー` に設定しておきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/31663c6c-355b-3fb8-2c4d-06d560c246bb.png" width="30%">

また Mac 側のサウンド設定について、Output を BackgroundMusic に設定しておきます。こうすることで、PC の音声を BackgroundMusic を通して出力することができます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/d3c1eac2-003c-8a39-e7a0-9958eb92cba4.png" width="50%">

Windows と異なり Mac の場合 PC の音声を共有することは結構難易度が高いです、、、。しかし、BackgroundMusic を使えば、Spotfy や YouTube などの音声をまとめて扱うことができるので非常に便利です。OBS を使った配信などでも活用できると思います。

## 2. BlackHole

インストールをすれば、システム環境設定のサウンドから BlackHole が選択できるようになります。特に設定などは必要ありません。BlackHole は、Mac の音声を仮想的にルーティングするためのアプリです。

## 3. LadioCast

ここの設定が設定が一番のポイントです。自分は以下のように設定することで一応 Google Meet での音声共有ができました。（多分色々やり方もあるしベストプラクティスではないかもですが）

入力１：Mac のマイク（自分の声）
入力２：Background Music（PC の音声）
出力 メイン：BlackHole 16ch

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/9c2dbfd4-6c3d-1ad1-ca28-d036c7099080.png" width="50%">

## 4. Google Meet

音声のインプットを BlackHole 16ch に設定することで、Google Meet で自分の音声と PC の音声を共有することができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/c17ac3a2-55ae-654d-47b6-e1f16cc29660.png" width="40%">

音声のアウトプットを Mac のスピーカーに設定することで、ミーティング相手の声を聞くことができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/9004b9ca-7fab-e0a6-535e-a367eca48968.png" width="40%">

なお、自分は BGM として Spotify を使うことが多いですが、自分の話している最終に音楽の音量が大きいと結構気になるので、Spotify の音量を下げつつ、他で調整をしています。

![spotify-volume.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/9c3df09c-3f50-085d-2df1-211c4dff7112.png)

一点補足として、Google Meet 側でノイズキャンセリング機能が ON になっている場合、人の音声以外の音を消してしまうことがあります。（これに気づかずめちゃくちゃ時間を溶かしました。。。）
その場合は、Google Meet の設定からノイズキャンセリングを OFF にしてください。

# やろうとして断念したこと

OBS と BackGroundMusic を使えば比較的簡単に、自分の声と PC の音声をミックスする形で配信や録音が可能です。しかもスライドや画面共有も凝った形式で行えます。
ただ OBS の画面も音声も両方合わせて Google Meet に共有するのは比較的難易度が高そうで、NDI を使えばいけるみたいな情報を得たのですが、この辺り Mac と Windows での違いもあり今のところ断念しています。
一応、今も音声はこの形式で声+PC 音声を共有しつつ、OBS の画面共有を Google Meet でやればそれっぽいことは可能です。（パフォーマンス的なことや設定の多さはさておき）
[Swift] String subscript substring

# subscript を使った String の substring

```swift:使い方
let string = "0123456789"
let substring_a = string[0...5] //=> "012345"
let substring_b = string[1...3] //=> "123"
let substring_c = string[3..<7] //=> "3456"
let substring_d = string[ ...4] //=> "01234
let substring_e = string[ ..<4] //=> "0123"
let substring_f = string[4... ] //=> "456789"
```

```swift:実装
extension String {
    subscript(bounds: CountableClosedRange<Int>) -> String {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return String(self[start ... end])
    }
    subscript(bounds: CountableRange<Int>) -> String {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return String(self[start ..< end])
    }
    subscript(bounds: PartialRangeUpTo<Int>) -> String {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return String(self[startIndex ..< end])
    }
    subscript(bounds: PartialRangeThrough<Int>) -> String {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return String(self[startIndex ... end])
    }
    subscript(bounds: CountablePartialRangeFrom<Int>) -> String {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        return String(self[start ..< endIndex])
    }
}
```

ただし、この実装は 性能が悪いため、何百万回も繰り返すようなら、 `String`を `Array<Character>`に変換してから `subarray`すること。

https://qiita.com/nak435/items/422bfdaccd7121c20467


# subarray 版

`subarray`（`ArraySlice`）は `Array`の標準機能です。
上とまったく同じ結果になります。

```swift
let string = "0123456789"
let array = Array(string)
let subarray_a = String(array[0...5]) //=> "012345"
let subarray_b = String(array[1...3]) //=> "123"
let subarray_c = String(array[3..<7]) //=> "3456"
let subarray_d = String(array[ ...4]) //=> "01234
let subarray_e = String(array[ ..<4]) //=> "0123"
let subarray_f = String(array[4... ]) //=> "456789"
```

**以上**
[Python] 変数とデータ型について

## はじめに
こんにちは！
今回も、備忘録を兼ねて。

Pythonでプログラミングをする上で、変数やデータ型は、とても大事ですね。
変数はデータを入れる箱のようなもので、データ型はその箱に入るデータの種類を表します。

今回はPythonの変数とデータ型について、解説していきます。

## 変数とは？

変数とは、データを格納するための名前付きのメモリ領域です。
「**変数名 = 値**」のように書くことで、値を変数に代入することができます。

```python
# 変数の定義と代入
name = "やました" 
age = 20
height = 170.5

# 変数の値を表示
print(name)   # 出力結果: やました
print(age)    # 出力結果: 20
print(height) # 出力結果: 170.5 
```

## データ型の種類

Pythonには、様々なデータ型が存在します。
代表的なデータ型は以下の通りです。

| データ型        | 説明                                                           | 例                                      |
|:------------------|:-------------------------------------------------------------------|:----------------------------------------|
| 整数(int)       | 整数を表す                                                       | `10`, `-5`, `0`                        |
| 浮動小数点数(float) | 小数を表す                                                       | `3.14`, `-2.7`, `0.0`                  |
| 文字列(str)       | 文字列を表す                                                       | `"Hello"`, `"Python"`                  |
| ブール値(bool)     | 真理値を表す。 `True` (真) または `False` (偽) のいずれか。 | `True`, `False`                        |
| リスト(list)      | 複数の値を順番に格納する。                                           | `[1, 2, 3]`, `["apple", "banana"]`      |
| タプル(tuple)     | 複数の値を順番に格納する。ただし、値の変更は不可。                  | `(1, 2, 3)`, `("apple", "banana")`     |
| 辞書(dict)      | キーと値のペアでデータを格納する。                               | `{"name": "やました", "age": 20}`         |
| 集合(set)        | 重複のない要素の集合を表す。                                         | `{1, 2, 3}`, `{"apple", "banana"}`     |
| NoneType         | 値が存在しないことを表す `None` という特別な値のみを持つ。       | `None`                                  |

## データ型の確認

`type()`関数を使うと、変数に格納されているデータの型を確認することができます。

```python
name = "やました"
age = 20
height = 170.5
is_student = True

print(type(name))       # 出力結果: <class 'str'>
print(type(age))        # 出力結果: <class 'int'>
print(type(height))     # 出力結果: <class 'float'>
print(type(is_student)) # 出力結果: <class 'bool'> 
```

## 型変換

あるデータ型から別のデータ型に変換することを**型変換**と言います。

```python
# 整数を文字列に変換
age = 20
age_str = str(age) 
print(age_str)   # 出力結果: "20"
print(type(age_str)) # 出力結果: <class 'str'>

# 文字列を整数に変換
age_str = "20"
age = int(age_str)
print(age)      # 出力結果: 20
print(type(age))  # 出力結果: <class 'int'>
```

## 変数の命名規則

変数名は自由に付けることができますが、以下のルールに従う必要があります。

- 使用できる文字は、英数字とアンダースコア(`_`)のみ
- 最初に数字を使うことはできない
- Pythonの予約語(`if`, `else`, `while`など)は変数名として使えない
- 大文字と小文字は区別される

## まとめ

今回は、Pythonの変数とデータ型について解説しました。

変数とデータ型は、Pythonプログラミングの基礎であり、これらをしっかりと理解することで、より良いプログラムを作成することができます。

みなさんも一緒にがんばりましょう！
【初学者用】JavaScript学習教材(DOM操作、アニメーション、非同期処理etc)

# はじめに
以前Reactのアプリ作成学習教材を作成したのですが、今回はJavaScriptバージョンです。
HTML,CSS,JavaScriptだけで構成されてますので、初心者の方も安心してください。

# 学習の仕方
各プロジェクトのコードは下記のGitHubにあげてます。
READMEファイルに学習手順を記載してますので、その通りに実施していきましょう。

https://github.com/Kroro1208/js-beginner-projects


# 作成するプロジェクトの一部
全部で11個のプロジェクトを作成します。
JS初学者が**DOM操作や簡単な非同期処理**に慣れることを主眼に置いてますので、DOM操作や苦手だな～という方は是非やってみてください:point_up:

## ポモドーロタイマー
![10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492127/5a7341dc-8744-42cc-0af5-dd54cf81dda5.gif)

## テキストカウンター
![8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492127/7b9b991a-eacb-a6cc-90ca-2993d229b23b.gif)

## テーマカラー切り替え
![6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492127/fbcdb6b6-681f-be07-cba7-5cc3bedb2298.gif)

## アイコンアニメーション
![1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492127/053a697b-87fd-4a2e-a7f8-7154d05fe5f5.gif)

## 画像のロード
![5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492127/9c140bac-8a80-a72f-311f-3e8273771f57.gif)


# おわりに
冒頭にも記載しましたが、必ずREADMEを読んでから始めてください:writing_hand:
コードの意味が分からなければまず考えてみて、それでもわからなければAIに聞きいて、理解した状態で作成していきましょう。
AI時代に必須の水冷サーバーの解説



こんにちは、皆さん！  
本日はAI時代に必須の「水冷サーバー」について解説します。

こちらも是非参考にしてください♪
https://note.com/kii_genai/n/n93f35bdc2b0e

### AI技術と電力消費の関係

AI技術の進展に伴い、AI向けサーバーの電力消費が劇的に増加しています。これは、より高度なAIアルゴリズムを計算するために必要なコンピューティングパワーが増大しているためです。

- **2010年頃**：サーバー1台あたりの消費電力はおおよそ250W。
- **2020年頃**：サーバー1台あたりの消費電力は倍の500Wに増加。

特に、AI向けのサーバーではその消費電力が飛躍的に大きくなっています。例えば、NVIDIAのAI向けサーバーGDX 100は10.2KW（10,200W）にも達します。

### データセンターの電力消費の現状

データセンターは、AI向けサーバーを含む多くのサーバーを収容し、運用するための施設です。これらのデータセンター全体の電力消費は、サーバー自体の消費電力と冷却システムの消費電力に大きく依存しています。

- **中規模データセンター**：消費電力はおおよそ5000KW（5MW）。
- **大規模データセンター**：消費電力は50MWに達することもある。
- **超大規模データセンター**：100MW以上の電力を消費することが予想される。

### 従来の冷却技術とその課題

データセンターの運用において、冷却技術は非常に重要です。従来の冷却技術としては、主にCRAC（Computer Room Air Conditioner）ユニットとCRAH（Computer Room Air Handler）ユニットが使用されています。

- **CRACユニット**：冷媒を使用して空気を冷却。
- **CRAHユニット**：冷水を使用して空気を冷却。

これらのシステムは、エネルギー効率の低さやスペースの問題、初期導入コストの高さなどの課題が存在します。

### 水冷技術の導入とその種類

水冷技術は、冷却効率が高く、従来の空冷技術に比べて大幅に優れています。以下に、代表的な水冷技術を紹介します。

- **ラック内冷却**：冷却装置をラックの内部に設置し、サーバーの近くで冷却。
- **リアドア冷却**：ラックの後部に冷却装置を設置し、排気熱を効率的に除去。
- **直接液体冷却（DLC）**：冷却水を直接サーバーの発熱部品に供給し、効率的に冷却。
- **液浸冷却**：サーバー全体を冷却液に浸し、非常に高い冷却効率を実現。

### 水冷技術の実用化に向けた課題

水冷技術の実用化には、いくつかの課題が存在します。

- **規格の統一**：メーカーごとの仕様の違いによる互換性の問題。
- **初期導入コスト**：高額な設置費用。
- **メンテナンスの複雑さ**：専門的な知識やスキルが必要。

### 将来の展望

今後、AI技術のさらなる発展に伴い、データセンターの電力消費は増加することが予想されます。このため、冷却技術の進化と効率化がますます重要となります。水冷技術の導入とその規格統一が進むことで、データセンターの冷却効率が向上し、エネルギー消費の削減と環境負荷の軽減が期待されます。

---

水冷サーバーは、AI時代におけるデータセンター運用の鍵となる技術です。今後の技術進展と規格統一の取り組みを注視していきましょう！

---

引用：
1. [NVIDIAのAIサーバーGDX 100](https://canplay-music.com/2019/04/02/nvidia-gdx/)
2. [データセンターの電力消費](https://www.inet.co.jp/blog/datacenter/power-consumption0207.html)
3. [リアドア冷却](https://cafe-dc.com/glossary/%E3%83%AA%E3%82%A2%E3%83%89%E3%82%A2%E5%86%B7%E5%8D%B4/)
4. [直接液体冷却（DLC）](https://japancatalog.dell.com/c/wp-content/uploads/04_HEROES_202312_Cooling.pdf)
【プラクティス紹介】1分でさらっと分かる「1-2-4-ALL」

![124ALL.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3526800/952f3820-c798-1e46-a3b8-e8b144d9ca05.jpeg)

## プラクティス名
1-2-4-ALL

## プラクティスの目的・狙い
* 参加者全員を議論に参加させる
* 全員に平等に話す機会を与え、声の小さい人の意見も拾い上げる
* 短時間で個々人のアイデアを集合知に変える

## どんな時に使うか
* 皆のアイデアを集約し、全員に共有したい時
* 声の大きな人が延々と話し続けるのを防止したい時

## 実施手順
1. 参加者に今回の検討テーマ（問い）を伝える（例：この問題を解決するには？）
1. 個人で1分間その答えを考える
1. ペアを組み、お互いのアイデアについて2分間話し合う
1. ペア同士をくっつけて、4人でさらに4分間話し合う
1. 全員で集まって5分間で各グループの結論（最も重要なアイデア1つ）を共有する

## アレンジ例
* 必要に応じて1-2-4のサイクルを何度か繰り返す（人数が多い時など）
* ホワイトボードに付箋を書き出すなど議論の過程を可視化する
* 検討テーマや参加人数に応じて、時間配分は適宜調整する

## アンチパターン
* 前の会話でどんな意見が出て、どのような過程でその結論に至ったのか、経緯を説明しはじめる（それだけで時間を消費してしまい検討時間が無くなる）

## 参考情報

原典はこちら。リベレイティング・ストラクチャーズ（という会議ファシリテーションアイデア集）の１つ。

https://www.liberatingstructures.com/1-1-2-4-all/

説明としては以下のサイトの方が分かりやすいかと思います。

https://openpracticelibrary.com/practice/1-2-4-all/

上記は２つとも英語サイトですが、日本語で最も詳しく書かれているのは、チェンジスペシャリストあきと様の記事かと。

https://www.a-output.com/liberating-structure

## こぼれ話（私的コメント）
原典ではどんな人数でも使える手法とされていますが、個人的には8～32人ぐらいのサイズが適当ではないかなと思っています。（オフラインでは物理的な場所の制約、オンラインでは接続数や部屋数などの制約が発生するため。また人数に比例して最後の「全員で共有」の時間も長くなる。）
会議のゴールが「共有」までであれば、このプラクティスだけでも足りそうですが、「意見を１つにまとめる」だった場合は結論を出すために別手法を組み合わせる必要がありそうです。

全然関係ないのですが、最初「1-2-4-ALL」というネーミングを見た時、数を表す名詞が「1,2,3,たくさん」しかないというアフリカの先住民族の話を想起してしまいました。はい、本当に関係ない話ですいません。。。

---
　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)
ZCU104 の Petalinux で MMC が認識されない問題への対応方法

# はじめに

久しぶりに ZCU104 用に Petalinux をビルドした所、mmc がマウントできず難儀しました。

その時の解決方法のメモです。

# 問題

Vivado で作成した XSA ファイルを元に作成したプロジェクトで Petalinux をビルドすると、mmc がマウントされません。Petalinux 起動時に下記メッセージを出力します。

```
mmc0: error -110 whilst initialising SD card
```

# 環境

<dl>
    <dt>Board</dt>
    <dd>Xilinx ZCU104</dd>
    <dt>Tools</dt>
    <dd>Vivado ML Edition 2024.1 (Windows11)</dd>
    <dd>Petalinux 2024.1 (Ubuntu 22.04.4)</dd>
</dl>

# 解決方法

Petalinux のプロジェクト配下にある `project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi` へ下記１行を追加してビルドします。

```diff_c
+ #include "zcu104-reva.dtsi"
/include/ "system-conf.dtsi"
/ {
};
```

`zcu104-revc.dtsi` というファイルもありますので、利用しているボードの Revision に合わせて選択します。[サポートによると](https://support.xilinx.com/s/question/0D54U00006usdPZSAY/how-can-determine-zcu104-revision-a-or-b?language=ja) Revision はボード上の FMC コネクタ横にシルクプリントされている様です。私のボードではプリントされていなかったので `zcu104-reva.dtsi` を選択しています。

ここで追加されるファイルの元ネタは [GitHub の Xilinx リポジトリ](https://github.com/Xilinx/device-tree-xlnx/tree/master/device_tree/data/kernel_dtsi/2023.2/BOARD) でした。ここには他のリファレンスボード用の定義もあります。

# MMC の動作確認

Petalinux をデフォルト設定のままビルドすると initrd を rootfs として起動します。この時 mmc が認識できていると `/run/media` 配下に自動でマウントされます。

```bash
zcu104-ps-only:~$ ls /run/media/
mmcblk0p1  mmcblk0p2
```

上記フォルダをアクセスする事で mmc の認識を確認できます。
VSCodeのPythonデバッガを動かす

プログラミングをしている時には不可欠なデバッギングですが、VSCodeのデバッガを使うことで効率的にデバッグを行うことができます。

いつもprintデバッグをしている人も、VSCodeのデバッガを使うことでデバッグの効率が上がるかもしれません。

（かく言う私もGoのprintで様々なデバッグをしてきたので自分に向けて書いた記事でもある）

次からはPythonを使ったデバッグの方法を書いていきます。

## 準備

extensionでPython Debugger、もしくはPythonをインストールします。

.vscode/launch.jsonに以下の記述をする。

（デフォルトの設定でこうなります）

```json:.vscode/launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python Debugger: Current File",
            "type": "debugpy",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal"
        }
    ]
}
```

これでF5を押すことでデバッグを開始できるようになります。

## ブレークポイント

ブレークポイントを設定することで、その行でプログラムが止まります。

ブレークポイントを設定するには行番号の左側をクリックする、もしくはF9を押します。（赤い丸が表示されます）

デバッグを開始するとブレークポイントで止まります。

## デバッグしてみる

以下のコードを書いてデバッグしてみます。

```python:main.py
def append_abc(s: str) -> str:
    a = append_a(s)
    b = append_b(a)
    c = append_c(b)
    return c

def append_a(s: str) -> str:
    return s + 'a'

def append_b(s: str) -> str:
    return s + 'b'

def append_c(s: str) -> str:
    return s + 'c'


def main():
    s = 'start'
    a = append_a(s)
    b = append_b(s)
    c = append_c(s)
    abc = append_abc(s)

if __name__ == '__main__':
    main()
```

任意の場所にブレークポイントを設定してデバッグを開始します。

ブレークポイントを設定した行でプログラムが止まり、変数やコールスタックを確認することができます。

このときのサイドバーには以下のような情報が表示されます。

- Variables: 変数の値を確認できます。
- Watch: 変数の値を監視できます。
- Call Stack: コールスタックを確認できます。

![Screenshot 2024-07-06 at 11.57.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655827/0faeac9b-fa73-9210-b69f-a7bf00a320dc.png)


## デバッグ中の操作

デバッグ中には以下の操作ができます。

| アクション | 説明 |
| --- | --- |
| 続行 / 一時停止 (F5) | 続行: 次のブレークポイントまで通常のプログラム/スクリプトの実行を再開する。 一時停止: 現在の行で実行中のコードを検査し、行ごとにデバッグする。 |
| ステップオーバー (F10) | 次のメソッドをそのコンポーネントのステップを検査せずに単一のコマンドとして実行する。 |
| ステップイン (F11) | 次のメソッドに入り、行ごとにその実行を追跡する。 |
| ステップアウト (⇧F11) | メソッドまたはサブルーチン内部にいる場合、そのメソッドの残りの行を1つのコマンドとして完了して、元の実行コンテキストに戻ります。 |
| 再起動 (⇧⌘F5) | 現在のプログラムの実行を終了し、現在の実行構成を使用してデバッグを再開する。 |
| 停止 (⇧F5) | 現在のプログラムの実行を終了する。 |

![Screenshot 2024-07-06 at 11.57.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655827/1d33b5f0-c1c0-5d13-b77d-dda35f309ebd.png)


ここまででVSCodeのデバッガの使い方について書いてきました。

さらにブレークポイントに条件をつけたり可能なので[ドキュメント](https://code.visualstudio.com/docs/editor/debugging)を見ながら使ってみてください。
【Unity】シーンを録画する（Recorder）

# Recorderとは？

「Unity Recorder」とは、Unity のエディタ内でゲームプレイ、アニメーション、その他のシーンコンテンツをビデオ、画像、オーディオ、アニメーションクリップなどのさまざまな形式でキャプチャおよびエクスポートするツールです。

# インストール方法

Unityエディタを開き、上部のメニューから
「Window」>「Package Manager」を選択します。
右上の検索バーに「Recorder」と入力し、出てきたパッケージをインストールします。

<img width="650" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470968/da262600-c99c-ddf4-08d5-6448ff560ed0.png">

# 使用方法

Unityエディタを開き、上部のメニューから
「Window」>「General」>「Recorder」>「Recorder Window」を選択します。

「Recorder Window」で「Add Recorder」をクリックし、
キャプチャしたい形式（ビデオ、画像、GIFなど）を選択します。

録画する対象や出力形式などの諸設定を調整し、
「Start Recording」をクリックすると、録画が開始されます。

録画を終了するには、「Stop Recording」をクリックします。

<img width="650" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470968/8b9069e8-ae8d-78c3-05c7-6f9ba9af7d0d.png">

最後までご覧いただきありがとうございました :laughing:
polymorphicと中間テーブルの違い

polymorphicと呼ばれる、初めましての概念と出会ったので記録します。
polymorphic自体は理解したつもりだったのですが、中間テーブルの違いはなんなのかなと思った時に分からなかったので聞いてみました。

以下本文

ポリモーフィック（polymorphic）と中間テーブル（join table）は、データベース設計において多対多の関係を扱うための異なるアプローチです。それぞれの違いと特徴を以下に説明します。

### ポリモーフィック（Polymorphic）

**定義:**

ポリモーフィック関連は、一つのモデルが複数の他のモデルに関連付けられる方法です。ポリモーフィック関連では、関連するテーブルに追加のカラムを使用して、関連付けのタイプを識別します。

**使用例:**

例えば、コメント（Comment）モデルが、記事（Article）や画像（Image）など、複数の異なるモデルに関連付けられる場合があります。この場合、ポリモーフィック関連を使用します。

```ruby

# Migration to create comments table with polymorphic association
class CreateComments < ActiveRecord::Migration[6.0]
  def change
    create_table :comments do |t|
      t.text :content
      t.references :commentable, polymorphic: true, index: true
      t.timestamps
    end
  end
end

# Comment model with polymorphic association
class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end

# Article model
class Article < ApplicationRecord
  has_many :comments, as: :commentable
end

# Image model
class Image < ApplicationRecord
  has_many :comments, as: :commentable
end

```

**特徴:**

- 複数の異なるモデルに関連付けられる。
- `commentable_type`と`commentable_id`というカラムを持つ。
- データベース設計がシンプルになることがある。

### 中間テーブル（Join Table）

**定義:**

中間テーブルは、多対多の関連を表現するために使用されるテーブルです。二つのテーブル間の関連を管理するために第三のテーブル（中間テーブル）を作成します。

**使用例:**

例えば、プロジェクト（Project）とユーザー（User）が多対多の関係にある場合、中間テーブルを使用します。

```ruby

# Migration to create join table for projects and users
class CreateProjectsUsersJoinTable < ActiveRecord::Migration[6.0]
  def change
    create_table :projects_users, id: false do |t|
      t.belongs_to :project
      t.belongs_to :user
    end
  end
end

# Project model
class Project < ApplicationRecord
  has_and_belongs_to_many :users, join_table: :projects_users
end

# User model
class User < ApplicationRecord
  has_and_belongs_to_many :projects, join_table: :projects_users
end

```

**特徴:**

- 二つのテーブル間の多対多の関係を管理する。
- 中間テーブルには、関連する二つのモデルの外部キーが含まれる。
- 関連情報を柔軟に拡張できる（例：役割や参加日などの追加属性）。

### 違いのまとめ

| 特徴 | ポリモーフィック | 中間テーブル |
| --- | --- | --- |
| 関係の種類 | 一対多、多対多 | 多対多 |
| 関連付けるモデルの数 | 複数の異なるモデルが可能 | 二つの特定のモデル |
| 設計のシンプルさ | 複数の異なるモデルと関連付ける場合にシンプルになることがある | 多対多の関係の管理が必要な場合にシンプル |
| 拡張性 | 関連タイプを動的に増やすのは難しい | 中間テーブルに追加属性を持たせることで柔軟に拡張可能 |

以上がポリモーフィックと中間テーブルの違いです。それぞれのアプローチは、特定の要件やデータモデルに応じて適切に選択されます。

DB関連の知識は後々の個人開発を見据えて身につけたい知識です。
なのでしっかり勉強したいと思います。
私がソフトウェア開発の不安を払拭できた理由

## はじめに

◆この記事は何？
エンジニア初心者は、ソフトウェア開発に不安を抱きがちです。
この記事では、私が不安を払拭できた理由を紹介します。

◆対象は？
エンジニア
特に初心者

◆この記事のねらい
初心者が抱くソフトウェア開発の不安の払拭

## エンジニア初心者の頃の不安

エンジニア初心者の頃、次のような不安を感じたことはなかったでしょうか。

- わからないことが多くて不安
- 何がわからないのかもわからない

ある書籍を読んだことがきっかけで、私は自分の不安の本質を理解できました。 その理解をもとに具体的な対策を立て、徐々に不安を克服していきました。

## 『エンジニアリング組織論へ招待』
書籍『エンジニアリング組織論へ招待』の「はじめに」では次のようにか書かれています。

> 先が見えないという「不確実性」をどう扱うかを知ることができれば、「不安」は「競争力」に変わります。（中略）本書は、「不確実性に向き合う」という立った一つの原則から、エンジニアリング問題の解決方法を体系的に捉える組織論です。

この本はエンジニアリングの不確実性を扱っています。

次の一文で、不安をそのまま受け入れられるようになりました。

> エンジニアリングの本質が「不確実性の削減」であることに気づかずにいると、確実でない要求仕様にフラストレーションを抱え、確実でない実現手段にストレスを感じ、確実なものを確実な手段で提供したいというような決してあり得ない思想を思い描いて、苦しい思いをすることになってしまいます。

開発中に要件が固まらないことにストレスを感じましたが、それが自然だと理解しました。

以降、「要件が固まっていないこと」に不安を感じることはなくなりました。

## 「わからない」をわかるようにする

本書で「わからない」の本質を理解しました。

> 本質的に「わからないこと」はたった二つしかありません。それは、「未来」と「他人」です。

「わからない」の解像度が高くなり、それぞれの不安に対策ができました。

例えば、内部ミーティングで未来について話し合い、不確実性を減らしました。
また、チームメンバーやステークホルダの活動を把握し、他人の不確実性を減らしました。

そして、残る不安は自分に関する不安だと気づきました。
自分に関する不安は主に品質/テストに関するものでした。
不安の原因がわかると、勉強することで、不安を克服して自信を持てるようになりました。

## おわりに

この記事では、ソフトウェア開発に関する不安の払拭について紹介しました。

参考になれば幸いです。
utoipaでserversを指定するには

# はじめに

趣味のプログラミングでrustをつかったwebサーバーを作成しています🦀

その際、utoipaを使ってopenapiのスキーマ出力 ⇒ openapi-generatorによるTSクライアント出力をしていたのですが、
deployするときにTSクライアントのbaseUrlを変えたかったので、openapiのserversスキーマ指定する方法をとることにしました

:::note info
`utoipa::openapi::Server`を使用するとよいです
:::

# サンプル

```diff_rust
    // ドキュメントのオブジェクト生成
    let mut doc = ApiDoc::openapi();

    // 環境変数から","区切りのURL取得
    std::env::var("SERVERS").ok().map(|servers| {
        doc.servers = Some(
            servers
                .split(',')
+               .map(|x| utoipa::openapi::Server::new(x))
                .collect()
        );
    });
```

:::note warn
`utoipa::openapi::Server::new()`を使用して生成しないとコンパイルエラーになります
:::

## new()を使用しないといけないのに気付かず詰まった

`#[non_exhaustive]`が設定されているので
`cannot create non-exhaustive struct using struct expression`
というエラーが、、

`cargo check`の実行結果によると
`For more information about this error, try 'rustc --explain E0639'.`
ということなので、実行してみると、new()使ってみなよとあったので無事解決した運びでした

rustcのexplainは親切でわかりやすいですね！

ちなみに…マクロを使ったserversの指定ができるのかよくわからないんですよね、、
あえて目をつむります🙈
OpenCV を使ってお絵かきアプリを作る方法(改良版)

# 0.最初に
「opencv お絵描き」でggって一番上に出てくる記事のものを改良したので紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/321a3703-c40c-b8af-e838-eaee8c69c9c5.png)

参考記事：

https://qiita.com/igor-bond16/items/ef26167a1139a34e24af

# 1.紹介
参考にした @igor-bond16 さんのはこんな感じ。
<img width=50% alt="参考" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/5fd8c34d-1b03-0727-8bd6-075d401c3566.gif">
マウスを速く動かしたときに連続せず点々になっているのが気になりますね。

次に改良したのがこんな感じ。
<img width=50% alt="参考" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/8dabb03f-d76d-8bc5-fcf0-bf7510d6e3bd.gif">
点々をなくしたのと、右クリックで第2色を使えるようにしたのと、Deleteキーで消せるようにしてみました。

# 2.コード
```py
#参考：https://qiita.com/igor-bond16/items/ef26167a1139a34e24af

import cv2
import numpy as np
import threading
import time

def nothing(x):
    pass

class OEKAKI:
    def __init__(self):
        self.drawing=False
        self.kesigomu=False
        self.lastClickPos=(-1,-1) #わざわざ初期化する必要もないのだが、変数を宣言という意味で入れてる
    def draw_circle(self,event,x,y,flags,param):
        #この関数は、cv2のWindow内でのマウスイベントが起こった時に毎回呼ばれる。
        #(該当ウィンドウ内で)クリックした、マウスが動いた、マウスを離したのイベント時。
        #最高で1秒間に120回程呼ばれる。
        b = cv2.getTrackbarPos('B','image')
        g = cv2.getTrackbarPos('G','image')
        r = cv2.getTrackbarPos('R','image')
        s = cv2.getTrackbarPos('Size','image')
        #i = cv2.getTrackbarPos(switch,'image')

        if event == cv2.EVENT_RBUTTONDOWN:
            self.kesigomu=True
        elif event == cv2.EVENT_RBUTTONUP:
            self.kesigomu=False

        if self.kesigomu==True: #消しゴムモードのとき
            b,g,r = 0,0,0 #描画色を背景色に

        if event == cv2.EVENT_LBUTTONDOWN or event == cv2.EVENT_RBUTTONDOWN:
            self.drawing = True 
            cv2.circle(img,(x,y),s,(b,g,r),-1) #変更点：クリックした瞬間に描画する
        elif event == cv2.EVENT_MOUSEMOVE:
            if self.drawing == True:
                #cv2.circle(img,(x,y),s,(b,g,r),-1) #動かせばその時描画する
                cv2.polylines(img,[np.array([self.lastClickPos,(x,y)])],False,(b,g,r),s*2)#直前の点と現在の点を直線で結ぶ
        elif event == cv2.EVENT_LBUTTONUP or event == cv2.EVENT_RBUTTONUP:
            self.drawing = False
            #変更点：離したときには描画しない

        if self.drawing==True:
            self.lastClickPos=(x,y) #点々になるのを防ぐため


img = np.full((800,800,3),255,np.uint8)
cv2.namedWindow('image')

cv2.createTrackbar('B','image',0,255,nothing)
cv2.createTrackbar('G','image',0,255,nothing)
cv2.createTrackbar('R','image',0,255,nothing)
cv2.createTrackbar('Size', 'image',1,30,nothing)
oekaki=OEKAKI()
cv2.setMouseCallback('image',oekaki.draw_circle)
#switch = '0 : OFF \n1 : ON'
#cv2.createTrackbar(switch, 'image',0,1,nothing)

while True:
    key=cv2.waitKey(1)
    if key & 0xFF == ord('q'):
        break
    elif key& 0xFF == 0: #DELETEキー
        img = np.full((800,800,3),255,np.uint8) #リセット
    cv2.imshow('image',img)
cv2.destroyAllWindows()
```

やったのは
- グローバル変数の使用をやめた
- トラックバーで"i"の変数を変更して色1/色2の切り替えをしていたところを、右クリックで色2になるようにした
- 削除機能を付けた
- なめらかに描画されるようにした

くらいです。よければぜひ。
Flutterでページ間での値を受け渡す(クエリパラメータで実装)

## はじめに
Flutterでページ間の値を受け渡す場合、グローバルコンテキストにデータを格納しないといけないですよね。ただ、一時的な情報なのにグローバルコンテキストに入れると依存関係が複雑化しやすいです。
Reactで実装していた時は、クエリパラメータで値の受け渡しを実装していたので、Flutterでもできなかいなぁと思い実装してみました。

## 成果物

![クエリパラメータでの値の受け渡し.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/31095532-1387-a43f-c702-8db03937f430.gif)


## ソースコード
前回の記事のコードの続きです。今回は修正箇所のみを記載していきます！！

https://qiita.com/koji0705/items/2b64ee123b8a44cb8518

```shell:ディレクトリ構成
~/develop/bottom_bar$ tree lib 
lib
├── main.dart
├── page
│   ├── homePage.dart
│   ├── profilePage.dart
│   └── searchPage.dart
└── route.dart

2 directories, 5 files
```

```dart:lib/route.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'page/homePage.dart';
import 'page/searchPage.dart';
import 'page/profilePage.dart';

final GoRouter router = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return HomeScreen();
      },
    ),
    GoRoute(
      path: '/search',
      builder: (BuildContext context, GoRouterState state) {
        // クエリパラメータを取得
        final query = state.queryParameters['query'] ?? 'No query';
        return SearchScreen(query: query);
      },
    ),
    GoRoute(
      path: '/profile',
      builder: (BuildContext context, GoRouterState state) {
        return ProfileScreen();
      },
    ),
  ],
);

```

:::note info
searchのパスを見てみましょう。
コンポーネントを表示する前にクエリパラメータを取得し、コンポーネントに値を渡しています。
:::

```dart:lib/page/searchPage.dart
import 'package:flutter/material.dart';

class SearchScreen extends StatelessWidget {
  final String query;

  SearchScreen({required this.query});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Search Page'),
      ),
      body: Center(
        child: Text('Search Query: $query'),
      ),
    );
  }
}
```
:::note info
クエリパラメータで設定した値が引数となりコンポーネントに届きます。
それを表示して完了となります。
:::
XXXリテラルについて整理する

## リテラルとは
プログラム上で数値や文字列など、データ型の値を直接記述できるように構文として定義されたものである。

## リテラルの種類
リテラルの種類についていくつかピックアップし、紹介する。

#### 文字列リテラル
頻繁に使用され、見慣れているであろうリテラル。シングルクォーテーション（'）またはダブルクォーテーション（"）で文字列を囲んだものを指し、文字列型のデータであることを表現する。
なおシングルクォーテーション（'）またはダブルクォーテーション（"）で差異はない。

``` javascript: sample_text.js
const str = "こんにちは";
```

#### 整数リテラル
こちらもよく見慣れているであろうリテラル。10進数の数字を表現したいのであれば、単にその数値だけを書く。

``` javascript: sample_num.js
console.log(255); // => 255
```

#### テンプレートリテラル
バッククォート（\`）で囲んだ範囲を文字列とするリテラル。本リテラルでは`プレースホルダー（${変数名}）`をリテラル中に記述することで、その変数の値を文字列中に埋め込むことができる。

``` javascript: sample_tmp.js
const str = "文字列";
console.log(`これは${str}です`); // => "これは文字列です"
```


## 参考サイト

https://jsprimer.net/basic/data-type/

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Template_literals
[Red Hat Enterprise Linux9] /bootと/boot/efiのデフォルトパーティションサイズは変更できない

直近、あるシステム用に新規でAmazon EC2（RHEL）を構築する必要がありました。
設定項目が多くOS設定は自動化スクリプトを作成し、一括で設定することになりました。
その際、Amazon EC2（RHEL）のディスク設定で躓きましたため、備忘録を兼ねてその対応履歴を記事にします。

## やりたかったこと
ベアメタルにおけるRHELの推奨パーティションサイズに合わせ、
下記/bootと/boot/efiのデフォルトパーティションサイズをそれぞれ、
1GiBと600MiBに拡張したいと考えてました。

```
$ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
nvme0n1     259:0    0  100G  0 disk
tqnvme0n1p1 259:3    0    1M  0 part
tqnvme0n1p2 259:4    0  200M  0 part /boot/efi
tqnvme0n1p3 259:5    0  600M  0 part /boot
mqnvme0n1p4 259:6    0 99.2G  0 part /
nvme2n1     259:1    0   30G  0 disk
nvme1n1     259:2    0    1G  0 disk
```

## /bootと/boot/efiのデフォルトパーティションサイズは変更できない
ただし、調査したところ、/bootと/boot/efiのデフォルトパーティションサイズは変更できないようです。

#### 理由①：AMIでデフォルトパーティションサイズが固定されている
Amazon EC2はAMIはから起動されるため、AMIデフォルト設定を変更できないか考えました。
ただ、パーティションサイズはデータとしてEBSボリューム（スナップショット）に保存されているものであり、AMIの各パーティションサイズのデフォルト値を変更することはできませんでした。

#### 理由②：/bootと/boot/efiの後ろに空き領域がない
AMIデフォルト設定の変更ができなかったため、次にAmazon EC2起動後にパーティションサイズを拡張することを検討しました。
ただし、起動後にパーティションサイズの拡張を行うには、対象パーティションの後ろの領域が空いている必要があります。
今回の例で言うと、/boot/efiの後ろには/boot、/bootの後ろには/が存在しています。
そのため、/bootおよび/boot/efiのサイズを拡張することは不可能でした...。

## まとめ
そもそもAMIから起動したAmazon EC2（RHEL）のデフォルトパーティションサイズは、Red Hatで決めた値？のはずであり、サーバの正常稼働には十分なサイズ設定だと思っています。
そのため、/bootと/boot/efiのパーティションサイズを拡張したいという場面は少ないと思いますが、誰かの参考になれば幸いです。

## 参考
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AMIs.html

https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/9/html/performing_a_standard_rhel_9_installation/recommended-partitioning-scheme_partitioning-reference
【AWS】EC2に新しいVersionのPythonをインストール

EC2で下記を実行する。

```
sudo yum remove -y openssl-devel
sudo yum install -y openssl11 openssl11-devel
wget -c https://www.python.org/ftp/python/3.10.14/Python-3.10.14.tar.xz
tar -Jxvf Python-3.10.14.tar.xz
cd Python-3.10.14/
sudo yum install gcc
./configure --enable-optimizations
make
sudo make install
```

python3で実行可能なようにシンボリックリンクを作成する
```
sudo rm /usr/bin/python3   # 既存リンクがあれば削除
sudo ln -s /usr/local/bin/python3.10 /usr/bin/python3
python3 --version
```

pip3も同様に。
```
sudo rm /usr/bin/pip3   # 既存リンクがあれば削除
sudo ln -s /usr/local/bin/pip3.10 /usr/bin/pip3
pip3 -V
```
インスタンスメソッドとは何なのか、整理してみる。

## インスタンスメソッドとは
それぞれのクラスのオブジェクト（インスタンス）に紐づけられている、専用のメソッド（関数）を指します。
インスタンスメソッドができることのひとつとして、後述のDateオブジェクトの例のように、オブジェクトの情報を返すといった機能が挙げられます。

#### クラス・オブジェクト・インスタンスとは？
「`クラス`をインスタンス化して生成した`オブジェクト`」のことを`インスタンス`と呼びます。
また`インスタンス`は`オブジェクト`でもあるため、`オブジェクト`と呼ぶこともあります。
なお`クラス`はオブジェクト（インスタンス）の設計図にあたり、以下のように`new演算子`を用いることで、`クラス`からオブジェクト型のインスタンスを生成できます。

``` javascript: sample.js
const now = new Date()
```

## インスタンスメソッドの具体例
以下はDateオブジェクトのインスタンスメソッドの一例です。★を参照ください。
インスタンスメソッドは多数あり、すべて挙げるときりがないため一部の紹介とします。
一例にあるインスタンスメソッド以外のメソッドについては、[こちらのサイト](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89 "Date_instanceMethod")を参照ください。
``` javascript: sample.js
const setDate = new Date('2022-10-27')
const setYear = setDate.getFullYear()    //★getFullYear()：年を取得する。
const setMonth = setDate.getMonth() + 1  //★getMonth()：   月(0~11)を取得する。
const setDay = setDate.getDate()         //★getDate()：    日を取得する。
const setDayOfWeek = setDate.getDay()    //★getDay()：     曜日(0~6)を取得する。

console.log(
  `${setYear}/${setMonth}/${setDay}(${
    ['日', '月', '火', '水', '木', '金', '土'][setDayOfWeek]
  })`
)
```
``` javascript: 出力結果
"2022/10/27(木)"
```

## 参考にしたサイト

https://www.sejuku.net/blog/24383

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

https://trends.codecamp.jp/blogs/media/terminology222

https://trends.codecamp.jp/blogs/media/terminology222
【Python】座標を取得する方法

●座標認識のコード

import pyautogui as gui
import sys

print('中断するにはCrt+Cを入力してください。')

try:
    while True:
       x=input("取得したい箇所にカーソルを当てEnterキー押してください\n")
       print(gui.position())

       
except KeyboardInterrupt:
    print('\n終了')
    sys.exit()


●必要な環境
pyautoguiのインストール

pip install pyautogui
自分がGitでまづいたところ（随時更新）

# はじめに
自分の勉強したものをgithubで管理しよう・・・
そんなときにつまずいたところを共有します。ほぼ自分のメモ用。
ちなみに記事は、自分のメモ⇨生成AIに書かせて、適宜かいつまんで載せています。

# 目次

1. リモートブランチを使いたい！
2. クローン時に名前を変えたい！
3. ブランチを指定してpushする
    * 3.1. 上流ブランチを指定してプッシュする
    * 3.2. コロンを使ってリモートブランチを削除する
4. 番外編: GitHubでのタグ付けは要注意！

## メモ
### 1. リモートブランチを使いたい！
Git clone直後は、mainブランチしかローカルに存在しません。 
他のブランチで作業したい場合は、以下の手順でリモートブランチをローカルに持ってきましょう！

- **まずは確認！**
使用可能なブランチをリストアップ！
   ```bash
   git branch -a
   ```
&emsp;
- **リモートブランチをローカルにコピー & チェックアウト！**
   `origin/`を付けるのがポイント！ 
   これがないとローカルブランチと認識されてしまいます！
   ```bash
   git checkout -b dev origin/dev 
   ```
   これで、リモートリポジトリの`dev`ブランチが、ローカルリポジトリにもコピー作成され
   チェックアウトされます！

### 2. クローン時に名前を変えたい！

プロジェクト名と異なる名前でクローンしたい場合は、
`git clone [リポジトリURL] [新しいプロジェクト名]`と入力しましょう！

```bash
git clone https://github.com/plataformatec/devise.git sample
```

これで、"sample"という名前でクローンが作成されます！

### 3. ブランチを指定してpushする

ローカルブランチをリモートリポジトリにプッシュする際、プッシュしたいブランチを明示的に指定することができます。

最も基本的な `git push` コマンドは `git push origin [ブランチ名]` です。これはローカルブランチ名を指定し、その上流ブランチにプッシュします。

```bash
// ローカル master ブランチを origin にある上流ブランチに push する。
git push origin master
```

上流ブランチが設定されていない場合は、ローカルと同じ名前のブランチにプッシュされます。

#### 3.1. 上流ブランチを指定してプッシュする

`:` (コロン) を使用すると、プッシュ先のリモートブランチを明示的に指定できます。
以下の例では、リモートブランチ名「master」に、ローカルブランチ名「akasatana」の情報をプッシュします。

```bash
// ローカルの akasatana ブランチを、origin 上の master ブランチに push する
git push origin akasatana:master
```

#### 3.2. コロンを使ってリモートブランチを削除する

コロンの前に何も指定しないと、「空」をプッシュすることになります。これを利用して、リモートブランチを削除することができます。

```bash
// リモートの feature/a を削除する
git push origin :feature/a
```

#### pullバージョン
```
git pull origin pullしたいリモートブランチ名:ローカルブランチ名
```

### ４. GitHubでのタグ付けは要注意！

GitHubのUI上でタグ付けする際は、意図しないブランチが作成される可能性があります！ 
詳細はこちらの記事をチェック！
[GithubのUI上でtagをつけるときの注意点](https://zenn.dev/umi_mori/articles/668d168c521b70)


# 参考
- [Git をマスターする - 究極のチートシート - ブランチのクローンを作成する](https://www.tempmail.us.com/ja/%E3%82%AE%E3%83%83%E3%83%88/git-%E3%82%92%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E3%81%99%E3%82%8B-%E7%B5%82%E6%A5%B5%E3%81%AE%E3%83%81%E3%83%BC%E3%83%88%E3%82%B7%E3%83%BC%E3%83%88-%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AE%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%B3%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)
- [git cloneしてきたプロジェクトの名前を変えてクローンしてくる方法](https://qiita.com/ko_coon/items/f7a555a1f57fa49e0ff9)
- [GithubのUI上でtagをつけるときの注意点](https://zenn.dev/umi_mori/articles/668d168c521b70)
- [ブランチを指定して git push する方法](https://www-creators.com/archives/5206)
- [リポジトリ内の特定のブランチをpullしたい](
https://github.com/uniba/knowledge_base/blob/master/git_tips/%E3%83%AA%E3%83%9B%E3%82%9A%E3%82%B7%E3%82%99%E3%83%88%E3%83%AA%E5%86%85%E3%81%AE%E7%89%B9%E5%AE%9A%E3%81%AE%E3%83%95%E3%82%99%E3%83%A9%E3%83%B3%E3%83%81%E3%82%92pull%E3%81%97%E3%81%9F%E3%81%84.md)
【Python】Flake8について調べてみた

## はじめに

pythonのツール「Flake8」について特徴や機能などの基本を理解したいと思い、「Flake8」について調べてみました。

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

## Flake8とは

以下は「Flake8」のGithubのREADMEより引用
>Flake8 is a wrapper around these tools:
>
>・PyFlakes
>・pycodestyle
>・Ned Batchelder's McCabe script

Flake8は「PyFlakes」と「pycodestyle」と「Ned Batchelder's McCabe script」の3つのツールのラッパーです。


### PyFlakes
Pythonプログラムのエラーをチェックするプログラムです。
PyFlakesは設計方針として、Pylintよりも高速に動作することを挙げています。
PyFlakesを実際に以下のtkinterを使用したサンプルプログラムに適用してみました。
その結果もあわせて記載します。

```PyflakesSample.py:

import tkinter as tk
from tkinter import filedialog, Text

# Function to save file
def Sample_SaveFunc(event=None):
    local_notuse = "Not use"
    print("Save_Sample")


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

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

# configure key-bind
root.bind("<Control-s>", Sample_SaveFunc)
root.bind("<Control-S>", Sample_SaveFunc)
# display window
root.mainloop()

```


```:Pyflakesの出力
PyflakesSample.py:2:1: 'tkinter.filedialog' imported but unused
PyflakesSample.py:6:5: local variable 'local_notuse' is assigned to but never used
```

「使用されていないインポート文の検出」や「使用していないローカル変数の検出」も実施していることを確認できました。


https://pypi.org/project/pyflakes/

### pycodestyle

PEP8のスタイル規則に照らし合わせて、Pythonプログラムをチェックするツールです。
以下pypiのサイト内で「使用例と出力」の章がありますが、この章にてE201:「 ( の後ろに空白がある場合に発生する警告」や E221:「演算子の前に複数の空白が存在する警告」などPEP8に沿ったコーディングであるかをチェックしていることが確認できました。

https://pypi.org/project/pycodestyle/

### Ned Batchelder's McCabe script

McCabe の複雑性をチェックするスクリプトです。
Pyflakesの箇所で紹介したサンプルプログラム：PyflakesSample.pyに対して、以下コマンドを実行することでMcCabe の複雑性を確認してみます。
```
python -m mccabe PyflakesSample.py
```

```:コマンドの出力結果
5:0: 'Sample_SaveFunc' 1
```
Sample_SaveFunc関数のMcCabe複雑度が1であることを示しています。
本スクリプトでMcCabe複雑度をチェックしていることを確認できました。

https://github.com/PyCQA/mccabe


## おわりに
Flake8は、「PyFlakes」と「pycodestyle」と「Ned Batchelder's McCabe script」のラッパーであり、それぞれ「Pythonプログラムのエラーをチェック」、「PEP8のスタイル規則に沿っているかをチェック」、「McCabe複雑度をチェック」しているツールであることがわかりました。本記事の内容が少しでも何かの役に立てば幸いです。


## 参考文献

https://flake8.pycqa.org/en/latest/

https://github.com/PyCQA/flake8