OmniAICreator/Qiita-1.07M huggingface dataset:
[React]フォーム外の条件によってzodでバリデーションしたい場合どうすればいいのか

## はじめに
この記事では、他にやっている記事を見つけられなかったためあくまでも今現在の自分の正解だと思い込んで書いています。
ReactとReact Hook Formを使っていて、フォーム外の条件によってバリデーションをさせたい場合、皆さんはどうしていますか？例えば、食べ物を注文するフォームがあるとしましょう。簡易的に考えるために、メニューをセレクトボックスから選ぶとします。しかしユーザーの年齢が20歳未満の場合はお酒を注文できないよう、バリデーションエラーを出させたいとします。UserとMenuの型、セレクトボックスの中身は以下とします。

```ts
type User = {
    id:number
    name:string
    age:number //年齢
}

type Menu = {
    id:number
    name:string
    isAdult:boolean //20歳未満かどうか
}

type SubmitMenu = {
    userId:number,
    menuId:number
}

const MenuOption:Menu[] = [
    {id:1,name:"オムライス",isAdult:false},
    {id:2,name:"お子様ランチ",isAdult:false},
    {id:3,name:"ビール", isAdult:true}
]
```
この時SubmitMenuをPOSTするとき、zodでどうバリデーションを実装すればいいのかです。、ageが20歳未満のときはどうやってバリデーションエラーを起こさせるかです。

## 余分にzodで型を作る
自分が今のところ良さそうだなと思ったのは、余分に`age,isAdult`を含めたバリデーションを作っちゃうことです。このことによって、inferによってzodによる型の恩恵を受けられるからです。
```ts
import { z } from 'zod';

//余分な項目を含めたスキーマ
const overSchema = z.object({
  menuId: z.number(),
  userId: z.number(),
  age:z.number(),
  isAdult: z.boolean()
});

// overSchemaのrefine付き
export const refineSchema = overSchema.refine(
  ({ age, isAdult }) => (age < 20 ? !isAdult : true),
  { path: ['menuId'], message: 'お酒は二十歳になってから' }
).refine(({menuId})=> menuId > 0,{path:["menuId"],message:"メニューを選択してください"})

// 本来送信したいスキーマ
export const schema = overSchema.omit({age:true,isAdult:true})

export type OverSchema = z.infer<typeof overSchema>
```
`overSchema`に`refine`を含めないことによって、他で使う時に`omit`や`pick`で好きなように中のスキーマを取り出せます。そしてsubmitする前に、余計なdataを除きます。また、UserのageはdefaultValueで設定してあげます。こうすることによってschema自体はzodオンリーで書くことができ、zodのメソッドをふんだんに使うことができます。送信用のメソッドが別のところで定義されていたとしても、schemaを使って型を作れば型安全にできます。
では、`isAdult`はどこで取得するかというと、`select`でonChangeした際にReact Hook Formの`setValue`メソッドで`isAdult`にセットします。

https://codesandbox.io/embed/react-hookform-zod-extra-c4df4x

## 終わりに
もしこうしたほうがもっと効率的だというのがあったらぜひコメントで教えてください。自分もこれが絶対の正解だとは思っていないので、間違っていたらまた正した記事を書きます。
あくまで、Reactのみで、送信する項目もmenuIdとuserIdのみという場合に限ったときの話でした。
lpic101　lpic102を取得した時の記録

昔の作業ログ
2022/09/30
# lpic101挑戦

## 目的
- システム一回り入門したかった。今回の観点はOS。
- RHEL操作、bashスクリプト理解などが業務に必要。
- Linuxを体系的に理解したい。
- lpic vs linuc
  - 個人的に今はクラウド重点じゃない、枯れてる方と言う判断でlpic。

## 状況
- 文系学部卒、特別なプログラミング経験やソフト、ハードなどの知識、経験なし。
- 基本情報FE取得済、セスペSC、ネスペNWを取得済。OSSDB gold取得済、デスペ1敗して保留中。

## 準備
pingtのみ。
pingtを集中したのが2022/09/01から。
通勤時間で細々と継続。

## 当日
持ち物は身分証二つ。

40分で一週
15分で見直し
3分で最終確認、
結果、合格。

誤訳あったが、
全てに原文となる英語表記が付いていたので、それ見れば良いと言う感じ。内容は英語優先。

↓しばらくしたらマイページに詳細が更新された。

セクションの詳細
|テストセクションの情報|正解率|
|---|---|
|System Architecture|100%|
|Linux Installation and Package Management|73%|
|GNU and Unix Commands|96%|
|Devices, Linux Filesystems, Filesystem Hierarchy Standard|78%|

## 次は
- 次はlpic102。
→ほんとは間髪入れずに取りたかったが、少し間が空いての挑戦となった。

以上

---
2023/06/21
# lpic102挑戦

## 目的
- RHEL操作、bashスクリプト理解などが業務に必要。
- Linuxを体系的に理解したい。
- lpic vs linuc
  - 個人的に今はクラウド重点じゃない、枯れてる方と言う判断でlpic。

## 準備
lpic101取得後、少し時間空いて、
pingtを集中したのが2023/04から。
通勤時間で細々と継続。

## 当日
持ち物は身分証二つ。

14:00 開始
14:56 退散
結果、pass！

21/60がNGと自己採点。
で、
結果は
640/800
ボーダーは500
ので、、、
思ったよりギリギリかな

残59分、一周目済
残42分、二周目済
36正解なら6割で、
39確定と自己採点して、
躊躇なく完了！
で、pass
まぁ、そうなるな。
→ミスは10問だったらしい。
　結果を見たい。振り返りがしたい。もどかしい。

↓しばらくしたらマイページに詳細が更新された。

セクションの詳細
|テストセクションの情報|正解率|
|---|---|
|Shells and Shell Scripting|100%|
|User Interfaces and Desktops|100%|
|Administrative Tasks|83%|
|Essential System Services|75%|
|Networking Fundamentals|78%|
|Security|80%|

## 結果
- 基礎的なコマンドや、利用する上での仕組みは把握できた。
- 業務時間中でLinux、bashについて0ベースでググる時間が減った。
- 新人には取り敢えずおすすめしたい。
  - ネスペ、セスペ取った状態だから、NW関係やセキュリティ関係に戸惑うことはなかったとは思う。
  - 物理端末にLinuxインストール、複数ディストリビューション試したり、パスワード忘れてシングルユーザモードで復旧とか試してたから、ブート関係や動作モードに戸惑わなかったとは思う。
  - とは言え、pingt主軸で問題無く行けると思う。
- 次はlpic2、3の範囲も見つつ、他の資格と順番考えて引き続き対応する。

以上
OSSDB silver goldを取得した時の記録

昔の作業ログ
2019/02/24
# OSSDB silver挑戦

## 目的
- システム一回り入門したかった。今回の観点はDB。
- postgres操作、構成、基本機能理解などが業務に必要。
- RDBMSを体系的に理解したい。

## 状況
- 文系学部卒、特別なプログラミング経験やソフト、ハードなどの知識、経験なし。
- 基本情報FE取得済、セスペSC、ネスペNWを取得済。デスペ1敗して保留中。

## 準備
- pingtメイン。
- 不明点は実機で都度確認。
- 公式サンプル問題と、無料セミナーpdfも確認。
- 学習期間　80時間程度。
  - 通勤片道30分＊2＊20営業日＊4カ月。
  - 20181029pingt登録。
  - 20190124全て金。#そう言えば当時はレベル方式じゃなくメダル方式だった。
  - 以降模試モードと公式サイトの例題。
  - 20190224受験。
  - 最初は各問題解説熟読→分からない単語調べる、と言う流れなので20問くらい解くだけでもかなり時間がかかった。
  - 全て金になってからはミスのみ解説確認に出来たので速度が上がった。

## 当日
持ち物は身分証複数。

50分で解答完了。
迷った問題ほぼ無し。
余裕持って合格。

 90/100点
|セクション|正解率％|
|---|---|
|一般知識|100|
|運用管理|88|
|開発/SQL|87|

## 次は
goldはpingtないので、通勤時間で短期決戦とは行かない想定。

以上
---

2020/10/30
# OSSDB gold挑戦

## 目的
- postgres操作、構成、基本機能理解などが業務に必要。
- RDBMSを体系的に理解したい。

## 準備
- pingtが無かったので、像本を熟読。
内部構造から学ぶPostgreSQL―設計・運用計画の鉄則
→postgresのバージョンアップに合わせて改版されているようなので、都度最新を確認してください。
- 操作に不明な点があれば都度実機確認。
- 公式のサンプル問題を解く。
- サンプルを真似て像本の内容から適当にクイズ化して解く。

## 当日
持ち物は身分証複数。

スタッフの準備ミスらしくちょっとお待ちくださいされて、
結局14:30くらいから開始だったかな？

残61分、30問回答完了
残48分、フラグ二問検証完了
残31分、全ての選択数、正誤検証完了
アンケートへ。5分くらい？
で、リザルト画面。
70ライン、73点。合格。
あぶな∑(ﾟДﾟ)

