OmniAICreator/Qiita-1.07M huggingface dataset:
Next15でThis module doesn't have an associated type. Use a known file extension, or register a loader for it.エラー

Next15をつかっていたところ、以下エラーが発生

```
 ./node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/index.html
Unknown module type
This module doesn't have an associated type. Use a known file extension, or register a loader for it.
```

## 原因：@mapbox/node-pre-gypに含まれる index.html をTurbopackが誤って解釈したため
Turbopackは Webpack とは異なり、一部のファイルタイプ（.html など）をデフォルトで無視しない仕様になっている。
Turbopackの場合、node_modules内に.htmlファイルがあるとそれを「未知のモジュールタイプ」として認識し、エラーになった。

### 具体的なエラーの流れ
1. Turbopack は`node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/index.html`をスキャン
2. index.html をモジュールとして扱おうとする
3. しかし、Turbopack は .html を適切に処理するローダーを持っていない
4. そのため「Unknown module type」エラーが発生


### @mapbox/node-pre-gypとは
Node.jsのネイティブモジュール (C++ アドオン) を管理するツール`node-pre-gyp`のMapbox カスタムバージョン。
通常、Node.jsでC++ で書かれたネイティブモジュールを使うときには、コンパイルが必要になり、手間がかかる。
その手間を削減する方法として、「あらかじめネイティブモジュールをコンパイルしてバイナリにしちゃえば、すぐにinstallできて楽じゃない？」と考えらえた。
その仕組みが`node-pre-gyp`。`node-pre-gyp`はコンパイルされたネイティブモジュールを配布・管理する仕組みなので、`node-pre-gyp`自体がコンパイルをしているわけじゃない。


### ネイティブモジュールとは
通常のNode.jsのパッケージはJavaScriptやTypeScript)で記述されるが、一部のパッケージはパフォーマンス向上のためにC++で書かれたコードを含む。
これをネイティブモジュールまたはC++アドオンと呼ぶ。

### Mapboxとは
デベロッパー向けの高機能な地図プラットフォームを提供する会社。地図データを高速で配信するためのネイティブモジュール (C++ アドオン)を作成しており、その中で、`node-pre-gyp`の仕組みを自分たちようにカスタムしている。カスタムしたものが`@mapbox/node-pre-gyp`。

## 解決策: Turbopackに`@mapbox/node-pre-gyp`のhtmlファイルを無視させる
`experimental.turbo.rules`で無視したいファイルをfalseに指定すれば、turbopackは指定したファイルを無視してロードしなくなる。
```ts:next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  experimental: {
    turbo: {
      rules: {
        "node_modules/@mapbox/node-pre-gyp/**/*.html": false,
      },
    },
  },
};

export default nextConfig;
```

今回は影響を最小限にするため`node_modules/@mapbox/node-pre-gyp/**/*.html`とした。
node_modules配下のhtmlは全部無視したいなら、`"node_modules/**/*.html": false`でもOK。

:::note info
今回は不要なhtmlファイルだったので無視をしていますが、もし必要なhtmlファイルの場合、ローダーを使って適切にhtmlファイルを処理する必要があります。
:::




## htmlファイルを無視させても良いの？
htmlファイルを無視してよいかどうかはプロジェクト次第ですが、個人的な見解としては**99%のケースで.hhtmlファイルを無視しても良い**と思っています。

:::note alert
個人の見解です!
:::

理由は次の通りです。
#### 1. node_modules内の.htmlを使わない
- ほとんどのパッケージは .html をコードとしては使わない
- .html が node_modules に含まれていても、ドキュメントや補助ファイルとして置かれているだけで、実際に import されることはほぼない

#### 2. Webpack では .html を無視していた
- Webpack では デフォルトで .html を無視 していたので、それと同じ動作にするだけ。つまり、Turbopack でも .html を無視するのが「自然」な動作


### .html を無視すると問題が起こる可能性があるケース
そうはいっても次のような使い方をしていれば、がっつり.htmlファイルが利用されているので、htmlファイルを無視すると問題になります。
```
import template from "./template.html";
```
こういう時は**html-loaderやfile-loaderなど.htmlファイルの利用用途に合わせて、適切なローダーを使って処理**してください



## 別の解決方法：@mapbox/node-pre-gypを呼び出さないようにする
`@mapbox/node-pre-gyp`は今回直接installしていなかったので、そもそも`@mapbox/node-pre-gyp`がどこから呼び出されているかを以下コマンドで調べてみた
```bash
npm ls @mapbox/node-pre-gyp
└─┬ bcrypt@5.1.1
  └── @mapbox/node-pre-gyp@1.0.11
```
`bcrypt`パッケージが`@mapbox/node-pre-gyp`を呼び出している
今回はパスワードをハッシュ化するための目的なので、`bcrypt`をやめて、`@mapbox/node-pre-gyp`パッケージを使わない`bcryptjs`を代用しても、エラーは解消する。

```bash
npm uninstall bcrypt
npm i bcryptjs
```
:::note warn
bcryptの方がbcryptjsよりも処理速度がかなり速いし、
:::
なでしこさんのプラグインを開発用にPHPでホストする

# 課題

