OmniAICreator/Qiita-1.07M huggingface dataset:
フレッツ光クロスでIPsecVPNを使用する。

仕事場の回線をフレッツ光クロスにしたが利用可能ポートが標準では16ポートx15ブロックでしかもランダム(!)なのでそのままではIPSecなどポートを任意に設定出来ないものについては接続が困難であった。
またNTTレンタル品のXG-100NEは最低限の機能しかなく10Gbを活かせるルータとしてはYamaha RTX1300ぐらいしか選択肢がなかった(そのRTX1300も業務仕様とはお世辞にも言えない)

そこで以下のような対策をとってみた。
・IPv4 over IPv6サービスのうち固定IPv4を取得する(固定IPを取得する事でポートの制約がなくなる)
・XG-100NEの配下にFortigate FG-60Dを設置しVPNサーバ専用とする
・XG-100NEにはWANx1 + LANx1の2ポートしか2.5/5/10Gbのインターフェースしかないため10GbのL2スイッチ(Netgear XS-708E)を間にいれる
・クライアントPCで10Gbを持っているものを所持していない為、検証用のサーバ(VMware vSphere環境下)にWindows Server2022を使用した。

構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546564/f556a1f6-e6d0-a747-783c-0182a345c4dd.png)

・発熱が多く信頼性も疑問なのでXG-100NEはインターネットGWとしての機能のみ持たせる
・FG-60DはVPNサーバの機能のみでUTMとしては利用していない
・10Gb-NIC搭載サーバはホスト1台のみなので検証に必要な仮想サーバは1つのホストにまとめた。
・原則的に冗長化はLACPとしたが将来的には余っているC2960をHA化しWi-Fi APを2台にして無線で冗長化をしたい

注意点
・XG-100NEのIPv4固定IPの設定は https://[XG-100NEのIP]:8888/t/ という隠しコマンドのようなURLです。
この画面のIPv4設定を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546564/d7ecf85c-09ca-d97a-060f-c350be2a06e3.png)
高度な設定を選択し一番下に取得した固定IPv4アドレスを入力します(DHCPで取得しているものとは異なります)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546564/c180f341-11b0-151a-758a-2539c9b845f9.png)

Topに戻ると利用可能ポートが0-65535になっているはずです(上記設定前は悲しいポート制限がされています)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546564/a531ec3d-a1a4-d598-ba38-a1b105cb704c.png)

次に静的NATPでVPNに必要なポートはFG-60Dに振り分ければOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546564/3e943001-ac90-762b-04cd-1395400e66b6.png)

今回はFG-60Dの設定内容なUTMについては触れていません。

しかし10Gbの業務用ルータっていつになれば手が届くのですかね・・
グローバルなモデルの機器だとIPv4 over IPv6への対応が絶望的ですので。

もっとも一番むかつくのは固定IPの設定方法が事実上、隠されている事だと思います。
おかげでXG-100NEではポート開放は不可能とまで言うサイトまでありますので。
機械類や設定を考えるとNuroBizなどが楽ですがお値段がですね・・
Bizでなければ安いけど結局は光クロス同様に多段ルータにする事になるかと思います。

一応速度計測をしてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546564/e91ec5c6-a247-5cc9-f794-37e6d4b6af04.png)
意外とやらかすのは仮想マシンのNICはE1000にすると上限1GbになるのでVMXNET3やパススルーを使いましょう。

VPNに関しては対応側の問題とFG-60Dが1GbのI/Fしか持たないため割愛します。

機材が揃わないと10Gbの恩恵はセキュリティを緩めないと難しいですね。
・HGWに相当する部分の選択肢が非常に少ない(LAGも組めないしI/Fが最低限しかない)
・2.5/5/10Gbに対応するスイッチが高価である
・Wi-Fiは11axにXG-100NEは対応しているが設定内容が実用にならない・・
・セキュリティがゼロトラスト構想でもしないと担保出来ない(10Gb UTMなんて買えないw)
【Git】git rm でファイルの削除を記録する方法

- ファイルの削除をステージに記録する場合は `git add` とは別のコマンドを使用する必要がある
- 一度コミットしてしまったファイルをGitの記録から削除するのにも別のコマンドを使います

# ファイルの削除を記録

`git rm` コマンドを使うとコミットされたGitの記録からも消えて、ワークツリーのファイルからも消えます。

> ＞_ コマンドライン
> 

```bash
# ファイルごとの削除
> git rm <ファイル名>
> git rm -r <ディレクトリ名>
```

ファイルを削除したいときは `git rm <ファイル名>` 

ディレクトリを削除したいときは `git rm -r <ディレクトリ名>`

**ファイルがいらなくなった時はこちらのどちらかを使う**

ワークツリーにはファイルを残したくて、Gitの記録からは削除したい時は

> ＞_ コマンドライン
> 

```bash
# ファイルを残したいとき
> git rm --cached <ファイル名>
```

`git rm --cached <ファイル名>` というコマンドを使います。

**ファイルはいるけどGitの記録だけ削除したい時はこちらを使う**

# git rm の使用方法

**例**：ワークツリーに `index.html` がありそれをコミットして リポジトリにも `index.html` が記録されているとします。

```mermaid
flowchart LR

D[index.html/削除] ---- E[git rm] ---- F[index.html/削除]

A[ワークツリー] ---- B((ステージ)) ---- C((リポジトリ))
```

`git rm` コマンドを打つと**ワークツリー**と**リポジトリ**の `index.html` ファイルが削除されます。
問題と課題の違い

あるべき姿と現状のギャップが 問題 (Problem) です。 
その問題を解決していくために具体的に取り組むべきことが 課題 (Challenge) です。

ストーリー
--
ある日、「東京」に住む主人公の「真理」は、愛犬の「太郎」がいつものように元気がないことに気づきました。太郎が元気がないというのは、真理にとっての「問題」でした。太郎は普段は活発で陽気な性格なのに、今日はぐったりしていて、望ましい状態ではありません。真理は心配し、動物病院に連絡しました。獣医師は太郎を診察し、病気の原因を突き止め、適切な治療を行いました。太郎が回復し、元気を取り戻すと、真理の問題は解決されました。

その後、真理は友人から「都市の愛犬レース大会」に参加するよう誘われました。真理は太郎を連れて参加することに決めましたが、レースは太郎にとっては

初めての経験でした。

太郎は速く走ることは得意ですが、障害物を飛び越えたり、曲がりくねったコースを通ったりするのは難しい課題でした。真理と太郎は一緒にトレーニングを始めました。最初は難しかったですが、真理は太郎の能力を引き出すために工夫し、徐々に課題を克服していきました。トレーニングの過程で、太郎は新しいスキルを習得し、真理との信頼関係が深まりました。

レース当日、太郎は初めての課題を乗り越えて、見事にゴールに到達しました。
真理と太郎は、共に課題を乗り越えたことで更なる絆が築かれ、成長したのです。

このストーリーを通じて、太郎の健康の問題とレースの課題が異なる状況であることが示されています。
問題は既存の状態がうまくいかない状況を指し、解決が求められます。
一方、課題は新しい目標に向かう際に克服すべき困難を指し、努力や協力を通じて成長や経験がもたらされる可能性があります。

問題 (Problem)
--
問題は、ある状況や状態において解決が必要な何か困難なことを指します。何かがうまく機能していない、矛盾している、または望ましい結果が得られない場合に、問題が存在すると言えます。問題は一般的に解決を求める状況や障害を示します。

課題 (Challenge)
--
課題は、難しい仕事や任務、または達成が難しい目標を指します。課題は単に問題だけではなく、成長や進歩を促す要素として捉えることもできます。課題は、個人や組織が努力し、スキルや能力を向上させるための機会としてとらえられることもあります。

要するに、問題は何かがうまくいかない状況や障害を指し、解決を求める必要があります。

一方、課題は目標達成や成長に向けて取り組む難しい仕事や任務を指し、解決する必要があるとは限りません。
__課題は挑戦として捉えることができると思います。__

## あなたの今の課題は、何ですか？ ##

私の現在の課題は、教える事です。

「教えることで教わる」というのは、教育のプロセスにおいてよく言われる言葉です。

この考え方には、10の理由があります。

1. **理解を深める**
他人に教える際には、自分が理解しているつもりでも、実際にその知識や概念を他人に説明するためには、さらに深い理解が必要です。他人が理解できるように情報を整理し、適切な語彙や例を選ぶことで、自分の理解も深まります。

2. **新たな洞察が得られる**
教える際には、相手からの質問や疑問に答える必要があります。その過程で、自分が考えていなかった視点や情報に触れることがあり、新たな洞察が得られることがあります。疑問を解決するための調査や研究を通じて、自分自身の知識が向上します。

3. **相手の反応への対応スキルが上がる**
教えることで、相手がどのように反応するかを観察することができます。相手の反応を通じて、自分の伝え方や説明の仕方を調整し、より効果的なコミュニケーションスキルを磨くことができます。

4. **教材の改善**
教材や教授法を他人に伝えることで、その教材の優れた部分や改善すべき点に気付くことがあります。他人のフィードバックを通じて、教材を洗練させることができます。

5. **共感と関係構築**
教えることで、他人のニーズやレベルに合わせて情報を提供することが求められます。その過程で相手との共感や信頼関係が構築され、より良いコミュニケーションが実現します。

6. **自己評価と成長**
自分の知識やスキルを他人に教えることで、自己評価を行う機会が生まれます。自分の得意な点や改善が必要な点を客観的に見つめ、個人的な成長を促進することができます。

