OmniAICreator/Qiita-1.07M huggingface dataset:
【Windows】ftp.exeは本当にPassiveモードで接続できないのか？(Windows Server 2022以外の場合)

:::note info
2024/09/15時点で元記事となっている[前回の記事](https://qiita.com/hidekko/items/b632fe0d55f5fa5bd0fc)の再検証を行いますので、それまでこちらの記事の内容は保留とします。
:::

:::note info
2024/09/15
再度検証しました。
検証のためにWindows Firewallの受信側でftp.exeを許可にしていたので通信できていました。
結局このWindows Firewallの受信側設定をデフォルトに戻す、つまりftp.exeの許可を削除したら通信ができなくなりました。
:::

[前回の記事](https://qiita.com/hidekko/items/b632fe0d55f5fa5bd0fc)の続きです。
前回の記事ではFTPクライアントがWindows Server 2022 Datacenter Editionでしたので、これより前のftp.exeでも試してみます。

# Windows Server 2019
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/b631bd67-ed4b-621e-682b-02bb8c8ca5a1.png)
はい。
アクセスできていますね。
サーバ側がPassiveモードで接続のみにしているので、接続できている時点でPassiveモードです。

# Windows Server 2016
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/b50baf44-b0c1-2b10-1414-ae986156dd5a.png)
はい。
これもアクセスできていますね。

# Windows Server 2012R2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/94eeaf76-3675-c4cd-afa9-af3f6794d8e6.png)
こちらもアクセスできてますね。

# Windows Server 2008R2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/c299d571-4ee5-6999-2477-b0f7a7b50f1a.png)
こちらもアクセスできています。

# Windows Server 2003R2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/d23d6822-cdee-2a07-726b-f4fed6060afa.png)
こちらもアクセスできています。

# Windows 2000
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/4262066d-3a7b-3e05-9d82-688eb8b27bb7.png)
はい。
まさかのWindows 2000でもアクセスできました。

# 結論、結局Windows OSネイティブのftp.exeがPassiveモードに対応していないという情報は何だったのか？
~~恐らくですがWindows Firewall(現在のWindows Defender Firewall)の許可設定ミスだったのではないかな？というのが個人の見解です。
ルーターやFirewallなどのネットワーク機器をFTPクライアントとFTPサーバ間で挟んでいる環境だと、それぞれのネットワーク機器の設定に依存するので複雑になりますが、今回FTPサーバとFTPクライアントを同じセグメントに配置しているので最も簡易なネットワークです。
単純にftp.exeがFTPクライアントとしてPassiveモードに対応していない、ということはどうも誤りのようです。
もちろん私の検証が不十分であったり、解釈が誤っていたりすることも考えられますので、何か疑問に思った方は是非コメントいただけると幸いです。~~

**<font color="red">Windows Firewallの受信側規則で許可設定を入れていたためPassiveモードで接続できていました。
結論、Windows OSのftp.exeはPassiveモードに対応していません！**

Windows Client OSもあるので、そちらも気が向いたら実施してみます。

本日はここまで。
Typescript　１　文と式　変数の宣言と使用

# 文と式の基本
```typescript
const greeting = "Hello, ";
const target = "world!";
console.log(greeting + target);
```

この文からわかるように、Typescriptの文は基本的にセミコロンで終わる。

次に、変数を文字を入れるときにはクォテーションマークが必要である。逆に、greetingやtargetは、greetingやtargetのような変数にはクォテーションマークは必要でない。

また、この文で多用されている「const 変数　＝　式」は、変数宣言をしている式だと考えることが出来る。

greetingというものに Hello,というものを代入されていて、targetというものにもworld!というものが代入されているのだ。このように文字や値が変数に入ることを代入と呼ぶ。

```出力
Hello,World!
```

このように、Typescriptというのは、式と式を演算子で繋ぐことが出来る。

また、この式の後にセミコロンがある文のことを式文と言って、与えられた式を実行するという役割がある。

式文は式を実行するためのもので最も基本的な文法といえる。

#  変数の宣言と利用
## 1.変数宣言の構文

```typescript
const 変数名 = 式;
```
これが変数宣言の基本形である。

```typescript
const greeting = "Good,";
const target = "Worldwide!";
console.log(greeting + target);
```
このプログラムでは、最初に変数greetingを作られる。

その変数に"Good,"という式の結果が代入される。

その後、targetという変数が作られる。その変数に式の結果が代入される。＝の後はどんな式でも良くて、
```typescript
const greeting = "Good,";
const target = "Worldwide!";
const text = greeting + target;
console.log(text);
```

```出力
Good,Worldwide!
```
こういった式でも構わないのだ。

変数宣言の別の形として、複数の変数の宣言を,で繋げることも可能である。
```typescript
const greeting = "Good,",
const target = "Worldwide!",
const text = greeting + target;
console.log(text);
```

ただ、この書き方はPrettierの普及やメンテナンスの観点により、あまり人気がない。最後をセミコロンで締める書き方が主流で、この,で締めるやり方は使わないほうがいい。

## 2.識別子
変数宣言の構文で変数名として使えるのは識別子だ。

変数名としてはどんなでたらめな文字列も使えるわけではなく、一定のルールがある。

識別子として、使える文字は決まっている。

半角アルファベット、ひらがな・カタカナ・漢字は識別子に使用可能だ。
```typescript
const あいう = 123;
const 技術評論 = あいう + 3454;
console.log(技術評論);
```
```出力
3577
```
どのような文字が識別子に利用可能かは、Unicodeという文字コードの企画で定義されている。
```typescript
const ! = 0;//構文エラー(!は識別子に使用できない)
const foo bar = 123;//構文エラー(空白は識別子に使用できない)
const if = 2423;//構文エラー(ifのような予約語は識別子に使用できない)
const const = 2423;//構文エラー(constのような予約語は識別子に使用できない)
 ```
このように、予約語や!、空白は識別子に使用できない。

一部の文字は、先頭以外の位置でのみ識別子につかることが出来る。

代表的なものは数字であり、例えば、foo1は識別子として使用できるが、1fooは識別子として使うことが出来ない。

識別子にはアルファベットの大文字・小文字は自由に使うことが出来る。ただ慣習として、変数名は小文字で始め、型名は大文字で始めることが多い。

## 　3.もう一つの関数宣言

もう一つの関数宣言としてletを使う方法があるが、letはコードの分かりやすさから極力使わないほうが良いので、ここでは説明を省略する。letとconstの違いは、再代入出来るかどうかで、基本的には同じなので、constを参考にして書けばいいと思う。
取引先紐づけ@VBA試作

```vba試作.txt
Option Explicit


Public Sub sample()


'プログラム2｜シート設定
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("取引先マスタ")
Set ws2 = ThisWorkbook.Worksheets("記入用")

'プログラム3｜各シートの最終行を取得
Dim cmax1 As Long, cmax2 As Long
cmax1 = ws1.Range("A65536").End(xlUp).Row
cmax2 = ws2.Range("A65536").End(xlUp).Row

'プログラム4｜データをリセット
 'ws2.Range("B5").ClearContents
 If Not cmax2 = 7 Then: ws2.Range("B8:D" & cmax2).ClearContents
 

    'プログラム6｜取引先を取得
    Dim torihiki As String
    torihiki = ws2.Range("B5").Value

 'プログラム7｜取引先が空欄か判定
Dim flag As Boolean ' BooleanのDefault値はFalse
    If torihiki = "" Then: flag = True

'プログラム8｜変数の初期化
Dim n As Long: n = 8
    
 'プログラム9｜条件に合致した行を抽出
Dim i As Long
For i = 2 To cmax1
    

        

    If flag = False Then
       If ws1.Range("A" & i) <> torihiki Then: GoTo Continue
    End If
    
    'プログラム10｜条件に合致した行のデータのみを対象して分析
    ws2.Range("B" & n & ":D" & n).Value = ws1.Range("A" & i & ":C" & i).Value
    n = n + 1
    
'プログラム11｜プログラム9で条件に合致しなかった場合、ここへジャンプ
Continue:
    Next
       
End Sub
AWS Network Firewall

# はじめに

この記事はAWS SAA試験勉強のための、AWS Network Firewallに関する知識のまとめです。


# AWS Network Firewallとは
VPC経由のネットワークトラフィックに対してファイアーウォールや侵入防止システムを提供するサービス。

# AWS Network Firewallの性質
Network Firewallは、VPC上のアウトバウンド及びインバウンド両方のトラフィックを検査できます。インターネット上の特定のドメイン名を含むURLへのアクセスのみを許可したり、特定の送信元からのトラフィック以外は全てブロックするなど、きめ細かな通信の制御が可能です。
MappedTypesについて調べてみた


# はじめに

Typescript MappedTypes の勉強メモ。
公式のドキュメントを自分なりにまとめたものです。

- https://typescriptbook.jp/reference/type-reuse/mapped-types
- https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

# Mapped Types

## 一言で

既存の型から新しい Object 型を定義する構文

## 構文

```tsx
type MappedTypes = {
  [P in T]: U
}
```

### **具体例**

Person のプロパティを Readonly にした型を作る

```tsx
type Person = {
  name: string
  age: string
}

// Mapped Types
type ReadonlyPerson1 = {
  readonly [K in keyof Person]: Person[K]
}

