OmniAICreator/Qiita-1.07M huggingface dataset:
LangChainの新機能「langgraph-engineer」：Agentを作成するためのAgentを作る

最近、GithubでLangGraph（LangChainが提供するエージェント構築用フレームワーク）のアップデートを確認していたところ、LangChainの開発チームが新機能の開発を進めていることに気づきました。現在はまだテスト段階かもしれませんが、試用コードなどはすでに整っているようです。この新機能は非常に興味深いので、共有したいと思います。
名前は⇩の「langgraph-engineer」です。

https://github.com/langchain-ai/langgraph-engineer


現時点ではまだスター数が数十個と少ないため、まだテスト中だと思われます。この機能を簡単に説明すると、agentを作成するためのagentを作るというものです。非常に革新的なアイデアだと思います。

LangChainの開発チームが想定している処理フローは、概ね以下のようになっています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/3ccd318c-3143-ddcc-de7f-95ea7c54f5a8.png)

まず、ユーザーがagentのワークフローを手書きで作ります。その後、マルチモーダルモデルを使用して手書きの結果を認識し、必要な情報を抽出します。次に、LLMが適切なpromptを通じて、抽出した情報をもとにLangGraphのコードを生成します（LangGraphのコードは、ノードやエッジなどの固定要素で構成されているため、promptをうまく調整すれば比較的完成度が高いコードのアーキテクチャを生成することが可能です）。

⇩は、Langgraph-engineerの使用例で生成されたlanggraphコードです。よく見ると、LangGraphの基本構成がほぼ完成していることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/3967f450-2f72-64bd-bb5e-04565953a43d.png)

この”agentを作るagentを開発する”テーマは、今後のAI-agentの分野でかなり流行する可能性が高いと感じています。現時点でのLLMコーディング能力はすでに非常に高いレベルですし、これからさらに性能が向上すれば、将来的にはエージェントの開発に人間が関与する必要性も減少していくと思います。agentを使ってagentを開発することは十分に可能であり、またagentの自己改善も期待できると思います。

関連する記事を調べたところ、中国ではこのテーマで取り組んでいる方が多いようです。例えば、⇩もagentを自動生成するプロジェクトです。

興味ある方ご覧ください：

https://github.com/happyapplehorse/agere
Sprockets::Rails::Helper::AssetNotPrecompiledErrorの解決

# はじめに
railsアプリケーション作成中にJavaScriptを導入しようとした際に、以下のエラーに遭遇したので、メモとして解説します。

# 問題
![スクリーンショット 2024-06-08 18.40.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673202/df1efaa1-dcd9-c68f-22a9-4dd3090f8517.png)


Sprockets::Rails::Helper::AssetNotPrecompiledErrorというエラーが表示されました。

# 解決方法
エラーに書いてある通り、以下のコードをapp/assets/config/manifest.jsに追記

```javascript:app/assets/config/manifest.js
//= link image_preview.js
```

(image_preview)の部分にはそれぞれ読み込みたいjsのファイル名を記述します。

この追記後、サーバーを再起動したら、エラーが解決できました。

# おわりに
エラーに書いてある通りに実行したら、解決できました。
完全にメモなので、また改めてこのエラーの理解を深めたいです。

# 参考
https://qiita.com/sanriyochan/items/99d63e8a8691eb29fa4c
Gitのリモートリポジトリの変更方法

# はじめに
gitlabを移行したことで、ローカルのリポジトリに設定しているリモートリポジトリを変更する必要がありましたのでまとめます。

# 実装方法
リモートリポジトリを変更したいローカルのリポジトリからgit bashを開きます。そして以下コマンドを実行してください。
```
git remote add origin <移行先のリモートリポジトリ>
```
【Vue / パフォーマンス最適化】「v-once」「v-memo」を使って再レンダリングを制御

## 「v-memo」と「v-once」によって解決できる問題

Vueは、大きく以下のような手順で再レンダリングをしています。

1. **データの変更**
OptionsAPIで言うところの`data`、CompositionAPIで言うところの`ref`や`reactive`などの**データオブジェクト**が変更されると、その変更が検出されます。

2. **仮想DOMの生成** 
新しい「**仮想DOM**」を生成します。仮想DOMは、実際のDOMの軽量コピーで、どこが変更されたかを効率的に計算するために使用されます。

3. **差分計算**
（2）で生成された新しい仮想DOMと、その前に生成された仮想DOMを比較して、どの部分が変更されたかを計算します。

4. **DOMの更新**
（3）にて算出した差分を、実際のDOMに対して適用します。（このプロセスは「patch」、「diffing」、「reconciliation」とも呼ばれています）

DOMはツリー状で形成されます。親にあたる要素が再レンダリングされた場合、その子要素も一緒に再レンダリングされてしまいます。

![Screenshot 2024-06-08 at 15.30.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2356280/d5ef02ac-5b34-80ca-b514-6ce04c695bc7.png)

子要素に多くの要素を含む場合、この不要な再レンダリングがパフォーマンスの低下に繋がることがあります。

このような、不要な再レンダリングを制御する為に使用されるのが、今回紹介する「v-once」と「v-memo」です。


# v-once
```vue
<template>
  <h1 v-once>Welcome to my page!</h1>
</template>
```

`v-once`は、それを適用した要素とその子要素にあたるものは全て、**初回のみレンダリングを行い、再レンダリングを実行しない**ようにすることができるディレクティブです。

たとえ依存するデータが変更されたとしても、再レンダリングは実行されないので表示は更新されません。


![Screenshot 2024-06-08 at 16.45.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2356280/cc43a273-5397-1c15-ca35-56826e983481.png)


使い所としては、「`ref`や`reactive`などのデータ更新によって再レンダリングされる必要のない要素」に対して適用します。

# v-memo
```vue
<template>
  <div v-memo="[valueA, valueB]">
    ...
  </div>
</template>
```

無条件で再レンダリングをさせない`v-once`に対して、再レンダリングに条件をつけられるのが、バージョン3.2より利用可能になった`v-memo`です。

指定された配列内のデータが更新された場合にのみ、再レンダリングを実行します。もし空配列を渡した場合は、`v-once`と同様の挙動になります。

大きなコンポーネントの再レンダリングをコントロールするのに便利です。


![Screenshot 2024-06-08 at 16.26.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2356280/0cc5322e-0336-85ef-4f4a-0a5a8a154a44.png)

使い所としては、以下のような`v-for`を用いて作成されたリストに対して使用します。

```vue
<div v-for="item in items" :key="item.id" v-memo="[items]">>
  <p>{{ item.id }}: {{ item.name }}</p>
</div>
```

