OmniAICreator/Qiita-1.07M huggingface dataset:
<number>←これなんぞ？ の解説（ジェネリクス型について）

## この記事は何？

本記事は、動的型付け言語メインで開発してきた筆者が、長年「何だこれ」と思いつつ放置してきたTypeScriptの呪文のような記述について理解したので、その気づきを初心者向けに共有するものです。

``` TypeScript:呪文に見える記述の例
const firstNumber = getFirstElement<number>([1, 2, 3]);
```

<details>
<summary>※このコードを初めて見た時の筆者の感想</summary>

「この`<number>`がホントになぞ。

引数でもないし変数でもない。関数の処理にも使われてない。

でもあちこちに出てくるから何かを意味してはいるみたい。意味わからん。」

</details>

## 結論

`<number>`は**ジェネリクス型**と呼ばれるものです。
（厳密にいうとジェネリクス型を継承した型となります。）

ジェネリクス型とは **使うタイミングで自由に型を決められる、仮置きの型** のことです。

専門用語だと**抽象化のために使う型**になります。


## 解説

初心者だと何を言ってるかわからないと思いますが、`<number>`のような書き方は、
**定義部分ではJavaScript（動的型付言語）っぽく型なしで書いておいて、使う時だけTypeScript（静的型付言語）の恩恵を受ける、良いとこ取りの書き方**
となります。

以下で使用例を使って説明します。

#### 使用例を見ながらの説明

```TypeScript:使用例
function getFirstElement<T>(arr: T[]): T {
  return arr[0];
}

const firstNumber = getFirstElement<number>([1, 2, 3]);
console.log(firstNumber); // 1

const firstString = getFirstElement<string>(["a", "b", "c"]);
console.log(firstString); // "a"
```

まず最初に「いきなり出てくるTってなんだよ」と思うかと思います。

このTは本記事の主役のジェネリクス型と呼ばれる型となります。

TとはTypeの頭文字で、「なんでもいいんだけど皆そうしてるから」という理由でTという文字を使うそうです。（極論`AAA`とかでもいいものです）

そしてTとは、使われる時にどんな型でも入れていいよという書き方です。

「なんで意味をなさない型を定義した？意味ないじゃん、引数の型違うんだからanyでいいじゃん！」と思うかもしれません。

その通りです。JavaScript的な使い方になりますがそれでちゃんと動きます。

でも落ち着いてください。

anyの場合関数を使う時に引数の型を固定しなくてよくなるため、1（数字）と"1"（文字）を入れ間違っても気づくことができず、静的型付け言語の良さを使うことができなくなります。

そこで、**何かしらの型は絶対いるけど後から好きな型を使えるようにした便利機能**がこのT（ジェネリクス型）となっています。

そしてこの機能を使うと**柔軟に静的型付言語を操ることができる**ようになるため、ソースコードの可読性を犠牲にしてまで利用されているような代物となっています。

```TypeScript:ジェネリクス型とanyを比較

// === ジェネリクスの書き方 === 
function getFirstElement<T>(arr: T[]): T {
  return arr[0];
}
const resultGeneric = getFirstElement<string>(["1", "2", "3"]);
console.log(resultGeneric);  // "1"

// === anyの書き方 === 
function getFirstElementAny(arr: any[]): any {
  return arr[0];
}
const resultAny = getFirstElementAny([1, "2", true]);
console.log(resultAny);   // 1 

// ↑上記のようにanyだと配列の中がガチャガチャでもエラーが出ずに使えるため、
// 本当は文字列の"1"が欲しい時に数字の1が意図せず渡されてしまう恐れがあります。
// 動的型付け言語だと特に複雑なロジックではこのような部分を見落として本番でのエラーが起きやすいのですが、それを防ぎやすくなっています。
```

<details>
<summary>※寄り道の補足（本筋から外れるので興味がある方だけご覧ください）</summary>

`getFirstElement<number>([1, 2, 3]);`の`number`はどこから出てきた？と初心者の時の筆者なら思ってるかもしれないので書いておきます。

numberやstringは、言語に最初から組み込まれている基本的な型です。TypeScriptを導入したときにダウンロードされる型定義ファイル（通常は目に見えない場所に保存されているファイル）により、これらが利用できます。

もし手作りの型を指定したければ以下のようにして使うことができます

```TypeScript:手作りの型を使う例
function getFirstElement<T>(arr: T[]): T {
  return arr[0];
}

type testType = string|number; // 手作りの型を定義
const firstNumber = getFirstElement<testType>([1, "2", 3]); // 手作りの型を使用
console.log(firstNumber); // 1 （エラーが出ずに出力される）
```
</details>

## まとめ

- `<number>`はジェネリクス型（を継承した型）
- ジェネリクス型は何かしら型を使うことは強制するけど、使う型は呼び出しの場面で決められる仕組み
- anyに似てるけど、コンパイルエラーをしっかり活用できるのがジェネリクス型
- ジェネリクス型は処理を共通化した時に多様化する引数の型定義の悩みを解消する仕組み

以上が`<number>`およびジェネリクス型の正体です。

これを理解できればソースコードが読みやすくなると思います。
さらに使いこなすことができれば、より保守性の高いコードを実装できるようになると思います。
今更だけどgo workを初めて使ってみた

この記事はApplibot Advent Calendar 2024 の12日目の記事です。前回の記事は[こちら](https://qiita.com/jaramon/items/153d9bd8fa789b9e5fd4)です。

# はじめに
最近初めてgo workを使ったので、go workの使いどころを紹介したいと思います。
go workの存在自体は知っていましたが、実際に使ったことがなかったので備忘録としても残しておきます。
改めて調べてみたらgo workってgo1.18から追加されたんですね。2022年3月くらい？

https://tip.golang.org/doc/go1.18#go-work

月日が立つのは早すぎて怖いですね。

# 結論
結論から書くのが好きなので、結論から書きます！
go workは複数のGoモジュールを一つのワークスペースとして効率的に管理するためのツールで、複数モジュールの依存関係を簡単に扱え、開発がスムーズになるものです！
というのが結論なのですが、まぁこれだけだとなんのことだか分からないと思うので実際に試してみました。

# 実際に試してみる
色々とテキストで書くよりも、実際にコードをみながら自分で体験するのが一番ということで実際にコードを書いてみます。

以下のようなディレクトリ構造を用意します。
```
my-go-workspace/
|-- moduleA/
|-- moduleB/
```

moduleBフォルダ内に以下の内容でGoモジュールを作成します
```shell
cd my-go-workspace/moduleB

# Goモジュールの初期化
go mod init moduleB

# ファイル作成
touch b.go
```

b.goの中身はこんな感じにしておきます。
```golang:b.go
package moduleB

func HelloB() string {
    return "Hello from Module B"
}
```

次に、moduleAフォルダ内に以下の内容でGoモジュールを作成します：
```shell
# moduleAフォルダに移動
cd ../moduleA

# Goモジュールの初期化
go mod init moduleA

# moduleA内のコード
touch main.go
```

main.goはこのような中身にしておきます。
```golang:main.go
package main

import (
    "fmt"
    "example.com/moduleB"
)

func main() {
    fmt.Println(moduleB.HelloB())
}
```

ここまでで準備は完了です。
この段階でmoduleA/main.goを確認するとimportでエラーが起きると思います。
それもそのはずで、moduleBは現在ローカルにしか存在せずgo getすることもできないからです。
そこでgo workの出番です。

```shell
# ルートディレクトリにいる状態で下記コマンド実行
go work init moduleA moduleB
```

すると、下記のファイルが作成されると思います。
```golang:go.work
go 1.23.2

use (
	./moduleA
	./moduleB
)

```

この時点で、先程でていたimportエラーは消えているはずでgo runしても成功すると思います。
```shell
go run ./moduleA
```

どういうことかというと、go.workファイルで指定されているモジュールに限ってローカルモジュールを参照しにいくということです。
この機能を利用すれば、公開はしていないけど先んじてローカルでだけ行った修正を実際に動かすことができるので素早い開発ができます。
go workがない場合は、まずモジュールを修正して、そしてそれを公開して実際に組み込んで初めて動作確認ができると思います。だいぶ手間ですね。
というわけで簡単にgo workの挙動は試せました！
ここからはgo workが登場する前と後でどのようなことが変わったのか調べたのでまとめてみました。

# go workが登場する前
## 複数モジュールの開発
複数のモジュールを同時に編集・ビルド・テストする場合、従来のGoモジュールシステムでは煩雑な手作業が要求されることもありました。
例えば、あるモジュールAが別のモジュールBに依存している場合、モジュールBに変更を加えた上でモジュールAをテストするのが難しい状況が発生していました。

## ローカルの依存関係管理
あるモジュールが他のローカルに存在する未公開のモジュールに依存している場合、その依存関係をうまく管理するのが困難でした。
ネットワークを通じて公開されていないローカルのモジュールを利用して開発を進めたいケースに適したツールが求められていました。

# go workが登場する後
## go workの導入
上記の課題を解決するために、go work 機能は導入されました。
go workは、複数のモジュールを一つのワークスペースとして管理する新しい方法を提供し、よりスムーズな開発体験を実現するための機能です。

## 複数モジュールの一括管理
複数のモジュールを一つのワークスペースで管理することができ、各モジュールの依存関係やバージョンを一元管理できます。

## ローカルモジュールの利用
未公開のローカルモジュールも簡単にワークスペースに組み込み、依存関係として扱うことができます。これにより素早いサイクルでの開発とテストが可能になります。

# まとめ
最後にもう一回まとめとして書きますが、go work便利なのでモノレポで複数モジュール開発を行う場合は積極的に使っていきましょう！
Azure Open AI の冗長化 (API利用)

:::note info
この記事は個人で検証した内容です。
Microsoft社の公式見解ではありません。
自身の判断で参照いただけますと幸いです。
:::

:::note info
2024年12月18日時点の状況に基づいた内容です
:::

## はじめに
この記事は[弥生 Advent Calendar 2024](https://qiita.com/advent-calendar/2024/yayoi) の12月18日の記事です。

弥生株式会社の不破です。コーポレートプラットフォーム部のインフラセキュリティとバックオフィス基盤のテクニカルリーダー (兼務) として弥生のシステム基盤を支えるプロジェクトであったり、新しい仕組みの導入推進をリードしています。

この記事では「Azure Open AI のクォータ制限を回避する方法」を考えるヒントになるような内容を記載したいと思います。

## 冗長化の目的
今更感ですが、冗長化の目的を簡単におさらいします。

* システム障害対策 (冗長化は可用性の手段の一つ)
    * 例) A系に障害が生じた際にB系で動作し続ける
* 災害対策
    * 例) 地理的分散してリスクを低減する