// ReadonlyPerson1と等しい
type ReadonlyPerson2 = {
  readonly name: string
  readonly age: string
}
```

:::note info
keyof を用いた反復処理と一緒に使われることが多い
:::

:::note warn
[Index 型](https://typescriptbook.jp/reference/values-types-variables/object/index-signature)とは明確に違う。
Index 型はプロパティ名を指定しない。MappedTypes はより厳密に定義したもの。

```tsx
type IndexSignature = {
  [K: string]: number
}
```

:::

</aside>

## 何が良いの?

- 既存の型から生成できるため、コードの重複を減らせる
- 厳密にプロパティ名を指定できるため型安全性が向上する

## 修飾子

### **readonly**

プロパティを読み取り専用に変換

```tsx
type Person = {
  name: string
  age: string
}

type ReadonlyPerson = {
  readonly [K in keyof Person]: Person[K]
}

// {
//    readonly name: string;
//    readonly age: string;
// }
```

### オプショナル

プロパティをオプショナルに変換

```tsx
type OptionalPerson = {
  [K in keyof Person]?: Person[K]
}

// {
//    name?: string | undefined;
//    age?: string | undefined;
// }
```

### マイナス

修飾子を消せる

```tsx
type RemoveReadonlyPerson = {
  -readonly [K in keyof ReadonlyPerson]: ReadonlyPerson[K]
}

// {
//    name: string;
//    age: string;
// }
```

### プラス

実は省略されていただけ

```tsx
type ReadonlyPerson = {
  readonly [K in keyof Person]: Person[K]
}

type PlusReadonlyPerson = {
  +readonly [K in keyof Person]: Person[K]
}

// {
//    readonly name: string;
//    readonly age: string;
// }
```

### `as` による再マッピング

キーを再マップできる

```tsx
type GetterPerson = {
  [K in keyof Person as `get${Capitalize<K>}`]: string
}

// {
//    getName: () => Person["name"];
//    getAge: () => Person["age"];
// }
```

## ⚠️ 注意

### プロパティを追加できない

```tsx
type PersonWithWeight = {
  [K in keyof Person]: Person[K]
  // ^ A mapped type may not declare properties or methods.
}
```

intersection を使う

```tsx
type PersonWithWeight = {
  [K in keyof Person]: Person[K]
} & { weight: number }
```

### Interface では使えない

理由は知らない。interface は素朴にオブジェクトを表現することに徹しているのかも。

```tsx
interface ReadonlyPerson {
  readonly [K in keyof Person]: Person[K]
}
```

## なぜこの名前?

どうやら Map は数学で”写像”を意味するらしい。
fyi: https://zenn.dev/axoloto210/articles/advent-calender-2023-day22

「なんすか写像って」ときかれた際は、Mapped Types のリンクを送ると平和になるかもしれない。
【Angular】Materialのmat-selectを共通化してみる

Angularは好きなんだけど、本音を言うとReactがいいなと思っている泉（[@izumin_0401](https://twitter.com/izumin_0401)）です。

# Angular Materialのプルダウンを共通化したい
ってことで、今回はmat-selectを共通化してみたンゴ。

## ブログ記事はこちら

https://traveler0401.com/angular-mat-select-common/

# ソースコード
## 共通mat-selectコンポーネント
```typescript:pull-down.component.ts
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';

interface Option {
  name: string;
  value: string;
}

@Component({
  selector: 'app-pull-down',
  standalone: true,
  imports: [CommonModule, MatFormFieldModule, MatSelectModule],
  template: `
    <mat-form-field [style.width]="width">
      <mat-select [(value)]="selected" (selectionChange)="change()">
        <mat-option *ngFor="let option of options" [value]="option.value">{{ option.name }}</mat-option>
      </mat-select>
    </mat-form-field>
  `,
})
export class PullDownComponent {
  @Input() width: string;
  @Input() selected!: string;
  @Input() options!: Option[];
  @Output() event = new EventEmitter<string>();

  change() {
    this.event.emit(this.selected);
  }
}
```

## 呼び出し側
```html:app.component.html
<app-pull-down
  [selected]="selectedIndex"
  [options]="[
    { name: '未選択', value: '-1' },
    { name: 'hoge1', value: '0' },
    { name: 'hoge2', value: '1' },
  ]"
  (event)="changePullDown($event)"
