OmniAICreator/Qiita-1.07M huggingface dataset:
pyenvについての解説

この記事では pyenv とはどういうもので、どのようなことできるのかを解説しています。
Windows環境での利用方法について説明しています。



# pyenvとは
pyenv は Python のバージョン切り替えを行うためのツールです。
pyenv を使用すると、異なるバージョンの Python をインストールすることができ、バージョンの切り替えを簡単に行うことができます。
[公式サイト github.com/pyenv](https://github.com/pyenv/pyenv)
Windowsで使用する場合は Windows環境向けに開発された pyenv-win を使用します。
[公式サイト github.com/pyenv-win](https://github.com/pyenv-win/pyenv-win)

### グローバル環境を汚染しない
pyenv を使うと、ユーザーフォルダ配下に Python をインストールするため、他のプロジェクトやシステムに影響を与えません。

### プロジェクトごとに Python のバージョンを指定
プロジェクトごとに異なるバージョンの Python が必要な場合、pyenv を使えばディレクトリ単位でバージョンを指定できるため、プロジェクトごとに適切な環境を構築できます。



## インストール
Windows環境で使用する場合は pyenv-win をインストールします。
[公式サイト インストールページ](https://github.com/pyenv-win/pyenv-win/blob/master/docs/installation.md)
インストール方法はいくつかありますが、公式サイトで最も簡単な方法として掲載されている PowerSell でコマンドを実行する方法を解説します。

:::note warn
注意
その他の方法を使用する場合、手作業での環境変数の登録やpyenv実行ファイルへの権限付与などを行う必要があるためお勧めしません。
:::

PowerShell を開き以下のコマンドを実行します。
```powershell
Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"
```
実行するとユーザフォルダ `C:\Users\ユーザ名\` の直下に .pyenv フォルダが作成され、pyenv-win の関連ファイルが展開されます。

pyenv のバージョンを確認します。
```
pyenv --version
```
バージョンが表示されればインストールは成功しています。



## pyenv を使用して Python をインストール
pyenv は PowerShell でコマンド入力して操作します。

### インストール可能なバージョンを調べる
```
pyenv install --list
```

### インストール例 (3.10.0をインストール)
```
pyenv install 3.10.0
```
`C:\Users\ユーザ名\.pyenv\pyenv-win\version` にインストールされます。

### インストールされているバージョンを調べる
```
pyenv versions
  3.10.0
* 3.11.0 (set by C:\Users\ユーザ名\.pyenv\pyenv-win\version)
```
選択しているバージョンに * が付きます。



## バージョン切り替え
### Python のデフォルトバージョンを指定
```
pyenv global 3.10.0
```
pyenv global コマンドを実行すると、ログインしているユーザが使用する Python のバージョンが変わります。

バージョンが変更されていることを確認します。
```
pyenv versions
* 3.10.0 (set by C:\Users\ユーザ名\.pyenv\pyenv-win\version)
  3.11.0
```

Python のコマンドでも確認できます。
```
python --version
Python 3.10.0
```

### プロジェクトで使用する Python のバージョンを指定
プロジェクトのフォルダに移動してコマンドを実行します。
```
cd C:\project1
pyenv local 3.11.0
```
pyenv local コマンドを実行すると、現在のフォルダに対して Python のバージョンを指定します。


バージョンが変更されていることを確認します。
```
pyenv versions
  3.10.0
* 3.11.0 (set by C:\project1\.python-version)
```

設定の解除は以下のコマンドを実行します。
```
pyenv local --unset
```


## その他のコマンド
### インストール可能な Python バージョンのリストを更新する
```
pyenv update
```
pyenv install --list で検出するインストール可能な Python バージョンを更新します。
高火力 DOKをJavaScriptから操作するためのSDKでタスクを作成・キャンセル・削除する

[高火力 DOK](https://www.sakura.ad.jp/koukaryoku-dok/)はさくらインターネットの提供するGPUコンテナサービスです。DockerイメージをGPUを使って実行します。

[高火力 DOKではAPIが公開されている]()ので、操作しやすくするためのSDKを「野良」で作成し始めました。Pythonでも良いのですが、せっかくなら別言語ということで、JavaScript/TypeScriptで作成しています。

今回はタスクの作成とキャンセル、削除ができるようになったので使い方を解説します。

## 必要な情報

SDKを利用する際には、さくらのクラウドのアクセストークンとシークレットアクセストークンが必要です。どちらもさくらのクラウドのAPIキーの中で作成できます。

## インストール

SDKのインストールは `npm` で行います。
```bash
npm install @goofmint/dok-sdk
```

## 初期化

先ほど作成したアクセストークンとシークレットアクセストークンで初期化します。

```ts
import DOK from '@goofmint/dok-sdk';

const dok = new DOK({
  accessToken: 'your_access_token',
  accessTokenSecret: 'your_access_token_secret',
});
```

## タスクの作成

新しくタスクを作成する場合には `task` メソッドを使います。

```ts
const task = await dok.task();
```

### 必要な情報を追加する

タスクに対して、コンテナやタグなどを追加します。

```ts
task
  .set('name', 'test-delete-task')
  .set('tags', ['test', 'task']);
const container = await client.container();
container
  .set('image', 'your_container_image_name')
  .set('plan', 'v100-32gb')
  .set('environment', {
    TEST: 'test',
  });
task.containers = [container];
```

後は `save` メソッドで保存できます。

```ts
await task.save();
```

## タスクのキャンセル

作成した、または取得したタスクの実行をキャンセルする際には `cancel` メソッドを使います。

```ts
await task.cancel();
```

## タスクの削除

タスクを削除する際には `delete` メソッドを使います。

```ts
await task.delete();
```

## コード

コードはGitHubで公開しています。ライセンスはMIT Licenseです。

[@goofmint/dok-js](https://github.com/goofmint/dok-js)

## まとめ

高火力 DOKのAPIでは、タスクの作成やキャンセルなども行えます。Webサービスの中でタスクを作成したり、その完了を監視するようなこともできるでしょう。

高火力 DOK自体はバッチ処理など、非同期処理に向いたサービスになります。都度管理画面をチェックしたりするのは面倒なので、APIを使うのが便利そうです。

[高火力 DOK APIドキュメント](https://manual.sakura.ad.jp/koukaryoku-dok-api/spec.html)
高火力 DOKをJavaScriptから操作するためのSDK（野良）を開発しています

[高火力 DOK](https://www.sakura.ad.jp/koukaryoku-dok/)はさくらインターネットの提供するGPUコンテナサービスです。DockerイメージをGPUを使って実行します。

[高火力 DOKではAPIが公開されている]()ので、操作しやすくするためのSDKを「野良」で作成し始めました。Pythonでも良いのですが、せっかくなら別言語ということで、JavaScript/TypeScriptで作成しています。

現在はデータ取得系の一部ができた段階ですが、使い方を解説します。

## 必要な情報

SDKを利用する際には、さくらのクラウドのアクセストークンとシークレットアクセストークンが必要です。どちらもさくらのクラウドのAPIキーの中で作成できます。

## インストール

SDKのインストールは `npm` で行います。
```bash
npm install @goofmint/dok-sdk
```

## 初期化

先ほど作成したアクセストークンとシークレットアクセストークンで初期化します。

```ts
import DOK from '@goofmint/dok-sdk';

const dok = new DOK({
  accessToken: 'your_access_token',
  accessTokenSecret: 'your_access_token_secret',
});
```

## タスクの取得

タスクというのは、DOKの実行単位です。過去に実行したタスクの一覧が取得できます。

```ts
const { tasks, meta } = await dok.tasks();
```

`meta` はページネーションの情報が入っています。 `tasks` は `Task` クラスのインスタンスの配列です。

## タスクの取得（1件）

特定のタスク情報だけを得る場合には、タスクIDを引数に指定します。

```ts
const task = await dok.task(taskId);
```

## アーティファクトの取得

アーティファクトというのは、タスクの実行結果として得られる成果物です。たとえば画像生成した結果の画像だったり、動画などです。

```ts
const { artifacts, meta } = await dok.artifacts();
```

こちらも `meta` はページネーションデータ、 `artifacts` はアーティファクトの配列です。

## コード

コードはGitHubで公開しています。ライセンスはMIT Licenseです。

[@goofmint/dok-js](https://github.com/goofmint/dok-js)

## まとめ

高火力 DOKのAPIでは、タスクの作成やキャンセルなども行えます。Webサービスの中でタスクを作成したり、その完了を監視するようなこともできるでしょう。

高火力 DOK自体はバッチ処理など、非同期処理に向いたサービスになります。都度管理画面をチェックしたりするのは面倒なので、APIを使うのが便利そうです。

[高火力 DOK APIドキュメント](https://manual.sakura.ad.jp/koukaryoku-dok-api/spec.html)
アジャイルプロジェクトにおける「リスペクト」と「個人間の対話」の再考  


アジャイル開発では「個人と対話を重視する」という原則が冒頭に掲げられています。  
この言葉を、何度となく耳にした人も多いでしょう。日々のデイリースクラム、レビュー、レトロスペクティブ。形式的には“対話”の機会は確保されています。

しかし、プロジェクトの現場で起きているのは「形式化した対話」ではないでしょうか。対話はしているが、リスペクトに裏打ちされた“本質的なコミュニケーション”が成立していない、そんな感覚を覚えたことはないでしょうか。

私自身があるアジャイルプロジェクトに関わる中で、「このままでは対話が形骸化し、品質にも悪影響を与える」と感じる場面がありました。本稿では、その経験とともに、アジャイルにおけるリスペクトの意義を再考してみたいと思います。

---

## 形式的な対話では、品質は守れない

メンバー同士が発言しているように見えても、次のような“空気”が漂っている場合があります。

- 言いたいことがあるが、場の雰囲気を壊したくない
- 過去の意見が無視された経験から、発言を諦めている
- 意見は通らないという前提で形式的に賛同している

このような状態では、本来アジャイルが提供しようとしている「継続的な改善」や「迅速なフィードバックループ」は実現されません。むしろ、表面上の合意により、設計ミスや技術的負債が温存されていきます。

---

## リスペクトの欠如が招く開発上の損失

「リスペクト」は単なる人間関係のマナーではなく、技術的な意思決定の質やチーム全体のパフォーマンスに直結する構造的な要素です。現場レベルでは、以下のような損失が発生します。

### 技術的負債の黙認
若手や外部パートナーが、構造的な問題に気づいていても、意見を言えずに終わってしまう。「この設計、あとから苦しくなるのでは？」という声が抑圧され、結果として将来の大きなリファクタにつながります。

### 認識齟齬の見逃し
質問しにくい雰囲気があると、小さな仕様の誤解や認識のズレが初期段階で是正されません。これが手戻りを生み、レビューやQAフェーズでの手間が増えます。

### レビューの形骸化
レビュー時に相手を尊重せず、単なる粗探しや否定的な指摘が増えると、健全な議論が成り立たなくなります。逆に、空気を読んで「何も言わない」状態になれば、レビューそのものが持つ価値が失われます。

---

## リスペクトとは「聴く姿勢」ではなく「価値を信じること」

リスペクトとは、単に相手の意見に耳を傾けることではありません。  
その人が話す内容に「意味があるはずだ」と前提を置いて受け止める姿勢です。

アジャイルのチームは、専門性や視点の異なるメンバーで構成されています。だからこそ、相手の背景や意図に興味を持ち、思考を深掘りする姿勢がなければ、対話は表面的な情報交換に終始してしまいます。

---

## 対話を再構築するために、チームができること

以下のような工夫が、リスペクトを前提とした対話を再構築するきっかけになります。

### 1. 心理的安全性の確保
「どんな意見でもまずは受け止める」「否定ではなく質問から入る」といった文化を醸成することで、意見の多様性が引き出されます。

### 2. 対話の“余白”を作る
デイリースクラム以外にも、ペアワーク、1on1、雑談タイムなどを設け、メンバー同士の理解が深まる余白を持つことが、信頼関係の醸成につながります。

### 3. レビューの質を明文化する
レビューガイドラインに「人格攻撃ではなく、改善提案を重視する」などの原則を定め、レビュー文化の質を担保します。

---

## おわりに：リスペクトなきアジャイルは、アジャイルではない

アジャイルは「早く作る手法」ではなく、「人を信頼し、人を活かす開発のあり方」です。  
そしてその根底には、「このチームには耳を傾ける価値がある」という相互の信頼が存在します。

リスペクトとは、技術的な選択肢の幅を広げ、失敗を乗り越える余地を与え、チームの知性を増幅させる力です。  
形式だけの対話から一歩踏み出し、意図や背景を共有する対話へと昇華させていくこと。  
それこそが、アジャイルを“名ばかり”にしないための、最も根源的な実践だと私は考えます。
Dateオブジェクトの最高にクソな仕様をまた見つけてしまった

JavaScriptの標準ライブラリである`Date`オブジェクトの悪名高さは古今東西で有名であり、今更クソ仕様が一つ見つかった程度でなんだ、といった感想をお持ちの方も多いと思うが私はこれでハマったのでこの記事に記す。

# クソ仕様
```js
const d = new Date();
d.setMonth(3);
console.log(d.getMonth())
```

さて諸君、上記プログラムにおいて**3行目で出力される数字はなんであろうか**？正解は「**これだけからは分からない**」である。

より具体的に言うと`3`の場合と`4`の場合があり得る。3の場合はいいとして4の場合、これはこのプログラムを実行した日付が例えば5月31日だった場合である。`new Date()`は現在の日時で初期化されるので、`d`は現在の日付5月31日が入っている。これに対して`d.setMonth(3)`を実行すると4月31日になる（別の有名なクソ仕様、「月の数は1ずれる」を忘れてはならない）が、4月は30日までなので繰り上がり5月1日になるのだ。

# 別の見方
このアホな仕様は別の見方をすることもできる。

```js
const d = new Date(2022, 0, 31);
d.setMonth(8);
console.log(d); // 10月1日
d.setMonth(8);
console.log(d); // 9月1日
```

全く同じ文`d.setMonth(8);`を2回実行しているが、各文実行後の`d`の値は同じか？答えは「同じではない」だ。

前セクションと同様に1回目の`setMonth`後では「9月31日」が繰り上がって`d`は10月1日になる。その後もう一度`d.setMonth(8)`を行うと9月1日になるので、いかにもただのsetterっぽい名前の同じ関数を同じ引数で呼び出しているにもかかわらず、1回目と2回目の時点で値が異なる。

# この仕様の凶悪な点
この仕様が凶悪なのは、これを元にしたバグに気づきにくいことである。この仕様は`setMonth`の引数の月が2月, 4月, 6月, 9月, 11月の場合かつ、元の日付が31日（引数が2月の場合は29日〜31日）の場合のみしか発現しない。実際私は数年間この仕様によるバグを含んだままのコードを知らずに使っていた（以下のような感じ）。

```javascript
function f(d: Date, month: number, day: number) {
  d.setMonth(month);
  d.setDate(day);
}
```

# 感想
私は最初にこの仕様が原因のバグに当たったとき、これはブラウザ側のバグに違いないと思った。月の値がおかしいのでブラウザのデバッガのコンソールで`setMonth`をもう一度実行すると値が変わるのだ。どうしてこれが正しい仕様だと想像できようか。

# 宣伝
この仕様に当たったのは、私の書いているJavaScriptの日付時刻ライブラリ[@silane/datetime-js](https://github.com/silane/datetime-js)の開発中である。JavaScript標準の`Date`オブジェクトはこのようにクソすぎるので、私が良い設計だと思っている[Pythonの標準ライブラリ](https://docs.python.org/ja/3/library/datetime.html)を模倣するように作っている。しかし内部では日付時刻の計算に`Date`オブジェクトを使っているのでそこでバグが発生していた。テストは書いていたが発現条件が厳しいので漏れていたということですね。
【Laravel】ログイン後、ログアウト後の遷移先指定方法

# はじめに
ログイン、ログアウトに分けて解説していきます。

# ログインのリダイレクト先を変更
## 方法1：RouteServiceProvider.php で一括管理
```/app/Http/Controllers/Auth/AuthenticatedSessionController.php
# store() メソッド
return redirect()->intended(RouteServiceProvider::HOME);
```
### return redirect()->intended(RouteServiceProvider::HOME)の解説
Laravelのログイン後に**「元々アクセスしようとしていたページ」**があればそこに戻し、なければ RouteServiceProvider::HOME にリダイレクトする。

| 状況 | 遷移先 |
|:-----------|:------------|
| 🔙 ログイン前に auth が必要なページにアクセスしていた | そのページへ戻る（＝intendedの意味） |
| ⚙ 特にアクセス元がない | RouteServiceProvider::HOME にリダイレクトされる |

### RouteServiceProvider::HOME の場所と値
```app/Providers/RouteServiceProvider.php
# 一番上
public const HOME = '/dashboard';
```
つまり、最初の状態では「/dashboard に飛ぶ」という設定になっている。


## 方法2：AuthenticatedSessionController.php で個別に変更
```/Http/Controllers/Auth/AuthenticatedSessionController.php
# store() メソッドのリダイレクト部分を以下のように変更
# 編集前(方法1を済んでいたらこのままでOK)
return redirect()->intended(RouteServiceProvider::HOME);
# 編集後
return redirect()->intended('/'); // または任意のURL
```
ここでは RouteServiceProvider::HOME を使っていて、前述の HOME 定数と連動しています。
return redirect()->intended(...) = 「元々アクセスしようとしていたページに戻る」処理


# ログアウト後のリダイレクト先を変更
```/Controllers/Auth/AuthenticatedSessionController.php
# destroy() メソッドの最後にあるリダイレクト先を変更
return redirect('/admin'); // 任意のURLに変更可能
```


# ✅ まとめ
| 処理 | 変更箇所 |
|:-----------|:------------|
| ログイン後 | 「AuthenticatedSessionController@store」 or 「RouteServiceProvider::HOME」 |
| ログアウト後 | AuthenticatedSessionController@destroy |
MCP (Model Context Protocol) の利点と重要性

## はじめに
Anthropic（アンソロピック）社は、自社のウェブサイトで、MCP（モデルコンテキストプロトコル）を次のように説明しています。

>MCPは、アプリケーションがLLMにコンテキストを提供する方法を標準化するオープンプロトコルです。MCPは、AIアプリケーション向けのUSB-Cポートのようなものと考えてください。USB-Cがデバイスを様々な周辺機器やアクセサリーに接続する標準的な方法を提供するように、MCPはAIモデルを異なるデータソースやツールに接続する標準的な方法を提供します。

Anthropic（アンソロピック）社ウェブサイト: https://docs.anthropic.com/ja/docs/agents-and-tools/mcp より引用

![MCPの概要 - visual selection (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4058228/8766159f-e51c-4d8c-8a34-6d86ce6dbf6d.png)

MCPによって、AIモデルが様々なデータやツールに接続可能となることが、何となく理解できたものの、MCPを利用することの利点やその重要性に関するわかりやすい説明を知りたいと思い、少し調べてみました。

## MCP の利点
**標準化された通信:** MCP は、AI モデルと外部データソースやツールとの間の通信を標準化します。これにより、異なるAIモデルやサービス間での相互運用性が向上し、開発者は個別の API 統合に苦労する必要がなくなります。

**セキュアな連携:** MCP は、AI が外部システムにアクセスする際のセキュリティと認証メカニズムを標準化し、安全なデータ連携を可能にします。アクセス権限を細かく設定できるため、「AI にどこまで許可するか」をまとめてコントロールできます。

:::note warn
2025年4月16日18時33分追記

MCP にはセキュリティ上の懸念事項があるとの説明も多く見受けられます。この点については、別途調べてみたいと思います。
:::

**リアルタイムな情報アクセス:** MCP に対応した AI は、ウェブの記事やデータベース、API など、様々な外部データソースに直接アクセスし、最新かつ具体的な情報に基づいて応答できます。

**動的なツール利用:** MCP は、AI が外部アプリケーションやサービスの機能を呼び出すことを可能にします。例えば、カレンダーへの予定追加、地図サービスでの経路検索などを AI が自動的に実行できます。また、利用可能なツールを動的に検出して対話することも可能です。

**複数のサービスを横断:** 1つの AI アシスタントが複数のデータソースやツールに同時に接続できるため、「今日の予定に関連する最新ニュース」のような、横断的な質問への対応が可能になります。

**開発効率の向上:** 標準化された統合パターンにより、開発時間の短縮、メンテナンス性の向上、コンポーネントの柔軟な交換やアップグレードが容易になります。

![MCP の利点 - visual selection (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4058228/60737195-44e0-4604-8114-54b7c575d041.png)

## MCP の重要性
MCPは、AI が単なるテキスト生成ツールから、より実用的でコンテキストを理解し、外部の世界とインタラクションできるインテリジェントなエージェントへと進化するための重要な基盤となります。

**AI の能力拡張:** 外部データやツールへのアクセスを容易にすることで、AI はより複雑なタスクを実行し、より正確でタイムリーな情報を提供できるようになります。

**AIエコシステムの発展:** オープンスタンダードである MCP は、様々な AI モデル、ツール、データソース間の連携を促進し、より多様で強力な AI エコシステムの構築に貢献します。

**ユーザーエクスペリエンスの向上:** AI アシスタントがユーザーのコンテキストをより深く理解し、パーソナライズされたサポートを提供できるようになるため、ユーザーエクスペリエンスが向上します。

**業界標準の確立:** MCP は、AI と外部システムの連携における事実上の標準となる可能性を秘めており、業界全体の開発効率と相互運用性を高めることが期待されます。

![MCP の重要性 - visual selection (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4058228/72dbf506-b3d2-48de-8527-bc64fc254a62.png)

[参考にした記事]

https://portkey.ai/blog/model-context-protocol/

https://tldv.io/blog/model-context-protocol/

https://www.merge.dev/blog/model-context-protocol/
GitHub Copilot AgentでゲームメモのWebアプリを作りました

## はじめに

最近、ClineをはじめとするVibe Codingが話題になっています。実は私はまだ触れていなかったので、どんなものか体験するためにWebアプリを作ってみることにしました。

## 作成したもの

https://ggmemo.pokekoyomi.com

ゲームの戦績をメモするためのアプリです。ちょっとカッコつけて英語で作りました。

このアプリは2つのモードを提供しています。1つ目はアクセスするだけですぐに使える「Basic Mode」で、データはすべてブラウザのローカルストレージに保存されるため気軽に利用できます。2つ目はサインインして使用する「Session Mode」で、ユーザーに紐づいたデータがサーバー上に保存される仕組みになっています。

以下がスクリーンショットです。
![memoform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48665/6f7a17cf-3521-4605-a949-b406b1edf5ec.png)
![memolist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48665/9b841e80-588a-4d1b-bdce-d5334dd07c8b.png)

## 技術構成

技術スタックはシンプルで、Firebaseをメインに活用しています。構成は次の図のとおり。

![056e3bb6f6f4-20250415.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48665/120246df-2e45-432f-ac0d-91234eb8f2a0.png)


## エージェント

https://github.com/features/copilot

今回使用したのはGitHub Copilotのエージェント機能。

### Clineではない理由

私にとってVibe Codingといえば最初はClineというイメージでした。そして実際に使ってもいました。

OpenAIやAnthropicのAPIと連携して使う場合、当然ながら従量課金で費用が発生します。使用量を気にしながら開発するのは心理的な負担になりました。

そこで、GitHub Copilotを使用すれば、Cline + VS Code LM APIの組み合わせで同様のことが月額10ドルという定額で利用できることを知りました。

しかし、実際に使ってみると2つの問題に直面。

1. Claude 3.7 Sonnetが使用できない（UI上で選択はできても実行時にエラー）
2. 長時間使用するとRate Limitのエラーが発生する

1については、UI上では選択できるものの、実行しようとすると以下のエラーが表示されてしまいます。
```
「Request Failed: 400 {"error":{"message":"Model is not supported for this request.","code":"model_not_supported","param":"model","type":"invalid_request_error"}}」
```

2については、体感で連続2時間くらい使用するとエラーが出てしまいます。

意外と使いづらい、月額課金でケチにやっているから仕方ないか。そう思っていたところ4/4にGitHub Copilotのエージェントモードが提供開始。
https://forest.watch.impress.co.jp/docs/news/2004732.html

こちらに蔵替えしたところ使い勝手が上がったのでそのまま使い続けています。

### 使ってみた感想

これはやばいです。自身でコードを書かずともアプリができてしまいます。1行もコードを書かずともです。

さすがに大規模開発となるとインプットするソースコードの量も多いですし、実用に耐えうるかどうかは検証しないと分からないですが、私が作ったような小規模なアプリであれば全然余裕です。

思い描いたことがすぐにかたちにできるのはおもしろいですね。新感覚です。

また、AIが書いたコードをじっくり読むことで学習も進みそうです。過信は禁物ですが、少なくとも自分以外の書いたコードに触れるという機会が増えるのはとても良いことだと思います。

## Vibe Codingのコツ

### 1回1タスク

エージェントに頼むタスクはとにかく小さく。

セッション内の会話履歴は（おそらく）すべてリクエストに含まれるため、会話が長くなると応答が遅くなったり、最悪の場合Rate Limitに引っかかる可能性があります。Clineを使っていた際は、このコツがつかめておらず、1時間もしないうちにRate Limitに達してしまいました。

GitHub Copilotでは今のところRate Limitには遭遇していませんが、リソースには当然限りがあるため、できるだけ効率的に利用するよう心がけるべきでしょう。

### プロンプトを用意

Clineだと `.clinerules` ,  GitHub Copilotだと `.github/copilot-instructions.md` です。

他の人が書いたものを参考に自分好みに設定していけばある程度はうまく動きます。

## おわりに

ソフトウェアエンジニアリングの世界は年々進化しているのを実感します。来年のどんなふうに進化しているんだろう。楽しみでなりません。

今回作成したWebアプリ「GGMemo」ですが、使い捨てではなく今後もメンテナンスします。

ぜひ覗いてみてください！

https://ggmemo.pokekoyomi.com
GitHubのPRに動画をそのまま貼る方法（.mov→.mp4備忘録）

# 🎥 GitHubに動画貼るメモ（自分用）

## 🙋‍♀️ 背景  
UIの動きを共有したくて `⌘ + Shift + 5` で録画。  
でもそのままの `.mov` ファイルは  
- 容量オーバーでPRに貼れない  
- QuickTimeで書き出しても**ダウンロードしないと再生できない**

というのが不便に感じた。

---

## ✅ やったこと  

1. QuickTime Playerで録画ファイルを開く  
2. 「書き出す」→ `720p` を選んで軽量化（サイズを小さく）  
3. 書き出した `.mov` の**拡張子を `.mp4` に変更**  
4. GitHubのPRコメント欄に**ドラッグ＆ドロップ**

→ そのまま再生できて快適🙆‍♀️

---

## 💡メモ  
- `.mov` のままだと重い＆再生できない  
- 書き出し＋拡張子変更だけで現時点では十分
buildrootでVerovioを使う

# 目的

組み込みLinux環境で musicxml -> svg変換を行なう


# 手順

[Verovio](https://www.verovio.org/index.xhtml)のリポジトリは[ここ](https://github.com/rism-digital/verovio)

~~詳しくは調べてないがGPL-3.0使用モジュールがあるっぽいので
利用は注意が必要~~

LGPL選択すれば良いだけっぽい

以下のファイルが必要
```
└ package
  ├ Config.in  ## 既存ファイル
  ├ ...
  └ verovio
    ├ 0001-cmake.patch
    ├ package/verovio/Config.in
    └ package/verovio/verovio.mk
```

## package/verovio/Config.in

もしかしたらdependency(cairoとか)が必要かもしれない

```config
config BR2_PACKAGE_VEROVIO
    bool "Verovio"
    help
      A music notation engraving library
```


##  package/verovio/0001-cmake.patch

commit idは生成ツールがあるが、
gitからダウンロードしてきて
ビルドディレクトリに配置されたものはgit管理ではないので
そのまま動作させられない
バージョン固定でパッチ当てるのが楽と思う

cmakeはcmakeディレクトリに移動するより
ルートにCMakeLists.txt作った方が楽なのでは？との理由で

```diff
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..7bd7bc8
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8...3.19)
+project(Verovio)
+
+add_subdirectory(cmake)
diff --git a/include/vrv/git_commit.h b/include/vrv/git_commit.h
new file mode 100644
index 0000000..3ff4bb2
--- /dev/null
+++ b/include/vrv/git_commit.h
@@ -0,0 +1,6 @@
+////////////////////////////////////////////////////////
+/// Git commit version file generated at compilation ///
+////////////////////////////////////////////////////////
+
+#define GIT_COMMIT "-8c3069d"
+
```

## package/verovio/verovio.mk

事前にフォント生成しないといけない

```makefile
VEROVIO_VERSION = version-5.1.0
VEROVIO_SITE = https://github.com/rism-digital/verovio.git
VEROVIO_SITE_METHOD = git
VEROVIO_SITE_VERSION = $(VEROVIO_VERSION)
VEROVIO_GIT_SUBMODULES = YES
VEROVIO_LICENSE = LGPL-3.0

VEROVIO_DEPENDENCIES = host-python3

VEROVIO_CMAKE_BACKEND = ninja

define VEROVIO_GENERATE_FONTS
	cd $(@D)/fonts && ./generate_all.sh
endef

VEROVIO_PRE_BUILD_HOOKS += VEROVIO_GENERATE_FONTS


$(eval $(cmake-package))
```

# package/Config.in

適当な場所に追加する

```diff
diff --git a/package/Config.in b/package/Config.in
index a47fdad1..3154015c 100644
--- a/package/Config.in
+++ b/package/Config.in
@@ -312,6 +312,7 @@ menu "Graphic libraries and applications (graphic/text)"
 comment "Graphic applications"
        source "package/pdf-viewer/Config.in"
        source "package/pdf-viewer-lvgl/Config.in"
+       source "package/verovio/Config.in"
        source "package/cage/Config.in"
        source "package/cog/Config.in"
        source "package/dmenu-wayland/Config.in"

```



# 確認

qemuで表示するとこんな感じ

![Peek 2025-04-16 14-43.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786381/cb7b28b3-7609-4f45-bb82-6fce0a4aa51c.gif)


~~文字が表示されない原因は調査中~~

# 文字を表示する方法

fontをインストールする(Dejavuで動きました)

Target packages > Fonts, cursors, icons, sounds and themes

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786381/27339c51-ab79-43c6-8872-c9add3b6af03.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786381/d87ab889-e6d9-415f-aa11-be9037357b6b.png)
Servicenowにアクセス

エラーの原因は以下の2点です：

---

### ❌ 原因①：`Write-Host` の文字列中に **全角の記号や特殊文字** が混ざっており、**クォーテーションが正しく閉じられていない**

この部分：
```powershell
Write-Host "笶・繧ｨ繝ｩ繝ｼ縺檎匱逕溘＠縺ｾ縺励◆・・ $_.Exception.Message
```

→ `"（ダブルクォーテーション）` で始まっているのに、**閉じる `"` がない**ため、構文エラーが出ています。

---

### ✅ 修正済みバージョンのスクリプト（日本語対応済み）

```powershell
# ServiceNow接続情報
$instance = "dev285867"
$username = "admin"
$password = "ZE3g^TzwfE0^"

# 検索条件なしで1件取得
$url = "https://$instance.service-now.com/api/now/table/problem?sysparm_limit=1"

# 認証情報
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username, $securePassword)

# REST API 呼び出し
try {
    $response = Invoke-RestMethod -Uri $url -Method Get -Credential $credential -Headers @{
        "Accept" = "application/json"
    }

    if ($response.result -and $response.result.Count -gt 0) {
        Write-Host "✅ レコード取得成功！"
        $response.result | Format-List
    } else {
        Write-Host "⚠️ レコードが見つかりませんでした。"
    }

} catch {
    Write-Host "❌ エラーが発生しました：" + $_.Exception.Message
}
```

---

### 🔍 修正ポイントまとめ

| 修正前 | 修正後 |
|--------|--------|
| `Write-Host "xxx $_.Exception.Message` | `Write-Host "xxx" + $_.Exception.Message` |
| `"` で始めたら必ず `"` で閉じる必要があります | OK |
| エラー表示を `"文字列" + エラー内容` 形式に変更 | OK |

---

これで構文エラーは解消されるはずです。再度実行してみてください。<br>もし次に表示されるエラーメッセージやレスポンスがあれば、それを教えてもらえればさらにサポートできます！
NetSuite × 経費精算システムで実現する業務効率化と経理DX【概要】

---

本記事ではOracle NetSuiteと経費精算システムの連携について概要の説明をします。経費精算システムやサービスについてはこの記事では限定をしないため、具体的なAPIやデータ項目については仮定かつ一般論としてお考えください。

【詳細】編もご参考に。
https://qiita.com/naoyamiyake/items/49fb8006f07dc512ba3d

---

## 1）NetSuiteと経費精算システムを連携する意義・ニーズ

経費精算システムは、従業員の出張・交通費・交際費などの申請・承認・精算を効率化する一方、ERPであるNetSuiteでは経理処理・会計記帳・支払処理が主な役割を担います。

**しかし、両者が分離運用されている場合、以下のような課題が発生します：**

- 二重入力・手作業によるデータ転記ミス
- 月次締め処理の遅延
- 支払処理や仕訳の手作業対応
- 経費利用状況のリアルタイム把握の困難さ

**NetSuiteと経費精算システムをAPI連携することで、これらの課題を解消し、以下のような効果を得られます：**

- 経費データの自動仕訳化・支払処理の自動化
- ワークフローの全社統一
- 監査対応の簡素化・証憑のデジタル一元管理
- 経費使用状況の即時反映と分析

---

## 2）利用者メリット

| 利用者 | メリット内容 |
|--------|---------------|
| **従業員（申請者）** | スマートフォンやWebから簡単に申請・領収書アップロードが可能 |
| **承認者（部門長）** | 一元化された承認フローで承認漏れなし、ワークフローの可視化 |
| **経理部門** | 申請情報が仕訳データとして自動生成、月次締め作業が大幅に短縮 |
| **経営層・CFO** | 経費予算と実績をリアルタイムで把握、分析レポートも即時反映 |

---

## 3）連携する技術的なポイント

| 項目 | 内容 |
|------|------|
| **データ連携形式** | JSON（REST API）、CSVインポート/エクスポート |
| **認証方式** | OAuth2.0（Concur、チームスピリット）、APIトークン（楽楽精算） |
| **API設計方針** | 経費申請→仕訳／支払トランザクションへの変換ロジックを要実装 |
| **主な連携対象データ** | 経費申請情報、承認ステータス、支払情報、証憑URL、従業員ID・部門ID |
| **マスタ連携** | NetSuite → 経費精算（従業員、部門、プロジェクト） |
| **エラーハンドリング** | APIエラー時の再送、整合性チェック、ログ管理が重要 |

---

## 4）連携方法（3つ）

### ① REST API 連携（Push型）
- 経費精算システムが、承認済み経費データをNetSuiteにPOST
- NetSuiteのCustom Recordまたは仕訳トランザクションを生成

### ② REST API 連携（Pull型）
- NetSuiteがスケジュールバッチで経費精算システムにGETリクエスト
- 承認済データを取得して加工・登録

### ③ CSVファイルバッチ連携
- 経費精算システムからCSVファイルを定期出力
- NetSuiteでSuiteScriptまたはCSVインポート機能を用いてデータ登録

---

## 5）代表的な連携ユースケース

### ユースケース：**経費精算システムから仕訳の自動作成**
- 明細データの連携の前提としてマスタデータ関連の同期を行う
- 経費精算システム上で経費申請・承認
- APIでNetSuiteに経費科目ごとの仕訳データ（DR/CR）を生成
- 会計上のプロジェクト・部門・取引先に正確に紐づけ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961752/62cd0e08-482b-4f8e-8167-c63068d8c661.png)