[公式ドキュメント](https://vuejs.org/api/built-in-directives#v-memo)によると`v-memo`は、1000件を超えるリストに対して使用すると効果を発揮するそうです。

あまり1000件を超えるリストを扱うことは無さそうですが、もし膨大な量のリストを扱う際には`v-memo`の利用を検討してみてください。

> v-memo は、パフォーマンスが重要なシナリオでのミクロな最適化を行うためにのみ提供されており、ほとんど必要ありません。この機能が役に立つ最も一般的なケースは、大きな v-for リスト（length > 1000）をレンダリングするときです

:::note warn
`v-for`と併用する際には、`v-for`を付与した要素に`v-memo`を付与してください。以下のように`v-for`の内部で`v-memo`を使用することはできません。

```vue
<div v-for="item in list" :key="item.id">
  <p v-memo="[list]">{{ item.id }}: {{ item.name }}</p>
</div>
```
:::
親コンポーネント、子コンポーネント発火

親コンポーネントから子コンポーネントの発火とか面倒臭い。
ということでpiniaで管理。

・app.vue で openRequestをする
・user.js の requestDialog が true になる
・userView.vue の モーダルが開く

という流れになる。

```App.vue

import { useStoreUser } from '/resources/user';
const user = useStoreUser();

```


```user.js

    state: () => ({
        requestDialog:false;
    }),

    actions: {

        //userviewでリクエストを送る
        openRequest(){

            this.$state.requestDialog = true;

        },
```

```App.vue

<a @click="user.openRequest()">[子要素を発火]</a>

```


```UserView.vue

<el-dialog v-model="user.requestDialog" title="リクエスト" width="95%">

```
DockerコンテナへのSSH接続ハンズオン

# はじめに
備忘録として、WSL2のUbuntu環境からDockerコンテナへのSSH接続をするハンズオンを書きました。是非とも参考にしてください。
※Dockerのインストール手順は省略します。

# 注意
SSHにはパスワード認証と公開鍵認証の2種類の認証方法がありますが、本記事では公開鍵認証のみを用いています。また、本ハンズオンではrootへのログインを有効にしている等、本番環境下としては適していない設定が一部あります。

# ハンズオン
まずはワークスペースディレクトリを作成し、そこへ移動します。
```
$ mkdir ssh-test-workspace
$ cd ssh-test-workspace
```
***
次に、以下の内容のDockerfileをそのディレクトリ上に保存します。
```Dockerfile:Dockerfile
FROM ubuntu:noble-20240429

# OpenSSHサーバをインストール
RUN apt-get update && \
apt-get install -y openssh-server

# SSHサーバの設定を変更
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config && \
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config && \
sed -i 's/#Port 22/Port 20022/' /etc/ssh/sshd_config

# クライアントの公開鍵をコンテナへコピー
COPY ssh-test-keys/ssh-test-ed25519.pub /root/.ssh/ssh-test-ed25519.pub

# クライアントの公開鍵をコンテナのauthorized_keysファイルへ追記
RUN cat /root/.ssh/ssh-test-ed25519.pub >> /root/.ssh/authorized_keys

# SSHデーモンの起動時に必要
RUN mkdir /var/run/sshd

EXPOSE 20022

# コンテナ作成時にSSHデーモンを起動
CMD ["/usr/sbin/sshd", "-D"]
```
(余談ですが、SSHサーバ設定はsshd_configファイルによって記述されています。そのため、sedコマンドを用いてsshd_configファイルの一部を書き換えることで、イメージのビルド時からSSHサーバ設定を変更することができるというわけなんですね。私もまだまだ駆け出しの身なので、「ああ、そうやってやるんだ...」という感じでした...。~~なんか力業っぽいですよね...。~~)
***
次に、今回使用する鍵を置くためのディレクトリを作成します。
```
$ mkdir ssh-test-keys
```
***
次に、今回使用する鍵を作成します。

```
$ ssh-keygen -f ssh-test-keys/ssh-test-ed25519 -N '' -t ed25519
```

:::note
-fは鍵の名前と保存先、-Nは鍵自体にかけるパスワードを設定するオプションです。
本来はコマンド実行時に入力を求められる項目ですが、このようにオプションとして加えておくことで、一発で鍵を作成することができます。
:::

実行に成功すると、ディレクトリ構成は以下のようになります。
```
.
├── Dockerfile
└── ssh-test-keys
    ├── ssh-test-ed25519
    └── ssh-test-ed25519.pub
```
***
次に、DockerfileからDockerイメージを作成します。
```
$ docker build -t ssh-test .
```
***
次に、先ほど作成したDockerイメージからDockerコンテナを作成し、起動させます。
```
$ docker container run -itd -p 20021:20022 --name "ssh-test-container" ssh-test
```
***
最後に、そのDockerコンテナへSSH接続します。
```
$ ssh -i ssh-test-keys/ssh-test-ed25519 root@localhost -p 20021
```
***
お疲れさまでした。今回のハンズオンで作成されたコンテナやイメージは以下のコマンドを順番に実行することで削除することができます。
```
$ docker container stop ssh-test-container
$ docker container rm ssh-test-container
$ docker image rm ssh-test
```

# (余談)公開鍵をコンテナへ保存する方法あれこれ
当初はssh-copy-idコマンドを用いて楽に公開鍵をコンテナへ保存させようと考えていましたが、このコマンド自体がそもそもSSHプロトコルを用いるせいで、このコマンドを動作させるためにあらかじめ公開鍵をコンテナへ保存する必要が出るというよくわからない状況が発生します...。
> ssh-copy-id uses the SSH protocol to connect to the target host and upload > > the SSH user key.
https://www.ssh.com/academy/ssh/copy-id

パスワード認証を用いたSSH接続からssh-copy-idコマンドを実行させ、公開鍵をコンテナへ渡すといった方法もあるにはありました。ただ、この方法では手間がかかると感じたため、今回はssh-copy-idコマンドを用いることなく、Dockerfile上から公開鍵をコンテナへ渡す形にしました。私はまだまだ経験が浅いため、このssh-copy-idコマンドって便利なのか不便なのかよくわかりません...。

# 参考記事
https://qiita.com/kuboshu83/items/f827ad7068550cded72d
Azure Load Testingをちょっと試したら月額課金された話

# Azure Load Testing とは

Azure Load Testing はフルマネージドの負荷テストサービスです。

https://learn.microsoft.com/ja-jp/azure/load-testing/overview-what-is-azure-load-testing

課金のメーターは次の 2 つがあり、今回の話はロードテストリソースのほうです。

- ロードテストリソース
- 仮想ユーザー時間 (VUH)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402286/9bcddd35-508a-8514-3d81-80a1a937fd1c.png)

最新の情報は公式をご確認ください。

https://azure.microsoft.com/ja-jp/pricing/details/load-testing/

# 失敗談

先日、どんな感じか少しだけ触ってみて雰囲気だけ掴んでその日のうちにリソースを削除したんですが、後日、1,573 円課金されていることに気付きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402286/35b34f81-731c-2477-50a7-7428c1bbca20.png)

価格ページを見直して時間課金でないことはすぐにわかったのですが、今後のためにサポートに問い合わせてみました。要約すると次のとおりです。

- Azure Load Testing はリソース単位での課金体系である
- リソースを作成した時点で月額料金が課金される
- 同一課金月の中で削除/作成を繰り返した場合でも作成の都度課金される
- 例外として、リソースのアクティブ期間が 5 日未満、かつ、テストを実行しないまま削除すると課金されない

例外は誤って作成した時なんかの処置だと思いますが、今回の私のケースみたいにちょっとだけ触ってみて（テスト実行して）すぐに消しちゃたパターンでも 1 か月分課金されますし、再作成してテストするとまた新たに課金されてしまうので注意が必要ですね。

# 反省点

Azure リソースの中には月額数万円かかるお高いものもいくつかありますが、たいていの場合が時間課金なので「ちょっとだけ使ってすぐに消せばいっか」と高を括っていたところがあります。

Azure Load Testing のように時間課金ではないメーターのリソースがあることを意識した上で価格ページを確認しようと反省しました。いずれにせよ、試しに触ってたとは思いますが、すぐに消さなければよかったなぁと。

Azure Load Testing のご利用は計画的に！
［DataSaberへの道①］

### はじめに
はじめまして、やまといいます。\
現在私は、TableauDataSaberチャレンジに挑戦しており、こちらの投稿はチャレンジの一環である「Tableauに関するブログ投稿」というお題があるため投稿しております！

### 自己紹介
私は、2022年卒で大学院を卒業し現在都内にてデータサイエンティストとして働いてます。\
学生時代は、ベイズ統計分野における理論研究を行っておりコーディングやツールを活用して分析やAI構築をするというよりかはノートとペンでゴリゴリ計算する方でした。
今は、社の新たなビジネス創出のためのデータサイエンスをしており同じ分野といえど学生時代に取り組んでいたこととは大きく乖離しているところがあります。社会に出ると私のようなバックグラウンドの人は結構珍しいなと最近思ってます。(←周りのDSは「学生時代からコンペでメダルとってました」、「AIベンチャーでインターンしてました」みたいな人がゴロゴロ、、、）
そういう人達の中で自分のバリューを出すためには、自分も実社会に活かせるDSを学ぼうと思い理論屋としての自分の立ち位置も意識しつつ、日々学習を進めています。

### 本プログラムへ参加したきっかけ
入社してからずっとそういうことを考えていたところ、「Tableau」に出会いました。（名前は聞いたことあったけど、よく知らなかった）。
仕事の中でデータは生物、できるだけ早く正確に分析してアクションに起こさないと価値を発揮が発揮できないもの、だと実感していた中でTableauは素晴らしい製品だなと思いました。

・ユーザーの使いやすさが考えこまれたUIUX
・データ処理速度
・自由度、など

これをマスターして自分の業務内でも有効活用していきたい、そう思ってDataSaberプログラムへチャレンジしました。

### 現在の取組状況
プログラムを開始して、だいぶたってしまったのですが（2024年5月上旬～）、技術課題はすべて完了しました。（技術課題を解いてみて編は次回投稿としたいと思います）
これまで独学で勉強はしていたものの、体系立てられたベストプラクティスやこんな方法あったんだと驚かされるものばかりでした。（1ヵ月前と比べてできること、スピード・質は圧倒的に向上しました。）
もしこの記事を読んでくれている人がいらっしゃいましたらプログラムを始めずとも技術課題にだけでも挑戦するといいかとおもいます！

［参考）私のTableauPublic］
https://public.tableau.com/app/profile/kazuki.yamada/vizzes
【Vuetify】vueバージョンが3.5.16以上だと、v-imgで指定した画像が表示されない

## 結論
以下のとおりvueのバージョンを固定すれば表示される。
```package.json
"vue": "3.4.15"
```
## 現象
以下のように`v-img`を指定し、表示を確認する。
```sample.vue
<v-img
    :src="card.src"
    class="align-end"
    gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)"
    height="200px"
    cover
>
    <v-card-title class="text-white">タイトル</v-card-title>
</v-img>
```

すると、以下のとおり`style="display:none;`となり、画像が表示されない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1106470/5007e311-17ac-2afe-5d83-299604eb6059.png)

力技で`display: block !important;`とCSSを指定しても言うことを聞かない。。。
調べてみると、海外の記事でバージョンが問題となっているところまで辿りつき、解決できました。
> Yes it broke anything using v-show with a transition. Stay on 3.4.15 until it's fixed.

和訳：そう、トランジションでv-showを使うものはすべて壊れてしまった。修正されるまで3.4.15を使い続けてください。


この問題はVuejsのバグです。日本語の記事がなかったので投稿してみました。
同じ問題に困っている方の参考になれば幸いです。