|セクション|正解率％|
|---|---|
|運用管理|77|
|性能監視|66|
|パフォーマンスチューニング|66|
|障害対応|83|

## 結果
-  取り敢えずpostgresの11の機能は、利用する側としては一通り把握できた。
-  実際の構築は、そう言った業務のチャンスあったら。それまでは手元で遊ぶくらい。
-  実務考えると、postgres単体は多分ない。クラスタを組む。そして高可用性の為、プロキシなりクラスタソフトなりとの組合せ、自動化が必須と思う。よって、この資格のみでは特に完結しない。
- 名前に反して、OSSのRDBMSとは何ぞや、みたいな資格じゃない。純粋にpostgresの、かつその時のバージョンの内容に関しての資格。

次はシェアード、シェアードナッシングなど、クラスタ関係を試そうかな。

以上
セスペ、ネスペを取得した時の記録


昔の作業ログ

2016/01/17

# セキュリティスペシャリスト挑戦

## 目的
- システム一回り入門したかった。今回の観点はSEC。
- 毎回公開鍵と共通鍵が分からなくなるのを対処したかった。
- 暗号化、証明書なども理解したかった。

## 状況
- 文系学部卒、特別なプログラミング経験やソフト、ハードなどの知識、経験なし。
- 基本情報FE取得済、応用情報AUは数回失敗して一旦保留中。
- 義務感でAU取るより、興味ある、鍵関係など気になっている分野に絞って対処しようと思った。
- 業務内容がエンジニアとして力になるような気がしないものばかりで、年数だけ経っていく状況に焦りがあった。資格を自分の仮想案件と見立てて、自分をレベリングしたかった。

## 対策
- 午前
  - 道場のみ
- 午後
  - 最も詳しいシリーズあるだけ5年分2周
  - 「暗号技術入門　秘密の国のアリス」を3周
  - 用語をggrks

→結論、とにかく過去問を対策することと、自身の語彙を増やすこと。
　良い解説本に出会えたことが大きかったと思う。

## 経過
- 期間
2016/01中旬対策開始
2016/04中旬受験

- 午前対策
通勤時間で道場。
https://www.sc-siken.com/s/

- 午後対策
始業前最低1時間、
帰宅後最低1時間、
最も詳しい過去問解説シリーズを解く。
慣れるまでは時間無視。
慣れたら時間計測。

## 結果
ギリギリ合格
|区分|得点|
|---|---|
|午前Ⅰ|免除|
|午前Ⅱ|72点|
|午後Ⅰ|75点|
|午後Ⅱ|64点|

- とにかく書籍の暗号技術入門が良かった。把握したい用語を分かりやすく説明してくれている。
- 業務にしても他の資格にしても、セキュリティに関する内容は必ずと言って良いほどあるので、
新人は早いうちに挑戦した方が得すると思う。

以上

---
昔の作業ログ

2019/01/17

# ネットワークスペシャリスト挑戦

## 目的
- システム一回り入門したかった。今回の観点はNW。
- 「pingが通らない」で止まらないようになりたかった。

## 状況
- 文系学部卒、特別なプログラミング経験やソフト、ハードなどの知識、経験なし。
- 基本情報FE取得済、セスペ取得済。
- 業務でNW関係の良く分からない不具合に手も足も出ない状況にもやもやしていた。
- NW詳しい人が鮮やかに解決するのを見て憧れた。

## 対策
- 午前
  - 道場のみ
- 午後
  - 最も詳しいシリーズあるだけ8年分2周
  - http/tcp/ip/ethヘッダフォーマット写経
  - 用語をggrks
- その他
  - 書籍は以下が良かった
  ネットワークはなぜつながるのか　第２版
  - ビットの計算に慣れ親しむため、Ciscoのゲームが良かった。Cisco binary game。
  　→残念ながらもう更新ないみたいでネイティブアプリは動かない。web版はまだある。
https://learningcontent.cisco.com/games/binary/index.html

## 経過
- 期間
2018/08中旬対策開始
2018/10中旬受験

- 午前対策
通勤時間で道場。
https://www.nw-siken.com/s/

- 午後対策
始業前最低1時間、
帰宅後最低1時間、
最も詳しい過去問解説シリーズを解く。
慣れるまでは時間無視。
慣れたら時間計測。

## 結果
ギリギリ合格
|区分|得点|
|---|---|
|午前Ⅰ|免除|
|午前Ⅱ|88点|
|午後Ⅰ|61点|
|午後Ⅱ|68点|

- 当日試験範囲の半分ちょっと理解できた、と言うだけで、別にネットワーク全般完璧に理解したとか全然思えない。
- 当時は理解できた、一度は合格レベルまで理解できた、と言う事実があると、自信に繋がる。
- ネットワークの要素が挑戦前よりは理解、説明できるようにはなった。
- 別にネットワーク関係メインの業務じゃないが、単純にネットワーク関係の語彙が増えた、恐怖心が無くなった。
- pingが通らない、に対して、レイヤーとかノードとか切り分けを考えられるようになった。絵を描き仮説を立てられるようになった。
- パケットキャプチャを見るようになった。
- スイッチとか設定できる訳じゃない、サーバでDNSとか各サービス構築できる訳じゃない、動作確認できる訳じゃない。机上の空論感。

資格で言えばベンダ資格と両輪、と言う感じかなと思うので、次は実務なり自習なり資格なりで手を動かすようにする。

以上

## 追記
以下の方の手法は現代的で、どの資格対策にも、新しい分野への対応にも、一定の効果がありそう、速度上がりそうと思った。
https://qiita.com/namn1125/items/048eb17fd5e8f802660a
Python で OpenStreetMap や図形を描画し画像を出力する

# 概要
マップ上に図形等を描画するのは GIS が得意とするところですが、大量のファイルの入力が必要であったり、描画した画像を大量に出力したりする必要があるような時には Python のコードで描画の処理を行いたいところです。

ここでは、GIS で行うような基本的なマップや図形の描画を Python で行う方法を紹介します。

# 環境
主に以下のライブラリを利用します。

- Python 3.11.6
- cartopy 0.22.0
- contextily 1.4.0

`cartopy` は `matplotlib` のグラフで地理空間を扱うためのライブラリです。

https://scitools.org.uk/cartopy/docs/latest/index.html

`contextily` は地図タイルを取得するライブラリで、取得されたタイルを `cartopy` で地理空間に拡張されたグラフに投影します。

https://contextily.readthedocs.io/en/latest/#

ここでは、`conda` を用いて以下のコマンドで環境を作成しています。

```powershell
conda create -n geo python=3.11
conda activate geo
conda install contextily cartopy
```

# 実装
ここでは、東京駅周辺のマップと合わせて東京駅の位置を示すポイントを描画することとして、以下のように実装しました。

```python
import cartopy.crs as ccrs
import contextily as cx
import matplotlib.pyplot as plt
import pyproj
from matplotlib.offsetbox import AnchoredText


def main():
    # 日本語フォントの設定
    plt.rcParams["font.family"] = "Meiryo"

    # 対象地域の適当な座標系を設定
    crs = ccrs.epsg(6677)  # 平面直角座標系 9系(JGD2011)

    # 座標系に対応したオブジェクト
    fig = plt.figure(figsize=(8, 8))  # 実際の出力サイズは描画領域で決まるため、ここでは最大サイズとして指定。
    ax = fig.add_subplot(1, 1, 1, projection=crs)  # projectionへのcrsの指定により地理空間に投影

    # 描画領域の設定（東京駅周辺の座標を確認して入力）
    ax.set_xlim(-8000.0, -4000.0)
    ax.set_ylim(-37000.0, -34000.0)

    # ベースマップ(OpenStreetMap)の追加
    cx.add_basemap(ax, crs=crs, zoom=16, source="http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")

    # 図形(ポイント)の描画
    lat, lon = 35.6810912, 139.7671861  # 東京駅の緯度経度
    transformer = pyproj.Transformer.from_crs("EPSG:4326", crs)
    y, x = transformer.transform(lat, lon)
    plt.scatter(x, y, s=200, c="red", alpha=0.5, label="東京駅")

    # 凡例の描画
    ax.legend(loc="upper right", prop={"size": 20})

    # OpenStreetMapのクレジットを右下隅に表示
    text_box = AnchoredText("© OpenStreetMap contributors", loc="lower right", borderpad=0, frameon=True)
    plt.setp(text_box.patch, facecolor="white", alpha=0.6, linewidth=0)
    ax.add_artist(text_box)

    # プロットエリアの枠を非表示
    ax.set_axis_off()

    # プロットエリア以外の部分をなくし、地図部分のみをファイルに出力
    fig.tight_layout(pad=0)
    fig.savefig("output.png", bbox_inches="tight", pad_inches=0)


if __name__ == "__main__":
    main()
```

以下のようにベースマップやポイント、凡例やOpenStreetMapのクレジットの表示ができました。

![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591150/8731b0c2-0ead-474d-5d21-cd87baa3096a.png)


# 参考文献