---

## 6）連携開発プロジェクトにおける社内確認事項

| 確認項目 | 説明 |
|----------|------|
| **API利用規約の確認** | 経費精算システムのAPIの公開仕様、利用制限（レート制限など） |
| **ID統合方針の確認** | 従業員ID、部門ID、プロジェクトIDなどの一意性と整合性 |
| **業務部門との要件整合** | 誰が申請・承認・差戻しするか、ワークフローのルール確認 |
| **証憑の保管方針** | 原本PDF等の保存場所（NetSuiteへのURL連携 or 外部参照） |
| **支払サイクル確認** | 月次／週次などの支払タイミングと連携タイミングを明確化 |
| **内部統制対応** | 申請内容・承認者のログ保存や仕訳修正の制限要件の確認 |

---
【詳細】編に続きます
https://qiita.com/naoyamiyake/items/49fb8006f07dc512ba3d

---
【Splunk】Splunk Cloudのトライアル環境と本番環境の差異

こんにちは。torippy1024です。
本日は小ネタです。

Splunk Cloudには当日含め15日間利用可能なトライアル環境が用意されています。
しかしトライアル環境と本番環境には非機能面だけでなくいくつかの機能面での差異もあります。

私自身もよくトライアル環境を払い出して使用するのですが、その差異がまとまっている公式URLをよく忘れるので、ここに記載するとともに自分自身でもメモとして残しておきます。

