OmniAICreator/Qiita-1.07M huggingface dataset:
【Unity】オンラインゲーム制作を学ぶ【Photon】

# はじめに
Unityの使い方を学び数か月・・・。
ゲーム制作の基本は理解したが、オンラインゲームはどうやって作るんだ？

・・・ということで調べてみると、何やらPhotonという便利なものがあるらしい！

オンラインゲームを自作するべくまずはPhotonについて学ぶことにした。

# 1.Photonって何？
そもそもPhotonとは何なのか。

:::note
Photonはマルチプレイヤー対応ゲーム向けにリアルタイム通信を行うためのサーバーシステムとクライアントフレームワークを提供しているシステムである。
:::

Photonを利用することでプレイヤー間での接続・同期が簡単に行えるようになる。

Photonのサーバには、<span style="color: red;">ネームサーバ</span>・マスターサーバ・ゲームサーバが存在し、プレイヤーはゲームサーバ内にルームを作成することで同ルーム内のプレイヤー同士でゲームを遊ぶことが出来る。

# 2.Photonを使うメリットは？
Photonのメリットは上記のように簡単にプレイヤーの接続・同期が行うことが出来る他、自身でサーバを用意する必要がないというメリットがある。

自分でサーバを用意すると場所や金銭コストが掛かり、ハードルが高く感じてしまう。

しかし、Photonは無料で最大20人まで同時通信が可能である！

:::note alert
無料プランでは1ルームのメッセージ数が500と定められていて、それを超えると無料プランでも超過料金がかかる可能性がある。
:::