https://yyousuke.github.io/matplotlib/cartopy.html

https://andrewpwheeler.com/2020/06/25/creating-a-basemap-in-python-using-contextily/
PandasによるDataFrameの値更新について

# 背景
pandasの特定行の値を更新したいが反映されないケースがあったので調査した。


# 調査結果
下記のミスケースでは、
master_df の一部を選択してコピーを作成し、そのコピーに対して "customer_name" の値が "XYZ" に変更されることを意味します。しかし、元の master_df は変更されず、警告も表示されません。つまり、意図した変更が元のデータフレームに反映されないという問題が発生します

元のデータフレームに対して、.loc や .iloc を使用してデータを選択し、その選択されたビューに対して変更を加える必要があります。

```py
print(master_df[master_df["customer_id"] == "IK152942"]["customer_name"])

#ミスケース
master_df[master_df["customer_id"] == "IK152942"]["customer_name"] = "XYZ"
print(master_df[master_df["customer_id"] == "IK152942"]["customer_name"])

#成功ケース
master_df.loc[master_df["customer_id"] == "IK152942", "customer_name"] = "XYZ"
print(master_df[master_df["customer_id"] == "IK152942"]["customer_name"])
```

出力
```
0    平田 裕次郎
Name: customer_name, dtype: object
0    平田 裕次郎
Name: customer_name, dtype: object
0    XYZ
Name: customer_name, dtype: object
```
SublimeText4 でInstallPackege が機能しない場合の対処法

# TL;DR
4.0 beta 版のPackageControl をDLしてきて既存のものとリプレイスすると解決します


# 経緯
Macを新しいマシンに移行するときにIntel→AppleSilliconに変更したときにSublimeText のPackage Install が動かなくなっていました。

日本語記事が全くなく、Sublime のForumを見たところ、海外ニキも同様の現象で苦しんでいたので解決方法を日本語で解説します。

# 解決方法

手順としては以下の通りです

1. [Github のRelease ページ](https://github.com/wbond/package_control/releases) にある `Package Control.sublime-package` をDLします
![スクリーンショット 2023-10-15 17.15.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65257/1f982aea-e255-fa79-6d30-7ce8c4c5b336.png)

1. SublimeText4 を起動します.
1. Menu→Settings→Browse Packeges... を選択します
![スクリーンショット 2023-10-15 17.16.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65257/e8850a14-f97e-6099-6c55-c1219e14f4b4.png)

1. Finder が開くので Packeges→Userの中にある `Package Control.sublime-package` を削除し、先ほどDLした `Package.Control.sublime-package` を配置します
1. DLしてきたファイル名が `Package.Control.sublime-package` とPackage とControlの間に `.` があるので、それを半角スペースに置換して `Package Control.sublime-package` というファイル名に変えます
1. SublimeText4 を再起動します

## 参考になったスレッド

https://github.com/wbond/package_control/issues/1612#issuecomment-1636034709

こちらの方法を実行したところ、install package が使えるようになりました
SwiftUiでViewの3D回転してみる

今回はViewを3D回転させてみようと思います。
あまり使い所が無さそうですが、頭の片隅にでも入れておけば、何かの役に立つかもしれないですね。

【Xcode】 15.0
【Swift】 5
【iOS】 17


```Rotation3dSampleView.swift
struct Rotation3dSampleView: View {
    var body: some View {
        Text("Hello, World!")
            .rotation3DEffect(.degrees(45), axis: (x: 0.0, y: 1.0, z: 0.0)
        )
    }
}
```

`rotation3DEffect`を使用すると、実装できます。
第一引数の`Angle`に角度を設定して、`axis`はどの方向かを設定するみたいです。
実行結果はこのようになりました。

![スクリーンショット 2023-10-15 17.10.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/bc8630c4-3dc3-72b9-30e6-db63c31b9bbc.png)
UE5 ブループリントでカメラの上下幅を制限する設定方法のメモ

自分用のメモです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572997/8f67469c-a461-c935-4743-3d956a1ea1af.png)
(適当な記事ですみません…。m(_ _)m)
storycapで、複数のviewportを自動で撮り分ける

## やりたいこと

