OmniAICreator/Qiita-1.07M huggingface dataset:
QR コードを URL からデコードするアプリを Flutter で作る

# QR コードを URL からデコードするアプリを Flutter で作る

こんにちは、@ekusiadadus です。
ひょんなことから QR コードを URL や Image ファイルからデコードするスマホアプリを作ることになりました。
いろいろ調べてみたのですが、なかなか文献が見当たらなかったので自分で作ってみました。

## 作ったアプリ

ソースコード: https://github.com/ekusiadadus/flutter-barcode-decode-from-url

![205739914-d9e65c78-f1f5-476b-b6c9-56bedccd779e.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/655bb3f2-b461-7bf3-18fb-94f8991b5d48.gif)

## 作り方

いろいろ考えたのですが、一番シンプルなのは次の手順だと思いました。

1. URL から画像を一時ストレージに保存させる
2. 画像ファイルから scan パッケージで、QR コードを読み取る

### 1. URL から画像を一時ストレージに保存させる

まずは、URL から画像を一時ストレージに保存させます。
本当はメモリ上にのせておくだけで読み取れると思うのですが、scan パッケージがファイルを読み取るようなので、一時ファイルに保存させます。
(もしやり方わかる方いたら教えてください)

```dart
final qrCodeController = TextEditingController();

//Image is a temporary memory Image
Image? image;
//File is a temporary file
File? imageFile;

void onGetImage(String url) async {
  final tmpFile = await urlToFile(url);
  setState(() {
    imageFile = tmpFile;
    image = Image.file(tmpFile);
  });
}
```

urlToFile は、次のように実装しました。
一時ファイルなので秒単位でファイル名が変わるようにしました。

```dart
// url to file function
Future<File> urlToFile(String imageUrl) async {
  Directory tempDir = await getTemporaryDirectory();
  String tempPath = tempDir.path;
  //datetime to make the file name unique
  File file = File('$tempPath${DateTime.now()}.png');
  http.Response response = await http.get(Uri.parse(imageUrl));
  await file.writeAsBytes(response.bodyBytes);

  return file;
}
```

## 画像ファイルから scan パッケージで、QR コードを読み取る

次に、画像ファイルから scan パッケージで、QR コードを読み取ります。
こんな感じで、scan パッケージの parse メソッドを使います。

```dart
//Result of the QR code
String? result;

void onGetImage(String url) async {
  final tmpFile = await urlToFile(url);
  final qr = await Scan.parse(tmpFile.path);
  setState(() {
    imageFile = tmpFile;
    image = Image.file(tmpFile);
    result = qr;
  });
}
```

state が更新されたら、画像が表示されるようにします。

```dart
body: Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      TextField(
        controller: qrCodeController,
        decoration: InputDecoration(
          border: OutlineInputBorder(),
          labelText: 'QR Code URL',
          suffixIcon: qrCodeController.text.isNotEmpty
              ? IconButton(
                  icon: const Icon(Icons.clear),
                  onPressed: () {
                    qrCodeController.clear();
                  },
                )
              : Container(width: 0),
        ),
      ),
      const SizedBox(height: 20),
      image ?? Container(),
      const SizedBox(height: 20),
      Text(result ?? ''),
    ],
  ),
),
```

実際の画面はこんな感じ

![barcode_from_url_tutorial – main.dart [barcode_from_url_tutorial] 2022-12-07 06-04-42.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/fd65637d-16a8-03ed-1b4c-6d82bf0ea279.gif)

## まとめ

Flutter で QR コードを URL や Image ファイルからデコードするアプリを作る方法を紹介しました。
scan パッケージを使うと、簡単に実装できました。
他にも、qr_code_flutter とか google ml kit 使う方法があると思います。

オンメモリでやる方法ない気がするんだよなぁ...
Firebase HostingからCloud Functionsへのrewriteで、リージョン指定できるようになった？

`us-central1`以外でもrewriteできるようになってない？　という話です。

