OmniAICreator/Qiita-1.07M huggingface dataset:
【Python】選択ソート

## 概要
選択ソートは、基本的なソートアルゴリズムの一つです。選択ソートの仕組みは、リストの中で最小（または最大）の要素を見つけ、それをリストの先頭に配置し、残りの部分について同じ操作を繰り返します。
選択ソートの計算量はO(n^2)で、効率はそれほど高くありません。

この記事では、Pythonでの選択ソート実装方法について説明します。

## コード
以下がPythonでの選択ソートの実装例です。

```python
def selection_sort(arr):
    n = len(arr)
    # リストの全ての要素を繰り返し処理
    for i in range(n):
        # 残りの部分の最小値を探す
        min_idx = i
        for j in range(i + 1, n):
            if arr[j] < arr[min_idx]:
                min_idx = j
        # 最小値を現在の位置にスワップ
        arr[i], arr[min_idx] = arr[min_idx], arr[i]
    return arr

# サンプルの使用例
if __name__ == "__main__":
    sample_data = [64, 25, 12, 22, 11]
    print("ソート前:", sample_data)
    sorted_data = selection_sort(sample_data)
    print("ソート後:", sorted_data)
```

### 実行結果
上記のコードを実行すると、次のような結果が得られます。
```
ソート前: [64, 25, 12, 22, 11]
ソート後: [11, 12, 22, 25, 64]
```

### 詳細
selection_sort関数は、リストarrを入力として受け取り、ソートされたリストを返します。
外側のforループでは、リストのすべての要素に対して操作を行います。
内側のforループでは、未ソート部分から最小の要素を見つけ、現在の位置（i）と入れ替えます。
この過程をリスト全体に対して繰り返すことで、全ての要素が昇順にソートされます。

## 参考
https://www.udemy.com/course/python-algo/?couponCode=KEEPLEARNING
【OpenAI o1】でDALL-E3へのPromptのテンプレートを作成する相談した結果を自分的に改善しました。


　どうも、カーブミラーです。

　今回は、昨日のテンプレートを作成する相談した結果を自分的に改善しました。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。　あしからず。
:::
　ニュースはないので、
　　さっそく本題です。

　今回は、
　　昨日（2024/09/20）に引き続き、
　　　出来上がったPromptを
　　　　私の目的に合わせて
　　　　　手直しします。

