OmniAICreator/Qiita-1.07M huggingface dataset:
500時間かけて作成したアプリ、ダウンロード数は5件で全て社内の人間だった件について

## はじめに
26歳で4年間勤めた酒屋を辞め、未経験からIT業界に飛び込みました。
最初の一年は運用監視の仕事に従事し、その後、転職して開発の世界に足を踏み入れました。未経験でアプリのリリースまでを振り返りました。
誰にでもあるような普通の転職ストーリーかもしれませんが、もしよければご一読ください。

## 作成した経緯とアプリ
携帯電話にかかってきた電話番号であればアプリでブロック等出来ますが、固定電話にかかってきた電話番号は手入力で検索しなければいけませんでした。
着信画面をGoogle検索しているうちに電話は切れてしまいます。
そこでカメラから電話番号を認識して検索するAndroidアプリを製作しました。

https://play.google.com/store/apps/details?id=com.company.phonenumberOCR

<img width="300" alt="1.png" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755555/d658fb66-c5c4-74bb-8b9e-4f27e3326060.png>
<img width="300" alt="2.png" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755555/1f822977-d116-200b-7ca2-6e1df611620f.png>
<img width="300" alt="3.png" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755555/3ce0613a-74ba-5307-25f7-8c00a93d779c.png>
<img width="300" alt="4.png" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755555/6650f664-b32b-d0d8-3bdf-5c83a3e6826a.png>

## 初めてのアプリ開発
開発経験ゼロの私が最初に挑戦したのは、PythonでOpenCVとTesseractを使用し、カメラで映した映像から電話番号を認識し、検索するアプリです。
アイデアはシンプルでしたが、実装には数々の試行錯誤がありました。
画像処理の基礎から学び、文字認識の精度を上げるために何度もアルゴリズムを調整し、ついに初めてのアプリが完成しました。

## Android版への進化
初めての成功に味をしめ、次はAndroid版の開発に取り組みました。
Android studioでKotlinを使って、カメラ映像から電話番号を認識し、検索するアプリを作成することに決めました。
ML KitのText Recognition v2を使って文字認識を行い、CameraXでカメラの制御を行います。
この技術を使えば、カメラに映った電話番号を即座に認識し、ウェブ検索してデータベースに保存できます。
さらに、同じ番号が再度認識された場合には、過去の着信日時を表示し、検索するか閉じるかを選べる機能も追加しました。
迷惑電話として登録できる機能も実装し、登録された番号は次回認識時に迷惑電話として表示されます。

## リリースまでの道のり
開発にかかった時間は実に500時間。
コードと格闘し、バグと戦いながらようやく完成しました。
しかし、ここからが本当の試練でした。アプリをリリースし、ダウンロード数がどれだけ伸びるかを期待していましたが、現実は厳しかったです。
初めてのリリースで得たダウンロード数は、わずか5件。それも全て社内の人間でした。

## 振り返り
500時間をかけて作成したアプリが、5人にしかダウンロードされなかった現実に直面し、正直に言えばがっかりしました。
しかし、この経験から学んだことは多いです。
技術的なスキルはもちろん、ユーザーが本当に求めるものは何かを考えることの重要性を痛感しました。
また、マーケティングやプロモーションの重要性も身に染みて感じました。

## 次のステップへ
この経験を通じて、開発者としてだけでなく、一人の社会人としても成長できたと感じています。
次は、この経験を活かして、より多くの人に使ってもらえるアプリを開発したいです。
そして、同じように苦労している開発者たちに少しでも希望を与えられるような存在になりたいと思っています。

## 最後に
ここまで読んでいただきありがとうございます。
固定電話にかかってくる迷惑電話にうんざりしている方、是非ダウンロードしてみてください！
これからもアプリを改良していこうと思いますので、気になる点や改良してほしい点がございましたら気軽にレビュー・相談してください。
Net-SNMP ビルドメモ

## なぜかSHA2使えない ⇒ OpenSSのせいかも
Net-SNMP 5.8以降では使えるはずなのに、コードからビルドすると何故か使えない。
どうもOpenSSLヘッダも無いとダメらしい。OSにライブラリのみ入っている状態では不可。

OpenSSLのコードを落としてきて、configure --with-openssl=PATHを指定する。
configure結果のAuthentication supportにSHA2アルゴリズムが入っていれば成功。

```
$ ./configure --with-openssl=/usr/local/openssl
<中略>
  Authentication support:     MD5 SHA1 SHA224 SHA256 SHA384 SHA512
  Encryption support:         DES AES AES128 AES192 AES192C AES256 AES256C
  Local DNSSEC validation:    disabled
```
## MIBを取得したいだけ ⇒ agentをビルドしない
MIBを取得したいだけの場合は、ビルドに時間かかるのでagentのビルドを止める。

```
$ ./configure --disable-agent
```

## 共有ライブラリを作らない

configureオプション --disable-shared で共有ライブラリ(libnetsnmp.so等)をコンパイルしない。
snmpgetやsnmpwalkも静的ライブラリとして

メリットとしては、実行時に共有ライブラリへのパス(LD_LIBRARY_PATH)を通さなくて良い。
あまりない機会が無いかもしれないが・・・。
システムとは違うバージョンのNet-SNMPを使いので自前でビルドしたが、パスが通っている所に共有ライブラリをインストールできない、とか・・・。

```
$ ./configure --disable-shared
```
Files.move使用時、AccessDeniedExceptionが発生する

## Files.move()とは
ディレクトリの移動、もしくはディレクトリ名を変更する際に使用される
また、ファイル名の変更は「File.renameTo」でも可能である
~~Filesクラスが使用できるなら、Fileクラスは極力使用しないことをお勧めする~~


■ファイルを移動、ファイル名の変更
「C:\\tmp\\test.txt」を「C:\\tmp2」に移動、かつファイル名を「test2」に変更する
```
val oldPath = Paths.get("C:\\tmp\\test.txt")
val newPath = Paths.get("C:\\tmp2\\test2.txt")
Files.move(oldPath, newPath)
```
■ディレクトリを移動、ディレクトリ名の変更
「C:\\tmp」を「C:\\tmp2」に移動、かつファイル名を「test2」に変更する
```
val oldPath = Paths.get("C:\\tmp")
val newPath = Paths.get("C:\\tmp2")
Files.move(oldPath, newPath)
```

上記の場合は問題ないが、、、
ディレクトリが空でない場合、「AccessDeniedException」が発生する場合がある

その場合は、別の方法を考える必要が生じる。
それは、「Files.copy」と「Files.walkFileTree」の合わせ技を使用する方法だ。
(なお、この方法は「Filesクラス」のJavaDocに記載がある)

■概要
Files.copyでは、コピー元とコピー先のパスを指定し、複製することができる。
また、コピー先のパスでは、ファイル名を変更して指定ができる。

Files.walkFileTreeでは、指定したディレクトリ以下のファイルパスをまとめて取得できる。
そのため、Files.copyと併用し、すべてのファイルを指定のコピー先に複製できる。
(もちろん、フォルダも複製が可能である)

■サンプルコード
```
val oldPathStr = "C:\\tmp"
val newPathStr = "C:\\tmp2"

Files.walk(oldPath).forEach {
    val oldPath = it.toString()
    val replacePath = oldPath.replace(oldPathStr, newPathStr)
    Files.copy(it, replacePath)
}

■結果
処理前：C:\\tmp\\test.txt
処理後：C:\\tmp2\\test.txt

```
【Golang】Go の最新リリース・バージョンの確認・取得【cURL】

> Go（以下 Golang）のリリースされている最新のバージョンを cURL で取得したい。