人の目では取りこぼしがちな、見た目のバグ(レイアウトくずれ, etc)。
これは、[Storybook](https://storybook.js.org/) x [storycap](https://github.com/reg-viz/storycap) x [reg-suit](https://github.com/reg-viz/reg-suit)を使えば、簡単に検知できます。

ここでレスポンシブ対応時には、Storybook上で異なるviewport(≒画面サイズ)を確認したいが、一つのコンポーネントに対して複数のviewportに応じたstoryを定義するのはちょっとしんどい、、、[^1]

そこでstorycap側で複数のviewportを自動で撮り分ける方法をメモ。

## やり方

※reg-suitとstorycapは導入済みとします。

`.storybook/preview.ts`に撮り分けたいviewportの設定を追加。

```typescript:preview.ts (抜粋)
import { ScreenshotOptions } from "storycap/lib/shared/types";

const screenshot: ScreenshotOptions = {
  viewports: {
    mobile: {
      width: 428,
      height: 926,
    },
    tablet: {
      width: 768,
      height: 1024,
    },
    desktop: {
      width: 1440,
      height: 1024,
    },
  },
};


const preview: Preview = {
  parameters: {
    ...
    screenshot, // <- parametersに追加
  },
  ...
};

export default preview;
```

以上。

## 補足

[`ScreenshotOptions`の`viewports`プロパティは`string[]`型も受け付けるようだが](https://github.com/reg-viz/storycap#type-screenshotoptions)、自環境で試した際は[Puppeteer側に定義済みのviewport名](https://pptr.dev/api/puppeteer.devices)しか呼び出せなかった。
(Storybookのaddonで定義したviewport名は呼び出せなかった。)

そのため、記事執筆時点ではreg-suit、Storybookのaddon両方でviewportを定義するしかなさそう。

## まとめ

もっといい方法あればぜひコメントお願いします!!

[^1]: モバイルファーストのPJならちゃんと定義したい。
リーダブルコード　第3章　誤解されない名前　まとめ

## 誤解を生ませないようにするために
名前を付けた時、名前が「他の意味と間違えられることはないだろうか」と何度も自問自答する
→初めてコードを見る人に誤解を生まなせないようにするため

例1）
データベースの問い合わせ結果を処理する、以下のコードがあるとする
`results = Database.all_objects.filter("year <= 2011)`
`filter`メソッドによって`year`が2011以下のオブジェクトを取り出す処理に見えそうだが、
a. `year`が2011以下のオブジェクト
なのか
b. `year`が2011以下ではないオブジェクト
なのかが明確でない
そのため、
- a. であれば、「`year`が2011以下のオブジェクトを選択する」という意味で、
`filter`→`select`に
- b. であれば、「`year`が2011以下のオブジェクトを除外する」という意味で、
`filter`→`exclude`に
変更する

例2)
`text`に書かれている最後の内容を切り落として「...」をつける関数があったとする
```
def Clip(text, length):
  ...
```
1. Clipメソッドの動作が、「最大length文字まで切り取る」場合、
「（新聞・雑誌などから）切り抜く」「（画像を）切り抜く［取る］」という意味を持つ
`Clip`という単語ではなく、
「文・説明などを切りつめる（切り取って短くする）」という意味の
`Truncate`を用いた方が読み手に疑問を持ちづらくなる
2. 「最大length文字まで切り取る」という動作のため、
`length`を「最大length文字」という`max_length`という変数名に直した方がいい
しかし、`length`といっても、バイト数なのか、文字数なのか、単語数なのかといった、
様々な解釈ができる
今回の場合は文字数を表しているので、
`max_length`→`max_chars`に変更する

## 参考資料
clip(英語)の日本語訳、読み方は - コトバンク 英和辞典
https://kotobank.jp/ejword/clip

truncate(英語)の日本語訳、読み方は - コトバンク 英和辞典
https://kotobank.jp/ejword/truncate

切詰める(キリツメル)とは？ 意味や使い方 - コトバンク
https://kotobank.jp/word/%E5%88%87%E8%A9%B0%E3%82%81%E3%82%8B-480332
Nuxt Bridge移行　runtimeConfigの環境変数が取得できない

Nuxt Bridgeの移行を試していた際に直面した問題についての備忘録。

runtimeConfigの書き換えを対応しようとしたのですが、
その中で`.env`に入れていた環境変数がうまく取得できずに詰まりました。

https://nuxt.com/docs/bridge/runtime-config


## 課題

`.env`ファイルに入れている環境変数を以下のようなイメージで取得していた。

```ts
publicRuntimeConfig: {
    URL: process.env.URL || "http://url",
  },
```

Bridgeへの移行ドキュメントを読むと、以下のようにすればいけるはずだと思った。
クライアントでも使う環境変数のため、publicキーの中に入れる。
（サーバーだけならprivateにしておく方がいいです。）

```ts
runtimeConfig: {
    public: {
      URL: process.env.URL || "http://url",
    },
  },
```

https://nuxt.com/docs/bridge/runtime-config

→結果、取得できませんでした

## 結論

特にドキュメントには書いてなかった（おそらく）が、
Nitro使用時にしかruntimeConfigの書き方は使えない可能性がある。

https://github.com/nuxt/bridge/issues/9

なので、元の書き方のままにして対応しました。
そして一応動いたので問題なしと判断。

なかなか調べても情報自体が少ないので、
正確な情報があれば教えていただけますと幸いです🙇
pandasによるDataFrame型の値取り出しについて

# DataFrame型の値取り出しについて
DataFrame型の値を取り出して利用する際に、型でエラーになることが多かったのでノウハウを残す。

エラー理由は下記の条件分だけでは該当数列すべてが抽出され（今回のケースでは1行しかないが）、class 'pandas.core.series.Series' 型なっていたことである。
そのため、.valuesを用いることで class 'str' の値を取り出すことができた。

```py
import pandas as pd

master_df = pd.read_csv("customer_master.csv")

#値のみが取得できていない
target_data = master_df[master_df ["customer_id"] == "IK152942"]["customer_name"]
print(type(target_data))
print(target_data)

#値が取得できている
print(type(target_data.values[0]))
print(target_data.values[0])
```
下記を参照
https://www.delftstack.com/ja/howto/python-pandas/how-to-get-a-value-from-a-cell-of-a-dataframe/
[Python] ランダムモジュール

## モジュールとは？

**モジュール**はプログラムを構成するコンポーネントで、関連するデータと関数を 1 つにまとめたユニットを意味します。

つまり実装したい機能を直接作成することなく、すでに作成されたファイルを取得することで、コードの可読性を高め、量を減らすことができます。

randomモジュールを利用して調べてみます。

<br>
<br>


## ランダムモジュール
randomモジュールを利用するためには、次のようなコードを作成する必要があります。

```python
import random
```

<br>

これでランダムモジュールを書くための準備が完了しました。



<br>
<br>

## サイコロ転がし
それではランダムモジュールを利用してサイコロ転がしてみます。

ランダムに整数を生成するには、次のようなコードを作成する必要があります。
```python
import random

print(random.randint(1,6)) # 1~6の中でランダムに設定される
```


## その他の機能

ランダムで実数を取得することもできます。
```python
import random

print(random.random()) # 0~1の中にある実数を設定する
```

1以上の実数を設定したいなら、ほしい数を掛けてください。
```python
import random

print(random.random() * 5) # 0~5の中にある実数を設定する
```
AWS Amplify Hosting に React (Vite) アプリをデプロイする

:::note alert
2024/05/15
この記事の内容は古いです．
:::

Ubuntu 22.04 (WSL2) で実行しています．

## Vite + React プロジェクトを作成

```bash
> npm create vite@latest
Need to install the following packages:
  create-vite@4.4.1
Ok to proceed? (y)
✔ Project name: … vite-project
✔ Select a framework: › React
✔ Select a variant: › TypeScript + SWC

Scaffolding project in /home/be4rr/projects/vite-project...

Done. Now run:

  cd vite-project
  npm install
  npm run dev
```

```bash
> cd vite-project
> npm install
added 153 packages, and audited 154 packages in 11s

37 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
```

開発サーバーを起動して動作を確認します．
```bash
> npm run dev

  VITE v4.4.11  ready in 138 ms

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

http://localhost:5173 をブラウザで開くとReactアプリが動作しているのを確認できます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/4578d17d-8bb8-9296-7bf9-1ea855cbc4f2.png)

満足したらターミナル上で`Ctrl+C`を押して開発サーバーを停止します．

## GitHub にアップロード

ここでGithubにプロジェクトをアップロードします．GitHubへのアップロードはコマンドで行っても良いですが，VSCodeから行うととても簡単です．
![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/904aa6c6-0872-f068-83a6-8aba3ca8de43.gif)

GitHubにリポジトリが作成され，プロジェクトの中身がアップロードされます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/520d1214-050f-9b19-de97-fa16152fd0cc.png)

## Amplify Hosting にデプロイ

AWSマネジメントコンソールから AWS Amplify を開きます．AWS Amplify のページを下の方までスクロールして Amplify Hosting の「使用を開始する」を押します．Amplify Studio ではないので注意してください．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/33f1b2b7-e079-15f6-9d7b-8e81ca071c5c.png)

GitHubを選択します．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/863d374a-0afb-df35-586d-1ee24a4cb671.png)

先ほど作成したGitHubリポジトリとブランチを選びます．米初回の場合はGitHubとの接続を求められます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/17390c71-b181-7c34-4028-9cbd48e9b3e9.png)

「構築とテストの設定」で「編集」を押し，ビルド設定を編集します．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/fdad6313-b7f7-4413-d17f-166a7e9c546c.png)

ビルド設定を次のように変更します．
```diff
- baseDirectory: /
+ baseDirectory: dist
```

最後に設定を確認し，「保存してデプロイ」します．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/356ea160-365c-42fb-7b8d-fb3fd9dcf5b8.png)

画面が遷移しデプロイが始まります．デプロイが完了後に左下のURLを開くとデプロイされたアプリを確認できます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/f25aaa26-48ea-1c94-2211-acc9c51ecd53.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/f85c072d-db27-b7a5-a665-e5e774d2dd1b.png)

## アプリの削除

デプロイしたアプリを削除するには，右上の「アクション」から「アプリの削除」を選択します．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/dde9d520-7010-d8f2-9c28-dd9f86af5049.png)

## 参考


https://docs.amplify.aws/guides/hosting/vite/q/platform/js/
【JavaScript・学習ログ2】条件分岐・繰り返し処理

# 目次
[1. if文](#1-if文)
[2. switch文](#2-switch文)
[3. while文](#3-while文)
[4. for文](#4-for文)

<font color=gray>参考：侍テラコヤ『JavaScriptの基礎を学ぼう』https://terakoya.sejuku.net/programs/60/chapters</font>
## 1. if文
条件を提起して処理を分岐させる記述。
```javascript
const num = 50;
if (num > 10) {
    console.log('定数numは10より大きい');
```
#### 戻り値について
```javascript
console.log(45 + 18); // 算術演算子
console.log(45 > 18); // 比較演算子
```
【実行】![スクリーンショット 2023-10-15 143231.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/99d2bf36-4778-4ab9-5879-035f225debe7.png)
算術演算子の場合は数値型のデータが戻り値として返され、比較演算子の場合は論理型(true,felse)が返される。
| | | | |
|-|-|-|-|
|==|等価|===|厳密等価|
|!=|等しくない|!==|厳密に等しくない|
|>|左辺が右辺よりも大きい|>=|左辺が右辺以上|
|<|左辺が右辺よりも小さい|<=|左辺が右辺以下|

#### 等価と厳密等価の違い
```javascript
console.log('5' == 5);
console.log('5' === 5);
```
【実行】
上がtrue、下がfalseで返される。値が同じだが文字列型と数値型とでデータ型の違いを認識しているため。

#### if-else分
numが４の場合は大当たり、numがそれ以外のときははずれと出力されるプログラム。
```javascript
let num = Math.floor(Math.random() * 5);
console.log(num);
if (num === 4) {
	console.log('大当たりです');
}
else {
	console.log('はずれです');
}
```
#### 「かつ」「または」で複数の条件を組み合わせる
```javascript
// 「&&」= かつ
& num < 30) {
	console.log('変数numは10より大きく、30より小さい');
} else {
	console.log('条件が成り立ちませんでした')
}
// 「||」= または
num = 30;
if (num === 10 || num === 30) {
	console.log('変数numは10または30です');
} else {
	console.log('条件が成り立ちませんでした')
}
```
## 2. switch文
提起した多数の条件によって処理を切り替える記述。
いずれのケースにも当てはまらない場合はdefault:で記述する。
```javascript
num = Math.floor(Math.random() * 5);
console.log(num);
switch (num) {
	case 2:
		console.log('小吉です');
		break;
	case 3:
		console.log('中吉です');
		break;
	case 4:
		console.log('大吉です');
		break;
	default:
		console.log('末吉です');
		break;
}
```
※breakを記述しないと、処理がすべて実行されてしまうため、必ず記述する。

<hr>

## 3. while文
条件を満たしている間、同じ処理を繰り返し行える記述。
```javascript
let num = Math.floor(Math.random() * 5);

console.log('最初の値は' + num + 'です');
while (num !== 0) {
	num = Math.floor(Math.random() * 5);
	console.log('現在の値は' + num + 'です');
}
```
※falseが返ってこず、無限ループを発生しブラウザがフリーズしてしまった場合はタブをタスクマネージャーから閉じる。
【実行】
![スクリーンショット 2023-10-15 162656.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/4b8444cc-1838-aad7-fc7c-25fbe895a91a.png)
## 4. for文
決まった回数、同じ処理を繰り返す記述。
```javascript
for (let i = 1; i <= 10; i++) {
	console.log(i);
}
```
![スクリーンショット 2023-10-15 163822.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/e7bb046c-a828-cd24-0f28-834351f268c4.png)

<hr>

（簡易メモ）
あとで記入
PMP試験受験を振り返って

こんにちは、ちゅらデータ SE きたっぴです。

先日、PMIが認定しているプロジェクトマネジメントに関する国際資格であるPMP(プロジェクトマネジメント・プロフェッショナル)の受験を行い、無事１回目の受験で合格することが出来ました。

受験を振り返り、感じたことについて記載したいと思います。

# 試験自体の難易度について
多くの解説サイトではPMP資格はかなりの難関資格と記載されておりますが、試験自体の難易度はそれほどではなかったかなと感じました。
合格ラインは正答率60%であり、ほとんどが四肢択一式の出題であるため想像よりも解きやすいと思います。シチュエーション問題の為、四肢択一式でもPMBOKを理解しておけばNG選択肢はすぐわかると思いますのでその後は学習した「PMPとしてのPMの在り方」に則ってふさわしい回答を行っていきましょう！

どちらかというと180問を230分で回答を行っていかなければならないため、体力テストの側面も強かったなという印象を持っています。
合格率は公表されておりませんが、よくよく比較されるIPA高度試験と比べてもかなり高いと思います。どちらも受験を行った身としては（IPA高度試験は不合格でした・・・）択一式のため、PMP試験の方が難易度が優しいなと感じました。

PMP試験は、試験自体の難易度ではなく、試験に臨む前の準備難易度が凄く高いと感じました。
・35時間研修
・3年間のマネジメント経験
・PMBOK基礎知識の習得

ここさえ乗り越えれば試験自体は高い壁でないと思います。

# 試験のプレッシャーについて
PMP試験を調べたことがある人ならわかると思いますが、本試験は受験費用が$555と他の比較するとかなりの高額となっています。
私の場合は、資格取得に理解ある会社に属していたため費用補助を頂く事が出来ましたが、そうでない場合は、ちょっとやってみようか！レベルの勢いで受験できないような壁となりますよね。
不合格となれば、また受験費用が掛かるためプレッシャーが非常にかかりました。
（不合格になったから受験費用オカワリ！なんてこんな高額であんまり言いたくない・・・）

また、未来永劫受け続けられるわけではなく受験回数制限もございます。
3回/年です。3回NGとなった場合は、再度35時間研修を行った上で翌年から挑戦可能となります。
不合格状態で1年以上いるのは非常にプレッシャーになると思います。

# PMP合格だけでマネジメントレベルの急上昇なんてない
PMPを合格することで、PMBOKについての知識を把握している人間であるとのお墨付きが頂けたと思っていますが、これだけでマネジメントレベルの急上昇なんてしないと感じています。
所詮、テンプレート通りのプロジェクトの進捗方法、課題発生時の解決手順といったものの知識の為、実際の現場で動いてみなければ身にはならないと思います。

ただ、本資格を持つことでどう進めていくのが、PMBOKとして定める正しい手順なのかは知ることが出来ました。現場で今まで挑戦できなかったことへの挑戦権を得られたと思っているので、資格に恥じない働きをしていきたいと思います。

（合格して、PMP資格という高級サブスクに加入する権利を得た気分でもありますｗ3年おきに2万程度の更新費+PDUを取得するためのセミナー代）

次回以降は、PMBOKに記載されている内容について小項目とはなりますが解説していこうかなと思います。
Vim で各行ごとに Python スクリプトを適用する方法

```find```で求めたファイルパスの```/```を数えることでディレクトリ深度を調べようとしたところ失敗したので調査したという記事です。

## やろうとしたこと

Vim にはフィルタという非常に便利な機能があります。これは指定された行を引数にしたコマンドの実行結果を返す機能です。

これを使って
```plaintext
./hoge.txt
./fuga/piyo.txt
```
というテキストを
```plaintext
1:./hoge.txt
2:./fuga/piyo.txt
```
のようにしようとしていました。

## うまくいかないコード

```vimscript
:%!python3 -c 'import sys; print(sys.stdin.read().count(r"/"))'
```
このようにすると、全ての行を結合して一行の文字列としてコマンドに渡したものと扱われてしまいます。


## うまくいったコード

どのように渡されているのかが分かれば難しいことはありません。
```vimscript
:%!python3 -c 'import sys; [ print(str(i.count(r"/")) + ":" + i) for i in sys.stdin.readlines()]'
```
Python の側で入力をリストとして受け取り内包表記で加工します。
複数個あるファイルの総サイズを求める方法

複数個あるファイルの総サイズを求める方法を調べたので共有します。

具体的には、次の 2 つのケースについて説明します。
- カレントディレクトリにあるファイルの総サイズ
- 複数のディレクトリにあるファイルの総サイズ


## カレントディレクトリにあるファイルの総サイズ

この場合は簡単です。

```bash
# 詳細を表示する
ls -l
# 2進接頭辞表記に変換する。K,M,Gなどと書かれていますが KiB,MiB,GiBです。
ls -lh
```
このコマンドで総サイズがわかります。

## 複数のディレクトリにあるファイルの総サイズ

次は、複数のディレクトリをまたぐ場合です。
この場合は、```find```でファイルリストを、```du```でファイルサイズを得て、 ``` awk ```を使い合計を求めるのが良いでしょう。
対象ディレクトリの共通する親ディレクトリに移動し、次のコマンドを入力します。

```bash
find . -type f -exec du {} + | sort -rn | awk 'BEGIN {print "SIZE\tNAME"} {sum+=$1;print $0} END {print sum,"TOTAL"}'
```

これで直下のディレクトリのファイルの総サイズが取得できます。
カレントディレクトリにあるファイルの総サイズもこのやり方でわかりますが、タイプ数が多いので使うことはないでしょう

更に絞り込みたい場合は```find```の```-name```オプションなどで細かくファイルを指定できます。
Python 3 エンジニア認定基礎試験に合格しました。

#### はじめに

タイトルにあるように「Python 3 エンジニア認定基礎試験」に合格しました。
このページには試験勉強に利用したものを記載します。

#### 読み飛ばしても問題ない内容

そもそもなぜPythonの資格を取ったのか、と。
配属先で「Python使うことになるよー」と話しが出たため、Pyhton知識ゼロのやまだは勉強することにしました。

#### 勉強に利用したもの
 - 参考書
   - スッキリわかるPython入門（著者：国本大悟さん/須藤秋良さん）
     - 理由：Javaの参考書も同じシリーズを利用していたため。読みやすい。
 - ネット
   - DIVER INTO CODE
     - 模擬試験を受けられる。
     - 隙間時間にも利用できた。移動時間とかとか。
     - 会員登録が必要（無料と有料、両方ある。山田は無料を利用）
   - PRIME STUDY
     - 模擬試験を受けられる。
     - メールで試験結果を受け取れ、間違った問題は赤字で表示される（受け取りによっては黒字かも。。）
   - Colaboratory
     - 実際にPythonのコードを書いて、書いた結果をすぐに確認できる。環境構築とか不要。Googleのアカウントさえあれば使える。
     - 参考書の問題をここに書いて、「ほぁぁぁ(\*'ω'*)」と感動していました。
  - 紙（ノート）※
    - 模擬試験で間違えた問題等を、問、答え、理由を書いて頭に叩き込むために利用。
    - ※やまだは紙に書くのが好きなので、「紙」に関しては人によります！

#### 終わりに

これから「Python 3 エンジニア認定基礎試験」を受ける人、頑張ってください！
Marvell(旧AQUANTIA) AQC107の動作を安定化させる

# はじめに
10GbE対応のLANカードの中でもお手頃な価格で入手できるMarvell(旧AQUANTIA) AQC107であるが、その動作が不安定なことは各種記事やレビューにて多々指摘されている。
筆者も不定期に接続が切断される現象に悩まされていたが、解消することができたためその方法について備忘録として記載する。

# 環境
- Windows 11 Pro 22H2
- AREA 10Koenig Gen2[^1]

# ドライバ/ファームウェアのアップデート[^2]
## ドライバ
[Marvelのサポートページ](https://jp.marvell.com/support/downloads.html)から最新版がダウンロードできます。
`2023/10/15`時点での最新版は`3.1.7`です。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577468/357e9c18-d068-8b09-6894-06cd6f3b6b3a.png)

## ファームウェア
`2023/10/15`時点での最新版は`4.2.40`ですが、
前項に記載のMarvelのサポートページからダウンロードできる最新版は`3.1.121`となっています。
`4.2.40`のファームウェアは非公式のサイトからダウンロード可能ですが、
まずは公式からダウンロードできる`3.1.121`にて事象が解消するか確認することを推奨します。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577468/f836af75-f045-193c-84c6-7c5927b1e7c9.png)

ダウンロードしたファイルを展開し、`atlflashupdate.exe`を管理者権限で実行することでファームウェアをアップデートできます。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577468/8201b31d-fcf3-28e4-e78b-c094802fe895.png)

### 4.2.40にアップデートする場合
`AQC107 4.2.40 Gigabyte`といったワードで検索すると見つかります。
公式以外からファームウェアをダウンロードすることになるため、自己責任で実施してください。

# NICの詳細設定
Offloadとつく項目をすべて`Disabled`にします。
![NICSettings](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577468/7de4b0ff-43c7-8478-1cbe-96262b49ec86.png)

`Disabled`にすることで各項目の処理をNICではなくCPUで処理するようになります。


[^1]: AQC107搭載であれば他製品にも適用できると思います。
[^2]: 筆者はこれらのアップデートのみでは問題の事象は解消しなかった。
【G検定】受験後の感想 2023年9月9日

## G検定 結果
![G検定_結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/d20f714d-d593-2b1e-d5cc-427a577613e0.png)

なんとか合格出来ましたので、学習方法等を備忘録として記載します。
~~数理・統計が低くて恥ずかしい~~

### G検定(2023年9月9日 開催を受験)
G検定の受験方法等の詳細は下記をご確認下さい
<https://www.jdla.org/certificate/general/>

### 受験の経緯
現在会社員として勤務
週に1度の上長との1on1のタイミングで
一緒に検定を取得してみないかと打診があり受験を決意。

分析業務を行う傍ら、ディープラーニングの基礎知識が
不足しているという点と純粋に面白そうという点から受験。

今後の受験者や社内の方向けです。

### 経歴
* GCP(BigQuery)を利用した分析業務を3年従事
　SQLとTableauの利用がメイン
* TableauのDATA Saberを2022年に取得

### 学習期間
* 2023年8月1日～9月9日
約1ヶ月で取得

### 参考本
【スッキリわかるディープラーニングG検定(ジェネラリスト) テキスト&問題演習 第2版】
<https://tacpub.jp/list/detail.php?bc=110101>

:::note info
　参考書籍のオススメは受験者によって異なるので
　本屋にて色々な本を手にとって気に入ったものを
　購入することをおすすめします

　個人的には昔から学習時に図や解説が多いものの方が
　記憶に定着するため、図が多いものを選択しました。
:::

### 学習方法
1\. とにかく本を1周

　基本的な部分で業務で知っている部分はさくっと読み
　DeepLearningの歴史の部分など知らない部分は一度ちゃんと読んでみる
　書籍の章ごとにある確認テストは分かるまで繰り返す

2\. オンラインの模擬テストの利用
<https://study-ai.com/generalist/>
　自身は最終日の**2日前**に上記を受験し
　スピード感と回答方法をイメージした
　書籍の問題と同じようなものをスピード重視で解く

### 参考にさせて頂いたリンク
1.G検定カンペ用語集
学習する際にすぐ調べることができたので感謝します
<https://gkentei.techblog.jp/archives/13712572.html>
<https://gkentei.techblog.jp/archives/13720716.html>

### G検定の所感
　受験後の感想としては、とにかく量が多いなという感じでした。
　残り10分で1割くらい(20問前後)が解けきれずでしたが、サクッと全文を読み
　なんとなく勘で回答を埋めていきました。

　全体的には**書籍**と**オンライン模擬テスト**の内容を把握していれば
　合格可能だと思います。

　書籍は本当によく出るページに折り目をいれていたので
　ど忘れや思い出したい時にすぐ引けるように準備しましょう。

　自分はチートシート等は使いませんでしたが、まとめページも
　多数作成されているので、自分にあったページを
　見つけておくことが重要かもしれないです。
C# DataGridView マウスホイールで左右スクロールする

# ソースコード

* ホイール操作：上下スクロール（通常通り）  
* マウスの右ボタンを押しながらホイール操作：左右スクロール  

```cs
//ホイール操作で上下スクロール、マウスの右ボタンを押しながらホイール操作で左右スクロール
dataGridView1.MouseWheel += (sender, e) =>
{
    DataGridView dataGridView = sender as DataGridView;

    //マウスの右ボタンが押されている場合は左右スクロール
    if ((MouseButtons & MouseButtons.Right) == MouseButtons.Right)//この1行をなくすと通常のホイール操作が左右スクロールに置き換わる
    {
        //スクロール列数
        int scrollNum = 3;

        //ホイール手前で右へ移動
        bool right = e.Delta < 0;

        //「表示される最初の列」が列固定などで画面外にある場合は処理しない
        if (dataGridView.FirstDisplayedScrollingColumnIndex >= 0)
        {
            int nextIndex, preCheckIndex;

            nextIndex = preCheckIndex = dataGridView.FirstDisplayedScrollingColumnIndex;

            //所定列分スクロールする
            for (int counter = 0; counter < scrollNum;)
            {
                preCheckIndex += right ? 1 : -1;

                //インデックスが範囲外、または固定列の場合は終了
                if (preCheckIndex < 0 || dataGridView.ColumnCount - 1 < preCheckIndex || dataGridView.Columns[preCheckIndex].Frozen)
                {
                    break;
                }

                //非表示セルの場合はカウントしない
                if (dataGridView.Columns[preCheckIndex].Visible)
                {
                    counter++;
                    nextIndex = preCheckIndex;
                }
            }

            //「表示される最初の列」を更新
            dataGridView.FirstDisplayedScrollingColumnIndex = nextIndex;

            //最左端のセルの場合で、セルが部分的に隠れている場合はオフセットを0にして隠れている部分をなくす
            if (!right && dataGridView.FirstDisplayedScrollingColumnHiddenWidth == dataGridView.HorizontalScrollingOffset)
            {
                dataGridView.HorizontalScrollingOffset = 0;
            }
        }

        //処理完了
        ((HandledMouseEventArgs)e).Handled = true;
    }
};
```

# 参考URL

* [DataGridView.FirstDisplayedScrollingColumnIndex プロパティ (System.Windows.Forms) | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datagridview.firstdisplayedscrollingcolumnindex)  
* [DataGridViewColumn.Frozen プロパティ (System.Windows.Forms) | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datagridviewcolumn.frozen)  
* [DataGridViewColumn.Visible プロパティ (System.Windows.Forms) | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datagridviewcolumn.visible)  
* [DataGridView.FirstDisplayedScrollingColumnHiddenWidth プロパティ (System.Windows.Forms) | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datagridview.firstdisplayedscrollingcolumnhiddenwidth)  
* [DataGridView.HorizontalScrollingOffset プロパティ (System.Windows.Forms) | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datagridview.horizontalscrollingoffset)  
* [HandledMouseEventArgs.Handled プロパティ (System.Windows.Forms) | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.handledmouseeventargs.handled)  
* [Windowsアプリケーションで［Enter］キーによるフォーカス移動を行うには？：.NET TIPS - ＠IT](https://atmarkit.itmedia.co.jp/ait/articles/0411/19/news111.html)
python で地球上のイベント分布図を大陸図に重ねて表示する方法

# はじめに

地球上のどこでイベントが発生しているかを表示する方法について紹介します。

https://scitools.org.uk/cartopy/docs/latest/

を用いた例になります。衛星や地球観測向けの用途です。

## 簡単なサンプルコードと解説

２次元のガウス分布でイベント発生して、地球図の上に重ねる方法を紹介します。イベントは発生頻度に大きくムラがあることを想定して、２次元ヒストグラムのz方向の表示を対数で表示することにしています。

``` python:
#!/usr/bin/env python

# 必要なライブラリやモジュールをインポート
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import cartopy.crs as ccrs
import cartopy.feature as cfeature

# イベント数の設定
event_num = int(1e5)

# 経度用のガウス乱数の平均値と標準偏差を設定し、乱数を生成
mean_lon = 0
std_deviation_lon = 60
random_lon = np.random.normal(mean_lon, std_deviation_lon, event_num)

# 緯度用のガウス乱数の平均値と標準偏差を設定し、乱数を生成
mean_lat = 0
std_deviation_lat = 10
random_lat = np.random.normal(mean_lat, std_deviation_lat, event_num)

# 描画の設定
fig, ax = plt.subplots(figsize=(10, 4), subplot_kw={'projection': ccrs.PlateCarree()})
ax.set_extent([-180, 180, -60, 60])
ax.add_feature(cfeature.BORDERS, linestyle=':')
ax.add_feature(cfeature.COASTLINE)
plt.title("count map")
plt.xlabel("longitude")
plt.ylabel("latitude")

# 地図上のグリッドラインを追加
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=0.5, color='gray', alpha=0.5, linestyle='--')
gl.xlabels_top = False  # Top longitude labels are turned off
gl.ylabels_right = False  # Right latitude labels are turned off