　　[【OpenAI o1】でDALL-E3へのPromptのテンプレートを作成する相談をしました。](https://qiita.com/kabumira/items/1e43cb94c40e344cd318)

　　[【OpenAI o1】でDALL-E3へのPromptのテンプレートを作成する相談をしました。続編で、画像を得るまで。](https://qiita.com/kabumira/items/02ed9fe5d03e093ba442)

　手直し、と書いたとおり
　　OpenAI o1は使いません。

　本当は
　　タイトルに入れるか悩んだんですが
　　　OpenAI o1絡みなので
　　　　入れることになりました。

　さて、
　　“私の目的”というのは、
　　　“ChatGPTに遊びを加える”
　　　　というものです。

　“遊び”というのは
　　自由度のことです。

　通常、ChatGPTは
　　Promptに対して、
　　　安定した回答をよこしません。
　　　　二転三転する、という
　　　　　意味ではなく、
　　　　　　“揺らぎ”と表現すべき
　　　　　　　でしょうか。

　“〜ありました”とか
　　“〜ございました”とか
　　　回答の内容は同じでも
　　　　フォーマットや言葉遣いが
　　　　　変わってしまいます。

　前回、OpenAI o1に
　　作成してもらったPromptは、
　　　構文があり、
　　　　そこに変数で指定した文言を
　　　　　書き入れるだけでした。

　その結果、
　　出来上がるPromptは
　　　いつも一緒です。
　　　　変えようがない、とも
　　　　　言えますね。

　逆に言えば、
　　このPromptを配布すれば、
　　　誰でもほぼ同じ画像を
　　　　生成できることになります。

　これはこれで良い、のですが
　　私的には、不満です。
　　　ChatGPTの揺らぎの
　　　　入る余地がなくて、
　　　　　生成される画像が
　　　　　　固定されてしまっています。

　そこで
　　テンプレートPromptを
　　　手直しして、生成するPromptは
　　　　ChatGPTさんに考えてもらう
　　　　　形にしました。

　それがこちらのPromptです。
```Text:テンプレートPrompt
// 変数宣言と初期化
スタイル = "[スタイル]"
主題 = "[主題]"
シチュエーション = "[シチュエーション]"
色彩 = "[色彩]"
背景条件 = "[背景条件]"
詳細条件1 = "[詳細条件1]"
詳細条件2 = "[詳細条件2]"

// DALL-E 3で画像を生成
```

　見てわかると思いますが、
　　プロンプト生成の
　　　文言を削除しました。

　構文は
　　本当に
　　　ChatGPTさんに
　　　　考えてもらう形です。

　では使用する手順です。
　❶GPT-4oであることを確認
　❷Prompt入力
　　　変数内容を決める
```Text:変数に書き込みしたPrompt
// 変数宣言と初期化
スタイル = "[サイバーパンク]"
主題 = "[未来都市]"
シチュエーション = "[夜景]"
色彩 = "[ダークトーン]"
背景条件 = "[未来的な建築物]"
詳細条件1 = "[若い女性]"
詳細条件2 = "[なし]"

// DALL-E 3で画像を生成
```
　❸送信
　❹ダウンロードリンクが表示

　これで出来るわけですが、
　　今回は、生成されたPromptを
　　　ごらんください。
```Text:前回のPromptのまま
サイバーパンク風の未来的な都市の夜景。色調はダークトーンで、背景には未来的な建築物が描かれています。シーンには若い女性が重要なディテールとして含まれ、他には特定の要素は含まれていません。
```
```Text:構文を削除したPrompt❶
サイバーパンクスタイルの未来都市の夜景。暗いトーンが特徴です。背景にはネオンライトで照らされた未来的な建築物が広がっています。前景には、若い女性が自信を持って都市の環境の中に立っています。雰囲気は暗く、金属やガラスの建物に光が反射してムードを強調しています。女性は未来的な服装をしており、サイバーパンクの美学に溶け込んでいます。
```
```Text:構文を削除したPrompt❷
サイバーパンクスタイルの未来的な都市が、夜の暗いトーンの中で描かれています。シーンは未来的な建築物に支配されており、暗い都市景観の中でネオンライトに照らされています。手前には若い女性がおり、彼女は未来的な衣装をまとい、そのハイテクな環境を反映しています。全体の雰囲気はムーディーで、サイバーパンクの夜のエッセンスが、暗闇の中で輝く都市によって見事に表現されています。
```
```Text:構文を削除したPrompt❸
サイバーパンク風の夜の都市景観。ダークトーンで描かれ、背景には未来的な建物が配置されています。若い女性がシーンの中央に立ち、ネオンの光に囲まれ、未来の大都市の高度な技術を反映した高層建築物がそびえ立っています。
```
　なお、それぞれ
　　別々のセッションで
　　　行ないました。

　もちろん、
　　画像を見て、
　　　判断してもらいましょう。

前回のPromptのまま
![1726898672834.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/9e94f2e7-24b1-f42f-415c-305ed78ec344.jpeg)

構文を削除したPrompt❶
![1726898707277.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/f5c8ec0d-e48e-8ad3-bd6f-520ae66facf6.jpeg)

構文を削除したPrompt❷
![1726898723620.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/62ed745e-ab7e-ac93-7f66-0400141afc37.jpeg)

構文を削除したPrompt❸
![1726898735388.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/dcb442f9-563a-d2dc-b607-976684508162.jpeg)

　いかがでしょうか？

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
C++ で使うファイルの拡張子

# これは何？

C++ で使うファイルの拡張子をどうすればいいのかの話を、軽く調べた結果とともに私見を書いた。

# そもそも

そもそも、C++ のソースコードの拡張子に決まりは無い。
あるのは慣習だけ。

ソースコードは C++ だとわかる拡張子が使われる。
ヘッダファイルは C++ だとわかる拡張子か、C言語のヘッダと同じ拡張子が使われる。

ヘッダファイルで C言語のヘッダと同じ拡張子が使われるのは

* C / C++ のどちらでも使えるヘッダがあるから
* ヘッダの拡張子は、コンパイラに「このソースは C じゃなくて C++ だよ」と教えるための情報として役に立たないので区別する必要があまりないから（昔はエディタが賢くなかった）

という2つの理由から「Cと同じでいいや」という判断をしたんだと思う。

今はエディタに「このファイルは C じゃなくて C++ だよ」と教えるヒントとして役に立つので `*.h` じゃないほうが便利かもね。

# 拡張子

よく使われていると思っているものを未調査の段階で書いてみると

|拡張子|使われ方|
|:--|:--|
|`.cpp`, `.cc`, `.cxx`|ソースコード。コンパイルの対象。|
|`.h`, `hpp`, `.hh`, `.hxx`|ヘッダファイル。インクルードされる。|
|`.inl`|インライン関数の定義。マイクロソフトさんのプロジェクトなどで散見される。|
|拡張子なし|ヘッダファイル。標準ライブラリで使われる。|

あたりを見かける。

GitHub を眺めてみると、他にも

* [`.c++`](https://github.com/search?type=code&q=language%3AC%2B%2B++path%3A*.c%2B%2B) ソースコードだよね
* [`.h++`](https://github.com/search?type=code&q=language%3AC%2B%2B++path%3A*.h%2B%2B) ヘッダだよね
* [`.ipp`](https://github.com/search?type=code&q=language%3AC%2B%2B++path%3A*.ipp) C++ のモジュールらしい
* [`.ixx`](https://github.com/search?type=code&q=language%3AC%2B%2B++path%3A*.ixx) 微妙に C++ じゃない気もする
* [`.tcc`](https://github.com/search?type=code&q=language%3AC%2B%2B++path%3A*.tcc) テンプレートの定義かな
* [`.tpp`](https://github.com/search?type=code&q=language%3AC%2B%2B++path%3A*.tpp) テンプレートの定義かな

といろいろある。

## 利用者の例

軽く調べた。

|利用者|ソース|ヘッダ|
|:--|:--|:--|
|[boost / filesystem](https://github.com/boostorg/filesystem/)|`.cpp`|`.hpp`|
|[cppwinrt](https://github.com/microsoft/cppwinrt/)|`.cpp`|`.h`|
|[gtest](https://github.com/google/googletest/)|`.cc`|`.h`|
|[OpenCV](https://github.com/opencv/opencv/)|`.cpp`|`.h`|

※ 上記は例えば「boost に `.cpp` と `.hpp` があったよ」ということで、全部そうだったということではない。

という具合で、文化圏によって色々ある。

# 使い分け

以下は私見。

## ソースコード

自分で（あるいはチームで）書くソースコードは一貫して `.cpp` にするとか、 `.cc` にするとか、そういう感じがいいと思う。

サードパーティのソースコードが参加すると入り乱れることになるわけだけど、それは諦めるのが良い。

## ヘッダ

ヘッダファイルには、普通の使われ方と異常な使われ方がある。

### 普通の使われ方

普通の使われ方っていうのは
* ファイルの冒頭付近で インクルードされることが想定されている
* インクルードすると 定数関数クラスあるいはテンプレートの定義が導入される

というやつ。
普通の使われ方のものには一貫して `.h` にするとか、 `.hxx` にするとか、そういう感じがいいと思う。ソースコード側と対になるのが良さそう。

### 異常な使われ方

異常な使われ方っていうのは、例えば

https://qiita.com/Nabetani/items/5a50fd9c32425ffb2cbc

に書いたようなやつ。他にも邪悪な使い方はたくさんあるけれど

* ファイルの冒頭付近で普通に インクルードするとコンパイルエラーになりがち
* インクルードすると 定義の導入 以外のなにかが起こる

という感じのものが、異常な使われ方を想定しているヘッダファイル。
冒頭にいれるわけではないので「ヘッダ」という呼び名自体が不適切で「インクルードされるファイル」という名前が適切かと思う。

こういう輩には、ひと目見て「あ、いつものヘッダとなんか違う」とわかるような名前をつけたい。

なので拡張子は

* 邪悪さが軽微であれば、C++ のヘッダとして使われることがあるけどチーム内ではふつう使わないもの
* 邪悪さが深刻であれば、C++ のヘッダではないもの

というのがおすすめ。前述の記事の内容なら私の中では軽微なので、チーム内が `.hh` なら `.hxx` をつけるとか、それぐらいにする。

### テンプレート用とかインライン用とか

マイクロソフトさんはインライン用に `.inl` を使ったりするようだけど、私は使い分けるメリットはあまりないと思っている。

例えば テンプレートの宣言と定義を分けたければ

`hoge_decl.hpp` で宣言、`hoge_def.hpp` で定義、のようにファイル名で伝えればいいと思っている。

とはいえ、それぞれの文化や背景に合わせてお好みで。

# まとめ

* C++ のソースコード・ヘッダファイルの拡張子には色々あるよ
* 普通のヘッダである限り、用途ごとに拡張子を変える必要はないと思うよ（そうしてもいいけどお好みで）
* 異常なヘッダファイルの場合には異常性をアピールするために拡張子を変えるのがおすすめだよ
TypeScript/JavaScriptで配列の重複データを効率的に除去する

配列データの処理において、重複した値を取り除く作業はよく必要になります。今回では、TypeScriptやJavaScriptを使用して配列内の重複データを簡単かつ効率的に取り除く方法を説明します。

 ### なぜ重複除去が必要か
 
重複データを持つ配列を処理する場合、パフォーマンスや正確なデータ分析に悪影響を与えることがあります。例えば、APIから取得したデータやユーザー入力を扱う際に、意図せず重複が発生することがあります。そのため、データのクリーンアップを行うことが重要です。

### Setを使った重複除去

最もシンプルで効率的な方法は、``Set``オブジェクトを使用することです。``Set``は一意の値のみを保持するコレクションで、重複する値を自動的に除外します。

例
```javascript
const array = ['A', 'B', 'A', 'C', 'B'];
const uniqueArray = Array.from(new Set(array));

console.log(uniqueArray); // 結果: ['A', 'B', 'C']
```

配列がプリミティブ型（文字列や数値など）の値を持つ場合に非常に有効です。``Set``は重複を自動的に削除するので、シンプルかつパフォーマンスも高いです。

### filter() と indexOf() を使った方法

``filter()``メソッドと``indexOf()``を組み合わせて、重複データを除去することも可能です。この方法は、カスタムロジックを追加したい場合やSetを使えない場合に有効です。

例
```javascript
    const array = ['A', 'B', 'A', 'C', 'B'];
    const uniqueArray = array.filter((value, index, self) => {
      return self.indexOf(value) === index;
    });

    console.log(uniqueArray); // 結果: ['A', 'B', 'C']
  ```
  
``indexOf()``は配列内の特定の要素が最初に出現するインデックスを返します。``filter()``と組み合わせることで、最初に出現した要素だけを保持し、重複を取り除きます。

### オブジェクト配列の重複データを除去する

オブジェクトを含む配列の重複除去には、少し異なるアプローチが必要です。オブジェクト同士の比較は、プリミティブ型とは異なり、``Set``では直接扱えないため、カスタムロジックを使ってユニークな値を抽出する必要があります。

例
```javascript
const data = [
  { name: 'D', description: 'D' },
  { name: 'A', description: 'A' },
  { name: 'E', description: 'E' },
  { name: 'E', description: 'E' }
];

const uniqueData = data.filter((item, index, self) => 
  index === self.findIndex((t) => t.name === item.name && t.description === item.description)
);

console.log(uniqueData);
// 結果: [{ name: 'D', description: 'D' }, { name: 'A', description: 'A' }, { name: 'E', description: 'E' }]

```

このコードでは、``findIndex()``を使って、配列の中で最初に出現したオブジェクトのみを保持し、同じ``name``と``description``を持つオブジェクトの重複を排除しています。この方法を使えば、オブジェクト内のプロパティを基準にして重複を除去することができます。

### TypeScriptでの型安全な重複除去

TypeScriptでは、上記の方法を型安全に実装することで、より堅牢なコードを書くことができます。型を使って、扱うデータの構造を定義することが推奨されます。

例
```javascript
interface Item {
  name: string;
  description: string;
}

const data: Item[] = [
  { name: 'D', description: 'D' },
  { name: 'A', description: 'A' },
  { name: 'E', description: 'E' },
  { name: 'E', description: 'E' }
];

const uniqueData = data.filter((item, index, self) => 
  index === self.findIndex((t) => t.name === item.name && t.description === item.description)
);

console.log(uniqueData);
```

TypeScriptでは、``Item``インターフェースを使用してデータの構造を明示的に定義しています。これにより、コードの可読性が向上し、型エラーを防止できる。
    
### 最後

重複データを除去する際、配列のサイズが大きくなると、パフォーマンスが問題になることがあります。一般的に、``Set``を使った方法は高速ですが、``filter()``や``findIndex()``を使った方法は配列が大きくなるほど処理時間が増加する。

特に、オブジェクトの比較では、``filter()``＋``findIndex()``の方法が計算量が大きくなる可能性があります。大規模なデータセットを扱う場合は、Mapを使った方法なども検討するとよいでしょう。
VercelとWordPressのWebhookでの再ビルド問題を解決する方法

## 課題

WordPressからWebhookを利用して記事の追加や更新を行った際、Vercelが再ビルドを実行していました。しかし、新規記事の追加は正常に行えるものの、**既存記事の更新が反映されない**という問題が発生しました。Vercelでの再ビルドは成功しているのに、更新が反映されない原因を解明する必要がありました。

## 仮説

更新が反映されない理由として、次の仮説が立てられました。

- **記事の追加**は、まだVercel側にキャッシュが存在しないため、問題なく処理される。
- 一方で、**記事の更新**は既にキャッシュに保存されているデータを参照しているため、再ビルド時にキャッシュから情報が引き出され、変更が反映されない可能性がある。

このため、再ビルドの際に**キャッシュを消去**すれば、更新も正常に反映されるはずだと考えました。

## 解決策

仮説に基づき、Vercelのビルド時にキャッシュを消去する設定を追加することにしました。

### 1. ビルドスクリプトのカスタマイズ

Vercelは、デプロイ時に `package.json` の `scripts.build` セクションに記載されたコマンドを実行します。デフォルトでは `next build` コマンドが使われますが、これではキャッシュがそのまま残ります。

そこで、**キャッシュを削除してからビルドする**ために、以下のように `package.json` の `build` スクリプトを変更しました。

```json
"scripts": {
  "build": "rm -rf .next && next build"
}
```
## 2. キャッシュ削除の効果

この変更により、Vercelは再ビルドのたびに `.next` フォルダ（ビルドキャッシュが保存される場所）を削除し、その後クリーンな状態で `next build` を実行します。これにより、キャッシュされた古いデータではなく、最新のWordPressの記事内容を基にしたビルドが行われるようになります。

## 結果

この対応を行った結果、Vercelでの再ビルド時に**新規記事の追加と更新の両方が正しく反映**されるようになりました。キャッシュの削除が機能したことで、更新がスムーズに行われ、WordPressからのWebhook経由での記事管理も効率的に動作するようになりました。

## まとめ

WordPressからのWebhookを使ったVercelでの自動ビルドでは、**キャッシュが問題**となる場合があります。特に、記事の更新が反映されない場合は、キャッシュが原因で古い情報がビルド時に使われている可能性が高いです。`package.json` のビルドスクリプトにキャッシュ削除コマンドを追加することで、こうした問題を解決し、正しく更新を反映させることができます。
文字化けはなぜ起こる？

## きっかけ
とある実装を任され、RFCを読み漁る中で、文字コードに対する関心が深まりました。日常的な業務ではそれほど深く理解していなくても、なんとかなってしまう場面が多いですが、学べる時に学んでおいて損はないなと思ったのがきっかけです。

文字コードとは？のような用語の説明はしません。文字コードの変換プロセスに焦点を当てて説明しています。

## 文字コードはシンプル
コンピュータは人間の文字をそのまま理解することはできないので、内部で文字を数字に変換しています。例えば「あ」を入力するとコンピュータでは以下のような２進数に変換されます。

```
あ -> 11100011 10000001 10000010
```

コンピュータは0か1しかわからないので、2進数に変換する必要がありますが、それだと人間にとって冗長でわかりにくく、効率的ではないので、16進数として表現します。

```
あ -> 11100011 10000001 10000010 → E3 81 82
```

この「文字」と「バイト列」の対応関係を「文字コード」と呼びます。

## 変換の流れ
まず、「あ」を入力すると、Unicode のコードポイントに変換されます。

```
入力:「あ」
     ↓
コードポイント: U+3042（Unicode）
```

次にコードポイントを2進数に変換します。ユニコードのコードポイント U+3042 は16進数で表現されますが、コンピュータでは2進数として扱われます。U+3042 を2進数に変換すると以下のようになります。

```
コードポイント: U+3042
     ↓
2進数: 0011 0000 0100 0010
```

次にこの2進数データを UTF-8 などのエンコード方式に基づいてバイト列に変換します。UTF-8 ではコードポイントが次のようにエンコードされます。

```
2進数: 0011 0000 0100 0010
     ↓
UTF-8バイト列:
- 1バイト目: 11100011 (E3)
- 2バイト目: 10000001 (81)
- 3バイト目: 10000010 (82)
     ↓
バイト列: E3 81 82
```

## 文字化けが発生する流れ
### 正常な場合
```
バイト列: E3 81 82
     ↓
UTF-8デコード:
- 1バイト目: 11100011 (E3)
- 2バイト目: 10000001 (81)
- 3バイト目: 10000010 (82)
     ↓
2進数: 0011 0000 0100 0010
     ↓
コードポイント: U+3042
     ↓
表示: 「あ」
```

### 文字化けが発生する場合

```
バイト列: E3 81 82 (UTF-8)
     ↓
デコード (Shift-JIS)
     ↓
無効なバイト列として解釈
     ↓
表示: 「�」や「?」（文字化け）
```

## まとめ
文字コードの歴史は長く、さまざまな背景や、規格の乱立などの変遷があって成り立っていることを、調べていく中で知れました。

スタンダードな技術を学んだとしても実務で即役立つわけではないですが、変わらない普遍的な技術を学び、根幹を知ることはエンジニアとして大切なことだと思っているので、今後も引き続き学んでいければと思いました。
sortの仕組みを整理した (JavaScript)

業務では、配列のソートはlodashを使うのですが、細かく条件を入れてソートしたい時はsortメソッドの方が便利です。そこで、今一度このsortの仕組みを整理してみました。

## sortメソッドとは
配列に対して、順番に２個ずつ要素を取り出して計算/比較した結果を**正もしくは負の数**で返す事で並び替えをしてくれる。
```javascript
[ARRAY_DATA].sort((a, b) => ここでa, bを計算,比較して,正か負の数を返す)
```

**並び替えの仕組み：**
結果が**正** → 第一引数 a を 第二引数 b の後に並べる → [b, a]
結果が**負** → 第一引数 a を 第二引数 b の前に並べる → [a, b]

実際に見ていきましょう、本記事内のコードは以下のサンプルデータを使っています。
```javascript
// サンプルデータ
// *startDateは本来UNIXタイムスタンプですが、便宜上わかりやすくしてます。
const arr = [
  { eventName: "イベントB", startDate: 3, round: null },
  { eventName: "イベントA", startDate: 5, round: null },
  { eventName: "イベントC", startDate: 3, round: 1 },
  { eventName: "イベントD", startDate: 4, round: 2 },
  { eventName: "イベントE", startDate: 1, round: null },
]
```

### sortの書き方(1) 第一引数と第二引数の差で判定

##### 昇順(データを小さい順に並べる)の場合
```javascript
arr.sort((a, b) => a.startDate - b.startDate)
```
aがbより小さい場合、負の数になるので、並び替えの仕組みの以下が適用される
`結果が負 → 第一引数a を 第二引数b の前に並べる → [a, b]`

![スクリーンショット 2024-09-21 13.46.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/a648d475-6c0c-4ffc-d529-f7b757ffc286.png)


##### 降順(データを大きい順に並べる)の場合
```javascript
arr.sort((a, b) => b.startDate - a.startDate)
```

bがaより大きい場合、正の数になるので、並び替えの仕組みの以下が適用される
`結果が正 → 第一引数 を 第二引数 の後に並べる → [b, a]`

![スクリーンショット 2024-09-21 13.46.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/ebe9e1fb-559e-7e4d-eebe-a9afd4a19d01.png)


### sortの書き方(2) 第一引数と第二引数を比較して、正、負の数を返す
昇順(データを小さい順に並べる)の場合
```javascript
arr.sort((a, b) => a.startDate < b.startDate ? -1 : 1)
```

aがbより小さい場合、-1を返すので、並び替えの仕組みの以下が適用される
`結果が負 → 第一引数a を 第二引数b の前に並べる → [a, b]`

降順(データを大きい順に並べる)の場合
```javascript
arr.sort((a, b) => a.startDate < b.startDate ? 1 : -1)
```

bがaより大きい場合、正の数になるので、並び替えの仕組みの以下が適用される
`結果が正 → 第一引数 を 第二引数 の後に並べる → [b, a]`

*この様に比較演算子を変えても同じ条件になります
`arr.sort((a, b) => a.startDate > b.startDate ? -1 : 1)`

### なぜ 1 と -1 なのか？
**正数か負の数か**を返せばいいので、必ずしも`1, -1`である必要はなく、`23, -25`などどんな数字でも結果は同じですが慣例的に 1, -1が使われています。

### 細かいソートルールを適用させる
サンプルデータの配列は各ObjectにstartDateという開始日の情報を持ってるので、それを昇順、降順で並び替えるのは前述の通りです。

ただ、startDateが同じデータが存在する事もあり得るので、その場合はroundを見て、roundがある方を上にしたいという要件があったとします。そういう細かいソートルールを適用させる時の実装をしてみます。

今回のサンプルデータだと、イベントBとCが同じstartDateで、Cがround値を持っているので、Cを上にしたい。という事になります。

```javascript
arr.sort((a, b) => {
  // 同じstartDateだった場合
  if (a.startDate === b.startDate) {
    // aにround値があれば上にしたいので、負の数を返す
    return a.round ? -1 : 1
  }
  // 降順にするので、b - a を実行
  return b.startDate - a.startDate
  // これでも同じです
  // return a.startDate < b.startDate ? 1 : -1
})
```

上記の結果はこの様になり、イベントCが上に来てるのがわかると思います。

![スクリーンショット 2024-09-21 13.45.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/758f898c-f822-7712-e360-434e7470752e.png)


参考：MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
leanbackライブラリにおけるViewBinding化の注意点

# leanbackライブラリにおけるViewBinding化の注意点

## 結論


``` kotlin
class SampleVideoFragment : RowsSupportFragment() {
    private var _binding: FragmentSampleVideoBinding? = null
    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!
    private var _adapter: ArrayObjectAdapter = ArrayObjectAdapter(RowPresenterSelector())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        adapter = _adapter
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // これを追加
        super.onCreateView(inflater, container, savedInstanceState)
        // これを追加

        _binding = FragmentSampleVideoBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val data = ( 1..100).map {
            CustomCardRow(it)
        }
        _adapter.add(data)
        
        val gridView = CustomGridView()
        verticalGridView.addView(gridView)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}
```

[参考]
- https://developer.android.com/topic/libraries/view-binding?hl=ja

## なぜか

ViewBindingを行う場合、通常は`super.onCreateView()`を書かないことが多いです。

このverticalGridViewをSampleVideoFragmentからアクセスするとnullエラーになってしまいます。

RowsSupportFragmentの親クラスであるBaseRowSupportFragmentのonCreateView()にmVerticalGridViewと呼ばれるGridViewのメンバ変数があり、onCreateView()で初期化しています。

そのため、onCreateView()にて、親クラスのonCreateView()をコールする必要があります。
Azureのストレージについて

Azureのストレージについて自分用にまとめたかったので備忘録として書きました。


# Blob Storage 

テキストデータやバイナリデータなどの大量の非構造化データを格納するために最適なもの


# Azure Files

サーバーメッセージブロック(SMB)プロトコル、ネットワークファイルシステム(NFS)プロトコル、および AzureFilesRESTAPIを介してアクセスできる高可用性ネットワークファイル共有を設定できるもの
【覚書き】Gitのoriginってなんなんだ

# 初めに
GitをCLI操作し始めてから、`origin`って単語をよく目にするようになりました。
最近ようやく意味を知ったので備忘としてアウトプットします。

# originとは
Gitでブランチをチェックアウトする時、`git checkout`コマンドを使用します。

```sh
$ git checkout -b testBranch origin/testBranch
```

`-b`の後が「作成するローカルブランチの名前」と「リモートブランチの名前」なのですが、ここで指定する`origin`がよく分かっていませんでした。

# 前提：ローカルリポジトリは複数のリモートリポジトリと紐づけることが可能
前提としてローカルリポジトリは複数のリモートリポジトリを紐づけることが可能です。

`git remote -v`のコマンドで現在紐づいている一覧を見ることができます。

```sh
$ git remote -v
another https://github.com/username/gitTest2.git (fetch)
another https://github.com/username/gitTest2.git (push)
origin  https://github.com/username/gitTest.git (fetch)
origin  https://github.com/username/gitTest.git (push)
```
この例では、`gitTest.git`と`gitTest2.git`という二つのリポジトリが紐づいていますね。

# originとはデフォルトのリモートリポジトリのエイリアス
もうお分かりの方もいるかと思いますが、`origin`とは**デフォルトのリモートリポジトリのエイリアス**です。

ローカルリポジトリをリモートリポジトリに紐づける際、各リモートリポジトリにエイリアスを設定することができます。そのデフォルトが`origin`というわけです。

通常の`git clone`をした場合、`origin`というエイリアスで登録されます。
```sh
$ git clone https://github.com/username/gitTest.git
$
$ git remote -v
origin https://github.com/username/gitTest.git (fetch)
origin https://github.com/username/gitTest.git (push)
```

`clone`時に `--origin`オプションを利用することで、エイリアスを指定することもできます。
```sh
$  git clone --origin another https://github.com/username/gitTest2.git
$
$ git remote -v
another https://github.com/username/gitTest2.git (fetch)
another https://github.com/username/gitTest2.git (push)
```

ちなみに、git remote addでリモートを紐づける際は、必ずエイリアスの指定が必要です。originの場合も同様です。

```sh
$ git remote add origin https://github.com/username/gitTest.git
$
$ git remote -v
origin  https://github.com/username/gitTest.git (fetch)
origin  https://github.com/username/gitTest.git (push)
```


# originは何に使うの
前述の通り、`origin`はデフォルトのリモートブランチを指定するためのエイリアスです。
リポジトリの指定が必要なコマンドを使用する際にその効果を発揮します。

例えば、`fetch`などですね。

```sh
$ git fetch           ← git fetch originと同義
$
$ git fetch another   ← 通常はリモートリポジトリのエイリアスを指定する
```

# 終わりに
ということで本日は`Git`の`origin`について書きました。
GUI使ってると意識しなくてもできたので気にしてなかったですが、コマンドで操作する際は気になりますよね。
今後も気になったものは調べていこうと思います。
GuardDutyの検出結果の通知を重要度の高いものに絞りたい！

### :sunny: 実現したいこと：GuardDutyの検出結果に関して、通知がたくさん来てしまうので重要度が低いものは通知しないようにしたい

 
## 前提：GuardDutyの重要度とは？
GuardDutyは検出結果の重要度が3つのレベル（High,Medium,Low）に分かれています。
以下のページに記されています。

https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/guardduty_findings.html

```
[High] (高)　　  7.0-8.9
[Medium] (中)　　4.0-6.9
[Low] (低) 　　　1.0-3.9
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/4495e813-cda9-ce30-e69f-26552698d46d.png)



### 重要度の高いものだけ通知させる方法
EventBridgeのイベントパターンで「カスタムパターン（JSONエディタ）」を選択し、以下のように設定

```
{
  "source": ["aws.guardduty"],
  "detail-type": ["GuardDuty Finding"],
  "detail": {
    "severity": [{
      "numeric": [">=", ＜通知を出したい値＞]
    }]
  }
}
```
:::note info
重要度「中」以上の場合は通知させたい場合
:::
```
# 例)重要度「中」以上の場合は通知させる
{
  "source": ["aws.guardduty"],
  "detail-type": ["GuardDuty Finding"],
  "detail": {
    "severity": [{
      "numeric": [">=", 4]
    }]
  }
}
```
:::note info
重要度「高」の場合は通知させたい場合
:::
```
# 例)重要度「高」の場合は通知させる
{
  "source": ["aws.guardduty"],
  "detail-type": ["GuardDuty Finding"],
  "detail": {
    "severity": [{
      "numeric": [">=", 7]
    }]
  }
}
```
EventBridgeの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/30ea288c-913f-164a-a042-6e7fed42d9bb.png)
【株式会社ワクト】インターン体験談

# 目次
1. [自己紹介](#自己紹介)
1. [インターン先](#インターン先)
1. [メンバー](#メンバー)
1. [インターンに応募した理由](#インターンに応募した理由)
1. [インターンをして得られたもの](#インターンをして得られたもの)
1. [成作物](#成作物)
1. [まとめ](#まとめ)

# 自己紹介
武蔵野大学データサイエンス学部3年の渡邊はるなです。
プログラミングは大学から始めました。

# インターン先
[株式会社ワクト](https://www.wakuto.net/)
qiita：https://qiita.com/organizations/wakuto-inc

# メンバー
武蔵野大学データサイエンス学部3年：渡邊はるな（わたなべはるな）
武蔵野大学データサイエンス学部3年：垣谷明宏（かきたにあきひろ）
武蔵野大学データサイエンス学部3年：松原清志郎（まつばらきよしろう）

# インターンに応募した理由
大学の合同企業説明会でインターンの説明を聞き、興味を持ったためです。
興味を持った理由は、普段グループワーク中心の授業を受けているので、それが企業ではどのように活用できるかを知りたいからと、今まで成作物を複数人で真面目に作る経験がなかったのでやってみたいと思ったからです。

# 具体的な業務内容
- 期間：2024/9/4(水)～9/12(木）・9/20(金) の8日間
- 勤務時間：10:00～17:00　※1日6時間の稼働/休憩1時間
- 実習時間：45時間

グループワークを用いたビジネス創成(開発あり)
Project-Based Learning(課題解決型学習)を用いてビジネスモデルの発案から
実際に設計・実装・テスト・チーム発表までの一連業務を短期間で模擬体験する。


<details>
<summary><b>実際に私が担当した業務内容</b></summary>
<div>

- アイデア出し、ペルソナ設定、ビジネスモデル図作成、収益予測、イメージ図・スライド作成
- サイト見た目の作成（HTML, CSS, Bootstrap）、サイト名決定（FestiMap）
- ページデザインの調整、追加フォーム作成、全ページ結合
- GitHubへのプッシュ、ログインページ作成、ロゴ作成、スライド作成
- 階層整理、パス調整、イベント追加フォームデザイン、スライド作成
- スライド調整、追加イベント情報表示（未完）、テスト項目の洗い出し

～～～展開ここまで～～～

</div>
</details>


# インターンをして得られたもの
- チームでの開発の難しさ・楽しさ
- Bootstrapの使用方法
- GitHubを使ったバージョン管理の難しさと重要性

今回のインターンを通じて、今まで感じていたプログラミングに対する苦手意識を少し克服することができました。特に、チームで何かを真剣に作るという経験が初めてだったため、グループ作業の難しさや楽しさを実感しました。フロントエンドでは主にBootstrapを使用して見た目の作成に取り組みましたが、苦手意識を持っていたBootstrapやデータベース操作においても、目的を明確にし、チームで協力し合うことで、プログラミングを通じてものを作る楽しさを学ぶことができました。

アイデア出しからテストまでの一連の流れを経験し、チームで一つのプロジェクトを進める際の大変さや、GitHubでのコンフリクトの解決や認識のずれを調整することの重要性に気づきました。一方で、わからないことをお互いに聞き合ったり、一緒に考えたりする過程で生まれる楽しさや、何かを達成したときの喜びをチームメンバーと共有できたことは、とても貴重な経験となりました。

特に感じたのは、グループ作業では定期的に認識をすり合わせることの重要性です。ペルソナを作成することで、発表内容がわかりやすくなることも学びました。また、初めてフレームワークを使った経験は非常に便利で、テンプレートの力を実感し、PHPやデータベースに対する苦手意識も少しずつ解消されていきました。GitHubやSourceTreeの操作には苦戦しましたが、チーム作業の中で徐々に理解が深まりました。

さらに、DBは全員がアクセスできる場所に配置することの重要性や、テスト段階での複数環境での確認作業の重要性なども学びました。このインターンを通して、技術的なスキルだけでなく、チームでの協力の大切さやコミュニケーションの重要性についても深く理解できたと感じています。

# 成作物
地方自治体のイベントをまとめたサイトを作成しました。

https://gms.gdl.jp/~kiyoshioz//haooy_copy/FestiMap/index.html

<details>
<summary><b>フィードバックを受けて直すべきだと感じたところ</b></summary>
<div>

- 市町村選択の画面で、読み仮名をつけないとわからない人もいるから、ルビを振る
- 海外に行こうとする観光客に対してどうアピールしていくかを考えるべき
- 

～～～展開ここまで～～～

</div>
</details>


# まとめ
最終日にワクトの社員約50名の前で発表をして、フィードバックをいただきました。
今回のインターンで、自分に足りないなと感じた技術（フロントエンド・バックエンドの技術）を今後向上させていけたらいいなと思っています。

今回の経験で、実際に世の中に出す想定でアプリを考える大変さ（利益はどう得るかなど）を知れたので、今後生活していく中で身の回りのアプリやサービスを見る目が変わったと思います。

毎回のお昼や最終日の懇親会でワクトの社員さんと話して、どの社員さんも優しいし、趣味を持っている人が多くて、楽しい会社だなと感じました。

また何か関われたらいいなと思いました。
ファインチューニングと転移学習：AIや機械学習における重要な手法

AIや機械学習において「ファインチューニング」と「転移学習」は非常に重要な技術です。本記事では、この2つの手法の概要と違いについて解説します。

## ファインチューニングとは

ファインチューニングは、事前に学習されたモデルに対して手元のデータを使い、モデルのパラメータを再調整することで、特定のタスクに適応させる手法です。

### ファインチューニングのメリット

大量のデータを必要とするAIの学習に比べ、ファインチューニングでは事前学習済みのモデルを利用するため、以下のメリットがあります。

- **費用や時間の削減**: モデルを一から作る必要がないため、コストと時間が大幅に減少します。
- **特定タスクへの適応**: モデルを特定のタスクに最適化できます。

### 具体例

例えば、日本人の顔を分類するために事前に学習されたモデルを、アメリカ人の顔分類に適応させる場合を考えてみましょう。

- **下位層**: 顔の輪郭などの一般的な特徴は固定。
- **上位層**: 顔の特徴的なパーツ（目、鼻など）を新しいデータで再調整。

このように、基本的な特徴を保持しながら、新しいデータでモデルを適応させることが可能です。

## 転移学習とは

転移学習は、あるタスクで得た知識を他のタスクに適用する手法の総称です。ファインチューニングも転移学習の一種で、特定のタスクに最適化する際によく使用されます。

### ファインチューニングと転移学習の違い

転移学習は他のタスクで得た知識を活用するアプローチ全体を指し、ファインチューニングはその中でも特定のタスクに適応させるための一手法です。

- **ファインチューニング**: 既存モデルを再学習して、パラメータを調整。
- **転移学習（ファインチューニングなしの場合）**: 別のタスクに対して新たにモデルを作成し、タスクAで得た知識をタスクBに適用。

## まとめ

ファインチューニングと転移学習は、AIや機械学習の分野で効率的なモデル開発を可能にする重要な手法です。特にファインチューニングは、既存のモデルを活用し、費用と時間を大幅に節約しながら特定のタスクにモデルを最適化する強力な方法です。

---
Proxmox で autoremove したら、proxmox-ve も削除された

## 何が起きたか

極めて一時的な事象だったのですが、Proxmox で `apt autoremove` すると、`proxmox-ve` が削除されるようになっていました。😲

以下がその時に表示された警告メッセージです。

```shell
Use 'sudo apt autoremove' to remove them.
The following packages will be REMOVED:
  proxmox-ve pve-manager

W: (pve-apt-hook) !! WARNING !!
W: (pve-apt-hook) You are attempting to remove the meta-package 'proxmox-ve'!
W: (pve-apt-hook)
W: (pve-apt-hook) If you really want to permanently remove 'proxmox-ve' from your system, run the following command
W: (pve-apt-hook)       touch '/please-remove-proxmox-ve'
W: (pve-apt-hook) run apt purge proxmox-ve to remove the meta-package
W: (pve-apt-hook) and repeat your apt invocation.
W: (pve-apt-hook)
W: (pve-apt-hook) If you are unsure why 'proxmox-ve' would be removed, please verify
W: (pve-apt-hook)       - your APT repository settings
W: (pve-apt-hook)       - that you are using 'apt full-upgrade' to upgrade your
```

GUI でアクセスできなくなったので、やってはいけないことをやってしまったことに気付き 😱、`ssh` で Proxmox に接続し、再度 `proxmox-ve` と `pve-manager` をインストールしました。

## 現状はどうなっているか

2024 年 6 月 17 日のみに発生したようで、現時点では `apt autoremove` しても `proxmox-ve` が削除されることはありません。

https://forum.proxmox.com/threads/upgrading-pve-tries-to-remove-proxmox-ve-package.149101/

https://forum.proxmox.com/threads/apt-wants-to-remove-proxmox-ve-during-update.149103/
[Cloudflare + Next.js] 25.0 MiBのサイズ上限を超えてデプロイできない

## Generated Pages Functions bundle size (30000000) is over the limit of 25.0 MiB

Next.jsのプロジェクトをCloudflare Pagesにデプロイしようとしたところ、25.0MiBのサイズ制限を超えたため、デプロイに失敗してしまいました。

## 原因はSentry.io

バンドルファイルのサイズを調べていく中で、このissueに行き当たりました。

[[🐛 Bug]: Sentry bloats up bundle size when building with npx @cloudflare/next-on-pages #860](https://github.com/cloudflare/next-on-pages/issues/860)

今回デプロイしていたサービスでは、エラートラッキングにSentry.ioを使っていましたが、どうやら`Sentry.io`と`cloudflare/next-on-pages`の間に問題があり、ファイルサイズが大きくなってしまったようです。

## ひとまず、Sentry.ioを外す

手元では解決が難しそうだったので、ひとまずSentry.ioを外しました。無事にファイルサイズが小さくなりデプロイも成功しました。
Sentry.ioを使えなくなったのは残念ですが、デプロイができないことの方が大きな問題と感じます。

## 最後に
同じような問題の報告は（少なくとも日本語では）あまり見かけなかったので、この記事が誰かの参考になれば嬉しいです。

### 参考文献
- [Build failed: Generated Pages Functions bundle size is over the limit of 25.0 MiB](https://community.cloudflare.com/t/build-failed-generated-pages-functions-bundle-size-is-over-the-limit-of-25-0-mib/705892)
- [Limits | Cloudflare Pages docs](https://developers.cloudflare.com/pages/platform/limits/#file-size)
- [Next.js with deploy to Cloudflare Pages failed, due to limit of 25 MB, after adding Sentry
#13723](https://github.com/getsentry/sentry-javascript/issues/13723)
【AWS CLI】セキュリティグループのルールで一つのポートに対して複数IPを登録したい！

### :sunny: この記事で得られること：セキュリティグループのルールをCLIで登録する方法

## 例えば…
セキュリティグループの設定でこんなことありますよね

ポート：3389　
送信元：10.0.1.0/32 , 10.0.2.1/32 , 10.0.3.0/28...（残り何十個とか...）

## マネコンだと一つのポートへ複数IPをいっぺんに設定できないのです！！:cry:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/f1422e2c-ab6d-22fd-bc99-7925f16562cf.png)
果てしない作業...
 

### そこで！セキュリティグループにルールを一括で登録するCLIを使ってみましょう！


:::note info 
前提知識
:::
```
#セキュリティグループのルールを出力するコマンド
ec2 describe-security-group-rules

# インバウンドルールを変更するコマンド
ec2 authorize-security-group-ingress

# アウトバウンドルールを変更するコマンド
ec2 authorize-security-group-egress

# 1つのポートに対して単一のIPアドレスのインバウンドルールを登録するCLI
aws ec2 authorize-security-group-ingress \
--group-id ＜セキュリティグループのID＞ \
--ip-permissions IpProtocol=＜プロトコル＞,FromPort=＜ポート番号＞,ToPort=＜ポート番号＞,\
IpRanges='[{CidrIp=＜送信元IPアドレスのCIDR＞,Description="＜説明内容＞"}]'
```


:::note info
1つのポートに対して複数のIPアドレスのインバウンドルールを登録するCLI
:::
```
aws ec2 authorize-security-group-ingress \
--group-id ＜セキュリティグループのID＞ \
--ip-permissions IpProtocol=＜プロトコル＞,FromPort=＜ポート番号＞,ToPort=＜ポート番号＞,\
IpRanges='[{CidrIp=＜送信元IPアドレスのCIDR＞,Description="＜説明内容＞"},{CidrIp=＜送信元IPアドレスのCIDR＞,Description="＜説明内容＞"}]'
```


## 実際に当てはめて使ってみる
今回は何もインバウンドルールが入っていない「Test-SG」を用意し、CLIを流してみます！
※プロトコルはTCP、ポートは3389を想定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/6e0cba28-cf63-24d5-3214-5ffc7f297739.png)


先程のCLIに当てはめると以下のようになります↓
※セキュリティグループのIDはセキュリティ観点から埋め込んでいません。
```
aws ec2 authorize-security-group-ingress \
--group-id ＜セキュリティグループのID＞ \
--ip-permissions IpProtocol=TCP,FromPort=3389,ToPort=3389,\
IpRanges='[{CidrIp=10.0.1.0/32,Description="CLI test"},{CidrIp=10.0.2.1/32,Description="CLI test"},{CidrIp=10.0.3.2/28,Description="CLI test"}]'
```


実際に追加されていることが確認できました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/3788f782-2543-82d6-2064-b866dd93ce7a.png)
Unity Assetの作成手順ガイド

## UnityでAssetを作成する方法

Unity Assetは、ゲームやアプリを作るための「素材」や「部品」です。このガイドでは、UnityでAssetを作る手順を、初心者向けに分かりやすく説明します。

### 1. Assetって何？

Asset（アセット）は、ゲームやアプリを作るための素材のことです。たとえば、次のようなものが含まれます。

- **3Dモデル**: ゲームの中に出てくるキャラクターや物の形。
- **テクスチャ**: モデルに貼り付ける「絵」や「模様」。
- **音（オーディオクリップ）**: 効果音や音楽。
- **プログラム（スクリプト）**: ゲームの中で「動き」や「反応」を作るためのコード。

これらを組み合わせて、ゲームの中で使えるものを作ります。

### 2. 新しいAssetを作る手順

#### ステップ 1: プロジェクトを作る
まず、Unityを開いて新しいプロジェクトを作ります。プロジェクト名をつけて、3Dや2Dのどちらかを選んでスタートしましょう。

#### ステップ 2: フォルダーを作る
プロジェクトの中に「Asset」を入れるフォルダーを作ります。これで作ったものを整理しておけます。
- 例: `Assets/MyAssets`

#### ステップ 3: Assetを作ろう
1. **3Dの形を作る**  
   `GameObject` → `3D Object`を選んで、Cube（四角形）やSphere（球）を作ります。これが3Dモデルです。モデルを選んで、大きさや位置を自由に調整できます。

2. **絵や模様を貼る（テクスチャ）**  
   自分で作った画像をAssetフォルダーに入れて、それを3Dモデルに貼り付けます。こうすることで、ただの四角いCubeもカラフルなオブジェクトに変わります。

3. **動きをつける（スクリプト）**  
   スクリプトというプログラムを作って、オブジェクトに動きをつけます。たとえば、オブジェクトが回転するスクリプトはこんな感じです。

```csharp
using UnityEngine;

public class RotateObject : MonoBehaviour
{
    public float rotationSpeed = 10f;

    void Update()
    {
        transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime);
    }
}
```

このスクリプトをCubeに適用すると、Cubeがくるくる回転します。

#### ステップ 4: Assetの設定
作ったAssetの「性質」を細かく設定できます。たとえば、物理的にどう動くか（重さやバウンドするかなど）を決めることができます。

### 3. 作ったAssetをエクスポートする方法

作ったAssetは他のプロジェクトでも使えるように「パッケージ」として保存できます。

#### ステップ 1: エクスポートするAssetを選ぶ
使いたいAssetをすべて選んで、`Assets` → `Export Package`をクリックします。

#### ステップ 2: パッケージとして保存する
どの素材をパッケージに含めるかを選んで`Export`をクリックすると、Unityパッケージファイル（.unitypackage）として保存されます。

### 4. Assetを他のプロジェクトで使う

作ったAssetは、他のUnityプロジェクトに「Import Package」で簡単に追加して再利用することができます。
shadcnのSliderで値が変更できない

# はじめに

shadcnを使って値を更新するのに時間がかかったのでまとめておきます

# 問題

以下のコンポーネントを利用して値の更新を実装しました。

https://ui.shadcn.com/docs/components/slider

```tsx
<Slider
  defaultValue={[150]}
  max={1000}
  step={50}
  onChange={(value: number[]) => setWordCount(value[0])}
/>
```

しかしなぜか値は更新できずChatGPTに聴いても上手く活きませんでした

# 解決方法

`onValueChange`を使うことで更新が可能です

```tsx
                    <Slider
                      defaultValue={[150]}
                      max={1000}
                      step={50}
                      onValueChange={(value) => setWordCount(value[0])}
                    />
```

# おわりに
独自の名前にするならドキュメントに書いてほしいなと思ってしまいます。

# 参考

https://github.com/shadcn-ui/ui/issues/170
AIに勉強の指針を聞いた。

これから勉強するものは、数学検定か漢字検定か迷ったので、Chat-GPTに聞いてみた。
<hr>

# 自分
数学検定か漢字検定か勉強するものが決まらないときどうしたらいいのか教えて　マークダウン記号そのままに出力して

# ChatGPT
数学検定と漢字検定のどちらを勉強するか迷っているときに、決断をサポートするための方法をいくつかご紹介します。

## 1. 目標や必要性を再確認する
<li>短期的な目標: まず、自分の今の生活やキャリアにおいて、どちらのスキルがすぐに役立つかを考えます。例えば、ビジネスや日常で文章を書く機会が多いなら、漢字検定が役立つかもしれません。一方、工学系や技術職を目指しているなら、数学検定の方が長期的なメリットが大きいです。</li>
<li>長期的な目標: どちらのスキルが将来の夢や目標に最も役立つかを考えてみてください。たとえば、データ解析や技術職を目指すなら数学、教育や文章作成の分野で働きたいなら漢字が役立つでしょう。</li>

## 2. 興味と楽しさを優先する
<li>興味のある方を選ぶ: 学ぶこと自体を楽しむことができる分野を選ぶことは、継続的な学習のために非常に重要です。数学の問題を解くのが楽しいと感じるなら数学検定、漢字や日本語に興味があるなら漢字検定を選ぶと良いでしょう。</li>
<li>楽しく続けられるかどうか: 試験勉強は継続力が必要です。どちらの学習に取り組んでいても楽しく感じられるか、モチベーションが保てるかを考えてみてください。</li>

## 3. 学習の時間や負担を考える
<li>学習時間の見積もり: どちらの勉強にどれくらいの時間を割けるかを考えます。たとえば、数学検定2級は、数学的な基礎が必要で、一定の学習時間が求められます。一方、漢字検定は日々の生活の中で少しずつ覚えることができるかもしれません。</li>
<li>負担の軽い方を選ぶ: 今の生活状況や体調を考慮して、無理なく続けられる方を選びましょう。漢字の勉強は日常生活で取り入れやすいので、負担が少ないかもしれません。</li>

## 4. 小さなテストや試験を実施してみる
<li>模擬テストを受けてみる: 数学検定や漢字検定の模擬試験や練習問題を実際に解いてみて、自分がどちらに手応えを感じるかを確認しましょう。どちらの方が現在のスキルレベルに合っているかを体感できます。</li>
<li>感覚的に合う方を選ぶ: 実際に問題を解いてみると、自分がどちらにより楽しさや手応えを感じるかが明確になることがあります。試してみて、感覚的に合う方を選ぶのも良い方法です。</li>

## 5. 友人やメンターに相談する
<li>他者の意見を聞く: 家族や友人、あるいは先生やメンターに相談してみるのも一つの方法です。外からの視点でアドバイスをもらうことで、新たな考え方が見つかることがあります。</li>

## 6. 一時的に両方を試してみる
<li>両方を少しずつ進めてみる: 最初にどちらか一つを決められない場合、両方の勉強を少しずつ並行して進めてみるのも良い方法です。1〜2週間ほど両方の勉強を試してみて、どちらにより集中できるか、どちらが楽しく感じるかを観察してみてください。</li>

## まとめ
<li>目標や必要性を再確認し、どちらが将来的に役立つかを考える。</li>
<li>興味や楽しさを優先し、続けやすい方を選ぶ。</li>
<li>学習時間と負担を考え、今の生活に合ったものを選ぶ。</li>
<li>実際に模擬問題を解いてみて感覚的に合う方を確認する。</li>
<li>友人やメンターの意見も参考にしてみる。</li>
<li>両方を少しずつ試して自分に合った方を見つける。</li>

これらの方法を使って、自分にとって最適な道を見つけられると良いですね。



## 感想
Chat-GPTを最初はナメてたけど、使い方次第だとわかった。
また、プログラム質問サイトなどで、こういう話題をふると、必ずうんこが沸くので、遠慮なく聞けるので、
もう、これは手放せません。質問サイトだと必ず揚げ足とりジジイがでてくるので、質問したくない。
学校の先生もいらなくなる時代も近いのでは？
「君のやりたいようになりなさい」とか、アドバイスにならないアドバイス、死んでしまえ。
CNNの歴史

# ディープラーニングのモデルを理解する上で押さえておくべき大事なものが３つ！

1. どんなタスクを解いたのか？
2. どういうアーキテクチャーだったのか？
3. 精度はどれくらいか？

---

# LeNet

## 1. どんなタスクを解いたのか？

**タスク**: 手書き数字を認識する問題

- 16x16の手書き数字を480枚
  - **train**: 320枚
  - **test**: 160枚

## 2. どういうアーキテクチャーだったのか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2571787/076e0dbd-cd46-cabc-416d-cb0a374c9684.png)


## 3. 精度はどれくらいか？

**精度**: 98.4%

---

# LeNet-5

## 1. どんなタスクを解いたのか？

LeNet-5は、手書き数字を認識する問題に取り組みました。このタスクは、手書きの数字（0から9まで）を自動的に分類するもので、MNISTデータセットに代表されます。このデータセットには、28x28ピクセルで表現された70,000枚の手書き数字画像が含まれています。

- **トレーニングデータ**: 60,000枚
- **テストデータ**: 10,000枚

## 2. どういうアーキテクチャーだったのか？
![LeNet-1024x544.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2571787/18b67c1a-fd9d-3b60-3d58-e29f944e7aa2.png)


## 3. 精度はどれくらいか？

LeNet-5は、MNISTデータセットを用いた手書き数字認識タスクで非常に高い精度を達成しました。報告された精度は**99.05%**です。この成果により、LeNet-5はディープラーニングの発展において重要な役割を果たし、その後の多くの畳み込みニューラルネットワークの基礎となりました。
IntelliJ で SQL を実行した結果のカラムソートに注意

# はじめに
IntelliJ のデータベースツールを使用し SELECT クエリを実行したとき、出力結果のカラムをクリックすることでソートできる。
しかしある時取得出来てないとおかしい ID がソートで現れず、困ってしまったのでメモを書き残す。

# どんな問題？
IntelliJ のデータベースコンソール (MySQL) で、500 件以上ヒットする SELECT クエリを実行する。
次に、結果としてテーブルに表示されたとき、カラムをクリックしてソートする。
すると、表示されていないとおかしいデータがソート時に現れない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/f22bab45-0ec0-3fe0-ad8d-2181d017b064.png)


# どうすればいい？
取得すると左上にカラムの表示数が選択できる。
ここで All を選択し、全ての結果を表示。
この状態でソートを行うと、正しく結果を見ることができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/1dd629d9-300d-3d72-d22b-54aabc957359.png)



# おわり
物凄く簡単なことですが、この仕様を知らずに割と悩んでいたのでメモとして残してみました。
みなさんも IntelliJ のデータベースコンソールで SELECT クエリの結果を取得するとき、注意してみてみましょう！
【ネタのアイディア】こっくりさんのUXをよくしたい


## 前書き

これは「ネタのアイディア」です。

タイトルにも書いてあるけどね。

## 本文

こっくりさんをするときに紙に文字を書きますが、
画像検索するとでてくるテンプレは濁点、半濁点、拗音、促音、アルファベットがありません。
これではこっくりさんと明快なやり取りが行えません。

これを解消すべく、UXがよいこっくりさんを考えてみました！

…というネタ

だれかやってくれんかな。

面白いUXの学習になると思うんだけどなー。
ありがとうチャットGPT！　その1　～Docker環境でエラー発生してmysqlが開けなかった件～

記事作成時点某エンジニア育成道場で学習中の完全初学者のメモ書きです。
詳しい方には何の役にも立たない備忘録のようなものです。

***

# エラーの発生
Xamppがエラーでにっちもさっちもいかなくなったので、
講師の先生に相談してDocker環境でMySQLを立ち上げ(？)
phpmyadminで接続（？）することに。

紆余曲折あって導入完了！よっしゃ使えるぞー！　と思った矢先に出るエラー…

```
[ERROR] [Entrypoint]: mariadbd failed while attempting to check config
command was: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --verbose --help
/usr/local/bin/docker-entrypoint.sh: line 105: mysqld: command not found
```

**なんやこれ…**

まず何が分からないって何が書いてあるのか分からない。
DeepL翻訳にお願いしたところ、

```
[ERROR] [Entrypoint]: mariadbd が config をチェックしようとして失敗しました。
コマンドは次のとおりです: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci--verbose --help
/usr/local/bin/docker-entrypoint.sh: line 105: mysqld: コマンドが見つかりません。
```
**なるほど！　で？**

やっぱり分からなかったので、元のエラー文そのままググってみたが同じ状況の記事は見当たらない…
検索力が圧倒的に足りないせいか、対処法がまるで出てこない。

もうだめだ、たすけてGPT！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816546/7f5263fe-b142-7578-79b6-c15aa4963afb.png)

**わかんないけどわかった！**
コードをコピーして無事にphpMyadminの起動を確認。
え、これもしかして発端のXAMPPのエラーも直せる…？


# 余談

デーモン名って？？？と思って調べたらこちらの記事に行き当たりました。

https://wa3.i-3-i.info/word11000.html

>デーモン（英：daemon）とは
>
>メモリ上で「さぁ、いつでもかかってこい」と待機している>常駐プログラムのUNIX系OSにおける呼び名
>
>です。

……要はうちのGoogle Nest Hubになんかやってもらうとき最初に「OKGoogle！」って言うようなものなのかな…？

で、それが今までmysqldで通ってたのがmariadbdしか受け付けなくなった、と…

**そんなんわかるかい！！！**
Git エイリアスを使ってブランチ切り替えを楽にする

#### リモート追跡ブランチから、ローカルで作業用のブランチを切る際、いちいちブランチ名を入力するのがめんどくさいと感じている方へ
-------------------------

以下のエイリアスを設定することで、現在のブランチ名を基に新しいブランチを簡単に作成して切り替えることができます。

エイリアスの設定
```
git config --global alias.nb '!f() { git switch -c $(git rev-parse --abbrev-ref HEAD)_#$1; }; f'
```

#### 使い方
現在のブランチから新しいブランチを作成したいとき、次のように入力します

```
git nb <新しいブランチ名>

例えば、現在のブランチが main で、main_#0001という新しいブランチを作成したい場合

git nb 0001
```
これにより、main_#0001 という新しいブランチが作成され、切り替えも自動で行われます。

#### 説明
エイリアスの定義

```
git config --global alias.nb '!f() { git switch -c $(git rev-parse --abbrev-ref HEAD)_#$1; }; f'
```

! の後に続く部分は、シェルのコマンドとして実行されることを示しています。
f() { ... }; f で、f という関数を定義し、その後すぐに呼び出しています。
また、エイリアス名を例としてnbとしていますが、ここは場合によっては使いやすいように修正可能です。

```
$(git rev-parse --abbrev-ref HEAD)
```
この部分で、現在のブランチ名を取得します。これがブランチ名のベースになります。

```
_#$1
```
この部分は、引数 $1 を使って新しいブランチ名に追加する部分です。
ここを場合によって、#がいらない場合は省いたり、ユースケースに応じて修正してください！


#### まとめ
このエイリアスを使うことで、ブランチ名の命名が一貫性を持ち、作業効率が向上します。
また、これを応用すればブランチ作成ではなく、切り替えのみ行う場合も同様に行えます。
ぜひ試してみてください！
【Flutter】EdgeInsetsの余白指定に関する小ネタ(.copyWith)

EdgeInsetsで余白指定する時に天啓を受けたので皆さんにも共有です。

Flutterで四方に均等な余白を指定したいとき、よく使うのはpaddingにEdgeInsets.all()指定だと思います。

例えば、すべての辺に12の余白を与える場合は次のように書きますよね。
```dart
Padding(
    padding: EdgeInsets.all(12),
    child: Text('hoge'),
),
```

ここで、ある一辺だけ異なる値を設定したい状況に遭遇したことはないでしょうか？
例えば、以下のように下辺だけ異なる余白を指定するケースです。
```dart
EdgeInsets.fromLTRB(12, 12, 12, 24)
```

もちろん fromLTRB() で良いのですが、同じ値を3つ入力しているの冗長じゃないですか？

そんな時はこうです。

```dart
EdgeInsets.all(12).copyWith(bottom: 24)
```

### copyWith() とはなんぞや？
`copyWith()`は、Flutterの多くのクラスで使われるメソッドです。
既存のオブジェクトをもとに、特定のプロパティだけを変更した新しいオブジェクトを生成するためのものです。

上記のコードでは`EdgeInsets.all(12)` で四方に12の余白を指定していますが、その後 `copyWith()` を使ってbottomプロパティだけを上書きし、下辺にだけ24の余白を適用しています。


### 最後に

私の思うこれのメリットは以下です。

- コードの簡潔さ：共通部分（上下左右の同じ値）は `EdgeInsets.all()` で一度に指定し、異なる部分だけ `copyWith()`で上書きできるのでコードがスッキリ
- 可読性の向上：fromLTRB() に比べて、どの辺が異なる値になっているか一目でわかりやすい


以上です。ありがとうございました。
iPhone / iPad で Ad Blocker を使う

## この記事の目的

この記事では、iOS で無料で使える広告削除アプリを紹介します。

Safari だけでなく、iPhone / iPad 全体で広告をブロックできるアプリを紹介します。

随時更新していきます。

## [NextDNS](https://nextdns.io/)

App Store: [NextDNS](https://apps.apple.com/jp/app/nextdns/id1463342498)

👉 docomo Wi-Fi で使用する DNS がブロックリストに含まれているようで、NextDNS 使用時は docomo 系の Wi-Fi が使えなくなります。😱

:::note info  
docomo 系の Wi-Fi が使えなくなる理由は、NextDNS が 280blocker のリストを参照していて、その [280blocker](https://280blocker.net/welcome/) のリストに、 docomo Wi-Fi の DNS が含まれているためだと想像。  
<https://github.com/nextdns/blocklists/blob/main/blocklists/280blocker.json>  
:::

```txt:https://280blocker.net/files/280blocker_domain_202411.txt
adnwif.smt.docomo.ne.jp
adw.addlv.smt.docomo.ne.jp
rec1.smt.docomo.ne.jp
alxc.addlv.smt.docomo.ne.jp
nttdocomo-service.com
```

👉 公共交通機関やコンビニの Wi-Fi でデータが流れない時は、NextDNS をオフにしてみてください。

✈️ ANA の無料 Wi-Fi サービス、[ANA Wi-Fi Service](https://www.ana.co.jp/ja/jp/serviceinfo/inflight-wifi/) でも NextDNS を off にする必要がありました。🤔

🎉 DNS として広告をブロックするため、[Warp](https://one.one.one.one/) や [Tailscale](https://tailscale.com/) など、他の VPN と併用して使えます。🎉

<!-- ## Control D Quick Setup

App Store: [Control D Quick Setup](https://apps.apple.com/us/app/control-d-quick-setup/id1518799460) -->

## Purge

App Store: [Purge: Porn Blocker & Safe DNS](https://apps.apple.com/jp/app/purge/id303399377)

👉 [Gigazine](https://gigazine.net/) が見られなくなります。😲

✈️ ANA の無料 Wi-Fi サービス、[ANA Wi-Fi Service](https://www.ana.co.jp/ja/jp/serviceinfo/inflight-wifi/) を使用するには、 Purge を off にする必要がありました。😵

## [AdSpamBlock](https://adspamblock.com/)

App Store: [AdSpamBlock](https://apps.apple.com/jp/app/adspamblock/id1581743170)

`blacklist` に追加することで [LINE](https://line.me/) の annoying な広告 😵 を削除できたのですが、対策されてしまいました。😢

✈️ ANA の無料 Wi-Fi サービス、[ANA Wi-Fi Service](https://www.ana.co.jp/ja/jp/serviceinfo/inflight-wifi/) を使用するには、 AdSpamBlock を off にする必要がありました。😵
Cursor エディタの Chat設定

Cursorエディタの右上にある歯車アイコンでCursor Settingsが開きます。

メニューのFeaturesを選び下の方にChat設定があります。

Chatのデフォルト設定

![Chat設定.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44761/61bda3c9-a786-41c1-eb42-361165985d82.png)








## 各項目の解説

**Chatの設定について**

### Always search the web
* **意味:** すべてのプロンプトに「@web」と入力したかのように、常にウェブ検索を行いながら回答します。
* **効果:** より広範な情報に基づいた、より正確な回答を得ることができます。

### Fade chat stream
* **意味:** チャットの表示がフェードイン効果で滑らかに表示されます。
* **効果:** 視覚的に見やすく、読みやすい表示になります。

### Default no context
* **意味:** デフォルトで、会話の文脈を無視して回答します。
* **効果:** 毎回新しい質問として扱い、過去の会話内容に左右されない回答を得られます。

### Narrow scrollbar
* **意味:** チャットのスクロールバーを細く表示します。
* **効果:** 表示領域を広く確保でき、より多くのチャット内容を確認できます。

### Auto scroll chat
* **意味:** AIが新しいテキストを生成するたびに、自動的にチャット画面が下にスクロールします。
* **効果:** 最新の会話内容を常に確認できます。

### Show chat history
* **意味:** チャット画面が空のときに、過去の会話履歴を表示します。
* **効果:** 過去のやり取りを簡単に確認できます。

### Show suggested files
* **意味:** チャット入力ボックスに、関連するファイルの候補が表示されます。
* **効果:** ファイルを探す手間を省き、効率的に作業を進めることができます。

### Collapse input box pills
* **意味:** チャット入力ボックス内のボタンを折りたたんで表示します。
* **効果:** 表示領域を広く確保でき、より多くのテキストを入力できます。
MacでStorXノード管理：IPアドレスを使ったChromeタブ自動起動

## はじめに

StorXノードを複数運用していると、IPアドレスを使ってノードの状態を確認する場合、いちいち手動でChromeのタブを開くのは時間がかかりますので、各ノードの管理を効率的に行いたくなります。このガイドでは、Macを使ってStorXノードのIPアドレスに基づくタブを自動で開く手順を説明します。

まず、簡単なIPアドレスリストの作成方法から始め、Bashスクリプトを使ったChromeタブの自動化手法までステップごとに解説しています。手動作業を自動化することで、日々の作業効率を大幅に向上させることができると思います。StorXノードを複数管理している方に最適な方法です。


## 1. IPアドレスリストの作成
Mac上で任意のフォルダに、以下のStorXノードのIPアドレスリストをテキストファイルに保存します。ファイル名は `ips.txt` とします。

### 1-1. nano でファイルを作成・編集

`nano` を使ってファイルを編集するのはとても便利です。以下は `nano` を使ってIPアドレスリストを保存する方法です。もちろん、`vim`でも結構です。

まずMacのターミナルで次のコマンドを入力して、`ips.txt` ファイルを開きます：

```bash:1-1
nano ips.txt
```

### 1-2. IPアドレスリストを入力
以下の例のように、IPアドレスを入力して、`nano` エディタ内に貼り付けます：

:::note alert

これらのIPアドレスは例に過ぎません。ご自身で編集してください。
:::

```sh:1-2
12.345.88.99
66.321.84.208
369.10.654.77
98.678.88.123

```

### 1-3. 保存して終了する
IPアドレスを入力したら、以下の手順で保存します。

**`Ctrl + X` を押して終了し、`Y` で保存を確認し、`Enter` で確定します。**

これで、`ips.txt` ファイルにIPアドレスリストが保存されました。



## 2. **Bashスクリプトの作成**
次に、スクリプトを作成しますが、このスクリプトは `ips.txt` にある各IPアドレスに対して、`http://IP_ADDRESS:14002`にアクセスするタブをChromeで開くというものです。

### 2-1. catコマンドを使用

まず`cat`コマンドを使ってスクリプトを作成する際、以下の手順に従うとスクリプトを正しく保存できます。注意点としてスクリプトと `ips.txt` を同じディレクトリに配置してください。

ターミナルで以下のコマンドを実行します：
```bash:2-1
cat > srx_chrometabs.sh
```

### 2-2. スクリプトのコード設定

次に、スクリプトの内容を入力します。以下のコードを貼り付けます：

```bash:2-2
#!/bin/bash

# テキストファイルからIPアドレスを読み込む
while IFS= read -r ip
do
 # MacOSのChromeで新しいタブを開く
 /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome "http://$ip:14002" --new-tab
done < "ips.txt"
```
:::note warn
**入力が完了したら、`Ctrl + D` を押して、`cat` コマンドを終了し、ファイルを保存します。**
:::

## 3. スクリプトの実行
以下のコマンドをターミナルで実行して、スクリプトを実行可能にします。

### 3-1. スクリプトに実行権限を付与

次のコマンドで、`srx_chrometabs.sh`ファイルに実行権限を付与します。
```bash:3-1
chmod +x srx_chrometabs.sh
```

### 3-2.スクリプトを実行

次に以下のコマンドでスクリプトを実行します。
```bash
./srx_chrometabs.sh
```

## 4. 確認
この手順を実行すると、Chromeで `http://IP_ADDRESS:14002` という形式でそれぞれのIPアドレスに対するタブが順次開かれます。
Dockerを使ったGitlabの構築

# はじめに
本記事では、Dockerを使ってGitlabを構築する方法について記述します。

# 環境
今回実施した環境は、以下です。window10のwslを用いてGitlabを構築しました。WSLはホストOSからしかアクセスできないです。そのため、チーム開発用にGitlabを構築したい方はポートフォワーディングなど活用してください。

```
WSL : Ubuntu 20.04
```

# フォルダ構成
フォルダ構成は以下です。docker-compose.ymlでコンテナのビルドをします。gitlabディレクトリはgitlabコンテナのボリュームを永続化するために、ホストOSのボリュームをマウントするためのものです。

```
├── docker-compose.yml
└── gitlab
```
# 手順
docker-compose.ymlファイルは以下のように記述しました。

```
version: '3.6'
services:
  web:
    image: 'gitlab/gitlab-ce:latest'
    hostname: 'localhost'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://localhost'
    ports:
      - '80:80'
    volumes:
      - './gitlab/config:/etc/gitlab'
      - './gitlab/logs:/var/log/gitlab'
      - './gitlab/data:/var/opt/gitlab'
```
簡単にファイルの説明をしておきます。
* ports : ホストOSとgitlabコンテナのポートを対応づけます。
→ホストOSの80番ポートとgitlabコンテナの80番ポートを対応づけています。
* volumes : ホストOSとgitlabコンテナのボリュームを対応づけます。
→コンテナを停止した後も、gitlabコンテナのデータが消えないようにします。
* external_url : gitlabコンテナのURLを指定します。


上記ファイルの存在するディレクトリで、以下コマンドを実施してください。
```
docker-compose up -d
```

少し時間が経つと、http://localhost にアクセスすると、gitlabにアクセスすることができます。

![スクリーンショット 2024-09-21 12.06.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693671/27075aee-9e15-5d2a-44a4-be2b7f235c95.png)

# 参考文
+ [Qiita : DockerイメージからGitLab環境を構築(GitLab&Runner)](https://qiita.com/Nats72/items/ca80b0bfede4d8e10158)
Unity Asset Storeでの販売手順

## Unity Asset Storeでのアセット販売ガイド

Unity Asset Storeは、ゲーム開発やアプリケーション制作に必要なアセットを販売できるプラットフォームです。このガイドでは、Unity Asset Storeでアセットを販売するための具体的なステップを紹介します。

---

### 1. 販売者アカウントの作成

#### ステップ1: Unity IDの作成
アセットを販売するには、まずUnity IDが必要です。Unity IDは、Unityのサービスを利用するためのアカウントです。

1. [Unity ID登録ページ](https://id.unity.com)にアクセスし、アカウントを作成します。
2. 必要な情報（メールアドレス、パスワード）を入力し、アカウントを作成します。

#### ステップ2: 販売者アカウントの登録
Unity IDを作成後、販売者アカウントを登録します。これにより、Unity Asset Storeでアセットを販売できるようになります。

1. [Asset Store Publisher Portal](https://assetstore.unity.com/publishing/publish-and-sell-assets)にアクセスします。
2. 「Get started」をクリックし、販売者プロフィールを作成します。
3. 住所、支払い情報、会社名（個人でも可能）などの必要な情報を入力します。

---

### 2. アセットの作成と準備

#### ステップ1: アセットの作成
Unityエディタを使用して、ユーザーにとって価値のある高品質なアセットを作成します。アセットの種類は多様で、以下のものが一般的です。

- 3Dモデル
- スクリプト（コード）
- テクスチャやマテリアル
- 音楽や効果音
- ツールやエディタ拡張

アセット作成の具体的な手順については、[こちらのページ](https://qiita.com/koichi2426/items/055aa15f7927f75b0bde)を参考にしてください。

#### ステップ2: アセットのパッケージ化
アセットが完成したら、Unityエディタを使用してパッケージ化します。

1. Unityエディタで、パッケージ化するファイルを選択します。
2. 「Assets」メニューから「Export Package」を選び、パッケージに含めるファイルを確認し、「Export」をクリックします。

#### ステップ3: メタデータの準備
アセットを販売するためには、アセットに関する情報を準備する必要があります。

- **アセットのタイトル**: わかりやすく魅力的なタイトルをつけましょう。
- **説明文**: アセットの機能や用途を具体的に説明します。
- **スクリーンショット**: 1280x720ピクセル以上の高品質な画像を用意します。
- **アイコン**: 512x512ピクセルのアイコン画像を作成します。
- **プロモーション用バナー**: 横長のバナー（例えば1920x1080ピクセル）が推奨されます。

---

### 3. アセットのアップロード

#### ステップ1: Asset Store Toolsのインストール
アセットをアップロードするには、Unityの「Asset Store Tools」を使用します。このツールを使用して、アセットのアップロードと管理を行います。

1. Unityエディタで「Asset Store」にアクセスし、「Asset Store Tools」を検索してインポートします。
2. ダウンロードが完了したら、プロジェクトにインポートします。

#### ステップ2: アセットのアップロード
Asset Store Toolsを使用してアセットをアップロードします。

1. Unityエディタの「Asset Store Tools」メニューから「Package Upload」を選びます。
2. タイトルや説明、スクリーンショットなどの必要な情報を入力し、アセットをアップロードします。

---

### 4. 審査プロセス

アセットをアップロードした後、Unityの審査チームが内容を確認します。通常、審査には数日かかりますが、問題がなければアセットは公開されます。もし審査に通らなかった場合は、改善点が通知されるので、修正して再度提出しましょう。

---

### 5. アセットの管理と売上確認

#### ステップ1: 売上の確認
アセットが販売されると、Unity Publisher Portalで売上を確認できます。月ごとの売上や、アセットごとのパフォーマンスを追跡できます。

#### ステップ2: アセットのアップデート
既存のアセットに新機能を追加したり、バグ修正を行う場合は、アップデートが可能です。アップデートには再度審査が必要ですが、既存ユーザーにとっては嬉しい改善となります。

---

### 6. 支払い

アセットの販売収益は、月末にPayPalや銀行振込などの登録済みの支払い方法で受け取ります。支払いが行われるためには、最低限の収益が必要な場合があるので、Unity Publisher Portalで確認しましょう。

---