ぶっちゃけ [https://go.dev/dl/](https://go.dev/dl/) を覗きに行けばいいのですが、golang 本体の更新をパッケージマネージャでなく俺様スクリプトで行っているため、<font color=darkorange>**バージョン情報を取得できるエンドポイントが欲しかった**</font>のです。

[`golang 最新リリースバージョン 確認 curl` でググって](https://www.google.com/search?q=golang+%E6%9C%80%E6%96%B0%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3+%E7%A2%BA%E8%AA%8D+curl)もピンポイントでヒットしなかったり、`https://go.dev/VERSION?m=text` を使った方法ばかりだったので、自分のググラビリティとして。

## TL; DR <sub><sup>（今北産業）</sup></sub>

1. <font color=darkorange>**確認用のエンドポイント**</font>が提供されている
    - 最新リリース・バージョンの確認 URL: **`https://go.dev/dl/?mode=json`**
1. よく見かける `https://go.dev/VERSION?m=text` は、`https://go.dev/` のバックエンドで動いている golang のバージョン[^1]で、最新と異なることがある
1. レスポンスは JSON なので `jq` コマンドなどで抜き出す必要がある

```shell:最初のstableバージョンを抜き出す
LATEST=$(curl -sSL https://go.dev/dl/?mode=json | jq -r ['.[] | select(.stable == true)'][0].version)
```

```shell-session:実行例
$ curl -sSL https://go.dev/dl/?mode=json | jq -r ['.[] | select(.stable == true)'][0].version
go1.22.4
```

- [オンラインで動作をみる](https://paiza.io/projects/pn62sYq8NwXBYy_RoCOi6w) @ paiza.IO

:::note info
ちなみに、最新ではないものの `go.dev` のドキュメントで生成されるサンプルの動作と合わせたい場合は、`https://go.dev/VERSION?m=text` の最初の行だけを取り出すと、バージョンを合わせられます。

```shell:go.devのgoバージョンを取得
CURRENT=$(curl -s https://go.dev/VERSION?m=text | head -n 1)
```
```shell-session:実行例
$ curl -s https://go.dev/VERSION?m=text | head -n 1
go1.22.1
:::

## 参考文献

- [URL for latest stable Go release](https://stackoverflow.com/questions/51933636/url-for-latest-stable-go-release) @ StackOverflow
- [Hitting curl https://go.dev/VERSION?m=text returns a go version package which is not available to download](https://github.com/golang/go/issues/51135#issuecomment-1035545489) | [Issue #51135](https://github.com/golang/go/issues/51135) | Golang @ GitHub

[^1]: https://github.com/golang/go/issues/51135#issuecomment-1035545489
IBM Cloud Logsを使ってみた

## はじめに
IBM Cloud で IBM Cloud Log Analysis などログ管理系のサービスをお使いの皆さんが気になっているであろう、 IBM Cloud Logs がGAされたので、使ってみました。~~執筆時点の2024年6月末の時点ではまだ東京や大阪ではGAされていません。~~
今回は検証のために　IBM Cloud Logs 上でログを確認できることを目的とし、簡易的に設定を行ってダッシュボードでログを確認します。
本稿では、IBM Cloudのアカウントを持っている（作成済み）であることを前提としています。また、有料プランを使用していますで、その点もご注意ください。

:::note info
(24/08/29更新) 東京(jp-tok)と大阪(jp-osa)でもGAされました。
:::

## IBM Cloud Logs のインスタンスの作成
まずは IBM Cloud Logs のインスタンスを作りましょう。

1. IBM Cloud コンソールにログインし、画面上の「カタログ」を選択し、「Cloud Logs」をキーにして検索します
2. Cloud Logs を選択します
3. ロケーションを選択します。今回はマドリッドを選択します
4. プランはStandardしかないため、Standardの内容を確認します
5. リソースの構成で、名前やリソースグループを選択します
6. 「以下の条件を読み、同意します。」で条件を確認後、チェックを入れます
7. 「作成」ボタンを押します
8. 数分後に IBM Cloud Logs のインスタンスが作成されます

:::note warn
(24/06/27更新) IBM Cloudのサポートの方に対応してもらい、ロケーションでフランクフルト(eu-de)を選ぶとインスタンスが作成できない不具合は解消されました。
:::

## Object Storage のバケットの準備
ログを保管するための IBM Cloud Object Storage のバケットを作成します。データとメトリックの２つの用途のためのバケットを作成します。
今回は検証を目的としているため、既存の IBM Cloud Object Storage のインスタンスにバケットを作成しました。手順は次のドキュメントを参考にしていください。
[データを保管するバケットの作成( Object Storage の製品ガイド)](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-getting-started-cloud-object-storage#gs-create-buckets)

:::note warn
バケットは IBM Cloud Logs のインスタンスと同じリージョンに作成しましょう。
:::

:::note warn
同じバケットをデータ・バケットとメトリック・バケットの両方に使用することはできません。（同じバケットを選択すること自体はできましたが、正しく動いているか判断できませんでした）
:::

## IBM Cloud Logs の設定

設定のため、IBM Cloud コンソールの[リソース・リスト](https://cloud.ibm.com/resources)、もしくは、[可観測性](https://cloud.ibm.com/observe/logging)から IBM Cloud Logs のインスタンスを開きます。

### ストレージの設定
IBM Cloud Object Storage と統合して、ログを保管します。
1. 画面左の「ストレージ」を選択します
2. ログ・データの「接続」を選択します
3. 「サービスの許可」が求められる場合は、内容を確認し、「今すぐ許可」を選択します（ここで追加された設定は、[IAMの許可](https://cloud.ibm.com/iam/authorizations)で確認できます）
4. データ用に作成したバケットを選択します
5. 「接続」を選択します
6. 数分待つとバケットとの接続が完了します
7. ログ・データと同様にメトリック・データもバケットと接続します 

### データソースの追加
今回は検証として、Cloudant のログをプラットフォーム・ログ経由で収集する設定を行います。
まず、ログ・ルーティングの設定を行い、プラットフォーム・ログをCloud Logsに送信するように設定します。
1. [ログ・ルーティング](https://cloud.ibm.com/observe/logs-routing/rules)を開きます
2. マドリッドの「ターゲットの設定」を選択します
3. IBM Cloud Logs のインスタンスを選択し、保存します

次に、Cloudant のインスタンスを作成します。
1. IBM Cloud コンソールの画面上の「カタログ」を選択し、「Cloudant」をキーにして検索します
2. 「Cloudant」を選択します
3. リージョンはマドリッドを選択します
4. プランや名前などを選択し、「作成」します
5. リソース・リストで Cloudant のインスタンスが作成されたことを確認します

:::note warn
IBM Cloud Logs に対応しているプラットフォーム・ログを生成するサービスは限られています; [プラットフォーム・ログを生成する IBM Cloud サービス](https://cloud.ibm.com/docs/logs-router?topic=logs-router-cloud_services)
:::

## IBM Cloud Logs のダッシュボード

1. IBM Cloud コンソールの[リソース・リスト](https://cloud.ibm.com/resources)、もしくは、[可観測性](https://cloud.ibm.com/observe/logging)から IBM Cloud Logs のインスタンスを開きます
2. 「ダッシュボードを開く」を選択します
3. ダッシュボードのメニューから「Explore Logs」 > 「Logs」を開くと、収集されたログが確認できます

## 参考情報
- [IBM Cloud Logs の製品ガイド](https://cloud.ibm.com/docs/cloud-logs "IBM Cloud Logsの製品ガイド")
- [IBM Cloud Log Routing の製品ガイド](https://cloud.ibm.com/docs/logs-router "IBM Cloud Log Routingの製品ガイド")
- [IBM Cloud Logs の Release notes](https://cloud.ibm.com/docs/cloud-logs?topic=cloud-logs-logs-release-notes)
ESP32 を USB シリアルの DTR 信号でリセットする 

ESP32 DevKit などでは、Arduino 環境から書き込みを行うと自動でリセット&書き込みモードとなり、書き込みが終わると再度リセットとなり通常モードに戻る。
調べると、シリアル信号の DTR 信号を使ってリセット信号、RTS 信号を使って書き込みモードにしているらしい。

https://ja.wikipedia.org/wiki/RS-232 より：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/cba203ab-9ecc-57ce-2593-d0e5958ec955.png)

オレオレ ESP32 基板でも同じようにできないかな?

# USB シリアルモジュール

いつも使っている CP2102モジュール。このモジュールは DTR 端子が出ている。RTS 信号も出ているのだけどピンが立ってない。

![IMG_20200218_102556.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/1efa1e2b-38ef-1487-a870-2275f0472945.jpeg)

書き込みモードにするのは以下のように手動スイッチをつけるとして、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f9375991-0e7a-d935-5f63-9f52cbde4692.png)

リセットを、この CP2102 モジュールの DTR 信号を使って自動でできないかな? 

試しにこのように回路を作ってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/c9c6b8d0-1f27-ba4c-dda4-65b47d4cc77c.png)

元々、ESP32 用の遅延起動信号発生回路をこのように組んでました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/092abbf6-6197-88df-f9e8-3a803166938a.png)

ここに DTR を直結しただけです。ちゃんとした回路にするには 1kΩ ぐらいの抵抗を噛ませたほうがいいでしょうね。


この状態で書き込んでみました。

![DS1Z_QuickPrint1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/221ac60b-0a93-ab9f-54f8-4cd80e3c13ff.png)

黄色がDTR信号、水色がESP32_EN信号です。この回路だと2箇所で測っている意味はないですが。


あらかじめ SW4 を押しておき、書き込みが開始されたら SW4 を離すようにします。
波形の通り、書き込みが開始されたら2回のLoパルスが出ています。 書き込み終了時にはパルスが出ていませんが、リセットがかかります。恐らくソフトウェアリセットが効いているのでしょう。


うまく遅延回路とか作ってやれば、DTR信号のみで書き込みモードにもできそうですね。
3Dスキャナーを使用したバイクのフロントガラス修正

導入
オートバイのフロントガラスは、ライダーの快適性と安全性を提供する上で重要な役割を果たします。しかし、市販されているフロントガラスのサイズや形状は限られており、すべてのライダーのニーズを満たすことができません。この問題を解決するために、私たちは 3D スキャナー技術を使用してオートバイのフロントガラスを変形することにしました。以下は私たちの技術的な実践と探求です。
![d660aca5a5dc9e593ac05629f8945c6f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/f55c06d0-2cd7-257d-5ff7-17f76c6f778f.png)

一般的なワークフロー
1. スキャン前の準備作業: 修正の目的とニーズを決定します: まずお客様とコミュニケーションをとり、フロントガラスに対する期待と改善点を理解します。
バイクの準備: 正確なフロントガラス形状データを取得するには、スキャンする前にバイクが安定した位置にあることを確認する必要があります。
2. 適切な 3D スキャナーの選択: ハードウェアの選択: プロジェクトのニーズと予算に基づいて、フロントガラス表面の詳細な形状をキャプチャできる高精度 3D スキャナーを選択しました。
ソフトウェアの選択: スキャン データを処理および分析し、編集可能な 3D モデルを生成できるプロ仕様の 3D スキャン ソフトウェアを使用します。 
3. フロントガラスの 3D スキャン:
スキャンプロセス: フロントガラス表面に沿ってスキャナーを移動させ、完全なフロントガラス形状データを取得します。スキャンプロセス中は、鮮明なスキャン結果を得るために十分な光を確保してください。 データ処理: スキャンが完了したら、ソフトウェアを使用してスキャンデータを処理し、ノイズや不要な詳細を除去し、正確な 3D モデルを取得します。
![433bf0b03707a145ddd3c508f7d04aa3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/2c1a4c1d-ec32-fe22-7e03-e8cb6537c699.png)
![2f9d7652b9d395bdb7b393c8110df32c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/6af420b8-8a2e-02b7-51dc-a73a2cbaaf70.png)
4. フロントガラスの修正設計と分析:
3Dモデル編集：取得した3Dモデルをソフトウェアにより編集し、お客様のニーズに合わせて形状やサイズを調整します。このようにして、パーソナライズされたフロントガラスのデザインを実現できます。機能分析: シミュレーションおよび分析ツールを使用して、空力特性、風抵抗の低減など、改造されたフロントガラスの性能を評価できます。
![d456d868b473b3bc6d32b74207ab152f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/d9b73fda-a97e-5d99-1e05-75f68ed299cc.png)
![3adf175e691471438233f4cf4ca7efb6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/ccb8d3f1-39db-98f3-48bf-fda17980d3d5.png)
5. 製造とテスト:
フロントガラスのプロトタイプの製造: 最終デザインに基づいて、3D プリントまたはその他の製造技術を使用してフロントガラスのプロトタイプを製造します。実機テスト：プロトタイプをバイクに搭載し実機テストを実施します。フロントガラスの効果を評価し、以前のフロントガラスと比較します。

ソフトウェアとハ​​ードウェアの構成:
3Dスキャナー：https://www.revopoint3d.jp/products/standalone-3d-scanner-miraco
データ処理ソフト：Revo scan
デザインソフト：ZBrush

要約する
オートバイのフロントガラスの修正に 3D スキャナーを使用することで、個別のデザインと正確な形状のカスタマイズを実現できます。この技術の応用は、より良いライディング体験を提供するだけでなく、オートバイ改造業界により革新的な可能性をもたらします。
Teams会議でWindowsの通知音に邪魔され会議音声が途切れる事象の解決方法

### 初投稿のため練習もかねて先日遭遇した厄介なトラブルに関する小ネタを書いてみます。

## タイトルの事象が発生したときの状況
・複数のワイヤレスイヤホンを持っている
・たまにモニターやPCに内蔵のスピーカーからも音を出している

上記の環境でTeamsのオーディオ設定の音声出力先をよくいじっていたのですが、ある日を境にとあるイヤホンを接続したときだけタイトルの通りWindows通知音に会議音声が負けて聞こえなくなるという事象が発生しており、なかなかのストレスを感じておりました。

## 何が困るか
会議中にちょっと声の小さい人がいるときなどに音量を変更するとPCから **「ポローン」** のような音がして会議音声が聞こえなくなります。
また、会議中に入ったTeamsチャットや受信メールの通知音にも負けます。
通知音を切ったら解決はするのですが、それだと会議中以外も通知に気付きにくくなります。

## 解決方法
分かってしまえば完全に自分のせいでした。
私のイヤホンのうち、Soundcore Liberty Air 2というものを仕事でよく使っています。

※もっといいイヤホンも持っていますが寿命を減らしたくなく仕事では主に安いものを使用しています。（完全な余談）

そのSoundcoreを仕事で利用しているPCに接続してオーディオ設定を開くと
・Soundcore Liberty Air 2(ヘッドホン)
・Soundcore Liberty Air 2(ヘッドセット)
という二つが表示されており、違いがわからずどっちでもいいだろうと適当に使っていたのですが、そこに問題がありました。
![オーディオ設定画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693926/af0a4761-b81a-c0f7-fdcd-a4f83ec3f733.png)



ヘッドホンと記載されているほうで接続すると、音声入力が1系統になるようで「会議音声＋通知音」という鳴らし方ができないようでした。（音楽の再生用途のため…？）
ヘッドセットというほうに接続を切り替えた結果、会議中に各種通知音を鳴らしても会議音声が途切れることなく聞こえました。

## まとめ
PC側の設定をいろいろいじっても直らず、社内サポートデスクまで問い合わせを上げておいて最終的には自己解決するという、なんともお恥ずかしい話でした。
ただ、この事象ってワイヤレスイヤホンを使う人なら普通に遭遇するようなことだと思ったので記事にしてみました。
ワイヤレスイヤホンってなぜか選択肢複数出てくることありますよね？（Stereoか、LのみRのみなど）
いろいろ考えて使わないといけないという教訓になりました。

それでは良い一日を。
なんだか助かる便利なおっちゃんになりたい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426622/b03ab1a9-c7c3-6518-16f8-1416f7d46452.png)

## これまでの生存戦略

それほど尖った能力や知識がない中で、私のこれまでの生存戦略としては求められればなんでもやる、少しくらい泥水でも飲むというものでした。

フロントエンドからバックエンド、データベース設計、API設計、実装、インフラ側の設定、提案書作成、プレゼンテーション、プロジェクト進行、どれも“専門家として誇れるか”というと疑問がありますが、求められればなんでもやるスタンスでそれが自分の価値提供の形と考えていました。

また、以前までは「若い」というのも、強みでした。
一回りほど上の年齢に見られることも珍しくなく、「そんな若かったのか」と驚かれるなかで、「若いのに頑張ってるね」と年齢のフィルターで大目にみてもらえました。

しかし、そんな私も気が付けば40歳、もう若さという武器はありません。
（つい先日まで20代だったはずなのに..何かおかしい..）

体力的にも無理が効かず、新しいことを学ぶ力や記憶力の衰えも感じはじめました。

## 人工知能が仕事を奪う

最近の仕事では、GitHub Copilotを用いて、AIに書いてほしいコードを伝える意味でコメントを書いては生成したものを修正して、思い通りにならない場合は自分で書き直して、というような進め方をしています。

プログラミング時にサジェストされるもの採用率はおおよそ50%くらいで、以前までの半分くらいしかコードを書いていないと言えます。
（Copilotが意図通りにコードを吐くように、コメントを入れたり、冒頭を書き始めたりするので、プログラミングという行為自体のアプローチが変わったともとれます。）

ChatGPTに依頼したほうが早い作業やコード生成はChatGPTに依頼することもあります。

下記の「ChatGPTと一緒にWebサイト制作」シリーズでも対話しながらプログラムコードを作成しました。

* [ChatGPTと一緒にWebサイト制作① 調査編](https://qiita.com/koji-yamauchi/items/1615a7479d482b899fee)
* [ChatGPTと一緒にWebサイト制作② ヒアリング編](https://qiita.com/koji-yamauchi/items/e01bb5b59917545a1dea)
* [ChatGPTと一緒にWebサイト制作③ UML編](https://qiita.com/koji-yamauchi/items/774d0d7a445ae8562052)
* [ChatGPTと一緒にWebサイト制作④ サイトマップ作成編](https://qiita.com/koji-yamauchi/items/4dd67868dc5b0bf903c3)

上記の記事の中でもわかるように、現時点では自力でそのコードを書く能力がある人ではないと使いこなすことは難しい状況です。

しかし、改善したい課題や欲求が明確な場合、具体的な手法がイメージできていなくてもAIと協力しながら成し遂げられる世界は、もうすぐそばに来ていると感じています。

すなわち、クライアントが我々のような専門家に依頼する機会やインセンティブが大幅に減ることが予測されます。

![iceceamshop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426622/25c89ebc-216d-3634-486a-a01bf42b06f7.png)



## これからの生存戦略

時代の急速な変化の中、「もう、生きていくには気のいいおっちゃんを目指すしかないな。」と言うことがあります。
これは半分冗談で、半分本気です。

プログラムのコードや中間成果物のアウトプット自体の価値が今後さらに低下するのは免れません。

## 目指している人物像

今後のキャリアプランとしては、下記のような人物像（便利なおっちゃん）を意識しています。

* おっちゃんは自分の仕事に明確な境界を引かない
    * 「みんな時間ないなら、おっちゃんがこの作業やっとくなー」
* おっちゃんは暗黙の期待をせず、言葉に出す
    * 「おっちゃんは、こういうことを期待しているし、やってほしいと考えているけど、この期待を持ったままでいい？」
* おっちゃんはフットワーク軽く具現化する
    * 「考えていることの認識にギャップないか、おっちゃんの考えまとめてみたけどどう？あってる？ほな、来週はちょっと動くモックにしてみせるな」
* おっちゃんはたまにアホな質問をするが、たまにアホな質問が役に立ったり前提を見直す機会につながる
    * 「ごめん、アホなこと言うようやけど、これって実現せなあかんのって何でやったっけ？」
* おっちゃんはうっかりしていることもあるけど、間違いを認められる
    * 「こないだ言ってたやつやけど、よく考えるとおっちゃんが間違えてたわ。ほんまごめんな」
* おっちゃんは困ったら助けを求められる
    * 「ごめん、全然どうしたらいいかわからんくって、知恵かしてくれへん？」
* おっちゃんはいざという時、すごい頑張る
    * 「それは大変やな、踏ん張りどころやとおもうから、おっちゃんも一緒にやるわ」
* おっちゃんは顧客の成功を心から願う
    * 「業務改善につながって、ほんま喜んでたで、嬉しい話やな」
* おっちゃんは沢山の引き出しをもっていて、色々な提案ができる
    * 「もしかしたら開発せんくても、表計算の機能で目的達成できるかもしれんな」
* おっちゃんは周りの成長を喜ぶ
    * 「おっちゃんに出来ひんこと、いっぱい出来るようになって嬉しいし、尊敬やわ」
* おっちゃんはなんだかんだで身銭をきれる
    * 「お、いいよ。飲み行こうか？でも会社のお金はつかえへんから割り勘やで〜」「今日はおっちゃんの話相手になってくれたから払っとくわ〜ありがとうな」
* おっちゃんは嫌な役回りでも買って出る
    * 「依頼した業者さん、全然うごいてくれへんな、約束もやぶってばっかりやし、先方の上司も同席してもらって、おっちゃんが改めて現状の問題とか経緯を説明するな」
* おっちゃんはすぐに夢やビジョンを語る
    * 「このプロジェクトは社会の役に立つし、関係しているみんながちょっと幸せになると思うで」
* おっちゃんは実は自分が不要になることを目指している
    * 「おっちゃんは、おっちゃんはもういなくても大丈夫やで。って言われるのがゴールやと思っているで」

実際には、[無個性を目指している](https://qiita.com/koji-yamauchi/items/60fd5e52f37d0e162d4f)ので、標準語を話す関西人ですが、 **“なんだかいてくれると助かる、便利なおっちゃん”** になれたらなんとか生きていけるのではないかなと考えています。
Railsでのユーザー認証の実装とbcryptの活用方法


## 流れ

### 1. Userのモデルとコントローラーを準備する

```ruby
rails g model user username:string password_digest:string
```

```ruby
rails g controller users
```

```ruby
rails db:migrate 
```

以下のファイルが生成されます：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824310/b76bc216-0e70-8824-13e6-2aa70659953d.png)

`users_controller.rb`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824310/38a56c5c-bb43-6430-b46c-4720f1c0165c.png)
`user.rb`

`user.rb` に以下のメソッドを追加します：

```ruby
class User < ApplicationRecord
  has_secure_password
end
```

### 2. Gemfileにgemパッケージを追加する
```shell
gem 'bcrypt'
```

ターミナルで次のコマンドを入力します：
```shell
bundle install
```

### 3. Railsのインタラクティブコマンドラインに入る

ターミナルで次のコマンドを入力します：
```shell
rails console
```

ユーザーを作成します：
```shell
User.create(username: "suzuki", password: "password123")
```

ターミナルに以下の出力が表示されます：
```shell
  TRANSACTION (0.1ms)  begin transaction
User Create (0.5ms)  INSERT INTO "users" ("username", "password_digest", "created_at", "updated_at") VALUES (?, ?, ?, ?) RETURNING "id"  [["username", "suzuki"], ["password_digest", "[FILTERED]"], ["created_at", "2024-06-26 01:18:17.472828"], ["updated_at", "2024-06-26 01:18:17.472828"]]
TRANSACTION (0.1ms)  commit transaction
=>
#<User:0x000000010c894a38
id: 1,
username: "suzuki",
password_digest: "[FILTERED]",
created_at: Wed, 26 Jun 2024 01:18:17.472828000 UTC +00:00,
updated_at: Wed, 26 Jun 2024 01:18:17.472828000 UTC +00:00>
```

これで、パスワードが暗号化されて保存されました。

## 问题

### 質問1：なぜデータベースのusersテーブルのパスワードフィールドはpassword_digestですが、ユーザーを作成する際にはpasswordを渡すのでしょうか？

has_secure_password はRailsの内蔵メソッドで、ユーザーパスワードの暗号化と検証を便利に行うための方法を提供します。具体的には、以下のことを行います：

1.  属性処理：モデルに has_secure_password を使用すると、自動的に仮想属性 password が追加されます。この属性はデータベースに保存されません。
password 属性に値を設定すると、has_secure_password はbcryptを使用してパスワードを暗号化し、暗号化された結果をデータベースの password_digest フィールドに保存します。
2. 検証：has_secure_password は、モデルに authenticate メソッドを追加します。このメソッドは、ユーザーが提供したパスワードが password_digest に保存されているハッシュ値と一致するかどうかを検証します。また、password 属性の存在性と長さの検証も自動的に追加されます。
【Flutter】MediaQueryでpaddingが0になる時の対処法

MediaQueryDataのpaddingプロパティを使って、ノッチ部分やステータスバーなどの高さなどを取得できます。
https://api.flutter.dev/flutter/widgets/MediaQueryData/padding.html
ただし、この値はMediaQueryのremovePaddingコンストラクタによってremoveすることができます。

iphone 15 ProMaxでの検証です。
```dart:media_query_test.dart
    return Builder(
      builder: (context) {
        print(MediaQuery.of(context).padding.top); // 59
        return Scaffold(
          body: MediaQuery.removePadding(
            context: context,
            removeTop: true,
            child: Builder(builder: (context) {
              print(MediaQuery.of(context).padding.top); // 0
              return const SizedBox();
            }),
          ),
        );
      },
    );
```
このremovePaddingはAppBarやSafeAreaなどを使用した時に使われます。
```dart:scaffold.dart
  void _addIfNonNull(
    List<LayoutId> children,
    Widget? child,
    Object childId, {
    required bool removeLeftPadding,
    required bool removeTopPadding, // Scaffoldのappbarプロパティがnullでない時にtrue
    required bool removeRightPadding,
    required bool removeBottomPadding,
    bool removeBottomInset = false,
    bool maintainBottomViewPadding = false,
  }) {
    MediaQueryData data = MediaQuery.of(context).removePadding(
      removeLeft: removeLeftPadding,
      removeTop: removeTopPadding,
      removeRight: removeRightPadding,
      removeBottom: removeBottomPadding,
    );
    //　割愛
  }
```

よって、AppBarを設定している場合は、Scafolldの子Widgetでは以下のようになります。
```dart:media_query_test.dart
    return Builder(
      builder: (context) {
        print(MediaQuery.of(context).padding.top); // 59
        return Scaffold(
          appBar: AppBar(),
          body: Builder(builder: (context) {
            print(MediaQuery.of(context).padding.top); // 0
            return const SizedBox();
          }),
        );
      },
    );
```

ではもし、appbarを指定したScaffoldやSafeAreaの子Widget内で値を取得したい場合はどうすれば良いでしょうか。

1\. 親が取得したpaddingを子Widget内で使用する。
```dart:media_query_test.dart
    return Builder(
      builder: (context) {
        final topPadding = MediaQuery.of(context).padding.top;
        print(topPadding); // 59
        return Scaffold(
          appBar: AppBar(),
          body: Builder(builder: (context) {
            print(topPadding); // 59
            return const SizedBox();
          }),
        );
      },
    );
```

2\.MediaQueryDataのfromViewコンストラクタを使用する。
https://api.flutter.dev/flutter/widgets/MediaQueryData/MediaQueryData.fromView.html

```dart:media_query_test.dart
    return Builder(
      builder: (context) {
        print(MediaQuery.of(context).padding.top); // 59
        return Scaffold(
          appBar: AppBar(),
          body: Builder(builder: (context) {
            print(MediaQueryData.fromView(View.of(context)).padding.top); // 59
            return const SizedBox();
          }),
        );
      },
    );
```

1.のやり方だとネストが深くなると大変なところもありますが、2.のやり方だとどこからでもアクセスできるのがメリットかなと思います。

# 最後に
記事を読んで頂きありがとうございました！今回初めて記事を書いてみました。今までは自分の記事など需要があるのかと思っていましたが、ないよりはあった方がいいだろうと考え投稿させて頂きました。

この記事に関しての技術的な指摘はもちろん、記事の書き方について、またはこの記事にかかわらず皆様が記事を書く上で気をつけていることや、初心者の内に知ってればよかったことなどコメント頂けると助かります🙇‍♂️
AIを5倍賢く活用する方法について語る

# 挨拶
皆さんこんにちは！！ヤピ丸です！！

今回は某青い鳥のなれの果てを漂ってた時に興味深い投稿を見つけたのでそれを試してみたいと思います！

# 投稿内容
実際の投稿は参考にURLを記載しておきますのでそちらをご覧ください。

その投稿に書かれていた内容は一言でいうとChatGPTに対して「その回答を改善してください」と繰り返しいうことで、どんどん回答の**クオリティが上昇**するということです！
ちょっと実際に試してみたのでどうなったか語っていきます！

# 結果
### 最初の質問と回答
こんな感じです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/f4bf7678-5b62-86af-2d96-5d4e2159c25f.png)

質問は適当でも大丈夫そうだったので、今回はおいしいラーメン屋さんについて質問してみました！

ここからこのAI君を詰めていこうと思います。
### 一回目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/fc1cb0c9-6d5d-bd12-8613-70fed13b8efc.png)

確かに最初の回答と比べるとおすすめ理由が具体的になっていますね。
この記事の執筆中ちょうどお昼時だったので、かなりおなかがすいています(笑)

### 二回目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/1eefd8c3-5259-ff3f-a786-73a9214ea011.png)

謎の点数が追加されました(笑)これは何の点数なのでしょうか？
あとの変更点は最後の総評文ですが、ここは受け手の好みによって感じ方が変わりそうですね。

### 三回目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/bc3d6cc4-87f1-9a49-2960-fc82fd1b40e4.png)

まるで、ラーメン雑誌やブログ、テレビ番組の宣伝文句のような言い回しになりました！
その道に詳しい人の評価が高いという情報に弱い人は多いと思います。私も弱いです(笑)

### 四回目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/5d71585b-8b2c-98f1-1d94-95e8ddbbed2b.png)

ここでの変化は二回目の変化と似た感じで受け手によって好みが分かれるところとなりそうです。

### 五回目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/e2315bcd-aa94-816c-9f76-405cee8de9b1.png)

音を上げられてしまいました(笑)

### おまけ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/23f20efa-efd9-baec-8079-6abe098c770d.png)

定量的な答えがないものに対して解答を求めるとこうなります。
ChatGPTのAIの特徴的にも、質問の内容的にも答えのある問いに対してやったほうがいい結果が得られそうですね！

### まとめ
今回はChatGPTの回答のクオリティを上げる方法として回答の改善を要求するという手法を見たので試してみました。
人によって賛否が分かれる部分もあると思いますが、回数を重ねるごとに回答のクオリティは確かに上昇していたと思います！
また、ChatGPTのAIの特徴的にも、質問の内容的にも答えのある問いに対してやったほうがいい結果が得られそうですね！
単純な方法でしたが、実際に学習やコードを書いているときや壁打ちの相手として活用するときにも同様の方法で回答のクオリティを上げることができるとおもうので今後も使っていきたいと思います！

# 参照
https://x.com/satori_sz9/status/1805272056055083336?s=53&t=BhkTofcBU0ZtEB9HhJ42Bw
RでGIS（shapefileなどの読み込み）

# データの読み込み

RでShapefileなどのGISデータを読み込むにはsfライブラリーを使用します。
```
library(sf)

# Shapefileの読み込み
shapefile_data <- st_read("path/to/data/hoge.shp")
```


読み込んだshapefileはSimple featureとして定義される。

```
> shapefile_data

Simple feature collection with 9560 features and 6 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: 139.334 ymin: 41.35165 xmax: 148.8944 ymax: 45.55724
Geodetic CRS:  JGD2011
First 10 features:
   N03_001    N03_002 N03_003 N03_004 N03_005 N03_007
1   北海道 石狩振興局    <NA>  札幌市  中央区   01101
2   北海道 石狩振興局    <NA>  札幌市    北区   01102
3   北海道 石狩振興局    <NA>  札幌市    東区   01103
4   北海道 石狩振興局    <NA>  札幌市  白石区   01104
```

ここでは試しに[国土数値情報の行政区域ポリゴン](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-2024.html)を読んでみる。
地物数は9560あり、属性のフィールドは6つあることがわかります。
Geometry typeはポリゴンであることのほかデータ領域の座標（Bounding Box）や座標系（Geodetic CRS）などの情報もわかります。

`変数名$フィールド名`とすると、属性テーブルの各カラムの値にアクセスすることができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/6f660eeb-9774-5610-5776-0a4f455523c3.png)



GeoJSONも同様に読める
```
river_data <- st_read("path/to/data/hogehoge.geojson")

```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/9b0c6821-4a65-622e-3424-7da7f8edc0a2.png)
（ここでは同じく国土数値情報の[河川ラインデータ](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-W05.html)）


# 地図の描画
そのままplotすると属性の各カラムで適当に色分けした図を出してくれる

```
plot(shapefile_data)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/cdc775c1-a6af-948c-7072-5f800cfe1cb6.png)


ggplotで描画するには以下のようにする
```
ggplot(data = shapefile_data) +
  geom_sf()
  ```
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/8c292c70-b94d-0e9c-38ff-a222e5f409b2.png)


特定のカラムで色分けした図を描画するには以下のようにする
```
ggplot(data = shapefile_data) +
  geom_sf(aes(fill = カラム名))
  ```
ここではN03_002のカラムで色分け
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/81731712-cbe5-50b9-a07c-d27238295c54.png)