# 2次元ヒストグラムを計算し、地図上にプロット
H, xedges, yedges = np.histogram2d(random_lon, random_lat, bins=[120, 29], range=[[-180, 180], [-31.15, 31.15]])
pcm = plt.pcolormesh(xedges, yedges, H.T, norm=LogNorm(vmin=1, vmax=np.amax(H)), transform=ccrs.PlateCarree())
plt.colorbar(pcm, ax=ax, shrink=0.4, label='Number of events')

# 描画を最適化
plt.tight_layout()

# 画像として保存
plt.savefig("earth.png")

# 画像を表示
plt.show()
```

これを実行すると下記の図が生成されます。

![earth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/88b877d1-8c94-46ec-c510-82a3bb1e86c6.png)

## 補足

背景となる地球の座標系の表示は、

``` python:
ax.set_extent([-180, 180, -60, 60])
``` 

のように、経度-180度から 180度、緯度-60度から60度の範囲に設定しています。

データの方は、

``` python:
H, xedges, yedges = np.histogram2d(random_lon, random_lat, bins=[120, 29], range=[[-180, 180], [-31.15, 31.15]])
```

この部分で、経度-180度から 180度、緯度-31.15度から31.15度(特に深い意味はありませんが、日本で打ち上げた地球周回衛星のおおよその緯度)の範囲に設定しています。

もし、経度のデータが、0度から 360度の仕様となっている場合は、

``` python:
def convert_longitude(longitude):
    return longitude - 360 if longitude > 180 else longitude