[なでしこ](https://nadesi.com/index.php?FrontPage)のプラグインを開発する際、いちいち貯蔵庫に保存してもいいかもしれないが、もっと気軽に試したい。
そこで、今回は PHP を用いてローカルのファイルをHTTPで取り込めるようにホストすることで、手元で書いているプラグインをWeb簡易エディタで実行できるようにする。

# 方法

JavaScriptでプラグインを書き、**文字コード UTF-8** で保存する。

```javascript:plugin.js
const plugin = {
  'プラグインテスト': { type: 'const', value: 42 }, // @ぷらぐいんてすと
  'meta': {
    type: 'const',
    value: {
      pluginName: 'plugin_serve_test',
      description: 'プラグインのテスト',
      pluginVersion: '1.0.0',
      nakoRuntime: ['wnako', 'cnako', 'phpnako'],
      nakoVersion: '3.6.0'
    }
  },
};

if (typeof navigator === 'object') {
  navigator.nako3.addPluginObject('plugin_serve_test', plugin);
} else if (typeof module !== 'undefined') {
  module.exports = pluginObj;
}
```

:::note info
プラグイン名を `"plugin_test"` にすると、「取り込む」はエラーにならなかったが、「プラグインテスト」が `undefined` になってしまい、実行がうまくいかなかった。
既にあるプラグインと名前が被った可能性がある。
そのようなプラグインは[全端末の命令](https://nadesi.com/v3/doc/index.php?%E5%91%BD%E4%BB%A4%E4%B8%80%E8%A6%A7%2F%E6%A9%9F%E8%83%BD%E9%A0%86&show)や[プラグイン一覧](https://nadesi.com/v3/doc/index.php?%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E4%B8%80%E8%A6%A7&show)には載っていないんだけどなあ……
:::

作成したプラグインを、取り込んでもらうためのヘッダを追加して配信するためのPHPのコードを用意する。
[`readfile()`](https://www.php.net/manual/ja/function.readfile.php) を用いることで、指定したファイルの内容を出力できる。

```php:serve.php
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: text/javascript');

readfile('plugin.js');
```

:::note info
`Content-Type` の指定は、無くても動くようである。
とはいえ、あったほうが気持ちいいだろう。
:::

上記2個のファイルが置かれたディレクトリで、PHPの簡易サーバーを立てる。

```bash
php -S 127.0.0.1:8901
```

[なでしこ3 Web簡易エディタ](https://nadesi.com/doc3/index.php?%E3%81%AA%E3%81%A7%E3%81%97%E3%81%933%E7%B0%A1%E6%98%93%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF)でプラグインを用いるコードを実行する。

```text:ホストしたプラグインを用いるなでしこのコード
！「http://localhost:8901/serve.php#.js」を取り込む
プラグインテストを表示。
```

以下のように、無事に実行することができた。
`https` が用いられている簡易エディタのページから `http` のプラグインを取り込んでいるが、問題なく取り込めるようである。

![実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/72c2353e-a80e-4647-a8b6-a99827092d8f.png)

:::note info
フラグメントなしのURLを用いた

```text
！「http://localhost:8901/serve.php」を取り込む
```

を用いると、

> [エラー]NakoError: [取り込みエラー]main.nako3(1行目): ファイル『http:\//localhost:8901/serve.php』は拡張子が(.nako3|.js|.js.txt|.mjs|.mjs.txt)以外なので取り込めません。

というエラーが出てしまい、取り込めなかった。
しかし、`#.js` というフラグメントをつけることで、書かれている以外の拡張子 (`.php`) でも取り込むことに成功した。
:::

:::note info
`https` ではなく `http` でホストしているため取り込めないときは、cloudflared を用いて `https` でのアクセスを可能にすると取り込める可能性がある。
[Cloudflare の ngrok的なサービスがあるらしい ⇒ $ cloudflared tunnel --url localhost:8080 といった使い方 #ArgoTunnel - Qiita](https://qiita.com/youtoy/items/3d312552f08a729bb5bb)
:::

# 参考サイト

* [📖 なでしこ3 マニュアル - 文法/JSプラグインの作り方](https://nadesi.com/v3/doc/index.php?%E6%96%87%E6%B3%95%2FJS%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9&show)
* [【PHP】PHPでファイルをダウンロードする - GOOTA TECH](https://tech.gootablog.com/article/php-file-download/)
* [PHPでのCORS許可設定｜ビスポーク株式会社のブログ](http://commonld.com/blog.php?id=53)
個人的備忘録：Dockerのエントリーポイントスクリプト（docker-entrypoint.sh）を作成し、ローカルで動作確認してみた

## はじめに

Dockerを活用する際、コンテナの起動時に特定の処理を実行する必要がある場合があります。

:::note info
そのようなケースで役立つのが **エントリーポイントスクリプト（docker-entrypoint.sh）** です。
:::

本記事では、`docker-entrypoint.sh` の基本的な使い方から、実践的な活用方法までを詳しく解説します。

## Dockerエントリーポイントスクリプトとは？

`docker-entrypoint.sh` は、Dockerコンテナが起動する際に最初に実行されるスクリプトです。

通常、コンテナの初期設定や環境変数の設定、アプリケーションの起動などを行うために使用されます。

## エントリーポイントスクリプトを使用するメリット

- **環境変数の適用**：環境変数を動的に設定し、アプリケーションに渡すことができる。
- **実行前処理の追加**：データベースのマイグレーションや設定ファイルの自動生成が可能。
- **CMDとの組み合わせ**：Dockerfileの `CMD` に渡されたコマンドを適切に処理できる。

## ローカル環境で簡単に試す

ローカルで `docker-entrypoint.sh` を試すのは非常に簡単です。以下の手順で動作確認できます。

1. `docker-entrypoint.sh` を作成する

```bash
#!/bin/sh
set -e

echo "Hello from docker-entrypoint.sh!"
exec "$@"
```

2. 簡単な `Dockerfile` を作成する

```dockerfile
FROM alpine:latest
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["echo", "Container started"]
```

3. コンテナをビルド・実行する

```sh
docker build -t my-entrypoint-test .
docker run --rm my-entrypoint-test
```

**実際のターミナル画面**

![Screenshot 2025-02-19 at 7.19.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/5550ebc0-1a00-415c-9df1-f7dbad63b4de.png)

これを実行すると、エントリーポイントスクリプトが動作し、`Hello from docker-entrypoint.sh!` のメッセージが表示された後に `Container started` と出力されます。

**実際のターミナル画面**

![Screenshot 2025-02-19 at 7.19.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/ea7f79a7-32bb-4590-a58e-9a0d000d1f0f.png)

## `exec "$@"` の意味

エントリーポイントスクリプトの最後で `exec "$@"` を実行することで、CMD に渡されたコマンドを実行しつつ、シェルプロセスを `PID 1` に置き換えることができます。

***これにより、**適切なシグナルの受信やコンテナの正常な終了**が保証されます。***

## まとめ

`docker-entrypoint.sh` を活用することで、Dockerコンテナの動作を柔軟にカスタマイズできます。特に、環境変数の設定や実行前処理を行う場合に便利です。

**ポイント**：
- `ENTRYPOINT` を使うとコンテナの起動時に必ずスクリプトを実行できる。
- `exec "$@"` を活用して適切にプロセスを管理する。
- 簡単な `Dockerfile` を作成すれば、ローカル環境ですぐに試すことができる。

これらを活用して、よりスマートな Docker コンテナの設計を行いましょう！
個人的備忘録：Cognito認証を用いた curl コマンドによる API リクエストでデータを挿入してみた

## はじめに

DB にデータを挿入する方法を探していて、適切なリクエストの送り方が分からず困っていました。

:::note info
**その中で `curl` コマンドを使う方法が有効だと知り、実際のリクエスト例を整理することにしました。**
:::

本記事では、`curl` コマンドを使用して API にリクエストを送る方法を解説します。特に、JSON データを送信する方法と、認証トークンを使用する方法に焦点を当てます。

## コマンドの概要

以下の `curl` コマンドを例に説明します。

```sh
curl -X POST \
     -H 'Content-Type: application/json' \
     -H "Authorization: Bearer xxxxx.yyyyy.zzzzz" \
     -d '{"score":77}' \
     "http://localhost:1323/api/scores"
```

### オプションの説明

- `-X POST` ： HTTP メソッドとして `POST` を指定
- `-H 'Content-Type: application/json'` ： リクエストの `Content-Type` を JSON に指定
- `-H "Authorization: Bearer xxxxx.yyyyy.zzzzz"` ： 認証用の Bearer トークンをヘッダーに設定
- `-d '{"score":77}'` ： JSON データをリクエストのボディに含める
- `"http://localhost:1323/api/scores"` ： API のエンドポイント

## 認証トークンについて

このコマンドでは `Authorization: Bearer xxxxx.yyyyy.zzzzz` という認証トークンを含めています。これは JWT (JSON Web Token) などの認証方式で API にアクセスする際に必要となります。

### トークンのダミー化

実際の環境では、トークンは個別の認証情報として発行されるため、外部に漏洩しないように注意が必要です。本記事では `xxxxx.yyyyy.zzzzz` のようにダミーのトークンを使用しています。

## API エンドポイントについて

この例では `http://localhost:1323/api/scores` という URL にリクエストを送信しています。実際の環境では、この URL は変更され、サーバーが提供する適切な API のエンドポイントを指定する必要があります。

## 実行結果の確認

この `curl` コマンドを実行すると、API は以下のようなレスポンスを返す可能性があります。

### 成功時のレスポンス例

```json
{
  "message": "Score submitted successfully",
  "score": 77
}
```

### 認証エラーの場合

```json
{
  "error": "Unauthorized",
  "message": "Invalid or expired token"
}
```

このような場合、トークンが無効または期限切れである可能性があるため、新しいトークンを取得する必要があります。

## まとめ

- `curl` を使用して API に `POST` リクエストを送信できる。
- `Content-Type: application/json` を指定することで JSON データを送信可能。
- `Authorization: Bearer <トークン>` をヘッダーに含めることで認証を実施。
- API のレスポンスを確認して適切に対応する。

この情報を活用して、安全かつ正しく API へリクエストを送信することで解決しｍ
【SwiftUI】オセロの初期配置画面を描画してみる

## はじめに
SwiftUIの図形描画を用いて、オセロの初期配置画面（黒の丸が2枚、白の丸が2枚それぞれ交差する形で配置されるアレ）を作成したので、備忘録として残します。

---

## 環境
【Xcode】16.2
【iOS】18.2
【macOS】Sequoia 15.3.1

---

## ポイント
- `HStack` の中に2つの `VStack` を用意し、丸を **横×2 縦×2** の配置で4つ置けるようにする。
- `.stroke` のモディファイアで、白の丸を表現する。
- 共通部分を抽出してリファクタリング。

---

## 1. `Circle()` で丸を4つ描画

![スクリーンショット 2025-02-19 6.12.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4004493/b332b4e4-8476-4be6-9d33-d0bf79f24450.png)

---

## 2. 各丸のデザインを修正

- 上段の右側・下段の左側の丸は、`.stroke` を利用して **白丸** を表現。

![スクリーンショット 2025-02-19 6.18.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4004493/097d6aa7-527c-4025-be4e-bbfb44663ab3.png)

⚠️ `.stroke` は `ShapeStyle` プロトコルに準拠するビューに対するモディファイアであり、`.foregroundColor` を先に持ってくるとより一般的な `some View` が返されて引数の不一致となるため、**`.stroke` を先に記述する**。

---

## 3. 黒丸・白丸の構造体を作成し、`ContentView` 内で呼び出し（リファクタリング）

![スクリーンショット 2025-02-19 6.32.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4004493/4a4fe127-70ec-4425-9dcd-3f1fd009f31f.png)

☝️ 黒丸・白丸のデザインを修正したい場合、各構造体にモディファイアをつけたり画像を貼ったりすれば、**全ての丸に反映される** ので、リファクタリングで共通部分をまとめるのが大事！
Lチカいろいろ

リビングにいろいろネットワーク関係の機材があり、夜電気を消すといろいろチカチカしています。

FreeBSDのgpioにはgpioledというのがあって、点滅を制御できます。これはgonzoさんの書いたもののようです。小ネタですが結構いいです。

ZRouterではstatusとhintsかdtsでラベルのついたledを点滅するようにしています。モジュールがハングアップしてないかわかります。

ブートしてrcが始まると早めの点滅になり、rcが終了するとゆっくりの点滅に変わります。

これ以外にもGPSのPPSやJJYの信号のLEDも点滅しています。JJYは生の信号の点滅とデコーダーの点滅のLEDが付いています。

c1k,c2kのNetBSDはUSB HD(IDE)にインストールしてあり、これのアクセスランプもときどき点滅します。通常は緑の点灯なのですが、アクセスがあると赤になります。以前はときどきハングして赤いままになることが、あったのですが1年くらい安定して動いています。

またEthernet SwitchにつながれたLEDも点滅します。

LCDディスプレーのLEDもMacが落ちていると点滅しています。今は売ってない三菱のディスプレーですがなんかとっても明るいです。

Mac mini G4はスリープしているとPWMで蛍みたいなLチカになります。
PHPで「四則演算」の動作を確認してみた。

# 概要

PHPで「四則演算」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/php/num/index2.html

# 実装

以下のファイルを作成しました。

```sample.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
</head>
<body>

<p>PHPのテストです。</p>

<p>
<?php
echo "8 + 3 = ", 8 + 3, '<br />';
echo "6 - 2 = ", 6 - 2, '<br />';
echo "4 * 7 = ", 4 * 7, '<br />';
echo "12 / 4 = ", 12 / 4, '<br />';
echo "5 % 3 = ", 5 % 3;
?>
</p>

</body>
</html>
```

以下のコマンドを実行しました。

```
$ php sample.php 
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
</head>
<body>

<p>PHPのテストです。</p>

<p>
8 + 3 = 11<br />6 - 2 = 4<br />4 * 7 = 28<br />12 / 4 = 3<br />5 % 3 = 2</p>

</body>
</html>
```

# まとめ

何かの役に立てばと。
powershellでwindows のネットワーク・デバイス名を変更する

現在の状態
~~~
PS > netsh interface ipv4 show interfaces

Idx     Met         MTU          状態                 名前
---  ----------  ----------  ------------  ---------------------------
  1          75  4294967295  connected     Loopback Pseudo-Interface 1
 14          15        1500  connected     イーサネット
~~~

変更する
~~~
PS > netsh interface set interface name='イーサネット' newname='10GbE'
~~~

結果
~~~
PS > netsh interface ipv4 show interfaces

Idx     Met         MTU          状態                 名前
---  ----------  ----------  ------------  ---------------------------
  1          75  4294967295  connected     Loopback Pseudo-Interface 1
 14           5        1500  connected     10GbE
~~~
読書感想文「タスク管理ゲーム化計画」

# 書籍名「タスク管理ゲーム化計画」
著者：うさぼう
kindle版
出版社無し


# 読もうと思った動機
・タスク管理に苦手意識があり改善したいと思っているため

# 印象に残った部分

## １章　タスク管理に追われる No.196~204

・不満の元は、自分なりのタスク管理を確立するまでの試行錯誤にあります。
　本やツールから想像する理想と実際に行動した結果とのギャップが不満として現れているのです。


・理想のタスクが自身の習慣になるまでの仕組みづくりが必要

## ２章　秋を防ぐコツは４つ目のステップ
・「インベストメント（投資）」
　→データを集めるともったいなくてやめにくくなる
　例としては、スーパーマケットのポイントカード、ラジオ体操のスタンプ等

・飽きを防ぐ方法は新しい魅力を取り入れ続けて、バージョンアップさせること


フック・モデル
プロダクトをユーザーに習慣的に利用してもらうためのフレームワーク
https://applis.io/posts/how-to-create-hook-model



## ７章　Willing conquest
複数人で遊ぶミニゲーム
習慣として続けたいことを登録し、達成報告を通じて移動ポイントを手に入れ陣取りを行います。







# 実践できること or 感想

## 感想
・ゲーミフィケーションという概念が興味深いと思いました。
　他の分野でも応用できそうなので、時間があったら深堀りします。

・Willing Conquestはサービス終了になっているのは残念でした。




## 実践すること
・HabiticaとTodoistを試す。
　　※Habiticaは　ロールプレイングゲームのようなタスク管理プログラム
  　　willing conquestの代わりに使ってみます。
　　https://habitica.com/

・上のタスクツールをデータべに貯めるシステムを自作する。
**自前のデータベース**上にタスクを記録します。
データベース上に記録しておけば、ツールを変えやすいかつ振り返りもしやすくなりそう
hibiticaは完了したタスクが30日だかに削除されるので、ログを取っとく必要はありそうです

画像は構成図。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/52c94e67-618e-4e21-855f-b0c88b4698c1.png)

・著者のブログにも目を通す
「うさぼうの人生ダッシュボード化計画」
https://usabo.hatenadiary.jp/



・参考文献を買って読む
「仕事を成し遂げる技術」
「ハマる仕掛け　使われ続けるサービスを生み出す「心理」×「デザイン」」
「「仕事のゲーム化」でやる気モードに変える 経営に活かすゲーミフィケーションの考え方と実践事例」
「ゲームにすればうまくいく」
著者のブログより
ゲーミフィケーション本、最初に読むなら「ゲームにすればうまくいく」をおすすめします
https://usabo.hatenadiary.jp/entry/2017/04/24/225441
競プロ日記#25/02/19

# アルゴ式-[頂点の次数](https://algo-method.com/tasks/94f477006d8c44e0)
- 無向グラフにおいて1つの辺が成立するには2つの頂点が必要である。
- 今回は辺の本数が16で0を除いた1~5までの頂点の次数の合計が13→頂点0の次数は3

# アルゴ式-[フォロー](https://algo-method.com/tasks/412)
- 今回は片方がフォローしているからと言ってもう片方がフォローしているとは限らないので有向グラフ
- 有向グラフの場合は相互の代入は不要。
- 配列変数.pop_back()で配列の最後に要素を追加できる
ViewConfiguration.minimumTouchTargetSizeと近隣Composableのクリックイベントの優先順位について

# 概要
ViewConfiguration.minimumTouchTargetSizeは設定された範囲内のコンポーネントの最小のタッチエリアを指定する。
コンポーネントのサイズより大きな範囲を最小のタッチエリアとして指定することもできるため、タッチエリアと近隣のコンポーネントの領域が仕組み上被りうる。
領域が被ったコンポーネントにクリックイベントが設定されている場合、ViewConfiguration.minimumTouchTargetSizeで拡張されたタッチエリアではなく近隣コンポーネントのクリックイベントが優先される。
検証している限りこの優先順位はコンポーネントの宣言順の影響は受けない。


# 詳細
## ViewConfiguration.minimumTouchTargetSizeとは
ViewConfigurationとは、ロングプレスがタイムアウトする時間や、スクロールやスワイプの判定の閾値を設定できるinterfaceです。JetpackCpmposeのために用意されたinterfaceではなく、AndroidViewから存在しています。AndroidViewや、JetpackComposeといったレイヤの話ではなくシステム側に干渉できるinterfaceとなります。

この中にminimumTouchTargetSizeという項目があり、UIの最小タッチエリアを指定できます。デフォルトでは縦横48dpに指定されている。この48という数字はMaterial Designで指定されているタッチエリアの最小領域です。他のUIに関するinterface、例えばModifier.minimuminteractivecomponentsizeでも同様の数字が指定されており、統一的に使用されている数字だとわかります。詳しくはドキュメントを参照してください。

https://m3.material.io/foundations/designing/structure#b421e522-35a6-47cd-bfc6-bf94cbacf7bb
https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier#(androidx.compose.ui.Modifier).minimumInteractiveComponentSize()

## ビジュアルイメージ
赤いボックス、青いボックスを横並びに表示する。
クリックした領域に応じてトーストが表示される。

<img width = "350" src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1816697/f04a4652-e87f-411f-9e4c-1f5045d61d64.png" >


## コード
以下のようなコードで、赤いボックス、青いボックスを横並びに表示する。
minimumTouchTargetSizeを縦横500dpで上書きしたViewConfigurationを使って緑のボックスを囲んでいる。

```kotlin
val context = LocalContext.current
val defaultViewConfiguration = LocalViewConfiguration.current

class CustomViewConfiguration : ViewConfiguration by defaultViewConfiguration {
    override val minimumTouchTargetSize: DpSize
        get() = DpSize(500.dp, 500.dp)
}

val customViewConfiguration = CustomViewConfiguration()

Row(
    modifier = Modifier.fillMaxSize(),
    verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.Center
) {
    Box(
        modifier = Modifier
            .size(200.dp)
            .background(Color.Blue)
            .clickable {
                Toast.makeText(
                　　　context, 
                     "青クリック",
                     Toast.LENGTH_SHORT
                    ).show()
                },
        )

        CompositionLocalProvider(
            LocalViewConfiguration provides customViewConfiguration
        ) {
            Box(
                modifier = Modifier
                    .size(200.dp)
                    .background(Color.Green)
                    .clickable {
                        Toast
                            .makeText(context, "緑クリック", Toast.LENGTH_SHORT)
                            .show()
                    }
            )
        }
    }
```

## 挙動
この時、青い箱以外の全ての範囲どこをクリックしても緑の箱のタッチエリアとなる。が青い箱のエリアだけはタッチエリアを奪えない。

![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1816697/0947aae8-cdd5-47ab-a920-99cfde43da59.gif)
JestでSupabaseとのやりとり部分をモック化してテストを実施する方法

# 概要
Jestでプログラムのテストを実施する際に
Supabaseのデータを取得したり更新したりする関数をモック化した際の覚え書きです。

## コード


<details open><summary>テスト対象</summary>
supabaseのテーブルを更新する関数が想定の動きをするかテスト

```tsx
export async function UpdateStudyRecord(row: Row) {
    const { id, title, time } = row;

    try {
        const { data, error } = await supabase
            .from("study-record")
            .update({ title, time })
            .eq("id", id);

        if (error) {
            console.error("データの編集中にエラーが発生しました:", error.message);
            return { data: null, error };
        }

        return { data, error };
    } catch (err) {
        console.error("予期しないエラーが発生しました:", err);
        return { data: null, error: err instanceof Error ? err : new Error(String(err)) };
    }
}

```
</details>

<details open><summary>テストコード</summary>
テスト対象の内部で実施しているsuoabaseのupdate処理をモック化

```tsx
//モックの宣言
jest.mock("@/utils/supabase", () => ({
  supabase: {
    from: jest.fn(),
  },
}));
```

```tsx
describe("supabaseMethod", () => {
  it("update成功時", async () => {
    (supabase.from as jest.Mock).mockReturnValue({
      //select以降のupdateの関数を記載
      update: jest.fn(() => ({
        eq: jest.fn().mockResolvedValue({ data: { id: "1" }, error: null }) , //成功時の戻り値を指定
      })),
    });
    const row: Row = { id: "1", title: "新しいタイトル", time: 1 };

    await expect(UpdateStudyRecord(row)).resolves.toEqual({
      data: { id: "1" },
      error: null,
    });
  });

  it("エラーが発生した場合", async () => {
    (supabase.from as jest.Mock).mockReturnValue({
      update: jest.fn(() => ({
        eq: jest.fn().mockResolvedValue({ data: null, error: new Error("更新に失敗") }),
      })),
    });

    const row: Row = { id: "1", title: "エラーテスト", time: 1 };

    await expect(UpdateStudyRecord(row)).resolves.toMatchObject({
      data: null,
      error: new Error("更新に失敗"),
    });
  });
});

```

insetやdeleteも中身を変更するだけ
insertなどで使いまわせるようにmockの宣言時はselectのみ記載
RAdam と相性のいい学習率のスケジューリング

# はじめに



前回の [ADOPT の記事](https://qiita.com/hasebirokou/items/6c22bca9e3d70348472d)で RAdam を強く推したのですが、一般的に RAdam は使われていません。RAdam が学習率のスケジューリングと干渉して使いづらい点が広く使われない原因と考えています。

しかしながら、現在 RAdam と相性のいいスケジューリング手法が主流になりそうということで紹介したいと思います。

紹介する手法は下記の3つなります。

1. ScheduleFree
2. WSD/WSD-S
3. Constant LR + EWA

## ScheduleFree

ScheduleFree ついては RAdamScheduleFree の作者のはまなすなぎさ氏がこれ以上ないぐらいに詳しく書いています。

https://zenn.dev/dena/articles/6f04641801b387

なんども読み返しました。

RAdamScheduleFree は学習率ぐらいしか設定する必要があるハイパーパラメータがないため、極めて使いやすいです。RAdamScheduleFree を使えばそれだけであなたも RAdam ユーザです。

注意点としては以下の2点があります。

1. 学習時と評価時のパラメータが異なるため、学習時の指標が参考情報程度(ただし、実行した感じでは割と順調に学習損失も減っていきます)
2. Batch Normalization を使った場合、Batch Normalization 用の統計情報を評価の直前に取り直す必要がある

学習時の損失は元々参考情報みたいなものですし、Batch Normalization は最近はめっきり使わないため、実質デメリットなしです。

## WSD/WSD-S

WSD は Warmup-Stable-Decay の略です。
つまり、最初に学習率を0から徐々に上げていき、一定の学習率で学習した後、最後に学習率を下げながら学習する手法です。最近 Cosine Annealing LR よりも良いという評判です。

この手法で RAdam を適用する場合、単純に Warmup の部分を RAdam で代替すればよいはずです。RAdam-Stable-Decay ということになるのでしょうか。

以下に詳しい分析をした論文へのリングを記載します。

https://arxiv.org/pdf/2410.05192

この論文では WSD-S(WSD-Simplified)という手法を提案しています。

違いは学習の再開の仕方で一度 WSD で学習を行いパラメータを保存した後にさらに長く学習したいというときに挙動が異なります。WSD では学習率を下げる直前のパラメータを保存しておいて、そこから再開します。対して、WSD-S では学習率を下げ終わった後に保存したものから再開します。

以下に論文中の図を引用します。

![wsd-s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494948/237e6171-e16a-452d-b3df-c5a723d54074.png)

デメリットとしては学習中の validation の指標が参考にならないという点ぐらいでしょうか。基本的に Decay の際に急激に指標が良くなるので。

### Constant LR + EWA

Constant LR + EWA は学習自体は固定学習率で行い、評価用モデルを EWA で作成します。
EWA は Exponentially Weighted Average の略で学習中に、一定間隔でパラメータの指数移動平均を計算し、評価用モデルとします。

この手法も単純に RAdam と組み合わせて使っても何も問題がありません。なにせ学習率は一定なのですから。

以下の論文で ScheduleFree, WSD, Constant LR +EWA の比較で、最も性能が良かったと紹介されています。

https://arxiv.org/abs/2410.21676

デメリットとしてはメモリ使用量が増加する点、ScheduleFree と同様に Batch Normalization の統計量を取り直す必要がある点があります。

### おわりに

RAdam を使いやすい手法について紹介しました。
どれも単に RAdam と組み合わせ易いだけではなく、性能が良い上に学習の中断・延長などがしやすい利便性の高い手法なのでおすすめです。
EC2インスタンスにSSH接続してみた - TeraTermの設定からマクロ作成まで

## はじめに

AWSのことをなんとなく知っておいた方がいいかなという軽い気持ちで、自宅で一生懸命EC2インスタンスを触ってみました。同じように「とりあえずAWS触ってみるか」という方の参考になれば幸いです。

## 環境

- OS: Ubuntu（AmazonLinuxでも良かったのですが、なんとなくUbuntuにしました）
- SSH クライアント: TeraTerm v5.3

## 手順

### 1. EC2インスタンスの作成

- EC2ダッシュボードからインスタンスを起動（ポチポチ進めていけば何とかなります）
- AMIでUbuntuを選択（よく見かける名前なので選びました）
- キーペアを新規作成してダウンロード（大事に保管！）

### 2. セキュリティグループの設定

- インバウンドルールでSSH（ポート22）を許可
- ソースは「マイIP」を選択（セキュリティ重要ですよね...）

### 3. 接続への挑戦

実はAWS管理コンソールのEC2 Instance Connectも試してみたのですが、なぜかうまく接続できず。おそらくAmazonLinuxだったらスムーズに使えるけどUbuntuの場合は他にも追加で設定とかパッケージのインストールとかが必要なのかなと推測しました。
TeraTermなら接続できたので、今回はこれでよしとすることにしました！

### 4. TeraTermでの接続設定

- ホスト名：パブリックIPアドレス（例：xx.xx.xx.xx）
- ユーザー名：ubuntu
- 認証方式：SSH鍵認証
- 秘密鍵：ダウンロードしたキーペアファイルを指定

### 5. TeraTermマクロの作成

```
;-------------------------------------------------------
;ログイン情報
HOSTIP = 'xx.xx.xx.xx'  ; EC2のパブリックIPアドレス
USERNAME = 'ubuntu'
PASSWORD = ''
KEYFILE = 'C:/workspace/aws/keypair.pem'  ; キーペアファイルのパス
;-------------------------------------------------------

;-------------------------------------------------------
;SSHログイン
msg = HOSTIP
strconcat msg ':22 /ssh /auth=publickey /user='
strconcat msg USERNAME
strconcat msg ' /keyfile='
strconcat msg KEYFILE

connect msg

end
```

## 注意点

- IPアドレスやキーファイルのパスは環境に応じて変更（\と/でハマりました...）
- セキュリティグループの設定は必要最小限やる（大事だと思います）
- キーペアファイルは安全な場所に保管してください（なくしたら大変そうです）

## まとめ

AWS初心者なりにEC2インスタンスへのSSH接続を頑張ってみました。Instance Connectは断念しましたが、TeraTermで接続できてマクロまで作れたので、まずは良しとしました。次は他のAWSサービスも触ってみようと思います。

## 参考情報
以下の記事参考にさせていただきました。お世話になりまｓ。

EC2インスタンスの作成
https://business.ntt-east.co.jp/content/cloudsolution/column-10.html

teratermマクロの作成
https://zenn.dev/madogiwa_kyoso/articles/1e7b54c878ef4e
ツッコミ歓迎Cline使用ベストプラクティス

# 前説

以下の記事で

https://qiita.com/robitan/items/770e7796a93eb3441515

こんなこと書きましたけど

![スクリーンショット 2025-02-18 23.56.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210824/4c2f95d4-5cb3-4773-a0c2-5d13b92046a3.png)

さっそくつくりました。

![ezgif-18bddb4df395f2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210824/a2c9756a-cda2-4c7b-9e62-843311537b12.gif)

https://github.com/robitan/solar-system-simulator-with-cline

今回は完全にプロンプトだけでここまできました。ソースコードに自分では一切手をいれていませんし、修正のヒント等も与えていません。それでここまでのものができました。

いちおう補足しておきますと、3D基盤まで（それこそcanvasタグのレベルから）Clineがゼロから実装してくれたわけではなく、Three.jsが提供しているサンプルライブラリを使用して見栄えのするものを作ってくれた感じです。いや自分だったら１日でやるの絶対無理なので十分すごいですよほんと。

なおREADMEに動画gif貼るのは自分でやりましたが、なかなかうまくいかず無駄なコミットを増やしました。人間の開発者はもはやお荷物説爆誕。泣きそう。

はじめて触ってからまだ１週間も経っていないのにベスプラ語るのもどうなんだって話なのですが、思っていた以上にClineがすごすぎたので、前記事の訂正もかねて現在までにわかったことを書き記しておきます。

本当にこれであってる？　と思いながらやっている部分もあったりしますので、**間違っていたり、もっと良い方法があれば、ぜひ教えてください！**

# （本文）いまのところのベストプラクティス

1. VSCodeにClineをインストール
1. ClineのAPI Providerを設定（相変わらずAnthropic使ってますがそれぞれお好みがあればそれでも）
1. Auto-approveは全部オンに設定
1. [Memory Bankについて公式の説明に従い](https://github.com/nickbaumann98/cline_docs/blob/main/prompting/custom%20instructions%20library/cline-memory-bank.md)、「Custom Instructions」を設定
![スクリーンショット 2025-02-18 11.33.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210824/da881108-8bb5-4a76-8a41-0b495a10e185.png)
1. [Memory Bankについて公式の説明に従い](https://github.com/nickbaumann98/cline_docs/blob/main/prompting/custom%20instructions%20library/cline-memory-bank.md)、ルート直下に `memory-bank` というフォルダを追加
1. ルート直下に `.clinerules` というファイルを追加し、作成してほしい仕様やルールなどを書き込む（あまりいい例ではないですが、悩んだ場合は[この記事のリポジトリのファイル](https://github.com/robitan/solar-system-simulator-with-cline/blob/main/.clinerules)をご参照ください。または下記の参考URLなどもご参照されるのもよいと思います）
1. Clineへプロンプト（命令文） `initialize memory bank` を送る → memory-bankディレクトリ以下に必要なファイルが作成される
1. modeを「PLAN」にして、 `follow your custom instructions` と命令 → Clineが計画をたてはじめる![スクリーンショット 2025-02-19 0.36.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210824/c150ff56-794c-44cc-8b08-e90cbd082d1e.png)

1. 計画を終えたClineが `モードを「ACT」にして、続けるボタンを押して` 的なことを言ってくるので、言われた通りに実行![スクリーンショット 2025-02-19 0.29.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210824/61a24b89-69f8-432f-a4f6-9fb0c88bac20.png)

1. あとはときどきClineに請われるままにボタンを押す。途中途中けっこう動かなかったりするけどClineを信じて押す。
1. セッションを切り替える必要（New Chatから始め直す必要）が発生したら、まずは `update memory bank` と命令してMemory Bankを更新。その後は再び `follow your custom instructions` と命令すれば、あとは前項と同じ。
1.  完 成 🙌

とっても簡単ですね！

この記事がお役に立ちましたら幸いです。

# 参考URL

 - https://qiita.com/reoring/items/0c359cc4323bf89965a1
 - https://github.com/nickbaumann98/cline_docs/blob/main/prompting/custom%20instructions%20library/cline-memory-bank.md
 - https://zenn.dev/berry_blog/articles/c72564d4d89926
 - https://zenn.dev/watany/articles/50665ee40f4948
 - https://github.com/RooVetGit/Roo-Code/blob/main/.clinerules
システム開発における工程

## システム開発における工程

今回はシステム開発における工程の手順と内容をご紹介します。

※ 全ての開発現場が同じ手順でないことをご了承ください
※ Webサイト・アプリ開発なども便宜的にシステム開発と同義として扱う

### 1. 計画・予算見積もり

まずは計画を立てます。その際に顧客などとの打ち合わせで予算や見積もりなども決定していきます。
顧客折衝などもこのフェーズに含まれます。

### 2. 要件定義

その名の通り、システムに必要な要件を定義します。
このフェーズでも顧客折衝が含まれる可能性もあります。

### 3. PoC

Proof of Concept（プルーフ・オブ・コンセプト）の略で、日本語では「概念実証」や「コンセプト実証」といいます。私はより分かりやすいように、「技術検証」と呼んでいます。
設計フェーズで、「あれ、これ技術的に実現不可能じゃね？」とならないように、先んじて要件の技術検証をしておきます。

### 4. 基本設計

システムの仕様、具体的な機能を明確にします。
例えば、システムに必要な機能として「ログイン機能」や「売買機能」などを記述します。
また、処理の流れを図にして全体を把握するような役割もあります。

### 5. 詳細設計

システムの仕様をより詳細にします。
上記の基本設計に則るなら、「ログイン機能」や「売買機能」の仕様を記述します。
例えば、用意する関数、引数、フィールド、クラス、リクエスト方法など...

### 6. 実装・開発

設計書に基づいて機能を実装・開発していきます。

### 7. 単体テスト

`5. 詳細設計`に対応するテストです。
プログラムを構成する比較的小さな単位(ユニット)が個々の機能を正しく果たしているかどうかを検証するテストです。
詳細設計で記述されている機能は単体テストによって実装を確認できます。

### 8. 結合テスト

`4. 基本設計`に対応するテストです。
複数のプログラムやモジュールを組み合わせた際に、意図したとおりに動作するかどうかを検証するテストです。
詳細設計で記述されている各機能の結合 = 基本設計の機能　は結合テストによって実装を確認できます。

### 9. システムテスト

`3. 要件定義`に対応するテストです。
システム開発の最終段階のテストで行われることが多く、システムが問題なく要件を満たせているか全体的に確認します。

### 10. その他作業

このフェーズは要件によっては必要のない場合もあるでしょう。
必要なケースは例えば、データの本番移行作業などです。

### 11. リリース

リリースして終了です。と同時に運用保守のフェーズに入っていきます。

## まとめ

以上、システム開発における工程をご紹介しましたが、これはあくまで私がいた現場に基づいて作成した手順になります。

規模によってはあるフェーズが省略されていたり、各フェーズが合体されて1つのフェーズになっていることがあるでしょう。

ご参考程度によろしくお願いいたします。
マクロ定義関数

以下のコードを実行すると、エラーが出る。「8行目で')'が必要です」とのこと。

```cpp: マクロていき関数
#include <stdio.h>
#define sum(x, y) (x + y);

int main(void)
{
   int a = 10;
   int b = 20;
   printf("合計は%d", sum(a, b));

   return 0;
}
```

2行目の`#define sum(x, y) (x + y);`末尾のセミコロンが原因。うっかり打ってしまいがち。
マクロ関数は、呼ばれた場所で、定義されたとおりに丸ごと展開される。行末にセミコロンがあると、それもろとも展開されてしまう。
このコードでは、8行目が`printf("合計は%d", (a + b););`となり、printf関数の閉じカッコが見当たらないといわれる。

仮引数や返却値の型をいちいち設定しなくてもよくなったり、実行効率が上がったりというメリットがある一方で、インクリメントの挙動を見落としたり、使い方によっては展開式が煩雑になったりで、マクロて関数も一長一短…ということらしい。
【Telegraf】 MongoDBを3.4から7.0にしたらGrafanaでMongoDBのグラフが出なくなった

タイトルの通りですが、この場合、Telegraf をインストールしたサーバで

```
tail /var/log/telegraf/telegraf.log
```

とすると

```
2025-01-01T08:00:35Z E! [inputs.mongodb] Error in plugin: unable to connect to MongoDB: no reachable servers
```

などと出ます。結論から言うと Telegraf をバージョンアップすれば解決します。

ちなみに上記の問題が出た Telegraf のバージョンは `telegraf-1.17.0-1.x86_64` でした。

Telegraf の更新、具体的には、CentOS7では以下。

```
yum update telegraf
```

ですが、

```
The GPG keys listed for the "InfluxDB Repository - RHEL 7" repository are already installed but they are not correct for this package.
```

と出て、バージョンアップできないことがあります。

その場合は、 `/etc/yum.repos.d/influxdb.repo` を書き替えて、

```
gpgkey = https://repos.influxdata.com/influxdb.key
```

となっているところを

```
gpgkey = https://repos.influxdata.com/influxdata-archive_compat.key
```

とし、

```
yum clean all
```

としたあと、 `yum update telegraf` でうまく行くかと思います。

`systemctl restart telegraf` をお忘れなく。

---

Telegraf をバージョンアップしたあと、ログにこんなエラーが出ることがあるようです。

```
2025-01-01T08:00:29Z E! [outputs.influxdb] When writing to [udp://xxx.xxx.xxx.xxx:8089] could not serialize metric: "xxxxxxxxxxxxxxxxxxxx": need more space
```

`/etc/telegraf/telegraf.conf` の `[[outputs.influxdb]]` 下に

```
  udp_payload = 10240
```

としたら治りました。10240はちょっと大きすぎかもしれないので、最初は1024とかから試してみてください。

以上
308日目 初めてのVue.js + TypeScript + API 社畜♀

初めてのVue.jsとTypeScript

## Vue.js + TypeScriptとは？

✅ Vue.js: Webアプリを作るためのJavaScriptフレームワーク
✅ TypeScript: JavaScriptに「型」をつけたもの（エラーが減る＆開発しやすくなる）

 Vue.jsとTypeScriptを組み合わせるメリット
 ・型チェックでエラーを防げる
 ・コードの補完が効く（開発が楽になる）
 ・チーム開発でもバグが減る

## Vue3 + TypeScript + APIでよく使う定番関数・機能まとめ

| 関数・処理 | 役割 |
|------|------|
| ref() | 変数をリアクティブにする（単一の値向け） |
| reactive() | オブジェクト・配列をリアクティブにする |
| computed() | 値を自動計算してくれる（APIから取得したデータを加工して表示するのにcomputed()が便利） |
| watch() | 変数の変更を監視して処理を実行（入力値が変わるたびにAPIを叩く時に使う） |
| onMounted() | コンポーネントが表示された時に実行 |
| onUnmounted() | コンポーネントが削除された時に実行 |
| onUpdated() | コンポーネントのデータが更新された時に実行 |
| props | 親 ⇒ 子にデータを渡す |
| emit | 子 ⇒ 親にイベントを送る |
| defineProps() | setup()内でpropsを使うための関数 |
| defineEmits() | setup()内でemitを使うための関数 |
| useStore() | Piniaを使って状態を管理 |
| fetch() / axios.get() | APIからデータを取得 |
| axios.post() | APIにデータを送信 |
| Pinia | アプリ全体の状態管理（VueではPiniaを使うとAPIから取得したデータをグローバル管理できる） |

### エディターの初期化(initEditor())

✅ ref()でHTML要素を取得
✅ onMounted()でコンポーネントが表示されたときにエディターを初期化

### APIからデータを取得（GET）

✅ axios.get()でAPIからデータを取得
✅ onMounted()でコンポーネントが表示されたら実行

### Vueのライフサイクルでよく使う関数

onMounted(): コンポーネントが表示時に実行
onUnmounted(): コンポーネントが削除された時に実行
onUpdated(): コンポーネントのデータが更新された時に実行

✅ APIを叩くときにonMounted()をよく使う

## Vue.js + TypeScriptにおける async / await の基本と使い方

#### 1.async / await とは？
📌 async / await を使う理由
・APIのデータ取得や非同期処理を簡単に書ける
・コードが読みやすくなる

✅ 非同期処理とは？
すぐに結果が出ない処理を、待たずに実行できるようにする仕組み（例: API通信、DB操作）

#### 2.async / await の基本
❌ awaitなし（悪い）
⇒ APIのデータが取れる前にconsole.logが実行されてしまう

✅ async / await を使う（正しい）
⇒ awaitをつけると、データ取得が終わるまで待ってくれる
   関数に async をつけないと await は使えない

#### 3.Vueコンポーネントで async / await を使う
📌 onMounted()でAPIを取得
⇒ onMounted(): コンポーネントが表示されたらAPIを叩く

#### 4.await を Promise.all()で並列処理

通常、APIを１つずつ待つと時間がかかることがある。
Promise.all()を使うと複数のAPIを同時に実行できる。
⇒ 待ち時間を短縮

#### 5.async / await を使うイベント処理
ボタンをクリックした時にAPIを実行することもよくある。
VueでAPIを使うなら async / await は絶対に必須！
📌 awaitをボタンクリックイベントで使う

awaitをつけることで、APIのデータ取得が終わるまで待てる！

✅ ボタンをクリックするとhandleClick()が実行される
✅ 送信中はボタンをdisabledにして2回押せないようにする

#### 6. async / await / watch()を組み合わせる
データの変更を監視して、非同期で処理を実行したいときにwatch()を使う
入力値が変わるたびにAPIを実行できる
📌 watch()でデータが変わったらAPIを取得

#### 7. computed()でデータを加工
APIから取得したデータを加工して表示するのにcomputed()が便利
✅ データを計算・加工するときはcomputed()を使う

#### 8. Piniaでグローバルなデータ管理
VueではPinia（ピニア）を使うとAPIから取得したデータをグローバル管理できる
✅ Piniaを使うと、複数のコンポーネントでAPIデータを共有できる

Vue + TypeScript + APIでは「エラーを防ぐ」「処理を共通化する」のが大事！


**TO BE CONTINUED**
【トラブルシュート】ルーターのIPアドレス被り

# 概要

先日、とあるルーティングのセグメントから、インターネットに向けてアクセスできないという問い合わせがあり、対応を行った。。
こういった問題があったときに、どのような症状として見られ、どのような対応をしていけばわかったのか。対応した手探りの手順を今後のために記載する。


## 経緯の概要
1. サーバセグメントから、インターネットに向けて出ていけない。通信が不安定という問い合わせを受けた。
1. サーバセグメントからtracerouteを実行し、戻りのパケットで止まっている事を確認できた。
1. 下位ルータ側のルーティングテーブルを確認。
1. 下位ルータのOSPFテーブルのコストを確認
1. それぞれのtcpdumpを追加。
1. 上位ルータにてtcpdumpを実行
1. 上位・下位ルータにてarpを確認する。
1. 上位ルータで表示されるMACアドレスが、下位ルータの実際にやり取りするMACアドレスと異なる事を確認する。
1. MACアドレスから、juniperのNATで既に使用しているアドレスである事を確認する。
1. このNAT設定は既に使われていないため、この設定を削除する。
1. このARPテーブルを更新させるために、下位テーブルからMACアドレスをGARPで更新させる。
1. 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/59684f67-021d-4aaf-b5cf-885a9280d1ce.png)


## 具体的にやっていったこと。

サーバ 1から、インターネットに向けてtracerouteをする。
```
traceroute -nI 8.8.8.8
```
この時、下位ルータと上位ルータは一応通っていたが、下位ルータがすごい反応が遅かった。
また、帰りの通信が戻ってこなかった。

下位ルータ2台にて、以下のコマンドを実行する。
```
show ip route
```
これで、上位ルータへのスタティックルートが設定されている事を確認する。
また、図では記載していないが他の社内セグメントには疎通ができる事を確認できた。

ECMP（分散処理）の設定が働いていないのか？と思い、下位ルータにてOSPFのコストを確認する。ここでは、1台だけコストを上げ、片方は下げるという事を行っている。
```
show ip ospf interface xxx
```

tcpdumpを下位ルータに実行する。すると、ルータ側では戻りのパケットでは返ってこない事を確認した。
```
tcpdump -nn -e -i eth2 host 8.8.8.8 and icmp
```

上位ルータ側で、下位ルータのMACアドレスが表示されるか確認した。
2台冗長構成の場合は2台両方で実施すること。
```
show arp | include 下位ルータのMACアドレス。
```
これをみると、うまくMACアドレスが表示されない事を確認した。
下位ルータにて、以下のコマンドを実行してみる。この時点で、上位ルータのMACアドレスが見れるか確認する。
```
tcpdump -nn -i eth2 arp 
```
ここで、上位ルータにて以下のコマンドを実行する。
```
show arp 下位ルータのIPアドレス
```
これで表示されるMACアドレスが、どうも下位ルータのMACアドレスと異なるようだ。

juniper側のコンフィグを見ると、アドレスが使用されている事を確認したため、削除を行った。

その後、下位ルータで以下のGARPコマンドを実行して、隣接するネットワーク帯にいるMACアドレステーブルを書き換えさせた。`-U`は、`-A`でも更新できる。
```
arping -U -I eth2 下位ルータのIPアドレス
```
なぜかapt updateで躓いた時の話

# 問題に至った背景
業務でLinuxを使っています。当然プロキシ配下にあります。
いつも通り、`apt update`しようとしたところなぜかうまくいかない。。もしやプロキシ情報が変わったのか、と思いIT関連の担当者に問い合わせるも特に変わっていないとのこと。そんな時に確認したことと今回解消した手段を記録しておきます。

## 今回解消した方法
一定時間待つ！

# 原因
大きくは二つありました。
- システム時間がaptサーバよりも遅れていたこと
- aptのパッケージ更新がコマンド実行直前行われていたこと

以上の事象が重なったことで、現時点ではないはずの未来の更新情報を取得したと判定されてうまくupdateができなかったと考えられます。

# 対策
- 一定時間待つ!(再掲)
- システム時間を大胆な未来に設定しておく
- 時間を司るサーバのプロキシを設定しておく <- やり方がわからないのでご存じの方教えてください。。

## apt updateできないときに確認すべきこと
1.プロキシ設定は間違いないか？
2.依存関係に問題がないか？
3.極端に古いリンク切れのパッケージをリストに加えていないか？

# 最後に
今回は事象としてレアなためか当時記事が見当たらなかったため、備忘録として残しました。こういう問題って解消したときにすっきりしますよね！
atcoder_水色精進記録3

# Atcoder水色精進記録
挑戦していた水色が自力で解けなかったため、未ACの緑
ABC218
E - Destruction
https://atcoder.jp/contests/abc218/tasks/abc218_e

# アルゴリズム・データ構造
DP

# 考察
辺を取り除く最低が規定されていないため、負の辺は取り除く必要なし
取り除いていい辺はできるだけ値が大きい方が良い
→Cの値でsortして小さい順にUnionFindで結合、すでに連結だったらその辺を取り除く
(ただし、Cが0以上の場合)

計算量
事前ソート　NlogN
loop数　N
UnionFind ならし：α(N)　最悪：logN
全体 NlogN

# 提出
https://atcoder.jp/contests/abc218/submissions/62900211

# 感想
UnionFindについて慣れてきた。
緑色の問題はかなりの確率でACできる。(Atcoderの色判定の精度がすごい)
フリーランスエンジニアは2025年をどうサバイブするか

もう2月なのですが、このタイミングで、2025年の展望など書きたいと思います。単に気づいたら2月でした。時間の流れは怖い。

さて、今年はIT業界にとって昨年以上に変動の年になるのではないかと感じています。理由は言わずもがな生成AIの進化によるところです。これから恐ろしいスピードで私たちの仕事の在り方が変換していくことでしょう。果たしてエンジニアとして生き残ることができるのだろうかという危機感もありますが、楽しみな気持ちの方が大きかったりします。

「エンジニアの仕事がなくなるのでは？」という声もあちこちで聞こえてきますが、個人的には短期的にそのような事態が起こるとは考えていません。むしろ、日本のIT業界は依然として深刻な人材不足に直面しており、経済産業省の試算では2025年には最大で43万人のIT人材が不足すると予測されています。いわゆる「2025年の崖」です。

2023年2月時点の日本のITエンジニア数は約144万人と推計されています。単純計算すると、現在のIT人材1人あたりの生産性を約1.3倍に高める必要があることになります。数字だけを見ると「生成AIを活用すると何とかなるのでは？」と思えるかもしれませんが、ここで我々エンジニアが忘れてはならないのが『人月の神話』です。1人の生産性が1.3倍になったところで、システム開発全体の生産性がそれに比例して向上するとは限りません。むしろ、開発組織をうまくドライブさせなければ、その恩恵を受けることすら難しいのが実情です。

こうした状況を踏まえると、生成AIの恩恵を最も受けやすいのは、大企業ではなく、フリーランスやスタートアップのような小規模な組織であると考えています。個人や少人数のチームは、意思決定が早く、柔軟に新しい技術を取り入れることができるため、AIの進化を武器にできる可能性が高いです。

# 2025年以降のフリーランスエンジニアに求められること
2025年以降のエンジニアにとって最も重要なのは、「AIを活用した仕事に慣れること」です。AI駆動開発、AIを用いた技術研鑽、AIを活かした業務の自動化などで、フリーランスエンジニアは、AIを使い倒し、その知見を組織にフィードバックできる人材となることが生き残る鍵になると個人的には考えています。

仕事がなくなるわけではない。しかし、仕事のスタイルは劇的に変化する。2025年は、この変化を最大限に楽しみながら適応していきたいものです。
[ODC]ODC Studio上のScreen名とURLのパスの一部を別にする

通常、ODCのScreen名はURLのパスの一部として使われる。
ScreenのNameプロパティがScreen1であれば、URLは
　https://FQDN/App名/Screen1
 のようになる。

これを、ScreenのName=Screen1のまま、URLを
　https://FQDN/App名/ChangedURL
のように変更する手順を確認する。

# 環境情報
ODC Studio(Version 1.5.9)

# 設定方法と各項目の説明
ドキュメントは見つからなかった（2025/02/18時点）が、実験してみた結果、ScreenのAdvanced下にあるCustom URL=Yesにし、Page NameにURLのページ部分に使いたい内容を設定すれば良い。

設定箇所と各項目の説明は以下の通り。

Screenプロパティ（赤枠部分）
![スクリーンショット 2025-02-18 23.34.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/9aa4ba83-1491-431f-855d-78c54eb72acb.png)

赤枠内の各項目の説明
- Custom URL: デフォルトはNo。Yesにすると、URLをカスタムできる（Yesの時のみ、Page NameとURL Structureを設定可能）
- Page Name: Text型。URL内のPage部分のパスを設定する
- URL Structure: Query string/Pathから選択。ScreenのInput Parameterをクエリストリングで受け取るか、パスで受け取るかを制御する

URL Pattern項目は変更不可。
Page Name・URL Structure・Input Parameterから決定される、実際のURLの相対パス部分を表示する。

# 実験結果
Screen NameはCustomURLTestとして、各プロパティの値を変更して実験してみた結果は以下の通り。

| Custom URL | Page Name | URL Structure | URL Pattern| 実際のURL例（相対） |
|:-:|:-:|:-:|:-:|:-:|
| No  | - (入力できない）  |  -（入力できない） | CustomURLTest?In1={In1}&In2={In2}  | CustomURLTest?In1=test1&In2=test2 |
| Yes  | ChangedURL  | Query string  | ChangedURL?In1={In1}&In2={In2}  | ChangedURL?In1=test1&In2=test2 |
| Yes | ChangedURL  | Path  | ChangedURL/{In1}/{In2}  | ChangedURL/test1/test2 |

# 注意点
Custom URLをYesにすると、Screen Nameを使ってのアクセスはできなくなる。
上の実験例で言うと、Custom URL=Yesとした場合、ChangedURLでアクセスはできるが、CustomURLTestではアクセスできなくなる。

つまり、この設定で可能なのは、URLの置き換えであって別名をつけることはできない。
【UE5】UIにMeshを表示する

# やりたいこと
レベルに配置してあるCharacterをUIに表示する

# 環境
Windows
UE5.3.2

## RenderTextureを作成する

ContentBrowserで右クリックしてRenderTextureを作成、適当なサイズにしておく。

## マテリアルを作成

マテリアルを新規作成して、
- Material DomainをUser Interfaceに変更
- Blend ModeをTranslucentに変更
![スクリーンショット 2025-02-18 232053.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85509/516c86e2-0e83-4f79-a082-c9fe566d5271.png)
- 上記で作成したRenderTargetをサンプルして、以下のようにノードを繋ぐ
![スクリーンショット 2025-02-18 232239.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85509/252c13e8-d40d-45aa-884e-b5a13fde5305.png)


## SceneCaptureComponent2D

- Characterに`SceneCaptureComponent2D`をAddする
![スクリーンショット 2025-02-18 230122.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85509/6d7b8205-ba57-482f-bc15-681a477bd060.png)
- Texture Targetを作成したRenderTextureにする
![スクリーンショット 2025-02-18 230232.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85509/309de8ef-a502-445d-b246-567bd9c20115.png)
- SceneCaptureComponent2Dの位置を調整してキャラクターが映るようにする
- Character Blueprintを以下のように組む
![スクリーンショット 2025-02-18 233907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85509/9505ac5e-d6f7-478d-9ebc-2b35472104ec.png)


## UIを作成
- Widget Blurprintを作成して、Imageが表示できるように適当にUIを組む
- ImageのBrush→Imageに上記で作成したマテリアルを設定する

![スクリーンショット 2025-02-18 232811.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85509/c5a7d755-d18b-4034-8dc4-20abcc3cc9b6.png)

# 結果
![スクリーンショット 2025-02-18 234204.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85509/f24cd087-e24a-49d7-9486-de39729fedd7.png)
PHP explode関数

## 説明
文字列をも文字列により分割し、文字列の配列を返す。

## 使い方
```php
explode($separator, $string, int $limit = PHP_INT_MAX)
```
## 使用例
使用例①
```php
<?php
$input1 = "hello";
$input2 = "hello,there";
$input3 = ',';
var_dump( explode( ',', $input1 ) );
var_dump( explode( ',', $input2 ) );
var_dump( explode( ',', $input3 ) );
?>
```
出力は以下の通り
```
array(1)
(
    [0] => string(5) "hello"
) 

array(2)
(
    [0] => string(5) "hello"
    [1] => string(5) "there"
)
array(2)
(
    [0] => string(0) ""
    [1] => string(0) ""
)
```
使用例②
```php
<?php
$str = 'one|two|three|four';

// 正の値を持つ limit
print_r(explode('|', $str, 2));

// 負の値を持つ limit
print_r(explode('|', $str, -1));
?>
```
出力は以下の通り
```
Array
(
    [0] => one
    [1] => two|three|four
)
Array
(
    [0] => one
    [1] => two
    [2] => three
)
```
limitが負の値-nの場合は最後のn個を除くすべての構成要素が返される。
スライドパズルをJavaScriptで実装！シンプルだけど奥深いパズルの作り方

# スライドパズルをJavaScriptで実装！Swap型 & Slide型の2種類を比較

## はじめに

スライドパズルはシンプルながら奥深いパズルゲームです。本記事では、JavaScriptを用いて **Swap型** と **Slide型** の2種類のスライドパズルを実装しました。それぞれの違いとコードの解説を行います。

## Swap型スライドパズル

### 特徴
- 任意の2つのタイルを入れ替える方式。
- 数字の順番を整えていくロジックが必要。
- 直感的にプレイしやすい。

### コード
```html
<style>button{font-size:50;width:100;height:100</style>
<body id=b><script>
	z=3,Z=z*z,x=Z-1;
	for(p="x",i=x;i;p=[i--,...p]);
	for(i=0;i<2*Z;i+=r-t?1:0)[p[r],p[t]]=[p[t=new Date%x],p[r=new Date%x]];
	m=n=>{
		N=n-x;
		if((~~(n/z)==~~(x/z)&&(n+x)%2)||N==z||N==-z)p[x]=p[n],p[n]="x",x=n;
		b.innerHTML=p.map((v,i)=>`${i%z?"":"<br>"}<button onclick=m(${i})>${v}</button>`).join``
	};m()
</script>
```

### 解説
1. **変数の初期化**
   - `z=3` で3×3のパズルを設定。
   - `Z=z*z` で全タイル数を計算。
   - `x=Z-1` で空白セルの位置を最後に設定。
2. **初期状態の設定**
   - `p` 配列に数値を格納し、シャッフル。
3. **タイルの移動処理**
   - 同じ行で隣り合っている、または上下に並んでいる場合のみ入れ替え。
   - `m(n)` 関数でクリック時の処理を実行。

## Slide型スライドパズル

### 特徴
- 空白タイルをスライドさせる方式。
- パズルゲームとして一般的。
- 適切な順序でスライドさせる戦略が必要。

### コード
```html
<style>button{font-size:50;width:100;height:100</style>
<body id=b><script>
	z=3,Z=z*z,x=Z-1;
	for(p="x",i=x;i;p=[i--,...p]);
	for(i=0;i<2*Z;i+=r-t?1:0)[p[r],p[t]]=[p[t=new Date%x],p[r=new Date%x]];
	m=n=>{
		f=p.filter((_,i)=>i%z==n%z);
		((t=n/z|0)-(s=x/z|0))||(p.splice(x,1),p.splice(x=n,0,"x"));
		if(/x/.test(f)){
			f.splice(s,1),f.splice(t,0,"x");
			for(i=n%z;i<Z;i+=z)p[i]=f[i/z|0];
			x=n
		}
		b.innerHTML=p.map((v,i)=>`${i%z?"":"<br>"}<button onclick=m(${i})>${v}</button>`).join``
	};m()
</script>
```

### 解説
1. **初期設定**
   - `x=Z-1` で空白の位置を最後にする。
   - `p` 配列をシャッフル。
2. **タイルのスライド処理**
   - 空白と同じ行または列のタイルをスライドさせる。
   - `m(n)` でクリック時のスライド処理を実行。

## まとめ

- **Swap型** はどこでもタイルを入れ替え可能で直感的。
- **Slide型** は空白を動かす一般的なパズル。
- どちらも短いコードで実装可能！

興味のある方はぜひ試してみてください！
bashスクリプト

<h2>事前知識</h2>

<h3>ルールとして素晴らしい</h3>

https://zenn.dev/portinc/articles/bash-best-practice



<h2>echoの動き</h2>

```
#DISK容量の情報を変数に格納
[root@centos8_1 ~]# DISKSIZE=$(LANG=C df)
[root@centos8_1 ~]#

#echoの動作の違いを確認してみよう

#改行コードなしで1行で出てくる

[root@centos8_1 ~]# echo ${DISKSIZE}
Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 1883360 0 1883360 0% /dev tmpfs 1912824 16 1912808 1% /dev/shm tmpfs 1912824 17620 1895204 1% /run tmpfs 1912824 0 1912824 0% /sys/fs/cgroup /dev/mapper/cs-root 26631472 8026144 18605328 31% / /dev/sda2 1038336 240896 797440 24% /boot /dev/sda1 613184 7404 605780 2% /boot/efi tmpfs 382564 12 382552 1% /run/user/42 tmpfs 382564 0 382564 0% /run/user/0

#変数をダブルクォーテーションで囲むと改行が追加される

[root@centos8_1 ~]# echo "${DISKSIZE}"
Filesystem          1K-blocks    Used Available Use% Mounted on
devtmpfs              1883360       0   1883360   0% /dev
tmpfs                 1912824      16   1912808   1% /dev/shm
tmpfs                 1912824   17620   1895204   1% /run
tmpfs                 1912824       0   1912824   0% /sys/fs/cgroup
/dev/mapper/cs-root  26631472 8026144  18605328  31% /
/dev/sda2             1038336  240896    797440  24% /boot
/dev/sda1              613184    7404    605780   2% /boot/efi
tmpfs                  382564      12    382552   1% /run/user/42
tmpfs                  382564       0    382564   0% /run/user/0

```

<h2>ディスクサイズ確認スクリプト</h2>

```
[root@centos8_1 ~]# cat df.sh
#!/bin/bash

LANG=C

WAR=80

DISKSIZE=$(df)

echo "${DISKSIZE}" | grep '/dev'> df.txt


while read  FILESYS BLOCK USED AVAIL USE MOUNT
do

    if [[ ${USE%\%} -lt ${WAR} ]] ; then

        echo "GOOD"

    else

        echo "DISK SPACE ${USE}"

    fi



done < df.txt




```


やっぱりセンスがない(笑)




```
#!/bin/bash

while read line

do

numnum=`expr ${line} - 1`

STR=`sed -n ${numnum}p xyq.txt`


if [[ "$STR" != "zzz" ]];
then

  echo ${line}

fi


done < num.txt

```
PowerAutomateを使用してAWS S3ファイルを格納する方法

# この記事の作成に至った経緯
現在対応している案件で、MS Dataverse上に存在するデータをPowerAutomateを使用してCSVファイルとして保存し、その後SharePointとAWSのS3環境に保存してほしいと依頼を受けました。
なかなか需要のある技術かはわからないですが、個人的な備忘録もかねてこちらに記事投稿をすることでアウトプットしておこうと思った次第です。

## ワークフローの流れ
簡単に表したのものではありますが、全体のワークフロー図としては下記のようなイメージになります。
```mermaid
graph LR;
    A(トリガー)-->B(データの作成とSharePointに格納);
    B<-->C(Lambdaを呼び出し、AWSから認証機能つきURL取得);
    B-->D(認証機能付きURLを使いS3へPUTリクエストを送る);
```
トリガーからデータの作成やSharePointへの格納はよく使われる機能だと思うのでここでの説明は省きます。
SharePointに格納したファイルを「コンテンツを取得」のアクションで取得したのち、HTTPのアクションを使いPowerAutomateからPOSTリクエストをAWSのLambdaを呼び出しS3への認証機能が付与されたURLを発行後、そのURLへPUTリクエストを送信することで今回の要件を満たすことができます。

## AWSへHTTPリクエストを送信する際に必要な設定
PowerAutomateからLambdaや認証機能付きのURLへリクエストを送るためにはいくつかの設定が必要になります。
1\.IAMの設定
ここではユーザーの作成、アクセスキーIDとシークレットアクセスキーIDの取得、ロールの設定（S3へのアクセス権限）が必要になります。

2\.API Gatewayの開通
ここでAPIを作成しPowerAutomateからLambdaへリクエストを送信します。


3\.Lamdaへのコーディング
私はS3の環境へPowerAutomateから受け取ったファイル名のcsvファイルを核のする際に必要な認証URLを作成するコードをPythonで書きました。

## 今回のフローを開発した際の注意点
今回のワークフローを組むことで、どんなファイルでもS3へのデータ移送ができるようというわけではなく、PowerAutomateやAWSにいくつかの制限があるので最後に紹介したいと思います。

### PowerAutomateの制限
一度のアクションで処理できるデータの量は100Mbという制限があります。
これはSharePointからコンテンツを取得するときにも対象のファイルの容量が制限を超えているとエラーになるので気を付けましょう。
https://learn.microsoft.com/ja-jp/power-automate/limits-and-config

### AWSでの制限
API Gatewayを使用して取得したファイルをAWSへの移送をすることは可能ですが、作成したAPIを使用してデータの送信をする場合は容量が10Mbまでという制限がかかっています。
一方でREST APIやAWS CLIを使用してPUTリクエストを送信する場合は5Gbまでこの制限が引き上げられるので、PowerAutomateを使用する場合の実質的な制限は100Mbとなります。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/limits.html
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/upload-objects.html
uvにてAWS CodeArtifactのPythonパッケージをインストールする

CodeArtifactでホストしているPythonのパッケージをuvでインストールする方法についてです。

まず、以下の公式のドキュメントにも方法がいくつか記載があります。こちらも確認してみてください。

https://docs.astral.sh/uv/guides/integration/alternative-indexes/#aws-codeartifact


上記のドキュメントに記載が無い方法を書こうと思います。



## index毎の認証を環境変数で渡す方法について

`pyproject.toml` にて以下のようにCodeArtifactの情報を設定を準備します。

この設定に対して認証情報を渡します。

```toml
[[tool.uv.index]]
name = "myartifact"
url = "https://my-domain-012345678912.d.codeartifact.ap-northeast-1.amazonaws.com/pypi/my-repository/simple"
```

この時点だとCodeArtifactの認証が通らずにエラーとなります。

```sh
$ uv add my-package
Using CPython 3.12.9
Creating virtual environment at: .venv
  × No solution found when resolving dependencies:
  ╰─▶ Because my-package was not found in the package registry and your project depends on my-package, we can conclude that your project's requirements are unsatisfiable.

      hint: An index URL (https://my-domain-012345678912.d.codeartifact.ap-northeast-1.amazonaws.com/pypi/my-repository/simple) could not be queried due to a lack of valid
      authentication credentials (401 Unauthorized).
  help: If you want to add the package regardless of the failed resolution, provide the `--frozen` flag to skip locking and syncing.
```


以下のように `UV_INDEX_` 始まりの環境変数から認証情報を渡せるようになります。

```sh
# Tokenを取得します
AWS_CODEARTIFACT_TOKEN="$(
    aws codeartifact get-authorization-token \
    --domain $AWS_DOMAIN \
    --domain-owner $AWS_ACCOUNT_ID \
    --query authorizationToken \
    --output text
)"


# 以下の形式で認証情報を設定
# UV_INDEX_{tomlファイルのtool.uv.index.nameを大文字}_USERNAME=aws
# UV_INDEX_{tomlファイルのtool.uv.index.nameを大文字}_PASSWORD=${token}
export UV_INDEX_MYARTIFACT_USERNAME=aws
export UV_INDEX_MYARTIFACT_PASSWORD=${AWS_CODEARTIFACT_TOKEN}


# これでインストール可能です
uv add my-package
```
【CLI】コマンド出力が停止した際にスペーサーを挿入して見やすくする方法

spacerを使用するとコマンド出力が停止するたびに自動でスペーサーが挿入され、ログなどが見やすくなります。

https://github.com/samwho/spacer

## spacerのインストール

Homebrewを使用する場合には以下のコマンドを実行することでインストールできます。

```terminal
brew install spacer
```

## 使い方

以下のようにコマンドを実行すると指定した時間経過すると自動でスペーサーが挿入されます。

```terminal
your command | spacer --after 5
```

`--after`を指定しない場合には1秒間隔でスペーサーが挿入されます。

![スクリーンショット 2025-02-18 23.02.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/2ad43f25-25fe-4f94-836f-9653323e693f.png)

エラー出力も考慮する必要がある場合には以下のように実行します。

```terminal
your command |& spacer --afeter 5
```

fishを使用している場合には`|&`の代わりに`&|`を使用します。