複数のデータを重ね合わせるには以下のようにする
```
ggplot() +
  geom_sf(data = shapefile_data, fill = "lightgreen", color = "black", alpha = 0.5) +
  geom_sf(data = river_data, color = "lightblue",size =1) 


  ```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/a2f41121-585d-ac05-4866-b11b4c1cd816.png)



# 画像として保存

```
map_plot <- ggplot() +
  geom_sf(data = shapefile_data, fill = "green", color = "black", alpha = 0.5) +
  geom_sf(data = river_data, color = "lightblue",size =0.01) 


ggsave("Hokkaido.png", plot = map_plot, width = 12, height = 8, units = "in", dpi = 600)


```

画像として書き出せた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/063c3916-47ed-a3e4-5805-bd2f8e2efd3c.png)



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/c4888610-240a-34c6-bf0b-dbf4ca96fcf0.png)

pngの他にpdfやjpgにも出力可能。
dpiで解像度を指定できます。
The Ultimate Guide to Building a Winning Digital Marketing Strategy

Conquer the Digital World Your Guide to a Winning Marketing Strategy
Feeling lost in the digital jungle? Don't worry, we've got your compass! In today's online landscape, a strong digital marketing strategy is your key to reaching the right audience and achieving your business goals.
Know Your Why & Who:
Start by defining your brand and target audience. What makes you unique? Who are you trying to reach? Understanding these aspects lays the groundwork for successful campaigns.
Chart Your Course:
Choose the digital channels that resonate with your audience. SEO boosts organic traffic, social media fosters engagement, and email marketing nurtures leads. Consider a mix that aligns with your goals.
Content is King:
High-quality content is the backbone of your strategy. Create valuable content (blogs, videos) that educates your audience and establishes your brand as a thought leader.
Measure & Optimize:
Track your progress with analytics tools. See what's working and adapt your strategy for continuous improvement.
Embrace the Journey:
The digital world is ever-changing. Be prepared to learn, experiment, and refine your approach to stay ahead of the curve.
Ready to unlock your digital potential? This guide sets you on the path to building a winning digital marketing strategy that drives results!
GitHub ActionsでFastAPIテストを自動化