></app-pull-down>
```

もっといい書き方ありそうだけど、一旦これでいいかな...

# まとめ
Angular Materialの共通mat-selectコンポーネントを作ってみた。

「@angular/material」のimport箇所を減らせると嬉しくなるよね。

ではまた。

# 関連記事
https://qiita.com/izumin0401/items/c48bf6a7a4d03635a831

https://qiita.com/izumin0401/items/67c041f58d64dc03015b

# 最後に
暇つぶしに[Twitter](https://twitter.com/izumin_0401)と[ブログ](https://traveler0401.com/)もやってるので見てね。
CCNP Enterpriseを取得しました。

本日ENARSIに合格しました。先にENCORに合格していたため、CCNP Enterpriseとして認定されました。やったね。
<br>
<br>
<br>
<br>
<br>

まあ、想定より時間がかかってしまい自信をなくしたり~~あまりにも酷い日本語訳にブチギレたり~~しましたが合格したのでヨシとしましょう。
勉強方法については特に特別なことをしていないのでワザワザ書きません。
ただ、問題集だけで合格するのは厳しいと感じる難易度でした。大人しく検証環境を用意したほうがいいと思います。

## 試験結果
### ENCOR
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3768522/149c2c3f-1c05-58a8-6843-6b72f6d54f6e.png)

なんでこれで合格しているんですかね？
<br>
### ENARSI
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3768522/39142a74-4035-2fd1-2df3-1014f938582f.png)
L3 Technologiesの正答率がやや低いのが気になるけど他が高くてなんとか合格できたっぽい

## 勉強期間
### ENCOR
約5ヶ月(2023年5月2023～年9月)

### ENARSI
約10ヶ月(2023年10月～2024年7月)

## 勉強開始時点の筆者のスペック
### 保有資格
・ITパスポート
(CCNAは持っていません)

### IT業界歴
1年2ヶ月ほど
但し、最初の1年は技術に触れる機会の無いヘルプデスクの案件に参画していたため、インフラエンジニア歴でいうと2ヶ月ほどでしょうか。

## CCNPを受験した経緯
何故受験する資格としてCCNPを選択したかというと主に以下の理由からですが、主に以下の理由からです。
- インフラの分野(ネットワーク、サーバ、クラウド)のなかだとネットワークに興味があった
- 初級資格を複数個取得するより中級以上の資格を1つ取得したかった
- 22歳がCCNPを持っていたら面白いと思ったから
- 逆張りオタクだから
※ネットワークエンジニアの諸先輩方を逆張りオタクとする意図はありません。
<br>
順に記載していきます。

> インフラの分野(ネットワーク、サーバ、クラウド)の中だとネットワークに興味があった

読んで字の如くです。強いて言えばサーバとクラウドに関しては全く知識がないのに対し、ネットワークに関しては幼少期からネトゲをプレイしていたことで回線やポート開放などの知識があったことと、(挫折しましたが)以前にCCNAの勉強をしていたから他よりとっつきやすかったのかもしれません。
<br>

> 初級資格を複数個取得するより中級以上の資格を1つ取得したかった

広く浅く知識を身につけるより一旦は狭く深く知識を得たいと考えてこの方針としました。
結局この判断が正解だったのかはわかりませんが、当記事の執筆時点でネットワークに対する深い知識が要求されるもののサーバやクラウドに関する知識はそれほど要求されないような案件に参画しているので、今のところこの判断を下したことによる不都合などは生じていないです。多分。
<br>

> 22歳がCCNPを持っていたら面白いと思ったから

自分は学歴がないうえ、仕事に活かせるような一芸もなく、取柄といえば「若さ」だけなので自分の強みとなるような要素がほしいと思っていました。そこで安易に「**22歳がCCNPを持っていたら面白いのでは？**」と考えました。よく考えると資格だけ持っているペーパーホルダーにはなんの面白みもないし、20代前半のCCNPホルダーは探せば普通にいると気付いたのはENCOR合格後でした。~~ちなみにENARSIの合格までに時間がかかったので22歳のうちにCCNPホルダーにはなれませんでした。~~
<br>

> 逆張りオタクだから

時代はクラウド！と言われているのは理解していましたが、「**うるせえ俺はミーハーじゃねえんだ**」という逆張りオタク精神が働きました。余計なプライド(?)ですね、反省しています。

## これから
別にCCNPを取得したからといって一般無能エンジニアの自分が急に有能エンジニアに早変わりする訳ではないので、勉強は継続しようと思います。
ただ、何を勉強するかは決めていないんですよね。
無謀にもCCIEに挑戦するのか、あまりにもやる気の出ない応用情報の勉強をしてネスぺまで狙うのか、サーバやクラウドの方面の勉強をするのか、この3択ではあるのですが、どうしましょうかね？
なんであれ有能になれるようこれからも精進します。
コードレビューで意識すること

コードの理解
---
`目的の把握`: 変更がなぜ行われたのか、その背景や目的を理解する。
関連するチケットや仕様書を確認し、変更の意図を把握する。
`機能の確認`: 変更が既存の機能や他の部分に影響を与えないか、全体のフローを理解するためにコード全体の流れを確認する。

コーディング規約の遵守
---
`スタイルガイド`: プロジェクトごとに定められたコーディングスタイルガイドに従っているか確認。
インデント、命名規則、コメントの書き方など。
`リンター`: 自動化されたリンターを使用して、スタイルガイドに違反していないかをチェック。

テストの確認
---
`ユニットテスト`: 新しいコードや変更されたコードに対して、適切なユニットテストが書かれているか。
カバレッジ: テストカバレッジが十分かどうかを確認。
カバレッジツールを使用して、未テスト部分を特定。
`テストの実行`: テストが実際に実行され、全てパスしているか確認。

コードの可読性
---
`明確な命名`: 変数名、関数名、クラス名が意味を持ち、役割が明確であるか。
コメント: 必要に応じて適切なコメントが付けられているか。特に複雑なロジックや意図がわかりにくい部分。
`関数の分割`: 関数が適切な長さであり、一つの関数が一つの役割を持っているか。
長すぎる関数はリファクタリングの対象。

パフォーマンスと効率
---
`アルゴリズム`: 適切なアルゴリズムが使用されているか。計算量が無駄に大きくないか。
`リソース管理`: メモリやCPUリソースの無駄遣いがないか。
不要なオブジェクトの生成や過度なループがないか。

セキュリティの考慮
---
`入力のバリデーション`: ユーザーからの入力が適切にバリデーションされているか。SQLインジェクションやクロスサイトスクリプティング（XSS）に対する対策。
`認証と認可`: 適切な認証と認可が実装されているか。
アクセス制御が正しく行われているか。

スケーラビリティ
---
`拡張性`: コードが将来的な拡張や変更に耐えられる設計になっているか。依存関係が適切に管理されているか。
`モジュール化`: コードがモジュール化され、再利用可能なコンポーネントとして設計されているか。

エラーハンドリング
---
`例外処理`: 適切な例外処理が行われているか。例外がキャッチされ、適切な対応がなされているか。
エラーメッセージ: エラーメッセージがユーザーにとって理解しやすく、開発者にとってトラブルシューティングがしやすい情報を提供しているか。
依存関係の管理
`ライブラリの使用`: 使用されているライブラリが最新であり、セキュリティの問題がないか。
`バージョン管理`: ライブラリや依存関係のバージョンが適切に管理されているか。
バージョンの衝突や非互換性の問題がないか。

フィードバックの提供
---
`具体的なフィードバック`: フィードバックは具体的かつ建設的であるべきです。
改善点だけでなく、その理由や代替案も示すと良い。
ポジティブなポイント: 良い点も必ず指摘し、開発者のモチベーションを高める。
小さな変更に分割
`PRのサイズ`: プルリクエスト（PR）は小さく保ち、レビューしやすいサイズに分割する。
大きな変更は複数のPRに分ける。
`コミットメッセージ`: 各コミットメッセージが意味を持ち、変更の理由や内容が明確であるか。

ペアプログラミング
---
`リアルタイムレビュー`: ペアプログラミングにより、リアルタイムでコードをレビューし、即座にフィードバックを提供する。
`知識の共有`: 経験豊富な開発者がペアプログラミングを通じて、他のメンバーに知識を伝える機会を提供する。

自動化ツールの活用
---
`CI/CD`: 継続的インテグレーション/継続的デリバリー（CI/CD）パイプラインを使用して、コードの自動ビルド、テスト、デプロイを行う。
`静的解析`: 静的コード解析ツールを使用して、コードの品質やセキュリティの問題を自動的に検出。

フィードバックの記録
---
`コードレビューの履歴`: コードレビューのコメントやフィードバックを記録し、後で参照できるようにする。
これにより、同じ問題の再発を防ぐ。
`ドキュメンテーション`: フィードバックを元にドキュメントを更新し、ベストプラクティスを共有。

時間の確保
---
`スケジュール`: コードレビューに十分な時間を確保し、急いで行わない。
適切なスケジュールを設定し、レビューの質を保つ。
`優先順位`: 緊急度に応じてレビューの優先順位を設定し、重要な変更から先にレビューする。

チームの教育
---
`ワークショップ`: 定期的にワークショップを開催し、コードレビューのベストプラクティスを共有する。
`メンタリング`: 経験豊富な開発者が他のメンバーに対してメンタリングを行い、スキルアップをサポート。
ポジティブな文化の醸成
オープンなコミュニケーション: フィードバックをオープンに受け入れ、建設的な議論を促進する文化を育む。
`感謝の表現`: 良いコードや改善点に対して感謝の意を示し、チーム全体の士気を高める。
頭が悪くなるAIの使い方【実体験を元に】

近年、人工知能（AI）の急速な発展と普及に伴い、「AIを使うと頭が悪くなる」という懸念が聞かれるようになりました。しかし、この問題に対する根本的な考え方の違いについて、私なりの見解を述べたいと思います。
AIは頭を悪くするのか？
結論から言えば、AIを使うと頭が悪くなるとは思いません。問題は AIの使い方 にあると考えています。

# 実体験

私は趣味でもプログラミングをしています。もちろん最近はLLMを使ってプログラミングの殆どの部分をAIにまかせて書いています。
最初のプロトタイプ（例えば50行ぐらいのコード）であればAIは1発でうまくいくコードを書いてくれますが、あるラインを超えると、AIの出す結果に不良が混ざります。
それを取り除くために「こんなエラーが起きたよ。訂正して」とAIに伝えていました。それで、ほとんどうまくいくのですが、さらに別のラインを超えると、訂正をすると別の部分に影響が出てきたりして………
どんどんと収集がつかなくなっていきます。

しかし、最近は、そのような流れにも慣れてきたのでAIを使うプログラミングの感覚が少しづつつかめてきました（考えてみれば当たり前のことなのかもしれませんが）

# 良い使い方と悪い使い方
AIの使い方には、大きく分けて良い使い方と悪い使い方があります。


- 良い使い方：自分の理解を促進するためにAIを活用すること。つまり、AIを通じて新しい知識や視点を得ようとわかろうとする姿勢です。

- 悪い使い方：結果だけを求めてAIに頼りきってしまうこと。例えば、プログラムが動かないからといってAIに丸投げし、自分で考えることを放棄してしまうような態度です。

悪い使い方をすると、確かに成長の機会を逃し、深い理解を得ることができません。しかし、これはAI特有の問題ではありません。

# AIだけの問題ではない
実は、この問題はAIに限ったことではありません。例えば：

- 本を読む時
- インターネットで情報を調べる時

これらの場合も、同じような問題が起こり得ます。結果だけを求めて内容を深く理解しようとしないマネージャーがいるように、情報源の種類に関わらず、その使い方次第なのです。

# 重要なのは学習プロセス
重要なのは、情報を得てから自分の中に落とし込んでいく過程です。具体的には：

- 根拠となる情報を調べる
- その情報を批判的に検討する
- 自分の既存の知識と統合する
- 新しい理解や洞察を得る

このプロセスを大切にすれば、AIを使おうが使うまいが、知的成長は可能です。


# 結論
AIは単なるツールです。それを使って頭が良くなるか悪くなるかは、使う人次第です。AIを含む様々な情報源を、自分の理解を深めるための手段として活用することが大切です。そうすることで、AIは私たちの知的能力を拡張する強力な味方となるでしょう。
最後に、この記事はAIを使って作成しました。しかし、その骨子は私自身が感じ、考えていたことです。AIを導入する際によく聞く議論ですが、反対意見も含めてコメントなどいただけますと幸いです。
AtCoderで入茶した話

# AtCoderで入茶した話

## はじめに

今回は、私がAtCoderで茶色レーティング(400)を達成するまでに行った方法を紹介したいと思います。
本記事の対象はAtCoderをまだ始めたことが無い方や、茶色に達していない方を対象にしています。

#### 筆者のAtCoderアカウント
- https://atcoder.jp/users/kikudesuyo

## 筆者のスペック

- 大学が物理系で数学についての知識はそれなりにある
- 約2年間開発を行っていたものの、アルゴリズムや計算量については全く知識がない

## 現在の状況(2024/07/28)

![AtCoderレーティンググラフ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767231/78994984-af6e-cc10-732c-49513884121f.png)

## 茶色までの道のり

### 1. 初めてのAtCoder (2024/04/13)

- 癖のある問題文に翻弄された
- 標準入力、出力の方法がわからずWAの連発

### 2. B問題を目標 (2024/04/20~2024/05/18)

- 段々問題の癖になれてきた
- 入力方法、出力方法にも慣れた

### 3. C問題を目標 (2024/05/19~2024/06/02)

- とにかく間違えまくってもいいからC問題に食らいついた
- WAしまくったのでパフォーマンスが全然出ない

### 4. パフォーマンスを意識 (2024/06/02~2024/07/27)

- A,B問題を間違えずに素早く解くことを意識した
- また、C問題が6割くらいは解けるようになってきた

## 効果的だった取り組み

### 1. 過去問の演習

- 解いた問題の復習を行い、使用したアルゴリズムをメモした

### 2. コンテストへの参加

特別な予定がない限りコンテストに参加した。参加をしないと上がるチャンスすら逃してしまう。
(宅飲み会中に抜け出してコンテストに臨んだことも、、)

## あまり効果的ではなかった取り組み

### 1. D問題の演習
- D問題を何回か取り組んだが、時間が非常にかかるのとモチベーションが続かなかったため、現時点でやるべきではない気がした
- C問題が確実に解けるようになってから行うのが効果的だと思った


## おわりに
とにかく参加することで、実力はついてくると思います。モチベーションを切らさずにともに頑張りましょう!


私自身も、茶色に満足せず、年内に緑コーダーになれるように精進します。
緑コーダーになったら、またこんな感じで投稿したいと思います。
robots.txtを取得しクロール拒否されていないかチェック①

# 概要

robots.txtを取得しクロール拒否されていないかをチェックするプログラムをPHPで作成したいと思います。

今回は、robots.txtを取得する処理を作成します。
次回は、クロール拒否されていないかチェックする処理を作成します。


# 前提
## robots.txtとは

検索エンジンのクローラーなどに、アクセスしていいURLを伝えるファイルです。

クローラーを作成する場合は、robots.txtに準ずる必要があります。

## robots.txtの場所

基本的にURLドメインの`/`直下に置くことになっているので、Qiitaのrobots.txtは、`https://qiita.com/robots.txt`にあります。