## 参考
https://github.com/vuetifyjs/vuetify/issues/19194
https://github.com/vuetifyjs/vuetify/issues/19191
N100 ファンレスPC  Quieter 4C を使ってみた

ファンレスPC を以前からテーマとして追ってますが、N100のファンレスPCとして割と良さそうな 「HiMeLE ミニPC Mini Quieter 4C 第12世代N100」を使ってみました。



![IMG_20240608_145910.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/66547b76-0cb1-66b4-304a-3d16ed6d276c.jpeg)

# 仕様
- メモリ  16GB
- SSD 512GB 
  - 256GB x 2です
- Windows 11 Pro
- 4K三画面出力

# 外観
本体です。

![IMG_20240608_145858.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/20fd7eba-1d8e-eb38-9ee5-bdbef09d9c36.jpeg)

パッケージ内容。

![IMG_20240608_145825.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d08c6dc6-fee8-9bc5-2561-db0debc16053.jpeg)


背面。電源供給がUSB形状になってますがUSBとは多分違うのではないかな。

![IMG_20240608_145948.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/520a7762-38c4-9dc8-29b7-0c4f2d54bc24.jpeg)


側面。USBx3。
![IMG_20240608_145959.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/1853d138-9d5e-b3d7-452d-6b24b3f54874.jpeg)

# 内部

![IMG_20240608_173518 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/b62dde4e-ca79-cbcb-5940-e0857791737b.jpeg)
![IMG_20240608_173542.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/a2bd9e66-4881-78c4-e14b-ee7a4fbc1787.jpeg)

# 起動してみました。

MS-Windows 11 Pro です。

キーボードがUSになっているのでここで修正しないといけません。
「設定」-「時刻と言語」-「言語と地域」-「日本語」の「…」-「言語のオプション」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/81b1c8f9-34d2-115c-1086-13448a2647c5.png)
「キーボードレイアウト」-「レイアウトを変更する」-「日本語キーボード(106/109 キー)」-「OK」して再起動

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8a7934fb-d92d-9ca7-ecd0-4055d84abb05.png)

ディスクが2つあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/4175d712-41f8-5d06-dace-af757088e632.png)

# Tips

- ブートオプションは F12 とかは効きません
- BIOS起動はDelキーです

#  Ubuntu を入れてみました。
割と熱くなります。40〜50℃ぐらいかな?

インストール中、このようにしてみたら

![IMG_20240608_170739.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/9dfa22a5-fa28-edb0-db25-ee918963c820.jpeg)


![IMG_20240608_170752.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d2a403f0-4d3b-9535-2f95-eb4849be2315.jpeg)

起動時に GRUB で選択できるようになっていました。

![IMG_20240608_172940.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/816b2786-482a-e42b-9757-448221930ab0.jpeg)

無事起動しました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/38a59090-fd3a-8760-6dc2-4da0c841f22b.png)

# ファンレスPC としての評価

中華工業用PCとか、キューブ型とかいろいろ試しましたが供給性の問題、技適の問題、1年で故障が目立つ、など色々問題がありました。


これはコンパクトながらキューブよりは放熱面積が確保できそうです。
特に、ディスプレイの裏のVESAマウントに取り付けしやすいので、そのように立てて使うと埋もれたりせずにエアフローが確保できて放熱に適していそうです。

パフォーマンスも16Gメモリなら、2〜3年でリプレイス前提ならいいのではないかな?

あとは壊れやすさですね。試してみます。

# 今後

このようなファンレスソリューションですが、N100 というパフォーマンスの良いチップで実現したものです。今後このようなチップの発展はどうなるかな? というところですが AI 処理能力の向上がトレンドになるのではにかという気がしていて、このようなパッケージングは今がちょうど美味しいところなのかも知れません。
packettracerの使い方。


1. まず最初。文字の大きさを調整できる。（デフォだと結構小さい。）
1. ![IMG_5467.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/098e523c-07d7-18dc-8b49-76f376ccab19.jpeg)

1. オプションのPrefarenceから、Fontを選択して、アプリケーションのサイズ、CLIのサイズ、インターフェースのサイズを選ぶことが可能。デフォは8だけど、12くらいだとみやすいかも。
1. 下の箇所を選択し、D&Dすることで機器を配置できる。
    1. 電気のマークのところで、ケーブルを選ぶことができる。
    1. クロスとか、ストレートを選択することができる。
    1. MDI同士またはMDIX同士で接続する場合はクロスケーブル。
        1. ただし最近は全てストレートケーブルで渡すのが主流である。
1. 上メニューの削除するボタンで、間違えておいたものを削除できる。
    1. このときカーソルの形が変わる。元のカーソルに戻す時は一番左にする。
1. 一番左の四角のようなもので、通常の選択ができる。


https://hetare-nw.net/archives/40

PCとサーバを、`クロスケーブルで繋ぐ（FastEthernetに繋ぐこと）`すると、緑色の三角がでてくる。これが、` リンクアップ`を表す。

![スクリーンショット 2024-05-26 14.33.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/7436a4ab-0dc7-0020-a590-fb297dc70a4c.png)

これを、ストレートケーブルで繋ぐと、いかのように赤色の三角になる。これが、リンクアップしていない状態である。パケットトレーサーではこのように表示される。
![スクリーンショット 2024-05-26 14.36.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/6158283f-5a9b-00d2-d1ab-c6376bea4168.png)

* ただし、現在のほとんどのPC、ネットワーク機器では`AutoMDI,MDIX`という自動でMDIとMDIXを切り替える規格になっているため、今の機器はストレートケーブルでもクロスでもリンクアップする。ただしパケットトレーサーではしっかりクロスとストレートを区別される。

そして、画面上で表示される機器をクリックすると、いろいろ設定できる。
コンフィグを選ぶと、IPアドレスを選択できる。

![スクリーンショット 2024-05-26 14.41.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/947e5d76-2986-355e-9f7e-8894e69def07.png)

コンフィグのすぐ右のDesktopから、機能を実行することができる。
ここではコマンドプロンプトを選択して、つないだケーブル同士での疎通が確認できるかどうかをみていく。

![IMG_5468.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/8c12f790-ab94-66eb-54a0-e43bfc94d704.jpeg)

コマンドプロンプトからpingを打ってみると、Replyが返ってきているのがわかる。
疎通できないものはタイムアウトしてくるはずである。

![スクリーンショット 2024-05-26 14.48.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/f0c7ea21-0121-12ca-81fd-85a7ee32f3cd.png)

また、ブラウザの機能もある。これを押して、さきほどのIPアドレスを入れてみる。すると、以下のように自動でhttpにリクエストされて、返ってくる。Serverは、すでにwebserverが立ち上がっている。

![スクリーンショット 2024-05-26 14.50.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/afa576b5-9a96-88e0-cefc-fc981c46a396.png)

これで単純なPCとサーバの繋ぎはわかった。

しかし、PC、サーバの接続口が一つしかないので、これでは複数の機器と通信することができない。
そこで、トポロジの中にスイッチを追加してやる。
*トポロジ（NW形態、ネットワーク構成図）のこと。

スイッチは、同じNW内の通信を中継する。MACアドレステーブルを持ち、宛先MACアドレスを見て中継を行う。MACアドレスは、イーサネットのインターフェースを特定するためのアドレス。
スイッチは各ポートから送られてくるMacアドレスを、Macアドレステーブルに格納する。通信の中にある宛先macアドレスを見て、通信を中継する。

## 実際にスイッチを用いたNWを作ってみる。

アクセスポイントは、下部メニューの中の、上部が一番左。その下の部分が右から3番目。そして真ん中にある`AP-PT`というものである。また、タブレットとAPのSSIDを指定することができる。これを同じ名前にすることで無線が接続できる。

スイッチは、上部が一番左。その下の部分が左から2番目。そして、左側にある`2960`というものを選択する。

スイッチ＜＝＞サーバやPCの場合は、ストレートケーブルを選択する。そして、それぞれの機器のIP亜sドレスを指定してあげよう。基本はかぶらなければ問題ない。

*アクセスポイントの配下にあるタブレットは、無線でアクセスする形をとる。

また、今回すイッチにIPをつけていないが、スイッチ自身にpingを送るわけでなければ、IPをつける必要性はない。（実運用の場合はSSHなどすると思うので、いると思うが。）

また、スイッチをクリックし、CLIを選択することで、CLIを開くことが可能。
開いたら、以下を入力する。
```
en
↑で、＃になるはず。

show mac-a
↑で、Tabを押せば補完される。
show mac-address-table

がでてくるはずである。
```
上記のコマンドを実行すると、macアドレスが見えているのがわかる。
音楽の世界：進化とノスタルジアの間

現代の音楽の世界は、まるで万華鏡のように絶えず回転し、進化とノスタルジアの美しい融合を呈しています。一方では、デジタル技術がミュージシャンに表現の場を与え、かつて想像もできなかった方法でリスナーに届く道を開きました。一方では、伝統的なコンサートの個人的なタッチと温かさを求める憧れは依然として強く感じられます。

https://laplantedessinges-streaming.bandcamp.com/album/streamingvf-films-la-plan-te-des-singes-nouveau-royaume-streaming-en-fran-ais-complet