### 単体テストサンプル

FastAPIのテストのためのモジュールTestClientを使って、テストの対象となるFastAPIモジュールに対してテスト用のクライアントを生成します。`test_` で始まる関数は自動的にテストケースとして認識されるので関数名をtest_sampleにします。サンプルコードは下のようになります。

api/tests/test_sample.py

```python
from app import app
from fastapi.testclient import TestClient

client = TestClient(app)

def test_sample():
    response = client.post(
        "/api/test-sample",
        json={
            [
            "test":"requset-sample"
            ]
        },
    )
    assert response.status_code == 200
    assert response.json() == {
        [
            "test":"respons-sample"
        ]
    }
```

まずはローカルで動作確認するためにpytestをインストールして、テストを実行します。

```shell
➜ pytest
========================================= test session starts =========================================
platform darwin -- Python 3.12.0, pytest-8.2.2, pluggy-1.5.0
rootdir: *****
configfile: pyproject.toml
plugins: anyio-4.3.0
collected 1 item                                                                                      

tests/test_get_city_code.py .                                                                   [100%]

========================================== 1 passed in 2.49s ==========================================
```

### 必要なPythonパッケージ

pytestを含めたpyproject.toml（パッケージ管理はryeを利用している）

```toml
[project]
name = "test-sample-api"
version = "0.1.0"
description = "FastAPIテストのサンプルコードです。"
authors = [
    { name = "kyoku", email = "kyoku@mierune.co.jp" }
]
dependencies = [
    "fastapi>=0.111.0",
     # ....(中略)
    "pytest>=8.2.2",
]
readme = "README.md"
requires-python = ">= 3.12"

[tool.rye]
managed = true
virtual = true
dev-dependencies = []
```