中身の説明は次回とさせていただきます。


# コーディング

## 処理内容

プログラムは汎用的に作ろうと思うので、`robots.txt`を直接指定しなくても、どんなURLでもrobots.txtのURLに変換します。


このようなURLが指定された場合に、`robots.txt`のファイルのURLを生成します。
`https://example.com/`
`https://example.com/robots.txt`
`https://example.com/hoge/`
↓
`https://example.com/robots.txt`


## プログラム（PHP）

### robots.txtファイルのURLを生成する関数

```php
/**
 * 指定されたウェブサイトのrobots.txtファイルのURLを生成
 *
 * @param string $url ウェブサイトの元のURL。
 * @return string ウェブサイトのrobots.txtファイルを指すURL。
 */
function makeRobotsUrl($url) {
    return parse_url($url)['scheme'] ."://". parse_url($url)['host'] ."/robots.txt";
}
```

### robots.txtを取得する処理

```php
// GETパラメータの取得
$requestUrl = isset($_GET["url"]) && filter_var($_GET["url"], FILTER_VALIDATE_URL) ? $_GET["url"] : false;
if ($requestUrl === false) {
   exit("urlが指定されていません");
}

// robots.txtの取得
$robotsUrl = makeRobotsUrl($requestUrl);
$robotsTxt = @file_get_contents($robotsUrl);

// robots.txtの存在チェック
if ($robotsTxt === false) {
    exit("robots.txtがありません");
}
```

このコードでrobots.txtが取得できるようになりました。

# おわりに

簡単なプログラムですが、`robots.txt`を取得する処理を作成しました。次回は、`robots.txt`の内容の説明を含めクロール拒否されていないかチェックする処理を紹介したいと思います。

少しでも参考になれば幸いです。

ここまで読んでいただきありがとうございました！
オブジェクト指向3

##    はじめに

  __<font color="blue">　【オブジェクト指向】</font>を__ __<font color="blue">　【Java = ジャバ】</font>言語で考えてみました。__

##### 以下を参照。
https://qiita.com/nekoozi/items/d0e0cb616b45048143af

# <font color="blueviolet">スーパークラス</font>

継承元の親クラス

```java

/**
  * 「人」を表す Person クラス
  */

public class Person {

    private int age;
    private String name;

	public Person(int age, String name) {
		this.age = age;
		this.name = name;
	}

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

```


-------------
# <font color="blueviolet">サブクラス</font>

スーパークラスを継承している子クラス
```java

/**
  * 「従業員」を表す Employee クラス
  */

public class Employee extends Person {

  private int employeeID;

// コンストラクタの宣言
  public Employee(int age, String name, int employeeID) {

    /* 親クラスの age と name 引数のコンストラクタを呼び出す */
    super(age, name);
    // コンストラクタの宣言
    this.employeeID = employeeID;
  }


  // getterメソッド
  public int getEmployeeID() {
    return this.employeeID;
  }


  // setterメソッド
  public void setEmployeeID(int employeeID) {
    this.employeeID = employeeID;
    }


}

```


-------------
# <font color="blueviolet">インスタンス</font>
Employee クラスを利用するテストプログラム

```java

class EmployeeTest {
  public static void main(String[] args) {

    Employee p = new Employee(25, "田中 太郎", 111 );
    
    System.out.println(p.getAge()); // 25
    
    System.out.println(p.getName()); // 田中 太郎
    
    System.out.println(p.getEmployeeID()); // 111
    
  }

}
```


-------------
実行結果
````
25
田中 太郎
111
````
-------------

オブジェクト指向4

https://qiita.com/nekoozi/items/57b538a88579e78f71b3




## 参考文献

Java関連情報サイト様

https://java.keicode.com/


https://camp.trainocate.co.jp/magazine/java-super/
オブジェクト指向2

##    はじめに

  __<font color="blue">　【オブジェクト指向】</font>を__ __<font color="blue">　【Java = ジャバ】</font>言語で考えてみました。__

##### 以下を参照。
https://qiita.com/nekoozi/items/2cb1d0ed21fa8f12b652

# <font color="blueviolet">クラス</font>
```java
public class Person {

    private int age;
    private String name;


	// コンストラクタの宣言
    	/*  引数はなし   */
	public Person() {
        this.age = 11;
        this.name = "仮太郎";
	}

 
	// コンストラクタの宣言
	public Person(int age, String name) {
		this.age = age;
		this.name = name;
	}

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

```


-------------

# <font color="blueviolet">インスタンス</font>

コンストラクタを使用して、setterメソッドを使用してから、再度年齢と名前を出力

```java
class PersonTest {
  public static void main(String[] args) {


    Person man = new Person();
    //Personクラスを元にインスタンス化
    	/*  引数はなし   */

 
    System.out.println("初期化された年齢は " + man.getAge());
    System.out.println("初期化された名前は " + man.getName());
    
    man.setAge(27);
    man.setName("真太郎");
    // man の age と name をセット

    System.out.println("年齢は " + man.getAge());
    System.out.println("名前は " + man.getName());



    Person woman = new Person(28,"姫");
    System.out.println("年齢は " + woman.getAge());
    System.out.println("名前は " + woman.getName());
    
  }

}
```
-------------



-------------
実行結果
````
初期化された年齢は 11
初期化された名前は 仮太郎
年齢は 27
名前は 真太郎
年齢は 28
名前は 姫
````
-------------


オブジェクト指向3

https://qiita.com/nekoozi/items/ad5baf8c901e07af2b31



## 参考文献

Java関連情報サイト様

https://qiita.com/morioheisei/items/10c792a7a0b13ea8c045
[Node.js][nodebrew][Mac] nodebrewを使用してMacにNode.jsをインストールする

# 目次
- [Hoebrewでnodebrewをインストール](#homebrewでnodebrewをインストール)
- [nodebrewでNode.jsをインストール](##homebrewでnodebrewをインストール)

# Homebrewでnodebrewをインストール
1. brewでnodebrewを検索する
    ~~~sh
    brew search nodebrew
    ~~~
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/2a1e3afd-2138-aa7c-b477-25eeacde16be.png)

1. インストールする
    ~~~sh
    brew install nodebrew
    ~~~

1. セットアップを行う
    ~~~sh
    nodebrew setup
    ~~~

    PATH情報が出力される。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/e92f4c86-a0a7-0c12-b67b-82fb3c8eb7b1.png)

1. PATH情報を.zshrc (bashを使用している場合は、.bash_profile）に追記する。
    ~~~sh
    echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zshrc
    ~~~

1. `source`コマンドを使用して変更を反映させる。
    ~~~sh
    source .zshrc
    ~~~

# nodebrewでNode.jsをインストール
1. インストール可能なnode.js(npm)のバージョンを確認する
    ~~~sh
    nodebrew ls-remote
    ~~~

1. インストールする
    ~~~sh
    // バージョンを指定したインストール
    nodebrew install v16.16.0
    
    // 最新版をインストール
    nodebrew install latest
    
    // 安定版をインストール
    nodebrew install stable
    ~~~

1. 正常にインストールされているか確認
    ~~~sh
    nodebrew list
    ~~~
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/a2d64ae7-6981-f112-2c79-48c91b3d148c.png)


1. Node.jsはインストールされただけで有効化されていないため、以下コマンドにて有効化
    ~~~
    nodebrew use v22.5.1
    ~~~

1. Node.js(npm)の動作を確認
    ~~~sh
    node -v
    npm -v
    ~~~