# 今まで（の認識）
Hostingで動的なページを表示する際などにFunctionsへrewriteするってことがありますが、[ここ](https://firebase.google.com/docs/functions/locations#http_and_client-callable_functions)にあるように

> Firebase Hosting の動的コンテンツを提供するために HTTP 関数を使用している場合は、 us-central1を使用する必要があります。

という縛りがあるので

```javascript:functions
export const hoge = functions.region('asia-northeast1').onRequest(app)
```

```json:firebase.json
"hosting": {
  "rewrites": [
    {
      "source": "/hoge",
      "function": "hoge"
    }
  ]
}
```

みたいな形にすると動かなかったんですよね。
少なくとも1年くらい前は`us-central1`じゃないとダメだったような記憶･･･。

# 今（2022/12/07）

なんですが、[ドキュメント](https://firebase.google.com/docs/hosting/full-config?hl=ja#rewrite-functions)を見ていたら

> regionがhosting構成から省略されている場合、Firebase CLI は関数のソース コードからリージョンを自動的に検出しようとします。指定されていない場合は、デフォルトでus-central1ます。ソース コードが利用できない場合、CLI はデプロイされた関数からリージョンを検出しようとします。関数が複数のリージョンにある場合、CLI では、 hosting構成でregionを指定する必要があります。

あれ、この記述って前からあったっけ･･･。
あったような気もするし、その上で動かなかった気もするしどうだったっけ？

ともやもやしたので

```json:firebase.json
"hosting": {
  "rewrites": [
    {
      "source": "/hoge",
      "function": "hoge",
      "region": "asia-northeast1"
    }
  ]
}
```

として`firebase serve`したところ･･･**あれ？　動いてね？**
Firebase CLIのバージョンは`10.2.2`と割と古いままなので、ここの問題でもなさそう。

ならばということでデプロイしたところ･･･**やっぱり動いてね？**

何かのあれでFunctionsが`us-central1`にデプロイされてたりするのか？　と思い、FunctionsのURLを直接叩くも、`us-cental1`はダメで、`asia-northeast1`だとちゃんと動く。
ダッシュボードを見ても確かに`asia-northeast1`だし。
同名の関数なのが微妙だったかと思い別名の関数でデプロイしてみてもやっぱり動く･･･。

以前試したときに動かなかったのは、何か設定がおかしかった（`firebase.json`に`region`指定してなかったとか）だけで、実は前からリージョン指定可能だったんだろうか？
それともどこかで仕様変更あったんだろうか？

## ちなみに
Functionsを`asia-northeast1`にした場合、`firebase.json`の`region`を未指定にすると動きません。
（devtoolsをみる感じ`us-central1`に繋がってるっぽい）

なので

> regionがhosting構成から省略されている場合、Firebase CLI は関数のソース コードからリージョンを自動的に検出しようとします。指定されていない場合は、デフォルトでus-central1ます。ソース コードが利用できない場合、CLI はデプロイされた関数からリージョンを検出しようとします。

にある「リージョンを検出しようとする～」のくだりはアテにしないほうがよさそうです。
そもそもCLIに言及してるから、localでの話なのかも？

# 終わりに

もし本当に勘違いとかでなく`us-central1`縛りがなくなったのだとしたら、Functionsでweb APIを作るときにプロジェクトID露出させなくて済むな～とか。
近いリージョンだけでやろうとすると、どうしても直アクセスになってたんですよね。

そしてドキュメントちゃんと更新してほしい･･･。
【Docker】docker-compose build実行時にload metadata for docker.io/library/○○とエラーが表示される

# 環境
・Mac M1 OS Monterey12.6
・docker desktop Version 4.15.0

今回はdockerでRailsの環境構築を行なった際にエラーがたくさん出たので解決方法を忘れないように備忘録として残します。
# load metadata for docker.io/library/○○○とエラーが何個も表示される
docker-compose build実行時に下記のようなエラーが表示されました。
```
=> ERROR [example_app_db:1.0.0 internal] load metadata for docker.io/library/postgres:○.○
=> ERROR [example_app:1.0.0 internal] load metadata for docker.io/docker/dockerfile:○.○
=> ERROR [example_app:1.0.0 internal] load metadata for docker.io/library/ruby:○.○.○
(※○にはバージョンが入ります)

failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to solve with frontend gateway.v0: rpc error: code = Unknown desc = failed to fetch oauth token: Post "https://auth.docker.io/token": dial tcp: lookup auth.docker.io on 192.168.xx.xx:xx: server misbehaving
```
エラー文をよく見てみると「トークンの取得に失敗している」という記述がありましたので、`docker login`で確認すると
![スクリーンショット 2022-12-08 1.20.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604036/5df3d24f-9476-211a-3bb4-bed8b4553cd6.png)
どうやらログインには成功しているようです。
docker desktopでログアウトしてもう一度ログインし直して解決している方もいましたが変わりませんでした。
念の為、dockerのアカウント設定で２段階認証用のアクセストークンを取得し、CLI上でもログインしてみましたがそれも変わらず。。

色々と調べてみると解決方法を見つけることができましたが、今回は２段階で解決できました。

# 解決方法①
まず１つ目ですが、Docker Hubのレジストリから直接pullしてくる方法です。
[こちら](https://docs.docker.jp/engine/reference/commandline/pull.html)に詳しい方法がたくさん記載されていました。
```
% docker pull postgres:○.○

※dockerfileの場合は階層も必要でした
% docker pull docker.io/docker/dockerfile:○.○
```
こちらの方法でpullしてくることによってエラーは出なくなりましたが、Rubyも同じようにpullし、もう一度buildするとRubyの出ていたエラーだけが解消されませんでした。

# 解決方法②
続いて二つ目ですが、docker desktopの設定を開いてGeneralにあるUse Docker Compose V2のチェックを外すことで解決できました。
![スクリーンショット 2022-12-08 1.44.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604036/24a2440f-cc60-a5f4-cda2-48072519d333.png)

# 最後に
dockerの環境構築ですんなりいったことが一度もない。。
今回はなぜ設定変更しただけで解決したのか理由がわからないままでした。
まあでも改めてdockerの便利さに気づくことができたのでよしとします！！
記事の感想や意見、ご指摘等いただけると助かります。
最後までご覧いただき、ありがとうございました。
年末なのでたまりに溜まったブランチを削除する

この記事は[KDDI Engineer&Designer Advent Calendar 2022](https://qiita.com/advent-calendar/2022/engineer-designer)の8日目の記事です。
# 知らぬ間に増殖するブランチ
チームで開発を進めていくうちに無駄なブランチがgithubに増殖してしまうことってありませんか？
僕が参加するプロジェクトでも気づけばブランチが500以上に増えていました。
500以上のブランチのうちmainやdevelop以外のブランチを見てみると開発の仕掛中で終わりになったブランチやPRがcloseされてそのまま残り続けているブランチもいくつかはあったのですが、1番多かったのは**マージ後も削除されずに残り続けているブランチ**でした。
そこでdevelopブランチにマージしたブランチを自動的に削除する設定をいれましたので、今回はその設定をご紹介します！

# 設定はたったの２つ！ブランチを自動的に削除する
結論から言います。以下の２つを設定するだけです。
- 削除されたくないブランチをプロテクトする
- ブランチの自動削除の設定をONにする

githubにはマージしたブランチを自動的に削除する設定が予め設けられています。
リポジトリのSettingsから``Automatically delete head branches ``のチェックを入れると、プルリクエストがマージされた後、head ブランチが自動的に削除されます。
![スクリーンショット 2022-12-08 0.39.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582866/03fd9aa0-8ae9-8319-4bef-b0e2d171b37b.png)

しかしこのままでは main <- stage のようなマージを行った際にstageブランチが削除されてしまうため、削除されたくないブランチにはプロテクトを設定します。
どうやらプロテクトと自動削除ではプロテクトが優先されるらしく、ブランチをマージした際もプロテクトされているブランチは削除されずに残り続けてくれます。
ブランチのプロテクトはSettings→branches→Branch protection rulesでプロテクトしたいブランチの名前を入力するだけで簡単に設定できます。
![スクリーンショット 2022-12-08 0.53.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582866/bfe2b6de-ccab-5601-acee-260362aa0db0.png)
また、``relese/**``のように[fnmatch 構文](https://ruby-doc.org/core-2.5.1/File.html#method-c-fnmatch)で指定することで規則的なブランチに対してもルールが設定できます。

# 一度消しても大丈夫。魔法のrestore branch
え、これだけ？？なんだか削除しちゃいけないブランチも削除されそうで怖い
でも大丈夫です。ブランチが削除されてもrestore branchをすればブランチが復活します。
![スクリーンショット 2022-12-08 1.11.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582866/4aa4bd77-ee13-90cd-eacc-bbfd4f164cad.png)
# 最後に
これでもう不要なブランチが増え続けなくなりました！
あとは500以上ある不要なブランチを削除すれば、年末の大掃除終了です！
では、それはどうやるのか、

簡単です。ひたすら削除ボタンを押し続けるのみ

＼＿ヘ(Д｀*)ポチポチポチ.......................................................

それでは良いお年を！！
フルスタックエンジニアがAWS Certified Solutions Architect – Associateを取得した

# フルスタックエンジニアがAWS Certified Solutions Architect – Associateを取得した

スタートアップで働くエンジニアの誰もが複数のポジションを兼任することが多いかと思います。
Webサービス系の場合、大体の場合、大きく分けると３つに分けられているかとは思います。
・バックエンド
・フロントエンド
・インフラ

## なぜ、資格を取得しようと思ったのか？
自分はもともとバックエンドエンジニアでサーバ構築とかも片手間でやっていたので、サーバの構築などはこれまでやってきましたが、クラウド設計については、ほぼやってきませんでした。

インフラの場合は、昨今はおおよそはAWSかGCP、あとはAzureなどのクラウドを使うことがほとんどだと思います。
AWSには２００個以上のサービスがあり、どのサービスを使えばいいのかは、直感ではわからないし、やりたいことに対してどのサービスを組み合わせれば、ベストプラクティスなのか？ということも調べないとわかりません。
というところから、体系的に学ぶということでAWSの公式資格を学ぶのが正しいと思います。

[AWSサービス一覧](https://dev.classmethod.jp/articles/aws-summary-2022/)

### 勉強方法
Udemyの講座で勉強しました。
[【SAA-C03版】これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座](https://www.udemy.com/course/aws-associate/)
まず、この講座をひたすら受講して理解します。47.5時間あるので1日１時間ずつやっても47日強かかります。
自分の場合は、仕事の合間で勉強していて、途中、プロジェクトが忙しくなって、半年ぐらい放置したりしていました。実質、３ヶ月ぐらいかかったと思います。

[【SAA-C03版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問](https://www.udemy.com/course/aws-knan/)
上記が一通り終わったら、模擬試験集で３周ぐらいやりました。合格点にならなかったところは講座のほうに戻ったりしながらやりなおしたりしてました。すべて90%以上の正答率まで繰り返しやりました。

### どうやって受験するのか？

* オフラインで受験
* オンラインで受験

#### オフラインで受験
* ピアソンVUEで会場予約して、受験する
自分はオフラインで受験にしました。
##### メリットとして
* 認定機材をチェックするのが面倒。
* 集中して受験できる。宅配や家族の邪魔から防御できる。
##### デメリット
* 会場まで行く必要がある。

手順としては、

1\.AWS資格サイトへアクセスしてアカウントを登録する
[資格サイト](https://aws.amazon.com/jp/certification/)

2\.ピアソンVUEでバウチャーを購入して、試験会場を予約する
バウチャーの購入はいろんなサイトがありますが、自分はAWSからのリンクでバウチャーを購入しました。
[AWSのバウチャー購入について](https://aws.amazon.com/jp/certification/bulk-voucher/)

その後、ピアソンVUEで試験会場を検索して、受けたい場所と時間を選択して予約する。

3\.受験する
現地で受験しましょう。持ち物は基本ロッカーに、入れてから入室するので、ノートなどは持ち込みはできません。

その場で合否がでます。
自分の場合はギリギリで合格でした^^;

### 最後に
一応、ベースの知識を得ることはできたので、こういった場合にはこのサービスを使うというのはわかったのは良かったです。
ただ、設定などのオペレーション方法については実際に操作してみたりしないとわからないのでそこは試験外で、別な次元なので自分で操作して覚えるしかないです。


ただ、必須かというとSIerとかAWSベンダーでなければ、それほどまでには必須ではないです。
要は、資格とってなくても設定さえできれば問題ないので。


#### 参考サイト
[WS認定資格試験の申し込み～受験の方法を徹底解説 2020年版](https://hackers-high.com/aws/how-to-take-aws-certification-exam/)

デジタルバッジがもらえますがどこで使うのやら・・・・
![aws-certified-solutions-architect-associate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99447/55562c8a-8334-17e3-dbed-736a48198ef9.png)
GithubActiionsで「Credentials could not be loaded, please check your action inputs: Could not load credentials from any providers」の対応



## エラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/7ed84a0e-0543-888e-1def-b6167249aa4f.png)

エラー箇所
```yaml
  - name: setup aws
    uses: aws-actions/configure-aws-credentials@v1
    with:
      role-to-assume: ${{ env.AWS_ROLE_ARN }}
      aws-region: ap-northeast-1
```

## 原因
WorkflowへのPermission不足
以下を追記してあげると動くかも

```yaml
permissions:
  id-token: write
  contents: read
```




## 参考
https://tech.guitarrapc.com/entry/2021/11/05/025150
【React】SWRのキャッシュについての整理

## 概要
この記事は[ジャンルなしオンラインもくもく会 Advent Calendar 2022](https://adventar.org/calendars/7743)の8日目の記事です。
最近、Reactのデータ取得のためのHooksライブラリであるSWRを触っていて、キャッシュの管理に少しハマりましたので、今回メモ書きを残しておきたいと思います。なお、SWRについての概要は[データ取得のための React Hooks ライブラリ「SWR」をNext.jsで試してみた](https://dev.classmethod.jp/articles/getting-started-swr-with-nextjs/)の記事などをご参照ください。

## 前提
前提とするSWRのバージョンは`1.3.0`とします。

## キャッシュの管理単位
[SWR 触ってみた](https://curucuru.co.jp/blog/20220629_swr)の記事の「データ取得」の項にある通り、`useSWR`の第1引数に設定するキーの単位で、キャッシュが管理されています。例えば、画面でデータのid毎にキャッシュを保持したい場合は、`/api/users/${userId}`　のような形でキーを設定します。

## 手動での再取得
[SWRの機能を簡単にまとめる - 手動で再取得したい場合](https://qiita.com/irico/items/d8f0ed7887f3c490ffa1#%E6%89%8B%E5%8B%95%E3%81%A7%E5%86%8D%E5%8F%96%E5%BE%97%E3%81%97%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88)の記事にある通り、`mutate('/api/users/${userId}')`の形式でキーを指定し、手動で再取得を行うことが可能です。

## キャッシュの削除
[useSWR cache management](https://blog.mmyoji.com/posts/2021/11-11-swr-cache-management/)の記事で紹介されている通り、mutateを使って直接データの更新をする方法と、`useSWRConfig`　のcacheのdeleteを使う方法が挙げられます。
個人的には、cacheのdeleteを使う方が分かりやすいかなと思います、`cache.delete('/api/users/${userId}')`のようにキーを指定して、キャッシュの削除が行えます。
Laravel8(API) × Vue.js で中間テーブルにPOSTする

現在お知らせ機能を実装しており、「次回から表示しない」ボタンを配置しています。ユーザーごとにどのお知らせを非表示にするかを管理するために、中間テーブルを作成しています。
現状はINSERTで中間テーブルにレコードを追加しています。
Vue.jsでaxiosを使って、APIからお知らせの情報を取得&表示まで実装済。
今回はAPIを完成することをゴールとします。

Laravel8（APIモード）
Vue2（SPA）

### 実装手順
- 中間テーブルのモデルを作成&関連付け
- UserControllerで中間テーブルへPOSTする内容を記述
- ルーティングの設定（api.php）
- PostmanでPOSTリクエスト送信
- Vue.jsからのリクエスト→APIとの疎通を確認
### 中間テーブルのモデルを作成&関連付け

多対多の中間（ピボット）テーブルのモデルを作成する場合、`using`メソッドを呼び出すこと。
Notificationsモデル
```php
public function users() {
        return $this->belongsToMany(User::class)->withPivot(['read', 'hide_next'])->using(NotificationUser::class);
    }
```
Usersモデル
```php
public function notifications() {
        return $this->belongsToMany(Noification::class)->withPivot(['read', 'hide_next'])->using(NotificationUser::class);
    }
```
ピボットテーブル用モデル生成
```php
php artisan make:model NotificationUser
```
NotificationUserモデル
```php
<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Pivot;

class NotificationUser extends Model
{
    use HasFactory;

    protected $fillable = ['id','notification_id','user_id','read','hide_next','created_at','updated_at'];
}
```
ちなみに、モデルを作成した際は、
```php
protected $fillable = ['hoge'];
2022年に行ったTerraform周りの施策まとめ

こんにちは。ZOZOの@wadasonです。
この記事は [ZOZO Advent Calendar 2022](https://qiita.com/advent-calendar/2022/zozo) カレンダー Vol.5の 8日目の記事です。

2022年に実施したTerraformに関連する施策についてまとめながら所感を書いていきます。深い内容は書いてないです。

# きっかけ
去年、入社し手間もない頃に職場のCloud FormationをTerraformに移行するという長期的な方針を立てました。最初は軽い気持ちで決めたのですが、かなり莫大なCloud Formationスタックを地道に移行していくのは途中で心が折れそうでした。ですが、継続的にTerraform周りの改善が進んだため、現在では単なる移行作業ではなく、それなりに意義のある良い取り組みになっていると考えています。

# 取り組み
## Cloud FormationからTerraformへの移行手順のブラッシュアップ

当初は[terraformer](https://github.com/GoogleCloudPlatform/terraformer)や[cf2tf](https://github.com/DontShaveTheYak/cf2tf)を利用しようと考えました。どのツールも魅力的だったのですが、利用しないことにしました。
網羅するAWSサービスが足りておらず、どのみち移行作業が発生したためです。

まずは手順を整備しました。
Cloud Formationの`PhysicalResourceId`とTerraformのimport時の第二引数が同じであるケースが多いことがわかりました。もちろんそうでないケースもありますが、徐々に知見を積むことで効率化できると考えました。
以下で取得できるCloud Formationの情報と照らし合わせて、Terraformで記述する予定の内容を入力すれば自動でimportコマンドが生成されるスプレッドシートを作りました。

```bash
$ aws cloudformation describe-stack-resources --stack-name ${STACKNAME} | jq -r ".StackResources[] | [.StackName, .ResourceType,.LogicalResourceId,.PhysicalResourceId] |@csv"  > ${STACKNAME}.csv
```
Terraformの入力項目は、モジュール名(module.hoge)、リソースタイプ（aws_iam_role etc..）、リソース名です。
若干効率化できたと思います。うまくいかなかった点としては、TerraformはS3など、Cloud Formationよりも細かくリソースが別れており、この方法ではうまくいきませんでした。

現状は目視確認や手動入力が多いので、スクリプトを書いてさらに効率化できると良いと考えてます。

## Terragruntの導入
移行を実施する中でstateが肥大化してCI/CDが遅くなってしまう課題がありました。そこで[terragrunt](https://terragrunt.gruntwork.io/)を用いてstateをCloud Formationスタックごとに分ける方針にしました。
バックエンドのS3バケットは共通化しつつ、stateを細かく分離できるため移行作業に安心して取り組むことができます。

もう少し落ち着いたら細かく分離しすぎたstateの共通化を検討しようと思います。
流石にstate多すぎな気がしているのと、TerraformやProviderのバージョン管理が多くなってしまい運用負荷が高いと感じます。

## その他
### ツールの導入
セキュリティスキャンを行う[tfsec](https://github.com/aquasecurity/tfsec)や、コードからコストを見積もる[infracost](https://github.com/infracost/infracost)の導入をチームで検討・実施しました。改めて現状を見直す機会になりました。
### Lambdaの整備
Lambdaを実装した人によって異なっていることが多くありました。そのため同じ管理手法に統一しました。
Lambdaのリソースに関してはTerraformで管理し、関数は同じ命名規則に沿ったリポジトリ名を配置することで管理コストを下げています。CI/CDが実装されていなかったり、さまざまなリポジトリに散らばっていたため実施してよかったです。

# おわりに

空いた時間を見つけて、楽しんで実施しています。詳しい内容はこれから発信していこうと思います！
[Python] Cognitoで認証周りを作る

## 有効なユーザーにログインしてみる

```python

import boto3
import os
import hashlib
import hmac
import base64

# hash化する関数
def get_hash(username):

    secret_key = os.getenv('SECRET_CLIENT')
    msg=username + os.getenv('CLIENT_ID')
    dig = hmac.new(str(secret_key).encode('utf-8'), 
    msg=str(msg).encode('utf-8'), digestmod=hashlib.sha256).digest()
    d2 = base64.b64encode(dig).decode()
    dig = d2
    return dig

def login(username, password):
    CLIENT_ID = os.getenv('CLIENT_ID')

    cognito_client = boto3.client('cognito-idp')

    auth_response = cognito_client.initiate_auth(
    
        ClientId=CLIENT_ID,
        AuthFlow='USER_PASSWORD_AUTH',
        AuthParameters={
            'USERNAME': username,
            'PASSWORD': password,
            'SECRET_HASH': get_hash(username),
        }
    )

    if auth_response['AuthenticationResult']:
        access_token = auth_response['AuthenticationResult']['AccessToken']
        refresh_token = auth_response['AuthenticationResult']['RefreshToken']

        return{
            "access_token": access_token,
            "refresh_token": refresh_token
        }
        
    else:
        
       raise ValueError("Login Failed")
        
login('username', 'password')

```
LazyLoad

![08.LazyLoad.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11525/e48d012d-35db-dfdc-4732-3518832e6547.png)

https://bliki-ja.github.io/pofeaa/LazyLoad/

Lazy Load は関連データの遅延読み込みを行うパターンです。

関連テーブルに入ったデータが必要ではあるけど、意味があるのはそのうち一部の場合だけ、といったケースはよくあります。SQL で JOIN クエリを使って、いくつもの関連テーブルを連結させた巨大な表を読み込む (あるいは、クエリは段階的であったとしても、関連データをあらかじめ全て読み込む) 方針でプログラミングすると、せっかく読み込んだデータのほどんどが、使われることなく破棄されます。

Domain Model では、詳細を問わない他のビジネスロジックに処理を委譲します。そうすると、一部が使われないどころか、場合によっては、読み込んだ関連データを全く使わないかもしれないのです。逆に全て使ったうえで関連の関連まで辿っていくかもしれません。必要な関連データが事前に「わからない」ということこそが、Domain Model の価値 (抽象化による連携) の裏にある本質です。

Lazy Load は、全ての関連データを、最初には取得しません。関連データが入るはずのオブジェクトフィールドには、未取得であるというマークだけを残しておきます。実際にそのフィールドにあるはずのデータが求められたときに、初めて関連データを取得するクエリを発行します。こうすることで、仮想的に、全ての関連データが存在するように見せかけつつ、無駄なデータの読み込みを節約することができます。たとえば、仕事に関係ありそうな技術書をとりあえず一式買って本棚に入れておき、実際に必要になってから詳しく読むようなものです。

しかし、細切れになった随時データ読み込みは、場合によってはパフォーマンスを劣化させることがあります。欲しいデータの総量に対して、クエリの発行回数が多くなりすぎるためです。一括で関連データを 100 行得るのと、1 行しか取得しないクエリを 100 回発行するのを比べると、前者の方がはるかに高速です。そうしたパフォーマンス問題を解消するために、決め込みで事前に一括読み込みをしてしまうことを、Eager Load と呼びます。

Domain Model を基本方針としたとき、Lazy Load が適しているか Eager Load が適しているかは、あらかじめ決めることができません。全体の動作から統計的に判断するしかないのです。あらかじめどちらが適しているかを、関連の関連まで詳細に考えようとすると、実質的にそれはTransaction Script になっていきます。

「Lazy Load が思ったより多い」問題は、実際のクエリログからわかりますが、「Eager Load に無駄がある」問題は、いくら動作ログを見てもわかりません。まずは、パフォーマンスに問題はあっても、いったん全てを Lazy Load の方針で作り、仮想的に全データがメモリにあるものと考えてロジックの全体を成り立たせ、後からパフォーマンスを最適化する、という流れがセオリーです。これは優先度の問題でもあります。いくらパフォーマンスが良くても、ビジネスロジックが間違っていては何の意味もありませんよね。
CSS Grid Layoutでのスキマをいい感じに埋める（Vueでの場合）

Webエンジニアにとって[CSS Grid Layout](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Grid_Layout)を使用する機会は増えてきているのではないでしょうか。
縦横の2次元に対して自由にレイアウトを組むことができるので非常に便利です。

そしてCSS Grid Layoutを使う中で、下の画像のように「ある領域に同じ要素を複数並べていったときに、領域の最後にスキマができてしまうので、このスキマをいい感じに埋めたい」
というケースに遭遇したことはないでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615201/6ba19721-b027-2857-95a2-faa3a0c76892.png)

正直なところ、遭遇したことがある人、これから遭遇する人は多くないと思いますが、これを実現するためのライブラリを以前作ったので、これのVueアプリケーション上での使い方を紹介させていただきたいと思います。

ライブラリはこちらです。[Grid Spacer](https://github.com/ryo-gk/grid-spacer)

使うと次のようになんとなくいい感じにスキマが埋まります。

![Grid_Spacer.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615201/2e6501ac-cbdc-9f83-ec1d-bf4a502c95e3.gif)

## 使い方
ますはインストールしてください。
```bash
> npm i grid-spacer
```

Vueでの使い方は、以下のようになります。

```vue
<script setup lang="ts">
import { onMounted } from 'vue'
import { useGridSpacer } from 'grid-spacer'

const { execute } = useGridSpacer({
  containerClass: 'container',
  spacerClass: 'box',
  spacerTag: 'div',
  type: 'fill'
})

onMounted(() => execute())
</script>

<template>
  <div class="container">
    <div class="box" v-for="i in 13" :key="i">
      <div class="content" />
    </div>
  </div>
</template>

<style scoped>
.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  gap: 4px;
  width: 90%;
  margin: 48px auto;
}

:deep(.box) {
  background-color: gray;
  width: 100%;
  height: 100px;
}
</style>
```

`useGridSpacer` から返される `execute` 関数を `onMounted` フックで実行するだけです。
scoped styleを使う場合は、要素のクラスに対して `:deep`セレクタを使用してください。

そして、 `useGridSpacer` に渡すオプションは次のような感じです。
- containerClass ... 要素が並ぶ領域のクラス名。
- spacerClass ... スキマを埋める要素のクラス名。
- spacerTag ... スキマを埋める要素のタグ名。
- type ... スキマを埋める形式。`fill`だと１つの要素で、`fit`だと複数要素で埋める。
　

`fit` type を使った場合は下のようになります。
![Grid_Spacer_fit.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615201/9a743f2d-d1f2-8e29-cc7b-7dc6124738d8.gif)

## まとめ
もしこんなことがしたいケースに遭遇したら、使ってみてもらえればなと思います。
MySQL闇歴史　スキップされたバージョン番号

2017年ごろからMySQLのマイナーバージョンのリリースは1, 4, 7, 10月の20日頃というサイクルが安定してきた。オラクルのCritical Patch Updatesのリリースとおおむね同じようなタイミングなのはもちろん偶然ではない。

知名度：★☆☆☆☆
闇度　：★★☆☆☆
スキップ度：★★★★★

MySQL 8.0のGAリリースのタイミングでMySQLサーバーやConnectors, Workbench, Shellおよび商用版のEnterprise MonitorやEneterprise Backupのマイナーバージョンを全て揃えるためにリリースされていないマイナーバージョンがいくつも出た。

MySQLサーバーの場合は8.0.11がGAとしてリリースされた。DMRが8.0.4まで進んだところで8.0.5 - 8.0.10はまとめてスキップされた。
[Changes in MySQL 8.0.5 - 8.0.10 (Skipped version numbers)](https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-5-through-10.html)

GAのマイナーバージョンが8.0.11になった背景は8.0.10までバージョンが進んでいたソフトウェアがあったから。それはConnector/Netだった。
[Changes in MySQL Connector/NET 8.0.10 (2018-01-30, Release Candidate)](https://dev.mysql.com/doc/relnotes/connector-nodejs/en/news-8-0-10.html)

MySQL Shell 8.0はやや不思議な流れになっていて、8.0.0がDMRで出たあと、8.0.1と8.0.2スキップされ、8.0.3 DMR -> 8.0.4 RCとなったところから8.0.11 GAまでバージョンが飛んでいる。
[MySQL Shell 8.0 Release Notes](https://dev.mysql.com/doc/relnotes/mysql-shell/8.0/en/)

しかしこのマイナーバージョンを揃える試みは初っぱなから揺らぎを見せる。Workbenchは8.0.0から8.0.10を一気にスキップしたと思ったら8.0.11がGAではなくまさかのRCでびっくりしたことを覚えている。
[Changes in MySQL Workbench 8.0](https://dev.mysql.com/doc/relnotes/workbench/en/news-8-0.html)

ちなみにこれを書いている時点でのMySQLサーバーなどの最新のマイナーバージョンは __8.0.31__ なのだが、2021年12月にMySQL Enterprise MonitorがApache Log4j 2の脆弱性対応のために2日連続でマイナーバージョンがリリースされるという異例の事態が発生。これ以降、他のソフトウェアとのマイナーバージョンに対して1つだけ進んだ状態が続いており、MySQL Enterprise Monitorだけが __8.0.32__ が最新となってしまっている。
[MySQL Enterprise Monitor 8.0 Release Notes](https://dev.mysql.com/doc/relnotes/mysql-monitor/8.0/en/)
Gitの変更が大量に出た時の対処法（vscode)

対処法
ユーザーディレクトリ配下に.gitのディレクトリが誤って生成されてしまっていたことが原因でした…

本来.gitディレクトリは各プロジェクトのディレクトリ配下に作成されているのですが、
誤ってユーザーディレクトリ配下に作成されてしまった結果、大量の差分ファイルが出てしまっていました。

Finder → ユーザーディレクトリ を確認し、.gitのディレクトリを削除すれば解決します!
(隠しフォルダは shift ＋　command ＋.　で表示できます)
Azureで提供される負荷分散サービス（Azure Load Balancer、Azure Application Gateway）

●Azureで提供される負荷分散サービス

■Azure Load Balancer
レイヤー４のロードバランサー。任意のポート番号やプロトコル(TCPまたはUDP)を振りわけの条件に使用し、いくつかの仮想マシンで負荷分散できる。
Webサーバーの負荷分散にも使用できるが、主にWebサーバー以外の負荷分散に使用される。

▲ロードバランサーの種類
・パブリック
一般的なロードバランサーの構成に使用される。ロードバランサーがパブリックIPアドレスを持ち、インターネットからロードバランサー宛に送られたトラフィックが分散される。
パブリックロードバランサーではネットワークアドレス変換(NAT)を行うため、バックエンドプールに含まれる個々の仮想マシンんにはパブリックIPアドレスは不要。

・内部
パブリックIPアドレスを持たないロードバランサーの種類。
プライベートアドレスだけをもち、仮想ネットワーク内からロードバランサー宛に送られたトラフィックが分散される。



■Azure Application Gateway
レイヤー７のロードバランサー。Webサーバー専用の負荷分散サービス。
必要に応じてWebアプリケーションファイアーウォール(WAF)やSSLオフロード機能も使用できる。
失敗に対処する話（本番環境で不具合を起こした1年目の体験談）



# 目次

[1. はじめに](#1はじめに)
[2. 自己紹介と当時の状況](#2自己紹介と当時の状況)
[3. 失敗した話](#3失敗した話)
[4. 原因と対策](#4原因と対策)
[5. まとめ](#5まとめ)
[6. 最後に](#6最後に)

# 1.はじめに

[WHIの7つの「Value」に沿ったエピソードを語ってください！ by Works Human Intelligence Advent Calendar 2022](https://qiita.com/advent-calendar/2022/works-hi-2) に参加しています。
本記事は11日目の記事となります。

WHIさんは「7つのValue」を掲げています。

- Work fun! 「遊び心で仕事を楽しむ」
- Ownership「当事者意識を持ってやり切る」
- Respect「一緒に働く仲間とお客様を尊重する」
- Know our Customers「お客様の価値を創造する」
- Solve「本質を追求し問題を解決する」
- Honor the Challenge「失敗を恐れず挑戦する」
- Integrity「品格を持って誠実に取り組む」

今回はその中から

> Honor the Challenge「失敗を恐れず挑戦する」
>

に焦点を当て、業務での振り返りを記事にまとめます。


# 2.自己紹介と当時の状況

- 自社サービスに携わるバックエンドエンジニア
- 入社して数か月の状態。比較的、難易度が低い実装を担当。


# 3.失敗した話

タイトルに記載しましたが、本番環境にアップ後に不具合を起こしました。

①実装の内容

- 複数のテーブルを結合する。結合したテーブルに条件を指定して該当のデータを取得し、画面に表示する。
- 取得したデータによって画面に表示する内容を変える。

②できていなかったこと

- SQL文の条件漏れ→絞り込みができていなかった
- IF文で`false`の場合の処理の記載漏れ→表崩れが発生した

影響範囲はチームメンバー内と、比較的最小限で済んだことが不幸中の幸いでした。

チームの先輩からの報告で不具合に気づき、現在は修正済みです。


# 4.原因と対策

①コードの理解不足

内容を理解せず、**「なんとなく動いた」** 状態で進めてしまいました。

:::note warn
対策
不明点は確認し、理解したうえで実装を行う
:::

②参考資料を活用しない

SQL文に関しては先輩に考えてもらい、実装に組み込んだのですが手入力で作業を行いました。
その結果、条件の指定が抜けていました。
思い込みで作業すると、ミスを誘発する可能性があります。

:::note warn
対策
- コピーペーストを行う
- スペルミス対策として、スペルチェッカーを使用する
:::


参考： VScode Code Spell Checker

https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker


③動作確認が不十分

今回の実装では画面表示が数ページに渡る内容でした。

最初の数ページを確認して「問題がない」と判断をしていました。

:::note warn
対策
全データ・想定されるデータでの確認を行う
:::



# 5.まとめ

失敗したときに「対処する方法を学ぶ機会だ」と気持ちを切り替えて、
できることを行うことが大切だと思います。

今回の経験を踏まえて、
何が起きても対処できるよう成長していきたいと思います。


# 6.最後に

何かありましたら、ご意見やご感想をいただけると幸いです。
読んでいただき、ありがとうございました。
非同期処理がよくわかっていなかった話

# VUEでバックエンドにフォームバリデーションAPIを投げるときの注意
## 困ったこと
バックエンドにフォームのバリデーションを投げ、
返ってきた結果をもとに次の画面に進むか今の画面にとどまるかを分岐させたい。
しかし、APIのバリデーションチェックはOKでもなぜか画面遷移せず、
ボタンをもう一度押したときに画面遷移する。
以下が実際のコード。
※APIを投げる部分にはaxiosを使用
```
<script lang="ts">
//
const name=ref<string>('satoutarou')
let validationResult=ref<boolean>(false)

//バリデーションチェックAPIを使用する関数
async function checkVaridatesAPI (){　　
    try {
        //APIでユーザ名のチェック
        const res = await axios.post("/usernameapi",{
        "username": name.value,
        })
        //チェックOKならvalidationResultにTrueを代入
        validationResult.value = true;
    } catch (err) {
        //チェックNGならvalidationResultにFalseを代入
        validationResult.value = false; 
    }

//次の画面へボタンを押したときに実行される関数
async function Validation() {　　　
    //↑の関数を実行(結果の真偽が変数に入る）
    await checkVaridatesAPI();    
    //結果をもとに次の画面を遷移するor今の画面にとどまる        
    if(reserveValidationResult.value){
        router.push({name:'nextpage'});
    }else{
        router.push({name:'nowpage'});
        
    }
}
<script>
<template>
    <button v-on:click="Validation()" type='button'>次の画面へ</button>
</template>

```

## 非同期処理というものを理解していなかった
JavaScriptやTypeScriptは非同期言語と呼ばれ、処理を上から順に実行してくれても1処理ごとに完了を待ってくれるわけではない。
そのためcheckVaridatesAPIで非同期処理を加えて動くものだと思っていたが…  

上記のコードの場合
`checkVaridatesAPI();`
の実行結果を待たずにその下のIF文に進んでしまい、
`let validationResult=ref<boolean>(false)`
にて変数の初期値としてfalseが設定されているため、
`router.push({name:'nowpage'});`
の処理が実行されてしまった。
※すべて完了したころにAPIの結果が代入されるため2回目以降のボタン押下では次のページへ遷移できる。
## async awaitを追加
以下が非同期処理を加えて改良したコード
```
<script lang="ts">
//
const name=ref<string>('satoutarou')
let validationResult=ref<boolean>(false)

//バリデーションチェックAPIを使用する関数
const checkVaridatesAPI (){　　
    try {
        //APIでユーザ名のチェック
        const res = await axios.post("/usernameapi",{
        "username": name.value,
        })
        //チェックOKならvalidationResultにTrueを代入
        validationResult.value = true;
    } catch (err) {
        //チェックNGならvalidationResultにFalseを代入
        validationResult.value = false; 
    }

//次の画面へボタンを押したときに実行される関数
const  Validation() {　　　
    //↑の関数を実行(結果の真偽が変数に入る）
    checkVaridatesAPI();    
    //結果をもとに次の画面を遷移するor今の画面にとどまる        
    if(reserveValidationResult.value){
        router.push({name:'nextpage'});
    }else{
        router.push({name:'nowpage'});
        
    }
}
<script>
<template>
    <button v-on:click="Validation()" type='button'>次の画面へ</button>
</template>

```
ゲーム等で物語を楽に書くように新スクリプト言語「KoeScript」を作ってみた

今回の記事は約一年間かかりました開発の結果についてです。

簡単いうと、ゲーム等のなかで長い話を書く用の新しいスクリプト言語でございます。目的が物語を書くから「声」の漢字からKoeになってScriptを合わせKoeScriptになりました。GitHubでオープンソースとして登場しました。
よければ[KoeScript公式サイト](https://komanaki.github.io/koescript/)それとも[KoeScriptリポジトリ](https://github.com/komanaki/koescript/)をご覧ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1564614/09920ecd-6648-4c7a-6474-1431d5b058ea.png)

## 言語を作るの理由

現在は話用のスクリプト言語が多いので、どうして新しい言語を作ろうって思いましたか。その理由が三つであり。

1. こよなく、言語がいつもあるエンジンやあるソフトと繋がって、他の環境で使用できません。
2. 普通のスクリプト言語の書き方が難しし、論理が強すぎて誰でもはあまり使えません。
3. 特にノベルゲーム制作だと、使える言語は使えろエンジンやプラグインによる。

この状況で、誰でも書けると読めるスクリプト言語の開発を決めました。その上、初心者プログラマーが手伝えるようにソードコードが簡単に書きました。

## 機能の一覧

KoeScriptを利用したファイルでは、3つ類の事を書くことができます。

1. まずはもちろん「メッセージ」です。誰かのキャラが言うのセリフが書けます。
2. あとは「関数の呼ぶ」です。ゲームで効果ができるように、関数が呼べます。例えばキャラを画面に見せるか、音楽や効果音をするか、壁紙を変更するか。
3. そして話に大事なところをマークするために「ラベル」が置いとけます。

そのおかげで、どんなノベルゲーム通りに話が進んで、ゲームに影響ができます。

## スクリプト例

下記はKoeScriptの簡単の例でございます。

```r
# これはコメントですね。
# まずは日付を表示しましょう。
@date "31/01"
# これで音量の80パーで音楽を再生しましょう。
@bgm "lonely_moon" volume=0.8

# 壁紙を変更するように関数を呼び。薄りながら下から上まで滑る。
@bg "school_corridor" fade translate="up"

#　下記からのイベントをマークようにラベルを置きましょう。
*firstmeetingwithguide

# "guide"と申すキャラが「Hello!」と言います。
guide : Hello!

# キャラの名前が書いてなくたら、従前のキャラがまた話すっていう意味です。
How are you?
```

ただのセリフはいつもメッセージとして認めて、@マークから始める行が関数呼びとして認めます。

関数を呼びながら、もちろん引数も書けます。これからは音楽をかける`bgm`関数を例として使いましょう。

```c#
[KoeFunction]
public void Bgm(string name, float volume = 1) {
    // 関数の内容
}
```

KoeScriptでは、位置引数も省略可能な引数も伝えます。位置引数`name`は望んでいる音楽の名前、そして`volume`省略可能な引数は音量ですね。

```r
# 位置引数の場合は、正しい位置で値を書いと置いて
@bgm "super_song"

# 省略可能な引数の場合は、引数の名と値を`=`で区切られた書いて置いて。
@bgm "mega_song" volume=0.7
```

## 基本的にどう使えるの？

KoeScriptの中心は、[KoeScript言語の参考](https://github.com/komanaki/koescript/blob/main/Language-Reference.md)です。今でもプロジェクトの第一です。この参考による、インタープリタ方式で最初のC#実装ができました。構文が簡単なので、他の言語で実装を開始したら速くできると思います。

その上、KoeScriptが色々別のゲームやアプリに実装されたら、どこでも同じ使い方があるように共通の関数とタグが決めました。例えば壁紙を変更ために呼ばれる関数があったら、「共通の関数」の`@bgm`による書いたら楽になります。それとも話のセリフにふりがな表示したい、「共通のタグ」がすでにやり方が決めました。

特にいつか新しいKoeScript向けのアプリやプラグインができたら、その共通の関数とタグを理解できたら、KoeScriptを使っているゲームやアプリにすぐ役に立てます。

上記のドキュメントたちがGitHubで見つかれるから、いつか言語が進化したいなら誰でも更新を提案できます。

ただいまKoeScriptに関する実装は：

* [**koescript-cs**](https://github.com/komanaki/koescript/tree/main/koescript-cs) : C#言語で原初実装
* [**koescript-unity**](https://github.com/komanaki/koescript/tree/main/koescript-unity) : Unityエンジン向けパッケージ
* [**koescript-vscode**](https://github.com/komanaki/koescript/tree/main/koescript-vscode) : Visual Studio Code向け拡張機能

## 生きている言語へ

言語の開発って普通に難しい領域のですが、最初から簡単に行こうと決めたから初心者プログラマーなどでも参加できて自分のプロジェクトに利用して、それにてKoeScriptが真面目に言語になるチャンスがあると思います。

GitHubにどんな提案でもが出来たら良かったです。ご遠慮なくよろしくお願いします。

---

読んでいただきありがとうございます。このトピックで話したいなら、ツイッターは[@komanakun](https://twitter.com/komanakun)、Wantedlyは[こちら](https://www.wantedly.com/id/michaelhubert)、LinkedInプロフは[こちら](https://www.linkedin.com/in/michaelhubertme/)です。
DoctrineとEloquent比較大全8: リレーション先テーブルのデータを利用

day8の今日はday7で定義したリレーション先テーブルのデータを利用する方法を見ていきます。

## Doctrine

```php
<?php

declare(strict_types=1);

use App\Entity\Author;
use App\Entity\Book;
use Doctrine\ORM\EntityManagerInterface;

require __DIR__.'/../vendor/autoload.php';

/** @var EntityManagerInterface $entityManager */
$entityManager = require __DIR__.'/bootstrap.php';

$book1 = $entityManager->getRepository(Book::class)->find(1);
echo $book1->getAuthor()->getName(); // Authorのnameを見ることができる

$author1 = $entityManager->getRepository(Author::class)->find(1);
// $author1の著作タイトルをすべて表示
foreach ($author1->getBooks() as $book) {
    echo $book->getTitle().PHP_EOL;
}
```
<https://github.com/77web/doctrine-vs-eloquent/blob/f35c85cce094c389ca54689ca86925e58c66d3ce/Doctrine/Usecase/join.php>

## Eloquent

```php
<?php

declare(strict_types=1);

use App\Models\Author;
use App\Models\Book;

require __DIR__.'/../vendor/autoload.php';

$book1 = Book::find(1);
echo $book1->author->name; // Authorのnameを見ることができる

$author1 = Author::find(1);
// $author1の著作タイトルをすべて表示
foreach ($author1->books as $book) {
    echo $book->title.PHP_EOL;
}
```
<https://github.com/77web/doctrine-vs-eloquent/blob/f35c85cce094c389ca54689ca86925e58c66d3ce/Eloquent/Usecase/join.php>

- Doctrineと違い、リレーション定義時に定義したのは `author()` `books()` メソッドでしたがデータを読み取るのは `author` `books` プロパティになる点に注意が必要です。
Go のバージョンを上げたら gRPC のコード差分が出てきた件

## gRPC のコード差分

仕事で Go を使って gRPC の開発をしているとき、 同じ `*.proto` から生成された `*.pb.go` ファイルが人によって差分が生じるという問題が起こりました。

出てくる差分というのは、下記のように整形されていないコメントがあったとき、これから生成される `*.pb.go` 内のコメントが整形されたりされなかったりするというものです。

```proto:person.proto
syntax = "proto3";

option go_package = "example.com/person";

//    Person はプロフィールを表すメッセージです。
message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;
}
```

```go:ある人の person.pb.go
//    Person は人のプロフィールを表します。
type Person struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Name  *string `protobuf:"bytes,1,opt,name=name,proto3,oneof" json:"name,omitempty"`
	Id    *int32  `protobuf:"varint,2,opt,name=id,proto3,oneof" json:"id,omitempty"`
	Email *string `protobuf:"bytes,3,opt,name=email,proto3,oneof" json:"email,omitempty"`
}
```

```go:他の人の person.pb.go
// Person は人のプロフィールを表します。
type Person struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Name  *string `protobuf:"bytes,1,opt,name=name,proto3,oneof" json:"name,omitempty"`
	Id    *int32  `protobuf:"varint,2,opt,name=id,proto3,oneof" json:"id,omitempty"`
	Email *string `protobuf:"bytes,3,opt,name=email,proto3,oneof" json:"email,omitempty"`
}
```

## 差分が出る原因

調べてみたところ、どうやら Go 1.19 を使うかどうかでコメントが整形されるかどうかの挙動が変わるようでした。リリースノートを読んでみると下記の通り `gofmt` がコメントを整形するようになったことが原因のようです。

> Doc Comments
Go 1.19 adds support for links, lists, and clearer headings in doc comments. As part of this change, gofmt now reformats doc comments to make their rendered meaning clearer. See “Go Doc Comments” for syntax details and descriptions of common mistakes now highlighted by gofmt. As another part of this change, the new package go/doc/comment provides parsing and reformatting of doc comments as well as support for rendering them to HTML, Markdown, and text.

つまり別に gRPC を使ってなくても単に Go ファイルを整形すれば、これまで未整形だったコメントは整形されるようになるということです。

gRPC のコメントが整形されるかどうかは `protoc-gen-go` をインストールする際にどの Go バージョンでインストールしたかで変わってきます。

```bash
# go が 1.19 以上ならコメントが整形される
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
```

## 対策

根本原因は `*.proto` ファイルのコメントが整形されていないことなので、まずはこれを整形してあげたいところです。

`*.proto` ファイルの整形は `clang-format` を使えばできるのですが、残念ながらコメントの整形には対応していないようです・・・

https://clang.llvm.org/docs/ClangFormat.html

仕方がないので gRPC を生成するときだけ Go のバージョンを開発者全員で統一することにしました。

```bash
$ go install golang.org/dl/go1.18.9@latest
$ go1.18.9 download
$ go1.18.9 install google.golang.org/protobuf/cmd/protoc-gen-go@latest
```

## まとめ

`*.pb.go` は自分で整形するファイルじゃないので、原因特定で結構ハマりました。まさか `protoc-gen-go` をビルドした Go バージョンで差分が出るとは・・・
Dependabotを採用してAnsible lintを自動的にアップデートしていく

こちらの記事は[Ansible lint Advent Calendar 2022](https://qiita.com/advent-calendar/2022/ansible-lint) 9日目の記事になります。

今回は作成したAnsibleコンテンツに対してAnsible lintをどのようにバージョンアップをしていくかを考察します。

Ansible lintをバージョンアップさせる方法はいくつかあるかと思います。今回は[Dependabot](https://docs.github.com/ja/code-security/dependabot)によるバージョンアップについて解説します。

### Dependabotによるバージョンアップ

リポジトリサービスにGitHubを利用している事が前提になりますが[Dependabot](https://docs.github.com/ja/code-security/dependabot)と言う依存関係を解決するためのサービスが提供されています。このサービスを利用する事によりAnsible lintをはじめとするライブラリを自動でアップデートすることができます。

#### 良い点

* 手軽に導入できる
* テストに利用したライブラリのバージョンをコードで明示できる
* ほぼ自動で依存関係がバージョンアップされる（競合が発生しても[Dependabot](https://docs.github.com/ja/code-security/dependabot)により多くは解決される）

#### 悪い点

* GitHubを利用している事が前提
* 常に最新版のAnsible lint、Ansibleで動作確認を行うためAnsibleのバージョンの固定が煩雑になる

### Dependabotによるアップデートを行う例の解説

[Dependabot](https://docs.github.com/ja/code-security/dependabot)を利用してAnsible lintを継続的にアップデートしていく[サンプル](https://github.com/samples-mamono210/cowsay)です。

`.github/dependabot.yml`で継続的にアップデートを行うライブラリの種類を設定します。今回はActionライブラリとpipを指定します。

```yaml:.github/dependabot.yml
---
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "daily"
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "daily"
```

今回のサンプルではテストフレームワークにMoleculeを採用しています。`molecule/requirements.txt`へテスト実行時に利用するライブラリのバージョンを記載します。[Dependabot](https://docs.github.com/ja/code-security/dependabot)はpipライブラリと`molecule/requirements.txt`を監視しpipライブラリの方でバージョンアップがあったら`molecule/requirements.txt`を更新するようにpull requestを作成します。

```text:molecule/requirements.txt
ansible==7.1.0
ansible-lint==6.9.1
molecule==4.0.4
molecule-docker==2.1.0
```

`molecule/requirements.txt`を参照する事により対象のプロジェクトがどのバージョンのAnsible / Ansible lintで動作確認がされているのか確認できます。

### そもそもAnsible lintのバージョンは上げるべきなのか？

判断が難しい部分かと思います。Ansible lintの性質上、[Ansible Community Package](https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html)へ依存しておりAnsible lintのバージョンだけ上がっても[Ansible Community Package](https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html)のバージョンが同時に上がらないと解決が難しい不具合が起きる可能性があります。

一番良いのはリリース・デプロイ環境等で実行する[Ansible Community Package](https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html)のバージョンに合わせて採用するAnsible lintのバージョンも`同時期にリリースされたバージョンに合わせる`ことかと思います。


### 参考サイト

* [samples-mamono210/cowsay | GitHub](https://github.com/samples-mamono210/cowsay)
【Playdate】クランクでプレイヤーを動かしてみる

[前回](https://qiita.com/sada_lp1/items/3010d86f71e54284559b)のクランク通知をベースにして、クランクを動かすとプレイヤーも動くように調整してみましょう。

![sample_crank.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/a71372f6-eec1-5ee3-8c8a-ce5e1d10a068.gif)

```
import "CoreLibs/object"
import "CoreLibs/graphics"
import "CoreLibs/sprites"
import "CoreLibs/timer"

import "CoreLibs/ui"

local gfx <const> = playdate.graphics

local playerSprite = nil

local distanceFromCenter <const> = 60 -- 中心からの距離

function myGameSetUp()

	local playerImage = gfx.image.new("Images/playerImage")
	assert( playerImage )

	playerSprite = gfx.sprite.new( playerImage )
	playerSprite:moveTo( 200, 120 )
	playerSprite:add()

	local backgroundImage = gfx.image.new( "Images/background" )
	assert( backgroundImage )

	gfx.sprite.setBackgroundDrawingCallback(
		function( x, y, width, height )
			backgroundImage:draw( 0, 0 )
		end
	)
	
	playdate.ui.crankIndicator:start()

end

myGameSetUp()

function playdate.update()

	if playdate.buttonIsPressed( playdate.kButtonUp ) then
		playerSprite:moveBy( 0, -2 )
	end
	if playdate.buttonIsPressed( playdate.kButtonRight ) then
		playerSprite:moveBy( 2, 0 )
	end
	if playdate.buttonIsPressed( playdate.kButtonDown ) then
		playerSprite:moveBy( 0, 2 )
	end
	if playdate.buttonIsPressed( playdate.kButtonLeft ) then
		playerSprite:moveBy( -2, 0 )
	end

	gfx.sprite.update()
	playdate.timer.updateTimers()
	
	if playdate.isCrankDocked() then
		playdate.ui.crankIndicator:update()
	else
        local angleRad = (playdate.getCrankPosition() -90) * ( math.pi / 180 )  -- radianを格納
        local x = distanceFromCenter * math.cos(angleRad) + 200 -- x座標
        local y = distanceFromCenter * math.sin(angleRad) + 120 -- y座標
        
        playerSprite:moveTo(x, y)
	end


end
```

`playdate.getCrankPosition()`で現在のクランクの角度を取得しています。
Playdateのクランクは真上が「0」となるので、ラジアンを求める際「-90」で起点を調整しています。
あとは通常通りの三角関数によって座標を計算し、`playerSprite:moveTo(x, y)`で座標に移動しています。
【PowerShell】関数のswitchパラメーター

# はじめに

先日に職場で見かけたPowerShellのコードで、関数のパラメーターに「switch」という見慣れないデータ型が指定されていました。
私が今まで使ってきた言語では見たことがないデータ型だったので、今回は「switch」というパラメーターについて調べた結果をまとめてみました。

# switchパラメーターとは？

* [こちらの記事](https://www.itlab51.com/?p=5968)には、「switch パラメータは引数の値が指定されなくてもその、引数名が指定されたかだけで判断します」と書かれています。
* 前回の記事では`-パラメーター名 {値}`という書き方をしましたが、`-パラメーター名`だけで引数が指定されたことになるようです。

https://qiita.com/nkojima/items/4489f33cfc1fb3cbaece#%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC%E4%BB%98%E3%81%8D%E3%81%AE%E9%96%A2%E6%95%B0

# switchパラメーターの使い方

* パラメーターに`[string]`などのデータ型の代わりに、`[switch]`と指定します。
* switchパラメーターはブール値（Boolean型）と同じように扱えるので、if文でパラメーターがセットされているかどうかを判定できます。
* 関数の呼び出し側では、switchパラメーターの変数名にハイフンを付けた`-japanese`というパラメーターを指定しています。
  * 関数を呼び出す側で`$true`/`$false`を指定するよりも、switchパラメーターを使った方が「何の処理に使われるパラメーターなのか」ということが推測しやすくなるので、コードの可読性が上がると思います。


```powershell:switchパラメーター付きの関数の例
function SayHello {
    param([switch]$japanese)

    if ($japanese) {
        Write-Host "こんにちは"
    } else {
        Write-Host "Hello"
    }
}
```

```text:実行結果
> SayHello -japanese
こんにちは
> SayHello
Hello
```

# 参考URL

* [PowerShell - ファンクションの引数で switch パラメータを使用する](https://www.itlab51.com/?p=5968)
* [about_Functions_Advanced_Parameters (PowerShell 5.1)](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_functions_advanced_parameters?view=powershell-5.1)
* [PowerShellで自作関数を作る](https://qiita.com/nkojima/items/4489f33cfc1fb3cbaece#%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC%E4%BB%98%E3%81%8D%E3%81%AE%E9%96%A2%E6%95%B0)
AWSマネジメントコンソールのデフォルトリージョンの設定（東京: ap-nurtheast-1）

#　はじめに
各種AWSサービスを構築する際に、間違って東京リージョン以外のリージョンで作ってしまったことはないでしょうか。
本記事は、1分でできるリージョンのデフォルト設定について、記述したいと思います。

# デフォルトのリージョンの設定方法

AWSのマネジメントコンソールの右端の「設定」を押下します。

![スクリーンショット 2022-12-07 23.59.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/766039/95958f14-8ed6-3f11-4948-62f93215267e.png)

デフォルトのリージョンのフィールドが初期設定だと、「最後に使用したリージョン」となっているため、
よく使用するリージョンに設定して保存します。

![スクリーンショット 2022-12-08 0.02.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/766039/bfe033bf-eacb-1f1b-dea1-3bbadc1db8f3.png)
Sudachi バイナリ辞書の中身をダンプする

## はじめに

以前、形態素解析器 Sudachi の辞書バイナリからコメントや作成日などの[ヘッダ情報をダンプする方法](https://qiita.com/kazuma-t/items/265b11ef6946a186339f)を紹介しました。今回は辞書バイナリから収録されている語の情報を (おおむね) 出力する方法を紹介します。

## 収録語のダンプ

収録されている語の情報を出力するためには `DictionaryPrinter` をつかいます。

```bash
$ java -cp sudachi-0.6.3.jar:jdartsclone-1.2.0.jar com.worksap.nlp.sudachi.dictionary.DictionaryPrinter system_core.dic
 ,5967,5967,10, ,空白,*,*,*,*,*,キゴウ, ,*,A,*,*,*
!,5970,5970,1055,!,補助記号,句点,*,*,*,*,キゴウ,！,*,A,*,*,*
#,5969,5969,2588,#,補助記号,一般,*,*,*,*,キゴウ,＃,*,A,*,*,*
$,5969,5969,2784,$,補助記号,一般,*,*,*,*,キゴウ,＄,*,A,*,*,*
%,5969,5969,3197,%,補助記号,一般,*,*,*,*,キゴウ,％,*,A,*,*,*
&,5969,5969,2098,&,補助記号,一般,*,*,*,*,アンド,&,*,A,*,*,*
*,5969,5969,4462,*,補助記号,一般,*,*,*,*,キゴウ,＊,*,A,*,*,*
+,5969,5969,2072,+,補助記号,一般,*,*,*,*,キゴウ,＋,*,A,*,*,*
.,-1,-1,0,.,名詞,普通名詞,一般,*,*,*,コンマ,コンマ,*,A,*,*,*
...
```

ユーザー辞書の場合は以下のようにユーザー辞書を作成したときのシステム辞書を指定する必要があります[^1]。

```bash
$ java -cp sudachi-0.6.3.jar:jdartsclone-1.2.0.jar com.worksap.nlp.sudachi.dictionary.DictionaryPrinter -s system_core.dic user.dic
```

[^1]: ユーザー辞書はシステム品詞の情報をもっていないため。

## 辞書ソースとの相違

出力された情報はおおむね辞書ソースにちかいものですが、何点かちがいがあります。

### 見出し (TRIE 用) が正規化されていない

[つかっていないカラムの話その1](https://qiita.com/kazuma-t/items/59f5ea7a3ff5e5fb41d1)で説明した0カラム目と4カラム目の話ですが、このツールの出力は両方4カラム目になっています。辞書構造上0カラム目の情報はダブル配列で実装された TRIE 中にしかなく、キーを再現するには TRIE を葉からたどる必要があり取り出すのが面倒だからです。

### 分割情報が ID 表記になっている

内部的には ID で保持されているのでそれをそのまま出力しています。v1.0 以降では構成語情報表記が必須になる予定なので、そのうち直します。

### 同義語グループ ID が出力されていない

同義語グループ ID が導入される前につくったツールなので追随させるのをわすれていました。そのうち直します。

## まとめ

Sudachi の辞書バイナリは `DictionaryPrinter` をつかって中身をみることができます。辞書作成時のソースとは一部ことなるところもありますが、辞書の中身を確認したり、元ソースをなくしてしまったときの復元などにご利用ください。

ではよい Sudachi life を。
continue文は結局続けるの？続けないの？？

# はじめに
はじめまして！
NE株式会社 開発統括部のはやしまきです。

エンジニアのみなさん、タイトルを見てこいつ何言ってんだとなっていることでしょう。

すんごい今更なのですが、
コードを読んでいる際、continue文を見ると
「continueって結局続けるんだっけ…？」とよくわからなくなるときがあります。

ここはスキップだよな…と思いながらも心配になり、リファレンスを開くというのを何度もやってます。リファレンスをブクマしておいた方がいいですね。お守りです（？）

意味をもぐもぐ咀嚼し、納得して、もう開かなくていいように記事に残します。
一緒にもぐもぐできたら幸いです！

この記事は、[NE Advent Calendar 2022](https://qiita.com/advent-calendar/2022/ne) 8日目の記事です。

# なぜ勝手に混乱してるのか

- 英単語の"continue"は「継続する」の意味
- for文などのループ構造で用いられた際、スキップの指示する

おいおいおい、継続するんかやめるんかどっちや…
どこまでをやって、どこからはやらないのか…

となりました。多分私ぐらいです。

# continue文とは

continue文は、ループ構造において書かれた後の残りの処理を**スキップ**し、**次のループの最初からまた続けて**処理をします。

```php:例
<?php
for ($i = 0; $i <= 5; $i++) {
    if ($i === 3) {
        continue;
    }
    echo $i . PHP_EOL;
}
```

```php:結果
0
1
2
4
5
```
このように、3のときは```echo```での出力をスキップし、ループをやめることなく5週目のループに入っています。

continueがある条件のときは「ここでやーめた！」となるわけですね。

リファレンス：[continue文](https://www.php.net/manual/ja/control-structures.continue.php)

## continueの前後の処理はどんな感じ？

continueが書かれている前と後ろに処理を入れてみます。

```php:例
<?php
for ($i = 0; $i <= 5; $i++) {
    if ($i === 3) {
        echo '< ヤッホー！' . PHP_EOL;
        continue;
        echo 'やっほー！ >' . PHP_EOL;
    }
    echo $i . PHP_EOL;
}
```
```php:結果
0
1
2
< ヤッホー！
4
5
```

continueの前に書かれてあるものは処理されますが、後に書かれたものは処理されませんでした。
挨拶が返ってくることはなかったですね。。虚無

同じ条件式内でcontinueの後にいくら処理を書いても無視されてしまいます。
条件式内の一番最後に書くことになりますね。

# 結論

continue文は、
**ループ内の処理はやめるけど、ループは継続する**

「ここでやーめた！はい次行って！」と言ってるイメージです。
よくよく考えるとリファレンス等の"スキップ"の表記がぴったりで、納得します。

……んじゃもう名前```skip```でよくね？？

# 英単語"continue"の意味は「継続する」だよな……？

私の思ってる「継続する」じゃない可能性も無きにしもあらずだなと思い、英単語の意味も見てみました。

>continueとは
>(間断なく)続ける、継続する、持続する、(…し)続ける、続ける、(…を)(中断後また)継続する、断続する、(中断後に)続ける、(…と)引き続いて言う、(…に)継続させる

引用：[Weblio英和辞書](https://ejje.weblio.jp/content/continue)

ふむふむ、やっぱり「続ける、継続する」だな……

……

んんん？

>(…を)(中断後また)継続する、断続する、(中断後に)続ける

！！！！！！

**「中断後に続ける」！！！！！！**

英単語って深いですね。
この処理を```continue```と命名した人の気持ちがわかりました。

# おわりに

私の心配のもとであるcontinue文について調べてから納得するまでを書きました。

単純な処理でも、さっと書いて実行してみると、より納得して頭に入りますね。

さらに、英単語の知識もつきました。
普段何気なく使ってる構文の英単語を辞書で見てみると、新たな学びがありそうです！
聴覚障害がある学生がハッカソンに参加して困ったこと

# はじめに
こんにちは。ふじえもんと申します。

聴覚障害があります。伝音性難聴で、音が小さく聴こえるという特徴があり、骨導補聴器と呼ばれる補聴器を使って、「骨から音を聴いて」います。
現在、とある大学の3年次です。(どこの大学かは、聴覚障害のことをある程度知っている方であればお察しいただけるかと。)


今日は、以前参加したハッカソン([技育CAMP8月vol.7](https://talent.supporterz.jp/geekcamp/))に参加して困ったことについてお伝えします。

ハッカソンの成果物に関する技術的な話はここではしませんので悪しからず。
もしご興味があれば、こちらの[note](https://note.com/fujiemon_tad/n/n244aa6e76df5#26b7e0d6-4a01-4511-b723-decb40f168f3)をご覧ください。(大変長いので、読むときはお時間の余裕があるときに。)

今回は5分で読み終えるようなボリュームにしました！

# 困ったこと
聴覚障害があると、どこに行ってもとにかくコミュニケーションで困ります。

聴覚障害といっても、聴こえの程度は人それぞれで全く聴こえない人もいるし、補聴器を使えばある程度は相手の発言内容がわかる、補聴器を使うほどではないけど、聴こえにくい人もいます。

現在、聴覚障害に対する**情報保障**(=障害がある人が情報を入手する際に、その場にいるすべての人と同じように**情報**を受け取れるようにすることを言います。)としては、字幕(文字通訳、文字起こし)や手話通訳などがあり、コミュニケーションに関しては、それに加え筆談やチャットなどを使い、**文字**で情報のやり取りをする方法もあります。

※以下、当事者(同期)の同意、確認を貰っています。

で、ハッカソンに参加して何が困ったかというと、情報保障が無かったために、(一緒に参加した同期が)**十分に情報を受け取れなかった**ことです。

それは、チーム開発にも大きく影響が及んだ(詳細は[note](https://note.com/fujiemon_tad/n/n244aa6e76df5#26b7e0d6-4a01-4511-b723-decb40f168f3)参照)し、ハッカソン全体でも、**誤字脱字が含まれているであろう大量の文章**から、意図を読み解き、発言内容を**推測**するという、ただでさえ、短い時間での開発という重い重い負荷があるのに、精神的にも目にもキツイ処理をずっとしていました。(スマホで音声認識をしていたようです。使用アプリについては主旨から逸れるので触れませんが、音声認識というよりは「音声入力」と書いた方が適切でした。収音環境としてPCスピーカーから音を出していたので精度はそんなに良くなかったです。)


ただ、運営に完全に非があると言いたいわけではありません。

自分たちが、その必要があること、文字起こし等をして欲しい旨説明していなかったため、自分たち自身にも反省すべき点はあります。

この経験から、まだまだ、「自分たち自身で声を上げないと/自分から交渉しないと、[情報保障](https://note.com/fujiemon_tad/n/n2bbf7fd2fd98)は用意して貰えない」と実感しました。

本イベントに限らず、ありとあらゆるイベント、催しでいつでもどこでも誰もが、(参加者がそのようなことを一々考えずとも)**気軽にイベントに飛び込めるような環境**になって欲しいと**強く**願っているので、今回この記事を発信することにしました。

とくに、**企業や企画・運営をされている方**にご一読いただきたいです。
なので、拡散、共有してくだされば大変有難いです。

# さいごに
「ハッカソン」という文化は非常に素晴らしいものだと思います。
モノづくりやチーム開発、競い合いなどといった**色んな楽しさを気軽に経験できる**、そんな「場」があれば、もっといろんな学生が参加しやすくなるんじゃないかなあと思いました。

聴覚障害に限らず、聴覚情報処理障害(APD)がある方もいらっしゃいますし、音声より文字の方が情報を得やすい聴者だっていらっしゃると思います。通信不良があったときや、途中参加する場合でも、過去のログを参照できれば助かる方もいらっしゃると思います。

他にもエンジニアを目指す学生にとって魅力的なコンテンツもたっくさんあります。実際、技育祭は2回フルで参加しました。(情報保障は無かったですが..) いろんな方のいろんな経験、話が聞けるので、本学の学生、とくに後輩にオススメしたいのですが、今のままではオススメしにくいです。。


二度とこのような経験は他人、とくに後輩にはしてほしくない。

そう願いながら、この辺で今日は失礼します。
ここまで読んでいただきありがとうございました。

今日は、障害者週間の最終日とのことで、**障害に関する一つの啓蒙のきっかけ**となれば幸いです。

ぜひ、皆さんの周りにも拡散、紹介してくれると、ふじえもん喜びます。ﾜｲﾜｲ



本記事の内容に関して、ご質問、気になる点などありましたら、どなたでも[Twitter](https://twitter.com/fujiengineer)のDM、コメントにてお待ちしております。
リツイートなどでも構いません。

勿論、「このような状況のときにどのような情報保障をしたらいいか」などといったご相談にも、喜んでお答えいたします。(必ずしも完全な回答が出来るとは限りませんが、まずはご一報いただけるとお互いにWin-Winになるような情報交換が出来るかと思います。)




以上。　

文責:ふじえもん(2022/12/9)
(主張が激しすぎたと思わなくもない...)