7. **新しい知識と技術の獲得**
年下の世代は、新しい技術や知識にアクセスしやすく、それらを取り入れています。年長者が年下から学ぶことで、最新の情報や技術を得ることができます。これにより、過去の方法だけでなく、現代のニーズに合ったアプローチを見つけることができます。

8. **逆の視点からの学び**
年下の人々は異なる視点や経験を持っています。年長者が年下から学ぶことで、新しいアイディアやアプローチを取り入れることができます。これにより、より多様な視点を持つことができ、問題に対するより創造的な解決策を見つける手助けとなります。

9. **柔軟性と適応力の向上**
社会や技術の変化は速いものです。年下の世代は変化に適応するスキルを持っていることが多く、年長者がそのスキルを学ぶことで、柔軟性と適応力を向上させることができます。

10. **世代間のつながりを強化**
世代間のつながり: 年長者が年下に教わることは、世代間のつながりを強化する手段でもあります。お互いに尊重し合い、学び合うことで、異なる世代同士のコミュニケーションが促進され、社会全体の調和が生まれる可能性があります。

そんな訳で、最近、AWSの勉強会をするようになりました。(すべての AWS 認定資格を持っています。)
興味がある方は、お気軽にお声がけください。

対象：AWS Certified Solutions Architect  Professional を目指す方
アソシエーションで紐付けられたテーブルの片方をrails db:migrate:redoを使って編集しようとしたらできなかった件について

## 今回やりたかったこと
usersテーブルとtasksテーブルを1:多でテーブルの紐付けを行った後にusersテーブルにaddressをいうカラムを追加しようと思って直接マイグレーションファイルにカラム名とデータ型を入力して、rails db:migrate:redoを実行しようとしたらエラーが出た。

## ではなぜ、エラーが出たのか？
**rails db:migrate:redoは見えていないだけで実は、<font color = red>一度ファイルをdownをにして、その後にupをしている。</font>**
そのため、紐付けたテーブル同士の依存関係があるアソシエーションでは、片方のマイグレーションファイルをredoでを使って編集しようとした場合、<font color = red>片方だけがdownになってしまうので、もう片方のテーブルとの整合性が取れなくなる</font>ことから、それを阻止するためにrailsがエラーを出す

## ではどうやってカラムの編集を行うのか
**結論、新しくマイグレーションファイルを生成し、変更したいカラムを追加・削除・変更する。**
こうすることによって、既存のマイグレーションファイルをdownにしなくても良いため、エラーは起こらない。
もしくは、整合性の観点から紐付けたテーブルのマイグレーションファイル両方をdownする。その後、マイグレーションファイルを編集して、rails db:migrateで両方をupする方法もあるらしいが、個人的には新たにマイグレーションファイルを生成した方がやりやすいため、今後はそっちを使っていこうと思う。
OpenStudio Measureの概要

# OpenStudioを効率よく運用する方法
EnergyPlus/OpenStudioの日本語版テキストや講座資料を見ると、ほとんどがSketchUpプラグインで建物の形状を作り、OpenStudioのインターフェイスで簡単に編集をして、細かい所を出力されたファイルをIDF Editorで直すという作業を行っている。この方法で致命的なのは、IDF EditorからOpenStudioに戻れないということで、もし形状が変わったり、モデルに間違いがあると、元のOpenStudioファイルから編集して、IDF Editorでの作業をやり直さなければいけない。しかしOpenStudio Measureを使いこなせるようになれば、そもそもIDF Editorを使わなくてよくなり、効率よくEnergyPlusを活用できるようになる。そこで今回はOpenStudio Measureの概要とその使い方について解説する。

# OpenStudio Measures
[OpenStudio Measure](https://nrel.github.io/OpenStudio-user-documentation/getting_started/about_measures/)はRubyで書かれたスクリプトのことで、インターフェイスでポチポチクリックして編集しなければいけないところを一気に編集させることができる。さらに通常インターフェイスで編集できない[Schedule:Compact](https://bigladdersoftware.com/epx/docs/9-1/input-output-reference/group-schedules.html#schedulecompact)なども触ることができるので、IDF Editorを使用せずにモデルを修正することができる。個人的によく使うのは、SketchUpからモデルを作ると、不要なスケジュールや外皮などがいっぱいついてくるので、それらを全部削除してくれるMeasureで、モデルをかなりスッキリさせられる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660870/6d7d5064-8a22-6d7f-4b5a-51e5926ff068.png)
しかし、建築の専門家にRubyの勉強のをしないとこの便利な機能が使いないとなればハードルが上がってしまうため、利用者が少なくなってしまう。そのため、開発者のNRELはMeasureを共有するためにBuilding Component Library (BCL) を作り、他の人が公開しているものをダウンロードし、そのまま自分のモデルに適用することができる。先ほどの例のように、色んな人がよく行っている作業は既にBCLに共有されていて、様々な作業を効率化されることができる。2023年8月現在、約270のMeasureがBCLに公開されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660870/25f6c84c-f4fa-de03-c555-6456e8f76618.png)

# Measureの使い方
例えば建物全体の照明を20％下げる例を見てみる。インターフェイスのみで編集する場合は、LoadsタブからLights Definitionの中身を一つ一つ変えていかなければいけない。

Measureを適用する場合は、ツールバーの"Components & Measures"の"Apply Measure Now"を選択し、そこから出てきた画面で、"Electric Lighting"から"Reduce Lighting Loads by Percentage"を選び、入力で照明負荷を20％下げる。"Apply Measure"を押すとすべての部屋の照明負荷を編集することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660870/63b52912-2bce-5dce-6c1b-77fae050cd3f.png)

もし、10％減、20％減、30％減のようにいくつかの照明負荷の減少を比較したい場合、元の照明負荷を変更せずにMeasureを適用する方法もある。"Measures"タブから、右側のLibraryパネルの"Electric Lighting"を広げて、"Reduce Lighting Loads by Percentage"を選択すると、上記と同じように照明負荷を変更できる。しかし、先ほど違うのは、すぐに照明負荷を変更するのではなく、解析を行う直前にMeasureが適用されるので、ここの入力を変更するだけで比較が可能となる。さらに比較を一度に行うためには、Openstudioと一緒にダウンロードされるParametric Analysis Tool（PAT）を使うとMeasureを使ったパラメトリック解析が可能になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660870/33286881-ff39-45f6-554f-779737fff3eb.png)

これは簡単な例だが、Measureによっては空調システムを自動的に作成したり、LEEDモデリングのASHRAE 90.1 Appendix G Baselineモデルを作成することもできる。

# Measureのダウンロード方法
### アプリケーション内から
一番簡単なのは、ツールバーの"Components & Measures"から"Find Measures"を選び、該当するカテゴリーからMeasureを探す方法。検索バーからMeasureを絞り込むこともできる。ほしいMeasureにチェックを付けて、下の"Download"ボタンを押すと、Measureがモデルに適用できるようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660870/86ca8f2a-a229-82d4-5c07-13bf442b8a76.png)