```

のような関数を持ちいて、180度以上のデータを -360度の分だけ平行移動しましょう。
LangChainでカスタムエージェントを作る

# LangChainにてカスタムエージェントを作ってみた。
Function CallingとLangChainの組み合わせにより、Re-Actプロンプトの実現ができるが、LangChainの用意したツール(PythonREPLTool等)にて簡易に簡易に実現できるユースケースばかりではなく、要件に応じてアクションをカスタマイズしたいといったケースのサンプル。参考サイトのコピペですがAzure OpenAIのリソースで動作＆日本語応答だけカスタマイズしています。

- Langchain Agentを使う場合に、実行機能を任意に作成したい場合に使う。
- langchainのBaseToolを継承したクラスとして定義。_runメソッドを実装することで、Agentのアクションで実行される。


## Azure OpenAIのリソース定義
AOAIリソースのエンドポイントURL、APIキー、デプロイ名を設定する。（OS環境変数に設定したものを取得するようにするのが良い）
```
BASE_URL = ""
API_KEY = ""
DEPLOYMENT_NAME = ""
```

## カスタムリソースの定義部
サンプル例では円の半径（r）から円周(2πr)を計算するためのツール（CircumferenceTool）を作成する。BaseToolを継承して作成する。
```
from langchain.tools import BaseTool
from math import pi
from typing import Union

