OmniAICreator/Qiita-1.07M huggingface dataset:
【Unity】メニューUIを作成する

## はじめに

こんにちは、かなたです。
UnityでメニューUIを作成する方法についての備忘録になります。

ここでいうメニューUIとはゲーム中にボタンを押すとモーダル表示されるUIを意味します。
例えば、設定ボタンを押すと表示されるBGMやSEの音量を変えられるウィンドウです。

## 1. ボタン・モーダルウィンドウ・背景の作成

最初にUnity上でButtonコンポーネントを持つオブジェクトを作成します。
Imageコンポーネントに`Button`をつけるなど方法は問いません。

続いてモーダル表示するウィンドウを用意して`Alpha`を設定した黒背景も用意します。
ここまでのUnityの画面を貼ります。

![image00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922528/785052ba-f4ea-18a4-2793-0ef3145351ba.png)



## 2. MenuControllerの作成

次にモーダルの表示・非表示を管理する`MenuController`を作成します。


```csharp:MenuController.cs

using UnityEngine;

public class MenuController : MonoBehaviour
{
    public GameObject menuBackground;
    public GameObject menuWindow;

    public void ToggleMenu()
    {
        if(menuWindow.activeSelf)
        {
            menuWindow.SetActive(false);
            menuBackground.SetActive(false);
        }
        else
        {
            menuWindow.SetActive(true);
            menuBackground.SetActive(true);
        }
    }
}

```

### コード内容
ToggleMenu()：モーダルウィンドウと背景のアクティブ状態を切り替えます。

## 3. 表示切り替えボタンへの設定


表示切り替えボタンの`OnClick`に`MenuController`を持つオブジェクトを設定し、`ToggleMenu`を割り当てます。
ボタンを押した時にメニューの表示・非表示が切り替わります。


![image02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922528/5c4ff9da-7c97-9b0a-ff89-49545db19fc4.png)


...



## おわりに

以上がメニューUIの作成方法になります。
オブジェクトのアクティブ状態を切り替えるだけなので、Unity開発者であればできて当たり前なことと思います。
この記事が何かの為になれば嬉しいです。
それではさよなら。
Laravelのリレーション管理：外部キーを明示的に指定する方法

# はじめに
この記事はLaravelを学習する過程で得られた結果の備忘録です

誤りや追記が必要な場合は都度修正します

## Laravelのリレーション設定
次のように hasMany メソッドが存在する場合、Laravelは外部キーを自動的に推測します。

そこで発生しやすいエラーが、**存在しない外部キーを参照する**ことです。

本来ならば`customer_id`を参照して欲しいところ`customer_customer_id`というカラム名を自動的に推測して参照する場合があります。このような推測が誤って行われると、エラーの原因になります。

そのため**hasMany** と **belongsTo メソッド**それぞれの引数に対して、外部キーを指定することで、正しい外部キーを参照することができます。

### 修正前
```customer.php
public function customer_contacts()
{
    return $this->hasMany(CustomerContact::class);
}
```
```customer_contacts.php
public function customer()
	{
		return $this->belongsTo(Customer::class);
	}
```
### 修正後

```customer.php
public function customer_contacts()
{
    return $this->hasMany(CustomerContact::class,'customer_id');
}
```
```customer_contacts.php
public function customer()
	{
		return $this->belongsTo(Customer::class,'customer_id');
	}
```

## まとめ
Laravelでリレーションの設定を組み込む場合は、メソッドの引数に対して外部キーを与えることで、確実に外部キーを参照することができるようになります。この設定により、予期しないエラーを防ぎ、アプリケーションの信頼性を向上させることができます。
FastAPIプロジェクトのはじめかた

## 必要なモジュールをインストール

以下を実行
  - `pipenv install pydantic-settings`
  - `pipenv install fastapi[all]`

    Pythonプロジェクトを作ったら `pydantic-settings` は即インストールで良い

## ディレクトリを構成
以下の構成を最初に作ってしまうことを推奨
  ```plaintext
    + [project-root]
          +-- src
               +-- api
                    +-- .gitkeep
               +-- controller
                    +-- .gitkeep
               +-- models
                    +-- .gitkeep
               +-- main.py
               +-- settings.py
          +-- tests
               +-- conftest.py
          +-- Pipfile
  ```

## 環境変数読み込み実装

`src/settings.py` を編集

backendを構築する上でDBアクセスなど高確率で何らかの外部変数が必要になる
環境変数や.envファイルによる指定を想定

  ```python
  from pydantic_settings import BaseSettings


  class Settings(BaseSettings):
      FOO: str  # プログラムで扱う環境変数を定義
      BAR: int

  settings = Settings()

  ```

## サンプルAPI実装

`src/api/foo.py` を作成

スキーマとリクエスト/レスポンス処理を記載
処理は `Controller` に委譲することでFastAPIからの移植性を確保
以降は `Controller` 以下の作り込みになる

`Controller` はDBへのコネクションやロードしたLLMなどを保持する想定

  ```python
  from fastapi import APIRouter
  from pydantic import BaseModel
  
  from controller.foo import FooController

 
  foo_router = APIRouter()
  controller = FooController()
  
  
  class FooGetRequest(BaseModel):
      pass

  class FooGetResponse(BaseModel):
      data: str
  
  @foo_router.get('/foo')
  async def health(request_body: FooGetRequest):
      result = controller.get( ...)
      return FooGetResponse(result ...)


  class FooPostRequest(BaseModel):
      data: str

  class FooPostResponse(BaseModel):
      id: int
  
  @foo_router.post('/foo/post')
  async def health(request_body: FooPostRequest):
      result = controller.post(request_body ...)
      return FooPostResponse(result ...)
  ```

## エントリポイント実装

`src/main.py` を編集

import用の `sys.path` をここで設定しておく

  ```python
  import os
  import sys
  from fastapi import FastAPI

  sys.path.append(os.path.dirname(__file__))
  from api.foo import foo_router
  from api.bar import bar_router

  
  app = FastAPI()
  app.include_router(foo_router)
  app.include_router(bar_router)
  ```

## サーバ起動

以下のコマンドにより `uvicorn` を起動

  - `uvicorn src.main:app --host 0.0.0.0 --port 8000 --reload`

    `localhost:8000` に適当なリクエストを送って動作確認する
Gitでremoteの管理をする方法

初Qiitaです。よろしくお願いします。

## 概要

Gitで複数のリモートを使い分けるときのコマンドをまとめました。

基本的には`git remote`コマンドにオプションを指定しながら操作していきます。

リポジトリ名 (`origin`や`upstream`のような、各リポジトリに個別に名付けるもの) と、対応するリポジトリのurlの準備が必要です。

## Remoteとの連携操作


### リポジトリとの連携の追加

```
git remote add [リポジトリ名] [リポジトリのurl]
```

### リポジトリとの連携の削除

```
git remote rm [リポジトリ名] [リポジトリのurl]
```

### リポジトリのurlの変更

```
git remote set-url [リポジトリ名] [新しいリポジトリurl]
```