### BCLサイトから
もう一つの方法はBCLのサイト（[Building Component Library](https://bcl.nrel.gov/)）からダウンロードするやり方。ダウンロードしたファイルはC:\Users\\[ユーザー名]\OpenStudio\Measuresに入れないと現れない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660870/4ae44e51-2921-6219-0ab1-c319583aae72.png)
ドメイン変更後に旧URLへのアクセスをCloudFrontでリダイレクトする

# 概要
example.com ⇒ sample.net にドメインを変更した場合、AWSのCloudFront Functionを使えば簡単にリダイレクトできます。

# CloudFrontのディストリビューションを作成します。
## オリジンドメイン
どちみち設定したオリジンにはアクセス行かないので、オリジンドメインは何でもOKです。

## 代替ドメイン
**旧**ドメインを設定します。
<a href="https://gyazo.com/6992f1dcdd3811f3eb6f9c05c1a5ad49"><img src="https://i.gyazo.com/6992f1dcdd3811f3eb6f9c05c1a5ad49.png" alt="aws証明書マネージャーページのスクリーンショット" width="805.3333333333334"/></a>

## カスタムSSL証明書
**旧**ドメインで使用していた証明書を設定します。

そのほかはデフォルトでOKです。

# CloudFront Functionを作る
メニューから「関数」を選びます。表示されたページ内の「関数を作成」から関数を作ります。
<a href="https://gyazo.com/3ec256d9dc3ee9107574b9b5a390e6cd"><img src="https://i.gyazo.com/3ec256d9dc3ee9107574b9b5a390e6cd.png" alt="Image from Gyazo" width="368"/></a>

## 関数
すべてをリダイレクトするように関数を書きます。
stringifyQueryStringは[こちらのページ](https://tech.enechange.co.jp/entry/2022/05/31/161435)を参考にさせていただきました
```javascript
var querystring = require('querystring');

function stringifyQueryString(eventQueryString) {
    var query = {};
    Object.entries(eventQueryString).forEach(function(q) {
        query[q[0]] = q[1].multiValue ? q[1].multiValue.map(function(m) {return m.value}) : q[1].value;
    });
    return querystring.stringify(query);
}

function handler(event) {
    var request = event.request;
    var headers = request.headers;

    var response = {
        statusCode: 302,
        statusDescription: 'Found',
        headers:
            { "location": { "value": `https://[新ドメイン]${request.uri}?${stringifyQueryString(request.querystring)}` } }
        }

    return response;
}
```

※このままだとクエリパラメータが無いときに無駄に「?」が付くので気持ち悪い人はちゃんと作ってください。

## 発行
発行します。
<a href="https://gyazo.com/99ab46cb6286aedf5ee486d418b3cecf"><img src="https://i.gyazo.com/99ab46cb6286aedf5ee486d418b3cecf.png" alt="Image from Gyazo" width="970.6666666666666"/></a>

同じ画面の「関連付けられているディストリビューション」から先ほど作ったディストリビューションを紐づけします。

# 旧ドメインのCNAMEあるいはAレコードにディストリビューションを設定
旧ドメインのCNAMEやAレコードにディストリビューションのドメインを指定します。
ディストリビューションのドメインとは一覧の「ドメイン名」列にあります。
<a href="https://gyazo.com/41faecc362739fb5eb488487db05e774"><img src="https://i.gyazo.com/41faecc362739fb5eb488487db05e774.png" alt="Image from Gyazo" width="989.3333333333334"/></a>


これでリダイレクトします！



サブドメインの変更として書いてある記事がいくつかありましたが普通にドメイン変更した場合でも同様に行けました。コストも低いし便利です。クエリパラメータを維持してリダイレクトできるのも嬉しいです。
以前は[S3を使ったリダイレクト](https://qiita.com/takahiko/items/342f0726fe88987db93c)などありましたが、今はCloudFront Functionを使うほうが早くて安くて楽です。


もっといい案もある気がするのでお勧めリダイレクト設定案教えてください。
Windows・Linuxからコマンド1行でDiscordにメッセージを送信する

Discordで自分用のサーバーを作っておき、そこにプログラム等から通知を送るようにしておけば、スマホにも通知が届いて何かと便利。自動実行をしているプログラムが想定外の動作をした時や、サーバー障害を検出した時など。

通知を送るには、まずDiscordクライアントで通知を送りたいチャンネルの設定を開き、Webhook（ウェブフック）を作成する。URLをコピーしておく。

![2023-08-30_14h31_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209963/bc1ffa46-5610-e3b0-38e8-59bb6a49d550.png)

WindowsのコマンドプロンプトやLinuxのシェルからメッセージを送信するには、curlコマンドを使って以下のように実行する。curlは多くのLinuxディストリビューション及びWindows 10のバージョン 1803以降ならデフォルトでインストールされている。

```BAT
curl -H "Content-Type: application/json" -X POST -d "{\"username\": \"ユーザー名\", \"content\": \"メッセージ本文\"}" ウェブフックURL
```

このコマンドをLinuxならシェルスクリプト、Windowsならバッチファイルに書き、他のプログラム・スクリプトやCron・タスクスケジューラから実行することもできる。

ただし、最近のWindowsでデフォルトになっているPowershellの場合、curlコマンドはInvoke-WebRequestコマンドのエイリアスとして設定されているため、同じコマンドだとエラーになる。Invoke-WebRequestで実行することもできるが、コマンドが複雑になる上、日本語が文字化けしたりする。cmd.exeを介して以下のように実行することはできる。

```Powershell
cmd.exe /c 'curl -H "Content-Type: application/json" -X POST -d "{\"username\": \"ユーザー名\", \"content\": \"メッセージ本文\"}" ウェブフックURL
```

Discordはサーバー・チャンネルごとに通知をカスタマイズすることができるので、スマホにもプッシュ通知を送るチャンネルと、通知は行わず情報を貯めておいて時間のある時に見るチャンネルを分けるといった使い分けをすると便利。
RubyMine2023.2.xでDockerコンテナ内のコードをデバッグ実行が動かない問題とその解決法

Dockerコンテナで動いているRailsベースのバックエンドサービスのデバッグをしようとしたところ、debaseとruby-debug-ideがインストールされてないということで、RubyMineがこの２つのgemをインストールしようとしたものの、コケてしまう現象に遭遇しました。

エラーメッセージに下記のような内容が出力されているので

```
Successfully installed debase-ruby_core_source-3.2.1
Building native extensions. This could take a while...
ERROR:  Error installing ./debase-3.0.0.beta.7.gem:
	ERROR: Failed to build gem native extension.

    current directory: /usr/local/bundle/gems/debase-3.0.0.beta.7/exto