### GitHub Actionsワークフローを作成

GitHub Actionsのワークフローを定義し、Pull Requestをオープンしたタイミングで作成したテストコードを走らせます。

.github/workflows/api-test.yml

```yaml
name: Test API

on: pull_request

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
        with:
          lfs: true

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: "pip"

      - name: Install dependencies
        run: pip install -r requirements.lock
        working-directory: api
      - name: Run tests
        run: pytest
        working-directory: api
```

- actions/checkout@v4：Workflowがリポジトリにアクセスする
- actions/setup-python@v5：Pythonの実行環境をインストールする。cacheを指定することによってpip dependenciesのキャッシュを利用してテストを高速化する。
- おまけ：actというツールを利用して、GitHubにアップロードする前にローカルでWorkflowの動作を確認することもできます。M2 Macでテストしたところ`actions/setup-python@v5` がインストールできず、Apple Siliconとの相性がよくないですが、本番のLinuxでは正常に動作します。

https://github.com/nektos/act#act-user-guide
SQLServer2022検証環境用の導入

**1．目的**
自分が何をしたのかあとでわかるように記載する。

**2.SQL Server試用版とSSMSのインストール**
2-1
以下の事前準備をする。
https://learn.microsoft.com/ja-jp/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver16#download-ssms
上記リンクからSQLServer2022をダウンロードする。