### 参考資料
Git公式ドキュメント: [Git - git-remote Documentation](https://git-scm.com/docs/git-remote)

### あとがき
将来的には`git remote`のドキュメントを全部読んでみたいです。オプションのバリエーションもそんなに膨大なわけではないので意外と行けそう。
API経由でTerraform CloudのWorkspaceの設定を変更する

# はじめに

どうも、@to-fmakです。今回は、APIを利用してTerraform CloudのWorkspaceの設定変更を行いましたので、その手順について紹介します。
具体的には、WorkspaceのTerraformバージョンを変更する方法と、最近開発した一括設定変更用の自動化ツールについて紹介します。

※本記事の内容はすべて執筆時点（2024年10月）の情報に基づいています。

# WorkspaceのTerraform Version設定について

Terraform CloudのWorkspaceでは、以下のような方法でTerraformのバージョンを設定することができます。

## Automatically updating

- `~>1.9.0 latest(1.9.8)`など：マイナーバージョン（例：1.9）まで固定し、パッチバージョン（例：1.9.8）は最新を使用する
- `latest`：最新のバージョンを常に使用する

## All released versions

過去にリリースされたすべてのバージョンから、特定のバージョンを選択することができます。

## デフォルトの設定

>By default, HCP Terraform uses the latest Terraform version. You can alternatively select an exact version or use a version constraint.

デフォルト設定では、最新のバージョンが自動的に適用されます。

# API経由での設定方法

以下の手順でWorkspaceのTerraformバージョンを更新します。

## アクセストークンの取得

APIを使用してTerraform CloudのWorkspace設定を変更するには、まずTerraform Cloud APIのアクセストークンを取得する必要があります。
Terraform CloudのUser SettingsからAPIトークンを生成します。

## Workspace IDの確認

対象のWorkspaceのIDをAPI経由で取得するか、Terraform CloudのGUIで確認します。WorkspaceのIDをAPI経由で取得コマンドは以下です。

```bash
curl \
    --header "Authorization: Bearer {YOUR_TOKEN}" \
    --header "Content-Type: application/vnd.api+json" \
    --request GET \
    https://app.terraform.io/api/v2/organizations/{YOUR_ORG_NAME}/workspaces/{YOUR_WORKSPACE_NAME} | jq -r '.data.id'
```

※jqを使用していますので、インストールされていない場合は事前インストールが必要です。

## APIリクエストの送信

以下のようなAPIリクエストを利用して、WorkspaceのTerraformバージョンを更新します。

```bash
curl \
    --header "Authorization: Bearer {YOUR_TOKEN}" \
    --header "Content-Type: application/vnd.api+json" \
    --request PATCH \
    --data '{
          "data": {
            "type": "workspaces",
            "id": "{YOUR_WORKSPACE_ID}",
            "attributes": {
              "terraform_version": "1.9.8"
            }
          }
        }' \
    https://app.terraform.io/api/v2/workspaces/{YOUR_WORKSPACE_ID}
```

Automatically updatingにしたい場合、terraform_versionの値を以下のように記述できます。

```text
"terraform_version": "~>1.9.0"
```

# Terraform Version Updater for Terraform Cloud

指定したOrganization内の指定したWorkspace（複数指定可能）のTerraform Versionを一括で変更するツールを作成しました。
詳細はrepo内のREADME.mdをご参照ください。

https://github.com/to-fmak/tfc-tf-version-updater

# 参考URL

https://developer.hashicorp.com/terraform/cloud-docs/workspaces/settings

https://developer.hashicorp.com/terraform/cloud-docs/api-docs

## エンジニア募集

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！
ぜひお気軽にカジュアル面談へお越しください！！

https://gakken-leap.co.jp/recruit/
ER図とLucidchartについて

**ER図とは何か
ER図（Entity-Relationship Diagram）は、データベースの構造を視覚的に表現するための図です。データベース内の情報（エンティティ）、それらの関係、そして属性の関係性を明確にするために用いられます。ER図を用いることで、データの設計が論理的かつ効率的であるかどうかを事前に確認でき、実装や管理がしやすくなります。**

**ER図の基本要素
ER図では、以下の3つの主要な要素を使います。**

エンティティ（Entity）

データとして保存する対象のことです。
例：ユーザー、注文、商品 など。
表記：四角形で囲まれる。
属性（Attribute）

エンティティに付随するデータです。
例：ユーザーエンティティには、ユーザーID、名前、メールアドレスといった属性があります。
表記：楕円形で囲まれる。
リレーションシップ（Relationship）

エンティティ同士の関連を示します。
例：ユーザーと注文の間に「ユーザーが注文をする」という関係。
表記：ひし形で囲まれる。
ER図の具体的な例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3823687/67d63c0f-c481-9a64-ab98-9361af9e6cb9.png)


# 1. シンプルなER図の構成例
問題：ECサイトのデータベース設計
エンティティ：ユーザー、注文、商品
関係性：ユーザーは複数の注文を行い、注文には複数の商品が含まれる。
ER図構造例：

ユーザー（ユーザーID, 名前, メールアドレス）
注文（注文ID, 日付, 合計金額）
商品（商品ID, 商品名, 価格）
関係性：

1人のユーザーは複数の注文を行える（1対多）。
1つの注文には複数の商品が含まれる（多対多）。
多対多の関係を扱う方法
多対多の関係を表現する場合は、「中間テーブル」を使います。
上記の例では、「注文」エンティティと「商品」エンティティが多対多の関係になるため、注文詳細 という中間エンティティを設けます。

注文詳細（注文ID, 商品ID, 数量）
これで「注文」と「商品」の間に1対多の関係ができ、それぞれの注文に含まれる商品が明確になります。

ER図を使うメリット
複雑なデータ構造の可視化
ER図を用いることで、開発者同士やクライアントとの間でデータベースの構造を直感的に共有できます。

データの正規化を助ける
冗長なデータやデータの不整合を回避するための設計が容易になります。

開発前の設計の品質向上
データベースの論理的な欠陥やミスを、実装前に見つけて修正できます。

ER図の作成ツール
ER図を作成するには、以下のようなツールが便利です：

**Lucidchart – シンプルで使いやすいクラウドベースのツール←個人的におすすめのツール** 
Figma – UIデザインだけでなく、ER図の作成にも対応
MySQL Workbench – MySQLデータベースの管理に特化したツール
dbdiagram.io – データベース設計に特化したオンラインツール

今回は例としてLucidchartについて説明したいと思います。


Lucidchartの特徴
幅広い図表テンプレート

ER図、フローチャート、ネットワーク図、マインドマップ、プロセス図などのテンプレートが豊富。
テンプレートを使えば、素早くプロジェクトのニーズに合った図を作成できます。
リアルタイムでのコラボレーション

他のメンバーと同時に編集が可能。変更は瞬時に反映されるため、議論しながら図を完成させられます。
コメント機能や共有リンクを活用して、フィードバックを得ることも容易。
直感的なインターフェース

ドラッグ＆ドロップ操作で簡単に要素を配置できます。デザインの知識がなくても操作しやすい設計です。
多彩な連携機能

Google Drive、Microsoft Teams、Slack、Jira、Confluenceなどのツールと連携。
Lucidchart上の図表を簡単に他のツールへ共有・埋め込みが可能。
デバイスを問わない利用

クラウドベースなので、PC・タブレット・スマートフォンからアクセス可能。アプリも提供されています。
インポートとエクスポート機能

Visioファイルのインポートに対応。Visioからの移行もスムーズ。
作成した図表をPDF、PNG、SVGなどの形式でエクスポート可能。
Lucidchartの活用例
ビジネスプロセスの可視化
フローチャートやプロセス図を作成することで、業務の流れを可視化し、効率化のポイントを明確にできます。

ER図を使ったデータベース設計
データベースの構造を設計し、エンティティとその関係性を把握するのに最適です。LucidchartはER図のテンプレートも充実しており、簡単に設計ができます。

UI/UXデザインのワイヤーフレーム作成
WebやモバイルアプリのUI設計を、ワイヤーフレームとして素早くプロトタイプ化。チーム内でのフィードバックをもらいながら進められます。

ネットワーク構成図の作成
ITインフラやネットワークの設計図を作成して、システム管理や構築の計画に役立てます。

マインドマップでのブレインストーミング
アイデアを可視化するためのマインドマップを作成し、プロジェクトの初期段階で議論を促進します。

Lucidchartの料金プラン
Lucidchartは、個人利用から大規模なチーム向けまで対応する複数のプランを提供しています。

無料プラン

基本的な機能を利用可能。小規模な図表の作成に向いています。
個人プラン

より高度な機能が使えるプラン。無制限の図表作成とテンプレートが利用可能。
チームプラン

チームメンバーでのコラボレーション機能が充実。共有フォルダやリアルタイム編集が可能。
エンタープライズプラン

大規模組織向け。セキュリティと管理機能が強化され、カスタム統合も提供。
Lucidchartの始め方
アカウント作成
Lucidchartの公式サイト（https://www.lucidchart.com）にアクセスし、無料アカウントを作成します。

テンプレートを選択
ダッシュボードから必要なテンプレートを選んで、図表の作成を開始します。

要素をドラッグ＆ドロップ
図形やテキストボックスを配置し、必要に応じてラインや矢印で要素同士をつなげます。

共有・エクスポート
図表が完成したら、リンクで共有するか、PDFなどでエクスポートして配布します。



# まとめ
ER図は、データベースの設計段階で非常に重要な役割を果たします。エンティティ、属性、リレーションシップという基本要素を理解することで、効果的なデータベース設計が可能になります。ER図を活用することで、アプリケーションの開発がスムーズになり、データの不整合や冗長性を防ぐことができます。

**最後までよんでいただきありがとうございます。
毎日更新していますので、@y-t0910をフォロー,いいねしていただけると嬉しいです！**
プロジェクトを一括でChatGPTに認識させる方法

# 世界中のサービスに出会えるプラットフォーム

突然ですが、みなさんは「Product Hunt」というサイトをご存知でしょうか？  
開発者が自身のアプリやWebサービスを投稿し、ユーザーが実際に使って評価するためのプラットフォームです。評価の高いものはサイト上でランキング形式で表示され、注目を集めます。このサービスは2013年にアメリカの起業家によって開発されました。

開発者にとっては、自分のサービスに対するフィードバック（FB）をもらえたり、他の開発者がどのようなプロジェクトに取り組んでいるかの参考にもなります。また、ユーザーにとっては、思いがけない便利なサービスに出会えるチャンスかもしれません。

実際、私も現在取り組んでいるChatGPTとの対話形式でのWeb開発に役立つサービスを見つけましたので、後ほど紹介します。

https://www.producthunt.com

# 今回紹介するサービス「Code Spoonfeeder」

「Code Spoonfeeder」は、プロジェクトフォルダ全体をテキストファイルに変換してくれる便利なサービスです。このテキストファイルをChatGPTにアップロードすると、ChatGPTがプロジェクト内のコード全体を素早く把握してくれるため、効率的に支援が受けられます。

通常はコードをファイルごとに入力していくことで、ChatGPTが徐々にプロジェクトを理解していきますが、このサービスを使うと一括でプロジェクト全体を把握させることができます。これにより、ChatGPTからの適切な支援を即座に受けられるようになります。