/usr/local/bin/ruby -I /usr/local/lib/ruby/3.2.0 extconf.rb
checking for vm_core.h... no
checking for vm_core.h... no
**************************************************************************
No source for ruby-3.2.1-p31 (revision 31819e82c88c6f8ecfaeb162519bfa26a14b21fd) provided with
debase-ruby_core_source gem. Falling back to ruby-3.2.0-p0.
**************************************************************************
checking for vm_core.h... yes
checking for iseq.h... yes
checking for method.h... yes
checking for version.h... yes
creating Makefile
/usr/local/bundle/gems/debase-3.0.0.beta.7/exto/extconf_common.rb:75:in ``': No such file or directory - g++ (Errno::ENOENT)
	from /usr/local/bundle/gems/debase-3.0.0.beta.7/exto/extconf_common.rb:75:in `build_makefile'
	from extconf.rb:2:in `<main>'

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /usr/local/bundle/extensions/x86_64-linux-musl/3.2.0/debase-3.0.0.beta.7/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /usr/local/bundle/gems/debase-3.0.0.beta.7 for inspection.
Results logged to /usr/local/bundle/extensions/x86_64-linux-musl/3.2.0/debase-3.0.0.beta.7/gem_make.out
```

エラーをよく読んでみると

**No such file or directory - g++ (Errno::ENOENT)**

そうか、コンパイラがなくてネイティブコードがビルドできなかったのか。。。

Dockerファイルに

```dockerfile
RUN apk add alpine-sdk # alpineベースの場合
RUN apt install build-essential # debianベースの場合
```
を追記してdockerイメージを作成しなおした後で、RubyMineでデバッグするとdebase-3.0.0.beta.7.gemとruby-debug-ide-3.0.0.beta.12.1.gemのインストールが成功し、デバッグもできるようになりました。
VanJSのderiveのAPIが、ReactのuseEffectやuseMemoより賢いと思う３つの点

VanJSには`van.derive`というAPIがあります。引数にコールバック関数を渡して、関数内で使用しているState変数の値が変わると、コールバック関数が実行されるというものです。Reactユーザーにとっては`useEffect`や`useMemo`のhooksと同じようなことができる、と言うと分かりやすいと思います。※正確には全く同じ動きではないので注意

ですが、実際に`van.derive`を使用するとReactの`useEffect`や`useMemo`より賢いと思う部分があったので、3点ご紹介したいと思います。

## 理由

### 1.第２引数不要

Reactの`useEffect`や`useMemo`は第2引数に、どの変数が変更された時に、コールバック関数を実行するか指定する必要があります。（第2引数を指定しないこともできるが、用途が変わってくるため今回は考えない）

例えばReactの`useEffect`で、`count`の値が変更される度にコールバック関数を実行したい場合は、以下のように書きます。

```typescript:React
useEffect(() => {
  console.log(count)
}, [count])
```

しかしVanJSは第2引数を指定する必要はありません。コールバック関数内でState変数を使用していれば、その値が変更される度にコールバック関数が実行されます。以下の例では`count`の値が変更されると、自動的にコールバック関数が実行されます。

```typescript:VanJS
van.derive(() => {
  console.log(count)
})
```

些細なことかもしれないですが、わざわざ変数を指定しなくて済むためコードの記述量が減りますし、変数の指定忘れによるバグが防げます。

### 2.useEffectとuseMemoのどちらにも対応可能

`van.derive`はReactの`useEffect`と`useMemo`の両方を動きが実現できます。

`useEffect`の動きは1で説明したので省略。

Reactで`useMemo`を使用する場合は、以下のように書きます。`count`の値が変更される度に、コールバック関数が実行されます。

```typescript:React
const calculateExpensiveValue = useMemo(() => {
  let result = 0

  for (let i = 0; i < count * 100000000; i++) {
    result += i;
  }

  return result
}, [count])
```

VanJSで`useMemo`の動きを実現したければ、同じように変数を宣言して、`return`で値を返せばOKです。第２引数は不要です。以下の例でも、`count`の値が変更されると、自動的にコールバック関数が実行され、`calculateExpensiveValue`の値が変わります。

```typescript:VanJS
const calculateExpensiveValue = van.derive(() => {
  let result = 0

  for (let i = 0; i < count.val * 100000000; i++) {
    result += i
  }

  return result
})
```

### 3.最小限の関数の実行

これは実際の動きを見た方が分かりやすいと思うので、DEMOを用意しました。ブラウザの検証ツールで**コンソールログ**を見て、どの条件の時にコールバック関数が実行されるか確認してみてください。

https://stackblitz.com/edit/vitejs-vite-hfbnfw?file=src%2FApp.tsx

https://stackblitz.com/edit/vitejs-vite-erqcdk?file=src%2Fmain.ts


Reactの場合は`toggle`、`toggle2`、`toggle3`のどの値が変更されても必ずコールバック関数が実行されます。

VanJSの場合は`toggle`が`false`の場合は`toggle2`や`toggle3`の値を変更してもコールバック関数は実行されません。これは`toggle`が`false`の場合、必ず`if`文の最初の条件の`toggle1.val`が偽になり、その後の条件の`!toggle2.val && !toggle3.val`の値を確認する必要が無くなるためです。

## まとめ

VanJSの`van.derive`のAPIが、Reactの`useEffect`や`useMemo`より賢いと思う点を３つ紹介しました。正確には同じ動きをする訳では無いため注意が必要ですが、`van.derive`は極力パフォーマンスを考慮して作られているのかなと感じました。


## 最後に

### GoQSystemでは一緒に働いてくれる仲間を募集中です！

ご興味がある方は以下リンクよりご確認ください。

https://goqsystem.recruit.site?qiita=92bfd4d1c37f9beebef6
初心者がAIチャレンジやってみた（14）：オンライン環境に提出してみる

# 概要
「初心者がAI Challengeやってみた」シリーズの第14弾です。
今回は今までで取り組んできたコードをオンラインウェブサイトに提出して、スコアを見てみます。

本シリーズでは[Japan Automotive AI Challenge 2023](https://www.jsae.or.jp/jaaic/)にautoware初心者の筆者が試行錯誤しながら挑戦する記録を公開しています。自動運転に興味があるけどプログラミングに自信が無い方などの参考になれば幸いです。

前の記事はこちら：
* 第1弾：[初心者がAIチャレンジやってみた(1)](https://qiita.com/h_bog/items/86fba5b94b2148c4d9da)：Autowareを動かしてみる
* 第2弾：[初心者がAIチャレンジやってみた(2)](https://qiita.com/h_bog/items/a36df3042a342bd2a0c5)：1つ目の障害物の回避成功
* 第3弾：[初心者がAIチャレンジやってみた(3)](https://qiita.com/h_bog/items/849a4241cdef257f3b3a)：2つ目の障害物の回避成功
* 第4弾：[初心者がAIチャレンジやってみた(4)](https://qiita.com/h_bog/items/8bce776fef0a39676c46)：全障害物回避達成！（全パラメータ公開）
* 第5弾：[初心者がAIチャレンジやってみた(5)](https://qiita.com/h_bog/items/4ed94ef6256ac5ae9c03)：開発環境の再構築（番外編）
* 第6弾：[初心者がAIチャレンジやってみた(6)](https://qiita.com/h_bog/items/075543f30f9b3432fa1d)：Autoware-Miniを使ってみる
* 第7弾：[初心者がAIチャレンジやってみた(7)](https://qiita.com/h_bog/items/bcfd5648afa8b6dee5b3)：外部モジュール導入（失敗）
* 第8弾：[初心者がAIチャレンジやってみた(8)](https://qiita.com/h_bog/items/368543a4b10b356db0e5)：自作パッケージの導入
* 第9弾：[初心者がAIチャレンジやってみた(9)](https://qiita.com/h_bog/items/c84c4886c0ba0e6c1724)：障害物回避モジュールの作成①
* 第10弾：[初心者がAIチャレンジやってみた(10)](https://qiita.com/h_bog/items/a2c2cbdcec6a852bfcd5)：障害物回避モジュールの作成②（成功？）
* 第11弾：[初心者がAIチャレンジやってみた(11)](https://qiita.com/h_bog/items/4160e396fc5def3c8383)：障害物回避モジュールの改良①
* 第12弾：[初心者がAIチャレンジやってみた(12)](https://qiita.com/h_bog/items/c7ffd9d51e01adf8e021)：障害物回避モジュールの改良②
* 第13弾：[初心者がAIチャレンジやってみた(13)](https://qiita.com/h_bog/items/770e4e2437a963082b12)：障害物回避モジュールの改良③

:::note warn
筆者はautoware初心者です。
説明等が正確でない可能性があるので本記事だけではなく他の記事や[autowareのドキュメント](https://autowarefoundation.github.io/autoware-documentation/main/)も確認するようにしてください。
:::

# 目標
AI Challengeの締切日が近づいてきました。
そこで今回はオンラインサイトに今まで取り組んできたコードを提出して、何点のスコアが得られるのかを確認してみます。

なお、今回提出するコードは「最初の障害物を無視する」というずるをしています。
[大会ルール](https://automotiveaichallenge.github.io/aichallenge2023-sim/rule/index.html#regulation)の以下の点に反する実装となっているので、提出後は大会運営者様に連絡をして無効にしてもらっています。

> 決勝大会での走行時に危険が伴うため、あらかじめ経路を設定して決め打ちで走行するようなアルゴリズムにはしないでください。

# オンライン環境に提出
[公式サイト](https://automotiveaichallenge.github.io/aichallenge2023-sim/online/index.html#upload-procedure-to-online-environment)の手順に従って提出します。
非常にシンプルな手順なので特に補足はありません。

以下で説明する提出用ウェブサイトは大会参加者しかアクセスできませんが、[手順](https://automotiveaichallenge.github.io/aichallenge2023-sim/online/index.html#upload-procedure-to-online-environment)の「動作確認」部分を実行すれば非公式ですがスコアを確認することができます（大会期間終了後でもスコアを確認できそうです）。


提出画面はこんな感じです。
コードを提出してから実際に採点されるまでに30~60分程度かかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3483805/48ec71a7-bdaa-1b0f-fe8f-3e7f84953833.png)

私のスコア（＝距離点）は83.85でした！
距離点が高ければ高いほど良く、多分最後の障害物辺りまで行くとこれくらいのスコアになるのかなと思います。

判定は結構厳しめで、車両が障害物と接触した場合はもちろんですが、走行レーンの外に車体が少しでも出れば終了となります。

ちなみに私が提出した時点で他にも提出した方々がたくさんおり、多くの方が100点超え、中には140点を超えている方々もいました！皆さんすごいですね。


# まとめ
今回はオンラインウェブサイトにコードを提出してスコアを確認してみました。

大会には間に合わないかもしれませんが引き続きコードを改良していこうかなと思います。
特に最後の障害物を走破できるレベルまでに持っていきたいです。
github 最初のコマンド

# 初めに
自分のコードをgithubにrepositoryをアップロード（push)する時のコマンドの説明です。

# 典型的なコマンド

```terminal
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/<あなたのgithub repository.git>
git push -u origin main
```

## コマンドの意味

```terminal
git init
```
現在のディレクトリを新しいGitリポジトリとして初期化します。
このコマンドは.gitという隠れディレクトリを作成し、リポジトリのメタデータを格納します。

```terminal
git add README.md
```
README.mdファイルをGitのステージングエリアに追加します。ステージングエリアは、次のコミットに含める変更を一時的に保存する場所です。

```terminal
git commit -m "first commit"
```
ステージングエリアの変更をリポジトリにコミット（保存）します。コミットメッセージとして"first commit"を使用します。 コミットはリポジトリの歴史に永続的に保存されるスナップショットです。

```terminal
git branch -M main
```
現在のブランチの名前をmainに変更します。
-Mオプションは、ブランチがすでに存在する場合でも強制的に名前を変更します。

```terminal
git remote add origin https://github.com/<あなたのgithub repository.git>
```
 新しいリモートリポジトリを追加し、それをoriginという名前で参照します。
originはリモートリポジトリ（この場合はGitHub上のリポジトリ）のショートカット名です。

```terminal
git push -u origin main
```
ローカルのmainブランチをoriginリモートリポジトリにプッシュ（アップロード）します。
-uオプションは、今後git pushやgit pullを実行する際にリモートリポジトリとブランチ名を指定しなくても済むように、追跡関係を設定します。

# 覚える内容

* branch名　：　前はdefaultとしてmasterでしたが、master-slaveという差別的要素があることで、最近はmainにする傾向があります。

* main: これは**ローカルPCにあるブランチの名前**です。このブランチには、あなたが作業している変更が含まれています。ローカルブランチはあなたのコンピュータ内に存在し、その変更はリモートリポジトリにプッシュするまで他の人には見えません。

* origin: これは**リモートリポジトリ（この場合はGitHub上のリポジトリ）のショートカット（エイリアス）名**です。git remote add コマンドで設定されます。originは通常、リモートリポジトリのデフォルト名とされます。

* git push -u origin main というコマンドは、**ローカルの main ブランチの内容を origin として設定されたリモートリポジトリにプッシュ（アップロード）**します。この操作により、**ローカルとリモートの両方が同期**されます。

* ローカルの変更を強制的にリモートに適用したいときは、--force オプションを使用します。
```terminal
git push -u origin main　--force
```
GradleでBOMを利用する時の注意点

# はじめに
Gradleにはタスクの定義/実行や依存関係のコントール等、便利な機能が様々あると思います。
今回は、ライブラリのビルド依存関係を追加する場合のTipsを記載します。
BOMを利用する場合の注意点です。

:::note info
GradleはGroovy DSLの他にKotlin DSLでも記述可能だと思いますが、本記事の例はGroovyで記載しています。
また、ライブラリは例で記述した存在しないものです。
:::

# ちょっとふりかえり
## 依存関係の定義
Gradleで依存関係を定義する際、以下の様にdependencesを利用します。
例では記載のバリエーションの為、統一感の無い記述を行っていますが、**本来は実装を統一する方が視認もし易い**と思います。

```build.gradle
dependencies {

	implementation 'com.hulft:sample-library-a:1.0.2'
	
	//バージョンを省略したり
	implementation 'com.hulft:sample-library-a'
	
	//指定する要素毎に記述する事も可能
	implementation group: 'com.hulft', name: 'sample-library-a', version: '1.1.0'
	
}
```

依存ライブラリについて、　グループ : 名前 : バージョン(記載し無い事も可能)　という形で指定を行う事が可能です。

## BOMの利用
Gradleでは特定バージョンから、BOM(bill-of-materials)が利用可能です。
個人的な印象としては、ライブラリ自身が利用するライブラリのバージョンを含めた一覧、というイメージです。
BOM自体の詳しい説明は、[Gradle](https://docs.gradle.org/current/userguide/platforms.html#sub:bom_import)、[Maven](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#bill-of-materials-bom-poms)の公式サイトに記載されています。

GradleではBOMを以下の様に指定可能です。
```build.gradle
dependencies {

	//BOMの指定
	implementation platform('com.hulft:sample-library-dependencies:1.0.1.RELEASE')
	
}
```
例えば、BOMの定義上、以下の様な依存関係があった場合、
<dl>
    <dt>sample-library-dependencies</dt>
        <dd>sample-library-a : 2.0.1</dd>
        <dd>sample-library-b : 1.2.1</dd>
        <dd>sample-library-c : 1.2.3</dd>
</dl>

以下の様に定義する事で、個別に設定しているライブラリのバージョンを省略し、
BOM内に定義されているバージョンを利用出来ます。
```build.gradle
dependencies {

	implementation platform('com.hulft:sample-library-dependencies:1.0.1.DEV')
	
	//バージョン指定を省略
	//→ BOM内で定義されているバージョンのライブラリ(例では2.0.1)が利用される
	implementation 'com.hulft:sample-library-a'
	
}
```
# 注意点
特にライブラリ自身が依存するライブラリが多く、依存関係が複数ある場合、都度個別にバージョン指定するのは煩雑な場合もあると思います。
その様なケースでBOMの利用は依存管理の負荷を軽減してくれる、便利な機能だと思っています。

しかし、注意点も有ると思います。
例として、複数先から同じライブラリに対して依存を行う場合等が挙げられます。

以下の様なケースでは、sample-library-aのバージョン1.5.0を指定したつもりでも、
実際にはBOM内の定義とライブラリが衝突する事があり得ます。
```build.gradle
dependencies {

	//BOM内では sample-library-a : 2.0.1 が定義されている
	implementation platform('com.hulft:sample-library-dependencies:1.0.1.DEV')
	
	//BOM内で依存されているライブラリを直接指定して、特定のバージョンを指定
	//dependencies上はバージョン1.5.0が利用される様に見えてしまう
	implementation 'com.hulft:sample-library-a:1.5.0'
	
}
```
この様に異なるバージョンの同じライブラリを指定した場合の挙動は設定によって調整可能です。

<dl>
    <dt>例</dt>
        <dd>・Gradleが推移的依存関係から最も新しいバージョンを読込</dd>
        <dd>・ModuleDependency.excludeからBOM上の依存バージョンを除外</dd>
        <dd>・ResolutionStrategy.forceから依存バージョンを強制</dd>
</dl>

BOMは様々なシーンで便利に利用出来ると思いますが、BOM自体の定義を確認しないと、内部で依存しているライブラリの詳細に意識が向きにくい面もあると思います。
思わぬバージョン競合が起こり、それがデフォルト設定で解決されている様な場合、想定外のバージョンが読み込まれている、というような事もあり得そうです。

## 個人的な対策
当たり前かも知れませんが、依存関係部分を変更する際には、実際にどの様な依存関係となっているのか、を確認すると、想定外の事象を減らす事が出来ると思います。
```
gradle dependencies
```
ARCore SDK for Unityのサンプルプロジェクトのマーカーをなくす


ARCore SDK for Unity　のサンプルプロジェクトでスマートフォンにデプロイしたあと、スマートフォンをタップすると、こんなマーカーがでます。

[![Image from Gyazo](https://i.gyazo.com/7ca3034b770cd4b9ae9f51819e41636c.png)](https://gyazo.com/7ca3034b770cd4b9ae9f51819e41636c)


これを出なくするには、
サンプルプログラム「GeospatialController.cs」を改良します。

Assets/Samples/ARCore Extensions/1.38.0/Geospatial Sample/Scripts/GeospatialController.cs

705行目から以下をコメントアウトしてください。

```cs
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began
                    && !EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)
                    && _anchorObjects.Count < _storageLimit)
                {
                    // Set anchor on screen tap.
                    PlaceAnchorByScreenTap(Input.GetTouch(0).position);
                }

                // Hide anchor settings and toggles if the storage limit has been reached.
                if (_anchorObjects.Count >= _storageLimit)
                {
                    AnchorSettingButton.gameObject.SetActive(false);
                    AnchorSettingPanel.gameObject.SetActive(false);
                    GeospatialAnchorToggle.gameObject.SetActive(false);
                    TerrainAnchorToggle.gameObject.SetActive(false);
                    RooftopAnchorToggle.gameObject.SetActive(false);
                }
                else
                {
                    AnchorSettingButton.gameObject.SetActive(true);
                }