https://learn.microsoft.com/ja-jp/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver16#download-ssms
上記リンクからSSMSをダウンロードする。

2-2
ダウンロードしたファイルをローカルPCから仮想PCにコピーする。

2-3
SQL2022-SSEI-Eval.exeを仮想PCで実行する。

2-4
インストール-SQL Serverの新規スタンドアロン...を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824433/a659faef-0963-3bd2-c19f-bd6647d270e8.png)

2-5
Developperを選択し、次へ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824433/02b6e748-56c6-b38e-f1a3-075a00caa665.png)

2-6
同意して次へ。

2-7
チェックを外し次へ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824433/2873ddb3-2aaa-a853-9d3a-ab982b069a34.png)

2-8
警告が出ているが次へ。
(ポートに関しての警告のようなので問題があれば後程見直す。)
警告に出ていた参考のリンクは以下。
https://learn.microsoft.com/ja-jp/sql/sql-server/install/configure-the-windows-firewall-to-allow-sql-server-access?view=sql-server-ver16

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824433/fd3b7dd8-a743-c4e2-8b6c-470d0cec3aeb.png)

2-9
Azure拡張機能のチェックを外して次へ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824433/57c818ac-339c-d7d8-be24-c0a69f8421a8.png)

2-10
今回は以下の構成でインストールする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824433/61d4a7bb-7a2c-cffb-fa04-7a90d5d05545.png)

2-11
他はほぼ既存の設定(認証のみ混合)でインストール。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824433/4eb5dab0-7c40-7139-0ff5-7c7ab9d2d36f.png)

2-12
SSMS-Setup-ENU.exeを実行し、Installを選択する。

以上。
Deck.GLでPMTilesを読み込んで表示したい時に遭遇した事象についての解決策

# はじめに
この記事では[Deck.GL](https://deck.gl/)と[PMTiles](https://github.com/protomaps/PMTiles)が何かという説明はしません
Deck.GLでPMTilesのデータを表示しようとする時にどういう事をする必要があるのか
ある現象が発生してはまっていたのですが、[CTO](https://qiita.com/Kanahiro)に助けられましたので、その備忘録になります

# 参考にした記事
https://gunmagisgeek.com/blog/deck-gl/8323

実装にあたっては「日本でDeck.GLといえば」のshimizuさんの記事を参考にさせていただきました
他、色々と非公式なライブラリーは出ているのですが、基本はこの方式になるかと思います

# 方法
最新版のloaders.glでPMTilesを読み込むことが出来るので、Deck.GLのTileLayerで読み込み、PMTilesの内容によって、サブレイヤーで可視化する
という方法を取ることになります
データがベクターの時はGeoJsonLayer、ラスターの時はBMPLayerをサブレイヤーとして可視化を行います
TileLayerとかMVTLayerのみで可視化まで出来ないのはポイントかと思います

ここまでの実装は[shimizuさんの記事](https://gunmagisgeek.com/blog/deck-gl/8323)で確認できるかと思います

# 問題発生
この方法を取って可視化をさせようとしたのですが、タイルの表示時に、タイルのバッファーが表示されてしまうという現象が起きました
タイルは切れ目が見えないよう、ある程度バッファーを持っているのですが、TileLayerのみの表示ではなく、サブレイヤーでの可視化となることによって、バッファーの表示処理は自分で行わないといけないということのようです

![スクリーンショット 2024-06-26 14.15.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2788/e4049fd8-7dcc-2952-79a2-eba286f47c40.png)
こんな感じに格子状の模様が出てしまう

# 解決策
この現象を解決するために、[ClipExtension](https://deck.gl/docs/api-reference/extensions/clip-extension)を使います
これは可視化する対象を任意の矩形にクリップできるDeck.GLの拡張機能です

実装はこんな感じになります

```javascript
const tileSource = new PMTilesSource({
    url: "PMTilesの場所のURL"
});

const layer = new TileLayer({
    getTileData: (props) => tileSource.getTileData(props),
    visible: true,
    renderSubLayers: (props) => {
        return new GeoJsonLayer({
            id: props.id,
            data: props.data,
            // タイルの領域でクリップする
            extensions: [new ClipExtension()],
            clipBounds: [
                props.tile.bbox.west,
                props.tile.bbox.south,
                props.tile.bbox.east,
                props.tile.bbox.north,
            ],
            getFillColor: [255, 0, 80, 120],
            lineWidthScale: 1,
            lineWidthMinPixels: 0.5
        });
    }
}
```
バッファを持たないデータを作る、という手もあるかと思いますが、データの汎用性を保つならば実装側で対応した方が良さそうです
Windows WSL2のUbuntu 22.04.3LTSで aws cli がインストールできない場合

そういや WSL2 の Ubuntu 22.04.3LTS の環境に、aws cli 入れてなかったなぁ。ちょっと、`apt install awscli` としてインストールしてみるか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18599/930421cd-9d4e-6424-d985-f09853db3548.png)

あれ、インストールできない。なんでじゃろ。`apt-get update` してもダメだなぁ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18599/6b2bb38a-8fa9-0130-8e24-5c3b7993e8c7.png)

こんな時は、たいてい、apt がパッケージのリポジトリ情報を拾ってくるための `/etc/apt/souces.list` の内容が古いことが理由なんですよね。

つうことで、ネットで調べた情報を元に、こんな風にゴニョゴニョしてみる。

```
sed -ir 's@(archive|security).ubuntu.com@old-releases.ubuntu.com@g' /etc/apt/sources.list
```

/etc/apt/sources.list を確認すると、リポジトリのURLが変わってる事が確認できた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18599/763183f2-84b5-2249-a0c5-decbf0bd94f2.png)

ということで、もいっちょ `apt-get update` して 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18599/f6242a67-205a-bad8-b701-61ed79d72b0f.png)

`apt install awscli` を試してみよう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18599/842e0aa0-7e35-1bfa-e14a-f408a03837bf.png)

おー、エラーにならず、何かしらがインストールされてる。期待が高まる！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18599/cb9d8fb2-b0f1-e76a-e1fb-9e344dfb0b8e.png)

ということで、aws cliがインストールできました。

やったね！チャンチャン（古い終わり方）。
ノーコードでヒートマップを書く。

Webでヒートマップを作りたい場合
本来は、
QGISでヒートマップを作成したり
WebGIS（MapLibre等)にデータを載せて調整して作るのが王道ですが

https://maplibre.org/maplibre-gl-js/docs/examples/heatmap-layer/


以前は、有料だった、BIツールが
GoogleやMicrosoftをはじめ、有料や実質無料、オープンソースも含め、いろんなツールが普及してきました。

今回は、BIツールでヒートマップを書いてみたいと思います。
（WebGISは登場しません。）


## そもそもBIツールとは？

- インプットのデータソースに様々なモノを選べて
- コードを書かずに
- 可視化／分析ができる
ゆえに、報告やレポートの作成が楽になる。
→簡単に可視化出来て、スピード感がでる。


## どんなヒートマップを作るか？

GoogleのLooker Studioを使って
https://cloud.google.com/looker-studio?hl=ja

駅別乗降数データのヒートマップを作ってみたいと思います。


### 使用するデータ

- 国土数値情報の、駅別乗降数データ
    - https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-S12-v3_1.html#!

こちらの配布形式は、
シェープ、GeoJSONでした。

残念ながらLooker Studioでは、まだシェープやGeoJSONを読むことが出来ないので
QGISを用いて、ダウンロードしたファイルをCSV形式に変換しました。

![スクリーンショット 2024-06-26 13.56.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580547/d1823570-5478-b189-d2c4-b1aaa6773dfc.png)

## では本番
Looker Studioを起動して
空のレポート作成で
まず、使用するデータを追加します。
今回はCSVなので「ファイルアップロード」を選択します

![スクリーンショット 2024-06-26 13.59.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580547/8fa341d3-cb32-b1db-e37e-7dcc2a38b91d.png)

CSVを追加しただけでこの表が出ます。
![スクリーンショット 2024-06-26 14.01.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580547/3a9a4d67-c3fd-e52d-b4a4-f72819bdd942.png)

右側の設定で
どの項目を表示して、どんな順に並べるか選択もできます。
ページングでも表示できています