SpotifyやApple Musicのような音楽ストリーミングプラットフォームが業界を席巻し、手頃な価格で数百万曲への無制限アクセスを提供しています。これは、独立系ミュージシャンがグローバルなリスナーにリーチする機会を開き、巨大なレーベルとの契約に縛られることなく音楽を届けることを可能にしました。

音楽のジャンルも進化し続け、新しいサブジャンルやジャンル間のユニークな融合を生み出しています。さまざまな背景を持つミュージシャン同士のコラボレーションが活発になり、新鮮で革新的な音楽作品を生み出しています。

しかし、デジタル化の波の中で、伝統的なコンサートの温かさを懐かしむ人も依然として多くいます。ステージ上でのライブパフォーマンスは、ミュージシャンと観客の直接的な交流を通して、音楽配信では得られない体験を提供します。

https://laplantedessinges-streaming.bandcamp.com/community

音楽祭も再び活発化し、音楽愛好家が直接集まって演奏を楽しむ場となっています。かつて滅亡すると予測されていたレコード、カセット、CDは、今再び人気を集めています。音楽愛好家は、物理的な形式で音楽を収集して聴くことに独特の喜びを見出しています。

現代の音楽の世界は、技術革新と伝統への愛の美しい融合です。ミュージシャンとリスナーは常に適応し続け、愛する音楽を楽しむための新しい方法を探求しています。進化とノスタルジアが手を取り合い、世界中の隅々に響き渡る交響曲を生み出しています。
error: open("node_modules/.bin/loose-envify"): Invalid argumentの対処法

<h2>症状</h2>
Gitから新たにpullしたディレクトリから、データの更新をするために「git add -A」をしたところ、下記のエラーが発生しました。

```terminal:エラーメッセージ
git add -A
error: open("node_modules/.bin/loose-envify"): Invalid argument
error: unable to index file 'node_modules/.bin/loose-envify'
fatal: updating files failed
```

翻訳すると、
```terminal:翻訳
エラー: open("node_modules/.bin/loose-envify"): 無効な引数
エラー: ファイル「node_modules/.bin/loose-envify」のインデックスを作成できません
致命的: ファイルの更新に失敗しました
```

node_modules/binの下にあるはずのloose-envifyが開けないと言っているようです。
構成を確認したところ、bin以下に該当のファイルは存在しませんでした。

<h2>解決方法</h2>
npm installをして解決しました。

Gitからプロジェクトをアップする際に、.gitignoreでnode_moduleがない状態でアップされます。その状態のプロジェクトをダウンロードすると、node_moduleがないプロジェクトがダウンロードされます。

その状態でコードを変更しPUSHして、今回nodeがないよと怒られたみたいです。

<h2>参考</h2>

https://stackoverflow.com/questions/47815353/unable-to-push-to-git-repo-node-package-open-error

https://qiita.com/growsic/items/b2965c0ba3b0aaae1ff8
コルーチンとは？簡単に理解してみる

# はじめに
「コルーチンを使うと◯秒間処理を停止するという動きができる」と聞いてはいましたが、それは実際どうやればできるのか。
そもそもコルーチンってなんですか！という状態からのスタートだったので、とりあえず調べてみました。

## そもそもコルーチンとは。
**途中で停止したり中断したりできる処理の塊**という感じに捉えています。
途中で止められるというのが個人的推しポイントです。

## 基本の書き方

まずはコルーチンの書き方です。

```
 IEnumerator 関数名()
    {
        //処理(なくてもOK)

        yield return null;

        //再開後の処理
    }
```

呼び出すときは、呼び出したいところで

```
StartCoroutine("関数名");
```

と書けばOKです。

途中で処理を止めたい場合には

```
yield break;
```

と書きます。

コルーチン内で別のコルーチンを呼び出すことも可能です。
処理の中に``StartCoroutine("関数名");``を入れてもOKってことです！

ただ処理を止めるだけではなく、◯秒おきに処理を繰り返すということも、コルーチンを使えばできそうですね。

## ○秒おきに処理を繰り返す方法

```
 IEnumerator Repeat()
    {
        _count++;

        yield return new WaitForSeconds(3); //3秒待って再開する

        StartCoroutine("Repeat");
    }
```

変数「_count」が3秒おきに1ずつ増える処理です。

**呼ばれたらまず数を増やす**
**→停止する**
**→停止時間が終わったらもう一度コルーチンを呼び出す**

としました。

今まで似たようなもので、**◯秒後に関数を呼び出す**ことができるInvokeを使っていましたが、まだどちらの方が使いやすいとか、オススメとか、優劣をつけられるほど使いこなせていないので、もう少し色々作ってみたいですね。

## 開始演出を流している間、プレイヤーの入力を反映しないようにする

コルーチンを使えばこういうこともできますね。

①yield retrun〜の前に、入力判定を受けて動いているスクリプトをenable = false;する
②秒数を指定して時間を止める
③再開後にenable = true;の処理を書いて、入力判定があった時処理を行うようにする

今までInvokeしか知らない状態だと開始演出の作り方がわからなくて困っていましたが、コルーチンでは簡単にできます。
お困りの方はぜひコルーチンを使ってみてください。
AWS LambdaでBedrock APIを呼び出す

[link-1]: https://qiita.com/MhalTeddy/items/5fe8d8ace7b48e1fadec "Amazon Bedrock APIの基本"
[link-2]: https://qiita.com/MhalTeddy/items/b8917f72a32ca5d389dc "AWS CLI"
[link-3]: https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html "Lambda Permissions"

## はじめに
生成AIのRAGシステムを構築する前段階として、AWSのLambdaから生成AIモデルを呼び出してみました。
実行ロールの割り当てに引っかかって時間を使ったので、やり方をまとめました。

## Amazon Bedrockの事前準備
まず、AWS CLIをインストールして認証します。
方法は[AWS CLIを使い始めるまで][link-2]に書いています。

次に、Bedrockへのモデルアクセスとトークンの発行を行います。
こちらは、[「Amazon Bedrock API (Claude 3 Haiku)のはじめの第一歩」][link-1]にまとめました。

## Lambda関数の作成
`Lambda`→`Functions`→`Create function`からLambda関数を作ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2039603/9d836f91-ae5a-8bc9-352f-0850308b8de9.png)

`Create function`で関数を作成できたら、関数の設定を行います。
デフォルトではTimeoutが3秒となっていて、モデルの推論時間に間に合わない可能性が高いので、編集してTimeoutの時間を長くします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2039603/6f7e2152-2235-2d9e-da6e-d24c4286415f.png)

## Amazon Bedrock APIを使ってハンドラを実装
`Code`タブに生成AIモデルを呼び出すプログラムを書きます。
プログラムを書いた後、`Deploy`ボタンをクリックするのを忘れないでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2039603/e5d413eb-ae5c-53ba-2972-dc8be6a70ede.png)

プログラム自体は[前回][link-1]で使用したものと同じです。一箇所、プロンプトを引数で受け取れるように設定しています。

```python:lambda_function
import boto3
import json

def lambda_handler(event, context):
    brt = boto3.client(service_name="bedrock-runtime", region_name="ap-southeast-2")
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "messages": [{"role": "user", "content": event["prompt"]}],
        "max_tokens": 300,
        "temperature": 0.1,
    })

    modelId = "anthropic.claude-3-haiku-20240307-v1:0"
    accept = "application/json"
    contentType = "application/json"

    response = brt.invoke_model(
        body=body, 
        modelId=modelId, 
        accept=accept, 
        contentType=contentType
    )
    response_body = json.loads(response.get("body").read())

    return json.dumps(response_body, indent=4, ensure_ascii=False)

```

## ポリシーの割り当て
Lambda関数がAWSの他のサービスやリソースにアクセスするためには、Lambdaに実行ロールを割り当てなければなりません。
Bedrockへのアクセスは、`AmazonBedrockFullAccess`ポリシーを割り当てることで解決します。
まず、Lambdaのロール名が必要なので、`Configuration`→`Permissions`からロール名を確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2039603/20ee0391-1382-cc90-bf43-d71d4959e5be.png)

AWS CLIの認証とアクセスキーの登録を済ませた状態で、ターミナルで以下のコマンドを入力します。下記の`lambda-role-name`のところに、先ほど確認したロール名を入力してください。
```
aws iam attach-role-policy --role-name [lambda-role-name] --policy-arn arn:aws:iam::aws:policy/AmazonBedrockFullAccess
```

## テスト
`Test`ボタンをクリックして、テストを作成します。
テストはJSON形式で書く必要があり、ここで作成したテストは、`lambda_handler`関数の`event`に渡されます。
```:Test
{
    "prompt": "日本固有の料理を教えてください。"
}
```
テストを実行すると、無事に実行結果が得られました。
```:出力プロンプト
"はい、日本には非常に豊かな食文化があります。日本固有の代表的な料理をいくつか紹介します。\\n\\n1. 寿司 - 生の魚介類を酢飯の上に乗せた料理。江戸時代に発祥し、世界的に有名な日本の料理です。\\n\\n2. 天ぷら - 野菜や魚介類を薄く切って衣をつけて揚げた料理。軽くて香ばしい食感が特徴です。\\n\\n3. 蕎麦 - 細長い麺を使った料理。そばつゆに浸して食べるのが一般的です。地域によって味付けや食べ方が異なります。\\n\\n4. 懐石料理 - 季節の食材を使った数種類の小皿料理が特徴の伝統的な日本料理。繊細な盛り付けと味付けが魅力です。\\n\\n5. 焼き鳥 - 鶏肉を串に刺して炭火\"
```