# 参考リンク
- [macにnode.js（npm）をインストールするならnodebrewがおすすめ](https://fromscratch-y.work/blog/programming/mac-nodejs-install/#sec2-2)
- [【Mac用】nodebrewを使ってNode.jsをインストールする方法](https://ensei1375.com/nodejs-install/)
- [sourceコマンドについて詳しくまとめました 【Linuxコマンド集】](https://eng-entrance.com/linux-command-source)
最速でAnsible-Playbookの実行環境をDockerで作成する

## 最初に
今回はDockerのコンテナを使って最速でAnsible-Playbookの実行環境の構築する手順を紹介します。
前提として、Dockerデスクトップをインストールしておいてください。

## コンテナを作成
Dockerの入っている環境内(CMD)で下記コマンドを入力してコンテナを作ってください。
コンテナ名は任意の名前に変更してください。`your-contaner-name`

```
docker run -it --name your-contaner-name ubuntu:latest bash
```

## Ansibleをインストール
作成出来たらコンテナのシェルに入ります。
```
docker exec -it your-contaner-name /bin/bash
```
下記コマンドで依存関係をインストールします。
```
apt update
```
```
apt install ansible -y
```

全て正常に実行出来たら下記コマンドで導入を確認します。
```
ansible --version
```

これでAnsible-Playbookを起動する環境が完成しました。
## 動作確認
Ansible-Playbookでは様々なことができます。
[Ansibleについて詳しく説明しているサイト](https://zenn.dev/y_mrok/books/ansible-no-tsukaikata)
Ansible-Playbookの一番の特徴は<font color="rgb(0, 0, 0)">**冪等性**</font>という同じ操作を何度繰り返しても結果が同じになる性質です。

例えば下記のようなコードの場合は何回実行しても同じテキストファイルが生成されます。
- コンテナ内の`/root`に下記の内容のymlをコピーしてください
```test.yml
---
- name: Test Ansible Playbook
  hosts: localhost
  tasks:
    - name: Write "Hello, World!" to the file
      ansible.builtin.copy:
        dest: /tmp/test.txt
        content: "Hello, World!"
```

- `/root`に`test.yml`がある状態でコンテナのシェルに下記コマンドを実行してください
```
ansible-playbook -i localhost, -c local /root/test.yml
```
これで`/tmp`に`text.txt`が生成されます。

## 最後に
この例ではとても単純な操作を紹介していますがansible-playbookでは鍵登録やユーザー登録など、もっとインフラ寄りなセットアップをすることができます。
機会があれば参考にしてみてください。
ありがとうございました。

参考->https://zenn.dev/y_mrok/books/ansible-no-tsukaikata
【React】Reactで学習記録アプリを作ってみた

# はじめに
私は現在、JISOUというコミュニティでReactの学習をしています。エンジニア歴は4年になりますが、普段はWeb制作を行っていてアプリ制作は素人になります。今回は、学習の過程で制作した学習記録アプリについて紹介します。

# 制作したもの
今回制作したものは学習記録アプリになります。基本的には、Todoアプリに機能を追加したようなものになっています。スタイリングはしていないので非常にシンプルな構造になっています。

![chrome-capture-2024-7-28.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835217/9b481087-64a1-fd20-6b46-ea44eb89d107.gif)

# 気がついたこと
ReactはJavaScriptのライブラリです。JavaScriptの基本的な内容が分かっていないと学習効率が全く変わってくると感じました。私は以前、別のプログラミングスクールに通っていました。約4ヶ月ほど学習しましたがTodoアプリをまともに作れるかどうかのレベルにしか到達できませんでした。当時はカリキュラム通りに進めれば、Reactが習得できると考えていました。今思えば、自分でUdemyや書籍で基礎学習はしておくべきだったかもしれません。JISOUではカリキュラムの中で、Udemyを使用した基礎学習が含まれていました。私が以前と比べ大きく違いを感じたのはこの部分です。

__穴の空いたバケツにはいくら水を入れても溜まることはありません__。それが高級な水であっても一緒です。プログラミング学習に限った話ではないですが、何事においても基礎は大事だと改めて感じました。

# JISOUのメンバー募集中
プログラミングコーチングJISOUではメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？

気になる方はぜひHPからライン登録お願いします👇

https://projisou.jp
Meta-Llama-3.1-8Bは「แม่อย่าเก็บไว้คนเดียว」をどうトークナイズするのか

「[Meta-Llama-3.1-8B](https://huggingface.co/meta-llama/Meta-Llama-3.1-8B)」がリリースされたのだが、サポートしている言語が英語・ドイツ語・フランス語・イタリア語・ポルトガル語・ヒンディー語・スペイン語・タイ語の8つで、日本語は含まれていない。それならば、まずはタイ語のトークナイザを試してみよう。

```
>>> from transformers import AutoTokenizer
>>> tkz=AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3.1-8B",token="hf_this_token_is_dummy_use_your_own_one")
>>> print(tkz.convert_ids_to_tokens(tkz("แม่อย่าเก็บไว้คนเดียว")["input_ids"]))
['
', 'à¹ģà¸¡', 'à¹Īà¸Ńà¸¢', 'à¹Īà¸²', 'à¹Ģà¸ģ', 'à¹ĩà¸ļ', 'à¹Ħà¸§', 'à¹ī', 'à¸Ħà¸Ļ', 'à¹Ģà¸Ķ', 'à¸µà¸¢à¸§']
```

「[แม่อย่าเก็บไว้คนเดียว](https://qiita.com/KoichiYasuoka/items/851bbe0299f43c7eb4e9)」をトークナイズしてみたが、どうもマズイ気がする。`decode`してみよう。

```
>>> for t in tkz("แม่อย่าเก็บไว้คนเดียว")["input_ids"]:
...   print(" ",tkz.decode(t))
...
  

  แม
  ่อย
  ่า
  เก
  ็บ
  ไว
  ้
  คน
  เด
  ียว
```

単語の切れ目が「แม่」「อย่า」「เก็บ」「ไว้」「คน」「เดียว」になっていない。マトモに切れているのは「คน」くらいで、残りはボロボロだ。タイ文字クラスター(คลัสเตอร์อักษรไทย)すら、完全に無視してトークナイズしている。うーん、これでどうやってタイ語を処理すればいいんだろ。
Flutterのマテリアル構造とレイアウト ~Statefulウィジェット~ 

https://flutter.ctrnost.com/tutorial/tutorial05/

### [Statefulウィジェット](https://flutter.ctrnost.com/tutorial/tutorial05/)

#### スクリプトが実行される流れ
1. `RandomWords` ウィジェットが作成されます
1. `RandomWords` の `createState()` メソッドが呼び出されます
1. `createState()` メソッド内で、`new RandomWordsState()` によって `RandomWordsState` のインスタンスが生成され、返されます
1. 生成された `RandomWordsState` オブジェクトが `RandomWords` ウィジェットに関連付けられます
1. `RandomWordsState` の `build()` メソッドが呼び出され、`WordPair.random()` でランダムな単語ペアが生成され、テキストウィジェットとして表示されます

#### より簡単に書いた流れ
`RandomWords()` を呼び出すと `RandomWords` ウィジェットが返され、そのウィジェットが内部で `RandomWordsState` を生成し、`RandomWordsState` の `build` メソッドが `Text` ウィジェットを返す。

`class RandomWordsState extends State<RandomWords> { ... }` は、確かにクラスの定義構文ですが、Flutterの文脈においては、単なるクラス定義以上の意味を持ちます。
`<RandomWords>` というジェネリクス型パラメータを使用することで、`RandomWordsState` クラスが `RandomWords` ウィジェットの状態を管理することを明示的に示しています。
(`State<RandomWords>` の `<RandomWords>` の部分は、特定のウィジェットに特化した状態管理クラスを作るための指示だと考えた)
つまり、`RandomWordsState`クラスは`RandomWords`ウィジットの状態を管理するクラスということ

```dart
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) { 
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(appBar: AppBar(
        title: RandomWords(),
      ),
      body: Center(
        // RandomWordsクラス(Widget)を呼び出す
        child: RandomWords(),
      ),
      )
    );
  }
}

// StatefulWidgetを継承するRandomWordsクラス(Widget)を作成
class RandomWords extends StatefulWidget {
  @override
  // RandomWordsStateクラスのインスタンスを返す
  RandomWordsState createState() => RandomWordsState();
}

// createState()で返されるRandomWordsStateクラスを定義する
class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    // Textクラスのインスタンスを返す
    // 引数はランダムな英単語を生成するWordPairクラスのasPascalCaseプロパティ
    return Text(wordPair.asPascalCase);
  }
}


```
Google スプレッドシートの設定シートの初期値を Apps Script からパフォーマンスよく読み取る方法

## Google スプレッドシートの設定シートの初期値を Apps Script からパフォーマンスよく読み取る方法

### ⬛︎背景
多数のスプレッドシートと連携する　Apps Script を記述してきています。
Apps Script の定数をコード上にハードコードすると、ちょっとした変更をする際にコードを変更する必要があることを煩わしく感じ、「設定」シートに定数を書き込んでおき、それを利用するようにしています。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2533932/757ef571-7db2-9b38-7645-3226849c2808.png">

下記の様に「設定」シートのアドレスを指定して値を読むような方法を取っていました。

```
let ss = SpreadsheetApp.getActiveSpreadsheet()
let sh = ss.getSheetByName('設定')
let var1 = sh.getRange('B2').getValue()
Logger.log(var1)
```

しかし、この方法には欠点がいくつかあります。

a) 固定アドレス B2 で指定しているため、「設定」シートの行を並べ替えたり、行を挿入すると変更が煩わしい
b)  変数名「変数の名前１」から、abc　を取得していることがわかりにくい

これをどのように使いやすくするかを検討してみました。

### ⬛︎改善案１：　連想配列に格納してしまう
変数をひとつひとつ getValue で読む代わりに、getValues で A2:B で全ての行を読み、global 変数の連想配列に格納してみました。

```
let settings={}
function initSettings() {
  let ss = SpreadsheetApp.getActiveSpreadsheet()
  let sh = ss.getSheetByName('設定')
  let vars = sh.getRange('A2:B').getValues()
  vars=vars.filter((a)=>{ 
    if(a[0]!='') {settings[a[0]]=a[1]}
    return(a[0]!='')}
  )
}
initSettings()

function myFunction() {
  Logger.log(settings["変数の名前１"])
}
```

変数名を指定して、`settings["変数の名前１"]` のようにすれば、abc の値が取得できます。行の並びが変わっても変数名を変更しなければ、問題なくなりました。
しかし、(a), (b)の問題点は解決できたのですが、この方式だと、Apps Script の実行時に常に「設定」シートを読み込むために initSettings が呼ばれてしまいパフォーマンスが大きく落ちてしまうと思われます。
例えば、onEdit トリガーを使って、スプレッドシートが編集されるたびに、initSettings が実行されてしまうため改善したいところです。

### ⬛︎改善案2：　CacheService を利用してみた。（ついでに Class 化）
連想配列を使うアイデアはそのままにして、「設定」シートから読み込んだ値を CacheService を使いメモリ上に保管します。また、Utilities のようにClass 化して、使いやすくしてみました。

値の取得は `SettingsApp.values('変数の名前１')`で行えます。
「設定」シートを読み込んだ後、900秒(15分)以降に SettingsApp.values を使う際には自動で「設定」シートが再読み込みされます。「設定」シートのデータが変更した場合は、`SettingsApp.refresh()` を実行してキャッシュを再読み込みしてください。

トリガーなどで、SettingsApp.values を使っていない場合は、初期化は発生せず、使う時に必要に応じて再読み込みをする形で実現しました。 


```
/**
 * SettingsApp 
 * 「設定」シートの A 列に変数名、B列に値　を格納しておくけば、SettingsApp.values["変数名"] で値を参照できます。
 * 毎回、「設定」シートを読み込まず、15分に一度「設定」シートを読み込みます。
 */
let SettingsApp=new class{
  constructor(){
    let value=CacheService.getDocumentCache().get("settings")
    try{
      this.values=JSON.parse(value)
    } catch(ex){
      value=null;
    }    
    if(value==null){
      this.refresh()
    }
  }
  refresh(){
      let ss = SpreadsheetApp.getActiveSpreadsheet()
      let sh = ss.getSheetByName('設定')
      let data=sh.getRange("A1:B").getValues()
      this.values={}
      data=data.filter((a)=>{
        if(a[0]!='') this.values[a[0]]=a[1]
        return(a[0]!='')
      })
      // 900 秒間キャッシュを有効にします。
      CacheService.getDocumentCache().put("settings",JSON.stringify(this.values),900)
      Logger.log('Init')
  }
}()

function myFunction() {
  Logger.log(SettingsApp.values["変数の名前１"])
}
```
エンジニアのスキルシートがゲームみたいでかっこよかったので自分で自己紹介サイトを作ってみた

# イントロダクション
エンジニアとしてのキャリアを考え始めたとき、他のエンジニアの「TypeScript★★★、AWS★★」、みたいな、スキルシートを見て「かっこいい」と感じて、まず、今まで学んだHTMLとCSSの知識のアウトプットにもなるし、これから作る作品などもサイトでわかるようにしたいと思い、自己紹介サイトを作ることを決意しました。

# これまで学習してきたこと
### Progate
WEB開発コースでJavaScriptのコースとHTMLとCSSのコースを全部やってNode.jsまでやりました。（Node.jsは意味不明なまま言われるがままやっていた）

### Udemy
https://www.udemy.com/course/html-css-js/?couponCode=KEEPLEARNING

まず、実践的なHTMLとCSSの知識をつけたくてこのコースを受けました。

https://www.udemy.com/course/learn-basics-of-javascript/?couponCode=KEEPLEARNING

JavaScriptの知識が足りないと思って、受けましたが、学んだことがあるものばかりであまり意味がなかったです。ですが、丁寧な解説だったので構文の理解力があがりました。

### 自己紹介サイト作成後（一ヶ月くらい前に作り終わった）
### Progate
Reactのコース(楽しかった)とNode.jsのコースを全部やりました。

### Udemy

https://www.udemy.com/course/react-complete-guide/?couponCode=KEEPLEARNING

Reactを実践的に学びたいと思い受講。おすすめです。

https://www.udemy.com/course/nodejs-comp-guide/?couponCode=KEEPLEARNING

WEBアプリ制作に向けて受講中（7月28日）。Reactの講座でNode.jsを扱っていたのでスムーズに受けられている気がする。

# 準備と計画
JavaScriptも使って作成する気だったのですが、自分が作ろうと思っているデザインが結構シンプルで私の知識不足もあり、HTMLとCSSのみでよくねってなってHTMLとCSSのみで作成しました。Udemyの講座でBootstrapの使い方は学んでいましたが、その頃、YouTubeでエンジニア面談みたいなので「Bootstrap使ったら誰でも作れるでしょ」みたいなのを見てBootstrap使わないでつくるかーってなって作り始めてしまいました。（その後、使えばよかったと後悔する）ワイヤーフレームを作成しようとFigmaを使ってみるがむずくて断念。Pinterestなどでデザインを参考にして作成。

# 学んだこと、工夫したこと
ヘッダーのリストにa hrefを付けて任意の場所に飛べるようにすること。
ヘッダーを透けすようなデザインにした。
Font Awesomeの使い方
Githubで静的サイトの公開方法（作って満足してしまい、公開するのを忘れていた）
作り終えてコードがきたないことに気づき、チャットGPTと対話しながらきれいにした。
このくらいですかね。あとは、講座を見返したりして作ってました。

https://github.com/yuta-shacho/my.site

# 終わりに
シンプルなサイトだからなのか慣れてきたからなのか割と時間がかからなかったです。大学で作ってて友人に「これ自分で作ったの！すごいじゃん」と言ってもらってエンジニアのやりがいってこうゆうことなのかとか思ったり。始めて自分で作った作品でしたが、今思うと結構熱中して夢中で作ってました。作りたいと思うものがいっぱいあるのでそれを実現できるように勉強頑張ります。
長文レポート作成に特化したLLMツール「GPT-Researcher」を紹介します

最近、結構使いやすい長文生成に特化されたLLMツール（gpt-researcher）を発見しました。業界調査レポートなどの作成には活用できるかと思い、皆さんにも共有します。

gpt-researcherが特化されたユースケース⇩

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/2345887c-2e7b-e9d8-d761-67a4c3fd13b7.png)

# 1.使用方法：
gpt-researcherの使い方はとてもシンプルです。まずライブラリをインストールし、サンプルコードを実行するだけで使えます。

ライブラリのインストール⇩
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/cdb6813b-40b5-f4e0-35c0-e196206de6fb.png)

注意点として、デフォルトでは最小のトークン数に設定されているため、トークン制限を超えてしまうことがよくあります。そのため、トークン制限数の調整が必要です。調整方法については、公式ドキュメントのカスタマイズセクションに詳しく書いてあります：⇒https://docs.gptr.dev/docs/gpt-researcher/config）

試しに「2024年のAI動向レポートを作成してください」と質問してみました。
すると、agentが動き始め、まずいくつかのキーワードを生成します。そして、それらのキーワードを使って検索を行い、関連するウェブサイトを探し出します。⇩

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/83dea125-c0bd-42a2-8bd5-edc1bb4fa250.png)

次に、検索結果の整理と要約を行います⇩
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/13265038-00b4-7528-b4c7-c2b764f6bd51.png)