### Splunk Cloud Trialとは

Splunk Cloudのトライアル環境は、以下のURLより申し込みが可能な環境です。

https://www.splunk.com/ja_jp/download/splunk-cloud.html

有効期限はドキュメントによって14日間と書かれていたり15日間と書かれていたりで差異があります。
私が試してきた経験では、払い出し当日を含めると15日間利用可能だったので、含めなければ14日間、含める場合は15日間と理解しています。


### Splunk CloudのTrial環境と本番環境の差異

公式ドキュメントに記載があります。
いつもどこだったか忘れてしまうのですが以下です。
https://docs.splunk.com/Documentation/SplunkCloud/latest/Admin/TypesofSplunkClouddeployment


〜9.3.2411版におけるGoogle翻訳+意訳〜
(最新版の公式記述は上記リンクを参照ください)


|機能|トライアル環境|本番環境|
|---|---|---|
|Splunk Cloud Platformへのアクセス方法|Splunk Web サイト (www.splunk.com) で Splunk アカウントにログインし、インスタンスページに移動します。(注：トライアルでもウェルカムメールにログイン先URLは記載されているはず)|Splunk SalesからSplunk Cloud Platformをご購入いただいた際に指定したURLを使用します。このURLは、Splunk Cloud環境を払い出した際に受信したウェルカムメールに記載されています。|
|入力(インプット)の作成（ファイルのアップロード、HTML イベントの取り込み、アプリ関連の入力を含む）	|オンプレミスでForwarderを構成するか、Splunk Webを使用|オンプレミスでForwarderを構成するか、Splunk サポートにお問い合わせ(Splunk Webの使用も可能のはず)|
|データ取り込み(1日あたり最大)|1日あたり5GB、15日間	|契約に基づく|
|データのエクスポート、保持、削除	|Splunk Cloud Platformの無料トライアルに追加したデータは、トライアルインスタンスからエクスポートできません。無料トライアルの有効期限が切れると、インスタンスとその中のすべてのデータが削除されます。現在、トライアルアカウントを有料アカウントに変換することはできません。(注：マニュアルでサーチ結果をテキストファイルなどでエクスポートすることは可能のはず)|Splunk Cloud Platform は、データの削除タイミングを指定できるインデックス設定に基づいてデータを保持します。詳細については、Splunk Cloud Platform Service Descriptionの「Storage」セクション(https://docs.splunk.com/Documentation/SplunkCloud/latest/Service/SplunkCloudservice#Storage )をご覧ください。|
|Splunk Universal Forwarderを使用してデータを安全に送信(注：SSLによる暗号化通信によるデータ転送を指していると思われる)|はい|はい|
|Active Directory/シングルサインオン統合|サポートされていません	|サポートされている|
|Splunk Cloud Platform のリージョン|US Eastのみ|GovCloudを含む複数|
|IPアドレスによる許可/拒否リスト|いいえ|はい|
|Premiumu Appの利用可否|いいえ|はい|
|同時実行できるサーチ数の制限|最大10|購入した環境のトポロジーに依存|
|REST API URL|無料トライアルユーザーはREST APIにアクセスできません。トライアル期間中に利用可能な代替手段については、Splunkの営業担当者にお問い合わせください。|ご購入いただいたデプロイメントについては、以下のURLをご利用ください。https://<deployment-name>.splunkcloud.com:8089 また、必要に応じて、Splunk Cloud環境のポート8089を開放するためのサポートケースを起票してください。|
|HTTP Event Collector(HEC)のURL|https://inputs.< host>.splunkcloud.com:8088/< endpoint>|https://http-inputs-< host>:443/< endpoint>またはhttps://http-inputs.< host>.splunkcloud.com:443/< endpoint> (Google Cloudの場合)|


実際に検証する際には、AD/SSO統合ができないこと、IPアドレスによる許可/拒否リストが使用できないこと、Premiumu Appが使用できないこと、REST APIが使用できないこと、あたりが機能面で気になるところかなと思いました。

本日は以上です。
[Linux][command] テキスト処理_分割・統合_split, paste

# splitコマンド
~~~terminal:
# split [オプション] [入力ファイル] [出力ファイルの接頭辞]
~~~

| オプション | 由来 | 説明 |
|:--|:--|:--|
| default | split | - 入力ファイルを1000行ごとに分割する<br>- 出力ファイル名は接頭辞'x'に接尾辞'aa', 'ab', 'ac', ...を付けた形式で作成される |
| `-b SIZE` | bytes | - 指定したSIZE（バイト数）ごとにファイルを分割する<br>- SIZEにはK（キロバイト）、M（メガバイト）などの単位を使用できる |
| `-l 行数`<br>`- 行数` | lines | - 指定した行数ごとにファイルを分割する |

# pasteコマンド
```terminal
$ paste [オプション] [ファイルA ファイルB ...]
```

| オプション    | 由来        | 説明                                                            |
| :------- | :-------- | :------------------------------------------------------------ |
| default  | paste     | - 複数ファイルの各行を横方向に結合する（デフォルトはタブ区切り）                             |
| `-d 文字列` | delimiter | - 区切り文字を指定する<br>- 文字列内の各文字を順番に区切り文字として使用する（例：`-d ','`でカンマ区切り） |




# Ping-t
split
- [3262_split -500 hoge](https://mondai.ping-t.com/question_subjects/31/question_sessions/31375489/progressing_questions/480744521)
- [3266_paste -d](https://mondai.ping-t.com/question_subjects/31/question_sessions/32244301/progressing_questions/494010586)
JUnitの学習②_スタブについて

:::note warn
この記事はプログラミング初心者が自分のメモ用として書いている記事です。
そのため、誤った情報が記述されている可能性があります。
自己判断で読み進めてください
:::

##  スタブ(Stub)とは？

スタブとは、ユニットテストにおいて「他のクラスから呼ばれると、決まった値を返す」だけの簡易的な代用品のこと。

 別のクラスやコンポーネントに依存しているロジックを、テスト用に簡易化して置き換える際に使う、

たとえば、毎回値が変わる `Random` のような処理を「固定の値で返す」ことで、テストを安定させる目的で使用されるケースで説明する。

---

##  サンプルソース解説とその役割

以下は、実際のスタブの構成。
### インターフェース `RandomNumber`
```java
package junit.sample;

public interface RandomNumber {
	int nextInt();
}
```
✅【目的】
- ランダム値を生成するインターフェース。
- 実装を差し替えるための“共通の型”として使う。

---

###  本来の実装 `RandomNumberImpl`
```java
package junit.sample;

import java.util.Random;

public class RandomNumberImpl implements RandomNumber {
	private final Random random = new Random();
	@Override
	public int nextInt() {
		return random.nextInt();
	}
}
```
✅【目的】
- 実際のランダム値を返す処理です。
- テストでは「毎回違う結果」になり不安定になる原因です。

✅【このコードの代わりにスタブを使う理由】
- テスト時に `nextInt()` の戻り値が毎回異なると、「期待値がブレる＝テスト失敗」になります。

---

###  スタブ `RandomNumberStub`
```java
package junit.sample;

public class RandomNumberStub implements RandomNumber {
	@Override
	public int nextInt() {
		return 0;
	}
}
```
✅【目的】
- 毎回「0」を返す簡易実装。
- `RandomNumberImpl` を「決まった結果にする」ためのスタブ。
- これにより、常に「index 0」の値（例：「A」）が選ばれるようになります。

---

###  対象クラス `Randoms`
```java
package junit.sample;

import java.util.List;

public class Randoms {
	RandomNumber random = new RandomNumberImpl();

	public <T> T choice(List<T> options) {
		if (options.size() == 0) {
			return null;
		}
		int index = random.nextInt() % options.size();
		return options.get(index);
	}
}
```
✅【ポイント解説】
- `choice()` メソッドは、与えられたリストからランダムに1件選びます。
- `random` は `RandomNumber` 型なので、実際には `RandomNumberImpl` か `RandomNumberStub` を注入できます。
- ユニットテスト時に外から `random` を差し替えることができる設計になっている点が重要です。

---

###  テストクラス `RandomsTest`
```java
package junit.sample;

import static org.junit.jupiter.api.Assertions.*;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import org.junit.jupiter.api.Test;

public class RandomsTest {

	@Test
	void testChoice() {
		List<String> options = new ArrayList<>();
		options.add("A");
		options.add("B");
		Randoms sut = new Randoms();

		// ラムダ表現のスタブを直接設定
		final AtomicBoolean isCalled = new AtomicBoolean(false);
		sut.random = new RandomNumber() {
			@Override
			public int nextInt() {
				isCalled.set(true); // 呼び出し確認
				return 0; // "A"を選ばせる
			}
		};
		// または sut.random = new RandomNumberStub(); でも可

		assertEquals(sut.choice(options), "A");
		assertTrue(isCalled.get());
	}
}
```
✅【ポイント解説】
- `sut.random` にスタブ（匿名クラス or RandomNumberStub）を代入
- テストの意図：「Aが選ばれる状況を強制的に作る」
- `AtomicBoolean` により「本当に呼ばれたか」も検証

---

##  なぜスタブを使うのか？（現場での観点）

### ❌ スタブを使わない場合
```java
Randoms sut = new Randoms();
sut.random = new RandomNumberImpl();
```
- `nextInt()` の返り値が毎回ランダムなため、テスト結果が不安定になります
- 例：期待は「A」だったが、`nextInt()` が 1 を返して「B」になり失敗するなど

 これは "テストが壊れやすい" 状況となり危険。

---

### ✅ スタブを使うと？
- 「常に0を返す」スタブを使えば、100%同じ状態で再現できる
- 意図的に「index 0の選択肢（A）」が選ばれるため、**期待値との一致が保証される**
- これにより、テストの信頼性を向上させられる。

---

#  まとめ

 スタブは「決まった値を返す」だけのテスト用の代用クラス |
 本物の部分の代わりにスタブを使うと、テストを定義的にできる |
 例えば、毎回値が変わる`Random`をスタブで置き換えることで、結果を統一できる |
非同期処理を通して見えてきた、JavaScriptとブラウザの関係

# はじめに

JavaScriptで `fetch()` を使って非同期処理をしていたとき、こんな疑問が浮かびました。

> 「fetchって非同期処理って言うけど、内部ではどのような処理が行われているのだろう？」

この疑問から少しずつ調べていくうちに、JavaScriptとブラウザの関係がはっきりと見えてきました。この記事では、その学びを振り返りながら、非同期処理の仕組みとブラウザとの関係について整理していきます。

---

## Promiseの仕組みを整理

JavaScriptの非同期処理は主に Promise を通して扱われます。
非同期処理を開始すると Promise が返され、`.then()` を使って後続の処理を登録します。
その後、非同期処理が完了すると `resolve()` が呼ばれ、
その時点でマイクロタスクキューに `.then()` に登録された関数が入れられ、コールスタックが空になったタイミングで実行されます。

ここで疑問が湧きました。

> 「そもそも Promise の中の `resolve()` って誰が呼んでるの？」

---

## 非同期処理は JavaScript がやっていない

`fetch()` はJavaScript自体が提供している関数ではなく、
ブラウザの中にある「Web API」という仕組みが提供しているものです。

---

## Web APIとは？

- ブラウザがJavaScriptに提供している外部機能
- JavaScript単体では実行できないような処理（通信、タイマーなど）を代わりに実行してくれる
- 代表例：`fetch`, `setTimeout`, `addEventListener`, `localStorage`, `geolocation` など

つまり、役割は以下のように分担されている：

| やること | 担当者 |
|----------|--------|
| 通信処理 | ブラウザ（Web API） |
| Promise作成と`.then()`の登録 | JavaScriptエンジン（例：V8） |
| 処理の実行順制御 | イベントループ |

---

## 非同期処理の流れ

```text
1. JavaScriptが fetch() を呼び出す
   → Promiseを返す（この時点ではまだ結果はない）
2. ブラウザのWeb APIが通信処理を開始する
3. JavaScriptは次の処理へ進む（ブロッキングされない）
4. 通信が完了すると、Web APIはPromise作成時に渡されていた resolve() を呼び出す
5. resolve() が Promise の状態を「完了」に変更し、登録されていた .then() の関数をマイクロタスクキューに追加する
6. コールスタックが空になったタイミングでマイクロタスクが実行される
```

ここで重要なのは、`resolve()` は JavaScript の Promise 内部で用意された関数であり、Web API は「処理が終わったらこの関数を呼んでね」と渡された `resolve()` を呼んでいるだけ。
その結果、Promiseの状態が「fulfilled」になり、`.then()` に登録された関数がJavaScriptエンジンによってマイクロタスクキューに追加される。

---

## なぜJavaScriptは直接処理をしないのか？

~~「サンドボックス」というセキュリティ上の制限があるため。~~

~~サンドボックスとは、JavaScriptが動作する安全な実行空間のこと。Webページ上で動くJavaScriptがユーザーのファイルやネットワーク、プロセスに勝手にアクセスすることを防ぐため、ブラウザはJavaScriptにできることを制限している。~~

~~そのため、ネットワーク通信などの危険な処理は、JavaScriptではなくブラウザが担っている。~~

上記について、サンドボックスはセキュリティのためではあるが、fetch 関数が存在することとは直接関係はない。制限されているから fetch を使う、というよりも、そもそも fetch を使うように設計されている。（コメントいただき、修正しました。）

---

## 気づいたこと：これはOSとアプリの関係に似ている

ここまで学んでいく中で、次のように感じました。

> 「JavaScriptとブラウザの関係は、アプリとOSの関係に似ている」

多くのプログラミング言語（C, Goなど）はOSのシステムコールを使ってファイルや通信を扱います。
同様に、JavaScriptはブラウザが提供するWeb APIを使って外部の処理を行っています。

---

## まとめ：非同期処理はブラウザとの共同作業

- `fetch()` で非同期処理ができるのは、ブラウザのWeb APIが裏で通信処理を行ってくれているから
- JavaScriptはPromiseを作り、処理の登録をするだけで、実際の処理はブラウザに任せている
- `resolve()` はPromiseの作成時にJavaScriptエンジンが生成する関数であり、それをWeb APIに「後で呼んでね」と渡している
- `resolve()` が呼ばれたあとはJavaScriptエンジンが `.then()` に登録された処理をマイクロタスクキューに追加し、イベントループによって実行される
シンプルな解決策でClaudeデスクトップMCPサーバー構成の重大な問題を解決した方法


技術的な問題に直面して完全に困惑したものの、解決策が驚くほど単純だったという経験はありませんか？最近、私はMacでClaudeデスクトップのMCPファイルシステムサーバーを設定する際に、まさにこのような状況に遭遇しました。

## 課題：謎の構成失敗

`mcp-server-sqlite`と`uvx`は完璧に動作したのですが、`claude_desktop_config.json`を使用してファイルシステムサーバーを構成しようとした際に障害に直面しました。`npx`と`node`を直接使用する両方の試みが、私を困惑させる予期せぬエラーを引き起こしたのです。

### 最初の試み：NPXアプローチ

最初の構成は十分にシンプルに見えました：

```json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/xxx/Desktop"
      ]
    }
  }
}
```

しかし、ログには奇妙なエラーが表示されていました：

```bash
==> /Users/xxx/Library/Logs/Claude/mcp-server-filesystem.log <==
command not found: /Users/xxx/Desktop
```

不思議なことに、ターミナルで同じコマンドを直接実行すると完璧に動作しました：

```bash
npx @modelcontextprotocol/server-filesystem '/Users/xxx/Desktop'
# 出力: Secure MCP Filesystem Server running on stdio... Allowed directories: [...]
```

### 二度目の試み：Node直接アプローチ

次のアプローチでは、Node.jsを直接使用してみました：

```json
{
  "mcpServers": {
    "filesystem": {
      "command": "node",
      "args": [
        "/usr/local/lib/node_modules/@modelcontextprotocol/server-filesystem/dist/index.js",
        "/Users/xxx/Desktop"
      ]
    }
  }
}
```

しかし、これは構文エラーを引き起こしました：

```bash
==> /Users/xxx/Library/Logs/Claude/mcp-server-filesystem.log <==
/usr/local/lib/node_modules/@modelcontextprotocol/server-filesystem/dist/index.js:2
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
       ^

SyntaxError: Unexpected token {
    at Module._compile (internal/modules/cjs/loader.js:723:23)
    ...
```

ここでも、ターミナルで全く同じコマンドを実行すると問題なく動作しました。

この時点で、私は途方に暮れていました。パスの問題でしょうか？構成ファイルで`node`へのフルパス（例えば、`/usr/local/bin/node`）を指定してみたところ、一時的に機能するように見えましたが、それは脆弱な回避策であり、本当の解決策ではありませんでした。

## 予想外の解決策：バージョンの競合

かなりのトラブルシューティングの末、根本原因を発見しました：**システムに潜む古いNode.jsのバージョン**でした。

私のデフォルトのターミナルNodeは最新でしたが、Claudeが構成ファイルを通じてサーバーを起動しようとすると、古いバージョン（おそらく`nvm`によって管理されていた）が何らかの形で干渉していたのです。

## 状況を救った単純な修正

解決策は驚くほど簡単でした：古いNode.jsのインストールを削除し、システムに最新バージョンのみが残るようにしました。

結果はどうだったでしょうか？`claude_desktop_config.json`内の`npx`と`node`の両方の構成がエラーや混乱なく完璧に動作し始め、MCPを通じてファイルシステムにシームレスにアクセスできるようになりました。

## この経験から学べること

コマンドがターミナルでは完璧に動作するのに、別のアプリケーションから起動すると失敗するような状況に遭遇した場合は、ランタイム環境におけるバージョンの競合を確認することを検討してみてください。

時には最も強力な修正は最もシンプルなものです：開発ツールの古いバージョンをクリーンアップすることです。

あなたも同様のソフトウェアバージョンの競合による幻のような問題を経験したことはありますか？下のコメントで、あなたのトラブルシューティングの成功例についてお聞かせください。
【簡単Kubernetes】【HPA】KubernetesでPodの自動スケーリングを設定する方法

Kubernetes（K8s）では、アプリケーションの負荷に応じてPodの数を自動で増減させることができます。この機能を **Horizontal Pod Autoscaler（HPA）** と呼びます。

HPAを活用すれば、リソースの最適化や高可用性の確保が実現でき、運用効率が大幅に向上します。

本記事では、**HPAの概要・導入方法・設定例・ベストプラクティス** について解説します。

---

## ✨ 1. HPAとは？

Horizontal Pod Autoscaler（HPA）は、**CPU使用率** や **カスタムメトリクス** に基づいて、Podのレプリカ数を自動的に調整する機能です。

- ✅ **スケーリング対象**：Deployment、ReplicaSet、StatefulSetなど  
- ✅ **スケーリング基準**：CPU使用率、メモリ、カスタムメトリクスなど  
- ✅ **条件**：メトリクスが閾値を超えた場合にPod数が増減

---

## ⚙️ 2. 前提条件

HPAを利用するためには、以下の条件を満たしている必要があります。

- Kubernetesクラスタが稼働している  
- `metrics-server` がクラスタにインストールされている  
- 対象Podに **リソース制限（CPU requests/limits）** が設定されている  

✅ `metrics-server` のインストール（例）:
```bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
```

---

## 🛠️ 3. HPAの作成方法

ここでは、CPU使用率に基づいてHPAを作成する基本的な手順を紹介します。

### ✅ 3.1 Deploymentの作成（サンプル）

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: app
        image: k8s.gcr.io/hpa-example
        resources:
          requests:
            cpu: 200m
          limits:
            cpu: 500m
        ports:
        - containerPort: 80
```

```bash
kubectl apply -f deployment.yaml
```

---

### ✅ 3.2 HPAの作成

```bash
kubectl autoscale deployment sample-app --cpu-percent=50 --min=1 --max=5
```

- CPU使用率が50%を超えた場合にPod数が増加  
- 最小1、最大5までの範囲で自動スケーリング

---

## 🔍 4. ステータス確認とモニタリング

現在のスケーリング状態を確認するには以下のコマンドを使用します。

```bash
kubectl get hpa
```

出力例：

```
NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
sample-app   Deployment/sample-app   35%/50%   1         5         1          3m
```

---

## ✅ 5. ベストプラクティス

- 📌 **リソースのrequests/limitsを必ず設定する**  
  → HPAのスケーリング判断基準になります。

- 📌 **`metrics-server` は最新を使用し、安定して動作することを確認する**  
  → メトリクス取得に失敗するとHPAが動きません。

- 📌 **アプリケーションの起動時間を意識する**  
  → スケールアウト後のレスポンス遅延を避けるため。

- 📌 **HPAの設定値（CPU閾値やPod数）を本番ワークロードに合わせてチューニングする**

- 📌 **必要に応じてカスタムメトリクス（Prometheusなど）を導入する**

---

## 📝 6. まとめ

| 項目 | 内容 |
|------|------|
| 機能名 | Horizontal Pod Autoscaler（HPA） |
| スケーリング基準 | CPU使用率、カスタムメトリクスなど |
| 必須要件 | metrics-serverの導入、リソース設定 |
| スケーリング対象 | Deployment、ReplicaSet、StatefulSetなど |
| メリット | 負荷に応じた自動スケーリング、高可用性の確保 |

---

## 📘 参考リンク

- Kubernetes公式ドキュメント（HPA）  
  https://kubernetes.io/ja/docs/tasks/run-application/horizontal-pod-autoscale/

- metrics-server GitHub  
  https://github.com/kubernetes-sigs/metrics-server

---

以上、KubernetesにおけるHPAの導入と基本設定について解説しました。  
少しでも皆さんの参考になれば幸いです！

🙌 Qiitaでの「いいね」やコメントも大歓迎です！
【vuetify】clearableでclearした時空文字にしたい

clearableでクリアした時デフォルトではnullになってしまうので、`@click:clear`で調整

```js
<v-text-field
  v-model="text"
  clearable
  @click:clear="text = ''"
/>
```

将来的には`clear-value`で指定するようになりそう :eyes: 

https://github.com/vuetifyjs/vuetify/pull/21055
Ansible学習メモ③（NFSサーバの構築)

業務で最近Ansibleを使い始めました。私自身はエンジニア職ではないので普段コーディングをほとんどしないです。少しAnsibleがわかるように学習し始めています。


#### AnsibleでCentOSマシンにNFSサーバの構築
本タスクには六つのモジュールを使用
ansible.builtin.yum パッケージインストール
ansible.builtin.file　ディレクトリ作成
ansible.builtin.lineinfile ファイル編集
ansible.builtin.command ディレクトリのエクスポート
ansible.builtin.service サービスのリスタート
ansible.posix.firewalld ファイアウォール設定
※マニフェストを実行前、コレクションのインストールが必要
```
ansible-galaxy collection install ansible.posix
```
作成するマニフェストtest.yamlは以下のようです。
```
---
- name: export nfs share
  hosts: all
  become: true
  vars:
    share: "/nfs/share"
    option: "192.168.0.0/24(rw,sync,root_squash)"
    permission: "0777"
  tasks:
    - name: NFS share installed
      ansible.builtin.yum:
        name:
          - nfs-utils
          - nfs4-acl-tools
        state: present

    - name: share directory exists
      ansible.builtin.file:
        path: "{{ share }}"
        state: directory
        mode: "{{ permission }}"
        owner: root
        group: root

    - name: edit in /etc/exports file
      ansible.builtin.lineinfile:
        path: /etc/exports
        state: present
        line: '{{ share }} {{ option }}'
      notify: restart NFS Server

    - name: export share
      ansible.builtin.command: "exportfs -rav"

    - name: firewall enabled
      ansible.posix.firewalld:
        service: "{{ item }}"
        state: enabled
        permanent: true
        immediate: true
      with_items:
        - nfs
        - rpc-bind
        - mountd

  handlers:
    - name: restart NFS Server
      ansible.builtin.service:
        name: nfs-server
        state: restarted
        enabled: true
```
inventoryファイルを以下のように設定
```
XX.XX.XX.XX ansible_ssh_private_key_file=~/XXXXX.pem
```
(XX.XX.XX.XX: 対象マシンのIPアドレスまたはホスト名)

以下のコマンドを実行し、対象マシンにパッケージインストールを行う。
```
ansible-playbook -i inventory test.yaml
```
最近のCPUでタスクスケジューラから実行したタスクが遅い？

# はじめに
知ってましたか？私は知りませんでした。

Windows11上で、一回の実行で何分か以上かかる処理を、デスクトップから実行した場合と、タスクスケジューラから実行した場合で、1.5～2倍くらい後者の方が時間がかかる現象に出くわしました。

# 原因
なんでだと思いますか？
ヒント：実行したマシンのCPUは、第14世代Intel Core7プロセッサで、Pコア/Eコア[^1]の混在構成です。
（ここまで書いちゃったらもう分かりますよね）

正解は、
10
9
8
7
6
5
4
3
2
1
0
タスクスケジューラから実行した場合は、Eコアで実行されることがあるからです。
リソースモニタ等で監視しながら実行してみると、最初数秒はPコアで動いてるんですが、そのあとはEコアに処理が移っちゃってることが見て取れました。
負荷の低い処理ならそれでもいいんですが、CPU全力でぶん回すような処理なのにEコアのままで動かれるとキーッとなります。

# 解決方法
タスクスケジューラのタスクってデフォルトは低優先で動く（これも今回知ったんですが）ので、通常優先に変えたら変わるのかとも思ったけど変わらず。

タスクスケジューラで実行した処理がEコアで動くなんて情報、ぐぐっても見つけられなかった（英語だったらあったのかな？）ぐらいなので、解決方法も分からなかったんですが、ChatGPTに聞いてみたらズバリではないけど次の方法が示唆されました。

**「電源管理」を「パフォーマンス優先」にする**

して、その成果は・・・最後までPコアで動いた！

以上です。
別解としては、アフィニティ（タスクマネージャでいうと「関係の設定」です。分かりにくい）をいじって、Eコアへの割り当てを全部解除してしまう（＝Pコアだけが残る）という方法もあります。がこちらはプロセスが上がってからいじる必要があって事前に仕込んでおけないので一般的には「電源管理」でいいと思います。
もちろん消費電力は上がるはずですが。

# 感想
どのコアで実行するかは、プロセスの優先度でもなく、処理の負荷でもなく、親（タスクスケジューラ）の素性によって決められているという、ちょっと現代社会にあるまじきというか、いや現代社会でも変わらないというべきなのか、そんなお話でした。

[^1]: Qiita見てる人で知らない人は少ないと思いますが、最近のIntelの上位のCPUには、一つのCPUの中に、特性の異なる2種類のコアが入っていて、Pコア(Performance Core)は性能重視で電力消費多め、Eコア(Efficient Core)は電力効率重視で性能は抑えめのコアという構成になっています。スマホ向けだともっと前からこういう構成が一般的でした。
【Laravel】ゲストログイン作成手順

# 目標
・Aサイトをゲストログイン可能にする。
・Bサイトからの遷移のみでゲストログインを可能にする。(他は通常のauth認証発生)
↓
Aアプリで「トークン方式のURLチェック（遷移元URLの確認）」と「ゲストログイン処理」を組み合わせる。


# ✅ 実装手順（Aアプリ側）
##  ① ゲストログインルートを用意
```routes/web.php
Route::get('/guest-login', [GuestLoginController::class, 'login'])->name('guest.login');
```


## ② コントローラーを作成
```bash
php artisan make:controller GuestLoginController
```


## ③ コントローラーでトークンチェック & ゲストログイン
```app/Http/Controllers/GuestLoginController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;

class GuestLoginController extends Controller
{
    public function login(Request $request)
    {
        // 🔐 トークン検証（任意の文字列）
        if ($request->token !== config('app.guest_token')) {
            abort(403, '不正なアクセスです。');
        }

        // ✅ ゲストユーザーを取得 or 作成
        $guestUser = User::firstOrCreate(
            ['email' => 'guest@example.com'],
            [
                'name' => 'ゲスト',
                'password' => bcrypt('guestpassword'), // 初回だけ実行
            ]
        );

        Auth::login($guestUser);

        return redirect('/'); // 任意のページにリダイレクト
    }
}
```


## ④ .env にトークンを設定
```.env
GUEST_LOGIN_TOKEN=guest123
```


## ④ config/app.php に追加
```config/app.php
<?php

use Illuminate\Support\Facades\Facade;

return [

    ~~~

    // ゲストログインの遷移元とのトークンを指定
    'guest_token' => env('GUEST_LOGIN_TOKEN'),
];
```



# ✅ Bサイト（ポートフォリオ）側のリンク例
## 
```blade
<a href="https://ドメイン/guest-login?token=guest123" target="_blank" rel="noopener noreferrer">
    ゲストログインで体験する
</a>
```



# ✅ 本番環境のプロジェクト.envを編集
```.env
GUEST_LOGIN_TOKEN=guest123
```
↓
その後キャッシュクリア
```bash
php artisan config:clear
```




# 参考：Profileを編集不可にしたい場合
https://qiita.com/honaki/items/abb7a103eab411f2cc49
[Linux] sudo コマンドについて ①

### この記事について
sudoコマンドやその設定ファイルについて整理する。

### 一般ユーザーへ管理用コマンド実行権限を委譲する
通常、管理用コマンドは一般ユーザーでは実行することができない。
`/etc/sudoers`を編集することで、sudoコマンドを用いた一般ユーザーでの管理用コマンドの実行が可能となる。

* rootユーザーで`visudo`コマンドを実行し、`/etc/sudoers`の編集画面に入る。
```
  [root@localhost ~]# visudo
```

* 以下の行を追加する。これにより、`sudo`コマンドを用いた、一般ユーザーでの`systemctl`コマンドの実行ができるようになる。
```
  Kotaro ALL=NOPASSWD: /usr/bin/systemctl
```
:::note info
NOPASSWD の指定により、パスワード入力をせずにコマンドの実行ができるようになる。
:::

* 当該一般ユーザーで以下のコマンドを実行する。
  パスワードの入力をせずに、`sudo`コマンドを用いた管理用コマンドの実行ができた。
```
  [Kotaro@localhost ~]$ sudo systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2025-04-14 10:14:03 JST; 2 days ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
  Process: 861 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
  Process: 839 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 846 (chronyd)
    Tasks: 1 (limit: 23216)
   Memory: 2.2M
   CGroup: /system.slice/chronyd.service
           mq846 /usr/sbin/chronyd
```
### 実行可能コマンドの確認

* 一般ユーザーで以下のコマンドを実行する。
```
  [Kotaro@localhost ~]$ sudo -l
```

* 以下行より、当一般ユーザーが実行できる管理用コマンドを確認できる。
```
User Kotaro may run the following commands on localhost:
(root) NOPASSWD: /usr/bin/systemctl
```

以上。
🚀 RESTで始めたけど、GraphQL導入を本気で悩んだ話【NestJS + Prisma構成】


## はじめに

最近、「GraphQL不要論」がよく流れてくる。  
でもその一方で、「クライアント主導の柔軟なAPIが作れる」「型安全で保守しやすい」なんて声も多い。  
自分は、NestJS + Prisma + PostgreSQL で社内向けシステムを作ってるけど、**この構成にGraphQLはアリなのか？**という点をガチで考えた。

この記事は「GraphQLをまだ導入してないけど、めちゃくちゃ悩んでる人の思考整理メモ」みたいなもの。  
同じように考えてる人に届けば嬉しい。

---

## ✅ 現状構成：NestJS + Prisma + REST

まず今のバックエンド構成。

- フレームワーク：NestJS
- ORM：Prisma（PostgreSQL接続）
- API：REST（`@Controller` + DTO + Service）
- フロント：Next.js、社内用Reactアプリ

RESTで必要十分だし、開発スピードも出る。  
DBのスキーマとPrismaが直結してるおかげで型安全も担保されてる。

---

## 🤔 なぜGraphQLを検討したのか？

理由は1つ：  
**「フロント側で指標を柔軟に作りたくなった」**

RESTだと、例えばこんなケースが辛くなる。

- `/campaigns/:id/metrics` のレスポンスを変えるたびにバックエンド修正が必要
- 指標の数が増えてくるとエンドポイント設計が破綻し始める
- 「impressionsとclicksだけ欲しい」ってときでも全部返すか、API分けるしかない

GraphQLならこうなる：

```graphql
query {
  campaign(id: "abc123") {
    impressions
    clicks
  }
}
```
そしてフロント側で `CTR = clicks / impressions` を計算する。  
**「バックはデータを提供するだけ、どう使うかはクライアントに任せる」** という思想にピッタリ。

---

## 🔍 GraphQL不要論は気にするべき？

いろいろ読んだけど、だいたい以下の内容：

| 不要論の主張 | 実感としてどうか？ |
|--------------|--------------------|
| RESTで十分なケースが多い | 確かに社内用途ならRESTで完結することが多い |
| GraphQLは学習コストが高い | Nestならそれなりに自然に書けるが、スキーマ設計はやっぱり別モノ |
| Apolloが重い | 一理ある。クライアントが多いなら利点大きいけど、単一UIなら過剰感もある |
| N+1地獄になる | Prismaなら `include` や `select` である程度制御可能だけど意識は必要 |

なので、**「何に使うか」が重要。**  
いま自分のプロジェクトでいきなり全部GraphQLにするのは違うけど、**外部向けAPIや将来的な展開を考えると、今から設計目線でGraphQLを意識しておくのはアリ**だと思ってる。

---

## ✅ 現時点の自分の結論

- 社内向けの管理系UIやバッチ処理はRESTで十分
- 指標APIやフロント主導の柔軟なデータ取得にはGraphQLを検討したい
- Prisma + NestJS なら、RESTからGraphQLへの切り替えも段階的に進められる

いまはGraphQL導入前だけど、**その検討過程で見えた選定軸や判断基準**は、同じように悩んでる人の参考になるはず。

---

## 💡 余談：GraphQL導入フェーズで考えてること

- BFF的に外部向けだけGraphQLにする構成
- 認可処理の粒度（フィールド単位でやる？モジュール単位で切る？）
- metricsテーブル作るべきか、GraphQLで生データ返してクライアントで計算させるか

---

## 🙌 最後に

GraphQLは「今使うべきか？」じゃなくて、**「どこで使うべきか？」が重要**な気がする。 
この記事はまだ「実装前の話」だけど、むしろそういう時期に書いておくと後で自分で見返したときに意味あると思う。

**GraphQL、使わない理由もあるけど、使いたくなる理由もちゃんとある。**
自組織でTeamsを利用していない場合でもTeamsのデスクトップアプリで外部組織のTeamsにアクセスする方法

## 事前準備

1.  [ここ](https://www.microsoft.com/ja-jp/microsoft-teams/download-app) から Teams のデスクトップアプリをダウンロードし、インストールします。
2.  デスクトップアプリ版の Teams に、ご自身の Microsoft 365 アカウントでログインし、試用開始の画面が表示されることを確認します。
3.  **重要:** デスクトップアプリ版の Teams は**閉じずに、そのまま起動しておいてください**。

## 接続手順

1.  Web ブラウザ（Edge推奨）を開き、デスクトップアプリで接続したい**外部組織**の Teams にログインします。
    *   ログインURL: [https://www.microsoft.com/ja-jp/microsoft-teams/log-in](https://www.microsoft.com/ja-jp/microsoft-teams/log-in)
2.  Web ブラウザ上の Teams で、左端のメニューから `チーム` を選択します。
3.  接続したいチーム名の右側にある `・・・` (その他のオプション) をクリックし、`チームへのリンクを取得` を選択します。
4.  取得したリンクをコピーし、ブラウザのアドレスバーに貼り付けてアクセスします。
5.  「Microsoft Teams を開きますか？」のようなダイアログが表示されたら、`開く` や `今すぐ起動する` を選択します。
6.  デスクトップアプリ版の Teams が起動し、外部組織のチームが表示されれば成功です。

## トラブルシューティング: チャネル単体のウィンドウが表示される場合

上記手順 5. の後、チャネル単体の小さなウィンドウが表示されてしまうことがあります。

この場合は、以下の手順を試してください。

1.  チャネル単体のウィンドウの右上にある `・・・` (その他のオプション) をクリックし、`チャネルへのリンクを取得` を選択します。
2.  **デスクトップアプリ版の Teams を完全に終了します** (タスクトレイのアイコンを右クリックして終了するなど)。
3.  Web ブラウザから、手順 1. でコピーした**チャネルへのリンク**にアクセスします。
4.  デスクトップアプリ版の Teams が起動し、Web 版のようにチーム全体が表示されれば成功です。