## 参考
[Lambda 実行ロール][link-3]
Dartの継承と実装

他の言語のように継承や実装などを利用しながら、クラスのメンバのアクセス可能なスコープを考えてみる

# 今北産業
- Dartのprotectedの実現例
- DartのFactoryパターン実装例
- Dartの基本的な継承、実装

# protectedなメンバ変数の実現
Dartにはprotectedは存在しないため、スコープをサブクラスに限定したメンバへのアクセスの実現には少し工夫が必要です

## 実装例 抽象クラスで宣言、実装を行う
super classで継承するクラス共通の処理を行いつつ、サブクラスでは独自の実装を行うような設計を行う時にはこのような手段が取れます。

```.dart
abstract class UserRepository {
 User get _user;
 
 int userId() {
  return _user.id;
 }

 String name() {
  return _user.name;
 }
 
}

class HotelGuestUserRepository extends UserRepository {
 @override
 final User _user;

 String guestName() {
   return 'hotel guset ' + _user.name;
 }
 
 HotelGuestUserRepository({required user}): _user = user;
  
}
```


# 少し複雑なポリモーフィズムの実現 Factoryパターン
サブクラスもいくつかの系統に分かれていて、系統ごとに同じinterfaceを定義できる場合、Factoryパターンなどでカプセル化とポリモーフィズムを利用した設計をしたくなるかと思います。

## 実装例

```.dart
abstract class UserRepository {
 User get _user; // ①
 
 int userId() {
  return _user.id;
 }

 String name() {
  return _user.name;
 }
 
}

abstract class GuestUserRepository implements UserRepository { // ②
  String guestName();
}

class HotelGuestUserRepository extends UserRepository implements GuestUserRepository {　　// ③
 @override
 final User _user;

 @override
 String guestName() {
   return 'hotel guset ' + _user.name;
 }
 
 HotelGuestUserRepository({required user}): _user = user;
  
}

class GuestUserRepositoryFactory {
  static GuestUserRepository create({required User user}) {
    return HotelGuestUserRepository(user: user);
  }
}

void main() {
  var user = User(1, 'John Doe');
  GuestUserRepository guestRepo = GuestUserRepositoryFactory.create(user: user);
  print('Guest Name: ${guestRepo.guestName()}'); // ④　出力: Guest Name: hotel guest John Doe　
  print('User ID: ${guestRepo.userId()}'); //　⑤ 出力: User ID: 1 
  print('Name: ${guestRepo.name()}'); // 出力: Name: John Doe
}

```
## 解説
① Userをprotectedのアクセススコープにしたいため、super classではprivateなgetterとして定義する
② Factoryの戻り値型として利用するため、UserRepositoryのinterfaceを実装する
③ super classを継承し、interface定義であるGuestUserRepositoryを実装する
④ ③の実装でGuestUserRepositoryのinterfaceを実装しているのでアクセス可能
⑤ ②の実装でUserRepositoryのinterfaceを実装しているのでアクセス可能


# Dartの実装
DartのInterfaceは抽象クラスでも具象クラスを定義しても生成される

```.dart
// 具象クラス
class User {
 String name;

 User(this.name);
}

// 継承に見えるが実装
class GuestUser implements User {
 @override
 String name; // 具象クラスのnameメンバ変数を実装

 GuestUser(this.name);
}

// 抽象クラス
abstract class User {
 int get id;
 String name;
}

// 継承ではなく実装
class GuestUser implements User {
 @override 
 int id; // 抽象クラスのid getterをproperty実装
 
 @override
 String name; // 抽象クラスのnameプロパティを実装

 GuestUser(this.id, this.name);
}

```

# Dartの継承
```.dart
class User {
 String name;

 User(this.name);
}

class GuestUser extends User {
 GuestUser(String name) : super(name); 
}
```

```.dart
abstract class User {
  String name;
  int get id;

  User(this.name);
}

// 継承
class GuestUser extends User {
  GuestUser(this.id, String name) : super(name);

  @override
  int id; // idゲッターを実装
}
```
Parquet形式について サイズ編

# はじめに

ちゅらデータ株式会社 システムエンジニア きたっぴです。  
以前より、データロードの際はスキーマ情報も保持しているParquet形式で受け渡しを行う手段があるという事は知ってはいましたが最近読んだ「クラウドデータレイク」にて登場したDelta Lake、Apache Icebergのベースとなっている技術ということなので今回改めてParquet形式とはなんぞやを学ぶこととしました。

https://www.oreilly.co.jp/books/9784814400676/

# Parquet形式とは

 - カラムナーストレージフォーマット
     - 列指向フォーマット。そのため、行指向フォーマットより高速に分析を行うことができる
 - csv形式で保存するよりもファイルサイズが小さい
     - 圧縮、エンコーディングによりファイルサイズの削減に成功している

 端的に言えば、テキスト形式では閲覧できない形式であるがcsvファイルより軽量化され、分析を行う際も高速になる。いいことづくめのようだ。

 以下、今回はカラムナーストレージフォーマットについての第一印象、及び調査結果を記載したいと思う。

 ## カラムナーストレージフォーマット
 列指向フォーマット。parquet形式では、指定可能な数の行グループに分割してデータは保存されている。その上で分割された列グループのデータを「カラム単位」で記憶を行っているため特定のカラムを利用した分析の際に不要なカラム情報を無視することが可能になり、高速の分析が可能となる。

 説明を初めて読んだ際は行グループでの分割であれば行指向なのではないかと感じたがその後に行グループ内のデータの記憶方法が「カラム単位」という事で、分析時にカラム毎の取得ON/OFFが可能となるためこれは列指向であると考える。

 行グループの分割数のメリットデメリットについても調査を行ってみた。
 |特徴|細かく分割する場合|分割しない場合（大きな行グループ）|
 |--|--|--|
 |クエリ性能|向上（プルーニングが効果的）|低下（不要なデータの読み込みが発生）|
 |並列処理性能|向上（並列処理が容易）|低下（並列処理が難しい）|
 |メモリ使用量|削減（小さなデータ量を読み込む）|増加（大きなデータ量を読み込む）|
 |メタデータのオーバーヘッド|増加（メタデータが多くなる）|削減（メタデータが少なくなる）|
 |書き込み性能|低下（書き込み操作が頻繁）|向上（書き込み操作が少ない）|

 このあたりは一長一短あると思うのでデータソースの内容、及び分割方法によって分割サイズを考えることになるのだと思う。

 ## ファイルサイズ
  csvファイルよりもサイズが小さくなるようだが本当か？100万行のデータを用意して比較を行ってみた。
  |形式|サイズ|
  |--|--|
  |csv形式|約30MB|
  |parquet形式|約50MB|

  あれ？想定ではparquet形式の方がファイルサイズが小さくなくてはいけないはずだが何故だろう。

  実は上記の作成時にはparquet形式作成時に各20行の行グループに分割していたためサイズがcsvより大きくなっていたと思われる。
  行グループを1つとしてparquet形式で作成した場合の結果を合わせたものが下表になる。
  |形式|サイズ|
  |--|--|
  |csv形式|約30MB|
  |parquet形式(20行での行グループ)|約50MB|
  |parquet形式(行グループ1つのみ)|約9MB|

  # 最後に
  ネット上で記事を読み漁ったレベルではparquet形式で保存することでファイルサイズは小さくなるもの。という理解だけであったが行グループの分割ルールによってはcsvより大きくなることもあることが分かった。理由としては、圧縮によるサイズ減の効果より行グループごとに定義しているメタデータが多く必要になったサイズ増の効果が上回ったものと思われる。
  今回は、行グループの違いによる分析結果の差まで手が回らなかったがどれだけの違いが出るか試してみたいと思う。
webの基礎まとめ

学習記録です。

## HTTPリクエスト　HTTPレスポンス
### HTTPとは
webサーバーとクライアントの間で「どのように情報をやり取りするか」という取り決め(プロトコル)のこと。
URLの先頭に「http://」と書いてあるのは、HTTPプロトコルを使用してサーバーと通信することを通達するため

webページがブラウザに表示されるためには**リクエスト**と**レスポンス**が必要になる
👩‍💻：クライアント(情報を要求する側、通常ウェブブラウザ)
:globe_with_meridians:：サーバー(情報を提供する側、通常ウェブサーバー)

### リクエスト
👩‍💻　→→→→　:globe_with_meridians:
クライアントからサーバーに対して「〇〇のwebサイトをください」と要求すること

### レスポンス
:globe_with_meridians:→→→ 👩‍💻
サーバーからユーザーへ〇〇のwebサイトが返ってくること