最後、整理された情報を基にレポートを生成します。生成されたレポートは以下の通りです（Markdown形式に変換しています）↓
出力された内容を見る限り、特に問題はなさそうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/1ed82d38-c914-4b0c-11bd-de8dcdfbd809.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/91129460-3b4e-4a87-420b-0811d0e28eda.png)

もう一つ、「日立の調査レポートを作成してください」という質問も試してみました。
結果は以下の通りです。⇩

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/c2ae282d-3aa0-f31e-3cfa-1f507e2c3f76.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/a3117689-d47f-3f15-be24-683b51513121.png)

興味ある方試してみてください：

https://gptr.dev/
継承の問題点に関して（良いコード悪いコードで学ぶ設計入門のsection8を読んで）

## 目的
エンジニア2年目で、コードの共通化に関して悩み始めたため、勉強し始めた。

## 背景
前回、密結合に関して記事を書いたが、継承にも問題点が多いらしいため、継承についてシンプルに記載したい。

## 本文
### 継承の問題点
・スーパークラスを変更すると、サブクラスに影響が出る。
・スーパークラスはサブクラスのことを考えずに変更しがち。
・サブクラスがスーパークラスのメソッドを使用できるようになるため、共通ロジック置き場になりやすい。

#### 思い当たる例
・基底クラスとサブクラスがある時に、基底クラスのメソッドをオーバーライドして、得たい機能を実現していく。
・しかし、オーバーライド実装には、基底クラス側のロジックを知っていないとできない。
・このように関連知識が基底と継承それぞれに分離しているものは、良い設計とは言えないとこのこと。

## 改善方法
・下手に継承を使わず、単一責任原則を重要にすること
・値オブジェクト、コンポジション構造で設計できないか検討すること。