指標の部分を
乗降客数2021（S12_049）にしておきます。
これをヒートマップで表示したいと思います。

![スクリーンショット 2024-06-26 14.04.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580547/eb17a965-2359-4ceb-75ed-b4ef473eaf54.png)

グラフの追加→Googleマップ→ヒートマップを選択します。
これだけは、ヒートマップを表示する情報が足りないので
- 位置に、駅名（S12_001）
- 重み付けに、乗降客数2021（S12_049）
を指定します。

それだけで、このヒートマップが表示されます。（ズームや中心位置は移動しました。）
![スクリーンショット 2024-06-26 14.17.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580547/ddee7467-223b-3988-5a79-9393a953ac5a.png)

スタイルの設定で
ヒートマップの色や、ぼかし具合も変更できます。

## ポイント
このヒートマップのポイントは、CSVデータ内に緯度経度が無いことです。
位置に使うフィールドには、駅名しか指定していません。
したがって、漢字で一致してしまうのか、一部台湾や香港にプロットされてしまっています。
本来は、緯度経度や、住所で、位置を特定できるデータを設定する方が良いと思います。

## 考察
しかし、ヒートマップを作成するのに
ノーコードで、GUIでポチポチするだけでヒートマップが書けてしまいました。

一般の方が、手持ちのデータを
可視化したい手段としては
すごく簡単に出来ると思いました。
（今回はCSVデータを作るためにQGISを使いましたが・・・。）

他にも地図関連のレイヤタイプは色々あります。
![スクリーンショット 2024-06-26 14.19.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580547/4ea7f614-55ec-d91b-22e5-314ea026f077.png)

細かいカスタマイズをしようとすると、やはり、QGISやWebGISが必要ですが
- 背景地図を変えたい、切り替えたい、複数重ねたい等
- データソースを切り替えたい等
がなければ
初心者が単純なデータを手軽に可視化には、非常に有効だと思います。
GitLab CI/CDの効率化術：ルール設定の覚え書き

GitLab のジョブのルールを書いていて、「あれ、このルールどう書くっけ・・・」となるので備忘録

## ワークフローのルール

workflowは、パイプラインそのものを実行するかどうかを決定するルールです。
workflowのrulesはパイプラインの多重実行を防ぐためこのようなルールにしています。
マージリクエストイベントやスケジュールされたパイプラインのみが実行されるようにすることで、不必要な実行を防ぎます。
```yaml
workflow:
  rules:
    # スケジュールパイプラインの時は常に実行
    - if: $CI_PIPELINE_SOURCE == 'schedule'
      when: always
    # マージリクエストイベントが発生した場合にパイプラインを実行する
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
      when: always
    # pushイベントでマージリクエストが存在する場合はパイプラインを実行しない
    - if: $CI_PIPELINE_SOURCE == 'push' && $CI_OPEN_MERGE_REQUESTS
      when: never
    # 上記に一致しないブランチへのpushではパイプラインを実行する
    - if: $CI_COMMIT_BRANCH
      when: always
    # どの条件にも合致しない場合はパイプラインを実行しない
    - when: never
```

## スケジュール実行のルール
スケジュールなら常に実行
```yaml
  rules:
    - if: $CI_PIPELINE_SOURCE == 'schedule'
      when: always
```
スケジュールなら常に実行しない
```yaml
  rules:
    - if: $CI_PIPELINE_SOURCE == 'schedule'
      when: never
```

## 実行日時のルール

たとえば 9時〜18時(業務時間内)は実行しないとか
```yaml
  rules:
    - if: $CI_PIPELINE_SOURCE != "schedule" && $CI_PIPELINE_CREATED_AT =~ /T(09|1[0-8]):/
      when: never
```
デプロイ環境に影響を与えるような処理で使ったりします。
スケジュールの場合に許可しているのは、どうしても実行したい場合に実行できるようにするためこうしています。

## コミットメッセージのルール
強制的にCIを実行させたりしたい時用
空コミットで、コミットメッセージに `[force ci]` と入れてコミット&pushすることで実行させることができます
```yaml
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /\[force ci\]/
      when: always
```

`git commit --allow-empty -m "[force ci]"` でコミットしてpushすれば実行できます。
※ゴミとして残るので `rebase` で drop しましょう。

---

ほかにも忘れがちなrulesあれば今後追記していきます。
ひたすらCPUとGPUをいじめる

# 総合システム検査テストのたたき台づくり

- 市販ではBurnintestなどありますが、自分たちでどうにかならないとゆうしゅうｎ同僚が制作しているのを見て刺激を受けた
- Ubuntuしか仕事では最近使わないので、ちょっとつくってみる
- Windowsってなんだかんだすごいんだなと思うこともある

:::note info
For your reference 
Regarding the English / CN explanation below link is better for non-Japanese speaker 
:::

En

https://github.com/mi-kaneyon/Ubuntu_loadpower/tree/main

### Cn

https://github.com/mi-kaneyon/Ubuntu_loadpower/blob/main/%E4%B8%AD%E6%96%87.md

# できること (機能追加しました)
![maindisplay2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155177/6ddce916-0f92-5bf1-e1fc-1d370846213a.png)


- テキストボックス内は基本的なCPU情報などを載せています。

**ひたすら負荷をかける**
- α版みたいなものなので特に見どころはありませんが。
- 将来的にはスキルを身に着けてもう少し情報・機能を充実させたい

# セットアップ
- Githubからクローンするとディレクトリ作成したり、ファイルの配置が面倒なので、create_and_move_files.shで対応

```Ubuntu:ターミナル画面

chmod +x create_and_move_files.sh
./create_and_move_files.sh

```

スクリプトの中身はシンプル

```Ubuntu:ターミナル画面

#!/bin/bash

# Create main directory
mkdir -p lin_bench

# Create subdirectories
mkdir -p lin_bench/cpu_load
mkdir -p lin_bench/gpu_load
mkdir -p lin_bench/system_info

# Move files to respective directories
mv main.py lin_bench/
mv cpu_load.py lin_bench/cpu_load/
mv gpu_load.py lin_bench/gpu_load/
mv system_info.py lin_bench/system_info/

echo "Directory structure has been created and files have been moved to their respective directories:"
echo "1. main.py has been moved to lin_bench directory."
echo "2. cpu_load.py has been moved to lin_bench/cpu_load directory."
echo "3. gpu_load.py has been moved to lin_bench/gpu_load directory."
echo "4. system_info.py has been moved to lin_bench/system_info directory."


```

:::note warn
注意
CPU/GPUの負荷ゲージですが、かなり範囲狭いので、近々調整します。＝すぐにMAX負荷状態になる・・・
:::
Claude 3.5 Sonnet 新機能「Artifacts」その２

# はじめに

Claude 3.5 Sonnetは、Anthropic社が2024年6月にリリースした最新の大規模言語モデル(LLM)です。その中でも特に注目を集めているのが、新機能の「Artifacts」です。(今のところ無料版でも使えます）

前回の記事に続き、「Artifacts」を使ってどのようなことが出来るか試し、結果をまとめております。Artifactsの設定方法などは前回の記事に記載してありますので参考にしていただければ幸いです。

https://qiita.com/firesign2023/items/77cfc9cf972ed08b53ca

# 工場管理ダッシュボード

## プロンプト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/d903bcde-771a-9679-1f04-c0c727f48ab3.png)

## 生成されたアプリ

![工場管理ダッシュボード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/6fa60730-14e4-3871-20e4-f23ac9297c64.gif)

# NISA 投資ダッシュボード

## プロンプト

~~~
以下の仕様でWEBアプリを作成してください。
アプリには大きく分けて3つのセクションがあります：
1. 投資サマリー
トータル・リターンのパーセンテージと金額を表示
次の投資日までの日数を表示
次回の投資に必要な金額の表示

2. ポートフォリオの概要
資産配分を示す円形チャート
毎月の投資額
ポートフォリオ総額

3. 次回投資予定日
パフォーマンス追跡
長期的な資産パフォーマンスを示す棒グラフ
各ファンドの保有資産とその損益のリスト

# 主な特徴
ナビゲーションが簡単なホームボタンを備えた、クリーンでユーザーフレンドリーなインターフェース
ポートフォリオの構成を素早く理解するための色分けされたビジュアル
リターンと次の投資要件を自動計算
詳細なファンド情報の閲覧が可能
このアプリは、サマリー、チャート、設定などの異なるビューを切り替えるために、下部のナビゲーションバーを使用することができる。
ユーザーが投資に関する情報を入手し、一貫した投資スケジュールを維持できるよう、明確で実用的な情報を提供することに重点を置く。
~~~

## 生成されたアプリ

# ![NISAダッシュボード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/12a085f2-1fdf-4f62-e95b-fa210ee04f89.gif)



# 終わりに

以下の様なエラーが発生して上手く動作しない場合もありますので、その都度修正してもらっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/50dab39d-3924-0771-237e-88972b1c9b6d.png)

コード量が多くなってくると大変なので、この辺りの修正が楽になるといいですね。
Databricks生成AIクックブック - ステップ6: デプロイと監視