【一連の流れ】
1. **クライアントがリクエストを送信**
クライアントがURLを入力するとHTTPリクエストが生成され、サーバーに送信される
1. **サーバーがリクエストを受信**
サーバーは要求されたHTMLや画像などを準備する
1. **サーバーがレスポンスを返す**
レスポンスをクライアントに送信(レスポンスには、要求されたデータだけではなくステータスコードやヘッダー情報が含まれる)
1. **クライアントがレスポンスを表示**
クライアントは受け取ったレスポンスを処理しユーザーに表示する
これによりHTMLがブラウザに表示される

## URLの全体構造
インターネット上でリソース（ウェブページ、画像、動画、ファイルなど）の場所を特定するためのアドレスのこと。
プロトコル、ホスト名、パス(エンドポイント)、クエリパラメータなどで構成されている。
### エンドポイント
エンドポイントは、APIサーバー上のリソースの場所を特定するURLの一部。
エンドポイントはHTTPメソッドと一緒に使用され、具体的な操作（取得、作成、更新、削除など）を実行する
```
https://api.example.com/v1/users/123?include=details
```
上記のURLの中で`/v1/users/123` がエンドポイントに当たる。
例えば、HTTPメソッドが
**GET**の場合は、**IDが123のユーザー情報を取得**
**DELETE**の場合は、**IDが123のユーザー情報を削除**
となる

### HTTPリクエストメソッド
エンドポイントに対して行う具体的な操作を指定するためのもので、適切なものを使用する必要がある
| メソッド名 | 説明 |
|:----------------|:----------------|
| GET | データを取得する |
| POST | データの登録|
| PUT | データの登録/更新（リソース名を指定する） |
| DELETE | データの削除 |
| PATCH | データの一部変更 |

**PUTとPATCHの使い分け**
`PUT`はデータを完全に上書きしたい場合
`PATCH`はデータの一部だけを更新したい


## API
APIとは「Application Programming Interface」のことで、webサービスやソフトウェアの機能を別のwebサービスやソフトウェアから呼び出せるようにしたもの。
**活用例**
- 自社のサイトにGoogleマップのAPIを導入することで常に最新の地図を掲載できる
- 自社サイトで商品購入の際にAmazonPayを導入することでクレジットカード等の個人情報を持たずに決済ができる


## JSON
ウェブサービスやAPIなどでデータを送受信する際の標準的なフォーマット。
**書き方**
`key(名前):value(値)`の形で記述

```JSON:例
{
  "name":"山田太郎",
  "age":20
}
```
テストを実行すると`Jest encountered an unexpected token`になる


# 事象
GPTに聞いても解決しなかったので備忘録として書き出します。

`npm run test hogehoge.ts`

### エラー

```
  ● Test suite failed to run

    Jest encountered an unexpected token // エラーになる

    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

      By default "node_modules" folder is ignored by transformers.


      ^^^^^^

    SyntaxError: Cannot use import statement outside a module
~~~~~~~~~~
    > 2 | import axios from "axios";
        | ^
```

# 解決方法
結論から言うとAxiosがcommonjsからEMSでビルドされるようになったからみたいです。

`jest.config.js`を書き換えます

```jest.config.js の抜粋
 moduleNameMapper: {
    '^axios$': require.resolve('axios'), //追加
  },
```

再度実行すると、、、、成功！！！

### 文献
ここで議論していました。確かに私も同じようにupdateしたあとに発生しました。
https://github.com/axios/axios/issues/5101
【Swift】ファイル操作を簡単にするための extension を作ってみた

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【Swift】ファイルやディレクトリ操作するための extension をまずは作った<br>👉 <a href="https://t.co/Z2zVpDvLkH">https://t.co/Z2zVpDvLkH</a><a href="https://twitter.com/hashtag/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0?src=hash&amp;ref_src=twsrc%5Etfw">#プログラミング</a> <a href="https://twitter.com/hashtag/Swift?src=hash&amp;ref_src=twsrc%5Etfw">#Swift</a> <a href="https://twitter.com/hashtag/ios?src=hash&amp;ref_src=twsrc%5Etfw">#ios</a></p>&mdash; chanzmao (@maochanz) <a href="https://twitter.com/maochanz/status/1799962181070692611?ref_src=twsrc%5Etfw">June 10, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


```swift
FileManager.default.showContents()

// /HOME/Documents/ 
// /HOME/Documents/another/ 
// /HOME/Documents/another/copied.txt [6 bytes]
// /HOME/Documents/some/ 
// /HOME/Documents/some/copied.txt [6 bytes]
// /HOME/Documents/some/moved.txt [6 bytes]

```

なるべくシンプルなのでいい。

```swift
FileManager.default.showContents(.temporaryDirectory)

// /HOME/tmp/ 
// /HOME/tmp/.DS_Store [6 kB]
// /HOME/tmp/CFNetworkDownload_1Ji1Ym.tmp [1.8 MB]
// /HOME/tmp/CFNetworkDownload_3ravkG.tmp [1.8 MB]
// /HOME/tmp/CFNetworkDownload_ArezWZ.tmp [1.8 MB]
// /HOME/tmp/CFNetworkDownload_Q2vc3J.tmp [920 kB]
// /HOME/tmp/CFNetworkDownload_WnW3m7.tmp [1.8 MB]
// /HOME/tmp/CFNetworkDownload_s4wpzr.tmp [1.8 MB]
```

 https://zenn.dev/maochanz/articles/0cc5fa1731fed6
 
# 🧑🏻‍💻 参考

https://android.benigumo.com/20240608/file-ex/
VSCodeで "code ."が効かないとき

# VSCodeで"code ."が効かない

```bash
code .
```
通常、VSCodeはターミナルで上記コマンドを実行すると実行したディレクトリでVSCodeが新しいウィンドウで開かれます。これが規定の動作です。しかし原因は色々ありますがこれが有効になっていないときがあります。

この投稿ではターミナルで`code .`を実行したときに、実行したディレクトリでVSCodeが新しいウィンドウで開かれるようにする方法を説明します。

なお、`macOS`を使っている前提です。

## 実行したディレクトリをVSCodeで開くには

下記の2つの設定を見直すことで改善されます。

1. VSCodeの設定を変更し新しいウィンドウで開くようにする
1. Pathが通っているか確認する


以下で一つずつ見ていきます。

## VSCodeの設定を変更し新しいウィンドウで開くようにする

VSCodeの設定画面を開き、下記のように設定を変更します。

この結果、「メニュー > フォルダーを開く」 で、VSCodeが新しいウィンドウで開かれるようになります。

```json
{
    "window.openFoldersInNewWindow": "always",
    "window.openWithoutArgumentsInNewWindow": "on"
}
```

## Pathが通っているか確認する
VSCodeのPathの設定が不十分なことも考えられます。下記のコマンドを実行し設定を確認します。

1. VScodeを開く
1. コマンドパレットを開く（ctrl + shift + P）
1. `Shell Command: Install 'code' command in PATH` を選択

→ successfully が表示されればPathは通っていると考えられます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102978/385b5407-8559-74e9-1520-f82e4395facb.png)


以上です。
Rocky Linux 9 でPHPを8.0から8.2にアップグレード

テスト用マシンにRocky Linuxを入れてからけっこう経ってしまって、そう言えばアップグレードを怠ってたな、ということで覚書を兼ねて。
```
# dnf -y upgrade
```
全408モジュール、814ファイルものアップグレードがあった。サボりすぎ。

ところでPHPのバージョンは、というと
```
# php --version
PHP 8.0.3 (cli) (built: Aug 3 2023 17:13:08) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.0.30, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.30, Copyright (c), by Zend Technologies

# dnf module list php
Rocky Linux 9 - AppStream
Name              Stream             Profiles                               Summary
php               8.1                common [d], devel, minimal             PHP scripting language
php               8.2                common [d], devel, minimal             PHP scripting language
```
8.2が最新らしい。8.0で不自由してないし8.1やら8.2の最新機能を使うことも当分ないと思うが、8.2でDeprecatedの機能を使っているわけではないので一応アップグレードしておこう。
```
# dnf -y module install php:8.2
```
からの
```
# php --version
PHP 8.2.13 (cli) (built: Nov 21 2023 09:55:59) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.2.13, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.13, Copyright (c), by Zend Technologies
```
でおしまい。

追記。
PHPのスクリプトを書くときにAdobe Dreamweaverを使ってて、構文チェックを自動でしてくれるので助かっているのだが、未だに7.1までしか対応していない。なので例えば8.0から使える```match```が入ってたりすると警告を出してくる。なんとかなりませんかねえ。

ところで、別システムでPHP8.1→8.2を同手順によって実行しようとしたところ
> エラー: 設定オプション module_stream_switch から明示的に有効化されていない限り、モジュールの有効なストリームを切り替えることはできません。

とのエラーが。この場合は
```
# dnf -y module reset php:8.1
```
をやってからでないと8.2にならなかった。
SpringBootで静的なcssやJavaScriptのファイルを扱う

# この記事はこれの続きです

https://qiita.com/waokitsune/items/25e7712c5bcd96c8bae7

# 静的なファイルを置いておくフォルダー作成

**パッケージではなくフォルダー** というのがポイント。

『src/main/resources』直下にフォルダー作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/80337334-1d39-a97e-fd9b-dea7ea41b313.png)