# 3.実際にPhotonを使ってみる
UnityでPhotonを使うには、AssetStoreにある[PUN2](https://assetstore.unity.com/packages/tools/network/pun-2-free-119922?locale=ja-JP)を使うことで容易に実装できる。

### サーバへの接続
サーバへの接続は以下の記法で可能である。
```C#
// マスターサーバーへ接続する
PhotonNetwork.ConnectUsingSettings();
```
この一文のみでマスターサーバへの接続が可能である。

接続完了後はOnConnectedToMaster関数を継承して使用すれば接続後の処理を行うことが出来る。
```C#
// マスターサーバーへの接続後に呼ばれるコールバック
public override void OnConnectedToMaster() {
    // マスターサーバ入室後に行いたい処理を書く
}
```
ここでよく使われるのがゲームサーバの作成・入室である。
```C#
// GameRoomという名前のサーバを作る
PhotonNetwork.CreateRoom(”GameRoom”);
```
この一文で「ルーム」という名前のルーム（ゲームサーバ）が作成可能である。

CreateRoomの引数にRoomOptionsを入れることで最大参加人数などルームごとの設定を自身で指定することも出来る。
```C#
// オプションでサーバの参加は最大8人に設定する
RoomOptions options = new RoomOptions();
options.MaxPlayers = 8;

// 作成したオプションを引数に
PhotonNetwork.CreateRoom(enterRoomName.text, options);
```

接続完了後はOnJoinedRoom関数を継承することでその後の処理を記述することが出来る。
```C#
// ルーム入室後に呼ばれるコールバック
public override void OnJoinedRoom()
{
    // ルーム入室後に行いたい処理を書く
}
```
### ゲーム開始
ルーム作成後、ゲームを開始するときはPhotonNetwork.LoadLevel関数を呼び出すことで任意のシーンへ切り替えてゲームを始められる。
```C#
// SceneBattleという名前のシーンに移動する
PhotonNetwork.LoadLevel(SceneBattle);
```

また、ゲームから途中で抜けることが出来るOnPlayerLeftRoom関数、もしもルームを作成したマスタープレイヤーが離れた場合に呼ばれるOnMasterClientSwitched関数も用意されており、それぞれに処理を記載することでゲームごとに設定を変えることが出来る。

### PunRPCでの同期
　プレイヤーの動機には同期するオブジェクトにPhotonViewコンポーネントを追加し、PunRPC属性を同期させたい関数に追加することで可能となる。
```C#
[PunRCP]
public void Hoge(){
    // 同期させたい処理を書く
}
```
# まとめ
Photonは無料でゲームサーバの作成やプレイヤーの同期などオンラインゲームに必要な処理を簡易・簡潔に行うことが出来る。それはプログラム初心者でも理解しやすく実践し易いものであった。

PUN2からはUnityが非推奨としているResourceファイルを使わずにプレハブを呼び出すことも可能になった。

随時調べたことを追記もしくは新規に記事を作成していきます。

## 【参考】
[Photon公式HP](https://www.photonengine.com/ja-jp)
[PUN2(Photon Unity Networking 2)で始めるオンラインゲーム開発入門]( https://zenn.dev/o8que/books/bdcb9af27bdd7d/viewer/3305df)
【Xcode】Xcode内でドキュメントを閲覧する

# はじめに
今までわからないことがあれば検索からドキュメントに飛んでいましたが、
Xcode15からXcode内でドキュメントがPreviewできるようになったらしいので使ってみました

# やりかた
① 右上の5本線を押します
![スクリーンショット 2023-09-21 21.31.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/569df1c6-bf8e-ebc5-88f6-a4c91726ea91.png)

② 「Assistant」を選択します
![スクリーンショット 2023-09-21 21.32.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/a0e35d6e-07df-4a46-f140-b7ec15914465.png)

③ 輪っかが2個重なったようなアイコンを選択します
![スクリーンショット 2023-09-21 21.33.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/e039d876-1adf-ba38-66af-66dd33fa6a24.png)

④ 「Documentation Preview」を選択します
![スクリーンショット 2023-09-21 21.35.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/169fb0a2-a0fe-8b21-8238-2ecc4a297e5c.png)

完成！！
カーソルの合っているところのドキュメントを表示してくれます
![スクリーンショット 2023-09-21 21.36.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/61bd61aa-f507-ad31-5382-5b216cd4975f.png)

# おわり
これめっちゃ便利！！！
leetcode ２分木

## ２分木の問題を解く時の頻出アルゴリズム
再帰関数の中で「右の木」と「左の木」に分けて、再帰関数に再代入する。

## Passするプログラムの形（おそらく。。。）
```python
def 再帰関数:
    if node is None:
        return
    毎回する処理
    再帰関数(右の木)
    再帰関数(左の木)
```
ポイントは```return```を各場所です！

## Passしたコード
```python:
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sumNumbers(self, root: Optional[TreeNode]) -> int:
        nums = []
        tmp = ''
        def _make_number_from_Tree(node:TreeNode, tmp:str):
            if node is None:
                return 

            tmp += str(node.val)
            if node.right is None and node.left is None:
                nums.append(int(tmp))
            _make_number_from_Tree(node.right, tmp)
            _make_number_from_Tree(node.left, tmp)
        
        _make_number_from_Tree(root, tmp)
        return sum(nums)
```

#### 失敗例１
```python:
def sumNumbers(self, root: Optional[TreeNode]) -> int:
    nums = []
    tmp = ''
    def _make_number_from_Tree(node:TreeNode, tmp:str):
        tmp += str(node.val)
        if node.right is not None:
            _make_number_from_Tree(node.right, tmp)
        if node.left is not None:
            _make_number_from_Tree(node.left, tmp)
        nums.append(int(tmp))
        return 
        
    _make_number_from_Tree(root, tmp)
    return sum(nums)
```

### 失敗例２
```python
def sumNumbers(self, root: Optional[TreeNode]) -> int:
    nums = []
    tmp = ''
    def _make_number_from_Tree(node:TreeNode, tmp:str):
        tmp += str(node.val)
        if node.right is None:
            nums.append(int(tmp))
            return 
        else:
            _make_number_from_Tree(node.right, tmp)

        if node.left is None:
            nums.append(int(tmp))
            return
        else:
            _make_number_from_Tree(node.left, tmp)
    _make_number_from_Tree(root, tmp)
    return sum(nums)
```
E資格合格体験記

# はじめに
[JDLA Deep Learning for ENGINEER][link-1] 2023#2に合格することができたので、試験までにやったことを振り返りたいと思います。

なお、勉強前の知識はG検定合格レベル(1年前に取得)です。

# 教材/認定プログラム
以下を利用して勉強しました。
- [キカガク ディープラーニングハンズオンセミナー][link-2]
    - その他認定プログラム事業者は以下から確認できます。
    - https://www.jdla.org/certificate/engineer/programs/bizlist/
- [ゼロから作るDeep Learning][link-3]
- [ゼロから作るDeep Learning② 自然言語処理編][link-4]
- [ゼロから作るDeep Learning④ 強化学習編][link-5]
- [徹底攻略ディープラーニングE資格エンジニア問題集 **第2版**][link-6]

# やったこと
- 認定プログラム
    - キカガクの認定プログラムを利用しました。ディープラーニングハンズオンコースを受講することで、E資格対策コースを受講することができました。(セットで付いてきました。)
    - ディープラーニングハンズオンコースとE資格対策コースを完了し、事前確認テストを受けることでE資格の受験資格が得られました。
    - ある程度実力がついた時期にテストを実施しました。
- 黒本(6~7周)
    - 黒本はPythonでの実装ベースで問題が出題されることが多く、なぜその選択肢になるのかを理解することが勉強になりました。解説を読んでも理解できない場合にはその分野の解説動画を漁ってなんとか理解しました。
    - 黒本を中心に進めようと思っていたので6~7周しましたが、実際はもう少し黒本の比重を落としても良かったと思います。
    - 後ろについている模擬試験は簡単なため、そこまで力を入れなくても良いと思います。
- ゼロつく
    - それぞれを一度じっくりと読みました。実装は必要と思う箇所だけ行いました。
    - 特に自然言語編、強化学習編は時間をかけて読みました。
- Youtubeの解説動画やネットの解説記事
    - 主に黒本には掲載が無い新領域や、理解しきれていない分野を理解するのに利用しました。
    - 特にTransformerの理解に苦戦したので、解説動画に非常にお世話になりました。


## やるべきだったこと
1. 試験範囲の確認は早々にすればよかった
試験範囲をもう少し早めに確認すればよかったかなと思います。黒本を中心に勉強したのですが、公開されている試験範囲と少しずれており、追加で勉強が必要な箇所がかなりある印象でした。そのため勉強を始める前に範囲を確認しておき、必要・不必要な部分をチェックしておくべきでした。
1. もう少し深掘りをすればよかった
もう少し深掘りをできればよかったかなと思います。試験範囲が広いこともあり、実際の論文を読むことをせずに論文の解説記事を読んで終わりだったのですが、論文を読むことでより知識の深掘りができてより高得点が取れたのではと思います。特に新領域は黒本ではカバーできませんので、今後受ける場合は必ず目を通すべきだと思います。
1. 背景も確認すればよかった
それぞれのモデルが出てきた背景をより深く確認すべきだったかなと思います。

# 感想
勉強前の前提知識はG検定くらいでしたが、何とか合格することができました。わからないことが多すぎて途中心が折れそうになりましたが少しずつ理解を深めていきました。業務などで機械学習に触れてきた人とはどうしても差が生まれるので、物量でカバーする必要があったのが大変でした。今後受験される方の参考になれば幸いです。

<!--- --->
[link-1]:https://www.jdla.org/certificate/engineer/
[link-2]:https://www.kikagaku.co.jp/course/deeplearning-hands-on
[link-3]:https://www.oreilly.co.jp/books/9784873117584/
[link-4]:https://www.oreilly.co.jp/books/9784873118369/
[link-5]:https://www.oreilly.co.jp/books/9784873119755/
[link-6]:https://book.impress.co.jp/books/1120101184
DOMContentLoadedが発火しない？readyStateとDOMContentLoadedの発火順序

# 実現イメージ

Webページの読み込みが完了した時点でJavaScriptを実行したいため、readyStateとDOMContentLoadedを使って制御を行おうと考えた。

# 当初のコード
```javascript
if (document.readyState === "complete") {
  // ページの読み込みが完了している場合、直ちに関数を実行
  this.send();
} else {
  // そうでない場合、DOMContentLoadedで関数を実行
  document.addEventListener("DOMContentLoaded", () => {
    this.send();
  });
}
```

readyStateがcompleteだったら即実行して、そうでなければDOMContentLoadedイベントで発火する仕掛けにした。

# 動かない時がある

しかし、実際にこれをWebサイトに埋め込んでみると埋め込んだページによっては処理が発火しないケースがあった。
そこで、ブレイクポイントを仕込んでreadyStateを確認してみたところ、

![スクリーンショット 2023-09-21 21.12.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/31d83d80-ce03-728e-88bb-e558c175d0cf.png)

上記のようにreadyStateがinteractiveになっていた。
そのため、DOMContentLoadedで発火する分岐に入っているのだが、

readystateの各ステータスとDOMContentLoadedの発生順は、

1. loading: ドキュメントが読み込み中。
1. interactive: ドキュメントが完全に読み込まれているが、サブリソース（画像など）がまだ読み込まれていない。この時点でDOMContentLoadedイベントが発火します。
1. complete: ドキュメントとすべてのサブリソースが読み込まれた。この時点で load イベントが発火します。

となるため、interactiveを確認した時点でDOMContentLoadedを設定しても時すでに遅し、ということでした。

# 修正後のコード

```javascript
if (document.readyState === 'loading') {
  // 読み込み中ならDOMContentLoadedで関数を実行
  document.addEventListener('DOMContentLoaded', () => {
    this.send();
  });
} else {
  // そうでなければ即実行
  this.send();
}
```
loadingの時だけDOMContentLoadedイベントで発火させて、それ以外は即実行するようにしました。
これにより問題が無事解決しました。

# まとめ
Webページの読み込み状態に応じてJavaScriptの実行タイミングを制御することは、多くのWebサイトやアプリケーションで重要です。この記事では、readyStateとDOMContentLoadedを使用して、その制御を試みた経緯と、遭遇した問題、そしてその解決策について詳しく説明しました。

初めはreadyStateがcompleteの場合にのみ即時実行するアプローチを採用しましたが、interactiveの状態での動作を考慮していなかったため、問題が発生しました。最終的には、loadingの時だけDOMContentLoadedイベントで処理を実行し、それ以外の場合は即時実行する方法に変更し、問題を解決しました。

この経験を通じて、Web開発においては、各ブラウザや状態における動作の違いを理解し、それに対応する方法を考えることの重要性を再認識しました。読者の皆様も、この記事が同様の問題に直面した際の参考となれば幸いです。
リーダブルコードを読んだ

https://www.oreilly.co.jp/books/9784873115658/
<h1>リーダーブルコードを読んだ所感</h1>

当たり前の内容と切って捨てるのは簡単だけど、当たり前がちゃんとできていれば炎上プロジェクトはもっと減っている

当たり前の内容だからこそ整理・言語化された情報を繰り返しインプットすることで定着する

<h1>読んでよかったところ</h1>
<h2>第１部全体</h2>
こうするのが良いとわかっていても、レビューで的確に指摘ができず、結局個人の裁量にゆだねてしまったり、ルールだから！と押し付けてしまうことがある

こういう切り口で指摘すればよいのかとても参考になった

<h1>実際に試して結果を計りたいところ</h1>
<h2>第２部全体</h2>
方針は同意！

手段については自分のかかわっているプロジェクトに適応できるか不透明なので、機会があればどうにか組み込んで成果につながるかモニタリングしたいなあ

<h1>議論・検討したいところ</h1>
<h2>１４章　テストと読みやすさ</h2>
私はテストコードは作りこむな派なので<b>独自のミニ言語を実装する</b>というところには引っ掛かりを感じた

テストコードも保守性は大事にするべきだけど、良いフレームワークがどんどん出てくるご時世、リッチにしたはいいけれどその資産に囚われて環境を変えるハードルが高くなるのは避けたい

とはいえ、扱ってる言語を含めた環境に依存する話なので、テストコードを作りこんだ方がリターンが大きいケースもあるんだろうなあ、と

そういうとこ、いろんな意見を聞いてみたい
Ruby on Rails5速習実践ガイドの感想



[Ruby on Rails5速習実践ガイド](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4%E5%AF%A7%E5%AD%90/dp/4839962227/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1GBXVR6FTZEZZ&keywords=ruby+on+rails+5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89&qid=1695165969&sprefix=ruby+on+rails5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89%2Caps%2C164&sr=8-1)を一通り読むことができましたため、読んでみて、良かったところや学んだこと、難しかったことを記載します！



## 良かったところ

### 設計についても触れられていたこと

Railsの文法の話だけでなく、コードの可読性を高めるためにMVCモデルの中のどこにコードを書いた方が良いのか、または新しいクラスを作成して、そこにコードを書いた方が良いのかが書かれていのはとても勉強になりました。

モデルに書くべきなのか？それともコントローラーに書くべきなのか？の判断基準が不明確でしたが、書籍を読んだことにより、少しずつ明確になってきました！

印象的に残った箇所は、**モデルに書くのは、モデルオブジェクトのデータを加工したりする場合は、モデルに書いた方が良いです。**

例えば、テーブルに郵便番号(123-4567)が保存されており、ビュー側は123と4567で別のインプットボックスとなっております。ビューでユーザから入力された郵便番号が123と4567で別々に入ってくるため、テーブルに保存する際には郵便番号を保存する際には結合して、格納する必要があるため、結合処理をコントローラーではなく、モデル側で行います。

編集画面でテーブルから郵便番号をビュー側に表示する際にも郵便番号を123-4567を123と4567で分割する必要があるため、その際にもモデル側で分割処理を記述する必要があります。

また、**モデルオブジェクトのインスタンス変数を呼び出して、データを変更している処理もモデルに記述します。**

例えば、ブログに関するプログラムにおいて、記事の公開状態や公開日時を変更する処理はコントローラーではなく、モデル側に書きます。`@article.status = 'published'`や`@article.published_at = Time.current`のようなコードのことです。このようなコードが連続している場合は、モデルに寄せます。

最後に、**ビュー側にビジネスロジックを書かず、モデル側に書くことです。**

ビュー側に計算処理や比較演算子を用いた判定処理は書かないで、モデル側に書くことです。また、モデルに書くのか、ビューに書くのかの判断が難しい場合は、Decoratorも検討します。

例えば、日付の表示形式がテーブルで保存されているデータとビューで表示したい場合で異なる場合です。





## 学んだこと

### マイグレーションファイルはロールバックできることも確認する

マイグレーションファイルは`rails db:migrate`してテーブルが作成できることだけなく、`rails db:migrate:redo`をすることによって、ロールバックできることも確認する必要があることです。

ロールバックすることになった場合にロールバックが失敗してしまう可能性もあるため、マイグレーションファイルを作成した際にはロールバックできることも確認が必要であることです。

今まではマイグレーションファイルを作成して、テーブルが作成できればオッケーと思っていましたが、最悪の事態も想定して、ロールバックができることも確認する必要があることを学びました。


### タイムゾーンの設定に関する仕組みについて

タイムゾーンはデータベースからデータを取得・更新する際だけでなく、Railsでモデルからデータベースのデータを取得したcreated_atはTimeWithZoneオブジェクトのため、そのオブジェクトにもタイムゾーンが設定されております。

データベースおよびTimeWithZoneオブジェクトのタイムゾーンの設定ファイルがそれぞれあることを知りました。

### アセットパイプラインの仕組みについて

JavascriptやCSSなどのフロント側のプログラムをどのようにして、ブラウザで参照することができるようになるのかの仕組みを知ることができました。アセットパイプラインによって、ブラウザが高速にフロントエンドのプログラムを参照することができるようになっていることを知りました。

アセットパイプラインでは以下のことを行なっております。

- SCSSやcoffeeスクリプトなどのプログラムをCSSやJSにコンパイル
- コンパル後にCSSやJSをapplication.jsやapplication.cssなどにまとめられます。
- まとめられた後に、改行やスペース、コメントなどが削除される。
- コードからハッシュ値を生成して、それをファイル名に付与します。ハッシュ値を付与することで、ブラウザがキャッシュしていたファイル名と異なるようにすることで、新しいファイルが正常に読み込まれるようになります。

開発環境と本番環境でアセットパイプラインが行なっている内容も異なります。

本番だと上記に記載したコンパイルからダイジェストの付与まで全て行います。一方、開発環境では、デバッグのしやすさを考慮して、アセットの連結や圧縮は行いません。

開発者ツールでJSをデバッグする際に開発環境だとプログラムで書いた内容をそのまま見れますが、本番環境だとプログラムの内容と異なって表示されており、疑問に思ってました。アセットパイプラインが環境ごとに行う内容が異なっていたからだと学びました！

## 難しかったところ

chapter10-12-4 外部サービスのロジックを閉じ込めるという箇所が読んでも頭に入らなかったため、時間をおいてもう一度読み返してみようと思います！
國際學校學生的留學夢：由SAT到美國簽證的探索



對於國際學校的學生而言，赴美留學往往是一個深受期待的目標。他們從小沉浸在多元文化的環境中，使得他們更具備踏[出國留學](https://www.apexcharity.org/news/3/83)的勇氣和能力。然而，從夢想到真實行動，SAT考試和美國簽證是兩大不可或缺的環節。本文將探討這兩個關鍵過程。

國際學校：多元的起點

[國際學校](https://www.apexcharity.org/news/3/82)學生擁有獨特的教育背景。他們不僅學習世界課程，還常與來自不同文化背景的同學互動，這使得他們更容易適應其他國家，尤其是美國的多元文化環境。

SAT考試：留學之鑰

大部分美國大學都要求國際學生提交SAT成績作為入學的標準之一。這項考試涵蓋了數學和英語閱讀寫作部分，旨在評估學生的基礎學術能力。許多國際學校學生會投入大量時間準備[SAT](https://www.apexcharity.org/news/3/84)，確保他們的分數能夠突破申請大學的門檻。

[美國簽證](https://www.apexcharity.org/news/3/94)：夢想成真的最後一步

成功通過大學的申請程序並獲得錄取後，學生需要獲得美國的學生簽證，通常是F-1簽證。這需要學校發放的I-20表格，然後學生須支付SEVIS I-901的費用，並於當地的美國領事館或大使館安排面試。只要成功通過面試，學生就可以拿到他們夢寐以求的學生簽證。

總之，國際學校學生雖然擁有跨文化的優勢，但赴美留學的路仍然充滿了挑戰。無論是SAT的嚴峻考試還是簽證的申請過程，每一步都需要學生的努力和堅持。但只要有決心，這些挑戰都將轉化為他們成功的催化劑。
【Eclipse】ERMasterが重すぎて開けないとき

## はじめに
.ermファイルがある時を境に肥大化し（10MBくらい）、重すぎて開けなくなる。
テーブル数は多くても100個前後なので、このサイズは明らかにおかしい。

## 環境
MacOS
Eclipse Version: 2022-03 (4.23)
ERMater 更新止まっているのでとりあえず最新版

## 原因（バグ？）
.ermファイルに以下のような行が突然複製され続けて何万行と増えるときがある。
```xml
<referenced_column>42</referenced_column>
<referenced_column>42</referenced_column>
// ↑↓が何万行もある
<relation>1</relation>
```
.ermファイルのサイズが10MBを超えてくるとおおよそこの問題が発生している。
**Windows環境でも発生しており、再現性がない。**
弊社内で外部キーを貼っているときに発生するときがあると言っている方がいたが、毎回発生するわけではないのでどの操作が根本原因なのか不明。

## 一時的な対症療法
.ermファイルをVSCodeなどで開き、一括置換などで対象行を削除する。

クリティカルな発生原因が知りたい。
Tanzu Application Platformでcert-managerを除外してデプロイする際の注意点

Harbor構築後など既にcert-managerが入っている環境にTanzu Application Platform(以下TAP)をデプロイしようとすると、cert-managerがバッティングしてデプロイに失敗する。
そこでcert-managerを除外リストに追加してデプロイする訳だが、以下のようにcert-managerを除外リストに入れてデプロイしても失敗する。
```yaml
excluded_packages:
- cert-manager.tanzu.vmware.com
```
TAPはデフォルトで、`shared.ingress_issuer`に`tap-ingress-selfsigned`を指定してデプロイされる。
この`tap-ingress-selfsigned`はcert-managerのリソースである`kind: ClusterIssuer`で定義され、オレオレ証明書の認証局となってくれるのだが、これが`excluded_packages`でcert-managerを指定するとデフォルトで作成されなくなる。
そのため、このIssuerに証明書を発行してもらおうとするコンポーネントのデプロイが全滅する。
例えばapi-auto-registration-controllerなんかが以下のエラーで起動できなくなる(ContainerCreatingで止まる)。
```sh
Events:
  Type     Reason       Age                   From               Message
  ----     ------       ----                  ----               -------
  Normal   Scheduled    4m35s                 default-scheduler  Successfully assigned api-auto-registration/api-auto-registration-controller-6bcfff7665-hntp5 to tis-sharedcluster-0919-md-1-v8hf6-7bddbfb84f-5wx4b
  Warning  FailedMount  2m32s                 kubelet            Unable to attach or mount volumes: unmounted volumes=[ca-cert-info], unattached volumes=[kube-api-access-gsxs2 ca-cert-info]: timed out waiting for the condition
  Warning  FailedMount  25s (x10 over 4m35s)  kubelet            MountVolume.SetUp failed for volume "ca-cert-info" : secret "ca-extractor" not found
  Warning  FailedMount  18s                   kubelet            Unable to attach or mount volumes: unmounted volumes=[ca-cert-info], unattached volumes=[ca-cert-info kube-api-access-gsxs2]: timed out waiting for the condition
```
Secretは以下のようになり、期待する証明書が発行されていない。
```s
$ kubectl get secret -n api-auto-registration
NAME                 TYPE                                DATA   AGE
ca-cert              servicebinding.io/ca-certificates   2      6m40s
ca-extractor-jm2rk   Opaque                              1      6m38s
image-pull-secret    kubernetes.io/dockerconfigjson      1      6m40s
```
そのため、cert-managerを除外する際は、予め`tap-ingress-selfsigned`を自作して配布しておくとよさそう。
```yaml
cat << EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: tap-ingress-selfsigned
spec:
  selfSigned: {}
EOF
```
上記実施後、cert-managerを除外してTAPをデプロイした結果は以下。
```sh
$ kubectl get app -n tap-install tap
NAME   DESCRIPTION           SINCE-DEPLOY   AGE
tap    Reconcile succeeded   5m5s           5m6s
```
無事回避できた。
Github 初めて使ってみた。使い方まとめ（M2 macbook pro）

# Giuhub
macbook pro M2
githubでの使い方まとめ（自分用メモ）

## 課題

1.pushした際に以下のようなエラーが発生

<aside>
💡

error: src refspec master does not match any
error: failed to push some refs to 'https://github.com/keishi85/test.git'

</aside>

2.pushの際に以下のようなエラーが発生

```bash
! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'github.com:keishi85/talk_robo.git'
```

## 現状

1.以下のようなエラーが発生

パスワードの入力にはGithub上のトークンを使用

```bash
%  git remote -v
origin	https://github.com/keishi85/test.git (fetch)
origin	https://github.com/keishi85/test.git (push)

% git push origin main
Username for 'https://github.com': keishi85
Password for 'https://keishi85@github.com': 
remote: Write access to repository not granted.
fatal: unable to access 'https://github.com/keishi85/test.git/': The requested URL returned error: 403
```

## 解決策

1. Githubでトークンを発行する際に「repo」にチェックをつける

→ローカルにクローンするなどの操作を可能にする

[GitHubのAccess token認証方法とは？Password認証の廃止 | ポテパンスタイル](https://style.potepan.com/articles/34189.html)

1. Github上でリモートリポジトリを作成する際に、リモートリポジトリとローカルリポジトリのファイルが異なるとpushできないっぽい。
    
    つまり、リモートリポジトリを作成する際に、README.txtを作らない。
    

## Githubにpushするまでの流れ

1. ローカルリポジトリの作成

```bash
$ git cd dir_name
$ git init
$ git branch -m master main
```

1. add, commitを行う

```bash
$ git add .  (file_name)
$ git commit -m '(content)'
```

1. ローカルリポジトリにリモートリポジトリとのインデックスを作成

```bash
$ git remote add origin '(リモードリポジトリのURL)'
```

1. push(branchの指定も可能)
module not found: error: can't resolve 'react'

### エラー
```
module not found: error: can't resolve 'react'
```
　'react'モジュールそのものの例がネットに載ってなかったので、苦労しました。

### 解決方法
```
yarn add styled-components
```
　これで解決しました。もう消えてしまったので分からないですが、エラーの後に「styled-componentsに対しての話ですよ」とか書いてあったのかも。。。

### 参考（package.json）
　上記の解決方法を思いついたきっかけは、動いてるreactアプリの```package.json```と見比べたことでした。
　reactアプリが動いた時の```packeage.json```を載せておきます。差分があるかを見てみると、解決の糸口が見えてくれるかも！
```json:package.json
{
  "name": "todo-app",
  "private": true,
  "dependencies": {
    "@babel/preset-react": "^7.22.5",
    "@rails/actioncable": "^6.0.0",
    "@rails/activestorage": "^6.0.0",
    "@rails/ujs": "^6.0.0",
    "@rails/webpacker": "5.4.4",
    "axios": "^1.5.0",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "prop-types": "^15.8.1",
    "react": "^17.0.1",
    "react-dom": "^17.0.2",
    "react-icons": "^4.10.1",
    "react-router-dom": "^5.3.4",
    "styled-components": "^6.0.7",
    "turbolinks": "^5.2.0",
    "webpack": "^4.46.0",
    "webpack-cli": "^3.3.12"
  },
  "version": "0.1.0",
  "devDependencies": {
    "@babel/plugin-proposal-private-methods": "^7.18.6",
    "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
    "react-toastify": "^9.1.3",
    "webpack-dev-server": "^3"
  }
}
```

### package.jsonって何？
　インストールすべきパッケージのバーションが書いてます。
```yarn add パッケージ```で追加できます。
　※手動ではなく、コマンド経由で更新します。

### package-lock.jsonって何？
　実際にインストールしたパッケージのバージョンが書いてます。
　```package.json```　　　：予定
　```package-lock.json```：実際
　　という違いがあります。

### node_modulesって何？
　```package.json```を基にインストールしたパッケージがいっぱいあります。
　量が多いので、.gitignoreに指定されます（githubにアップロードされません）。
Streamlit をAzure App Serviceで動かす時のAPI Keyの置き場所

最近、エンジニア職じゃないのに生成AIのデモアプリをChatGPTに聞きながら、Streamlitで作る、というのにハマっています。本当に楽しい、いい時代になりました！

ただ、StreamlitってCommunity Cloudで共有するのはとても簡単なんですが、プライベートなレポジトリからは１つしかアプリを作れなくて、２つやりたいんですよ、と思っても有料プランがない。デモアプリをそれぞれ違うお客さん向けに作っておきたいなー、というとき、いきなり不便です。

そしたら、Azure App Serviceで動かせますよ、という記事がQiitaにあって、初めてAzure App Serviceを使いましたが、その手順通りにしたら、かなり手軽にできました。
[Streamlit を Azure App Serviceで動かす！](https://qiita.com/takashiuesaka/items/491b21e9afb34bbb6e6d)

記事を書いてくださったマイクロソフトの方、ありがとうございます！

簡単なんではありますが、生成AIのAPIを使ったデモアプリを作るにあたり、私が個人的にどうやるのかわからず、はまったことがあるので、書いておきます。

## APIキーはどこに置くの？

APIキーはどこに置くのでしょうか？色々な方法があるとは思いますが、上記の手順書で、"アプケーション設定にSCM_DO_BUILD_DURING_DEPLOYMENTというKEYを作り、値にtrueまたは1をセットします。最後に保存ボタンをクリックすることをお忘れなく。"という作業があります。この作業と同じように、アプリケーション設定でAPIキーの変数名と、API Keyの値を格納しておくことができます。

こんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322998/df93d3ad-f257-11ef-5ec6-4709cceda76a.png)

## アプリケーション設定へのAPIキーの書き込み方

で、この時、APIキーの値は、クォーテーションマークなどでは囲みません。そのまま書き込みます。ローカルに置いた.envファイルからコピっていた私は最初、ここでつまづきました。つまり、こんな感じです。
- ダメな例: "apikeyの文字列です"
- 良い例: apikeyの文字列です

## APIキーの呼び出し方

アプリ側でのAPIキーの呼び出し方は、こんな感じです。ローカルに置いた.envファイルからの呼び出しとは書き方が少し違うと思います。

```python:
your_api_key = os.environ['YOUR_API_KEY']
```

## 簡単なパスワード認証のかけ方

ちなみに、元の記事には、Azure Active Directoryでの認証の付け方が書かれていました。しかし、もっと簡単にpwを一個だけ設定しておくようにしたいのだよな、というときもあると思います。その際も、上と同じやり方で、Azure App Serviceのアプリケーション設定にパスワードを入れておき、同じやり方で取り出して使うことができます。

あとは、[Streamlit公式のやり方](https://docs.streamlit.io/knowledge-base/deploy/authentication-without-sso)に沿って作ります。公式の内容は、Streamlit Communiy Cloudを使う前提になっているので、st.secrets["password"]としていますが、これを上と同じようにos.envison["password"]とするだけで、Azure App Serviceのアプリケーション設定に格納したパスワードに変えることができます。



おしまいです。それでは！

## 参考文献
https://learn.microsoft.com/ja-jp/azure/app-service/configure-language-python#access-app-settings-as-environment-variables

https://qiita.com/takashiuesaka/items/491b21e9afb34bbb6e6d

https://docs.streamlit.io/knowledge-base/deploy/authentication-without-sso
iOS17の実機端末に対してXcode14からビルドできない（Could not locate device support files）

## 解決策
Xcode15（Beta）からビルドすることでビルドできるようにはなりました。

## 背景
日付：2023年9月21日
Device：iPhone 13（実機）、OS：17.0
Xcode：Xcode 14.3.1 (14E300c)

端末をiOS1７に上げた状態で、Xcode 14.3.1 (14E300c)から端末を選択・ビルドを行おうとすると、下記エラーが表示されインストールできなくなっていました。
> **Could not locate device support files**
> 
> 
> You may be able to resolve the issue by installing the latest version of Xcode from the Mac App Store or [developer.apple.com](http://developer.apple.com/).
> 
> [missing string: 869a8e318f07f3e2f42e11d435502286094f76de]
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245300/14d75bca-613f-e63e-0112-2b02f0b0e6da.png)

## 調査
[How to run on iOS 17 Device using Xcode 14](https://stackoverflow.com/questions/76412754/how-to-run-on-ios-17-device-using-xcode-14)
[Missing iOS 17 device support files](https://developer.apple.com/forums/thread/730947)
[Xcode14を使用してiOS17デバイスをデバッグする方法](https://qiita.com/4q_sano/items/a94a1f8ffeb41dfe11a6)

などで触れられている、下記コマンド実行でXcodeの設定を変更できる感じのコマンド試しましたが実機ビルドエラーは解消しませんでした。
（シミュレーターだったら行ける？）
```
defaults write com.apple.dt.Xcode DVTEnableCoreDevice enabled
```

取り敢えず戻しておきます
```
defaults write com.apple.dt.Xcode DVTEnableCoreDevice disabled
```

## 解決した方法
身も蓋もないですが、社内でXcode15.0（Beta 8）に上げていた端末があったのでそちらで実行すれば問題なくビルド・インストールできました。

## あとがき
しばらくはXcode14.xのままで検証・運用したい場合などあると思うので、何か良い回避策が取れたら良いですね…。
ミッションクリティカルなJavaアプリケーションのためのBrowsium Catalyst vs CheerpJ in Chrome

![Browsium-Vs-CheerpJ-1024x578.png.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486144/901a5961-6aad-7501-1b5d-093a3e862cdc.jpeg)
来月、Microsoftは長寿ブラウザであるInternet Explorerのメインストリームサポートを終了する意向であり、Windows 11上のIE11デスクトップアプリケーションは無効になる。

しかし、一部のアプリケーション、特にJavaアプレットをベースとしたアプリケーションは、インターネットエクスプローラーでのみ確実に動作し、Chrome Enterpriseユーザーは[GoogleのLegacy Browser Support (LBS)](https://support.google.com/chrome/a/answer/9270076?hl=en)を介してこれらのコンテンツにアクセスします。
![1Chrome-LBS-Infographic-4-300x157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486144/4ed301f9-f9c4-1d0d-004a-326d75d53ee0.png)

IEの無効化は、Chrome経由でこれらのアプリケーションへのアクセスを維持する必要がある企業のワークフローに大きな変化をもたらす。6月からは、MicrosoftのEdgeとEnterprise Mode Site List（EMSL）が必要になる。

# Browsium Catalyst
[Browsium](https://www.browsium.com/catalyst/)は以前からある技術で、2022年6月以前のGoogleのChrome Legacy Browser Supportと同様の働きをする。

Catalystを使用することで、組織は特定のURLに対するユーザーのブラウザ使用を容易に制御することができる。例えば、ユーザーがインターネットにアクセスする際にChromeを常用しているが、JavaでビルドされたCRMをIEで開く必要がある場合、Catalystを使ってルールセットを作成し、ユーザーがChromeでCRMにアクセスしようとすると、自動的にEdgeの「IEモード」に移行させることができる。

しかし、このニーズを解決するもっと良い方法はないでしょうか？下記のように、私たちのブラウザベースのソリューションであるCheerpJは、レガシーなブラウザとクライアント上のJavaの必要性を取り除きます。これにより、レガシーアプリケーションのセキュリティを向上させながら、定期的なメンテナンスの必要性をなくすことができます。
![2Browsium-2-300x149.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486144/95bbb663-95b6-333b-5ac3-a8fa1cac981b.png)

# CheerpJ
CheerpJは、ミッションクリティカルなJavaアプリケーションやアプレットを最新化し、アクセスを維持するエンタープライズグレードのソリューションです。組織は、既存のJavaアプレットやアプリケーションへのアクセシビリティを維持したり、HTML5ページ（ReactやAngularなどのフレームワークによるものを含む）内に統合するためにそれらを最新化したりすることができます。

CheerpJ Applet Runnerは、JavaプラグインやインストールなしでJavaアプレットを実行するためのChromeとEdge用のブラウザ拡張機能です。Chrome、Edge、Firefox、Safari、その他の最新ブラウザでJavaアプレットにアクセスすることができ、最新のITアーキテクチャで内部またはサードパーティのJavaアプレット・インターフェースを使い続けることができます。

CheerpJ Applet Runnerは、エンタープライズ設定で使用することができ、Microsoftベースのエンタープライズ・アーキテクチャ上のEdgeやChrome上でGlobal Policy Objectsを介してデプロイすることができます。

4.5 ⭐ – 80,000+ Users 👤

優れたカスタマーサポートを備えた拡張機能です！私たちは、民間航空機からの自動天気予報を表示する大規模で広範なアプレットを持っています。 CheerpJバージョンは高速です。
**– Bill Moniger, NOAA**

Cut-the-knotは、javaを使ってアニメーション化された数学アニメの宝庫である。やっとまたサイト全体を楽しめるようになりました。開発者の方々、本当にありがとうございました🙂。
**– Mathologer Mathematics**

https://leaningtech.com/legacy-modernisation-jp/

引用元：https://leaningtech.com/browsium-catalyst-vs-cheerpj-for-mission-critical-java-applications-in-chrome/
Azure プライベートエンドポイントの削除

サービスの検証などでプライベートエンドポイントを作成し、不要になったので削除しようとしたところスムーズに削除が出来なかったので自分用のメモとして記録します。
結論から記載すると、Azureポータル上からポチポチ消すことは可能なのですがちょっとした手順が必要になります。


## プライベートエンドポイントの作成で作成されるリソース
プライベートエンドポイントを削除しようと思った時にプライベートエンドポイントリソースを1つ削除すれば良いわけではありません。
プライベートエンドポイント作成時に付随して作成されるリソースがあるので、そちらも削除する必要があります。

▼プライベートエンドポイント作成前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293404/950602cb-103e-0910-0226-872215deb80b.png)

▼プライベートエンドポイント作成後
※Vnetは手動で作成しました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293404/1f04c7fc-dab0-8c90-fd36-2fa9c43adf8d.png)

今回はAzure Cosmos DB用のプライベートエンドポイントを作成したため、Azure Cosmos DBのページからプライベートエンドポイントを作成すると以下のリソースが作成されました。
* プライベート DNS ゾーン
* ネットワーク インターフェイス
* プライベート エンドポイント

## 注意点
ここから本題ですが、プライベートエンドポイントの削除は上記に記載したリソースを削除することで完了します。
ただしプライベート DNSゾーンのみ削除に注意が必要です。

単純に削除しようとすると以下のように「ネストされたリソースが存在する間は削除できません」といったエラーが発生します。

>プライベート DNS ゾーン 'privatelink.documents.azure.com' を削除できませんでした。エラー: Cannot delete resource while nested resources exist. Some existing nested resource IDs include: 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293404/d366414a-014c-abfa-7015-3533f5315a20.png)


## ネストされたリソース

プライベートエンドポイントやネットワークインターフェースは削除済みで「ネストされたリソース」なるものは見つかりませんが、既定では表示がされないようになっているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293404/3f01d448-9dbc-102e-312a-04614b60ecbc.png)

リソースグループのリソース一覧の上部にある「非表示の型の表示」にチェックを入れると表示されるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293404/0ba98257-1242-e08e-e3be-bafbc999f4df.png)

[microsoft.network/privatednszones/virtualnetworklinks]という種類のリソースが表示されました。
これが今回の「ネストされたリソース」になります。

このリソースはプライベートエンドポイント作成時に補助的なリソースとしてAzureインフラストラクチャで作成、管理されているものになります。

今回の目的であるプライベートエンドポイントの削除では補助的なリソースの削除が必要となります。

補助的なリソースを削除すると、当初エラーのでていたプライベート DNS ゾーンも自動的に削除されます。（補助的なリソース削除後少し時間をおくと削除されます）




## おわりに

▼今回のポイント
リソースの作成時にはAzureインフラストラクチャ側で自動的に作成・管理されている補助的なリソースが存在する。
リソース削除の際には補助的なリソースも削除する必要がある。

>一部の補助的なリソースは、Azure インフラストラクチャで作成、管理します。既定では、ポータルにこれらのリソースは表示されません。表示/非表示を切り替えるには、このチェック ボックスを切り替えてください。リソース グループやサブスクリプションのクリーンアップを実行する場合に、これらのリソースを表示しておくと便利です。


作成時には自動で作成されかつ、補助的なリソースとしてポータルの既定では非表示となっているので注意が必要です。
Dockerコンテナ削除方法

Dockerコンテナを完全に削除する方法を以下に示します。これにはコンテナの停止、削除、および関連するボリュームの削除が含まれます。慎重に実行してください。

1. **コンテナの停止**:
   まず、削除したいコンテナを停止します。コンテナIDまたはコンテナ名を使用して停止します。

   ```bash
   docker stop <コンテナIDまたはコンテナ名>
   ```

   たとえば、コンテナIDが `abcd1234` の場合:

   ```bash
   docker stop abcd1234
   ```

2. **コンテナの削除**:
   コンテナを停止したら、次にコンテナを削除します。

   ```bash
   docker rm <コンテナIDまたはコンテナ名>
   ```

   または、全ての停止中のコンテナを削除する場合:

   ```bash
   docker container prune
   ```

3. **ボリュームの削除**:
   コンテナが関連付けられているボリュームも削除する場合、以下のコマンドを使用します。コンテナIDまたはコンテナ名を指定します。

   ```bash
   docker volume rm <ボリューム名>
   ```

   ボリューム名は通常、コンテナ名と関連しています。ボリュームがコンテナに関連付けられていることを確認してから削除してください。

これらの手順を実行することで、Dockerコンテナとそれに関連するボリュームを完全に削除できます。ただし、データの損失を避けるために、重要な情報が含まれているかもしれないボリュームを削除する前にバックアップを取得することをお勧めします。
TypeScriptのジェネリクス（Generics）とは

ジェネリクス（Generics）は、型のパラメータ化を可能にするプログラミングの仕組みです。ジェネリクスを使用することで、一つの関数やクラスで、様々な型に対応したコードを書くことができます。これによって、コードの再利用性が高まります。

## ジェネリクスのメリット
1. **型安全**：
   ジェネリクスを使用することで、型の不整合がコンパイル時に検出されます。これにより、実行時の型エラーを防ぎます。
   
2. **再利用性**：
   一つの関数やクラスを、様々な型で利用できます。これによって、同じロジックを異なる型に対して繰り返し書く必要がなくなります。

### ジェネリクスの基本例
以下は、TypeScriptでジェネリクスを使用した基本的な例です。

```typescript
function echo<T>(arg: T): T {
    return arg;
}

let resultNumber = echo<number>(123); // 123
let resultString = echo<string>("Hello"); // "Hello"
```

この例では、`echo`関数は、任意の型`T`を受け取り、同じ型`T`を返す関数です。`<T>`が型パラメータで、これによって`arg`の型と返り値の型が`T`になります。そして、この関数を呼び出す際に、`<number>`や`<string>`といった具体的な型を指定することで、異なる型に対応した`echo`関数を利用できます。

### より具体的な例
例えば、あるオブジェクトを配列に変換するようなジェネリクス関数を考えます。

```typescript
function convertToArray<T>(obj: T): Array<T> {
    return [obj];
}

let numberArray = convertToArray<number>(1); // [1]
let stringArray = convertToArray<string>("hello"); // ["hello"]
```

ここで`convertToArray`関数は、任意の型`T`のオブジェクトを受け取り、そのオブジェクトを含む`T`型の配列を返します。関数を呼び出す際に、`<number>`や`<string>`といった具体的な型を指定しています。

## ジェネリクスを使わない場合
ジェネリクスを使わない場合、関数に特定の型を指定するか、またはany型を使用することになります。特定の型を指定した場合、その型の値しか受け付けません。any型を使用した場合は、どんな型の値でも受け付けますが、型安全が失われます。

### 特定の型を指定する場合：

```typescript
function echoNumber(arg: number): number {
  return arg;
}

let resultNumber = echoNumber(123); // 123
```

この場合、`echoNumber`関数は`number`型の引数しか受け付けません。

### any型を使用する場合：

```typescript
function echoAny(arg: any): any {
  return arg;
}

let resultNumber = echoAny(123); // 123
let resultString = echoAny('hello'); // 'hello'
```

この場合、`echoAny`関数はどんな型の引数でも受け付けますが、型安全が失われ、TypeScriptの利点が活かせません。

## ジェネリクスとanyの差
ジェネリクスを使うと、関数やクラスが様々な型で動作できますが、それでも型安全が保たれます。これは、ジェネリクスを使う場合、型をパラメータとして渡すので、TypeScriptの型チェッカーが型の正しさをチェックできるからです。

以下のジェネリクスの例において:

```typescript
function echo<T>(arg: T): T {
  return arg;
}

let resultString = echo<string>("hello");
```

この場合、`echo`関数は`<string>`ジェネリクスパラメータを通して、`string`型として動作します。これにより、関数内では`arg`は`string`型として認識され、型の誤りがあればコンパイルエラーが発生します。

### any型との違い:

- **型安全**: `any`型を使うと、型チェッカーはその値の型をチェックしないため、型安全が失われます。一方、ジェネリクスを使うと、型チェッカーはジェネリクスパラメータとして渡された具体的な型をチェックし、型安全が保たれます。
  
- **自動補完とリファクタリング**: ジェネリクスを使用した場合、IDEの自動補完機能が効くため、開発がスムーズになります。また、リファクタリングも安全に行うことができます。

- **コードの可読性**: ジェネリクスを使用すると、どの型で動作することを意図しているのかが明示的になり、コードの可読性が向上します。一方で、`any`型を使うと、どの型が来るべきかが不明確になります。

### いつ何を使うか？
- 汎用的なコードを書く必要がある場合や、複数の型で動作する必要がある場合は、ジェネリクスを使用します。
- 特定の型だけを扱う必要がある場合、またはコードのシンプリシティが求められる場合は、特定の型を指定します。

## その他
ジェネリクスは、特定の型（stringやnumberなど）だけでなく、インターフェースやクラスなどの複雑な型やカスタム型に対しても使用できます。


## まとめ
ジェネリクスは、型をパラメータとして扱うことで、一つのコードが様々な型に対応できるようにします。これによって、型安全を保ちながらコードの再利用性が向上します。
Unityで3D<ui<3Dの表示にする方法

Unityで3D<ui<3Dの表示するためのカメラの設定を残します
タップエフェクトを最前面に表示したい時などに活用

## 環境
Unity 2023.1.10f

## カメラの設定
・CanvasのRender Modeは、Screen Space - Cameraにし、RenderCameraは、奥の3Dカメラを設定します
・手前のカメラはタップエフェクトを表示するために奥のカメラの位置とはづらしています
・3DカメラのProjectionのsizeやCanvasのPlane Distanceは調整してください
・置くと手前の3DカメラのProjectionのProjectionは、Orthographicを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/84036b60-2488-1474-8e33-443acab1f95a.png)
【ServiceNow】Utahリリース　Next Experience　お気に入りの管理

Utahへのバージョンアップで新規追加された機能について紹介します。
Next Experienceにてお気に入りの管理ができるのでその結果をまとめました。

https://docs.servicenow.com/bundle/utah-platform-user-interface/page/get-started/servicenow-overview/concept/managing-your-favorites.html

# Next Experienceでお気に入りを追加する
メニューの☆マークをクリックし、そのメニューをお気に入りに登録します。
[名前]フィールドにグループの名前を入力します。
[場所] フィールドで、[お気に入り] メニューのグループを作成した場合は、お気に入りをリストするグループを選択します。
グループを作成してお気に入りリストを整理する方法については、次章「Next Experienceでのお気に入りの整理」を参照してください。
これ以上変更を加えない場合は、「完了」を選択します。 
お気に入りのアイコンとその色を変更するには、[その他] を選択し、アイコンとその色を選択して、[編集を保存] を選択します。 
お気に入りを削除するには、[削除] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599975/3449dd1d-ce6e-cc79-0c42-ede87d130487.png)

# Next Experienceでのお気に入りの整理
Next Experience の統合ナビゲーションで [お気に入り] メニューを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599975/6bdde51c-9817-0938-06a5-58853b86550a.png)

以下の[お気に入りの編集] アイコンを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599975/750101c2-0e33-7e53-7b37-fa049893c30f.png)

 [カスタム グループの作成] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599975/31f8d371-69fc-0763-c61f-451e6752865a.png)

[名前] フィールドに、グループの名前を入力します。
このグループのお気に入りに関連付けられているアイコンの色を選択します。
グループ内の各お気に入りに固有の色を設定することもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599975/482fbe82-7793-5f7d-d7db-e5b0a92a079f.png)

お気に入りをグループ名の下にドラッグして、お気に入りをグループに移動します。
[編集を保存] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599975/2f1888f5-dc9e-7496-87d4-eba9a4712289.png)

# おわりに
お気に入りを使用することで、よく使用するページにすばやく移動できたり管理が容易になりました。
【2023年版】PythonでMultiSetを使う

Atcoderの2023年8月の言語アップデートに伴い、Pythonで`sortedcontainers`ライブラリが使えるようになりました。平衡二分木を使ったMultiSetはPythonにないので、今後は`sortedcontainers`の`SortedList`が使えそうです。

## SortedListのメソッド一覧と計算量
[Grant Jenksの公式ドキュメント](https://grantjenks.com/docs/sortedcontainers/sortedlist.html)を参照しました。

| メソッド                 | 説明                                                                                     | 計算量            |
|------------------------|------------------------------------------------------------------------------------------|------------------|
| `add(value)`           | 要素をソートして追加                                                                     | $O(\log n)$     |
| `update(iterable)`     | 複数の要素をソートして追加                                                               | $O(k \log n)$   |
| `clear()`              | すべての要素を削除                                                                       | $O(n)$          |
| `discard(value)`       | 要素を削除（存在しない場合は何もしない）                                                 | $O(\log n)$     |
| `remove(value)`        | 要素を削除（存在しない場合はValueError）                                                  | $O(\log n)$     |
| `pop(index=-1)`        | 指定されたインデックスの要素を削除して返す                                                 | $O(\log n)$     |
| `bisect_left(value)`   | 二分探索で挿入位置を左側から探す                                                         | $O(\log n)$     |
| `bisect_right(value)`  | 二分探索で挿入位置を右側から探す                                                         | $O(\log n)$     |
| `count(value)`         | 指定された値の出現回数を取得                                                             | $O(\log n)$     |
| `index(value, start=0, stop=None)` | 指定された値のインデックスを取得（存在しない場合はValueError） | $O(\log n)$     |
| `__getitem__(index)`   | 指定されたインデックスの要素を取得。スライスもサポート。                                  | $O(\log n)$     |



## 使用例
```python
from sortedcontainers import SortedList

# SortedListのインスタンスを作成
sl = SortedList([3, 1, 4, 1, 5, 9, 2, 6, 5])
print(f"Initial list: {sl}") # [1, 1, 2, 3, 4, 5, 5, 6, 9]

# add(value): 要素をソートして追加
sl.add(8)
print(f"Added 8: {sl}") # [1, 1, 2, 3, 4, 5, 5, 6, 8, 9]

# update(iterable): 複数の要素をソートして追加
sl.update([7, 10])
print(f"Updated with [7, 10]: {sl}") # [1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]

# clear(): すべての要素を削除
sl.clear()
print(f"Cleared list: {sl}") # []

# 以下の操作は新たなSortedListで行う
sl = SortedList([1, 2, 3, 4, 5]) 

# discard(value): 要素を削除（存在しない場合は何もしない）
sl.discard(10)
print(f"Discarded 10 (not in list): {sl}") # [1, 2, 3, 4, 5]

# remove(value): 要素を削除（存在しない場合はValueError）
sl.remove(1)
print(f"Removed 1: {sl}") # [2, 3, 4, 5]

# pop(index=-1): 指定されたインデックスの要素を削除して返す
pop_val = sl.pop(-1)
print(f"Popped last element ({pop_val}): {sl}") # [2, 3, 4]

# bisect_left(value): 二分探索で挿入位置を左側から探す
print(f"Bisect left of 2: {sl.bisect_left(2)}") # 0

# bisect_right(value): 二分探索で挿入位置を右側から探す
print(f"Bisect right of 2: {sl.bisect_right(2)}") # 1

# count(value): 指定された値の出現回数を取得
print(f"Count of 2: {sl.count(2)}") # 1

# index(value, start=0, stop=None): 指定された値のインデックスを取得（存在しない場合はValueError）
print(f"Index of 2: {sl.index(2)}") # 0

# __getitem__(index): 指定されたインデックスの要素を取得
print(f"Element at index 1: {sl[1]}") # 3


```
devise入力フォームカスタマイズ

# 初学者の備忘録
初学者の備忘録です。今回は前に投稿したの[devis編](https://qiita.com/Kooszs12/items/4bf3e25c4d3deda8b309)の続きのような,deviseを使用した入力フォームのカスタマイズ編になります。


## 今回の目標
１：サインアップの時に名前（nameカラム）も一緒にデータベースに保存されるようにする！
２：サインインの時にemailではなくnameでサインイン出来るようにする！


## サインアップの時にnameの入力フォーム追加
【１】　マイグレーションファイル
まずはnameカラムを追加してきましょう。
```diff_ruby:db/migrate/（年月日時分秒）_devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""

## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at

## Rememberable
t.datetime :remember_created_at

## Trackable
# t.integer :sign_in_count, default: 0, null: false
# t.datetime :current_sign_in_at
# t.datetime :last_sign_in_at
# t.string :current_sign_in_ip
# t.string :last_sign_in_ip

## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable

## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at

## 名前を保存するカラム
+t.string :name
t.timestamps null: false
end

add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
```
マイグレーションファイルに追記したので忘れずに`$ rails db:migrate`しましょう。


【２】　View
入力フォームのViewにもname入力フォームを追加します。
```diff_ruby:app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|　%>
  <%= render "user/shared/error_messages", resource: resource %>

  <!--名前入力フォーム追加-->
  +　<div class="field">-->
    +　<%= f.label :name %><br />
    +　<%= f.text_field :name %>
  +　</div>
  
  ... (省略)

<%= render "user/shared/links" %>
```
追記によって入力フォームにNameフォームが追加されました。
![スクリーンショット 2023-09-21 18.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3503032/cc2903ef-d08c-4ac9-e57c-9d5690f6958b.png)


【３】　Controller
最後にControllerを変更します。
デフォルトではメールとパスワードしか許可されていません。そこで名前も許可します。
deviseのストロングパラメータを編集する場合、ApplicationController に記述していきます。
deviseのコントローラは直接修正できないため、全てのコントローラに対する処理を行える権限を持ApplicationControllerに記述する必要があります。

```diff_ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end
```
これでサインアップ時に名前も入力してデータベースに保存されるようになりました。
動作確認をして終了となります。お疲れ様でした。


## サインイン時にnameでログイン出来るようにする
Coming Soon
【TypeScript】2つの日時データの差を、日・時・分・秒に分けて求める

## 内容

二つの日時データ（Dateオブジェクト）の差を求めて、  
**残り時間は、あと何日と何時間 何分 何秒です！** とか表示したくて。  
毎度苦労するので、形に残しておこうと思いました。

## コード

ずいぶん泥臭い書き方になってしまいました。。  
日付を二つ引数で渡しますが、どちらが先の日付・後の日付でも構わないよう、
差を絶対値にしています。

```
/** 1日の秒数 */
const DAY_TO_SEC = 60 * 60 * 24;

/** 1時間の秒数 */
const HOUR_TO_SEC = 60 * 60;

/** 1分の秒数 */
const MIN_TO_SEC = 60;

/**
 * 二つの日時データの差を、日・時・分・秒に分解して求める。
 *
 * @param time1 比較したい日時：その1
 * @param time2 比較したい日時：その2
 * @returns { day: 日数の差; hour: 時間の差; minutes: 分の差; sec: 秒の差 }
 */
export function calcTimeDifference(
  time1: Date,
  time2: Date
): { day: number; hour: number; minutes: number; sec: number } {
  // 秒単位での差を求める・・・UNIXタイムからミリ秒部分を削って、以後の計算に利用する
  let diffBySec = 
    Math.abs(Math.floor(time1.getTime() / 1000)
    - Math.floor(time2.getTime() / 1000));

  // 何日差か計算
  const dateDiff = Math.floor(diffBySec / DAY_TO_SEC);

  // 何時間差か計算
  diffBySec = diffBySec - dateDiff * DAY_TO_SEC;
  const hourDiff = Math.floor(diffBySec / HOUR_TO_SEC);

  // 何分差か計算
  diffBySec = diffBySec - hourDiff * HOUR_TO_SEC;
  const minDiff = Math.floor(diffBySec / MIN_TO_SEC);

  // 何秒差か計算
  diffBySec = diffBySec - minDiff * MIN_TO_SEC;
  const secDiff = diffBySec;

  return {
    day: dateDiff,
    hour: hourDiff,
    minutes: minDiff,
    sec: secDiff
  };
}
```
Bubbleでストライプ模様の一覧を作成する方法！

備忘録として残します。
下記のような、一覧を作っていきましょう。超簡単です。
![202309212.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1263502/3d09b5c8-088b-b977-17c2-4ce57469847b.png)


1. Repeating Groupの中に背景となるShapeを配置する。
![名称未設定3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1263502/acb3b9a6-fcc7-84d2-b741-bdc135a99e0a.png)

2. ShapeのConditionalに"現在セルのindex数を2で割った時、余りがあるかないかの真偽チェック"を設定する。(セレクトボックスの中に<-modulo->という選択肢があります)
![20230921.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1263502/ac5dab63-f83c-f2d3-7413-b03ed32bc489.png)

3. 続けて、偽だった場合の背景の色を設定する。


以上です！
autonomalabsのAWSIMを動かしてみる

## 概要

AWSIMをforkしたプロジェクトに[autonomalabsのAWSIM](https://github.com/autonomalabs/AWSIM)があります．これは，一般車ではなく，レーシングカーのシミュレーションのようです．本記事では，これを動かしてみたいと思います！![Screenshot from 2023-09-21 17-23-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320782/fab81786-feb2-7369-a25d-41a571a10bee.png)

## インストール方法

基本的にはリポジトリのREADMEに従います．ただ，現時点で，実行ファイルをそのままダウンロードすることは出来なさそうだったので，Unityをインストールして，自らビルドする必要がありそうです．

## 遊んで見る

![Screenshot from 2023-09-21 17-51-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320782/848fd01a-1c6b-5c55-c2de-ee5eb6d2dc3a.png)

このメニュー画面で，人間が運転するか，ROSに接続するか，車を何台使うかなど，様々選択できます．人間が運転するを選択すると，特にプログラムを記述することなくシミュレータで遊ぶことができます．

<iframe width="600" height="360" src="https://www.youtube.com/embed/TA4e78xnGpQ" title="autonomalabs AWSIM HUMAN play" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

慣れないと少し難しいですが，カーレスゲームとしても割と面白いです．

また，ROSとの接続を使って，Joystickから操作するためのノードを以下に書いてみました！

```python
import rclpy
from autonoma_msgs.msg import VehicleInputs
from rclpy.node import Node
from sensor_msgs.msg import Joy


class AutonomaManualNode(Node):
    def __init__(self):
        super().__init__("awsim_autonoma_manual")
        self.publisher_ = self.create_publisher(VehicleInputs, "vehicle_inputs", 10)
        self.joy_subscriber_ = self.create_subscription(
            Joy, "joy", self.joy_callback, 10
        )

    def joy_callback(self, msg: Joy):
        self.get_logger().info(f"Axis 0: {msg.axes[0]}, Axis 1: {msg.axes[1]}")
        vehicle_inputs = VehicleInputs()
        vehicle_inputs.throttle_cmd = msg.buttons[1] * 20.0
        if msg.buttons[0] == 1:
            vehicle_inputs.brake_cmd = 1000.0
        vehicle_inputs.steering_cmd = msg.axes[0] * 100.0
        self.publisher_.publish(vehicle_inputs)


def main():
    rclpy.init()
    node = AutonomaManualNode()
    rclpy.spin(node)
    rclpy.shutdown()


if __name__ == "__main__":
    main()

```

このノードは，joystickの指令を，車への入力である`vehicle_inputs`に変換してpublishしている単純なものです．

シミュレータから，どのようなトピックが出ているかが気になる方は，
https://github.com/autonomalabs/AWSIM/blob/racing-main/docs/RacingSim/ROS2Interface/index.md
を参照してみてください．

## 強化学習で車体を一定速で直進させてみる

このシミュレーションにおいて，車への入力は速度のような単純なものではなく，スロットル(「エンジンに対して行う空気供給量を調整するという役割を持つパーツ・システムをいう」らしい)とハンドルの傾きとなっており，ダイナミクスなどを真面目に考えると，複雑になっている気がします．

なので，その複雑さを考慮せず制御を行うために，強化学習を導入してみようと思います．導入する手法はPETS([arxiv](https://arxiv.org/abs/1805.12114))というものです．

この手法は大まかに，ニューラルネットワークでダイナミクスモデルを学習し，学習されたモデルに対してMPCを行うといったものです．

今回は，その手法に対して，
$$
r = - \alpha (v_x - v_{x_{ref}})^2 - \beta (y - y_{ref})^2
$$
のような，直進しながら一定速度を出してほしいという気持ちを込めた報酬を設計して動かしてみました．

以下，結果の動画です．

<iframe width="1260" height="760" src="https://www.youtube.com/embed/-aA6xbMv0e0" title="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

このときは，15mphで動くようにパラメータを調整しました．ただ，見る限り上手く走っていないです．．．恐らく，学習不足か何かしらの実装ミスがあるのだと思います．上手く調整して走らせたいですね！
Điều kiện du học Mỹ: Bạn cần gì?

Khi bạn quyết định du học tại Mỹ, điều quan trọng nhất là hiểu rõ về các điều kiện và yêu cầu cần thiết để có được một trải nghiệm du học thành công. Dưới đây là một số điều kiện quan trọng bạn cần biết:

**1. Hồ sơ du học đầy đủ:** Điều đầu tiên bạn cần là một hồ sơ du học hoàn chỉnh và đầy đủ các giấy tờ cần thiết. Hồ sơ thường bao gồm hồ sơ xin visa, bằng tốt nghiệp, chứng minh tài chính, bảo hiểm du học, và các tài liệu khác.

**2. IELTS hoặc TOEFL:** Đa số các trường đại học và cao đẳng ở Mỹ yêu cầu bạn có điểm số IELTS hoặc TOEFL để chứng minh khả năng tiếng Anh. Điểm yêu cầu có thể khác nhau tùy theo trường học và chương trình học.

**3. Chứng minh tài chính:** Bạn cần phải chứng minh có khả năng tài chính để du học tại Mỹ. Điều này có thể thông qua tài khoản ngân hàng, hợp đồng tài trợ, hoặc học bổng.

**4. Visa du học:** Để nhập cảnh và học tại Mỹ, bạn cần xin visa du học Mỹ. Quá trình xin visa bao gồm phỏng vấn và đảm bảo rằng bạn đủ điều kiện để du học tại Mỹ.

**5. Thời gian và kế hoạch học:** Bạn cần xác định thời gian bạn muốn du học tại Mỹ và lựa chọn chương trình học phù hợp, bất kể là học bậc đại học, cao đẳng, thạc sĩ, hay chương trình ngắn hạn.

**6. Visa thường trú (nếu cần):** Nếu bạn muốn du học và định cư tại Mỹ sau này, bạn cần thận trọng về việc xin visa thường trú và cân nhắc kế hoạch dài hạn.

Để biết thêm chi tiết về điều kiện du học Mỹ và cách xử lý các thủ tục liên quan, bạn có thể truy cập Du học Việt Phương để nhận được sự hỗ trợ tận tâm và tư vấn chuyên nghiệp. Du học Mỹ là một cơ hội tuyệt vời để trang bị kiến thức và kỹ năng quý báu cho tương lai của bạn.