class CircumferenceTool(BaseTool):
    name = "Circumference calculator"
    description = "use this tool when you need to calculate a circumference using the radius of a circle"

    def _run(self, radius: Union[int, float]):
        return float(radius)*2.0*pi

    def _arun(self, radius: int):
        raise NotImplementedError("This tool does not support async")
```

## Azure OpenAIのChatModel定義
Langchain のLLM Chat modelを定義する。AOAIを使うため、AzureChatOpenAIモデルを使用。api_versionはFunctionCallingを使うのであれば2023-07-01-previewを使用。（ここらは利用機能と公式APIリファレンスの状況によって変えるところ） Chatの会話履歴を保持するためのMemoryも用意する。

```
from langchain.chat_models import AzureChatOpenAI
from langchain import LLMChain, PromptTemplate
from langchain.chains.conversation.memory import ConversationBufferWindowMemory

llm = AzureChatOpenAI(
    openai_api_base=BASE_URL,
    openai_api_version="2023-07-01-preview",
    deployment_name=DEPLOYMENT_NAME,
    openai_api_key=API_KEY,
    openai_api_type="azure",
)

conversational_memory = ConversationBufferWindowMemory(
        memory_key='chat_history',
        k=5,
        return_messages=True
)
```

## カスタムツールを使用するエージェントの定義
Toolの定義にて先ほどのカスタムツールを設定。agentをイニシャライズして、LLM、toolを指定して完了。

```
from langchain.agents import initialize_agent

tools = [CircumferenceTool()]

# initialize agent with tools
agent = initialize_agent(
    agent='chat-conversational-react-description',
    tools=tools,
    llm=llm,
    verbose=True,
    max_iterations=3,
    early_stopping_method='generate',
    memory=conversational_memory
)
```


## 実行
実際に実行してみる。
```
agent("半径5mの円周は？日本語で回答して。")
```

## 実行結果
実行結果としてLLMがToolを使用すると判断し、そのインプット（半径）を指定。Toolの実行結果を持って最終結果を算出し、回答文をLLMが作成する。

```
    > Entering new AgentExecutor chain...
    ```json
    {
        "action": "Circumference calculator",
        "action_input": "5"
    }
    ```
    Observation: 31.41592653589793
    Thought:```json
    {
        "action": "Final Answer",
        "action_input": "半径5mの円の円周は約31.42mです。"
    }
    ```
    
    > Finished chain.
    
    
    {'input': '半径5mの円周は？日本語で回答して。',
     'chat_history': [],
     'output': '半径5mの円の円周は約31.42mです。'}
```



## 参考
https://www.pinecone.io/learn/series/langchain/langchain-tools/
AtCoder解説やってみます

私は地方で働く小さなSIerの1エンジニアです。
勉強のため、インプットした内容を整理したり、見つけた便利な方法などをお伝えします。
2023年10月現在トピックとして考えているのは下記です。
どんどんアウトプットしていきたいと思います。
1. AtCoderでPythonを使って解いた問題の解説を書いてみる
2. Salesforce Marketing Cloudの実装などで困ったこと
3. 最近読んだ本の感想など

AtCoderのアカウントは下記です。
https://atcoder.jp/users/jacobiIdentity

適宜こちらは更新しようと思います。
よろしくお願いします。


#### 二部グラフ
https://qiita.com/sato_ryo/items/a0d8f044631921089380#d---good-tuple-problem
### 尺取法
https://qiita.com/sato_ryo/items/a0d8f044631921089380#d---good-tuple-problem
### UnionFind木
https://qiita.com/sato_ryo/items/9d96bbb0ff4dd0e7bcc5
### 累積和
https://qiita.com/sato_ryo/items/fe05b15636b232da5d04#c---consecutive
お風呂スイッチをラズパイのみに変更

# 変更内容

下記で作った、ESP8266でのお風呂スイッチが壊れちゃいました、もともと、ラズパイのNode-REDでWEB-APIを叩く方式だったので、ラズパイ上にそのままサーボコントロールを書いて、動かすことにしました。

元に記事
↓
https://qiita.com/ABK28/items/062d6d5dd331ba5e7c82

# お礼

下記を参考にしました。
っていうか、ほぼそのままです。

https://qiita.com/elyoshio92/items/b2e7a7728875ebebe542

ありがとうございます。


#　pythonコード

上記サイトを編集して、下記コードを書きました。

```py
import RPi.GPIO as GPIO
import time

INTERVAL = 0.6
PIN = 14
FREQ = 50

GPIO.setmode(GPIO.BCM)

GPIO.setup(PIN, GPIO.OUT)
servo = GPIO.PWM(PIN, FREQ)

#init
servo.start(0.0)

servo.ChangeDutyCycle(2.7)
time.sleep(INTERVAL)

servo.ChangeDutyCycle(4.0)
time.sleep(INTERVAL)

servo.ChangeDutyCycle(2.7)
time.sleep(INTERVAL)

GPIO.cleanup()
```

``/home/ofro-sw/sg90.py`` として保存しました。

# ラズパイの配線

４pin　→　電源 5V
6pin　→　GND
8pin（GPIO１４）　→　制御線
です。

![IMG_8815.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/77539cba-6aa8-bc8b-7f59-8dd93db0fe44.jpeg)

![IMG_8816.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/68838dc7-0c78-484f-9b03-a7f18630b23b.jpeg)


# 試し実行

```
/usr/bin.python /home/ofro-sw/sg90.py
```

動いた！　
OKです。

# Node-REDの変更

これまで、WEB-APIを叩いてたところを、コマンド実行に置き換えます。

![Node-RED_20231015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/8c51693c-02d2-8082-716a-7190788e17e1.png)

## デプロイ

デプロイを忘れずに。

# Alexaを試す

「アレクサ！　お風呂をつけて」

うぃーーん。

#完成

めでたしめでたし
Bash スクリプトのユニットテスト入門: Bats を使ってみよう

## **はじめに**

Bash スクリプトは非常に便利ですが、その信頼性を確保するためには適切なテストが不可欠です。この記事では、Bats（Bash Automated Testing System）を使って Bash スクリプトのユニットテストを行う方法を紹介します。Bats は、Bash スクリプトをテストするための強力なツールで、シンプルな構文と使いやすさが特徴です。

## **インストールとセットアップ**

最初に、Bats をインストールしセットアップします。Linux の場合、以下のコマンドを使用します。

```bash
sudo apt-get install
```

## **テスト対象の Bash スクリプト**

この記事では、簡単な計算機スクリプト **`calculator.sh`** をテスト対象として使用します。

```bash
#! /bin/bash

add () {
  echo $(($1 + $2))
}

subtract () {
  echo $(($1 - $2))
}
```

## **テストの書き方**

Bats を使用してテストを記述するには、Bats テストスクリプトを作成します。以下は、**`calculator.sh`** のテストを行うためのサンプルスクリプト **`calculator_test.bats`** です。

```bash
#!/usr/bin/env bats