フォルダー名は『static』。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/59428758-002a-49e0-ef16-c9faa337112e.png)

# 静的なファイル作成後はこちら

staticより下の階層については、フォルダー名やファイル名に特別な縛りはありません。
本記事ではこのようにcssとJavaScriptのファイル置きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/169117ed-617a-3043-6eb2-ad710b3bc845.png)

cssの中身。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/1a246d24-2c2a-cc79-4b76-35af7c8918e3.png)

JavaScriptファイルの中身。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/93403e1d-1e7a-61a9-641d-63fced9c6939.png)

# thymeleafファイル

本記事では『css』『js』フォルダーは認証除外フォルダーに指定していません。
そのため、ログイン成功後画面で読み込むようにします。

```html:login-success.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">


<head>
	<link th:href="@{/css/global.css}" rel="stylesheet">
	<script th:src="@{/js/global.js}" charset="utf-8"></script>
</head>


<body>
	
	<h1>login-success</h1>
	
	<div th:text="${userName}"></div>
	
	<form th:action="@{/logout}" method="POST">
		<button type="submit" value="go">ログアウト</button>
	</form>
	
</body>
</html>
```

# 動作確認

cssが効いていて…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/b089319d-3df6-69c8-c096-fccd85f42093.png)

JavaScriptも動作しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/0bd72dab-698d-2470-c9d5-fb840d640ce1.png)

# バージョン

Microsoft Windows [Version 10.0.22631.3672]
JAVA 17.0.10
Spring Boot v3.3.0
Railsプロジェクト作成の際に詰まったことメモ bundle install SSL接続エラー

## この記事の目的
色々な記事を調べましたがどれやってもうまくいかず。
たくさんの方が記事出していたのですぐ解決できると思ったんですが、だいぶハマりました。
私の場合の解決方法を備忘録として。

## 前提
- ruby -v
ruby 3.3.2 (2024-05-30 revision e5a195edf6) [x86_64-linux]

- rails -v
Rails 7.1.3.4

- gem -v
3.5.11

## 確認したこと
bundle installの際のこのエラー
```
run  bundle install
Fetching gem metadata from https://rubygems.org/....


Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/ due to underlying error <SSL_connect returned=1 errno=0 peeraddr=162.159.24.4:443 state=error: sslv3 alert handshake failure (SSL alert number 40) (https://rubygems.org/specs.4.8.gz)>
```
SSL接続エラーです。
他の方の記事を見て証明書再取得したり、Gemfile.lockを消したりと色々試しました。

何しても解決できず、最終的に以下で解決しました。
```
gem sources --remove https://rubygems.org/
gem sources --add https://rubygems.org/
```
同じURLのはず（笑）
けどソースの参照URLを設定し直したらOKでした。

同じ状況の方の助けになりますように！
Rails - データベースの既存レコードからバリデーションエラーのデータを探す方法

# 概要

Rails的にはバリデーション違反なのだが、いちどデータベースにレコードが記録されてしまい、そのまま残っているデータがあるという場合がある

それを見つける方法

単に `instance.validate` するだけで良い

## コード例

examines テーブルの全てのレコードのバリデーション違反状態を確認する例


```rb
Example.all.each do |example|
  example.validate

  if example.errors.present?
    p example.errors.full_messages
  end
end
```


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
Python ツール #5 ― PDF 操作（回転、結合）

# Python ツール #5 ― PDF 操作（回転、結合）

たまたま、今回、たくさんの PDF ファイルの中身を回転させたり結合させたりする必要がありましたので、その Python スクリプトを開発してみました。[^1] 
今後の実務で複雑な PDF 操作をするかもしれないので、そのときは、今回の Python スクリプトをスニペット（断片ソースコード）として再利用しようと思います。[^2]

## ソースコードの簡単な説明

* pdf_rotater.py（Python スクリプト）。・・・ PDF 回転
    ```python:pdf_rotater.py
    #!/usr/bin/env python3
    
    ・・・
    
    # Import Libraries
    import os
    import sys
    import PyPDF2
    from pathlib import Path
    
    # Constants
    IN_DIR = '.\\input_rotater'
    OUT_DIR = '.\\output_rotater'
    ROTATE_ANGLE = 270    # 90, 180, 270
    
    
    # Main
    def main() -> None:
    
        in_file_list = list(Path(IN_DIR).glob("**/*.pdf"))
        for in_file_name in in_file_list:
            print('%s' % in_file_name)
            if os.path.isfile(in_file_name):
                in_file = open(in_file_name, 'rb')
                reader = PyPDF2.PdfReader(in_file)
                writer = PyPDF2.PdfWriter()
                for page in range(0, len(reader.pages)):
                    obj = reader.pages[page]
                    obj.rotate(ROTATE_ANGLE)
                    writer.add_page(obj)
                _, out_file_name = os.path.split(in_file_name)
                in_file.close()
                out_file = open(os.path.join(OUT_DIR, out_file_name), 'wb')
                writer.write(out_file)
                out_file.close()
    
        sys.exit(0)
    
    
    # Goto Main
    if __name__ == '__main__':
        main()
    ```
    入力フォルダーの .pdf ファイル数分ループし、PDF ファイルの全ページを 270 度回転して、出力フォルダーに PDF ファイルを保存します。
* pdf_merger.py（Python スクリプト）。・・・ PDF 結合
    ```python:pdf_merger.py
    #!/usr/bin/env python3
    
    ・・・
    
    # Import Libraries
    import os
    import sys
    import PyPDF2
    from pathlib import Path
    
    # Constants
    IN_DIR = '.\\input_merger'
    OUT_DIR = '.\\output_merger'
    OUT_NAME = 'merged.pdf'
    
    
    # Main
    def main() -> None:
    
        merger = PyPDF2.PdfMerger()
    
        in_file_list = list(Path(IN_DIR).glob("**/*.pdf"))
        for in_file_name in in_file_list:
            print('%s' % in_file_name)
            if os.path.isfile(in_file_name):
                merger.append(in_file_name)
    
        merger.write(os.path.join(OUT_DIR, OUT_NAME))
        merger.close()
    
        sys.exit(0)
    
    
    # Goto Main
    if __name__ == '__main__':
        main()
    ```
    入力フォルダーの .pdf ファイル数分ループし、1 つの PDF ファイルに合併し、出力フォルダーに PDF ファイル “merged.pdf” を保存します。

## ソースコードの置き場所

https://github.com/tengbu-haoshou/Python_tool-pdf_manipurator

## 参考

**PDF ライブラリ 6 選**

https://feeld-uni.com/?p=2677

**PDFMuPDF、pyPDF2、PDFMiner**

https://python-work.com/pdf-read/

**Spire.PDF**

https://qiita.com/rafluctua702101/items/13f7104fa9648911bde0

##

[^1]:実家のスキャナーが A4 横書き文書を A4 縦書きにスキャンして、1 ページ 1 PDF ファイルで生成してしまうようです。Adobe Acrobat の有料版では、回転や合併ができるようですが、〇〇〇〇です。よって、Python スクリプトを開発することにしました。