[Step 6: Deploy & monitor — Databricks Generative AI Cookbook](https://ai-cookbook.io/nbs/5-hands-on-deploy-and-monitor.html) [2024/6/26時点]の翻訳です。

:::note warn
本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

> [Databricks生成AIクックブック](https://qiita.com/taka_yayoi/items/36c51bce8f33a70cf204)のコンテンツです。

# ステップ6: デプロイと監視

![](https://ai-cookbook.io/_images/workflow_deploy.png)

これで、あなたの[RAG POCを構築](https://qiita.com/taka_yayoi/items/917a67a4aafe5cb9896a)、[評価](https://qiita.com/taka_yayoi/items/c53863b12652a72d0607)し、[その品質を改善](https://qiita.com/taka_yayoi/items/c1f76a39a43506fe7e33)したので、RAGアプリケーションをプロダクション環境にデプロイすることができます。これは、あなたがパフォーマンスの監視とフィードバックの収集を完了したことを意味しないことに注意することが重要です！デプロイした後でも、データや利用パターンは時間と共に変化するので、品質の継続改善は非常に重要です。

:::note info
Databricksでは、Mosaic AI Agent Servingを用いることで、そのままの状態であなたのチェーンをデプロイすることができます。手順については、[エージェントサービングのドキュメント](https://docs.databricks.com/ja/generative-ai/deploy-agent.html)をご覧ください。
:::

## デプロイメント

あなたのRAGアプリケーションのスムーズなオペレーションと成功を確実にするためには、適切なデプロイメンテが重要となります。以下に、RAGアプリケーションをデプロイする際に注意すべき重要な検討事項を示します:

1. **キーとなるインテグレーションポイントとの特定:**
    - あなたのRAGソリューションをどことどのように連携すべきかを特定するために、既存システムやワークフローを分析します。
    - 特定のインテグレーションがより重要で、他よりも複雑かどうかを評価し、それに合わせて優先度付けを行います。
1. **実装のバージョン管理とスケーラビリティ:**
    - トラッキングとロールバックを容易にするために、あなたのモデルに対するバージョン管理システムをセットアップします。
    - [Databricksモデルサービング](https://docs.databricks.com/ja/machine-learning/model-serving/index.html)のようなツールを活用することで、増加するロードに対応し、効率的にスケールするあなたのデプロイメントアーキテクチャを設計します。
1. **セキュリティとアクセス制御を確実に:**
    - エンドポイントの保護や機微データの防御のように、RAGアプリケーションをデプロイする際にセキュリティのベストプラクティスに従います。
    - 許可されたユーザーのみがあなたのRAGアプリケーションを操作できるようにするために、適切なアクセス制御機構を実装します。

## モニタリング

あなたのRAGアプリケーションをデプロイしたら、そのパフォーマンスを監視することが重要です。現実世界での利用では、事前のテストや評価では明らかにならなかった問題が表出することがあります。さらに、データと要件の変更は、時間と共にアプリケーションのパフォーマンスにインパクトを与えます。以下に、従うべき需要なモニタリングのプラクティスを示します:

1. **メトリクスの監視とロギングの確立:**
    - 精度、レスポンス時間、リソースの使用率のような、あなたのRAGアプリケーションの健康状態と効果を監視するためのキーとなるパフォーマンスメトリクスを定義します。
    - デバッグと改善目的のために、重要なイベント、エラー、ユーザーとのインタラクションを捕捉する包括的なロギングを実装します。
1. **アラートとフィードバックチャネルのセットアップ:**
    - プロアクティブな問題解決を可能にするために、異常や重要な問題を通知するアラートを設定します。
    - RAGソリューションに対するユーザーフィードバックを受け付けるチャネルを提供し、定期的にレビューし、このフィードバックに対応します。
1. **継続的な監視と改善:**
    - 確立されたモニタリングメトリクスを用いて、あなたのRAGソリューションのパフォーマンスを継続的に分析します。
    - あなたのRAGソリューションに対する繰り返しの改善と最適化を推進するために、モニタリングから得られる洞察を活用します。
1. **定期的なヘルスチェックの実施:**
    - ユーザーにインパクトが出る前に、潜在的な問題をプロアクティブに特定、対応するための定期的なヘルスチェックをスケジュールします。
    - 特定のコンポーネントやインテグレーションが問題に対して脆弱で詳細なモニタリングを必要とするのかどうかを評価します。

<br>

- [目次](https://qiita.com/taka_yayoi/items/36c51bce8f33a70cf204#%E7%9B%AE%E6%AC%A1)
- 前のセクション: [データパイプライン修正の実装](https://qiita.com/taka_yayoi/items/fd2f3cd4119184e62ce5)

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
6週間でAZ-104を取得した話

### はじめに
AZ104を取得したので、その体験記を書いていきます。

私は昨年の3月に転職してアプリ開発からクラウド開発へ仕事が変わりました。
クラウドへの知見はとても薄い中での挑戦でしたので、同じ境遇の皆さんに少しでも参考になればと思います。

### 受験前のレベル
+ AZ-900取得済み（2024年3月）
+ Azure経験：2か月
+ オンプレミス設計（NW・MW・OS）：3年
+ Webアプリ設計でクラウドを設計：2年（GCPのFunctionsを少し触る程度）

こんな感じで、Azureは最近業務で触り始めたけど全く・・・といった感じでした。
5月段階では、正直PEって何？LBに種類なんてあるの？ってレベルです。

### 勉強期間
約6週間　総時間は40時間ほど（1日1時間未満の学習ペースでした）

### 勉強方法
AZ-900を取得していたので、幸いサービスの名前を知っているレベルでした。
後は、「問題集解く⇒誤ったところをDocs眺める⇒もう一度解く」の繰り返しです。
+ 問題集
[Udemy 問題集](https://learn.microsoft.com/ja-jp/credentials/certifications/azure-developer/?practice-assessment-type=certification)

こちらのUdemyの問題集を試験問題③まで解きました。
最初に解いたときは40%ぐらいでしたが、7回ぐらい周回して95%以上のスコアになるまで繰り返しています。

+ 参考資料
[MS公式Docs](https://learn.microsoft.com/ja-jp/credentials/certifications/azure-developer/?practice-assessment-type=certification)

基本的にはUdemyの問題集に開設も詳しく乗っており一本で十分ですが、もっと細かいところまで知りたくなったらDocsを活用して確認をしていました。Docsは少し癖があって未だに読むのに苦戦しています。

### 試験前の準備
正直、あまり何もしてません。下記を読んだくらいです。
[MS公式学習ガイド](https://learn.microsoft.com/ja-jp/credentials/certifications/resources/study-guides/az-104)

試験が終わってから知りましたが、MS公式の試験を体験できる環境があるみたいです。私は後述しますが、AZ-900と試験形式の違いにびっくりしたので、やっておいた方がいいかと思います。
[MS公式試験サンドボックス](https://learn.microsoft.com/ja-jp/credentials/certifications/prepare-exam#explore-the-exam-sandbox)

## 感想
### 難易度
問われている知識レベルは、Udemyの問題集と同じ傾向なのでしっかり問題集で対策をしておけば難しくはないです。ただ、「紛らわしい設問」や「多彩な出題形式」に悩まされたのでその点を以下にピックアップしておきます。
#### 紛らわしい設問
そんなオペレーションするの！？という操作を問われたものが難問かありました。例としては、以下のような感じです。
~~~
1. 仮想マシンのバックアップとったよ
2. 仮想マシンの設定いろいろと変更したよ（変更内容が一覧で記載）
3. 1のバックアップに戻したよ
問：2の状態にもう一度したいけど何の設定を変更すればいい？
~~~
日本語を理解するのに5分はかかりました・・・まぁ、そんな問題は少ないので気にせず進めましょう！

### 多彩な出題形式
慣れてなかったので、すごく焦りました。
詳しくは話せませんが、学習の際は以下意識するようにしてみてください。
+ 問題集で出てきた問題について、Azure Portal上での具体的な操作をやってみる
+ Import/ExportやVPN接続など構築の順番（流れ）が重要なものは背景を理解して覚える
+ 前述している「MS公式試験サンドボックス」を利用して慣れておく

### 他のクラウドベンダー資格との比較
別のクラウド資格からAZへ挑戦する方も多いと思いますので、過去に受験した同じレベルのクラウドベンダー資格との比較を載せておきます。
#### AWS認定資格
過去に取得した資格
+ AWS SAA(2022年)　
+ AWS SOA(2022年)

求められるレベル的には同じAdministrator向けの資格なのもあり、SOAと類似していたと思います。難易度としては、問題の多彩さや試験範囲の広さからもAZ-104の方が少し難しくかんじました。試験範囲としては、AZ-104ではMigrationも少し問われるので、ちょうど「(SAA+SOA)×0.75」といった感じでしょうか。

#### GCP認定資格
過去に取得した資格
+ GCP ACE(2022年)
+ GCR PCA(2023年)

ACEやPCAはかなりワンパターンかつ問題集も多く対策がしやすかったですが、AZ-104はGCP認定資格よりも出題形式が多彩で、Udemy問題集通りの問題も体感的に少なかったです。GCP認定資格よりもしっかりと中身を理解して試験に臨んだ方がいいかもしれません。