以下のサイトにアクセスし、プロジェクトフォルダを指定して「Upload」するだけで、テキストファイルが生成されます。これをChatGPTに添付すれば、フォルダ構成からコードの中身までをすべて理解してもらえます。

https://code-spoonfeeder-3fc96ecd8dd6.herokuapp.com/?ref=producthunt

![Code Spoonfeederのスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/5e4fe2a6-84f8-d042-2288-49fe1a04e5c7.png)

# ユースケース

1. **ChatGPTから開発支援を受けるとき**
2. **他の開発者が作成したプロジェクトを引き継ぐとき**  
   プロジェクト全体をすぐに把握できます。
3. **後から仕様書を作成するとき**  
   プロジェクト全体をテキスト化して、ドキュメント作成に役立てられます。
4. **新しいチャットに内容を引き継ぎたいとき**  
   同じチャットでやり取りを続けていると、段々と読み込みが遅くなることがあります。その際、プロジェクトをテキストファイルに変換して新しいチャットに添付すると、内容を引き継いだ状態でスムーズに新たなチャットを始めることができます。

# 最後に

こちらのサービスは、私がChatGPTの支援を受けながら作成したものです。  
ぜひアクセスしていただき、さまざまなフィードバックをいただけると嬉しいです。ソフトウェア開発初心者でも、ここまでのサービスを作り上げることができました。開発の詳細については、過去の記事で詳しく解説しています。

## サービス一覧

- **マニュアルを作成・共有するサービス**  
  手続き方法や申請方法のマニュアルを簡単に作成して共有できるプラットフォームです。  
  
https://manualshare.net

- **海外旅行者が日本に関する情報を自由に共有できるプラットフォーム**  
  日本を訪れる旅行者がさまざまなトピックについて情報交換できる、登録不要のオープンなプラットフォームです。

https://travel-class.com
PHPとは

# PHPとは
Web開発に特化したサーバーサイドのスクリプト言語のこと。処理がサーバーサイドで行われるのが特徴であり、ユーザーがWebページを訪問するとPHPコードがサーバー上で処理される。そのため、ユーザーはPHPコードを見ることができない。

# PHPとHTML
- ### HTML
文章や画像、リンクなどのコンテンツを配置し、ユーザーに見せるために使われる。HTML自体は静的であり、ユーザーの操作に応じてページが動的に変わることはない。

- ### PHP
Webページに動的な機能を追加するために使われる。PHPを使うことでデータベースから情報を取得したりと、ユーザーのリクエストに応じてページの内容を動的に生成することができる。PHPはサーバー上でHTMLを動的に生成する。
## 静的と動的
### 静的


- ***ユーザーに応じて変わらない***

誰がそのページを訪れても、同じ内容が表示される。

- ***サーバー側の処理が少ない***

サーバーがそのままファイルを提供するだけなので高速。

(使用例)紹介ページやブログなど
### 動的
- ***内容が変わる***

ページの内容は固定されておらず、サーバー上でリアルタイムに生成される。
そのため、動的なページは、ユーザーごとに異なる情報を表示できる。

- ***データベースと連携***

データベースと連携することで、ユーザーがリクエストするたびに最新のデータを取得して表示する。たとえば、商品一覧ページでは在庫の情報を動的に表示できる。

- ***サーバー側での処理が必要***

サーバーがユーザーからのリクエストに応じて、動的ページを生成する。そのため、静的なページに比べて処理が多くサーバーの負荷が高くなる。

(使用例)amazonなどのecサイト、Twitterなど




## **基本のPHPコード**
   PHPコードは `<?php` と `?>` の間に書かれる。

   ```php
   <?php
   echo "Hello, World";
   ?>
   ```


## **変数の宣言**
   PHPでは変数は `$` で始まる。以下では、変数 `name` に "hase" を代入し、出力している。

   ```php
   <?php
   $name = "hase";
   echo "Hello, " . $name . "!";
   ?>
   ```

 

## **条件分岐**
   `if` 文を使って条件分岐を行うことができる。

   ```php
   <?php
   $score = 85;

   if ($score >= 90) {
       echo "excellent";
   } elseif ($score >= 70) {
       echo "nice";
   } else {
       echo "bad";
   }
   ?>
   ```
これだけ知ればOK! ZIOのデザインパターン - Service Pattern