* 負荷対策
    * 例) A系だけでは処理しきれないのでB系で負荷を分散して並列処理する
* 損害の最小化
    * 例) 復旧までの時間最小化する
    * 例) データ保全する

このあたりの目的がありますが、今回のテーマは「Azure Open AI」なのでさらに目的が加わります。
* **クォーター制限の回避**

## Azure Open AI のクォーター制限
Azure Open AI にはリージョン単位でモデルをデプロイできるクォーターの制限があります。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/quotas-limits

このクォーター制限を回避する方法として考えられる例は、次の通りです。

1. クォーターの上限緩和申請をする
1. アプリ側でウェイト処理やリトライ処理を実装する
1. 別のリージョンを利用する

### 1. クォーターの上限緩和申請をする
一番スマートな方法ですが、ハードルが2つあります。

申請は専用フォームから理由や根拠などの各項目を埋めて提出するだけです。
ただし宛先が Microsoft社本国の専門チームであるため、英語での記載が必要です。
これが1つ目のハードルになります。

次に、1つ目のハードルを正当な理由や根拠でクリアしたとしても2つ目のハードルがあります。
リージョン単位での上限緩和を受け付けていない場合があります。
US系など人気が高いリージョンや規模が大きくないリージョンが対象になることがあります。
これが2つめのハードルになります。

### 2. アプリ側でウェイト処理やリトライ処理を実装する
これはアプリ側で制限して妥協しましょうという例です。

### 3. 別のリージョンを利用する
この記事のメインです。
上で `リージョン単位でモデルをデプロイできるクォーターの制限があります` と記載しましたが、上限緩和やアプリ側で回避できない or したくない場合に選択します。
ただし、単体でリージョンごとにモデルをデプロイしてもアプリ側で振り分け実装することは非現実的です。
そこで利用するのが冗長化の仕組みです。

## Azure の冗長化サービス
Azure には主に冗長化できるサービスが次の通りあります。

1. DNS
1. Front Door
1. Load Balancer (NLB)
1. Application Gateway (ALB)
1. Traffic Manager
1. API Management

## Azure Open AI のクォーター制限を回避する構成
:::note warn
今回記載する構成は一例です。
今回のテーマは Azure Open AI のクォーター制限を回避することなので API Management の細かい内容は省きます。
:::
### 構成イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618452/51e7f7d4-3d13-b4bb-b3d6-8f2b3ba6cb97.png)

### 構成の説明
まず Azure Open AI を冗長化する方法として Azure API Management を採用しています。
理由は、
1. Open AI API を利用する際に Key を送信する必要があるため平文で送るサービスは NG である
1. Open AI API Key はリージョン (リソース) ごとに異なるが API Management が認証を統一してくれる
1. ユーザーごとにリクエスト制限ができる

バックエンドの Azure Open AI のモデルは複数リージョン用意しています。
こうすることで、1リージョンあたりのクォーター上限に達していてもリージョンを束にすることで全体の総量をあげるという手法です。

## おまけ
API Management の GenAI ゲートウェイ機能など新しい機能が次々と出てきています。
AI 関係のサービスは Open AI を含めて日進月歩で変わっています。
AI で DX 進めている感を出してもバックエンドは世代前なんてことも。
アンテナを広く張って常に最新の技術についていく必要がありますね。便利な反面、ある意味エンジニア泣かせな気もしますね・・・

## まとめ
今回のテーマはここまでです。
少しでもみなさまのヒントになれば幸いです。
最後までご覧いただきありがとうございました。

---
納期がほとんどない？社内SEの仕事とは

# はじめに
なかなか知られていない、社内SEという仕事に興味がある人に向けてまとめていきます。


# 社内SEの仕事
## 業務範囲
システムの設計・開発だけでなく、要件定義やユーザー対応、インフラ管理まで仕事の範囲です。また、PCトラブル対応、IT資産管理などを行うこともあり、社内の便利屋さんとして柔軟に働くことが求められます。
開発するシステムも会社の業務改善や効率化を目指すものが多く、「急いでリリースすること」よりも、「質の高いシステムを作ること」が重視されがちです。

## ユーザーとの距離感
システムユーザーが同じ会社の社員であることもあり、利用者と距離が近く、要望や苦情を直接受けることもあります。ユーザーの立場が分かりやすいことから、使いやすいシステムを作成することが求められます。

## 評価基準
技術力よりも業務理解を求められることが多く、業務の効率化や問題解決につながるかどうかが評価の鍵になります。

## 技術
業務フローに適した技術選定を行うため、最新の技術よりも「確実性」や「使いやすさ」を求められます。

## キャリア
長期間同じ会社で働くことが前提な、安定志向の人が多いです。業務ではレガシー寄りな技術を使いがちなので、技術トレンドに追いつくことが難しい場合もあります。実際、副業や転職をしようとしても、募集要項と技術マッチしにくいこともあります。(実際、著者は今苦しんでいます)

# 「納期がほとんどない」とは
ユーザーが同じ会社の社員であることから、社内の事情を理解してもらいやすく、納期があまりありません。最終的にユーザーの意図に沿ったものが完成すればよいので、納期に関しては融通がききやすいです。ただユーザーとの距離が近い故に、要望があがりやすく、プロジェクトが長期化しがちです。

# 納期がない中で効率よく進めるコツ
複数のプロジェクトを長期的に管理することになり、効率的に仕事を進めることが重要になります。

## 優先順位を明らかにする
トラブル対応や緊急性の高いタスクが多い社内SEだからこそ、タスクの優先順位を定めます。
特に機器トラブルはユーザーが仕事をできなくなる場合もあるため、緊急性の大小判断より前に実際に現場へ行って確認することも多いです。
緊急性の高いタスクがない場合、業務上重要なタスクを行います。特に経営判断に関わる仕事は機密性も高く、まとまった時間を確保できる時に集中的に取り組みます。
空いた時間で要望や改善に取り組み、便利な機能提案の資料作成や開発を行います。

## マイルストーンを設定する
プロジェクトが長期間に渡るため、同僚同士でも進捗が分かりにくくなりがちです。
なので、大まかな目標と期日を決めて共有し、進捗報告することでプロジェクトの遅延を防ぎます。

## 定期的に進捗報告する
関係者に進捗状況を報告することで、他部署の不安を解消し、プロジェクトの透明性を確保します。定例会議やメールで進捗を共有する仕組みにするのもいいでしょう。

# 終わりに
「納期がない」という特徴は、社内事情を反映した柔軟な対応が可能になる一方で、プロジェクトが長引いたり、モチベーションが低下したりすることもあります。一方、「納期がない」という自由さを活かし、目標設定やタスク管理を工夫することで、効率的に成果を上げていくこともできるでしょう！
python: pip-compile で python setup.py egg_info did not run successfully って出たら、library 名を疑え

# 背景

<code>pip-compile</code> をしようとしたら件名のエラーが出た。ほんとはもっと長文ですが・・

その際の対処法の記録

```powershell: pip-compile error
> pip-compile
    error: subprocess-exited-with-error

    × python setup.py egg_info did not run successfully.
    │ exit code: 1
    ╰─> [67 lines of output]
 (...省略)
  ```

  # 結論

- <code>requirements.in</code> に記述追加した python library 名が間違っていた

具体的には、以下の間違えだった
恐らくだけど、古い？もしくは未対応ライブラリで対処出来なかったのかな？と詳細は未確定ですが :sweat: 

```python: requirements.in
dotenv
```

https://pypi.org/project/dotenv/

本当は、<code>python-dotenv</code> とすべきだった・・

```python: requirements.in
python-dotenv
```

https://pypi.org/project/python-dotenv/

## 言い訳

library の説明に以下とあったので、そのまま <code>requirements.in</code> に追加したことが失敗の元だった。

まぁ、よくあることだけど
- library 名と、import 名が違う

ってやつでした :sob: 

```python
from dotenv import load_dotenv

load_dotenv()  # take environment variables from .env.

# Code of your application, which uses environment variables (e.g. from `os.environ` or
# `os.getenv`) as if they came from the actual environment.

```

# 試した内容