```

ちなみに、マーカーの形を変えるには
多分ここだと思います。（未検証）

[![Image from Gyazo](https://i.gyazo.com/35e0485d20337729e21b3ad45e114f64.png)](https://gyazo.com/35e0485d20337729e21b3ad45e114f64)


以上
LaravelにおけるTraitの使い方

## Traitとは？
Laravelにおける「**Trait**（トレイト）」とは、再利用可能なメソッドの集まりを指すPHPの機能のこと。
Traitはクラスに直接インポートされ、そのクラスのメソッドを拡張するために使用される。
Traitは継承の制約を持たないため、複数のクラスで同じメソッドやプロパティを共有したい場合に有効。

## Traitの利点
### コードの再利用
一連のメソッドをTraitとしてまとめることで複数のクラスで同じコードを再利用でき、コードの重複を避けることができる。

### 機能の拡張
Traitを使用してクラスにメソッドを追加することで、そのクラスの機能を拡張できる。
例えばLaravelのTraitは、モデルに対して日付のフォーマットやソート機能を追加するために使用されることがある。

### 横断的な機能の提供
Traitは複数のクラスで使用されるため、Traitに含まれるメソッドは複数のクラスに対して共通の機能を提供できる。これによりアプリケーション全体で一貫性のある動作を実現可能。

## 継承(extends)と何が違うの？
### 階層構造の有無
継承はクラス間に階層構造を作る。親クラスから子クラスへのメソッドやプロパティの引き継がれる。
Traitは階層構造に依存せずにコードを再利用する。異なるクラスが異なるTraitを組み合わせての利用が可能。
### 継承の制約
継承は通常1つのクラスからのみしか継承できない。多重継承がある一部の言語ではクラスが複数の親クラスから継承することができるがその際に複雑性が生じる可能性がある。
Traitは複数のTraitを同じクラスに適用することができるためクラス間で異なるコードの組み合わせが実現できる。
### コードの共有範囲
親クラスから子クラスへの継承はすべての子クラスで同じメソッドやプロパティが使用可能だがその階層内に限られる。
Traitは異なるクラス間でコードを共有できるため階層に依存せずに再利用できる。
### 柔軟性
継承は親クラスとの関係が固定されるため、クラスの構造や振る舞いを変更する際に柔軟性が制限されることがある。
Traitはクラス階層に縛られずにコードを再利用できるため、異なるクラスの組み合わせや変更に対して柔軟なアプローチが可能。

###
| 項目                 | 継承(extends)                     | Trait                         |
|------------------------|-------------------------------|-------------------------------|
| 階層構造                 | あり                          | なし                          |
| 継承の制約               | 1つの親クラス                 | 複数のTraitを同時に利用可能    |
| コードの共有範囲         | 階層内で共有                   | 異なるクラス間で共有            |
| 柔軟性                 | 制限あり（固定の階層構造）     | 高い柔軟性                    |
| メンバーの引き継ぎ       | あり                          | なし                          |
| コードの変更の影響範囲 | 子クラスのみに影響                | Traitを変更すると影響を受ける  |


## 適している場面  
・クラス間に明確な階層関係がない場合
・複数のクラス間で共通のコードを再利用したい場合
・多重継承を避けたい場合
・クラスの組み合わせを柔軟に変更したい場合

## 具体的
仮にモデルであるUserクラスに対して特定の機能を追加したい場合、Traitを使用してユーザー関連のロジックを共有することができる。

### 1. **Traitの作成**:

まず、Traitを定義する。とりあえずユーザーに関連するメソッドである`getUserFullName`を提供するTraitを定義してみる。

```php:Trait
// app/Traits/UserFunctionsTrait.php
namespace App\Traits;

trait UserFunctionsTrait
{
    public function getUserFullName()
    {
        return $this->first_name . ' ' . $this->last_name;
    }
}
```

### 2. **モデルにTraitを適用**

次に、`User`クラス**内**でTrait をuseする。

```php:Model
// app/User.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Traits\UserFunctionsTrait;

class User extends Model
{
    use UserFunctionsTrait;

    // モデルのその他の定義や関連付け
}
```

このコードで、`User`クラスは`UserFunctionsTrait`内で定義したメソッドを使用できるようになる。今回では`getUserFullName`を利用すること`User`クラスのメソッドのように使える。

### 3. **Controller内で使用**

コントローラー内で`User`モデルのTraitを使用する。

```php:Controller
// app/Http/Controllers/UserController.php
namespace App\Http\Controllers;

use App\ModelsUser;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    public function show($id)
    {
        $user = User::findOrFail($id);
        $fullName = $user->getUserFullName();

        return view('user.show', compact('user', 'fullName'));
    }
}
```

今回では`show`アクション内で`User`クラスのgetUserFullName`メソッドを使用して、ユーザーのフルネームを取得するようにしている。
TraitをModel内で使用することで共通のメソッドや機能を複数のモデルで再利用することが可能。


## 感想
継承するのはextends、共有するのはtrait、似ているようで用途が違うのでごっちゃしにないような注意しなければ。
【Salesforce】TODOの割り当て先に別ユーザを設定してるのにメールが送信されない

# 問題