[ZIO](https://zio.dev/)は "Type-safe, composable asynchronous and concurrent programming for Scala" というキャッチコピーで表されるフレームワークです。ZIOには[Service Pattern](https://zio.dev/reference/service-pattern/introduction)と呼ばれるデザインパターンがあり、このパターンによってキャッチコピーにある `Type-safe, composable` (型安全に合成可能) を実現することができます。また、単体テストフレームワークもこのパターンで作られているので、Service Patternに則ることで自然とテストしやすい（＝テスタブルな）構成になります。便利ですね。

# なぜService Patternが必要なのか

そもそも、なぜService Patternが必要なのでしょうか？それはZIOのEnvironment Typeを効果的に使うためのパターンだからです。"Environment Type"とは、`ZIO[R, E, A]`の3つの型引数のうちの一つである`R`のことです。Service Patternは`R`を通して依存性の注入を行う仕組みを提供します。

# Service Pattern

サービスパターンは大きく分けて2人のアクターがいて、「そのサービスを提供する人」と「そのサービスを使う人」です。そして提供側には「サービスの仕様」と「サービスの実装」を用意する必要があります。

## そのサービスを提供する人

### サービスの仕様

標準出力に `Hello` と出力するサービスを作るとしましょう。それを HelloService として、その仕様を記述します。

```scala:HelloService.scala
import zio.*

trait HelloService:
  def hello(): Task[Unit]

object HelloService:
  def hello(): RIO[HelloService, Unit] =
    ZIO.serviceWithZIO(_.hello())
```

本当に必要なのは trait だけですが、object があることで「そのサービスを使う人」が便利になります。

### サービスの実装

そして、この trait を実装するクラスと、この実装を ZLayer として提供する object を作ります。

```scala:HelloServiceImpl.scala
import zio.*

private class HelloServiceImpl extends HelloService:
  override def hello(): Task[Unit] =
    Console.printLine("Hello")

object HelloServiceImpl:
  def layer: ULayer[HelloService] =
    ZLayer(ZIO.succeed(new HelloServiceImpl()))
```

## そのサービスを使う人

サービスを使う場合、実際に使うコードと、そのZIOインスタンスにZLayerを渡す必要があります。

```scala:Main.scala
import zio.*

object Main extends ZIOAppDefault:
  def run = {
    for _ <- HelloService.hello()   // 実際に使っている部分
    yield ()
  }.provide(HelloServiceImpl.layer) // ZLayerを渡している部分
```

ここでの特徴を整理します。

- 「実際に使っている部分」は仕様に依存しています。つまり、実装を入れ替えられます。
- 実装を入れ替えるには「ZLayerを渡している部分」を切り替えます。一般的な使い方としては単体テストです。

面白いのは、ZIOはエフェクトシステムにおける「エフェクト」というインスタンスになります。これは「実際に使っている部分」と「ZLayerを渡している部分」を分離できます。

```scala:Main.scala
import zio.*

object Main extends ZIOAppDefault:
  def domain =
    for _ <- HelloService.hello()          // 実際に使っている部分
    yield ()

  def run =
    domain.provide(HelloServiceImpl.layer) // ZLayerを渡している部分
```

ここで `domain` は仕様にしか依存していない純粋な処理になっています。一方で `run` は依存するインスタンスを注入している部分（一般的に wiring と呼ばれる部分）になります。

サービスパターンは一種のフラクタル構造になっていて、「サービスを提供する人」は、別の「サービスを使用する人」になれます。そのため大きなアプリケーションであっても、小さなサービスの集合体として記述することができます。

また、単体テストは `domain` に対して任意のFakeオブジェクトをprovideすることで処理を切り替えることができます。

### Type-safe

とってつけたように補足を。複雑なdomainを作った際、必要な ZLayer が少なかった場合はコンパイル時点でエラーになり、かつ有効な ZLayer の候補を教えてくれます。Environment Typeの型境界のおかげでいい感じにエラーを生成してくれるんですね。便利。

# まとめ

ZIOには3つの型引数があり、そのうちの一つである `R` を活用するためのデザインパターンがあります。それがService Patternであり、これには次のメリットがあります。

- `R` を通してDIができます。
- サービスの実装ではなく、サービスの仕様に依存します。これにより単体テストがしやすくなります。
- Service Patternはフラクタルです。これを組み合わせることで小さなサービスの集合体から大きなアプリケーションを組み上げることができます。

つまり、ZIOでアプリケーションを作るには、Service Patternだけ知っていればOKなのです。便利。
Macでショートカットappを使い楽にconda環境操作

# 内容
Mac標準アプリのショートカットappで、メニューバーからクリックでconda環境の色々を行う。
1. Make Env : 新規環境の作成
1. Remove Env : 環境の削除
1. Activate Env : `conda activate env_name`した新規Terminalタブを作る
1. Export yml : ymlファイルを書き出し

# 動機
プログラミング初学者の時に(今は初心者)環境構築した際、`conda ~~`みたいなコマンドを見て、
「え、これ覚えなきゃいけないの??」と思った際に作ったもの。
1、2年前に作ったもので、ちょっとずつ変えていって今の形に落ち着いた。

# 予備知識
下の`https://www.icloud.com/~~`からダウンロードして使用する。
その際、「Make Env」と「Export yml」自身の環境に合わせてpathを変えなければならない
ymlのパスが〜という感じで書かれているが、ymlとはここでは
「condaで環境を作るときのレシピ」のようなもの、pipで最初にコレコレを入れてねのように
詳しくは自身で調べてください。

# ショートカット本体

### Make Env
新規環境の作成

https://www.icloud.com/shortcuts/c7ba338964304fde807c77830b14a99a

使用者の環境に合わせて以下の部分を自身のベースとなるymlに変えてください。

<div align="center"><img width="500" alt="image" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1278266/0ca47af5-ee19-0e70-b959-0bc23f5a7ef6.png"></div>

### 1. Make Env
新規環境の作成

https://www.icloud.com/shortcuts/c7ba338964304fde807c77830b14a99a

使用者の環境に合わせて以下の部分を自身のベースとなるymlに変えてください。
<div align="center"><img width="500" alt="image" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1278266/0ca47af5-ee19-0e70-b959-0bc23f5a7ef6.png"></div>

### 2. Remove Env

https://www.icloud.com/shortcuts/0555b3001bd940108b3266228572efab

### 3. Activate Env

https://www.icloud.com/shortcuts/0d16b0b5c04d40e8942b2cfb581b4d6f

### 4. Export yml

https://www.icloud.com/shortcuts/c38cde2b19e7499bac2ff2d5454e748c

使用者の環境に合わせて以下の部分をymlを保存したいディレクトリのパスに変えてください。
<div align="center"><img width="500" alt="image" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1278266/9d854b2e-f188-da47-9211-c39f24e21ffc.png"></div>

# 作ってる際に得た知識
### `シェルスクリプトを実行`でconda
ショートカットappの`シェルスクリプトを実行`では`.zshrc`を読み込んでくれず、condaと打ってもパスが通ってないと言われてしまう。
この際`zsh -i -c 'code'`とすると、`.zshrc`を読み込んでくれる。
チャットGPTによると

::: note info
zsh -i -cは、Zshシェルをインタラクティブモードで実行し、
特定のコマンドを実行するオプションです。
- -i
  - インタラクティブモードでZshを起動します。
    インタラクティブモードでは、シェルはプロンプトを表示し、
    通常の対話的なシェルとして振る舞います。
    また、.zshrcなどの設定ファイルも読み込まれます。
- -c "command"
  - 指定したcommandを実行します。このコマンドの実行後、シェルは終了します。

例として、zsh -i -c "echo Hello"とすると、
インタラクティブシェルが起動してecho Helloが実行され、
出力が表示された後にシェルが終了します。
:::
だそうな

### 環境リストの取得
以下のようにやっています。
<div align="center"><img width="500" alt="image" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1278266/7faa7ff2-a9b9-68de-cbde-cb388f1d2544.png"></div>
「テキストを分割」を2回やっているのは、1回だと謎の空行が最後に必ず入ってしまうため。
fastlaneの出力に色をつける

## Come on 色付き出力

fastlane で何か文字列を出力したいときに

```ruby
  puts "print messages."
```

とかやっても、普通に白い文字（黒い背景なら）が表示されるだけです。
組み込み Action が出すようなカラフル出力にしたい場合は、

このよう⬇️⬇️⬇️に書くと...

```ruby:
  UI.error("error")
  UI.important("important")
  UI.success("success")
  UI.message("message")
  UI.deprecated("deprecated")
  UI.command("command")
  UI.command_output("command_output")
  UI.verbose("verbose")
  UI.header("header")
```

このように⬇️⬇️⬇️表示されます！

![fastlane.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169798/c5fcfd12-7391-9add-9a68-8b6337ef8fda.png)

## 参考
ここに書いてありました。

https://docs.fastlane.tools/advanced/actions/

⬆️⬆️⬆️の <b>User input and output</b> のとこ（アンカーが無い💧）。
【2023年版】Rustリポジトリのコミット動向、主要言語との比較

2023年のRustリポジトリのコミット数を Author ごとの時系列グラフにしてみました。

2023年のRustリポジトリの総コミット数は28014回でした。この数は、主要なプログラミング言語の中で圧倒的に大きく、Swift と Kotlin をのコミット数を足した数よりも大きいです。

Author の合計人数は1104名です。上位5名で合計11014コミット、全体の39%を占めています。

![rust-commits.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33011/9c2a91fa-077a-239d-dbc0-8b32b0193add.gif)

- 集計したリポジトリは [rust-lang/rust - GitHub](https://github.com/rust-lang/rust) の master ブランチです
- グラフデータには `git log -n 10000000 --date short --pretty=format:"%ad%x09%h%x09%an"` を使いました
- 2023年の総コミット数は `egrep '^2023' commits.txt | wc -l` で集計しました
- マージコミットや bot のコミットはそのまま含めています
- リポジトリによってはコミッターが複数のコミットを集約しています

----

参考までに、2023年の主要なプログラミング言語のコミット数の時系列グラフはこちらです。

![all-commits-2023.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33011/50dba6f8-a58b-be1d-0719-92b73874edd8.gif)

| 言語名 | コミット数 | Author 数 | 平均コミット数 |
|:-:|:-:|:-:|:-:|
| Rust  |  28014 | 1103 |  25.3 |
| Swift  |  16181 | 224 |  72.2 |
| Kotlin  | 10363  |  191 | 54.2 |
| C,C++(GCC)  |  9870 |  383 | 25.7 |
|  Ruby | 6767  |  307 | 22.0 |
| Java(OpenJDK)  |  4729 |  380 | 12.4 |
| Python  | 4458  |  645 | 6.9 |
|  PHP | 3765  |  144 | 26.14 |
|  Go | 3685  | 322 | 11.4 |
|  JavaScript(Node.js) |  2687 | 360 | 7.4 |
|  Perl |  1776 | 87 | 20.4 |
Firebase Storageからファイルをフェッチする際に発生するCORSエラーの解消方法

# 事象
Firebase Storageからファイルの取得をfetch関数を使用して試みたが、その際にうまく取得できなかった。
```tsx
import { useEffect } from "react";

export default function Home() {
  useEffect(() => {
    (async () => {
      // Firebase Storageに保存されている画像のダウンロードURLを取得
      const storageRef = ref(storage, 'image.png')
      const downloadUrl = await getDownloadURL(storageRef)

      // fetchして、画像データを取得
      const response = await fetch(downloadUrl)
      const blob = await response.blob()
      const image = new File([blob], 'image.jpg', { type: 'image/jpeg' })
      console.log(`サイズ: ${image.size} bytes`)
    })()
  }, [])
  return (
    <></>
  );
}
```
発生していたエラーは下記の通り。
```
Access to fetch at 'https://firebasestorage.googleapis.com/v0/b/xxxxxxxxxx'
from origin 'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
```
ローカル（`http://localhost:3000`）からFirebase（`https://firebasestorage.googleapis.com`）に対するリクエストがCORSポリシーによってブロックされたよって。
つまり、コードではなくFirebaseの設定の問題。

# 解決策
それじゃ、設定を変更しよう！と思ってFirebaseコンソール内を探してもそれらしき項目は見当たらず、、どうやらgsutilツールを使用して設定するのが一般的らしい。面倒。。
### step 1
下記からgsutilをインストールして、コマンドを使用できるようにしておく。
https://cloud.google.com/storage/docs/gsutil_install?hl=ja
### step 2
設定ファイルを作成する。重要なのは、originにブロックしてほしくないURL（今回で言うところの`http://localhost:3000`）を記載すること。
```json
[
  {
    "origin": ["http://localhost:3000"],
    "method": ["GET"],
    "maxAgeSeconds": 3600
  }
]
```
### step 3
gsutilコマンドを実行する。「step 2で作成した設定ファイルのパス」と「Google Cloud Storage URI」は適宜設定すること。
```
gsutil cors set [step 2で作成した設定ファイルのパス] [Google Cloud Storage URI]
```
Google Cloud Storage URIとは、`gs://`から始まるパスのことで、具体的には`gs://[FirebaseプロジェクトID].appspot.com`である。
ちなみに、実行後は設定が正しく反映されているかを確認できる。
```
gsutil cors get [Google Cloud Storage URI]
```
<br>
ということで、面倒だったけど無事解決。
undefinedを許容する場合の「Optional Property」と「Union型」での定義の違いについて

# ことのはじめ
TypeScript初心者数名でチームを組み、アプリ開発を行なっていたところ、オブジェクトのプロパティの型定義や関数の引数で以下の記述が混在していた。
```ts
type Hoge = {
  fuga?: number
}
```
```ts
type Foo = {
  bar: number | undefined
}
```
当時は「?」を使うのが省略記法で、ただの表記揺れかと思い、統一感がないので「?」を使う方に統一しましょう的な感じで話を終えていたが、調べてみたらちゃんと違いがあったので、備忘がてらメモ。

# 違い
まず、前者はOptional Propertyである。その名の通り、プロパティ自体が任意（オプショナル）となるので、プロパティを省略することができる。つまり、
```ts
type Hoge = {
  fuga?: number
}

const hoge1: Hoge = { fuga: 0 } // ⭕️
const hoge2: Hoge = { fuga: undefined } // ⭕️
const hoge3: Hoge = {} // ⭕️
```
と書ける。
<br>
それに対し、後者はUnion型である。プロパティの型がnumberまたはundefinedであるということが明記されているのであって、プロパティを省略することはできない。よって、
```ts
type Foo = {
  bar: number | undefined
}

const foo1: Foo = { bar: 0 } // ⭕️
const foo2: Foo = { bar: undefined } // ⭕️
const foo3: Foo = {} // ❌
```
となる。

# 所感
では違いを理解したところで、使い分けについて考えたみたが、簡潔かつ利便性が高いという理由で、やっぱり基本的にOptional Propertyで良くない？と思った。「プロパティが存在しない」と「明示的にundefined」の区別をつけたい場合がUnion型の出番かと思われるが、かなり限定的なケースかと思慮。TypeScript上級者さん達はどう使い分けてるのだろうか...？
[HubSpot CMS] ビルドステップなしでVue3を使うには

# やりたいこと
- Hubspot CMSのカスタムモジュール内でVue3を利用する
- Vue.jsはCDNから呼び出して使う

# 想定対象者
- 今までWebサイトで使っていたVue.jsのテンプレート部分をHubspotでも使いたい方
- ガッツリHubspotのテンプレートを開発環境から組まないライトユーザー（デザインマネージャで事足りる方）

## どうやったか

### 1. モジュールにCDNからVue.jsを読み込む
カスタムモジュール内のみでVue.jsを利用するため、`module.html`にCDNでVue.jsを読み込みます。
Hubspotで用意されている`require_js`関数を使います。

```jinja:module.html
{{ require_js("https://unpkg.com/vue@3/dist/vue.global.prod.js", "footer") }}
```

https://developers.hubspot.jp/beta-docs/reference/cms/hubl/functions#require_js

### 2\. モジュールのHubL内でVue部分をRawタグで囲む

https://developers.hubspot.jp/beta-docs/guides/cms/setup/js-frameworks?uuid=d986a488-cf2d-4710-9219-8ec5902a72c3

開発者ドキュメントにもそのように書いてあるんですが、Rawタグについて詳細な記法の記載がないのですが、いろいろ試してみたところ、このような記法になるようです。

```:module.html
{% raw %}
  <div id="app">
    {{ message }}
  </div>
{% endraw %}
```


このように書くことで`raw`タグに挟まれたコード`{{ message }}`の部分はちゃんとVue.jsのマスタッシュ構文として認識されるようになります。


### 3\. module.jsにVue.jsのコードを書く

あとは、モジュールに表示したいコードを`module.js`に記載します。この時、DOMの読み込み完了した後で実行されるよう、`document.addEventListener`でコードを囲んでコーディングします。

```js:module.js
document.addEventListener("DOMContentLoaded", (event) => {
  const { createApp, ref } = Vue

  createApp({
    setup() {
      const message = ref('Hello vue!')
      return {
        message
      }
    }
  }).mount('#app')
```

## 終わりに

Hubspot移行で簡単に以前Vueで作ったコードを利用したい際の覚書でした。
大体は開発者ドキュメントを見ればなんとかなるようにはなっていますが、たまにハマることがあるので誰かのお役に立てばいいなと思っています。
Salesforce CRM Analytics Connect API Postman Collectionの設定手順

参考資料：[Set Up the Connect API Postman Collection](https://developer.salesforce.com/docs/platform/connectapi/guide/set-up-the-collection.html)

## 設定手順
1. postmanにログインします。
    1. https://www.postman.com/

2. 以下のサイトに行って、run in postmanをクリックします。
https://www.postman.com/salesforce-developers/salesforce-developers/collection/z5vnma1/salesforce-crm-analytics-connect-api
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672646/76958efb-d282-486f-2655-bd4708b85f7b.png)

3. fork collectionを作成します。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672646/d62578ae-5814-07ba-82f2-ba63e5d97301.png)
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672646/951937b7-f2d6-a031-7019-36f9352b905c.png)

 4. Authiruzationタブをクリックし、一番下にある[Get New Access Token]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672646/7cbfdec9-f07c-e3b3-a619-2209229a6452.png)


 5. アクセスを許可します。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672646/e21df24f-c68b-7c6a-dce5-5be59088ae11.png)