# テスト対象のスクリプトを読み込む
load 'calculator.sh'

# add 関数のテスト
@test "2 + 3 は 5 に等しい" {
  result="$(add 2 3)"
  [ "$result" -eq 5 ]
}

# subtract 関数のテスト
@test "5 - 2 は 3 に等しい" {
  result="$(subtract 5 2)"
  [ "$result" -eq 3 ]
}

```

このテストスクリプトでは、**`load`** コマンドを使用してテスト対象のスクリプトを読み込み、**`@test`** ブロック内でテストケースを定義しています。

## **テストの実行**

テストを実行するには、ターミナルで次のコマンドを実行します。

```bash
bats calculator_test.bats
```

```
 ✓ 2 + 3は5に等しい 
 ✓ 5 - 2は3に等しい 

2 tests, 0 failures
```

Bats はテストを実行し、各テストケースの結果を表示します。このサンプルでは、**`calculator.sh`** スクリプトの **`add`** と **`subtract`** 関数が正しく動作することを確認するテストケースを含んでいます。

## **結論**

Bats を使用すると、Bash スクリプトのユニットテストを簡単に実行できます。テストはスクリプトの品質を向上させ、バグを早期に発見するのに役立ちます。ぜひ Bats を試して、Bash スクリプトの信頼性を高めましょう。

これで、Bats を使った Bash スクリプトのユニットテストについてのブログ記事の形式ができました。記事にはもちろん詳細な説明やスクリプトの詳細が必要ですが、この基本的な構造をベースに拡充していくことができます。
GitHubに100MBを超えたファイルをPushした時のエラー対策メモ

GitHubでUnityを使ってると**GH001: Large files detected. You may want to try Git Large File Storage**のエラーに出くわすことがあり、その度に「どうするんだっけ」となるのでメモがてらまとめておきます。

# 解決するまでの流れ
1. 「GH001: Large files detected. You may want to try Git Large File Storage」のエラーにぶつかる。
1. `git reset --soft HEAD^`や`git log` -> `git reset --soft コミット番号`を使って100MBを超えたファイルをcommitする前の状態まで戻る。
1. `git reset HEAD 100MBを超えたファイルのパス`で100MBを超えたファイルのaddを取り消す。[^1]
1. .gitignoreに100MBを超えたファイルのパスを書き込んで、今後追跡されないようにする。
1. `git add .`
1. `git commit -m "コミットメッセージ。"`
1. `git push`

<!--
<img width="50%" src="">
-->

# 中身
こちらのサイトを参考にしながら、流れを見ていきます。

https://murank.hatenadiary.org/entry/20110327/1301224770

## エラーにぶつかる前
エラーにぶつかる前のワーキングツリー、インデックス、HEADは次のようになっています。
![GitLFSエラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/fd88c55c-6a3d-4d65-e0ce-d1cf974ce512.png)

## 100MBを超えたファイルの追加
作業によって、ワーキングツリーに100MBを超えたファイルが含まれてしまいます。
![GitLFSエラー (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/af5c1c07-8a90-f102-cceb-6cda966f59da.png)



## git add & git commit
addとcommitをすると次のようになります。
![GitLFSエラー (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/7e63a67e-ac35-9ba1-17d5-82058c8089de.png)

## エラー発生
この状態でpushをすると、100MBを超えたファイルを含んだ状態でpushをすることになるので、エラーが出ます。
![GitLFSエラー (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/ce3d2c97-226d-5198-ae70-4015a69241a0.png)

## HEADを戻す
 `git reset --soft HEAD^`や`git log` -> `git reset --soft コミット番号`を使ってHEADを前回のcommit状態まで移動させることで、100MBを超えたファイルが含まれていない状態に戻します。
![GitLFSエラー (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/de936d57-5a4b-a325-7f68-3e7e3911a4d8.png)

## addを取り消す
`git reset HEAD 100MBを超えたファイルのパス`を使うことでHEADをHEADの位置（そのまま）に、インデックスをHEADの位置に移動させて**100MBを超えたファイルのaddだけ**取り消します。
![GitLFSエラー (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/bf5d3931-d044-4b55-b70b-364bf7ca09b7.png)

## .gitignoreに追記
.gitignoreに100MBを超えたファイルのパスを書き込むことで、今後100MBを超えたファイルの情報が追跡されないようにします。
![GitLFSエラー (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/b4e531a2-26c7-993c-caf4-a283d9c92892.png)

## git add
.gitignoreに100MBを超えるファイルを追加してからaddするので、100MBを超えるファイルを含んでいない状態になります。
![GitLFSエラー (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/8c798833-c2ff-311b-33b2-ce00a3bc3a70.png)

## git commit & git push
この状態であれば、commitしてpushしてもエラーは起きません。
![GitLFSエラー (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700137/ca71362f-0a19-42b2-9856-ac5d443227fb.png)

# 参考資料

https://qiita.com/kanaya/items/ad52f25da32cb5aa19e6

https://qiita.com/yukure/items/89562e5eb1d03995dc5b

[^1]: `git reset HEAD^ 100MBを超えたファイルのパス`を使えば2と3のプロセスを簡略化できそうですが、実際はエラーが解消されないので注意です。
Unreal EngineのLearning Agentsプラグインで車が自走するまで

UE5.3で搭載された機械学習プラグインであるLearning Agentsのチュートリアルを試してみました。

https://dev.epicgames.com/community/learning/tutorials/qj2O/unreal-engine-learning-to-drive

初学者として大変だったのは、機械学習が進んでいるのか見てもよくわからないことです。
チュートリアル通りに作ったはずがうまくいかず、フォーラムのやりとりを参考にチューニングする必要がありました。
その過程を紹介します。


## 学習過程の観察

学習過程はリアルタイムでレンダリングされるため目で確認できます。
Learning Agentsは以下の段階を踏んで運転を覚えていきました。

1. 直進
1. コースアウトしそうになったら減速
1. ハンドル操作

それぞれの段階をLearning Agentsが覚えると目に見えて車の動きが良くなりました。しかし、大部分の学習過程は見た目の変化はほとんどなく、本当に学習が行われているのか良くわかりません。

そこでログに出力される学習過程を確認すべく、Output Logを"avg"という文字列でフィルタリングします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66160/def99708-ff42-302b-1547-a7f4ac4918b4.png)

学習の過程を数字で確認できます。
Avg Reward、Avg Return、Avg Valueという３つの数値があり、これらが上昇することで学習が進んでいるとされます。
観察していると、これら数値が漸進的に上昇する傾向が確認できますが、逆に数値が大きく下降する場面もありました。数値が下がり始めたからといって間違った学習をしているということではないようで、後にちゃんと上昇に転じました。


## ハマりどころ

いくつかつまずきやすいと感じる点がありました。

### タイムアウト

Python側でタイムアウトが生じてしまうと、Unreal側でエラーが出力され、学習が停止してしまいます。
https://forums.unrealengine.com/t/learning-agents-fails/1281737/5
タイムアウトが生じさせないためには、Python側のタイムアウト値を上げるか、UnrealからPythonに頻繁にデータを送りこむ必要があります。

Unreal側で行えること
* 車の台数(Agent)を増やす
* MaxStepNumを減らす
* MaxEpisodeNumを調整


### 学習にとにかく時間を要する

数時間放置しても、アクセルを踏むことすらままならないことがありました。
この段階では設定間違いなのか、学習が進んでないのか、区別が困難です。
何度も実装を見直したり、フォーラムの情報を探すはめになりました。


## 最終的な設定

いくつかの設定でタイムアウトを起こさず、学習のスピードも上がったように見えました。
これら設定を行って一晩置いてみたところ、翌朝には運転を覚えていました。


### BP_RLTrainingManager の Tick を 0.01666とした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66160/4de98217-d6d8-5086-90cd-184c61b77810.png)

### Agentを倍に増やした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66160/adf488fe-89d3-5f48-87e8-913e954b70e1.png)
レベルに配置するSportsCar_Pawnも倍に増やしておく必要があります。

### Trainer Settings の調整
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66160/d1154613-e8b4-db70-31d3-d2721b353eee.png)
Max Step Num, Maximum Recorded Episodes Per Iteration, Maximum Recorded Steps Per Iterationを上のようにデフォルトより大きな値に設定しました。車が加速して走り出す前にイテレーションが打ち切られてしまっていたため、もっと走らせてあげようと思って設定しました。尚、コースアウトする車が多くでた場合はMax Step Numに達する前にイテレーションが打ち切られるようです。


## まとめと課題

自動車のチュートリアルはLearning Agentsの可能性を見るには良い題材でした。

一方、Learning Agentsを使いこなすには、Learning Agentsをチューニングしながら癖を把握していく必要があるでしょう。その意味では、結果を見るまで時間を要する自動車のチュートリアルは初学にはハードルが高いようにも感じました。

より短時間で結果にたどり着ける題材を見つけ、自前で一通り組んでみるのが早道かもしれません。