- 送信のアクセス権をすべてのメール
- 割り当て先の別ユーザのメールは検証済み
- 別ユーザの私に ToDo が割り当てられた場合にメール送信が「TRUE」

これでメールが送信されない・・・

# 解決策

TODOを作成するユーザもメールの検証が必要だった。

Sandboxだったので未検証だった・・・

逆によく気付いたな

# 参考

[ToDo に関する通知のユーザ制御を有効にする場合の考慮事項](https://help.salesforce.com/s/articleView?id=sf.tasks_control_email_notifications_considerations.htm&type=5)
Azure Storage AccountのIP制限設定をBicepでパラメータ化する

Azure Storage AccountのIP制限をBicepを使ってうまくパラメータ化できないか試した結果を書き残します。
Portalでいうとこの部分ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/511bd184-c4c1-d799-0848-5fc6447808f7.png)

# Bicepパラメータファイル作成
* 許可するIPリストは、.bicepparamファイルに配列で持たせます。

```bash:main.bicepparam
using 'main.bicep'

param location = 'japaneast'

// Storage Account Parameters
param storageAccountName = '[Your Storage Account Name]'
param storageSku = 'Standard_LRS'
param allowIpList = [
  'x.x.x.x'
  'y.y.y.y'
  'z.z.z.z'
]
```

# Bicepファイル作成
* .bicepファイルの方には可変パラメータは記載しないようにします。配列で受け取ったIPリストをfor文でipRulesに設定していきます。

```bash:main.bicep
param location string
param storageAccountName string
param storageSku string
param allowIpList array

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  location: location
  name: storageAccountName
  kind: 'StorageV2'
  sku: {
    name: storageSku
  }
  properties: {
    networkAcls: {
      defaultAction: 'Deny'
      bypass: 'AzureServices'
      ipRules: [for item in allowIpList: {
        value: item
      }]
    }
  }
}
```


# 実行
* パラメータを指定してデプロイし、ストレージアカウントのIP許可リストが問題なく設定されたことを確認します。

```
az deployment group create --resource-group [Your Resource Group Name] --template-file main.bicep --parameters main.bicepparam
```

以上です
Anacondaでよく使うコマンド

初心者でもよく使うAnacondaのコマンド一覧。環境はMacのzshです。

# 仮想環境の起動/終了

- ``` conda info -e ```: 仮想環境一覧の表示
- ``` conda create -n name python=x ```: Pythonのバージョンがxの仮想環境nameを作成
- ``` conda activate name ```: 仮想環境nameの起動
- ``` conda deactivate ```: 現在の仮想環境を終了

# ライブラリ関係

-  ``` conda list ```: 現在アクティブにしている仮想環境に入っているライブラリを確認
-  ``` conda install name==x ```: nameというライブラリのインストール、=　以降は省略可
-  ``` conda search --full-name name ```: nameというライブラリがAnacondaのチャンネルにあるか確認
-  ``` conda config --add channels name ```: nameというチャンネルをAnacondaのチャンネルに追加

# jupyter notebookの起動/終了

- ``` jupyter notebook ```: jupyter notebook の起動
- [Ctrl] + C: jupyter notebook の終了

参考文献
@naz_. "Anaconda でよく使うコマンド一覧". Qiita. 2018/10/18.　https://qiita.com/naz_/items/84634fbd134fbcd25296, (2023/08/30).

@yakisobamilk. "Anaconda仮想環境について". Qiita. 2019/04/12. https://qiita.com/yakisobamilk/items/867dce8e53824146ce05, (2023/08/30).

CG. "jupyter notebookの基本的な使い方。起動と終了". CodeGraffiti. 2018/08/19. https://code-graffiti.com/how-to-use-jupyter-notebook/#toc6, (2023/08/30).

のっくん. "【Anaconda】conda-forgeチャネルを追加する方法". NokkunBlog. 2019/03/23. https://ymgsapo.com/2019/03/23/anaconda-package-search/, (2023/08/30).
Golangの構文木操作ライブラリdstの紹介

dstとは**Decorated Syntax Tree**の略で、GOの構文木(go/astパッケージ)にファイルの情報を付加したものである。
go/astパッケージではスペースやコメントの情報を持たないので、コードを生成するという目的には適さない。

例えば以下の例の場合、コメントの位置情報を持たないので順序が保存されずに出力の際に壊れてしまう。

```go
code := `package a

func main(){
	var a int    // foo
	var b string // bar
}
`
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "", code, parser.ParseComments)
if err != nil {
	panic(err)
}

list := f.Decls[0].(*ast.FuncDecl).Body.List
list[0], list[1] = list[1], list[0]

if err := format.Node(os.Stdout, fset, f); err != nil {
	panic(err)
}

//Output:
//package a
//
//func main() {
//	// foo
//	var b string
//	var a int
//	// bar
//}
```

この例をdstなら以下のように出力できてコメントとソースの順序も保存されいてる。

```go
code := `package a

func main(){
	var a int    // foo
	var b string // bar
}
`
f, err := decorator.Parse(code)
if err != nil {
	panic(err)
}

list := f.Decls[0].(*dst.FuncDecl).Body.List
list[0], list[1] = list[1], list[0]

if err := decorator.Print(f); err != nil {
	panic(err)
}

//Output:
//package a
//
//func main() {
//	var b string // bar
//	var a int    // foo
//}
```

astからdstへ

dstはastのほぼ互換なので構文木に関するものはastをdstに置き換えれば大体いける

decorator.ParseFileを使ってdst.Fileを取得します