6. Manage Access Tokenの画面のinstance urlをメモします。「Use Token」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672646/888a443a-cdce-e783-7c1b-2e4dfc0eb242.png)

7. Variablesの画面に移動します。_endpointのところにメモしたinstance urlを記入して、[Save]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672646/8da70fc1-2364-da75-a4e5-1503443b707d.png)


設定完了しました。
試してみましょう

## getDatasetを試します。
1. getDatasetをクリックします。
2. GetのところにdatasetIDあるいはAPI名を入力します。
3.[Send]をクリックしますと、JSON格式の結果を返してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672646/668fca9f-ccbd-2f10-d406-9f2a98ab3d4e.png)
ファイルパスが255文字を超えるファイルのコピーと削除

## コピー
FastCopyを使う

https://fastcopy.jp/

## 削除
「この項目は見つかりません」と出て，操作不能になってしまったファイル削除

```
del "\\?\ファイルの絶対パス"
```
例
```
del "\\?\C:\Users\temp"
```
node.js からのコマンドライン引数を綺麗に受け取る

```js:runner.cjs
const parseArgs = () => {
  // 一旦ポジショナルだけパースする
  const { positionals } = util.parseArgs({
    allowPositionals: true
  });

  // パースした値をさらにオプションをつけてパースする
  return util.parseArgs({
    args: positionals,
    allowPositionals: true,
    options: {
      dir: {
        type: "string",
        multiple: true
      },
      mode: {
        type: "string"
      },
      help: {
        type: "boolean"
      }
    }
  });
};

const { values, positionals } = parseArgs();
console.log(values, positionals); // { dir: "./hoge", mode: "dev", help: true } [ "./fuga.json" ] 
```

```bash:bash
node runner.js ./fuga.json --dir ./hoge --mode dev --help
```
Laravelとは

# Laravelとは
- LaravelとはPHPのフレームワーク。
# フレームワークとは
**フレームワークとは開発に必要な機能をまとめた枠組みのこと。**
例えるとバーベキューセットのような物。
予め、食材(関数等)が用意されており、あとは焼く（呼び出す）だけ。
セキュリティ機能もバッチリ。

まとめると

**良く使う機能は予め搭載されており、呼び出すだけ。**
**１からコードを書くより効率的に、さらにセキュリティー上も安全なwebアプリを作成できる。**

# Laravelで作成できるもの
- 顧客管理システム
- ブログ
- 学習サイト
- ECサイト
- コミュニティサイト　等
【2023年版】Pythonリポジトリのコミット動向、主要言語との比較

2023年のPythonリポジトリのコミット数を Author ごとの時系列グラフにしてみました。

2023年のPythonリポジトリの総コミット数は4458回でした。この数は、主要なプログラミング言語の中だと PHP より大きくて Java より小さいです。

Author の合計人数は645名です。上位5名で合計1490コミット、全体の33%を占めています。

![python-commits.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33011/5111100a-88b2-9caf-5a56-487e7211b352.gif)