## 次のアクション
何が問題で何が正解なのか、知らない知識が多い。
とりあえず、わからない時にどこを見たら正解か、どんなやり方があるのかの検討をつけられるようにしたい。
Qiitaで文字に上付き文字を付ける

Qiitaで記事を書く際に、引用文献の番号を上付き文字で挿入することは、マークダウンの標準機能だけでは直接サポートされていません。しかし、HTMLタグを使うことで、Qiitaの記事内に上付き文字を作成することができます。これを利用して引用文献の番号を表記することが可能です。

例えば、文中で引用を行いたい場合には以下のように書くことができます。

```c:sample.c
これはサンプルテキストです。ここで重要なポイントを紹介します<sup>(1)</sup>。
```

これはサンプルテキストです。ここで重要なポイントを紹介します<sup>(1)</sup>。
アウトプット学習を1ヶ月続けた結果

# はじめに

JISOUでアウトプットを中心とした学習をし始めてちょうど1ヶ月が経ったので振り返ってみたいと思います。

# この1ヶ月の振り返り

### やったこと

- Udemyでインプット（2つの動画）
- React + Viteで学習記録アプリを作成
- TypescriptでTodoアプリをハンズオン学習
- Typescript+React+Viteで学習記録アプリをさらにアップデート
- Qiita記事投稿(この記事を入れて16本）

文字に書いてみるとシンプルなのですが、アプリ作成をするときはいつもいろいろな壁にぶつかります。

その時々に考えたことを共有したいと思います。

# エラー続きで絶望

最初に学習アプリを作り始めたときは、初めて自動デプロイを設定する時エラーが出て理由がわからずやみくもにAIに聞きながらエラーを解消しようとしていました。それでも1日中朝から晩までずっと時間を使ってもエラーが解消されないときに「なんで自分はこんなことをしているんだろう」とか「もう投げ出してしまいたい！」という超ネガティブな思考に入ってしまうこともありました。

けれど、同時に「ここで投げ出したらこの先もスキルが身に付かず今のままだ」という考えが何度も頭によぎり、うんざりするときもありつつあの手この手でエラー解消を続けました。

そうして試行錯誤した末にエラーが解消されたとき、信じられないほど嬉しかったことを覚えています。

その後別のアプリを作成したときに、前回と同じ作業をしたときにサクサクエラー解消が進んでいくことに気づいて、経験や知識がついて成長している実感を持つこともできました。また、あらかじめ環境構築している時とかにも「この部分がないとエラーになる」部分を時間をかけず見つけられるようになっていました。

# アウトプットの継続は大変

アウトプット学習は正直しんどいです。基礎部分のインプットをサクッと済ませてすぐに実践に入ります。そして実践しながらわからない部分は調べてインプットしたらその部分をQiita記事にしてアウトプットしています。

こういう学習方法は能動的に自分で進めていかなければならず、気が乗らないときはやらなくなりがちになります。だからこそ多くの人がアウトプット避けてしまいがちになるし、いつまでもインプット学習に甘んじてしまうのかなと思います。私がまさにそういうタイプで、実際に手を動かして何か作ることを避けていました。

今もアウトプットを続けるのが大変に感じる時もありますが、それでもできるだけ毎日少しでも進めるように心がけています。

時間の使い方としては、エンジニアとしてフルタイムの仕事もあるので平日に学習できない時もありますが、なるべく15分〜30分でも時間があればアプリ作成に時間を使うようにしています。また、エラーの理由などは電車内で検索してストックしておき家に帰ってから試すようにするとすんなり解決する時もあります。

# 1ヶ月やり続けて得た効果

まだ1ヶ月とはいえ、1ヶ月アウトプット学習をやり続けた効果はすごいと感じています。

例えば上記にも書いたようにインプット学習ではあまり出会わないエラーがたくさん出ます。Udemyなどのインプットでハンズオンしている時は、エラー解消法を講師が解説してくれていたり、Q&Aで講師に質問できるのであまり大変な思いをすることがないです。

でも一人でアプリを作ると誰も経験してないような謎のエラーが出て調べてもすぐに解決できないことがあります。そういったエラーをコンソール出力などでデバッグしつつ、ロジカルに考えながら解消していく力をこの1ヶ月で少し身につけられたように思います。

また、アプリを作成するハードルが一気に下がったように感じています。今はJISOUのカリキュラムに沿って作成していますが、「こういう風に段階的に作ればいいんだ」というアプリの手順を知ることができました。また、実装方法も自分なりのレシピが形成されていくので、他のアプリを作ろうと思った時にすぐにレシピを取り出して使えるようになりました。

# アウトプット学習は継続

今はまだ1ヶ月目なので簡単なアプリ作成でも時間がかかってしまうレベルでまだまだ学ぶことがあります。これからも今のペースでアプトプットを続けて、より多くの技術に触れていきたいと考えています。
また2ヶ月たった頃に記事を書く予定です。
最後まで読んでいただきありがとうございました。

# JISOUのメンバー募集中！

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
実践的なカリキュラムで、あなたのエンジニアとしてのキャリアを最短で飛躍させましょう！
興味のある方は、ぜひホームページからお気軽にカウンセリングをお申し込みください！
▼▼▼

https://projisou.jp/
【React+Typescript+Vite】 学習アプリを作成

# はじめに

以前こちらの記事で紹介した学習記録アプリをTypescriptを使用してつくりかえてみました。

前回はシンプルなCSSを当てているのみでしたが、今回はChakra UIを使用してより機能的に使えるようにしました。

# 作成したアプリ
![video.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825671/ce42bf1e-a5c7-b28e-bffe-9089b06bb1ae.gif)

### 概要
学習した時間や学習した内容を簡単に記録できるアプリ

### 使用言語・ライブラリ
Typescript, React

### DB
Supabase

### テスト
Jest
React-testing-library

### その他
Firebase
Github

# 実装機能

「登録する」ボタンを押すと、モーダルが表示されて学習内容と学習時間を入力できます。
![スクリーンショット 2024-07-27 9.37.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825671/2664c347-d9b1-ea46-1c91-37bf97c73fd3.png)


入力した内容が、画面右側に即時追加されます。
![スクリーンショット 2024-07-27 9.30.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825671/3e663684-ee52-bff1-55c1-0c2e40502c61.png)


削除ボタンを押すと、該当のデータを一つ表から削除できます。
![スクリーンショット 2024-07-27 9.31.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825671/7743e07f-63a0-d185-6c0f-73bb7fed4024.png)


編集ボタンを押すと、モーダルが開いて学習内容と学習時間を編集できます。
![スクリーンショット 2024-07-27 9.31.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825671/b2e5e900-eec2-3ee5-bb88-b57d85328db8.png)

モーダルの入力がない場合は、エラーメッセージが表示されます。
![スクリーンショット 2024-07-27 9.36.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825671/eb3e15f8-419c-bec7-c0c2-81eb638f651b.png)



画面にあるライトモードでダークモードとの切り替えが可能です。
![スクリーンショット 2024-07-27 9.31.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825671/871f114a-c45b-49ff-64c7-f417a93f8b71.png)


# 難しかったこと
今回react-hook-formを利用して、学習内容や時間の登録時に入力がないとエラーが出るようにしています。
ただ、初めて利用するものだったので仕組みを理解するまでに時間がかかりました。
特に「登録する」ボタンを押してから、モーダルが開いた後にすでにエラーが入力画面に表示されていたり、入力をしてもエラーが消えなかったりといろいろなパターンを経験しました。
最終的にはonChangeで入力された値をsetValue関数で更新することで、入力があった場合のエラーを消すことに成功しました。

# 感想
前回初めて作った時とは違い、テストやGithubActionsを使用したデプロイの作業に少しずつ慣れて、作業が大変だと思うことが少なかったです。
また、今回はChakra UIで見やすいUIを作ろうといろいろ試すことができたこともいい経験ができたと思います。自分の思う通りに部品を配置させるのは案外難しく感じましたが、今後もいろいろ作っていく中で慣れていきたいです。
実際に動くものを作ってみることで、自分がどこを理解していてどこがまだ曖昧な理解なのかというのがすぐわかるので今後もアウトプットを続けていきます。

# 今回学べたこと
今回のアプリ作成で以下を特に学べたと感じるので書いておきます。

- Chakra UIを使用したアプリ作成の方法
- react-testing-libraryのgetByAllやfindByAllの違い、waitForとactの違いなど
- モックを使ってテストをする方法
- react-hook-formの使い方
- Typescriptでクラスを作成し使用する方法
- 環境構築でのtsconfingやtsconfig.appなどの違い

# さいごに
アプリ作成を続けていることでエラーやバグなどの問題が生じても動じないようになってきました。今は何かを作っていくことが楽しいので、これからもどんどん作っていこうと思います。
最後まで読んでいただきありがとうございました！

# JISOUのメンバー募集中！

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
実践的なカリキュラムで、あなたのエンジニアとしてのキャリアを最短で飛躍させましょう！
興味のある方は、ぜひホームページからお気軽にカウンセリングをお申し込みください！
▼▼▼

https://projisou.jp/
「Cannot use JSX unless the '--jsx' flag is provided」エラー解決法

# 問題

jestとreact-testing-libraryを使用してテストを実施しようとしたら下記のエラーが出ました。

```
● Test suite failed to run
src/__tests__/AppComponent.spec.tsx:3:17 - error TS6142: Module '../App' was resolved to '自分のPCディレクトリ', but '--jsx' is not set.

 import App from "../App";
                  ~~~~~~~~
src/__tests__/AppComponent.spec.tsx:7:12 - error TS17004: Cannot use JSX unless the '--jsx' flag is provided.

     render(<App />);
             ~~~~~~~
```

# 原因
原因が何かわからなかったため、調べてみました。
このエラーが発生するのは、TSConfigでjsxのオプションが設定されておらず、jsxを使用しているにも関わらずTypescriptでの処理方法が記載されていないから起こるみたいです。

さまざまなサイトで以下の解決が紹介されていました。
tsconfig.jsonファイルに以下を追加、または既存のものがあれば変更を行う。

```tsconfig.json
{
  "compilerOptions": {
    "jsx": "react"
  }
}
```
またある情報ではreactではなく、preserveにするといいともありました。

私はどちらも試しましてみましたが、エラーは解消されませんでした。



# 解決

その後もいろいろ試しているうちに、環境ファイルの一部を以下のように変更することで解決できました。

まず、jestconfigの設定を以下のようにします。

```jest.config.js
export default {
    preset: "ts-jest",
    testEnvironment: "jsdom",
    setupFilesAfterEnv:['<rootDir>/jest.setup.ts'],
    transform: {
      '^.+\\.(ts|tsx)$': ['ts-jest', {
        tsconfig: 'tsconfig.app.json',
      }],
    },
    moduleNameMapper: {
      '^.+\\.svg$': 'jest-svg-transformer',
      "\\.(css|less)$": "identity-obj-proxy",
    },
    moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  };
  
```

変更点としては、setupFilesAfterEnv:['<rootDir>/jest.setup.ts']の部分にrootDirを追加したことです。このように明示的に参照先を指定することで正しいディレクトリを参照するようにできます。
おそらくjest.configファイルが読み込まれていなかったので、エラーが出ていたのかと思います。

あとは、tsconfing.app.jsonを以下のように変更しました。(このファイルがなければtsconfig.jsonで問題ないと思います）
主な変更点は、typesとallowSyntheticDefaultImportsを追加し、includeの一部を変更しました。

事象解決に直接関係しているかはわからないので、上記のjestconfigを修正してみてダメだった場合に追加するなどの対応の方がいいと思います。

```tsconfing.app.json

{
  "compilerOptions": {
    "composite": true,
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    "types": ["node", "jest", "@testing-library/jest-dom"],

    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,

    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  },
  "include": ["src", "./jest.setup.ts", "./src/ts/**/*"]
}
```

# おわりに
今回は、インターネット上に出ている情報をいくつも試してみましたが解決に至らず時間がかかりました。AIに助けてもらいつつ、試行錯誤する中で無事解決できました。同じようなエラーで悩む方の参考になれば幸いです！
unable to access 'https://github.com/

# 問題
githubリポジトリにgit pushをしようとしたら以下のエラーが出ました。
```
unable to access 'https://github.com/
```

# 対処法
調べてみるとこのエラーは以下のような原因で起こるみたいです。
1. インターネット接続の問題
2. DNSの問題
3. プロキシ設定の問題
4. GitHubのサービス停止

1のインターネット接続はwifi接続ができていることを確認しました。

次に2のDNSに問題がないかを以下のコマンドで試します。
```
ping github.com
```
以下の結果が出てきました。
```
ping: cannot resolve github.com: Unknown host
```
ホストがわからないと言っています。

一応他のサイトも確認。
```
ping google.com
```
こちらも上記同様、ホストがわからないというメッセージが出力されました。

そこで他の解決策に入る前にPCを再起動することにしました。

再起動後、再度上記のpingコマンドを試してみます。

すると、応答が確認できました。

# おわりに
今まで問題なくできていたgit pushが突然できなくなり解決方法もインターネット上にいろいろあったのですが、まずは再起動から始めてみることをおすすめします！
ROS2 オレ的記録

# やりたいこと
PC-AとPC-BでNodeを動かして、PCをまたいで通信させたい

# 作業段取り
PC-A機
- ROS2インストール
- ROS2で、sender・receiverモジュールを実装する
    - sender module
        - メッセージを送信し続ける
    - receiver module
        - メッセージを受信し続ける
- ROS2でpackage化する

PC-B機
- ROS２インストール
- Reciver module packageをインストール

PC-A機/PC-B機
- ROS2通信をセットアップ
- Sender/Receiver moduleで通信させる


# インストール
- Ubuntu22.04を用意する
- ROS2をaptでインストール

https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html

# プログラム確認
実質、send moduleとreceive moduleの確認

demo_nodes_py として、サンプルが存在している。

**送信側**
```
ros2 run demo_nodes_py talker
```

**受信側**
```
ros2 run demo_nodes_py listener
```

**実行結果**
上段がtalker、下段がlistnerの出力結果
```
[INFO] [1722148649.885563864] [talker]: Publishing: "Hello World: 43"
[INFO] [1722148650.885543004] [talker]: Publishing: "Hello World: 44"
[INFO] [1722148651.885587654] [talker]: Publishing: "Hello World: 45"
```
```
[INFO] [1722148649.888894554] [listener]: I heard: [Hello World: 43]
[INFO] [1722148650.888615317] [listener]: I heard: [Hello World: 44]
[INFO] [1722148651.888136696] [listener]: I heard: [Hello World: 45]
```

これで、想定していた送受信の準備が整った。ちなみに、プログラム本体は以下のところに配置
```
/opt/ros/humble/lib/python3.10/site-packages/demo_nodes_py/topics
```
Pythonなので、listner.pyやtalker.pyをエディタで開けば、プログラムを確認できる

# DDSの設定
インストールした状態だと、RTPSが設定済

https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.html

書かれている通り、ROS_DOMAIN_IDを設定すれば、同一サブネット内で通信される
```
export ROS_DOMAIN_ID=11
```

PC-AとPC-BからTalkerを動かして、PC-AでListnerを動かすと、このような出力

**PC-A Talker**
```
[INFO] [1722152977.610636752] [talker]: Publishing: "Hi, I am PC-A: 79"
[INFO] [1722152978.610479115] [talker]: Publishing: "Hi, I am PC-A: 80"
[INFO] [1722152979.611647554] [talker]: Publishing: "Hi, I am PC-A: 81"
```
**PC-B Talker**
```
[INFO] [1722152978.198109339] [talker]: Publishing: "Hello, I am PC-B: 21"
[INFO] [1722152979.198202274] [talker]: Publishing: "Hello, I am PC-B: 22"
[INFO] [1722152980.198333266] [talker]: Publishing: "Hello, I am PC-B: 23"
```
**PC-A Listener**
```
[INFO] [1722152977.612724374] [listener]: I heard: [Hi, I am PC-A: 79]
[INFO] [1722152978.203141011] [listener]: I heard: [Hello, I am PC-B: 21]
[INFO] [1722152978.612624961] [listener]: I heard: [Hi, I am PC-A: 80]
[INFO] [1722152979.202909262] [listener]: I heard: [Hello, I am PC-B: 22]
[INFO] [1722152979.613337310] [listener]: I heard: [Hi, I am PC-A: 81]
[INFO] [1722152980.203578031] [listener]: I heard: [Hello, I am PC-B: 23]
```

とりあえず、やりたいことの前半はできた感じ。何もしなくても通信するのは、想定外の結果。ただ、サブネット上に影響を与えそうなところが気になった(気にしない)。と、思ったら、ROS_LOCALHOST_ONLYがあった。1を設定すると、localhostに絞られる模様
```
export ROS_LOCALHOST_ONLY=1
```

今日はここまで
Keycloakを使ってみよう。

## 初めに
ここではDockerを使ってKeycloakを使うところまで記載する。

## Dockerを立ち上げる。
使ってないけど、DockerDesktopはインストール済みだったので、CMDで以下のコマンドを打つ。

```
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:25.0.2 start-dev
```
【Keycloakのサイトより】
https://www.keycloak.org/getting-started/getting-started-docker

すると、以下のように自動で起動した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981805/ed93b8c9-f68b-6db6-8419-33fef72700b1.png)

上のコマンドで、実はローカルホストのポートやKeycloakのIDパスワードを指定している。
IDパスワードは、「＝」の後ろのやつ。IDパスワードはまぁ好きなように設定したらいい。

ブラウザから以下のURLではいるとKeycloakが立ち上がっているのが確認できる。
http://localhost:8080/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981805/258ca6f3-65e1-43d7-a761-be0d738caaf3.png)

## AWSのコンソールとの連携
さて、さっぱりわからんので、ググってみた。
以下のページを参考にすると、コンソールへのログインができるところまで行ける。

https://qiita.com/gaichi/items/4e58d1d1c3ad4a024ffd

上のページのはちょっとバージョンが古いらしく、ちょいちょい画面構成が異なるが勢いでいけるはず。

詰まったのはHomeURLのところだけ。
Clientsの設定のところで「IDP-Initiated SSO URL name」のはてなマークのところで書かれているように、HomeURLの設定は以下のようになる。
```
{server-root}/realms/{realm}/protocol/saml/clients/{client-url-name}
```
そう。参考にしたページとはことなり、頭に「/auth」が不要なのだ。

というわけで、キークロークからのSSOでAWSコンソールにアクセスすることができるようになった。