[https://www.notion.so](https://www.notion.so)

```go
func (d *[Decorator](https://pkg.go.dev/github.com/dave/dst/decorator#Decorator)) ParseFile(filename [string](https://pkg.go.dev/builtin#string), src interface{}, mode [parser](https://pkg.go.dev/go/parser).[Mode](https://pkg.go.dev/go/parser#Mode)) (*[dst](https://pkg.go.dev/github.com/dave/dst@v0.27.2).[File](https://pkg.go.dev/github.com/dave/dst@v0.27.2#File), [error](https://pkg.go.dev/builtin#error))
```


> ParseFile uses parser.ParseFile to parse and decorate a Go source file. The ParseComments flag is added to mode if it doesn't exist.
> 

```go

	f, err := decorator.ParseFile(fset, "postback_strategy.go", nil, parser.DeclarationErrors|parser.AllErrors|parser.ParseComments)
	if err != nil {
		switch err := err.(type) {
		case scanner.ErrorList:
			for _, e := range err {
				fmt.Printf("%s:%d:%d %s\n", e.Pos.Filename, e.Pos.Line, e.Pos.Column, e.Msg)
			}
		default:
			fmt.Println(err)
		}
		return
	}
```

このfを使って、`ast.`とされてる箇所を`dst.`に置き換えれば大体いける。

なのでgolangでコード生成する必要があれば、こちらを使った方がいいかもしれない。

[https://github.com/dave/dst](https://github.com/dave/dst)
Railsバージョンを5.2.8→7.0.6へ上げたときにスクリプト系が動かなくなった件

どうもこんにちは、今回はRuby on Railsのバージョンアップ作業を行なった時にぶつかった壁について紹介します。

## 基本的な手順

基本的な手順は、[こちらの記事](https://qiita.com/jnchito/items/0ee47108972a0e302caf)を参照して行いました。

## バージョンアップの経緯

私の会社では、WebアプリケーションをAWS ElasticBeanstalkを使用してデプロイ/運用を行っています。

しかし、近々ElasticBeanstalkのRails5系のサポートが終了するとの警告があり、「これはバージョンを上げないとやばい！」ということで上げることになりました。

## ぶつかったこと

バージョンアップ作業自体は順調でした。RSpecやRubycop、Brakemanを導入していたおかげエラー箇所や冗長なコードを見つけるのがかなり容易でした。しかし、そのような自動テストではカバーできない問題に陥ってしまいました。

それが、**Javascript、CoffeeScriptが動かない！** という問題です。

厳密にいうと、動かないという問題だけで２種類の問題がありました。

1. Rails7.0.6へ上げた後に`rails s`でサーバーを立ち上げたら、Javascript、CoffeeScriptが全く動かないという問題。
1. Rails5.2.8時点で実装していたJavascript、CoffeeScriptは動くが、Rails7.0.6時点でJavascript、CoffeeScriptを修正しても修正内容がlocalhost上に反映されないという問題

１つ目は簡単でした。JavaScriptのハンドリングには、Rails5ではsprocketsが、Rails7ではimportmapが使用されていました。これでは、Rails7でJavascript、CoffeeScriptが動く訳ないですね。なので、Gemに`sprockets-rails`を導入することにしました。

```
1. Gemfileに`gem 'sprockets-rails'`を記載
2. `bundle install`を実行
3. 念の為、もう一度`rails s`を叩く
```

これでJavascript、CoffeeScriptが動き始めました。

しかし問題は２つ目です。

エラーも出ず、ただただ`console.log`でログ出力されないという問題が目の前にあるだけ。これはなんだろうと思い、調査をしました。そしたら、設定が足りないという凡ミスでした。

1. `config/application.rb`に`require "sprockets/railtie"`を記述
1. `config/initializers/assets.rb`に以下を記述

```
Rails.application.config.assets.paths << Rails.root.join('app', 'assets', 'javascripts')
Rails.application.config.assets.paths << Rails.root.join('app', 'assets', 'coffeescripts')
```

あとはもう一度`rails s`を叩けばOKです！

## うまくいかなかった場合

* `app/assets/javascripts/application.js`に`//= require users`というようにrequireする記述をスクリプトファイルの数だけ追加してみてください。
* `public/assets`ディレクトリをクリアして、`rails assets:precompile`を実行してみてください。

## まとめ

Ruby/RailsのアップグレードではJavaScript周りの作りは複雑なので、根気強く調査して頑張る！

バージョンアップ作業で困っている方をお助けできてたら嬉しいです。

以上
C#8.0で導入された配列インデクサの範囲指定がexclusive endな理由

C#8.0で、次のように配列の範囲指定での抽出が可能になりました。

```C#
string line = "01234567";
string line2 = line[0..4];

Console.WriteLine(line);	// 01234567
Console.WriteLine(line2);	// 0123
```

この記事がとても分かりやすいです。

https://qiita.com/YouKnow/items/93b4b978ecb113616fae

`array[start..end]` の時、startは「包括的(inclusive)」、endは「排他的(exclusive)」となります。
**つまり、startは結果に含まれますが、endは結果に含まれません。**

`"01234567"`という文字列に対して`[2..4]`は"23"です。

どうしてそうなっているのでしょうか？

分かりにくいと思う人もいるかもしれませんが、CやC++と同様、C#の「配列のインデックス」というのは「N番目の要素」を表しているというよりは「配列として確保されたメモリ上のデータの先頭からの距離」を表しているわけで、0から開始する以上、「範囲」を表す為にはこの方が都合がいいから、ということでしょう。

同じように「0から始まる数値の範囲」を表す例として、「時刻」があります。
「10時から17時まで」と聞いた時に、「17:59までだろう」と思う人はほとんどおらず、基本的には「17:00」まで、つまり「17:00にはイベントは終わった後」であると考えるでしょう。また、開始時刻についても、「10:01」からだと思う人はまずおらず、「10:00」から開始、つまり0ベースだと考えるはずです。

また、こうすることで、「10時から17時まで」と「17時から21時まで」といった複数の範囲が切れ目なく連続することも表現しやすくなります。

https://qiita.com/jun1s/items/b0dca1d666afde1de034

この例でもわかるように、0ベースで考える場合、その範囲については、startは「包括的(inclusive)」、endは「排他的(exclusive)と考えた方が直感的で分かりやすいのです。

例えば、「範囲0」を表したい場合に、この仕様だとこう書けます。

```C#
string line = "01234567";
string empty_string = line[2..2]; // "" が返る
```

もしこれを、次のように書かないといけないとしたら、むしろ直感的ではないと感じるでしょう。

```C#:ArgumentOutOfRangeExceptionが発生
string line = "01234567";
string empty_string = line[2..1]; // "" が返る…？ 
```

次に、「文字列を3文字ずつ切り出す」ような処理を考えてみましょう。

```C#
string line = "01234567";
int split_length = 3;
for (int start = 0; start < line.Length; start += split_length )
{
	int end = Math.Min(start + split_length, line.Length);	// end は最大長まで
	string sub = line[start..end];
	Console.WriteLine(sub);
	// 012
	// 345
	// 67
}
```

開始位置startに、切り出す長さsplit_lengthを足していくだけです。
とても簡潔に書けますね。
「どこまで処理するか？」も、line.Lengthまでやるだけです。長さに-1したりするようなことを考える必要はありません。

また、インデクサの指定方法には、新しく`^n`(ハット演算子)も加わりました。

```C#
string line = "01234567";
char c = line[^1]; // "7"
```

つまり、ハットには位置ではなく**末尾からの長さ**を指定します。これを見て「どうしてここは0ベースの位置指定じゃないのか？」と思われるかもしれません。

しかし、こうなっていることにより、末尾から3文字欲しい場合には次のように書けます。

```C#
string line = "01234567";
string line2 = line[^3..]; // "567"
```

また、「先頭5文字とそれ以降」に切り分けたい場合、次のように書けます。

```C#
string line = "01234567";
int split_length = 5;
string lineA = line[..split_length]; // "01234"
string lineB = line[split_length..]; // "567"
```

そして「末尾5文字とそれ以前」に切り分けたい場合、次のように書けます。

```C#
string line = "01234567";
int split_length = 5;
string lineA = line[..^split_length]; // "012"
string lineB = line[^split_length..]; // "34567"
```

長々と書きましたが、つまるところ、「そのほうが範囲を表現しやすい」ということでした。

# 参考
https://stackoverflow.com/questions/54092458/why-doesnt-the-new-hat-operator-index-from-the-c-sharp-8-array-slicing-feature
Virtual Box上でCPU拡張命令セット(AVX2)を有効化(Windows)

素でVBのVMを作ると新しめのCPU拡張命令セットは入っていない。

```bash
user1@my-VirtualBox:~$ cat /proc/cpuinfo | grep flags
flags        : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc
rep_good nopl xtopology nonstop_tsc cpuid pni pclmulqdq ssse3 cx16 pcid 
sse4_1 sse4_2 movbe popcnt aes rdrand hypervisor lahf_lm abm 3dnowprefetch
invpcid_single pti fsgsbase bmi1 bmi2 invpcid rdseed clflushopt
md_clear flush_l1d arch_capabilities
```

VMを落とした状態で、ホストOS側のコマンドラインで以下のコマンドを実施。

```bat
> VBoxManage setextradata "Ubuntu-BC" VBoxInternal/CPUM/IsaExts/AVX2 1
> VBoxManage setextradata "Ubuntu-BC" VBoxInternal/CPUM/IsaExts/AVX 1
> VBoxManage getextradata "Ubuntu-BC"
Key: GUI/LastCloseAction, Value: PowerOff
Key: GUI/LastGuestSizeHint, Value: 1920,1018
Key: GUI/LastNormalWindowPosition, Value: 0,23,1920,1057,max
Key: VBoxInternal/CPUM/IsaExts/AVX, Value: 1
Key: VBoxInternal/CPUM/IsaExts/AVX2, Value: 1
```

Windowsの場合、グループデバイスポリシーエディタ(gpedit.msc)で
「コンピュータの構成＞管理用テンプレート＞Device Guard＞仮想化ベースのセキュリティを有効にする」を無効にする。

さらにHyper－V仮想化を無効(`bcdedit /set hypervisorlaunchtype off`)にし、VBの準仮想化IFにHyper-V以外(KVMなど)を選択。

そうすると、ゲストOSのUbuntu側で

```bash
user1@my-VirtualBox:~/Desktop$ cat /proc/cpuinfo | grep flags
flags        : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc
cpuid tsc_known_freq pni pclmulqdq ssse3 cx16 pcid
sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx rdrand hypervisor lahf_lm abm 3dnowprefetch
invpcid_single pti fsgsbase bmi1 avx2 bmi2 invpcid rdseed clflushopt
md_clear flush_l1d arch_capabilities
```

という風に拡張命令セットが有効になった状態になる。
VSCode CLI インストール後 code コマンドを叩くとエラー

# 表示されたエラー

```sh
cannot execute binary file: Exec format error
```

# 背景

ECS Fargate（ARM64 のアーキテクチャー）のコンテナ内で、[vscode](https://code.visualstudio.com/) を使用したい。

↓

アーキテクチャーに合っていない、不適切な`vscode cli`のファイルをダウンロードしていた。

# 解決策

## 適切な platform に合わせたファイルをダウンロードする



### Intel Mac

```sh
curl -Lk 'https://code.visualstudio.com/sha/download?build=stable&os=cli-alpine-x64' --output vscode_cli.tar.gz

tar -xf vscode_cli.tar.gz
```

### ARM64

```sh
curl -Lk 'https://code.visualstudio.com/sha/download?build=stable&os=cli-alpine-arm64' --output vscode_cli.tar.gz

tar -xf vscode_cli.tar.gz
```

# 参考

- [vscode tunnel](https://code.visualstudio.com/docs/remote/tunnels)
- [vscode download](https://code.visualstudio.com/download#)
未経験からiOSエンジニアになった男の三ヶ月間

こんにちは！私はiOSエンジニアとしてキャリアをスタートしたばかりで、現在三ヶ月が経ちました。未経験からこの業界に飛び込んで、多くのことを学んできました。この記事で、その経験と感想を幾つか共有したいと思います。

# 1. APIってすげぇ
入社一週間ほどは環境構築やテキストを使いSwiftやXcodeについて学習を行いました。
最初はテキストと自身の開発環境（主にバージョン）が異なるため些細なことでつまづくことも多々ありました、、、
テキストでの学習が無事終了し、最初のプログラミングはポケモン図鑑のアプリを作成しました！
ポケモンのデータを取得し図鑑にするアプリです。
なんとなく制作に取り掛かる前はポケモンのデータを全て入力するのではと思っていましたが、APIからデータを取得することでポケモンの図鑑No,名前,画像を表示することができ、APIってすげぇと感動したのを今でも覚えています。
当初、右も左も分かりませんでしたが、先輩方にヒントを頂いたり、ChatGPTをフル活用したりとなんとか無事に完成することができました！

# 2. SourceTreeって怖い
無事にポケモン図鑑のアプリが完成しいよいよ実際のプロジェクトに参加しました。
最初はボタンを追加したり、文字の色を変えたりとコーディングの難易度は高くはありませんでした。
しかし、SourceTreeを活用したGitHubの操作は今まで行ったことがなく、訳もわからず操作して重大なミスをしてしまうのではと毎回ビビりながらコミット＆プッシュ、マージをしていました。
今では多少SourceTreeについても知識が身につきスムーズに作業が行えるようになり、昔に比べ成長を実感しています！！

# 3. AutoLayoutさん言うこと聞いてよ、、、
プロジェクトに取り組む中、レイアウトを自分で調整する場面が多々ありました。
自信満々にビルドしていざ確認してみると想像していたレイアウトとはかけ離れており、ショックを受けることが沢山ありました笑
自分では正しい位置に配置できていると思っていてもプログラム上は誤ってプログラムされており、Xibファイルをカチャカチャいじってなんとか正しい位置に配置するコツを掴むことができました!!
まだまだ、レイアウト調整に時間がかかってしまうこともあるのでさらにスキルを向上させていきたいです！！

# 4. プログラミングって楽しい
約三ヶ月間、先輩方のサポートもありプロジェクトに参加させて頂き、スキルが足りず足踏みすることも多々ありますが、
タスクが完了し、実際に動作確認で端末を操作した時にすげぇ動いてる！！と感動します。
自分の手で何か形になる物を作れるのはとてもやりがいがあり楽しいです。
まだまだスキルアップが必要ですがそういったやりがいを軸に今後もも励んで行けたらと思います！！

# 終わりに
この三ヶ月間は振り返れば本当にあっという間でした。ですが、ふと振り返ってみると三ヶ月前に比べて自分のできるようになったことはとても増えたなと成長を実感します。
これからも継続的に成長しエンジニアとして一日でも早く一人前になれるよう頑張ります！！
この記事がこれからのエンジニアになろうと考えている方に少しでも参考になれば幸いです。
長々となりましたが、ありがとうございました！
スプリントゴールは「バックログを空にすること」じゃないよ

## この記事は何
以前Qiitaで以下のようなスクラムに関しての記事を投稿しました。

https://qiita.com/getty104/items/35ccb10ce660e7487ef8

https://qiita.com/getty104/items/f4cbc641a273794ccec8

https://qiita.com/getty104/items/74512b8a0d89b8b4bea3

これらの記事では「チームとしてゴールを達成するため」のTipsについて紹介してきました。
しかし、そもそもスプリントゴールがなんなのかを理解していないと、これらのTipsを実践することは難しいです。
この記事ではスプリントゴールとはどういうもので、どのように設定すると良いかを説明します。

## スプリントゴールのよくある勘違い
スクラムを実施しているチームの中で、たまに「ゴールは特に設定していない」という方がいらっしゃいます。
ゴールを設定しない理由は以下のとおりです。

- このスプリントでやりたいことはスプリントバックログとして残してあるからゴールを設定する必要がない
- 結局スプリントゴールを設定しても、やることが「スプリントバックログを空にする」になってしまうから

これらの主張は一見正しいように見えますが、スプリントゴールとは何か、スクラムとは何かの理解を深めていくとこれらの主張には問題があることがわかります。

スクラムガイドには、スクラムは以下のように定義されています。

> スクラムとは、複雑な問題に対応する適応型のソリューションを通じて、⼈々、チーム、組織
が価値を⽣み出すための軽量級フレームワークである。

[スクラムガイドより引用](https://scrumguides.org/docs/scrumguide/v2020/2020-Scrum-Guide-Japanese.pdf)

そしてスクラムのコンセプトは以下の通りです。

> スクラムは「経験主義」と「リーン思考」に基づいている。経験主義では、知識は経験から⽣
まれ、意思決定は観察に基づく。リーン思考では、ムダを省き、本質に集中する。

[スクラムガイドより引用](https://scrumguides.org/docs/scrumguide/v2020/2020-Scrum-Guide-Japanese.pdf)

まとめてしまうと、スクラムとは「何が起こってもうまい行動ができるチームを作るためのフレームワーク」だと解釈しています。
そしてこの「うまい行動」をする上での指針になるのが「スプリントゴール」です。

## スプリントゴールとは何か

前項でスプリントゴールとは「何が起こってもうまい行動ができるチーム」を作る上で必要になる「指針」であるという紹介をしました。具体的にこれがどういうことかについて説明します。

スクラムガイドではスプリントゴールは以下のように定義されています。

> スプリントゴールはスプリントの唯⼀の⽬的である。スプリントゴールは開発者が確約するも
のだが、スプリントゴールを達成するために必要となる作業に対しては柔軟性をもたらす。ス
プリントゴールはまた、⼀貫性と集中を⽣み出し、スクラムチームに⼀致団結した作業を促す
ものでもある。

[スクラムガイドより引用](https://scrumguides.org/docs/scrumguide/v2020/2020-Scrum-Guide-Japanese.pdf)

つまりスプリントゴールとは「スプリント中何が起こっても達成したい状態」を定義することです。
スプリントバックログに載っているタスクは、スプリントゴールを達成するために着手するものではあります。
ただ状況が変わればゴールを達成するために行うアクションも変わることはいくらでもあります。
そのようなときはバックログに載せているタスクを入れ替えたり、減らしたり、追加したりすることをスクラムでは推奨しています。
スプリントゴールを設定せずにスプリントバックログを空にすることを目的にしてしまうと、スプリントの目的や優先順位が曖昧になり、チームの効率や成果を損ねる可能性があります。
そして何よりチームのメンバーそれぞれが着手しているタスクの目的を失いやすくなり、チームとしての自走力が低下してしまうことになります。
このような状態になると、いわゆるプロダクトオーナーやリーダーが不在だと自分たちだけでは何も判断して動くことができないチームになってしまうリスクがあります。

## スプリントゴールに設定するもの
ここまででスプリントゴールについて説明してきました。

ゴールに設定するものは、スプリント中に実現したい機能や価値、問題の解決など、具体的な成果物や目標を含めることが重要です。
具体的に設定するもののイメージを紹介します。

- 〇〇が〇〇を使うことができる状態になっている
- 〇〇が正式リリースできる状態になっている
- 次のスプリントから〇〇が着手できる状態になっている

このような成果をスプリントゴールに設定することで、チームの目的はゴールを達成することになり、スプリント中にバックログを完全に消化することだけでなく、ゴールを達成するために必要なアクションを柔軟に行う必要がある前提が出来上がります。

## まとめ
今回はスクラムにおける「スプリントゴール」について解説してみました。
チームとして達成したいと思えるゴールを設定することができれば、以下の記事で紹介したような取り組みもより価値のあるものになると思います。

https://qiita.com/getty104/items/35ccb10ce660e7487ef8

https://qiita.com/getty104/items/f4cbc641a273794ccec8

https://qiita.com/getty104/items/74512b8a0d89b8b4bea3
Rubyの定数探索をめっちゃ間違えるので勉強した

## 定数の探索には２種類ある

- 継承チェーンを利用した探索
- レキシカルスコープチェーンを利用した探索

### 継承チェーンを利用した探索

#### 動き

1. クラス内を参照
1. クラス内に参照するものがない場合には親クラスに参照しにいく

これを参照できる定数が見つかるまで繰り返します。

```ruby
class ParentClass
  CONSTANT = 'constant in ParentClass'
end

class ChildClass < ParentClass
  p CONSTANT
end
```

上記のコードを例にして考えると、

1. ChildClassクラスに定数の呼び出しがあるため、ChildClassクラス内を探索
1. ChildClassクラスには定数がないので、親クラスのParentClassクラス内を探索
1. そこに定数があったのでそれを参照

### レキシカルスコープチェーンを利用した探索

レキシカルスコープはクラスや関数の定義時にスコープが決まる。

レキシカルスコープチェーンを理解するには以下の二つを押さえる必要があるらしい。

- nd_next
- nd_class

ndってなんの略だろう、、、

#### nd_nextとは

nd_nextは、親のレキシカルスコープを保持しているポインタ。通常のクラスを作成した場合は、トップレベルのスコープが保持される。

#### nd_classとは

nd_classは、スコープに対応するクラスやモジュールの情報を保持しているポインタ。


#### 動き

1. nd_classを利用してスコープに対応するクラスorモジュールを参照する
1. クラスかモジュールが保持する定数テーブルに参照したい定数があるか確認する。
1. 参照するものが見つからない場合は、nd_nextポインタを利用して親のレキシカルスコープに参照しに行く

参照できるものが見つかるまで上記を繰り返し行う。

```ruby
module NameSpace
  CONSTANT = 'constant in NameSpace'

  class ParentClass
    class ChildClass
        p CONSTANT
    end
  end
end
```

上記のコードを例にして考えると、

1. ChildClassクラスで定数の呼び出しが行われる。
1. ChildClassクラスには定数がないので、一つネストを下げてParentClassクラスを探索する。
1. そこにもないので、さらにネストを下げてNameSpaceモジュール内を探索する。
1. そこに定数が定義されていたのでそれを参照する。

## 優先されるのは？

以上の二つで優先されるのは、レキシカルスコープチェーンを利用した探索である。

```ruby
class ParentClass
  CONSTANT = 'constant in ParentClass'
end


module NameSpace
  CONSTANT = 'constant in NameSpace'

  class ChildClass < ParentClass
    p CONSTANT
  end
end
```

上記のようなコードの場合、NameSpaceモジュール内に定義された定数が参照される。
NameSpaceモジュール内に定数が定義されていなかった場合、親クラスへ探索をしに行くため、ParentClassクラスに定義された定数が参照される。

## まとめ

定数の参照では以下の二つの探索方法によって探索が行われる。
ただし、優先されるのはレキシカルスコープチェーンである。

- 継承チェーンを利用した探索
- レキシカルスコープチェーンを利用した探索

また、ここでは解説しなかったが、includeやprependによってMix-inされたモジュールの中に定義された定数は参照されることはない。