[^2]:PDF ファイルの全ページを 1 ページづつに分割して、複数の PDF ファイルを作成する Python スクリプトも開発してみました。PDF 回転のスクリプトを流用したら、数分で完成させることができました。→ [GitHub リンク](https://github.com/tengbu-haoshou/Python_tool-pdf_manipurator/blob/master/pdf_splitter.py)
【Docker】M1 MacでMySQLコンテナを立ち上げた時にExit(2)する時の対処方法

# はじめに
M1 MacでMySQLコンテナ起動に少し苦労したので、記事にします。

# つまづいた点
以下のコマンドでMySQLコンテナを起動しましたが、`docker ps`では表示されず、`docker ps -a`すると、STATUSが`Exited (2)`でした。

```
docker container run -d \
  --platform linux/amd64 \
  --network wp-net \
  --name mysql \
  --mount source=mysqlvolume,target=/var/lib/mysql \
  --mount type=bind,source=/Users/{your_name}/mysqlbackup,target=/mysqlbackup \
  -e MYSQL_ROOT_PASSWORD=password \
  -e MYSQL_DATABASE=wordpress \
  -e MYSQL_USER=wordpress \
  -e MYSQL_PASSWORD=password \
  mysql:5.7.28
```

```
-zsh /var/lib % docker ps -a
CONTAINER ID   IMAGE               COMMAND                  CREATED             STATUS                           PORTS     NAMES
hogefugahoge   mysql:5.7.28        "docker-entrypoint.s…"   5 seconds ago       Exited (2) 4 seconds ago                   mysql
```


コンテナログを見ると以下のエラーが出てました。

```
2024-06-08 06:47:19+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.28-1debian9 started.
2024-06-08 06:47:20+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
runtime: failed to create new OS thread (have 2 already; errno=22)
fatal error: newosproc
```


# 解決方法

mysqlのバージョンを8系にします。

```
docker container run -d \
  --platform linux/amd64 \
  --network wp-net \
  --name mysql \
  --mount source=mysqlvolume,target=/var/lib/mysql \
  --mount type=bind,source=/Users/{your_name}/mysqlbackup,target=/mysqlbackup \
  -e MYSQL_ROOT_PASSWORD=password \
  -e MYSQL_DATABASE=wordpress \
  -e MYSQL_USER=wordpress \
  -e MYSQL_PASSWORD=password \
  mysql:8.0.26
```

docker psで表示されるようになります。

```
  -zsh /var/lib % docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                 NAMES
hogefugahoge   mysql:8.0.26   "docker-entrypoint.s…"   9 minutes ago   Up 9 minutes   3306/tcp, 33060/tcp   mysql
```

以上です。
フローティングバナー・フローティングボタン実装時に参考にしたサイト

<h1>フローティングバナー・フローティングボタン実装時に参考にしたサイト<h1>
<a href="https://engineer-labo.com/%e7%94%bb%e9%9d%a2%e3%82%92%e3%82%b9%e3%82%af%e3%83%ad%e3%83%bc%e3%83%ab%e3%81%97%e3%81%9f%e6%99%82%e3%81%ab%e8%bf%bd%e5%be%93%e3%81%99%e3%82%8b%e3%83%90%e3%83%8a%e3%83%bc%e3%82%84%e3%83%9c%e3%82%bf/">画面をスクロールした時に追従するバナーやボタンをCSSで作る方法</a>
【ITパスポート試験勉強まとめ】情報システム開発

エンジニア1年生が
ITパスポート試験勉強で学習した内容の
自分用まとめ①

# 情報システム開発

## 開発工程

### 上流工程
* 要件定義：顧客や自社の関係部署から伝えられた「こうしたい」を明確化
* 外部設計：(=基本設計)具体的な画面や帳票のレイアウトを設計
* 内部設計：(=基本設計)具体的な画面や帳票のレイアウトを設計

### 下流工程
* プログラミング：(=実装)
* 単体テスト：設計書や要件定義書の通りになっているかを試験

→モジュール単体でテストを行う
・ブラックボックステスト：モジュールの内部を無視し結果だけを確認
・ホワイトボックステスト：モジュールの内部を確認

* 結合テスト(統合テスト)：設計書や要件定義書の通りになっているかを試験
 
→モジュールを結合するテストを行う

* 総合テスト：設計書や要件定義書の通りになっているかを試験

→ソフトウェア全体のテストを行う

## 開発モデル

### ウォーターフォール開発
ウォーターフォール＝滝
上流工程→下流工程へ　※後戻りがない前提のモデル

### アジャイル開発
迅速、柔軟性を重視したモデル
工程では無く、機能やサービス、または段階でプロジェクトを分割し、
小さい単位で開発を繰り返す。=スプリント(イテレーション)
仕様や要件が固まっておらず、変更が起きやすいシステム開発に適している。

#### XP([エクストリームプログラミング](https://tracpath.com/works/devops/xp_extreme_programming/))
顧客の要望を取り入れながら、
要件定義から設計、開発、テストの工程をスプリント(イテレーション)という単位で繰り返す
アジャイル開発手法の1つ。

#### スクラム
プロダクトオーナー、スクラムマスター、開発者といったメンバーで小チームを組み、
機能単位で計画、設計、開発、テスト、リリースのサイクル(スプリント)を繰り返し、
プロダクトを完成させるフレームワークの1つ。

![waterfall-methodology-vs-agile_001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552881/d404f643-9017-b527-caf6-19f658bd6e4a.jpeg)

## 分析・設計手法

### 状態遷移図
![activity.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552881/1dee4b1c-1491-d61b-cb28-e759ead0d269.gif)

### データフローダイアグラム(DFD)
![dfd.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552881/8d625947-5086-7a54-e417-e450dd7f48c2.gif)

### ER図(エンティティリレーションシップ)
![er-shurui.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552881/81b82c61-352a-ae73-c583-4862998a6d96.gif)
![er-model.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552881/21155df2-a142-c1f3-96be-783d24d5278c.gif)

### UML(統一モデリング言語)13図法
#### 構造図

(静的構造)
1.クラス図：業務で用いられる情報の構造を図示≒ＥＲＤ
2.オブジェクト図：クラス図をオブジェクトのレベルで図示、インスタンス間の関係を表現
3.コンポジット構造図：構造を持つクラス等の内部構造の協調関係を図示
4.コンポーネント図：プログラムやリソースファイルの構成を図示

(実装)
5.パッケージ図：データやプログラムをパッケージとしてまとめて図示
6.配置図：ハードウェアなど物理的構成を図示

#### 振る舞い図

(要求)
7.ユースケース図 ：システムが外部に提供する機能と、利用者や外部システムとの関係を表現
(相互作用図)
8.相互作用概要図：以下の相互作用の図をまとめたもの
9.シーケンス図：オブジェクト間の相互作用（情報の流れ）を時間的に図示≒業務分析図
10.コミュニケーション図：オブジェクト間のリンク関係を図示(コラボレーション図)
11.タイミング図：時間を横軸にとり、システムの動作の開始や終了を図示

(その他の振る舞い)
12.アクティビティ図：ある振る舞いから次の振る舞いへの制御の流れを表現する≒ＤＦＤ
13.ステートマシン図：オブジェクト生成～消滅をイベント発生や時間経過による状態変化≒状態遷移図

## オブジェクト指向

開発効率を上げるために「オブジェクト」を組み合わせてプログラムを作ること

参考[：【10分でわかる】オブジェクト指向とは？](https://www.youtube.com/watch?v=CTIAYv88xj4)
Next.js × microCMSでプレビュー機能

# はじめに
ブログサイトを作る過程で学んだことを、備忘録目的で投稿しています。
自身は駆け出しエンジニアであり、React自体がほぼ初学者のため、誤った認識・理解をしている可能性があります。
万が一参考にする場合は、上記の点を考慮した上でご一読ください。
また、スタイリングについては割愛しています。

この記事は、過去に投稿した[Next.js × microCMSでブログサイト作成した際に学んだことを書き留める](https://qiita.com/miyaayim_eng/items/62f4267280a9f3cfaa4d)のプロジェクトを元に説明しています。

# 目的
microCMSのプレビュー機能で投稿前の記事を確認できるようにする。

# 作業環境
Windows10 Pro x64
Node.js: 20.14.0
npm: 10.3.0
Next.js: 14.2.3（App Router使用）

# 手順

## microCMS設定
microCMSの管理画面から記事投稿のAPI設定画面に移り、「画面プレビュー」項目を開きます。
遷移先URLにブレビュー用のURLを入力します。
例えば、`https://ドメイン名/articles/記事ID`として、記事詳細ページを表示するようにしていた場合、`https://ドメイン名/articles/{CONTENT_ID}?dk={DRAFT_KEY}`と入力します。
入力し終えたら、「変更する」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/51599f0d-2078-6a63-3da0-d1b42f4ad456.png)

## Next.js設定
記事詳細ページのファイルに、画面プレビューで使用する`draftKey`を取得できるように変更を加えます。
また、プレビューページはインデックス無効にし、検索結果に表示しないよう設定しました。

```src/app/articles/[slug]/page.jsx
import { getArticlesDetail } from "@/libs/microcms";

export async function generateMetadata({ searchParams }) {
  const metadata = {};

  // 下書きのプレビューページではインデックス無効
  if (searchParams.dk) {
    metadata.robots = {
      index: false,
    };
  }
  return metadata;
}

// `searchParams` と `draftKey: searchParams.dk` を追加
export default async function Page({ params, searchParams }) {
  const queries = { draftKey: searchParams.dk };
  const article = await getArticlesDetail(params.slug, queries);
  return (
    <>
      省略
    </>
  );
}

```
GitHubにプッシュし、Vercelで自動デプロイされるのを待ちます。

## 画面プレビューを試す
microCMSで記事を作成し下書き保存します、この時点では記事はWeb上に公開されていません。
その後、入力画面右上にある「画面プレビュー」をクリックして表示してみます。
通常であれば問題なく表示されるはずです。
しかし、自分の場合はうまく表示できず、エラーメッセージが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/c82a917e-6469-f754-5bdb-3f8b0640cc3a.png)


原因調査として、開発環境で直接下書きページにアクセスして表示できるか確認してみたところ、問題なく表示できました。
例：`http://localhost:3000/articles/rfd_lt0a-_x?dk=rh0MvLWqJH`

次に、`draftKey`を更新してみたところ解消されました。
microCMS入力画面左上の`draftKey`横に更新アイコンがあるのでクリックして更新します。
その後に、改めて画面プレビューを表示したところ、無事表示されました。
`noindex`もきちんと付与されていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/4c7440e4-f69f-c45c-922f-9d2d5705e1a4.png)


# 参考
[画面プレビュー｜microCMSドキュメント](https://document.microcms.io/manual/screen-preview)
[下書き中の記事を取得する方法は？｜microCMSヘルプ](https://help.microcms.io/ja/knowledge/how-to-get-draft-content)
[Next.jsのPreview Modeを使ってmicroCMSのプレビュー機能を実装してみた](https://zenn.dev/chot/articles/5da761918086be)
[Next.js（App Router）とmicroCMSでプレビュー画面を作った](https://blog.yutaaoki.jp/article/nqylffmkq7br)