- 集計したリポジトリは [python/cpython - GitHub](https://github.com/python/cpython) の main ブランチです
- グラフデータには `git log -n 10000000 --date short --pretty=format:"%ad%x09%h%x09%an"` を使いました
- 2023年の総コミット数は `egrep '^2023' commits.txt | wc -l` で集計しました
- マージコミットや bot のコミットはそのまま含めています
- リポジトリによってはコミッターが複数のコミットを集約しています

----

参考までに、2023年の主要なプログラミング言語のコミット数の時系列グラフはこちらです。

![all-commits-2023.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33011/50dba6f8-a58b-be1d-0719-92b73874edd8.gif)

| 言語名 | コミット数 | Author 数 | 平均コミット数 |
|:-:|:-:|:-:|:-:|
| Rust  |  28014 | 1103 |  25.3 |
| Swift  |  16181 | 224 |  72.2 |
| Kotlin  | 10363  |  191 | 54.2 |
| C,C++(GCC)  |  9870 |  383 | 25.7 |
|  Ruby | 6767  |  307 | 22.0 |
| Java(OpenJDK)  |  4729 |  380 | 12.4 |
| Python  | 4458  |  645 | 6.9 |
|  PHP | 3765  |  144 | 26.14 |
|  Go | 3685  | 322 | 11.4 |
|  JavaScript(Node.js) |  2687 | 360 | 7.4 |
|  Perl |  1776 | 87 | 20.4 |
TypstとVScodeにあるtypst-lspについて

# はじめに
~~備忘録です。~~
2024年11月5日に開発が打ち切りになりマーケットプレイスからも配信されなくなりました。
代わりに[Tinymist](https://github.com/Myriad-Dreamin/tinymist)を使用してくださいとのこと。
Pythonのtry-exceptについて知りました。感動。

# try-exceptとは？
pythonにおいて、エラー(例外)が発生する可能性のあるコードブロックを try ブロックで囲み、例外が発生した場合に except ブロック内のコードを実行するもの。

```
try: 
    何かしらのエラーが発生しそうな処理
except エラー名:
    そのエラー名が発生したときに実行する処理
```
↑のように書く。

## 知った経緯
現在、スクレイピングを学んでいる最中であり、その際に、httpリクエストが失敗したときの処理、どうしよう。。と悩んでいる時に、このtry-exceptを知りました。本来だったら、考えうるエラーに応じて、if文を書くしかないと思っていましたが、もっと簡潔に解決できました！
～実際のコード～
```
try:
    html = requests.get("URL")
    html.raise_for_status()
except requests.RequestException as e:
    print(f"Webページの取得に失敗しました：{e}")
    return None
```
## try
```
requests.get("URL")
```
【処理内容】
指定したURLに対してHTTPリクエストを送信し、サーバーからのレスポンスを取得する処理。
【起こりうるエラー】
・サーバー接続出来ない。(サーバーがダウンしている等で)
・タイムアウト。(サーバーが非常に遅い等で)
```
html.raise_for_status()
```
【処理内容】
HTTPステータスコードが200番台か確認し、200番台以外であれば、エラーとみなす。(200番台はリクエストが成功したことを示すレスポンスコード)
【起こりうるエラー】
・404 Not Found。(Webページが見つからない）
・500 Internal Server Error。(何らかのサーバ内で起きたエラー)

## except
```
except requests.RequestException
```
このRequestExceptionとは、requests モジュールにおけるすべてのリクエスト関連のエラーの親クラスです。ようするに、ネットワーク接続エラーが発生した場合に使われる、ConnectionErrorや、サーバーからエラーステータス（404など）を受け取ったときに使われる、HTTPErrorなどは、RequestException を継承したクラスなので、これをexceptに書けばほとんどのエラーに対応できる！(みたいな感じだと思います。。)
picoCTF 2024 writeup endianness

## endianness (General Skills)

Know of little and big endian? Source `nc titan.picoctf.net 56896`

添付ファイル
・flag.c

とりあえず、`nc titan.picoctf.net 56896`を実行する。
```
$ nc titan.picoctf.net 56896
Welcome to the Endian CTF!
You need to find both the little endian and big endian representations of a word.
If you get both correct, you will receive the flag.
Word: sbppe
Enter the Little Endian representation: 6570706273
Correct Little Endian representation!
Enter the Big Endian representation: 7362707065
Correct Big Endian representation!
Congratulations! You found both endian representations correctly!
Your Flag is: picoCTF{3ndi4n_sw4p_su33ess_02999450}
```
word`sbppe`をcberchefでTo Hexする。これを、little endianとbig endianに合わせて、並べ替える。
人間にとって、little endianは逆順となり、big endianは正順となる。
フラグが得られた。

`picoCTF{3ndi4n_sw4p_su33ess_02999450}`
Disable/Enable時のAwaitableを制御する

[Disable/Enable時のCoroutineを制御する](https://qiita.com/ELIXIR/items/fb32aa8124c117aa83d7)
[Disable/Enable時のUniTaskを制御する](https://qiita.com/ELIXIR/items/e3e2fb374fdf447b75aa)

Coroutine/UniTaskでのDisable/Enable時の挙動を見てきました。
ではAwaitableではどうでしょうか？

AwaitableはUnity2023 から実装された機能です。
[Unity Documentation](https://docs.unity3d.com/ja/2023.2/ScriptReference/Awaitable.html)

試してみたところ、Coroutine同様、Disableしても動き続けてしまうようです。
なのでCoroutine同様、Disable時は次の処理を待つようにしてみました。

```
using UnityEngine;

namespace Elix
{
    public class AwaitableCheck : MonoBehaviour
    {
        [SerializeField] TMPro.TextMeshProUGUI m_text = null;

        // Start is called once before the first execution of Update after the MonoBehaviour is created
        void Start()
        {
            //Debug.Log("Start");
            Awaitable awaitable = DoTaskAsync();
        }

        // Update is called once per frame
        void Update()
        {
            //Debug.Log("Update");
        }

        async Awaitable DoTaskAsync()
        {
            int count = 0;
            while (true)
            {
                m_text.text = $"{count}";
                count++;
                await Awaitable.WaitForSecondsAsync(1f);

                while(!gameObject.activeInHierarchy)
                {
                    await Awaitable.NextFrameAsync();
                }
                //Debug.Log("DoTaskAsync");
            }
        }
    }
}
```
Coroutineよりは挙動が素直で扱いやすそうです。

<iframe width="560" height="315" src="https://www.youtube.com/embed/dG-CmBMk8oY?si=ElfrWDINWK6xHOxW" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
[ ローカル LLM ] Open WebUI + ollama for Windows で複数の LLM を切り替えて使ってみた

# 複数の LLM を切り替えて使ってみたい

[前回](https://qiita.com/Yuzpomz/items/35965a44c958aafbde53)セットアップした Docker, Conda を使わない環境を使って複数の LLM を設定して Open WebUI で使ってみました
LLM の 登録は ollama からコマンドを打つ方法と Open WebUI の画面を使う方法がありますが今回は Open WebUI を使ってみましょう

# ollama の起動と確認

ollama は Windowws が起動したら自動的に起動していますが念のため確認をしますね

ブラウザで http://localhost:11434 にアクセスします

[ Ollama is running ]
の文字が表示されたらOKです。


起動していない場合は接続エラーの画面になります。ollama を起動してみましょう。
ついでに ollama list で登録済みモデルが表示されます。

```
ollama
ollama serve
ollama list

NAME                 ID              SIZE      MODIFIED
qwen2.5:7b           845dbda0ea48    4.7 GB    2 days ago
```

# Open WebUI の起動と確認

Open WebUI を 起動します。

```
cd .venv
scripts/activate
open-webui serve --host 0.0.0.0 --port 8080

  ___                    __        __   _     _   _ ___
 / _ \ _ __   ___ _ __   \ \      / /__| |__ | | | |_ _|
| | | | '_ \ / _ \ '_ \   \ \ /\ / / _ \ '_ \| | | || |
| |_| | |_) |  __/ | | |   \ V  V /  __/ |_) | |_| || |
 \___/| .__/ \___|_| |_|    \_/\_/ \___|_.__/ \___/|___|
      |_|
INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
```

ブラウザで http://localhost:8080 にアクセスしてログインしましょう。

# Open WebUI へのモデルの追加

左下のアイコンから 「設定」-->「 管理者画面」 を表示させて、「モデル」を表示させると「Ollama.com からモデルをプル」という項目があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920228/d0e37983-62d9-bc9d-389e-8f51aab4517a.png)

ここにモデルタグを入力するとモデルがダウンロードされて open webui から使えるようになります。すぐに使えるモデルタグは ollama.com で検索して確認できます。

登録の終わったモデルは「モデルを選択」のところから確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920228/65abd7ae-6d9e-5a48-78db-0a783e356936.png)

# 複数のLLMを使ってみましょ

Open WebUI の左側メニューに「ワークスペース」というのがあるのでクリックして開くとモデルごとにプロンプトを入力して使えるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920228/a5727533-6e52-d7b5-c175-a65b5470cea4.png)

## Qwen 2.5 さんにあいさつしてみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920228/05145cf9-b2bd-a8eb-2f75-ee613a8d994c.png)

## granite 3 さんに高い山を聞いてみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920228/fbd47c49-c31a-772b-ec52-f3e2176d0e15.png)

英語の方が精度が高いようですね～

## Llama-3-ELYZA-JP-8B-q4 さんにあいさつしてみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920228/50fc1ac6-19f9-6e7b-c0b0-b066787363f5.png)

モデルの違いが分かって面白いですね。
それではみなさんも快適な　ローカルLLMライフをお楽しみください！
マネージド K8s ユーザーのためのコントロールプレーン入門

## はじめに

私はマネージド K8s (Azure AKS, Amazon EKS など)を何度か利用したことがあります。
kubectl コマンドの利用時に裏で何らか API が実行されていることは認識していましたが、その先で何が行われているかまで理解していませんでした。

Kubernetes をしっかりと理解するには、マネージド K8s であまり意識していないコントロールプレーンを理解する必要があると感じ、調べてみました。

## コントロールプレーンって何だっけ

下記に記載があります。

https://kubernetes.io/ja/docs/concepts/overview/components/

> コントロールプレーンコンポーネントは、クラスターに関する全体的な決定(スケジューリングなど)を行います。また、クラスターイベントの検出および応答を行います(たとえば、deployment の replicas フィールドが満たされていない場合に、新しい Pod を起動する等)。

クラスタを維持する上で重要な、クラスターの状態を管理・制御するコンポーネント群、ですね。
情報を整理して監視し、指示を出す、高性能な脳ミソ、というイメージをしました。
指示を出すまでで、実際に作業をするのはワーカーノード上のコンポーネントになります。

以降で、重要なコンポーネントをいくつか紹介できればと思います。

## kube-apiserver：全ての入り口

下記に記載があります。

https://kubernetes.io/ja/docs/concepts/overview/components/#kube-apiserver

> API サーバーは、Kubernetes API を外部に提供する Kubernetes コントロールプレーンのコンポーネントです。 API サーバーは Kubernetes コントロールプレーンのフロントエンドになります。
> Kubernetes API サーバーの主な実装は kube-apiserver です。

コントールプレーンには Kubernetes API を外部に提供するコンポーネントが必要であり、その実装として kube-apiserver がある、ということですね ?
kubectl コマンドの通信先も kube-apiserver となります。
`kubectl apply -f manifest.yaml` のようなコマンドが何をしているか、でいうと、後述の etcd に直接マニフェストファイルを追加するのではなく、この kube-apiserver を経由してマニフェストファイルの定義を適用しています。

## etcd：データを守る番人

下記に記載があります。

https://kubernetes.io/ja/docs/concepts/overview/components/#etcd

> 一貫性、高可用性を持ったキーバリューストアで、Kubernetes の全てのクラスター情報の保存場所として利用されています。

RDB ではなくキーバリューストアですね。
シンプルな記載ですが、「一貫性」「高可用性」「Kubernetes の全てのクラスター情報の保存場所」という思い言葉が並び、非常に重要で「落とせない」ことが伝わってきます。

## kube-scheduler：Pod の新居を決める

下記に記載があります。

https://kubernetes.io/ja/docs/concepts/overview/components/#kube-scheduler

> コントロールプレーン上で動作するコンポーネントで、新しく作られた Pod にノードが割り当てられているか監視し、割り当てられていなかった場合にその Pod を実行するノードを選択します。

Pod が動作する場所を手配してくれる存在です。
Pod リソースが「作成された」だけでは Pod の実体はなくて、「ノードが割り当て」られてそこで実体を作られて初めて動く、ということをイメージしました。

> スケジューリングの決定は、Pod あるいは Pod 群のリソース要求量、ハードウェア/ソフトウェア/ポリシーによる制約、アフィニティおよびアンチアフィニティの指定、データの局所性、ワークロード間の干渉、有効期限などを考慮して行われます。

様々な条件をもとに、どのノードに割り当てるかを決定するようです。

## まとめ

概要レベルですが、コントロールプレーンについて整理してみました。
コントロールプレーンは実務を負わないことが分かり、ワーカーノード上に K8s のコンポーネントが必要なことを認識できました。
マネージド K8s では見えにくい部分でしたが、理解することで以下のような気づきが得られました：

- クラスター操作のリクエストは必ず kube-apiserver を経由する
- クラスターの状態は etcd に保存されている
- Pod の配置は様々な条件を考慮して kube-scheduler が決定する

次回はワーカーノードについて調べてみたいと思います。
neo4j+GraphRAGで実行できるけどFailed to write data to connection...ってエラーが出る

# 概要
neo4jを使ってGraphRAGを実装している時のお話です。
チュートリアルに従って以下のようなコードを書くと思います。

``` python:index.py
graph = Neo4jGraph(
    url=neo4j_uri,
    username=neo4j_username,
    password=neo4j_password
)

vector_index = Neo4jVector.from_existing_graph(
    OpenAIEmbeddings(),
    search_type="hybrid",
    node_label="Document",
    text_node_properties=["text"],
    embedding_node_property="embedding"
)
llm = ChatOpenAI(temperature=0, model_name="gpt-4o-mini-2024-07-18")

# ~~~省略~~~

if __name__ == "__main__":
    question = "〇〇について教えて"
    answer = chain.invoke({"question": question})
    print(answer)

```

で、実行すると
```
Failed to write data to connection ResolvedIPv4Address(('12.345.67.890', 7687)) (ResolvedIPv4Address(('12.345.67.890', 7687)))
Failed to write data to connection IPv4Address(('aa111111.databases.neo4j.io', 7687)) (ResolvedIPv4Address(('12.345.67.890', 7687)))
Failed to write data to connection ResolvedIPv4Address(('12.345.67.890', 7687)) (ResolvedIPv4Address(('12.345.67.890', 7687)))
Failed to write data to connection IPv4Address(('aa111111.databases.neo4j.io', 7687)) (ResolvedIPv4Address(('12.345.67.890', 7687)))
```
こんなエラーが出てきます。なんか2*2匹いるし。なんだろう。
バージョンはneo4j=5.25.0、Python=3.13.0 です。

# 原因：コネクションが生き残っているせい
参考記事

https://stackoverflow.com/questions/58295558/failed-to-write-data-to-connection-adress-neo4j-python

曰く、Neo4jのドライバーがクローズされていないために発生しているっぽい。
でも
```
graph.driver.close()
graph.close()
```
こんなプロパティないんですよね。ふむ？

# 解決
以下のコードで解決しました。
```
if __name__ == "__main__":
    question = "〇〇について教えて"
    answer = chain.invoke({"question": question})
    print(answer)
    
    graph._driver.close()
    vector_index._driver.close()
```

これでFailed to write data to connection は出なくなりました。
**が**、なんか怪しいのでジピ先生に聞いてみました。

```
• _driver.close() は何か
_driver.close() は、クラス内部で使用されている Neo4jドライバーの接続を閉じるメソッドを呼び出すコードです。
_driver は プライベート属性であり、クラスの内部実装として扱われます。
このメソッドを呼び出すと、Neo4jデータベースとの接続が終了します。

• なぜ使わないほうがいいのか
プライベート属性への直接アクセスは非推奨です。
カプセル化の原則に反し、クラス設計者が意図したデータ保護や内部実装の隠蔽を破壊します。
将来的な変更に弱い: ライブラリの更新で内部実装が変わると、コードが動作しなくなるリスクがあります。
メンテナンス性の低下: 他の開発者がコードを理解しにくくなり、バグの原因となります。

• 代替案は何か
接続管理クラス（例: Neo4jConnectionManager）を作成する
接続のライフサイクルを明示的に管理し、プライベート属性に依存しない方法でドライバーをクローズします。
コンテキストマネージャを利用して、接続の開始と終了を自動的に管理できます。
```

ということらしいです。目下のエラーが気になって（そもそも動作自体にはもともと影響無し）対応したのですが、実際の実装の時にはもっと考慮した方が良さそうです。

あとneo4j公式のQAにこんな質問がありました。

https://community.neo4j.com/t/when-should-we-close-the-database-connection/6984

>You should definitely not close the connection after every query. Connections are relatively heavyweight objects that involve setup and network roundtrips to authenticate you. If you close the connection after every query, your experience will be that queries are a lot slower as your code does a lot of extra unnecessary work.
（毎回クエリごとに接続を切るのはやめたほうがいいよ。接続って結構重いオブジェクトで、設定とか認証のためにネットワークの往復が必要なんだ。だから毎回切ってたら、無駄な処理が増えてクエリが遅く感じるようになるよ。）

だから可能な限りコネクションは維持した方が良さそうですね。このあたりも実装においてはしっかり作るようにしたいと思います。

以上です。
miseで開発環境とタスクランナーを統一的に管理する

# miseとは

miseは、開発環境のバージョン管理とタスクランナーの機能を統合したモダンなツールです。asdfの後継として開発され、Rustで実装されているため高速な動作が特徴です。元々、RTXという名前でしたがmiseに変更されました。direnvやasdfを使ったことがあれば、高速な動作性能が気に入るはずです。

Home | mise-en-place https://mise.jdx.dev/

## miseの特徴とメリット

miseには以下のような特徴があり、開発環境の管理を効率化できます。

- 統合的な環境管理機能
  - Node.js、Python等の異なる言語を一元管理
  - 環境変数(.env)の管理
  - asdfとの互換性を維持
- 使いやすい設定システム
  - TOMLフォーマットによる読みやすい設定
  - 環境変数とツールのバージョンを同一ファイルで管理
- 強力なタスクランナー機能
  - 依存関係を持つタスクの定義が可能
  - シェルスクリプトとの連携が容易
- 高いパフォーマンス
  - Rustで実装されたネイティブバイナリ
  - asdf（シェル実装）と比べて低オーバーヘッドで高速

# インストール方法

```bash
# Homebrewでインストール
brew install mise

# または直接インストール
curl https://mise.run | sh

# シェルの設定（zshの場合）
echo 'eval "$(~/.local/bin/mise activate zsh)"' >> ~/.zshrc
```

## Node.jsのインストール方法

よく使用するコマンドの例を以下に示します。

```bash
# インストール可能なバージョンの一覧表示
mise ls-remote node

# インストール済みのバージョン一覧
mise ls node

# 最新のLTSバージョンをインストール
mise use node@lts

# 特定のバージョンをインストール
mise use node@20.14.0

# グローバルで使用する場合
mise use -g node@20.14.0

```

# 基本的な設定例

nodejsを使うだけならこれコピペで大丈夫です。僕はこれ以外にもJava, Rubyを管理しています。

```toml:.mise.toml
[env]
_.file = [".env"]        # プロジェクトの環境変数ファイルを読み込み
_.path = ['./node_modules/.bin']  # ローカルのnode_modulesにパスを通す

[tools]
node = '20'  # メジャーバージョンのみ指定（20.x.xの最新版を自動選択）
```

# タスク管理

僕はおまけ程度でしか使ってませんが、プロジェクトのクリーンナップ用のシェルが書きたくなったらmiseで書いたりします。
nodeの世界以外のタスクを管理するイメージです。docker操作、成果物の一括削除等
具体的な使用例として、React NativeのプロジェクトでRailsとJava, xcode, Androidの世界線で操作する必要がありmiseにまとめたりしてました。

## 設定ファイル

```toml
[env]
_.file = [".env"]
_.path = ['./node_modules/.bin']

[tools]
node = '20.11.0'

[tasks.clean]
run = '''
#!/usr/bin/env bash
rm -rf node_modules .next
yarn
'''

[tasks.format]
run = "yarn eslint"

[tasks."build:node"]
run = "yarn build"
depends = ["format"]

[tasks.ci]
depends = ["build:node", "build:docker"]
```

## タスク実行例

```bash
# クリーンアップ
mise run clean

# ビルド
mise run build:docker

# CI用のタスク実行
mise run ci
```
【2023年版】Rubyリポジトリのコミット動向、主要言語との比較

2023年のRubyリポジトリのコミット数を Author ごとの時系列グラフにしてみました。

## Rubyリポジトリのコミット動向

2023年のRubyリポジトリの総コミット数は6767回でした。この数は、主要なプログラミング言語の中だと Java より大きくて Kotlin より小さいです。

Author の合計人数は307名です。上位5名で合計3254コミット、全体の48%を占めています。

![ruby-commits-2023.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33011/f52550af-72db-5cc2-dfbf-54e35c5eb273.gif)

- 集計したリポジトリは [ruby/ruby - GitHub](https://github.com/ruby/ruby) の master ブランチです
- グラフデータには `git log -n 10000000 --date short --pretty=format:"%ad%x09%h%x09%an"` を使いました
- 2023年の総コミット数は `egrep '^2023' commits.txt | wc -l` で集計しました
- マージコミットや bot のコミットはそのまま含めています
- リポジトリによってはコミッターが複数のコミットを集約しています

## Rubyと他の主要言語との比較

Rubyを他の主要言語と比較してみます。2023年の主要なプログラミング言語のコミット数の時系列グラフはこちらです。

![all-commits-2023.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33011/50dba6f8-a58b-be1d-0719-92b73874edd8.gif)

| 言語名 | コミット数 | Author 数 | 平均コミット数 |
|:-:|:-:|:-:|:-:|
| Rust  |  28014 | 1103 |  25.3 |
| Swift  |  16181 | 224 |  72.2 |
| Kotlin  | 10363  |  191 | 54.2 |
| C,C++(GCC)  |  9870 |  383 | 25.7 |
|  Ruby | 6767  |  307 | 22.0 |
| Java(OpenJDK)  |  4729 |  380 | 12.4 |
| Python  | 4458  |  645 | 6.9 |
|  PHP | 3765  |  144 | 26.14 |
|  Go | 3685  | 322 | 11.4 |
|  JavaScript(Node.js) |  2687 | 360 | 7.4 |
|  Perl |  1776 | 87 | 20.4 |

#### コミット数の比較

- Ruby のコミット数は6767で、主要な言語の中で5番目に多い
- 最もコミット数が多いのは Rust（28014）であり、Ruby の4.1倍
- Ruby のコミット数は Python より1.5倍多いことから Ruby の方が活発に開発されている

#### Author数の比較

- Ruby の Author 数は307で、主要な言語の中で7番目に多い
- 最も Author 数が多いのは Rust（1103）であり、Ruby の3.6倍
- Ruby の Author 数は Python より0.47倍少ないことから Python の方がコミュニティの規模が大きい

#### 平均コミット数の比較

- Ruby の平均コミット数は22.0で、主要な言語の中で6番目に多い
- Swift（72.2）と Kotlin（54.2）が特に高い平均コミット数を誇り、それぞれ Ruby の2倍以上
- 平均コミット数は Python より3.1倍多いことから Ruby の方が少数精鋭の傾向が強い

#### 総合的な分析

- Ruby はどの数値においても中間的な位置にあり、Java や Python と同程度に活発な開発が行われている
- Swift と Kotlin はコミット数と平均コミット数が非常に多く、活発な開発が少数精鋭で行われている
- Ruby の開発はより集中的な貢献が特徴で、Python の開発は広範なコミュニティの貢献が特徴である
ターミナル上での 全角・ひらがな↔半角 変換コマンドを自作してみた！

# 👍️ いいねのお願い
励みになるので、いいねをお願いします。 

# ✍️ はじめに
こんな事よくありませんか？

![スクリーンショット 2024-10-30 11.08.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3907333/bbd6bd67-f615-f933-691d-be8ddc7eafc2.png)  
と入力したいのに  
![スクリーンショット 2024-10-30 11.09.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3907333/ca809199-9486-1a4d-75f5-efcf8f50c479.png)  
になってしまった！！

ここで、`Ctrl + X`を入力すると  
↓↓↓↓↓↓↓↓↓↓↓↓↓↓  
![スクリーンショット 2024-10-30 11.08.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3907333/bbd6bd67-f615-f933-691d-be8ddc7eafc2.png)  
↑↑↑↑↑↑↑↑↑↑↑↑↑↑  
**自動で変換**される！！！ ＼(^o^)／

ものを作成しました。

# 🚀 やり方

必要なツール:

**nkf (Network Kanji Filter)**  
- nkfは、全角文字を半角文字に変換するために使用されます。  
- これは日本語の文字エンコード変換ツールで、Zshから全角→半角の変換に活用されています。

インストールコマンド例:
```zsh
brew install nkf
```

以下を`.zshrc`へ書き、読み込ませれば動作します。

```zsh
# 全角文字を半角文字に変換する関数
function zsh_convert_to_halfwidth() {
    # 入力された全角文字を半角文字に変換する
    local input="$BUFFER"
    local converted=$(echo "$input" | nkf -Z)
    
    # 変換結果を表示
    BUFFER="$converted"
    
    # カーソル位置を末尾に移動
    CURSOR=$#BUFFER
    zle -R
}

# ひらがなを対応する半角英字に変換する関数
function zsh_convert_hiragana_to_english() {
    local input="$BUFFER"

    # ひらがな -> 半角英字の変換テーブル
    typeset -A hira_to_eng=(

        [しゃ]=sya [しゅ]=syu [しょ]=syo
        [ちゃ]=cha [ちゅ]=chu [ちょ]=cho
        [じゃ]=ja [じゅ]=ju [じょ]=jo

        [あ]=a [い]=i [う]=u [え]=e [お]=o
        [か]=ka [き]=ki [く]=ku [け]=ke [こ]=ko
        [が]=ga [ぎ]=gi [ぐ]=gu [げ]=ge [ご]=go
        [さ]=sa [し]=si [す]=su [せ]=se [そ]=so
        [ざ]=za [じ]=zi [ず]=zu [ぜ]=ze [ぞ]=zo
        [た]=ta [ち]=ti [つ]=tu [て]=te [と]=to
        [だ]=da [ぢ]=di [づ]=du [で]=de [ど]=do
        [な]=na [に]=ni [ぬ]=nu [ね]=ne [の]=no
        [は]=ha [ひ]=hi [ふ]=fu [へ]=he [ほ]=ho
        [ば]=ba [び]=bi [ぶ]=bu [べ]=be [ぼ]=bo
        [ぱ]=pa [ぴ]=pi [ぷ]=pu [ぺ]=pe [ぽ]=po
        [ま]=ma [み]=mi [む]=mu [め]=me [も]=mo
        [や]=ya [ゆ]=yu [よ]=yo
        [ら]=ra [り]=ri [る]=ru [れ]=re [ろ]=ro
        [わ]=wa [を]=wo [ん]=n

    )

    # ひらがなを英字に変換
    local converted="$input"

    # 複数文字の変換を優先
    for key in ${(k)hira_to_eng}; do
        # 入力文字列に変換対象が含まれていれば置換
        converted=${converted//$key/${hira_to_eng[$key]}}
    done

    # 変換結果を表示
    BUFFER="$converted"
    CURSOR=$#BUFFER
    zle -R
}

# 全角スペースを半角スペースに変換する関数
function zsh_convert_fullwidth_space_to_halfwidth() {
    local input="$BUFFER"

    # 全角スペースを半角スペースに変換
    local converted="${input//　/ }"  # 全角スペースは「　」、半角スペースは「 」

    # 変換結果を表示
    BUFFER="$converted"

    # カーソル位置を末尾に移動
    CURSOR=$#BUFFER
    zle -R
}

# 各変換関数をまとめて呼び出すための関数
function zsh_convert_all() {
    zsh_convert_to_halfwidth
    zsh_convert_hiragana_to_english
    zsh_convert_fullwidth_space_to_halfwidth
}
zle -N zsh_convert_all

# ctrl + x にキーバインド
bindkey '^X' zsh_convert_all
```

:::note warn
ひらがな -> 半角英字の変換テーブル`hira_to_eng`は編集することをおすすめします。(入力の癖があると思うので。。)
:::


# 📝 まとめ
これを使うと、`全角・ひらがな↔半角変換`を一度に行い、入力をスマートに整えます！  
ぜひ使ってみてください！👋