```powershell: tried commands
pip install --upgrade setuptools
pip install --upgrade pip-tools
pip install --upgrade pip
pip-compile --dry-run --verbose
```

まぁ、最後のは詳細見たかったんだけど、何も変わらず

以下も後から見つけたけど、答えは無し。

https://stackoverflow.com/questions/64095094/command-python-setup-py-egg-info-failed-with-error-code-1-in-tmp

# あとがき

いつものやつですね

- 面倒くさがらず、Documents を確認しましょう :laughing:
ノリで始めた地方の技術コミュニティ(Okarev)について

:::note info
こちらは[脆弱エンジニアの Advent Calendar 2024](https://qiita.com/advent-calendar/2024/full-weak-engineer)の11日目の記事です。
:::

# はじめに
どうも[su-i-san](https://x.com/u_i_san)です。
CODE BLUEのアフターパーティーでもお会いした[脆弱さん](https://x.com/asusn_online)にこのアドカレに誘っていただきました。
なにか脆弱な事柄について書こうかなと思っていたのですが、良さそうな話題がなかったので、今回は私が関わっているコミュニティを紹介できたらなと思います。

# この記事の内容は？

岡山県出身/在学のコンピューター好きが集まり勢いで発足した[Okayama-Revengers(Okarev)](https://okayama-revengers.connpass.com/)というコミュニティが１周年を迎えられた過程とその他諸々お気持ちの記事です。

# 当コミュニティについて

[Okayama Revengers](https://okayama-revengers.connpass.com/) は、2023年に岡山県出身/在学のコンピューター好きが集まり勢いで発足した技術コミュニティです。Discord サーバーでの会話とイベント運営を中心として活動しています。

当コミュニティは "Boot Up, Geek Out, Share Together" をテーマとして、主にITにまつわる知見や楽しさを、学生・社会人・初心者・上級者など立場によらず交換しあうことを趣旨としています。岡山県に新たに集う場所を作り出したいという思いが名前の "Okayama" に込められています。

# これまでのLT大会について

- 第１回目(2023.10.15)

https://x.com/okarev_staff/status/1709892602177392851

```
第1回 LT大会「もう涼しくなってきたけ〜LT大会でもするかぁ！」
~集え！コンピューターの先駆者たち~
```

URL : https://okayama-revengers.connpass.com/event/295260/

https://x.com/okarev_staff/status/1713519924700950650

---

- 第２回目(2024.4.27)

https://x.com/okarev_staff/status/1770261550064144828

```
第2回 LT大会「もう春じゃなぁ〜 LT大会でもするかぁ！」
~集え！コンピューターの先駆者たち~
```

URL : https://okayama-revengers.connpass.com/event/312845/

https://x.com/okarev_staff/status/1784384036225581382

---

- 第３回目(2024.10.06)

https://x.com/okarev_staff/status/1819198936806314437

```
第3回 LT大会「もう秋じゃなぁ〜 LT大会でもするかぁ！」
~集え！コンピューターの先駆者たち~
```

URL : https://okayama-revengers.connpass.com/event/317725/

https://x.com/okarev_staff/status/1843194275233947914

無事、１周年を迎えられました！

---

:::note warn
第４回目は春頃の開催を予定しておりますので、皆様是非ご参加ください‼
:::

# 大学生が考える地方の問題点

情報系においてですが、学生が自由に参加できるようなコミュニティなどが少なすぎる。またはコミュニティは存在しているが、どんな活動をしているのかがわかるような情報が公開されていない。

といったような問題があると考えています。

情報系の学生が自由に参加できるコミュニティが少なかったり、活動内容が明確に公開されていないことによって、以下のような格差が生じる可能性があります。

#### 1. 学びの機会の格差
> 情報系の分野では、教室での学びだけでなく、コミュニティでの交流や活動を通じた実践的な知識の習得が重要だと考えています。コミュニティに参加できない学生は、そのような学びの機会を失う可能性があります。

#### 2. ネットワーク形成の格差
> 情報系では、業界のトレンドや技術的な知見を共有するために、人とのネットワークが不可欠です。コミュニティに参加できないことで、将来的なキャリア形成に影響を及ぼす可能性があります。

#### 3. モチベーションの格差
> 同じ興味を持つ人々と交流することで学びのモチベーションが高まる一方、その機会がない学生は孤立感を感じる可能性があります。結果として、学業や研究への意欲が低下する場合もあります。

#### 4. 情報の非対称性
> コミュニティが非公開で活動している場合や情報発信が十分でない場合、特定の学生だけが最新の技術や研究情報にアクセスでき、他の学生との間に知識の格差が広がることになります。


# その問題を改善する方法

**世代間を超えた**楽しいイベントをつくる、それに尽きるのではないかと思います。

「世代間を超えた」というところが大事だと思っています。
これは社会人になって働いてる現役世代、これから社会人になる大学生、またこれから大学生になる中高生が参加するようなイベントにする必要があります。

https://x.com/okarev_staff/status/1713461674731303075

> 実際のLT大会での休憩時間の様子です。

このようなイベントを一人で作るということは、難しいと思います。
**同じ思いを持った**出会った方々と一緒に作っていくのが良いのかなと考えています。

# 最後に

私はこのギークなコミュニティを今後3年5年10年続いて、学生を巻き込めるものにするには継続的な入れ替わりが必要不可欠だと思います。

情報系の部活動やそういった活動をしている団体などと協力ないしは共催でイベントを盛り上げられたらなと思います。

最初はほんとにのりに近いレベルで始めたこのコミュニティですが、毎回楽しんでくれている方々の笑顔を見て、開催できてよかったなと思っています。

### ぜひ観光がてらに岡山でLTしてみませんか。

---

 #### 余談
 高校生のときくらいに、地元（岡山）にそういったイベントがあればなと感じていました。
いつかはこのokarevのようなイベントを作りたいと思っていたときにちょうど**同じ思いを持った**メンバーに巡り会えました。

ほんと、タイミングが良かったなと思います。
VS Codeのニッチなショートカット集 (macOS)

この記事は、[Unipos Advent Calendar 2024](https://qiita.com/advent-calendar/2024/unipos) の2日目の記事です。

# VS Code ニッチなショートカットまとめ

この1年間ぐらいで探ってみた知ってると便利なVS Codeのショートカットを集めてみました。なおかつ、主観でニッチなものを集めてみました。
基本 Mac のショートカットで書きます。Windowsの方はごめんなさい :bow: 

## `⌘ + shift + f` からの `⌘ + ↓` または、`⌘ + ↑`

検索後のフィルターや結果に素早く移動できます。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/5587b4ee-be42-77e2-504d-ab4cd48d2549.gif">


## `⌘ + shift + f` からの `F4` または、`shift + F4`

検索後の結果にすぐにアクセスしながらEditorで開いた状態にもなります。また、`F4` または、`shift + F4`を何度も入力することで次や前の結果にすぐに移動できます。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/7ea35f1c-e17e-e800-56da-07750fe735da.gif">


## `⌘ + shift + .`

素早くある程度の塊でファイル内のコード間の移動ができます。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/faedd609-a434-805a-fa5d-db598c48e41b.gif">


## `⌘ + shift + .` からの `←`

パンくずを辿って他のファイルへアクセスできます。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/f284b1f6-628b-ea99-b8cd-0bec9c1b2227.gif">



## `⌘ + shift + e` からの `⌘ + P` からの `File: New ~~`

特定のフォルダーの場所に素早くフォルダやファイルを作成できます。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/d5216775-9a7f-dec8-9d77-2e79e6413250.gif">

## `⌘ + shift + e` からの `↓ または ↑` からの `⌘ + ↓`

ファイルツリーを移動して、Editorで選択中のファイルを開くことができます。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/509e0e3f-ab6c-b367-5340-f74074e1bd3c.gif">

## `⌘ + shift + e` からの `⌘ + alt + f` 

ファイルツリー内での絞り込みができます。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/a01a0025-4fd6-86b9-4ca9-b8b9bb767586.gif">


## `⌘ + k` からの `w`

開いているファイルのタブ一覧を特定のEditorから削除します。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/edaede5a-d449-c216-7445-b04bc653d563.gif">

## `⌘ + Control + →` または `⌘ + Control + ←`

分割されたEditor間をファイルのタブが移動します。

<img width="512px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103667/073651cc-806e-e2fb-69e1-ad330e1deaff.gif">

## 最後に

結構知らないショートカットが今年1年で多く見つかりました。こういうものを知ってると効率が上がるので、これからも探っていきたいです。

## 備考

- 利用させてもらったコード: https://github.com/microsoft/vscode
Pythonのモジュールインポートエラー

## 背景
いつものようにVSCodeでPythonを動作させようとしていたときのこと...
``` python
インポート "pandas" をソースから解決できませんでした
(module) pandas
```
あれ？と思ってとりあえず動作させようとすると...
``` python
例外が発生しました: ModuleNotFoundError
No module named 'pandas'
  File "C:\Users\Ishik\OneDrive\デスクトップ\neat_project\read_check_point_multi.py", line 5, in <module>
    import pandas as pd
ModuleNotFoundError: No module named 'pandas'
```
モジュールのエラーが発生. なお, numpyの方はインポートできていた. 

ターミナルでpip freezeで確認してみると, 
```python
$ pip freeze
...
pandas==2.2.2
...
```
どうやら存在してはいるみたい. 

## 行ったこと
- Pylanceのリロード
VSCodeのPylance拡張がモジュールを認識しない場合があるらしい. そのため, リロードしてみた. 
  1.  VSCodeで```Ctrl+Shift+P```を押下し, コマンドパレットを表示
  1.  ```Reload Window``` を選択し, リロード. 
  - 結果
    --> 特に変化なし. 
- pandasの再インストール
  - 結果
    --> 特に変化なし. 
- VSCodeでのPythonのパス変更
  VSCodeでPythonのパスを確認してみると, 
  ```C:\Program Files\Inkscape\bin\python.exe``` を示していた. 
  そういえば, 確かにInkscapeをインストールしたけど, 勝手に変えられてたみたい... 
  なので, 前まで使用していたPythonのパスに変更
  - 結果
    --> 問題解決
kaggle time series tutorial 最終part

https://www.kaggle.com/code/ryanholbrook/forecasting-with-machine-learning


は、今までに作ったdataを利用し、４つの戦略で予測を行っています。

直訳となり申し訳ないですが、以下の通りです

- マルチアウトプットモデル
自然に複数の出力を生成するモデルを使用します。線形回帰やニューラルネットワークはどちらも複数の出力を生成できます。この戦略はシンプルで効率的ですが、使用したいすべてのアルゴリズムに適用できるわけではありません。例えば、XGBoostはこれを行うことができません。


- 直接戦略
期間の各ステップごとに別々のモデルをトレーニングします：1ステップ先を予測するモデル、2ステップ先を予測するモデルなど。1ステップ先の予測は2ステップ先の予測とは異なる問題であるため、各ステップごとに異なるモデルを使用することが役立ちます。欠点は、多くのモデルをトレーニングすることが計算的に高価であることです。


- 再帰戦略
単一の1ステップモデルをトレーニングし、その予測を次のステップのラグ特徴量として使用します。再帰的な方法では、モデルの1ステップ予測をそのモデルにフィードバックして次の予測ステップのラグ特徴量として使用します。1つのモデルだけをトレーニングする必要がありますが、エラーがステップごとに伝播するため、長期間の予測は不正確になる可能性があります。


- DirRec戦略
直接戦略と再帰戦略の組み合わせ：各ステップごとにモデルをトレーニングし、前のステップの予測を新しいラグ特徴量として使用します。ステップごとに、各モデルは追加のラグ入力を取得します。各モデルが常に最新のラグ特徴量セットを持っているため、DirRec戦略は直接戦略よりも連続依存性を捉えることができますが、再帰戦略のようにエラー伝播の影響を受ける可能性もあります。


となります。多くの方法があり、データの種類によってどれを選ぶべきかは変わると思います。はじめに試すおすすめは再帰戦略です。長期間になれば予測に誤差が増えていき、心許ないですが他の方法でも結局長期予測は難しいこと、モデルが１つなので改善サイクルが行いやすいことが理由となります。
このあと全てのモデルについてcodeがありますが、特に難しい関数を使用しておらず、見たらすぐに理解できるものではないかと思います。
hexapdfを使ってPDFのプロパティを編集する

## 環境

Ruby3.3
Windows10

## はじめに

win32oleを使ってExcelファイルをPDFに出力したところ、PDFファイルを開くとプロパティの値がおかしくなっていました。PDFファイルのプロパティ値を正しく修正するためのトラブルシュート記事です。

そもそも、PDFファイルのプロパティ値は出力元のExcelファイルのメタデータがそのまま引用されます。PDFファイルを作成する直前にExcelファイルのメタデータを強制的にいじる方法もありますが、PDFファイルを作成した後に、PDFファイルを編集することもできます。

Excelファイルからメタデータを拾う場合はwin32oleで対応できますが、PDFファイルを編集する場合は、別途PDF系のgemを使う必要があります。

## 内容

win32oleを使ってExcelファイルから出力したPDFファイルのプロパティ値を表示するとこのようになっていました。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/060911f3-10d1-6c50-9ee7-965768943000.png)

タイトルに出力元のExcelファイル名が表示されています。しかも、日本語部分が文字化けしています。更に作成者が0となっており、折角なのでこちらも編集しておきます。

PDFファイルを編集するgemにhexapdfを使いました。
https://rubygems.org/gems/hexapdf

作成したコードはこちらです。
単純にPDFファイルをオープンして、任意の内容に編集してライトをするだけです。

```changepdf.rb
def changepdf(file)

    require 'hexapdf'

    path = "D:\\hoge\\#{file}.pdf"

    doc = HexaPDF::Document.open(path)
    doc.trailer[:Info][:Title] = "#{file}"
    doc.trailer[:Info][:Author] = "テストユーザー"
    doc.write(path, optimize: true)
end

changepdf("請求書")
```

編集後のプロパティ値です。このようにタイトルにはPDFのファイル名、作成者は任意の名前で編集することができました。

![無題1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/a40f9d4e-cc04-b4b6-7c09-15bf70bf1e3f.png)
pyenvでpythonのバージョン変更が出来ない時

# 問題
```shell:sh
$ python global 3.10.0
```
でpythonのバージョン変更を試みたが出来なかった。
# 解決策
PowerShellのプロファイルファイルを開き、環境変数を設定。
1. Powershellのプロファイルを開く
```shell:sh
code $PROFILE
```
以下の環境変数を設定
```shell:sh
$ env:PYENV = "$HOME\.pyenv\pyenv-win"
$ env:PATH = "$env:PYENV\bin;$env:PYENV\shims;$env:PATH"
```
上記のコードは、Windows PowerShell で pyenv を動作させるための環境変数を設定するもの。それぞれの役割を以下に説明。


# ```$env:PYENV = "$HOME\.pyenv\pyenv-win"```
1\. ```$env:PYENV```
- PowerShell の環境変数 PYENV を設定
- ここでは、pyenv のインストールディレクトリを指す

まずは下記のコードについて説明
```shell:sh
"$HOME\.pyenv\pyenv-win"
```
`$HOME` は、ユーザーのホームディレクトリ（例: C:\Users\Shin）を指します。
結果として、この設定は以下のようになります（例の場合）: C:\Users\Shin\.pyenv\pyenv-win
この環境変数を設定することで、pyenv がインストールされている場所を PowerShell が認識できるようになります。


# `$env:PATH = "$env:PYENV\bin;$env:PYENV\shims;$env:PATH"`

1\. `$env:PATH`
- システムの PATH 環境変数を表す
- PATH に追加されたディレクトリは、コマンドラインで直接アクセスできる実行可能ファイルを探すために使われるす

2\. ```$ env:PYENV\bin```
- これは pyenv の実行ファイルが格納されているディレクトリを指定しています。
- 例: C:\Users\Shin\.pyenv\pyenv-win\bin

3\. ```$env:PYENV\shims```
- ```pyenv``` が切り替えた Python バージョンに対応する仮想的な実行ファイルが格納されています。
- これにより、```pyenv``` を使用して異なる Python バージョンを切り替えた場合でも、python コマンドが常に適切なバージョンを呼び出します。

4\. ```$env:PATH```
- 最後に元々の PATH 環境変数を追加することで、既存の設定を保持
- この設定により、pyenv を通じてインストールした Python バージョンをシームレスに利用

# 全体的な動作
この設定により:
- pyenv コマンドが正しく動作
- ```pyenv global``` などで設定した Python バージョンを反映
- 他のアプリケーションやコマンドラインから適切な Python バージョンが呼び出されるように
９ｘ９のタイルをらせん状に消していきたい！！

## はじめに
今回が初投稿になります！
これはプログラム初心者の自分が分からないなりに作ったプログラムであることを
ご了承ください！

## らせん状に消すって？
自分が作っているゲームで９ｘ９のタイルの上で戦う多人数対戦ゲームを作っていたんですが、一定時間たったら徐々に周りのタイルがらせん状に消えていって、足場が狭くなっちゃった…！？
みたいな処理をさせたいと思い、作ってみることにしました。

雰囲気的には
![9x9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958162/c9aaed0d-9c88-d63e-8758-22608432990f.png)
これを、
![9x9 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958162/9cd61431-97d7-3ccc-cbd3-b2a91a703673.png)
こうして
![9x9 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958162/43b06269-fb1f-025f-3d5d-ccaf693817a4.png)
こういう感じに動かしたい！！

## プログラムとして起こすには？
まず消えているかの判定を格納しておく９ｘ９の二次元配列を持って置く
bool型で true,false で判断できるようにしておく

:::note info
今回は視覚的にわかりやすい 0,1 で記させていただきます
※1がtrue, 0がfalse
:::

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |

これを

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 0  | 0  | 0  | 0  | 0 | 0  | 0  | 0  | 0  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 0  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 0  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 0  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 0  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |
| 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  | 1  |

こう動かしたい。

そのために必要なものは、
①タイルを消していく方向
②現在何個目のタイルを消すかを計測するカウンタ
③次のタイルがもう消えてしまっている又はそもそも配列外かどうかの判定
④何週で消すのを止めるかの範囲

## ①タイルを消していく方向
らせん状に操作するにあたって方向がわかっていないとそもそも消していけない！！
消していく方向用に列挙型を作ってもいいと思います。自分はそう作りました。
もっと良い作り方が絶対あると思います…

```
enum class DIR
{
    UP,
    RIGHT,
    LEFT,
    DOWN
};
```

## ②現在何個目のタイルを消すかを計測するカウンタ
だんだん消すということでカウンタを上昇下降させて対応した配列番号に処理をさせる必要があります。
二次元配列なのでx,yそれぞれのカウンタを持って置きましょう。

## ③次のタイルがもう消えてしまっている又はそもそも配列外かどうかの判定
最初の一周で、カウンタを上昇下降させるのはいいのですが次に入る番号が配列外の値だった場合、致命的なエラーを引き起こしてしまいます…
そのため配列の上限下限を超えたら、その時点で方向を変えるようにします。
次に、次の配列番号がすでにfalse,又は0になっているならその時点で方向を変えましょう。
これでらせん状に消していく処理は完了です。

## ④何週で消すのを止めるかの範囲
このまま処理させては最終的にすべての足場が消えてしまい狭くなったどころではありません。
そのため何週で消すのをやめるかの範囲を決めておきます。
一周したらカウンタを増やす用の変数と何週消すのかの定数を持っておきます。
その定数以上になったら処理をこれ以上しないようにします。
これで消えるのが止まるはず。

## 最後に
ここまで見ていただき本当にありがとうございます。

この処理は決して最善の処理ではありません。
むしろ、改良の余地がいくつも残されていると思います。
そして、初投稿なのもあり、読みにくかった点や説明不足も多くあると思います。
これからも初心者なりにもっと処理を考えて組んでいきたいと思いますので、
よろしくお願いします。
ThunderBirdで始める！メール暗号化の基本とGPGの設定方法  

# ThunderBirdを使ったメールのGPG暗号化について  

Thunderbirdは、多機能でありながら無料で利用可能なメールクライアントとして広く知られています。その中でも特に注目される機能の一つが、GPG（GNU Privacy Guard）を使ったメールの暗号化です。本記事では、Thunderbirdを使ってGPG暗号化を設定し、安全にメールをやり取りする方法を解説します。  

## 必要なツール  

まず、以下のツールをインストールしてください：  

1. **Thunderbird**  
   最新版を公式サイトからダウンロードします。  

2. **GnuPG（GNU Privacy Guard）**  
   暗号化のコアとなるツールです。以下のコマンドでインストール可能です：  

   ```  
   # Linux（Debian系）:  
   sudo apt update && sudo apt install gnupg  

   # macOS（Homebrewを使用）:  
   brew install gnupg  

   # Windows:  
   Gpg4winをダウンロードしてインストール  
   ```  

3. **Enigmailアドオン（旧版の場合）**  
   Thunderbirdの旧版を使用している場合、GPGの統合にEnigmailアドオンが必要です。ただし、最新バージョンではネイティブでサポートされています。  

## GPG鍵の生成  

GPG暗号化の基盤となる公開鍵と秘密鍵を生成します：  

```  
gpg --gen-key  
```  

プロンプトに従い、名前、メールアドレス、パスフレーズを入力してください。生成された鍵は以下のコマンドで確認できます：  

```  
gpg --list-keys  
```  

## ThunderbirdでGPGを設定する  

### ステップ1：GPG暗号化を有効化  

Thunderbirdを開き、「アカウント設定」に移動します。そして「エンドツーエンド暗号化」のセクションを選び、「OpenPGPを有効にする」にチェックを入れます。  

### ステップ2：鍵をインポートまたは生成  

既にGPG鍵を作成済みの場合はインポートします。以下の手順で行います：  

1. 「アカウント設定」→「エンドツーエンド暗号化」→「鍵を管理」をクリック  
2. 「鍵をインポート」を選択し、ファイルを選んで鍵を読み込みます  

Thunderbird内で鍵を生成する場合は、「鍵を生成」オプションを選択します。  

## メールの送信と受信  

### 暗号化メールの送信  

1. 新規メール作成画面で、宛先のメールアドレスに対応する公開鍵を事前に取得している必要があります。  
2. メール本文を入力し、送信前に「暗号化」ボタンをクリックして有効化します。  

### 暗号化メールの受信  

受信した暗号化メールは、自動的に復号化されて表示されます。復号化には、GPG秘密鍵と対応するパスフレーズが必要です。  

## 注意点  

1. **公開鍵の管理**  
   公開鍵を交換する際は、信頼できる方法で共有することが重要です。鍵サーバーを利用することも可能ですが、慎重な運用が求められます。  

2. **バックアップの重要性**  
   秘密鍵を紛失すると復号化ができなくなりますので、鍵のバックアップを忘れずに取ってください。  

3. **バージョンの互換性**  
   ThunderbirdとGPGのバージョンにより設定が異なる場合があります。必ず最新版のドキュメントを確認してください。  

## まとめ  

ThunderbirdとGPGを使えば、メールの暗号化を簡単に導入できます。セキュリティを強化し、プライバシーを守るためにぜひ活用してみてください！
正規表現と文字クラス・フラグ

## 正規表現
正規表現は文字パターンを表す記法で、JavaScriptでは`/foo/`や`new RegExp("foo")`のようにして正規表現を表すオブジェクトを生成できます。

正規表現で使用される文字クラス・フラグについて簡単にまとめてみます。

### 文字クラス
`[abc]`のように`[]`で囲むことで宣言できます。
この例では`a`または`b`または`c`にマッチします。

`-`を使用すると範囲指定ができます。
`[1-9]`は`1`から`9`を、`[a-z]`は`a`から`z`までを表します。

他にも、`\d`のようにバックスラッシュと文字で指定できる汎用的な文字クラスがいくつか用意されています。
#### よく使われる文字クラス
`\d`:ASCII文字での数字。`[0-9]`と同じ。
`\D`:ASCII文字での数字以外。`[^0-9]`と同じ。
`\s`:Unicode空白文字。改行なども含まれています。
`\S`:Unicode空白文字以外。
`\w`:ASCII文字での単語文字。`[A-Za-z0-9_]`と同じ。
`\W`:ASCII文字での単語文字以外。`[^A-Za-z0-9_]`と同じ。
`.`:Unicodeの行末文字（改行）以外の文字。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Regular_expressions/Character_class_escape

### 正規表現中のエスケープ
`^`で否定を表すように、正規表現では特別な意味を持つ文字がいくつかあります。
この`^`自体を正規表現で使用したいときには`\`でエスケープする必要があります。

以下はエスケープしている文字自体を表します。
`\^`, `\$`, `\\`, `\.`, `\*`, `\+`, `\?`, `\(`, `\)`, `\[`, `\]`, `{`, `}`, `\|`, `\/`

文字によっては`\`をつけると、`\d`のように別の意味を持つようになるため注意が必要です。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Regular_expressions/Character_escape

### 正規表現のフラグ
正規表現`//`の２つ目の`/`のあとに特定の文字（フラグ）を記述することで、正規表現の動作を変更できます。
フラグには、`g`,`i`,`m`,`s`,`u`などがあります。

#### `g`フラグ
`//g`のように`g`を指定すると、正規表現に最初にマッチしたものだけでなく、文字列内での全てのマッチを検索するようになります。

#### `i`フラグ
大文字・小文字の区別をしなくなります。

#### `m`フラグ
文字列が改行されている場合、`^`と`$`は文字列の先頭と末尾だけでなく、各行の先頭と末尾にもマッチするようになります。

#### `s`フラグ
`.`が改行も含めてマッチするようになります。

#### `u`フラグとUnicode 文字クラス
`\u{}`によるコードポイントの指定や`\p{}`、`\P{}`の使用が可能になります。
`/\u{61}/`はuが61回繰り返したものにマッチしますが、`/\u{61}/u`はコードポイント`U+0061`、`a`にマッチするようになります。
また、サロゲートペア文字など複数の文字として扱われてしまう文字も1文字として扱われるようになります。

他にも、`\p{}`によってUnicode文字クラスを使用することができるようになります。
`/\p{Decimal_Number}/u`のようにUnicode文字プロパティを指定することができます[^1]。
```js
/\p{Decimal_Number}/u.test('٣') //true
/\d/.test('٣') //false
```
`\d`ではアラビア数字の0から9にしかマッチしませんが、`/\p{Decimal_Number}/u`であればインド数字`٣`[^2]などにもマッチするようになります。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape

#### `y`フラグ
`RegExp`メソッドである`exec`や`test`で正規表現オブジェクトの`lastIndex`番目のインデックスから検索するようになります。
また、`String.prototype.match`と`RegExp.prototype.exec`の挙動が変わります。

https://qiita.com/axoloto210/items/393b30b73fcb1664d017

[^1]:Unicode文字には複数のUnicode文字プロパティが設定されています。
[^2]:`٣`はアラビア数字で3にあたる数字です。
プロジェクトウィンドウにパスを表示する話

# アドカレ情報

前の日は...@LuminousNecoさんの[UnityでもGithub Copilotをおすすめします](https://qiita.com/LuminousNeco/items/7849c81eabbb19ee94d8)
次の日は...@am1tanakaさんの[Unity6ではじめてのAwaitable](https://am1tanaka.hatenablog.com/entry/unity-adcale24-awaitable)

# 要約

プロジェクトウィンドウのタイトルに開いているフォルダのパス（名前）を表示しておくと便利だよ。

# 本文

初めまして、ゲームエンジニアのwrsmAです。Unityとは仲良くさせてもらってます。
突然ですが、自分の環境ではプロジェクトウィンドウを複数画面出しておく機会が多いです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375892/13acd668-f7d6-f64e-eb32-4cfa6566798e.png)

このとき、ウィンドウ名が全て「Project」なので「どのウィンドウで何を見ていたか？」がとても分かりづらいと思っていました。

そこでEditorを拡張してウィンドウ名に現在開いているフォルダのパスを表示したら便利になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375892/1c7123b7-622b-5d49-572e-9eb0f8ba216e.png)

# 実装

プロジェクトウィンドウはスクリプト上では**ProjectBrowser**として実装されています。
ここから、実際に行った実装を以下の手順で紹介します。

1. ProjectBrowserの実体を取得する
1. 現在開いているパスを取得する
1. ウィンドウの名前に反映する

## 1. ProjectBrowserの実体を取得する

**Reflection**を用いてTypeの取得からObjectの取得までを行っています。
AssemblyやTypeは適宜キャッシュしておくと良いと思います。
また、後の手順で`titleContent`にアクセスするため`EditorWindow`の配列にキャストしています。

```cs
using System;
using System.Reflection;

using UnityEditor;
using UnityEngine;

public static class ProjectBrowserExtender{
    
    private static readonly Type _projectBrowserType;
    
    static ProjectBrowserExtender(){
        var asm = Assembly.Load("UnityEditor");
        _projectBrowserType = asm.GetType("UnityEditor.ProjectBrowser");
    }

    /// <summary>
    /// 全てのProjectBrowserの実体を取得する
    /// </summary>
    public static EditorWindow[] GetAllProjectBrowsers(){
        return Resources.FindObjectsOfTypeAll(_projectBrowserType) as EditorWindow[];
    }
}
```

## 2. 現在開いているパスを取得する

`ProjectBrowser`に、現在開いているパスを取得するための`GetActiveFolderPath`メソッドが存在するので、
それを用いてパスの取得を行います。
念のため、引数に渡された実体が`ProjectBrowser`かどうかをチェックしています。

```cs
public static class ProjectBrowserExtender{

    .
    .
    .
    /// <summary>
    /// ProjectBrowserが開いているフォルダのパスを取得する
    /// </summary>
    public static string GetActiveFolderPath(EditorWindow window){
        if (_projectBrowserType.IsInstanceOfType(window) == false){
            throw new Exception("window is not ProjectBrowser");
        }
        var methodInfo = _projectBrowserType.GetMethod("GetActiveFolderPath", BindingFlags.NonPublic | BindingFlags.Instance);
        return (string)methodInfo.Invoke(window, null);
    }
}
```

## 3. ウィンドウの名前に反映する

ウィンドウの名前は`EditorWindow`クラスが持つ`titleContent`を書き換えることで変更できます。

```cs
[InitializeOnLoad]
public static class ProjectBrowserTitleOverwriter{
    static ProjectBrowserTitleOverwriter(){
        EditorApplication.update -= OnUpdate;
        EditorApplication.update += OnUpdate;
    }

    static void OnUpdate(){
        foreach (var window in ProjectBrowserExtender.GetAllProjectBrowsers()){
            var activeFolderPathStr = ProjectBrowserExtender.GetActiveFolderPath(window);
            window.titleContent = EditorGUIUtility.TrTextContent(activeFolderPathStr);
        }
    }
```

# あとがき

紹介した実装では、OnUpdateにそのまま書きましたがEditorPrefsなどと連携して機能の切り替えができるようにしても良いと思います。

階層の深いフォルダなどは、かえって分かりづらいこともあるので表示する文字列を調節するのもアリだと思います。
ipywidgets


### 1. `Dropdown`ウィジェット
```python
import ipywidgets as widgets

selection_list = widgets.Dropdown(
    options=['選択肢1', '選択肢2'],
    value='デフォルト値',
    description='ラベル:',
    layout=widgets.Layout(width='幅(px)'),
    style={'description_width': 'ラベルの幅(px)'}
)
```
- **`selection_list`**: ipywidgets.Dropdownオブジェクト
- **`options`**: 選択肢のリスト
- **`value`**: デフォルトで選択される値
- **`description`**: ラベル
- **`layout`**: ウィジェットのレイアウト（幅など）
- **`style`**: ウィジェットのスタイル（ラベルの幅など）

### 2. `Button`ウィジェット
```python
run_button = widgets.Button(
    description='ボタンのラベル'
)
```
- **`run_button`**: ipywidgets.Buttonオブジェクト
- **`description`**: ボタンのラベル

### 3. `Output`ウィジェット
```python
output_area = widgets.Output()
```
- **`output_area`**: ipywidgets.Outputオブジェクト
- **機能**: 出力エリアを作成

### 4. ウィジェットの表示
```python
from IPython.display import display

display(selection_list, run_button, output_area)
```
- **機能**: ウィジェットを表示

### 5. ボタンがクリックされたときの処理
```python
def on_button_clicked(b):
    with output_area:
        output_area.clear_output()
        print("ボタンがクリックされました")

run_button.on_click(on_button_clicked)
```
- **`on_button_clicked`**: ボタンがクリックされたときに実行される関数
- **`on_click`**: ボタンにクリックイベントを設定

### 6. ファイルリストの取得
参照元ファイルが以下のような内容とする
```./test_files 
test_file1.txt	test_file2.xlsx
```
```python
from pathlib import Path

def get_txt_xlsx_files(directory):
    return [f.name for f in Path(directory).glob("*.txt")] + [f.name for f in Path(directory).glob("*.xlsx")]

input_directry = "./test_files"

dataset_file_list = widgets.Dropdown(
    options=get_txt_xlsx_files(input_directry),
    description='処理対象データセットファイルの選択:',
    layout=widgets.Layout(width='500px'),
    style={'description_width': '200px'}
)

```
- **`get_txt_xlsx_files`**: 指定したディレクトリ内の`.txt`および`.xlsx`ファイルを取得
- **`options`**: ディレクトリ内のファイル名のリスト
- **`description`**: ウィジェットのラベル
- **`layout`**: ウィジェットのレイアウト（幅など）
- **`style`**: ウィジェットのスタイル（ラベルの幅など）
asdf + ViteでReact環境構築

# はじめに
Reactについてドキュメントを読んだりインプットをしているものの、理解するにはアウトプットもしようと思い、その環境構築手順を備忘録がてら残します。

Next.js等フレームワークを使うこともできますが、今回は簡易的にReactを触りたいのでViteで環境構築をします。

# 手順
自分の使っている環境は以下なので、Windowsだったりシェルが異なる場合は手順も変わってくるのでご容赦ください。
- Macbook
- zsh
- Homebrew

## asdf
Dockerを立てるのも手間だったので、サクッと入れられるかつ簡単にバージョンを変えられるのでasdfを使いました。

asdfについてはこちら。

https://asdf-vm.com/guide/introduction.html

※ すでに自分の環境はHomebrewやgitは入っていたのでその手順は飛ばしています。

### asdfをダウンロード
```sh
$ brew install asdf

$ asdf --version
v0.13.1
```

### asdfをインストール
zshを使っているのでzshの手順を記載しています。異なる方はこちらを参照してください。

https://asdf-vm.com/guide/getting-started.html#_3-install-asdf

```sh
$ echo -e "\n. $(brew --prefix asdf)/libexec/asdf.sh" >> ${ZDOTDIR:-~}/.zshrc
```

### バージョンをインストール
最新バージョンを入れることもバージョンを指定することもできます。

```sh
# 利用可能なバージョンを確認
$ asdf list all nodejs
...
23.2.0
23.3.0
23.4.0

# 最新バージョンをインストール
$ asdf install nodejs latest

# バージョンを指定してインストール
$ asdf install nodejs 20.12.2
```

### バージョンを設定
バージョン設定は全体（global）に設定するか、プロジェクトごと（local）に設定するかも指定することができます。

```sh
# global
$ asdf global nodejs latest

# local
$ asdf local nodejs latest

# バージョン確認
$ node -v
v20.12.2
```

## Vite
### プロジェクト作成
SWCだと高速というのを見かけたので、興味本位で`react-swc`にしています。

```sh
$ npm create vite@latest my-react-app -- --template react-swc
Need to install the following packages:
create-vite@6.0.1
Ok to proceed? (y) y

Scaffolding project in ... /my-react-app...

Done. Now run:

  cd my-react-app
  npm install
  npm run dev
```

### 起動
プロジェクト作成時、最後に3つのコマンドが表示されたので順に実行していきます。

```sh
$ cd my-react-app

$ npm install

$ npm run dev

> my-react-app@0.0.0 dev
> vite


  VITE v6.0.3  ready in 386 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help
```

`http://localhost:5173/`にアクセスすると画面が表示されました👏
これで環境構築終了です。

![スクリーンショット 2024-12-11 20.16.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3733722/cc283ed4-6b56-fdfa-8b72-e5395702cfab.png)
JSやTSの関数フローを描くサービス

## はじめに

JavaScript/TypeScript/JSXの関数フローを描くサービスを作りました。

https://querykuma.github.io/JS-TS-Function-Flow-Chart/

## 関数フローとは何か

```JavaScript
function from() {
    to()
}
```

上のプログラムには関数ノード(from)から関数ノード(to)への関数フローがあります。

このサービスは1つのファイルからすべての関数フローを抽出して図示します。

## なぜ作ったか

関数フローを見たいと思ったことはありませんか？

関数フローにループ構造のあるプログラムが無限ループしていないかを調べるために手作業で関数フローを描いたことがありました。

そのようなときにJavaScriptのプログラムを構文解析して抽象構文木を出力するライブラリの存在を知りました。

Qiita記事のマークダウンでも使われている、フローチャートを図示するMermaidライブラリと組み合わせれば関数フローを描くウェブサービスを作れると思って作り始めました。

## 使い方

中央のファイル選択ボタンを押すかファイルをブラウザ内にドラッグすると、関数フローを図示します。

図の各ノードをクリックすると、関数フローのIN/OUTの矢印を色付けします。

図の各ノードをマウスホバーすると、関数フローのIN/OUTの詳細をポップアップ表示します。

画面右上アイコンの設定ボタンをクリックすると、設定画面で指定した名前の関数フロー（to）を非表示にできます。非表示設定の既定値が存在するので、すべての関数フローを表示したい場合は空白を設定する必要があります。

いずれにせよ使い方を説明しなくても使いやすいUIになるように工夫しました。

## 開発時に工夫したこと

他に開発時に工夫したことです。

### 関数フローの非表示

すべての関数フローを表示した図は全体の構造が見づらかったので、非表示機能を作って関数フローを絞れるようにしました。余計な関数フローを非表示にすることにより、注目したい関数フローに集中できます。

### 矢印のつながった先

関数フローの矢印がどこにつながっているのかが見づらかったので、クリックしたノードにつながった矢印に色付けする機能をつけました。

### espreeから@babel/parserへ

espreeはESLintが使うJavaScript構文解析器です。ESLintのカスタムルールを作るときに抽象構文木を触ったことがあり慣れていたので、espreeを最初に使いました。

しかし、ライセンスが混在することとjsdelivr.comが配信するライブラリが使えないことからacornに乗り換えました。acornはespreeが基にしているJavaScriptの構文解析器です。

他の構文解析器も調べました。@typescript-eslint/parserはTypeScript-ESLintが使うTypeScriptの構文解析器です。TypeScriptは専用の構文解析器を使います。

この開発では最終的に@babel/parserを選びました。JavaScriptとTypeScriptとJSXをシームレスに構文解析できるからです。最初はJavaScriptのみを受け付ける予定でしたが、TypeScriptとJSXも受け付けます。

### Jestのような一括自動テスト

開発の最終段階においてもなおアジャイル開発的な仕様変更をしていたら、ある箇所の修正が予期せぬ箇所に不具合を出し、テストが終わらない状況に陥りました。しかし、Jestのような一括自動テストで単純なものを自作することによって、終わらないテストを終わらせることができました。

特に効果が大きかったのは、影響範囲が分からない箇所を変更したときに一括自動テストに引っかかって影響範囲が分かるようになったことです。アジャイル開発的な仕様変更をするごとに、通過しなかったテストそのものが廃れたかを判定することに加え、テストを更新しなければならないことが面倒でしたが、任意のJavaScript入力という複雑さを管理してテストを終わらせるには必要だったと思います。

## さいごに

ファイル分割しないプログラミングをしていたためか複雑になった1ファイルの関数フローを見たいと思ってこのサービスを作りました。

一般的にはファイル分割するプログラミングが主流なのではないかと思います。その場合は１ファイルの関数フローを見たいことはあまりないかもしれません。

ですが1ファイルが複雑になり、複雑になった1ファイルの関数フローを見たいと思うようなことがあればぜひ使ってみてください。

https://querykuma.github.io/JS-TS-Function-Flow-Chart/
本物のクソコードを炊き上げる

皆さん、どうにも遠慮がちですね。
サクッと💩置きますよ。

```php
<?php
	if(isset($_SERVER['DEVELOP'])){
		define ("DEVELOP" , "true");
		error_reporting(0); 
	}else{
		define ("DEVELOP" , "false");
		error_reporting(E_ALL & ~E_DEPRECATED); 
	}

	if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
		$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
	}


if(strpos($_SERVER["REQUEST_URI"],"/ｱﾄﾞﾐｿ/")===0){
	 if($_SERVER['HTTP_X_FORWARDED_FOR']==="xxx.xxx.xxx.xxx, yyy.yyy.yyy.yyy"){
	 }else{
	 	die("error");
	 }
}else{
	ini_set( "session.gc_maxlifetime", 172800 );
	session_cache_expire(36000);
	session_start();

}
//}

?>
<?php // end
```
頭の天辺からつま先まで余すことなく全部ﾌﾞﾘﾌﾞﾘﾌﾞﾘﾌﾞﾘｭﾘｭﾘｭﾘｭﾘｭﾘｭ！！！！！！ﾌﾞﾂﾁﾁﾌﾞﾌﾞﾌﾞﾁﾁﾁﾁﾌﾞﾘﾘｲﾘﾌﾞﾌﾞﾌﾞﾌﾞｩｩｩｩｯｯｯ！！！！！！！

と言っていても仕方がないから、炊き上げていく。

# お焚き上げポイント
- インデントを適切に行う
- 不要なコメントやコードの除外を行う
- DEVELOPは多分環境変数なんだろうからgetenv()にする
- 真偽値文字列を真偽値にする
- 開発中ではエラーを出力する
- REMOTE_ADDRを上書きしない
- 条件分岐の可読性を上げる
- 許可するIPのロジックを見つめ直す
- セッションが煉獄長寿郎
- てか、php.iniに書け

## 俺はDEVELOPがどう使われてるのか知りたい
探してみる
```shell
grep -r "DEVELOP"
/path/xxx/yyy.conf:#	setENV DEVELOP "true"
```
なるほど。apacheのsetEnvを利用して開発モードとしているのな。define :relaxed:

じゃあ...
イクゾ！！！！！！！！
```php
<?php
session_start();

const ADMIN_PATH = '/ｱﾄﾞﾐｿ/';
const ALLOWED_IPS = ['xxx.xxxx.xxx.xxx', 'yyy.yyy.yyy.yyy'];

$isDevelop = filter_var(getenv('DEVELOP'), FILTER_VALIDATE_BOOLEAN);
if ($isDevelop) {
	error_reporting(E_ALL);
	ini_set('display_errors', 1);
} else {
	error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
	ini_set('display_errors', '0');
	ini_set('log_errors', '1');
	ini_set('error_log', '/path/php-error.log');
}

$remoteAddr = trim(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]);
if (str_contains($_SERVER['REQUEST_URI'], ADMIN_PATH) && !in_array($remoteAddr, ALLOWED_AIPS, true)) {
	http_response_code(403);
	header('Content-Type: text/plain; charset=UTF-8');
	die('403 Forbidden: Your IP is not allowed.');
}
```

労力をかけることなく、それなりに親切なコードになったのではないでしょうか。
以上でお焚き上げ完了です。

世の中にはまだまだ古くから働いてきたコード達が潜んでいます。
年に一度は遭遇します。見かけたら感謝の意を込めて汚れを拭き取って行く活動を継続して行っていきたいものです。
Elixirで作る「DDJ-FLX4のジョグ対応ブロックくずし」　その２　ゲームの画面の枠を作る

`Elixirで作る「DDJ-FLX4のジョグ対応ブロックくずし」　その１　プロジェクト作成からライブラリ追加まで`の続きです

https://qiita.com/t-yamanashi/items/fe2875d81710e2ddece8

# まずはゲームの画面の枠をつくる
画面の仕様
- mainから始まる
- main_loopは画面を閉じるまでループする
  - drawを呼ぶ  
- drawは画面を描画する

```elixir:lib/ddj_block.ex
defmodule DdjBlock do
  @moduledoc """
  Documentation for `DdjBlock`.
  """
  alias Rayex.Structs.Rectangle
  use Rayex

  def main() do
    init_window(800, 800, "DdjBlock")
    main_loop(true)
  end

  defp main_loop(true) do
    begin_drawing()
    draw()
    end_drawing()

    Process.sleep(100)
    main_loop(!window_should_close())
  end

  defp main_loop(_), do: nil

  defp draw() do
    rectangle = %Rectangle{x: 100.0, y: 100.0, width: 100.0, height: 50.0}
    draw_rectangle_lines_ex(rectangle, 1, %{r: 0, g: 255, b: 0, a: 255})
  end
end
```

テストを消しておく
画面の自動テストは無理なので
実施するなら、関数ごとのテストかな

```elixir:test/ddj_block_test.exs
defmodule DdjBlockTest do
  use ExUnit.Case
end
```

実行

```bash
iex -S mix
```

下記のエラーがでる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/2b241486-1cf1-3dbe-6ede-c189ddb9fa03.png)

# rayexビルド対策

:::note alert
音が鳴らないライブラリになっても文句を言わないこと
:::
とりあえず、ビルドを通るようにする

```diff_c:deps/rayex/c_src/rayex/rayex.c
//　省略
UNIFEX_TERM is_sound_ready(UnifexEnv *env, UnifexPayload *payload) {
  Sound sound = get_sound_unifex_payload(env, payload);
- bool res = IsSoundReady(sound);
+ bool res = false; // IsSoundReady(sound);
  return is_sound_ready_result(env, res);
}
//　省略
```

rayexをビルド

```bash
$ mix deps.compile rayex --force
```

起動できた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/4c7d6ace-7614-5bab-aa5e-227d1e0c108f.png)

だが、しかしバッテン押しても閉じない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/7d12c3e1-88ab-618b-eb5a-1a607c21432e.png)

# 終了対策
mix コマンドを作る
```elixir:lib/mix/tasks/ddj.ex
defmodule Mix.Tasks.Ddj do
  use Mix.Task

  def run(_arg) do
    DdjBlock.main()
  end
end
```

```sh
$ mix ddj
```

無事に終了できるプログラムができました

https://github.com/ymn-t-yamanashi/ddj_block/releases/tag/v0.02

# ソース


今回はここまで
つづく

https://qiita.com/t-yamanashi/items/87d734d7cf9f4b48b0ea
【小ネタ】MySQLのクエリ結果をキレイに整形したい。

テーブル内の構造を見ようとしたとき、
カラム数が多くてぐちゃぐちゃな出力になった経験はありませんか？

私はあります。

今回はそんな時に使える小ネタを紹介します。
## 例
```sql
mysql> SELECT * FROM `テーブル名`;
```
基本的にはこれできれいな横長の表形式で出力されると思います。

画面に収まる場合は問題ありませんが、
カラム数が増えると1行に入り切らず折り返してしまい、非常に見づらい表となってしまいます。

これを解決するにはどうするか？

答えは簡単です。`;`を`\G`変えてコマンドを実行するだけです。
```sql
mysql> SELECT * FROM `テーブル名`\G
```

末尾の文字を`;`から`\G`に変えることで縦表示が可能となります。
キレイに出力されましたね。

カラムごとの結果が縦に並ぶため、文字が折り返すこともなく見やすくなります。
横に長いテーブルを確認する場合には、特に重宝するオプションですので覚えておくと便利です。

ｽｯｷﾘ───ヽ(*ﾟдﾟ*)ノ───!!
Spring BootでのSqlLobValueの備忘録

Spring Bootを勉強するためにアプリケーションを開発している中で、BlobやClobに関するデータベース操作に苦戦しました。その過程で、大容量データ（画像や長文テキストなど）をデータベースに格納する際に便利なSqlLobValueクラスを知り、その活用方法を学びました。本記事では、SqlLobValueの基本的な仕組み、具体的な使用例、そして注意点について解説します。

## SqlLobValueの概要
SqlLobValueは、Spring JDBCでLob（Large Object）データ型を簡単に操作できるようにするためのクラスです。Lobは通常、以下のようなデータを格納するために使用されます：

|データ型 |内容 |主な用途 |
|---|---|---|
|CLOB|長文テキストや大量の文字列データ|ブログ記事、メモ、大規模テキストデータの保存|
|BLOB|画像、音声、PDFなどのバイナリデータ|画像ファイル、動画、音声データの保存|

SqlLobValueを利用すると、java.sql.Clobやjava.sql.Blobの操作を簡素化でき、以下のメリットがあります。
・**Lobデータの安全な管理**：直接的なJDBC操作の複雑さを軽減。
・**汎用性の高いデータ操作**：JdbcTemplateやSimpleJdbcInsertと連携して利用可能。

## CLOB/BLOBデータの取り扱い
1.ファイルの保存
ユーザーがアップロードした画像やPDFファイルなどをデータベースに保存する。

2.大きなテキストデータの保存
ブログ記事や長文メモなど、CLOBタイプのテキストデータを格納する。

3.ストリーミングデータの取り扱い
音声や動画などのデータをストリーム形式で処理し、データベースに保存する。

4.サンプルコード
① CLOBデータの挿入（テキストデータ）
```
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.lob.SqlLobValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Types;

@Service
public class ContentService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void saveTextContent(String textContent) {
        // CLOBデータをSqlLobValueでラップ
        SqlLobValue lobValue = new SqlLobValue(textContent);
        
        // SQL文の実行
        String sql = "INSERT INTO contents (content) VALUES (?)";
        jdbcTemplate.update(sql, lobValue, Types.CLOB);
    }
}
```
このコードでは、文字列データをSqlLobValueでラップし、JdbcTemplateを使ってデータベースに挿入しています。

② BLOBデータの挿入（バイナリデータ）
```
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.lob.SqlLobValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.File;
import java.nio.file.Files;
import java.sql.Types;

@Service
public class ImageService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void saveImageFile(String imageFilePath) throws Exception {
        // ファイルを読み込んでバイナリデータに変換
        File file = new File(imageFilePath);
        byte[] fileContent = Files.readAllBytes(file.toPath());

        // BLOBデータをSqlLobValueでラップ
        SqlLobValue lobValue = new SqlLobValue(fileContent);
        
        // SQL文の実行
        String sql = "INSERT INTO images (image_data) VALUES (?)";
        jdbcTemplate.update(sql, lobValue, Types.BLOB);
    }
}
```
バイナリデータも同様に、SqlLobValueを利用して効率的に格納できます。


## まとめ
SqlLobValueは、Spring BootでLobデータ（BLOBやCLOB）を効率的に操作するために非常に便利なクラスです。ただし、情報が少なく、利用方法を調べるのに手間取ることもあります。本記事が、その参考として役立てば幸いです。ぜひ、開発に活用してみてください！
iOSアプリ開発におけるファイルの役割を理解する

## はじめに
iOSアプリ開発では、データの保存場所を適切に選ぶことが重要です。適切な場所へのファイル格納ができていないとリジェクトの原因になる可能性があるので、今回はファイルシステム構造やディレクトリの役割を調べてみました。

## iOSのファイルシステム
iOSアプリのファイルシステムは、**サンドボックス構造**と言い、各アプリケーションが専用の領域を作成し、その領域でのみ操作が可能であり、他のアプリやシステム全体に影響を与えないように設計されています。

以下はアプリがアクセス可能なディレクトリです、それぞれの役割を見てみましょう。

```
├── Documents/
├── Library/
│   ├── Application Support/
│   ├── Caches/
│   ├── Preferences/
├── tmp/

```
### Documents
ユーザーが保存したファイルやエクスポートデータなど、ユーザーが利用可能なコンテンツを保存するフォルダです。
iTunes と iCloud によってバックアップされます。

### Library
#### - Application Support
アプリで生成されたログなどのデータファイルが保存されます。
iTunes と iCloud によってバックアップされます。


#### - Caches
キャッシュデータが保存されます。
iTunes と iCloud によってバックアップされません。

#### - Preferences
UserDefaultsのようなアプリ固有のファイルが含まれています。
 iTunes と iCloud によってバックアップされます。

### tmp
アプリ起動中に使用される一時的なデータが保存され、アプリが起動していない時に削除される可能性があります。
iTunes と iCloud によってバックアップされません。

## おわりに
各ディレクトリの役割を正しく理解し、適切な場所にファイルを保存しましょう！

## 参考文献
https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html
【競プロ-AtCoder】【動的計画法(DP)】A16 Dungeon 1【Golang】【初学者】

# A16 Dungeon 1

問題リンク：https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_p

解法：動的計画法（DP）

- 解答コード

```go
package main

import "fmt"

func main() {
	var N int
	fmt.Scan(&N)

	A := make([]int, N+1)
	for i := 2; i <= N; i++ {
		fmt.Scan(&A[i])
	}
	B := make([]int, N+1)
	for i := 3; i <= N; i++ {
		fmt.Scan(&B[i])
	}

	dp := make([]int, N+1)
	dp[1] = 0
	dp[2] = A[2]
	for i := 3; i <= N; i++ {
		dp[i] = min(dp[i-1]+A[i], dp[i-2]+B[i])
	}

	// 出力
	fmt.Println(dp[N])

}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3771904/6fc8396f-01f0-54e3-f207-8678eb8b92e6.png)


- コードの詳細
    
    インデックスは0から始めると考えるのが面倒になるため、1から使えるようにN＋1で初期化する。
    
    - 入力値の読み取り
    
    ```go
    	for i := 2; i <= N; i++ {
    		fmt.Scan(&A[i])
    	}
    	for i := 3; i <= N; i++ {
    		fmt.Scan(&B[i])
    	}
    ```
    
    - **`for i := 2; i <= N; i++`**:
        - `A[i]`に部屋`i-1`から`i`へのコストを格納します。
        - 部屋`1`から`2`へのコストは`A[2]`として入力します。
    - **`for i := 3; i <= N; i++`**:
        - `B[i]`に部屋`i-2`から`i`へのコストを格納します。
        - 都市`1`や`2`に関しては`B[i]`が存在しないため、このループは`3`から始めます。
    
    - DPテーブルの初期化
    
    ```go
    	dp := make([]int, N+1)
    	dp[1] = 0
    	dp[2] = A[2]
    ```
    
    - **`dp`**: 動的計画法で使用するスライス。`dp[i]`は部屋`i`に到達するまでの最小コストを表します。
    - **初期値の設定**:
        - `dp[1] = 0`: 部屋`1`のスタート地点なのでコストは0。
        - `dp[2] = A[2]`: 部屋`1`から`2`に行くコストは入力`A[2]`の値。
    
    - 動的計画法(DP)のループ
    
    ```go
    	for i := 3; i <= N; i++ {
    		dp[i] = min(dp[i-1]+A[i], dp[i-2]+B[i]))
    	}
    ```
    
    - **`for i := 3; i <= N; i++`**:
        - 部屋`3`以降の最小コストを計算します。
    - **状態遷移**:
        - `dp[i-1] + A[i]`: 1つ前の都市`i-1`から`i`へ移動する場合のコスト。
        - `dp[i-2] + B[i]`: 2つ前の都市`i-2`から`i`へ移動する場合のコスト。
        - `min`: 上記2つの値の最小値を選択し、`dp[i]`に格納します。
    
    - 結果出力
    
    ```go
    	fmt.Println(dp[N])
    ```
    
    - 部屋`N`に到達する最小コスト`dp[N]`を出力します。
    
    - 計算量
    
    計算量はO(N)となる。
    
    部屋Nまでのコストを計算するループは線形時間で処理される。