OmniAICreator/Qiita-1.07M huggingface dataset:
mlflow.start_run(nested=True)を使わないRun間の親子関係の設定方法

## 目次
[1. はじめに](#はじめに)
[2. 親子関係がどのように設定されているか](#親子関係がどのように設定されているか)
[3. `nested`オプションを使わない親子関係の作り方](#nestedオプションを使わない親子関係の作り方)
[4. 参考文献](#参考文献)

## はじめに
mlflowは、機械学習プロジェクトの実験管理を容易にするツールです。特に、実験（Run）に親子関係を持たせて管理することで、複雑な実験の追跡と分析が簡単になります。
通常Runに親子関係を持たせたい場合は、`mlflow.start_run(nested=True)`とすればいいのですが、それが適用できない場面に遭遇したため、他の方法でRun間に親子関係を持たせる方法を調べることになりました。
この記事では、mlflowのRunの親子関係がどのように記述されているか、`nested=True`オプションを用いないで親子関係を持たせる方法をまとめています。

## 親子関係がどのように設定されているか
mlflowでは、```tags.mlflow.parentRunId```によって、Runの親子関係が記述されています。
例えば以下のコードをサンプルとして実行します。
```python
import mlflow

with mlflow.start_run() as parent_run:
    mlflow.set_tag("mlflow.runName", "parent_run")
    print(f"Parent run ID: {parent_run.info.run_id}")
    with mlflow.start_run(nested=True) as child_run:
        mlflow.set_tag("mlflow.runName", "child_run")
        print(f"Child run ID: {child_run.info.run_id}")


>>>
Parent run ID: 0bfac406f7084cd39c27d3274f1e39f2
Child run ID: ac358223146a437a8167badfdaa9c150
```
すると、
```txt
mlruns
└── 0
    ├── ac358223146a437a8167badfdaa9c150 <- Child Run
    │   └── tags
    │       └── mlflow.parentRunId  # 0bfac406f7084cd39c27d3274f1e39f2
    ├── 0bfac406f7084cd39c27d3274f1e39f2 <- Parent Run
    └── meta.yaml
```
のようにログが記録されます（各Runのディレクトリ内には、metricsやartifactsなどのディレクトリも生成されますが省略しています）。
このとき、Child runである、```ac358223146a437a8167badfdaa9c150```の中のtagsというディレクトリ内に```mlflow.parentRunId```という名前のテキストファイルが作成され、ここに書かれたidによって親子関係が識別できるようになっています。
今回だと```mlflow.parentRunId```の中身は、```Parent run ID```である```0bfac406f7084cd39c27d3274f1e39f2```となっています。
mlflow uiで見てみると、以下のように親子関係ができています。
![Pasted image 20240207121212.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296599/04844bd9-0db7-d805-3a13-897e9886cd0d.png)

## `nested`オプションを使わない親子関係の作り方
上記のことを踏まえると、
```python
with mlflow.start_run(nested=True)
```
のようにして、親子関係を作ることができない場合でも
```python
import mlflow

with mlflow.start_run() as run1:
    mlflow.set_tag("mlflow.runName", "run1")
    run1_id = run1.info.run_id
    print(f"Run1 ID: {run1.info.run_id}")

with mlflow.start_run() as run2:
    mlflow.set_tag("mlflow.runName", "run2")
    mlflow.set_tag("mlflow.parentRunId", run1.info.run_id)
    print(f"Run2 ID: {run2.info.run_id}")


>>>
Run1 ID: 3c4e15b063234ea7b2969c4c72141ef0
Run2 ID: 4d0dceb3f8e74c9bb1ba7951aec8b18d
```
とすることで、```run2```を```run1```のChild Runとすることが可能です。
mlflow uiを立ち上げてみると、以下のようにきちんと親子関係ができています。
![Pasted image 20240207121637.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296599/09547b0e-badd-7fee-4cd0-a9e817d5b086.png)

## 参考文献
[mlflow document](https://mlflow.org/docs/latest/python_api/mlflow.html)
Entity Frameworkでのキャッシュ挙動とAsNoTrackingの使用方法

Entity Framework（EF）は、.NET開発者にとって強力なORM（Object-Relational Mapper）ツールです。データベース操作を抽象化し、オブジェクト指向のアプローチでデータを扱うことができます。しかし、この便利さの陰で、EFのキャッシュ挙動によって予期せぬ問題が生じることがあります。

## Entity Frameworkのキャッシュ挙動
EFを使用する際、データベースから読み込まれたエンティティはデフォルトでコンテキストにキャッシュされます。これはChange Trackerと呼ばれる機能により、データベースとアプリケーションの間でオブジェクトの状態を同期します。通常、この機能はアプリケーションのパフォーマンスを向上させますが、最新のデータを反映することなく古いデータを再利用するという問題が生じることがあります。

※実際に、データベースの値と`Linq`で取得した値が異なる現象が発生しました。

## AsNoTrackingの役割
AsNoTrackingはEFのクエリに対して変更追跡を無効にするメソッドです。このメソッドを使用すると、EFはエンティティをキャッシュせず、各クエリでデータベースから直接データを取得します。これは、特に読み取り専用のデータを扱う際や、大量のデータを扱う際に有用です。

## AsNoTrackingの使用例
以下の例は、商品情報をデータベースから取得するシンプルなメソッドです。ここではAsNoTrackingを使用しており、キャッシュを利用せずに最新の商品リストを取得します。

```cs
public List<Product> GetLatestProducts()
{
    using (var context = new ProductDbContext())
    {
        var products = context.Products
                              .AsNoTracking()
                              .OrderBy(p => p.Name)
                              .ToList();
        return products;
    }
}
```

このコードでは、AsNoTrackingを使用することで、最新の情報が必要な読み取り専用の操作において、データの整合性を確保しています。

## まとめ
Entity Frameworkのキャッシュはパフォーマンス向上に寄与しますが、最新のデータが必要な場合や、大量のデータを扱う場合にはAsNoTrackingの使用を検討するべきです。AsNoTrackingを適切に使用することで、アプリケーションのデータ整合性とパフォーマンスのバランスを取ることができます。

## Reference
- [QueryableExtensions.AsNoTracking メソッド](https://learn.microsoft.com/ja-jp/dotnet/api/system.data.entity.queryableextensions.asnotracking?view=entity-framework-6.2.0)
バッチファイルで画像を順番にリネームして保存する方法

### 【記事の概要】
この記事では、バッチファイルを使ってPCフォルダ内の画像を順番にリネームしていく方法について説明しています。
<br>

### 【メリット】
今まで手動で1つずつファイル名を変更していましたが、このバッチを使えば大量の画像ファイルを一瞬で変更できるようになります。
<br>
### 【手順】
1. **画像をフォルダに移動:** まず、整理したい画像を一つのフォルダに集めます。
2. **メモ帳を開く:** 提供されたバッチファイルのコードをコピーします。
3. **コードのカスタマイズ:** フォルダのパスを自分の環境に合わせて変更します。
4. **バッチファイルとして保存:** コードをバッチファイル（.bat）として保存します。
5. **バッチファイルを実行:** 保存したバッチファイルをダブルクリックして実行します。
<br>

```bat:bat
@echo off			
setlocal enabledelayedexpansion			
			
cd /d "C:\Users\onecl\Desktop\test"			
set /a "count=0"			
			
for /f "delims=" %%f in ('dir /b /a-d /od *.webp') do (			
set "filename=image-!count!.webp"			
ren "%%f" "!filename!"			
set /a "count+=1"			
)
```
<br>


### 【各コードの簡単な説明】

```@echo off:```コマンドの実行結果以外を表示しないようにします。
```setlocal enabledelayedexpansion:```変数の遅延展開を有効にし、ループ内で変数の値を動的に更新できるようにします。
```cd /d "C:\Users\onecl\Desktop\test":``` 画像ファイルが保存されているディレクトリに移動します。このパスは、実際のフォルダの場所に応じて適宜変更してください。
```set /a "count=0":``` リネームしたファイルのカウント用の変数を0に初期化します。
```for /f "delims=" %%f in ('dir /b /a-d /od *.webp') do (...):``` フォルダ内の.webp形式の画像ファイルを古い順に処理するためのループを作成します。delims=は区切り文字を指定しないことを意味し、ファイル名にスペースが含まれていても正しく処理されます。
```ren "%%f" "!filename!":``` 各画像ファイルをimage-番号.webpの形式にリネームします。!count!変数を使って、リネームするたびにファイル名に連番を付けていきます。
[WordPress]フィールド名からカスタムフィールドを特定する方法

WordPressのテーマファイルを触る時にソースコード上のフィールド名がどのカスタムフィールドに対応しているか、見つけ方がわからなかったので共有します。

# カスタムフィールド(ACF)とは
カスタムフィールドとはAdvanced Custom Fields(ACF)と言い、管理者画面で任意の入力項目を追加することができるプラグインです。
↓こんな感じのやつ
![スクリーンショット 2024-02-07 11.54.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655001/79f702ed-5589-5d76-002d-3cdc4b448a41.png)
参考画像：https://lucy.ne.jp/bazubu/advanced-custom-fields-36452.html

# フィールド名からカスタムフィールドを特定
例えばテーマファイルに以下の記述があったとします。
```
<?php echo get_field('review_headline'); ?>
```
この`review_headline`がどのカスタムフィールドなのかを特定する方法が調べてもヒットせず、自分なりに見つけ方を編み出したのでそのやり方を共有します。
1. 管理者画面で検証ツールを開き、`review_headline`で検索する
このやり方で大体対応しているカスタムフィールドを特定できる。上記の記述が書いてあるファイルがどのページに表示されているものか特定し、そこから管理者画面に遷移する。そこで検証ツールを開き、検索窓(cmmand+f)で検索する、という調べ方です。


2. フィールド名からカスタムフィールドの名称を推測する
例えば今回の`review_headline`の場合、reviewの文字が入っているので口コミに関連するフィールドと推測できます。
なのでカスタムフィールドのフィールドグループで"口コミ"、"評価"など検索すればヒットする可能性があリマス。
正直これは正攻法ではなさそうなので最終手段として取っておこう。

　
こんなざっくりしたやり方でも特定できるのでぜひ参考にしてみてください。
プログラミング解説動画を出して感じたこと

2023年に、Vue.jsの勉強がてら、YoutubeにVue.jsの解説動画を投稿しました。
Vue.jsの基礎の解説から、TODOアプリの作り方を一通り解説し、Vue.jsが初めての人がアプリ開発をできるようになることを目標としています。
その動画を出す中で感じたことをまとめました。

ちなみに動画はこちら
https://youtu.be/7esDY8YIsQk?si=vJDNcQWLC44CkLFX

# 自分の勉強になる

よく人に教えることで自分の理解が深まると言われますがまさにその通りでした。
なんとなくの理解で使っていた文法なども、解説するにあたって「どうしてこうなるのか？」を知る必要があるので詳しく調べました。
ひととおりサンプルコードも自作したので、Vue.jsにおける色々な要素を確実に身に着けることができたと感じています。
また、動画にコメントで質問をもらうこともあり、それきっかけで自分の気づかなかった視点で調べることもできました。

# 綺麗なコードを書こうという気になる

一人で開発する分にはコードの綺麗さはそこまで重視されない（もちろん綺麗な方が保守性も高く良いですが）が、人に見られることを考えると綺麗に書こうという意識が持てました。
一回書いた後に、「もっと良い書き方はあるか」とchatGPTに聞いてみたりもしました。

# 同じ初心者の人と繋がれて嬉しい

コメントで「Vue.js勉強中です！動画ありがとうございます！」などと頂くことがあり、同じ初心者の仲間が自分の動画で勉強してくれているのが嬉しかったです。
普段会社の人とだけ関わっているとあまりわからないですが、世の中には自分と同じように勉強している人がいると感じられるのも良かったです。

# まとめ

インプットしたことをアウトプットするのは大切！
最初は完璧じゃなくてもアウトプットの過程でさらに勉強できるので、これからも積極的にやっていこうと思いました。

またなにか思いついたら追記します。
基本情報技術者試験を受けてみた

2023年4月に受けた基本情報技術者試験の受験記です。
これから受けたい人の力に少しでもなれればと思います。

## 1.結果
![1000003949.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/730657/a31a4d6d-2264-2ca6-e302-a423cfa57917.png)
合格しました！
科目Bの得点が高くて嬉しかったです。

# 2.受けた理由
読み飛ばしていいです。

年末年始にだらだら過ごすのも勿体無いと思い何か勉強しようと考えていました。
勉強の中でも基本情報技術者試験を選んだ理由は2つあります。

### ITの基礎を身に付けたかった
私は文系大学出身なのでITの基礎を勉強したことがありません。まずは基礎を身につけることにより今後の成長の幅が広がると思いました。

### データベーススペシャリスト試験を受けるため
私はデータベースがサービスの中心であり、一番長く使われるものだと考えています。
そのため、パフォーマンスの高いデータベースを構築できるエンジニアを目指し、データベーススペシャリスト試験を受けようと考えています。
ただ、いきなりデータベーススペシャリスト試験を受けるのもハードルが高いと思い、基本情報→応用情報→データベーススペシャリスト試験とステップアップしたいと思いました。

以上の理由により、勉強してみるか！と動き始めました。

## 3.学習期間
2023/1/1〜2023/4/14の3ヶ月間。
試験は2023/4/15(土)でした。

## 4.学習方法
以下の参考書を使用しました。
◾️令和05年 イメージ＆クレバー方式でよくわかる 栢木先生の基本情報技術者教室 情報処理技術者試験
![81hLkWxs5RL._SL1500_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/730657/0afb66f3-1dfc-38ce-aa50-93fe19abece5.jpeg)

◾️かんたん合格 基本情報技術者予想問題集 令和5年度
![81D3YIYLxeL._SL1500_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/730657/06814b9d-8a73-f880-4455-ebb0fa43f1b8.jpeg)

◾️令和05年【上期】基本情報技術者 パーフェクトラーニング予想問題集
![815hqQnjynL._SL1500_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/730657/4a221911-e826-5076-3aab-473a0da6df5b.jpeg)

## 5.学習の流れ
### 2023/1/1〜2023/1/31
**イメージ＆クレバー方式でよくわかる 栢木先生の基本情報技術者教室 情報処理技術者試験**を一通り読みました。
初めて知る内容ばかりで記憶には2割程度しか残っていなかったと思います。途中にある練習問題は一切解かず(解けず)に終わりました。
ここでポイントなのですが、コンピュータ科学基礎理論系のページは難しいので最後に読みましょう。最初に読むと挫折します。

### 2023/2/1〜2023/2/12
2週間かけて**イメージ＆クレバー方式でよくわかる 栢木先生の基本情報技術者教室 情報処理技術者試験**の練習問題を解きました。ここら辺で簡単な問題は解けるようになりましたが、基礎理論系やネットワーク系の問題は全然できませんでした。

### 2023/2/13〜2023/2/28
**かんたん合格 基本情報技術者予想問題集**の科目A問題に取り掛かりました。
全部で3回分の予想問題がありますが、1回目正答率40%、2回目正答率58%、3回目正答率65%くらいの成績だったと思います。
基本情報技術者試験は正答率60%以上で合格なので、3回目の結果でひとまず安心しました。

基本情報技術者試験はテキストを読むより問題を解く方が、点数が上がります。
基礎理論系やネットワーク系の問題はこの段階で解けるようになりました。テキストは程々にして問題を解きましょう。
ちなみにこの時、科目Bの勉強は一切していないです。

### 2023/3/1〜2023/3/12
**かんたん合格 基本情報技術者予想問題集**の科目B問題に取り掛かりました。
科目Bも全部で3回分の予想問題がありますが、1回目正答率55%、2回目正答率60%、3回目正答率60%くらいの成績だったと思います。
プログラミング問題は実務でそれなりにやっていたためそこまで難しくなかったです。
ただ、セキュリティ問題で得点を落としていたため再度**イメージ＆クレバー方式でよくわかる 栢木先生の基本情報技術者教室 情報処理技術者試験**を読んでセキュリティの復習をしました。

### 2023/3/13〜2023/4/14
1ヶ月かけて**基本情報技術者 パーフェクトラーニング予想問題集**を解きました。
セキュリティを復習した甲斐もあって科目A・科目Bともに65%〜80%くらいで点数が取れるようになりました。
私の場合は3月下旬で得点がだいぶ安定してきたため最後の2週間は少したるんでしまいました。
これから基本情報技術者試験を受ける方は、やる気のピークを試験日辺りに向けるように意識したらいいかもしれません。

### 試験当日
試験というものが久しぶりだったため、緊張して試験開始15分くらいは頭が真っ白になりました。
一通り解いた後最初の問題を見直したら、数問間違っていたため気をつけて下さい。

## 6.基本情報技術者試験を受けてみて
基本情報技術者試験に合格したことにより、自分はITの基礎知識があるという自信がもてました。
実務をこなす上でも一通りの基礎知識があるので、何を言っているのかが分からない状態には滅多にならないです。

基本情報技術者試験に合格しても意味がないという声を聞いて不安になるかもしれませんが、私はとても役に立ったと感じていますし、試験を意味あるものにできるかはその人次第だと考えています。
ステップアップとして基本情報技術者試験を選んでよかったな、と振り返って思います。
お行儀が悪くなったアプリをいつまでたっても修正しない某社ITサポートに業を煮やして、どかせるスクリプトを書いた話

# まえがき
ここのサイトにはだいぶ長いことご無沙汰でした、sigmocです。腹立ちまぎれに告発・糾弾するのも大人気ないので、ここにささやかなコードとノウハウを共有することで心を鎮めようと思いますw
「背景」の章は年寄りのグチをぐだぐだ垂れ流しただけですので、お急ぎの方はすぐ「方法」の章へどうぞ。
# 背景
仕事で(というか、ちょっとした副業として)毎日、某社の某アプリにログインして、いつもディスプレイのすみの方1/4くらいのスペースに表示させていたんですよ。今時のお行儀の良い一般的なアプリは、たいてい前回使用時のウィンドウサイズと位置を覚えていて、再起動とか再ログインしたら前の表示位置や内容を再現するのが常識じゃないですか。そのアプリも使用開始から数年、そのような動作をしていました。なのに、去年の5月ごろだったかアップデートを適用すると、突然、前回使用時サイズや位置を再現するのをやめ、ログインしたら **必ず最大化したウィンドウ** でディスプレイを覆い尽くすようになったんです。
ウィンドウの左上端をちょいとドラッグして、いつもの定位置に持って行くのは、たった5秒程度でできることですが、毎日くる日もくる日も繰り返すのは地味に面倒くさいし腹立つわけで、某社サポート窓口に「元通りの動作に直してくれ」って要望してみたんですけど、
- 操作の詳細を教えろ
- スクリーンショットを撮って送れ
- アプリを再度インストールし直してみて
- アプリの環境設定から表示設定をリセットしてみて
- アプリの履歴?キャッシュ?フォルダを削除してみて
- ...などなど
いろいろ延々やりとりしても、一向にラチがあかず、問題は修正されないまま。向こうの開発・保守担当チームでは、この問題動作が再現できてないかのような口ぶりで、こちらの環境がおかしいんじゃないの風なことを匂わせてきて、もうアタマにきたので、オマエラには頼まん! 自分でなんとかするわ! って書いたのが今回のスクリプトです。
(いや、現象は再現するはずだろ。だってオレわざわざ同アプリのWindows版をクリーンインストールして、デモ用アカウントで新規ログインして試したけど、動作いっしょだったんだからさw)
# 方法
macOSに標準で付属している「スクリプトエディタ」で、次のようなAppleScriptを記述します。
```AppleScript:YourAppSetPos.scpt
tell application "System Events"
	set theTargetW to window 1 of process "YourAppName"
	set size of theTargetW to {1920, 1200}
	set position of theTargetW to {1920, 960}
end tell
```
`YourAppName`のところには、アプリの名前(メニューバーの左端、Appleマークのとなりに表示されてるモノ)を書きましょう。この例では、4Kディスプレイの右下1/4強のスペースにアプリのウィンドウ(のうち最前面にあるもの)を移動させます。
適当な名前でスクリプトをとりあえず保存して、「ファイル」メニューの「書き出す...」でファイルフォーマットを「アプリケーション」として書き出せば、Dockに置いといてワンクリックで起動できます。
ちなみに、マウス操作でお好みの位置とサイズにウィンドウを動かしたときに、その数値を知りたいと思ったので、以下のようなスクリプトも書きました。
```AppleScript:YourAppGetPos.scpt
set AppleScript's text item delimiters to {", "}
tell application "System Events"
	set theTargetW to window 1 of process "YourAppName"
	display alert "YourAppName's window" message ¬
		"size: {" & (size of theTargetW) & "}; position: {" & (position of theTargetW) & "}"
end tell
```
``YourAppName``のアプリが起動してない時などにこのスクリプト動かすと、エラーが出たりするけど、細かいことは見逃してくれw
# 設定について
上で書いたスクリプトの実行をしようとすると、一発目に「YourAppSetPosには補助アクセスは許可されません。」というようなエラーが出ます。
macOSの「システム設定」→「プライバシーとセキュリティ」で、「アクセシビリティ」に対する許可を設定してやる必要があります。
こんな感じ。
![AccessSettings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1263633/3f5add1e-3527-f80b-0d12-0022561ccfeb.png)
こんなお行儀の悪いヘッポコアプリ、ほかにあまりないだろうし、需要があるか知らんけど、何かの参考になれば...
Enjoy!
【10】Next.js app routerのチュートリアルやってみる(部分的な事前レンダリング)

# はじめに

Next.js app routerのチュートリアルの第１０章のアウトプットします。

https://nextjs.org/learn/dashboard-app/partial-prerendering

<details><summary>前の記事</summary>

【01】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/af58da3d20cbc790e767

【02】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/edf450b3ee135e83d1e8

【03】Next.js app routerのチュートリアルやってみる
https://qiita.com/naoyuki2/items/612221eac233aa9cbb74

【04】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/62f9beccbfe36eaf7f90

【05】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/8b71b1d1df7c9435a9c9

【06】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/58130c3cfbaf8a573de2

【07】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/2c2da0f8071e60454679

【08】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/45f45fcb9cc14506f79f

【09】Next.js app routerのチュートリアルやってみる(loading.tsxとSuspenseでストリーミング)

https://qiita.com/naoyuki2/items/717694288ec6017a3af2

</details>

# 第１０章 部分的な事前レンダリング

この章では下記を学習しました。

- 部分的な事前レンダリングとは何か

:::note warn
部分的な事前レンダリングは、Next.js14で導入された実験的な機能らしいです。

そのため、これから変更される可能性があるとのことです。
:::

# 部分的な事前レンダリングとは

簡単に言うと、静的なコンポーネントは事前に読み込んでおいてすぐに表示する！
そして穴が開いている非同期で動的なコンポーネントをストリーミングでだんだん読み込む！だそうです。

例えば下の例ではサイドバーは静的レンダリングを、それ以外のダッシュボードは動的レダリングを選択する方がパフォーマンスが良くなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/8983245d-5fd0-19cc-f10a-4e5fa3eadeca.png)

上のページをユーザーが訪問した場合は、

サイドバーは静的なコンポーネントであるため、高速にロードされます

そして、他の動的なコンポーネントは非同期で読み込まれます。

これにより、ページ全体の読み込み時間が短縮されるというわけです。

# 使い方

動的なコンポーネントに`Suspense`を利用することで実現することができますとは、書いてありましたが、具体的な実装例などはチュートリアル内には記載されていませんでした。

:::note warn
注:部分的な事前レンダリングの構成方法の詳細については、部分的な事前レンダリング (実験) のドキュメントを参照するか、部分的な事前レンダリングのテンプレートとデモを試してください。。この機能は実験的なものであり、まだ運用環境に導入する準備ができていないことに注意することが重要です。

https://nextjs.org/docs/app/api-reference/next-config-js/partial-prerendering

https://vercel.com/templates/next.js/partial-prerendering-nextjs
:::


# おわりに

なかなか難しい。

# 次の記事

https://qiita.com/naoyuki2/items/2be9503ac80fc4a1fa6a
Windows ServerのDHCPでリースしているIP一覧を取得するコマンド

以下をRSATが入った端末、かつ管理者権限で実行する
```powershell
(Get-DhcpServerv4Scope -ComputerName "dhcpサーバ名") | %{Get-DhcpServerv4Lease -ComputerName "dhcpサーバ名" -ScopeId $_.ScopeId }
```
シミュレーション

https://paiza.jp/works/mondai/c_rank_level_up_problems/c_rank_simulation_boss

```py
H = int(input())
P_dmg_1 = 1
P_dmg_2 = 1
M_dmg_1 = 1
M_dmg_2 = 1
#turnは３から
#Hははじめから２減らす
turn = 2
H = 35- 2
while True:
    turn += 1
    P_dmg_1 = P_dmg_2
    P_dmg_2 = M_dmg_1 + M_dmg_2
    M_dmg_1 = M_dmg_2
    M_dmg_2 = P_dmg_1  + P_dmg_2 * 2
    
    H -= M_dmg_2
    if H < 0:
        break

print(turn)
```
```py
H = int(input())
P_dmg_1 = 1
P_dmg_2 = 1
M_dmg_1 = 1
M_dmg_2 = 1
#turnは３から
#Hははじめから２減らす
turn = 2
H = 35- 2
while True:
    turn += 1
    P_dmg_1 = P_dmg_2
    P_dmg_2 = M_dmg_1 + M_dmg_2
    M_dmg_1 = M_dmg_2
    M_dmg_2 = P_dmg_1  + P_dmg_2 * 2
    #とりあえずプリント
    print(P_dmg_1)
    print(P_dmg_2)
    print(M_dmg_1)
    print(M_dmg_2)
    
    H -= M_dmg_2
    if H < 0:
        break

print(turn)
```
```py
1　←　P２回目
2 ←　P３回目
1　←　M２回目
5　←　M３回目（？？？）
2　
6
5
14
6
19
14
44
```

手動で計算すると
ケース１
１回目
HP 7
Pの攻撃1
Mの攻撃1

２回目
HP 6
Pの攻撃1
Mの攻撃1

3回目
HP 5
Pの攻撃 1+1 = 2
Mの攻撃1 1*2 + 1 = 3

4回目
HP 2
Pの攻撃 2+1 = 3
Mの攻撃1 3*2 + 1 = 7
この時点HP０

***

ケース２
１回目
HP 35
Pの攻撃1
Mの攻撃1

２回目
HP 34
Pの攻撃1
Mの攻撃1

3回目
HP 33
Pの攻撃 1+1 = 2
Mの攻撃1 1*2 + 1 = 3

4回目
HP 30
Pの攻撃 ３+1 = 4
Mの攻撃1 2*2 + 1 = 5

5回目
HP 25
Pの攻撃 5+3 = 8
Mの攻撃1 5*2 + 3 = 13

6回目
HP 13
Pの攻撃 13+5 = 18
Mの攻撃1 13*2 + 5 = 31

この時点でHP0

なので、ちょっと変ですね。。。
なんでかというと、
    P_dmg_1 = P_dmg_2
    P_dmg_2 = M_dmg_1 + M_dmg_2
    M_dmg_1 = M_dmg_2
    M_dmg_2 = P_dmg_1  + P_dmg_2 * 2

これだと、P_dmg_2はすでに今回分になってしまっているので、前回分のにならないからですね。。。orz

だから、ずらす動作と、計算要素は別にしないとだめらしいです。
時間がもうなかったので答えを見ました。
こっちは配列ですが思った通りずらしてましたね。。。

```py

H = int(input())
a = [0, 1, 1]
b = [0, 1, 1]
dmg = 2
i = 2
while dmg < H:
    a[0] = a[1]
    a[1] = a[2]
    b[0] = b[1]
    b[1] = b[2]
    
    a[2] = b[0] + b[1]
    b[2] = a[0] + 2*a[1]
    
    dmg += b[2]
    
    i += 1

print(i)


```
勉強になりました！
SvelteKitで稀にchunkファイルがNot foundエラーになる問題に遭遇した

## 発端

クライアントでページ A を表示したまま放置して、サーバに新しいバージョンをデプロイした後、放置していたクライアントでページ B へ遷移した際、下記のようなエラーが発生しました。

```
Not found: /_app/immutable/chunks/HogeComponent.2b502a68.js
```

## 原因

調査した結果、クライアント使用中に新しいバージョンをビルドしたことでチャンクファイルが存在しなくなってしまったことが原因のようでした。元々 SvelteKit にはスクリプトのバージョン確認機能が搭載されているみたいなのですが、ページのプリロードなどを使用していると先読みしたスクリプトでエラーが発生するケースも有るようです。

参考：[GitHub Not found /\_app/immutable/assets/xxx #9089](https://github.com/sveltejs/kit/issues/9089)

## 解決策

SvelteKit の公式ドキュメントに[バージョン管理に関する記述](https://kit.svelte.jp/docs/configuration#version)がありました。

kit.version.name についてはデフォルトでビルド時のタイムスタンプが設定されるとのことなので、今回はポーリング処理だけ実装してみました。

最上位の+layout.svelte へ公式ドキュメントからポーリング処理をそのまま転記します。

```js
<script>
    import { beforeNavigate } from '$app/navigation';
    import { updated } from '$app/stores';

    beforeNavigate(({ willUnload, to }) => {
        if ($updated && !willUnload && to?.url) {
            location.href = to.url.href;
        }
    });
</script>
```

次に svelte.config.js へポーリングインターバルの設定を追記します。  
今回は 60 秒に設定しました。

```js
export default {
  kit: {
    version: {
      pollInterval: 60000, // ms
    },
  },
};
```

## 結果

ページ B へ遷移した際にもエラーにならず、ユーザーが継続して利用できるようになりました。  
※ポーリングのインターバルはコストに影響する場合もあるので適切な値に設定しましょう。

## まとめ

SvelteKit も晴れてメジャーリリースを迎えましたが、まだまだ情報が少ないのが現状です。Vue.js, React,AngularJS など有名なフレームワークは大抵習得している筆者ですが、そのなかでも特に Svelte はストレスフリーに開発できるのでお気に入りです。  
今後もっと情報が増えて Svelte 利用者が増えることを期待しています。おわり。

## 参考

https://svelte.jp/

https://kit.svelte.jp/docs/introduction
【React＋Vite＋Supabase】.envの値の取り扱いでヒヤヒヤした話

# はじめに
**React＋Vite** でアプリを作成中です。
今回はSupabaseを使ってデータ取得を行います。
Supabaseライブラリをインストール済であることを前提に、React環境でSupabaseを初期化する手順についてまとめています。
その中でも **.envに記載のある値の扱い方をミスったので、説明をします。**

**下記の動画を参考に進めていきます。**（該当箇所は14分～）
（DB作成方法やクライアント初期設定方法も説明してくれています。）

https://www.youtube.com/watch?v=CZlZgRo0bZ4
# 問題
解説動画通り下記のコードを書いたところ、このようなエラーが出ました。
**"Uncaught ReferenceError: process is not defined"**
動画ではNext.jsとTypeScriptを使用しているため、**React環境だとエラーが出てしまいます。**
エラーが出たprocessオブジェクトはNode.js環境で提供されるものであり、ブラウザー上では利用できないのですね。
```js:supabase.js
import { createClient } from '@supabase/supabase-js'

// Create a single supabase client for interacting with your database
export const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key')
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
```
# 動作は問題ないけどダメな例
最初は下記のように修正しました。**が、この記載は避けたほうがいいです。**
```js:supabase.js
import { createClient } from '@supabase/supabase-js';

const SUPABASE_URL = '.env.localに記載の値';
const SUPABASE_ANON_KEY = '.env.localに記載の値';

export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
```

# なぜダメなのか
**keyの値を公開してしまうと、supabaseのアカウントを悪用される恐れがあります。**(場合によっては高額請求も)

https://qiita.com/saitotak/items/813ac6c2057ac64d5fef

# 解決方法
下記のように修正しました。
```js:supabase.js
import { createClient } from '@supabase/supabase-js';

const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL;
const SUPABASE_ANON_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY;

export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
```

```.env:.env.loval
VITE_SUPABASE_URL = '指定された値'
VITE_SUPABASE_ANON_KEY = '指定された値'
```
# おわりに
解説動画にもあるように、**gitプッシュする前にenvファイルを.gitignoreに追記しておかないと、ファイルの内容が筒抜けになります。**　忘れずに行いましょう。
ちなみに「ダメな例」のコードですが、ChatGPTに「このエラーを解決して！」と初期のコードを投げたら返ってきました。
処理としては確かに間違っていないけど。。注意喚起とか欲しかったな。
WSL2のUbuntuにSSHでログインする方法

「Pythonで実装するディープラーニング将棋AI」という本をテキストにして、実際にAIを作ろうと思っている。この本では、実行環境としてGoogle Colabのクラウドを使っており、自分もそれでやろうとしているのだが、長い時間の処理だと途中で接続が切れてしまったり、結局課金が必要な状況に追い込まれたので、ローカルに実行環境を作ろうと考えている。

GPUのコストなど考えると、どっちがいいのかが分からないが、最終目標ではローカルで動作させたいと思っているので、持っている自分のWindowsマシンを使って環境構築を試みた。

だが、Pytorchなどの環境や、使用するコマンドはLinuxで開発されているものが大半で、Windowsには移植されているということもあって、うまくインストールできない場合が多々あり、そこで時間のロスが出てしまうので、Windows上にWSL2でLinux環境を作って、そこでPythonを実行することを考えた。

そして、SSHでその環境にログインしてプログラムを実行するのであるが、なぜログインする必要があるのかという話になってくると、細かい将棋AIにまつわる説明が必要になるので、それは別の機会に説明するとして、今回は表題の方法について説明する。

Windowsには標準でSSHクライアントがインストールされているので、これを使う。

まずは、PowerShellからWSL2の準備を実行

```
PS C:\Users\username> wsl --install
```

このコマンド一発で、Ubuntuのインストールまで終了する。

次に、Ubuntuのコンソールを開いて、SSHを初期化する。

最初は ifconfigも入っていないので、その辺のネットワークツールもインストールしておく。

```
username@HOST:~$ sudo apt install net-tools
username@HOST:~$ sudo apt install openssh-server
username@HOST:~$ sudo systemctl enable ssh
```

これで、Ubuntu側のsshサーバーが立ち上がる。

WindowsからSSHでログインしてみる。その際のUbuntuのIPアドレスは、ifconfigコマンドで確認しておく。
ここでは、172.16.0.1とする。

```
PS C:\Users\username> ssh username@172.16.0.1
```

ここでパスワードを聞いてくる。パスワードを入力すれば、リモートログインが完了する。

しかし、パスワードを聞いてこないようにしないといけないので、PKIを使ってWindows側にキーペアを作成し、Ubuntu側に公開鍵をインストールする。

```
PS C:\Users\username> ssh-keygen

PS C:\Users\username> cd .ssh
PS C:\Users\username\.ssh> Get-Content id_rsa.pub |Set-Clipboard
```

これで、公開鍵がクリップボードにコピーできたので、これをUbuntu側にセットする。
.sshというディレクトリを作成して、その中にauthorized_keysというファイルを作成して、先ほどクリップボードにコピーした公開鍵のデータをそのまま入れる。

```
username@HOST:~$ mkdir -p .ssh
username@HOST:~$ chmod 700 .ssh
username@HOST:~$ cd .ssh
username@HOST:~/.ssh$ vi authorized_keys
username@HOST:~/.ssh$ chmod 600 authorized_keys
```

viで編集する。insertとして、マウスの右クリックするとペーストされるので、それを保存して完了。

これで、リモートログインがパスワードなしに可能となる。
SQLの問題を解いて学んだこと

SQL初学者がSQLの練習問題を解いて得たものを適当に残すためのメモです。

### DISTINCT  
カラムの内容が重複する行を削除したような形で出力する

※例
```sql
SELECT DISTINCT release_year
FROM books;
```
### LIMIT
取得行数を制限する

※例
```sql
SELECT *
FROM authors
WHERE gender = '男性'
LIMIT 3;
```


### LIKE
特定の文字を含むものを取得する

※例
```sql
SELECT *
FROM books
WHERE name LIKE '%マンガ%';
```


### IS NOT NULL
カラムが空ではないものを取得する

※例
```sql
SELECT *
FROM books
WHERE release_year IS NOT NULL;
```


### BETWEEN
指定した条件の間にはいるものを取得する

※例
```sql
SELECT *
FROM books
WHERE total_page BETWEEN 300 and 400;
```


### IN
複数の条件指定をまとめて行う

※例
```sql
SELECT *
FROM books
WHERE release_year IN (2004, 2008, 2018);
```


### COUNT
指定した要素の数を数える

※例
```sql
SELECT  COUNT(*)
FROM authors
WHERE gender = '女性';
```


### SUM
指定したカラムのレコードの合計を取得

※例
```sql
SELECT  SUM(figure)
FROM book_sales;
```


### MAX, MIN
指定した要素の最大値、最小値を取得する

※例
```sql
SELECT MAX(total_page), MIN(total_page)
FROM books;
```


### ORDER BY
指定した要素を降順もしくは昇順に並び替える

※例
```sql
SELECT *
FROM books
ORDER BY release_year DESC;
```


### GROUP BY
重複する要素をグループ化する

※例
```sql
SELECT release_year, COUNT(*) AS books_num
FROM books
GROUP BY release_year
ORDER BY books_num DESC;
```


### HAVING
グループ化した後の情報での、抽出条件を指定できる。

※例
```sql
SELECT release_year, COUNT(*) AS books_num
FROM books
GROUP BY release_year
HAVING COUNT(*) >= 2
ORDER BY books_num DESC;
```


### INSERT文
テーブルに情報を追加する

※例
```sql
INSERT INTO events (id, name, max_num) VALUES (3, '2022 WEBデザイントレンド', 100);
```


### UPDATE文
テーブルの情報を更新する

※例
```sql
UPDATE events 
SET max_num = 30 
WHERE name = '最新の英語学習法を学ぼう';
```


### DELETE文
テーブルの情報を削除する

※例
```sql
DELETE FROM events
WHERE name = '最新の英語学習法を学ぼう';
```


### JOIN
テーブルを結合し情報を取得する

※例
```sql
SELECT books.name AS book_name, authors.name AS author_name
FROM books
JOIN book_authors
ON books.id = book_authors.book_id
JOIN authors
ON book_authors.author_id = authors.id;
```
--------------------
記事を読んでくださった方は、是非弊社開発課のXもフォローしてね:ぽっ:
毎日エンジニアに向けた情報発信を行っています。
https://twitter.com/tech_cin
「エンジニアリングを速くせよ」というニーズに応えるために

# はじめに
生成AIをコアエンジンに据えるサービスが世間を賑わせている。それと同時に「もっとはやくリリースできないのか」という経営からの強い期待や、現場レベルでは同業他社を含む熾烈な競争が始まっているところもあるだろう。
よりはやくリリースするためには、無駄を省く、効率化する必要があるということで、「エンジニアリングのコストと時間」に着目されることが多い。

しかしながら、エンジニアリングとは本来は必要経費であり、仮に効率化されるとしても **対象が絞られているが故に最適化できる** に過ぎない。この前提が「高速化」のために重要であることを本稿では述べていくこととする。

＊エンジニアリング＝ソフトウェア開発を通じたモノ造りの意

# エンジニアリングを構成する要素
エンジニアリングを構成する要素とは何だろうか？  
異論は認めるがｗ、ここでは大きくは「プロセス」と「テクノロジー」に分けて考えていく。

![スクリーンショット 2024-02-07 10.31.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121442/5531a67f-70d0-c5d6-f4fa-247d8742af92.png)


## テクノロジー  
モノ造りをするうえで、再現可能な形で計算機に委ねられる部分、あるいはその構成を支える領域をテクノロジーと総称している。

速くせよに答えるために、デプロイの自動化、ローコードツールの活用はよくある話だ。いずれも **対象が定まっている** 、自動化の範囲が決められているからこそ、効率化され速くすることに貢献できる。
次に、「テスト」はどうだろうか。 **対象が定まっている** テスト、それこそバージョンアップ時には必ずこのデグレードテストを実施する、といった内容であれば効率化に寄与する。では、新機能の開発に関わるテストについてはどうだろうか。テストコードを実装する工数は、新規開発の予算が少ない中で重くのしかかってくるだろう。その新機能が今後どれだけ使われるのか、価値を提供する存在になるのか、といったビジネスに根ざした問いに答えることができれば、テストを自動化することで「モトが取れる（今後数年でROIが向上する）」という判断もできるだろう。
このように、仮にテクロノジーの領域であったとしても、テクノロジー視点だけでは効率化の判断はできず、 **テクノロジーが表現するビジネスとしての出力を顧みる必要がある** のだ。

## プロセス  
テクノロジーとそれを扱う人の間に存在するモノをプロセスと総称している。

「アジャイル開発ならウォータフォールより速く開発できるのでは？」と聞かれたことのあるエンジニアは多いのではないだろうか。エンジニアならば「速くなるわけないだろうｗ」と思いつつも「目的地に速く到達する可能性はあります」と遠回しな回答をした経験もあるだろう。

やるべきこと（作り込む機能）が変わらない場合、アジャイルの方が小さく造っていくために、細かな手戻りや総量としてのテストの最適化ができずに、ウォーターフォールよりも工期がかかるというのは容易に想像がつく。では、なぜアジャイルがこんなにも注目されるのかというと「そもそもやるべきことなんて開発している間に変化してしまうので、滝が流れ落ちるまでの間に目的地が移動してしまう」という、変化の激しい時代の意思決定に適したプロセスとされるからである。

また、開発プロセスとは別に発展してきた品質管理の手法にも速さの観点で課題がある。
顧客に提供するようなシステムやその部品となるプロダクトをウォーターフォールで開発する場合、開発規模や造る対象の複雑さから摘出すべきバグ数、テスト件数を事前計画し、計画に沿ってバグ数が収束することにより品質を確保できたものと判断する。（IPAでバグ密度などして紹介されている）
Webサービスに関わったエンジニアならば、事前に予見した開発規模から目標とするバグ数が定められたり、必要な工数が決まることに違和感を感じるのではないだろうか。
このような品質管理の方法では、開発規模という形で、その中に含まれる各機能について優先度や重み付けをしていないこと、また、摘出されたバグについても等しく扱っている点において、ビジネスとして意思決定に関与していないところに違和感を覚えるのである。

ここでアジャイル開発に話を戻すと、アジャイルではイテレーションという一定の作業期間を刻みながら、都度、ビジネスの状況に応じて、開発や実行すべきタスクを優先度判定のもとで選びとっていく。このプロセスの中では、各機能、運用中に起こった事象、それぞれについてビジネスに根ざした形で影響を見積もり（例. 流通総額への被害額がいくらか）、意思決定をしている。つまり、現在の目的地に向かうために都度判断、最適化することで、エンジニアリングがビジネスを支えている状態を保ち、それ故に速いと言えるのである。

# まとめ
ここで話を冒頭に戻そう。 ビジネスとテクロノジーが一体となって意思決定できるプロセスを保ち、それによって、いまやるべきことを絞り込むことで「**対象が絞られているが故に最適化できる**」状態に至ることができる。逆に言えば、これまでのようにテクロノジー視点から来るプロセスや管理基準によって、総量を満たすことや、すべてを等しく扱うことを求める方法論では、全体として速さを生み出せないということである。 

CI/CD、オブザーバビリティ、インフラの自動化、テストの自動化、コードレビューとペアプログラミング、継続的な学習と改善など、手段としてのベストプラクティスに注目されがちであるが、「それがなぜ必要とされたのか」というビジネスの背景、求められるスピード、切迫した事業環境、こうしたことを深く理解し、その上でアジャイルなりDevOpsなりの必要性を議論して欲しいと切に願う。

すべてはビジネスの成功のために。
IntelliJでSpring Bootを実行

## IntelliJのインストール
Intellijには無料版と有料版がありますが、今回は無料版IntelliJ IDEA Community Editionを使用します。
https://www.jetbrains.com/idea/download/?section=windows#section=windows
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/3e833262-ca78-15c7-1b45-0187280802ad.png)
## SpringBootプロジェクトの作成
https://start.spring.io/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/927f605f-2199-9710-9a1f-e2ba7f3004cf.png)
## IntelliJでプロジェクトを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/9301326e-aa98-3ec4-0990-5617e779f139.png)
## HelloWorldのサンプル作成
```java
package com.example.demo.controller;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;

@RestController
public class HelloController {

  // 「/hello」へアクセスがあった場合
  @GetMapping("/hello")
  public String helloWorld() {
    // 文字列を返す
    return "Hello Spring-Boot World!!";
  }

}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/42229793-1616-91ca-0b9e-52873408b209.png)
## build
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/5094416d-e2a4-7008-be48-7f9688a07993.png)
## bootRun
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/8f6baefb-753f-cc08-ddd3-e59604e33366.png)
## HelloWorldの確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/5c650de1-bc41-70dd-330e-3dc7b716792e.png)
Ubuntu 22.04 で Rails 4.2 を動かすには？

あるRailsアプリケーションを8年ぶりに動かそうとしています。
実行環境は、WSL上の Ubuntu 22.04 です。動かせるでしょうか？

8年前は2016年、Rails 5.0 がリリースされた年です。
残念ながら、このアプリケーションのRailsのバージョンは`5.0`ではなく、`4.2`でした。
Rails 4.2 がサポートしているRubyのバージョンは`2.2`です。

## 問題

Ubuntu 22.04 では Ruby 2.2 が動きません。正確には `gem install` できません。
実行すると次のエラーが出ます。

```sh
►gem install bundler
ERROR:  While executing gem ... (RuntimeError)
    Marshal.load reentered at marshal_load
```

実行したときに、このエラーが出ずにsegmentation faultすることもあります。

Ruby 2.2には`bundler`が含まれません。
`gem install`できないと`bundle install`もできず、ここから先に進むことはできません。

### 対応方法

これは既知のissueです。


https://github.com/ruby/setup-ruby/issues/496#issuecomment-1625000309

に、対応方法がいくつか書かれています。

- Don't use Ruby 2.2, it's EOL since forever and it's just broken with modern OS/C compilers
- Use ubuntu-20.04
- Use a Docker image

この中から、僕はDockerを選びました。

## Dockerを使ってRails 4.2を動かす

[ruby - Official Image | Docker Hub](https://hub.docker.com/_/ruby) を使います。
次の`Dockerfile`を用意します。

```docker:Dockerfile
FROM ruby:2.2

# throw errors if Gemfile has been modified since Gemfile.lock
RUN bundle config --global frozen 1

WORKDIR /usr/src/app

COPY Gemfile Gemfile.lock ./
RUN gem install bundler -v 1.17.3
RUN bundle install --jobs 4

CMD ["bin/rails", "s", "-b", "0.0.0.0"]
```

`bundler`はバージョンを指定しないと最新版がインストールされます。
最新の`bundler`はRuby 2.2では動きません。
Ruby 2.2 で 動く `bundler` のバージョンを指定します。

次のコマンドでコンテナをビルドします。


```sh
docker buildx build -t temp .
```

次のコマンドでコンテナを起動します。

```sh
docker run --rm -v (pwd):/usr/src/app -p 3000:3000 temp
```

次のように、Railsアプリケーションが起動するのがわかります。

```sh
[2024-02-02 09:07:52] INFO  WEBrick 1.3.1
[2024-02-02 09:07:52] INFO  ruby 2.2.10 (2018-03-28) [x86_64-linux]
[2024-02-02 09:07:52] INFO  WEBrick::HTTPServer#start: pid=1 port=3000
```

:tada:
結局バリデーションってなんなのさ

## 概要

Web界隈でよく聞くバリデーションについて本当に概要部分を簡単にまとめます。
※本記事に具体的なコードは出てきません。各々お使いのフレームワークなどのドキュメントでバリデーションの実装方法をご確認ください。

## バリデーションって？

バリデーションとは簡単に言うと「イケてないデータをフィルタリングするもの」であると思っていただいて大丈夫です。
ちょっと難しい言葉でいうと「特定の条件・規則を満たしていることを確認するプロセス」です。

※スペル的に「ヴァリデーション」が正しいようだが、本記事ではあえて馴染みのある「バリデーション」を用います。

## バリデーションがなかったら？

もしバリデーションを設定していなかったら「イケてないデータ」が皆さんの作るシステムに入ってきます。これによって処理がうまく動かなかったり、データが保存できなかったり、意図しないバグが発生する場合があります。
例えばユーザー登録時に、ユーザー名は必ず入力してほしいのにユーザーさんが入力を忘れて「登録」ボタンをクリックしてしまったとします。システムは「ユーザー名は必ず入っていること前提」で作成されている場合「必ずあるはずのものがない状態」になり、十中八九エラーで処理が停止します。

対応策としては主に下記が上げられます。
- ユーザーさんにユーザー名を絶対入力してもらえるようにしてもらう。
- ユーザー名がない状態を感知して、ユーザーさんにその旨を伝えて入力してもらう。

前者で我々開発者ができることとすれば入力欄付近に「ユーザー名は絶対入力してください！」と文言を表示するくらいです。ただし、人間は忘れる生き物です。注意喚起されていても忘れてしまったり、そもそもいたずらであえて入力しない人もいるかも知れません。その都度「エラーが発生しました。最初からやり直してください」というような画面が出ていたらユーザー体験はよくありません。
なので後者でカバーします。これがバリデーションです。「イケてないデータ」だった場合にユーザーさんにそれを伝えて正しい情報で再度送ってもらうというのがバリデーションです。

## じゃあバリデーションはどこで使うの？

まずは下記の画像をご覧ください。画面で入力された処理がどのように移動して永続化（DBに保存）されるかを簡略図で表しました。（フロントとバックが分かれていますが、フロント・バックが分かれているAPIベースのシステムに限った話ではないです。説明の便宜上このような書き方をしています。）
矢印はデータの流れだと思ってください。

![work__Visual_Workspace_for_Innovation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/584d7ee9-f383-a049-8203-2aa37b3942b2.png)

それぞれ例を見てみましょう

### 星1

これは先程の図だと少し星の位置が不適切かもしれません。
実際には「ユーザーが情報を入力中に動的にチェックする」バリデーションについて伝えたかったです。
ユーザーフレンドリーなページでパスワードの登録時の入力中に「パスワードが短すぎます」や「大文字を含んでください」などの内容が表示されるものです。
「保存ボタン」を押さずとも、入力内容に応じて入力内容をチェックして「イケてないデータ」ならエラー内容を表示するものになります。

### 星2

これは画面上で入力が終わり「登録ボタン」をクリックしたあとに入力されたデータが「イケてないデータ」かどうかをチェックします。
「やっと登録できた〜登録ボタンポッチっとな」としたときに「何だよ、条件に合ってなくてパスワードサイド入力しないとじゃん、めんどくさいなあ」となるやつです。
データを処理（バックにわたす）前にチェックするイメージです。

### 星3

実は星2と星3はユーザーから見分けがつかない事がほとんどです。（一部のマニアックなお友達ならブラウザの検証モードですぐわかるのですが）

星3でも下記と同じことが起こります。
>「やっと登録できた〜登録ボタンポッチっとな」としたときに「何だよ、条件に合ってなくてパスワードサイド入力しないとじゃん、めんどくさいなあ」となるやつです。

それでは何が違うかというと、チェックしている場所が違います。
星2では画面（フロント）でデータをチェックしていました。
星3では処理（バック）するところでデータをチェックします。

属にいう「APIのバリデーション」はこの星3に該当します。

「イケてないデータを処理の直前で発見する」「イケてない内容をフロントに返して、イケてるデータを送り直してもらう」という感じです。

### 星4

これは永続化（DB）直前でチェックする方法です。
永続化（DB）する場所のルールにデータが適合しているかをチェックします。
ユーザーさんの入力起因というよりは処理（バック）を抜けてきたデータが意図しない形になっていないかをチェックする意味合いが強いです。
よっぽどのことが無い場合、このエラーの内容をユーザーさんが詳細に知ることはありません。

## セオリー（所感）

基本的に星2と星3のバリデーションを併用する方法が一般的です。（一部フレームワークで表示テンプレートまで受け持つ場合はは星3のみの場合もあり）
イメージとしては、「フロントからデータが出るときに「イケてるデータ」かをチェックする + バックで処理が始まる直前で「イケてるデータ」かをチェックする」
です。

よりユーザーフレンドリーにするならこれに星1を追加、要件として永続化時にエラーを発生させたくないなら星4をプラスするイメージです。

## 外部サービス（API）を使うとき〜上級者向け〜

外部サービスや外部APIを使う場合、処理や永続化部分は我々がどうこうできる範囲ではない場合があります。

![work__Visual_Workspace_for_Innovation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/fd5e0c1e-f395-8689-fe39-c8554ef4c63c.png)

その場合、星1や星2で我々は対応する必要があります。
また基本的に外部サービスは外部APIは星3の実装が行われています。
外部サービスや外部APIのドキュメントを確認し、星3がどのような形式でエラーを返すのかを確認し、そのエラーが返ってきた場合、画面ではどのようなふるまいをするのかを決めて、実装する必要があります。
リモートデスクトップでチームズのサボり方（.hta）

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title>aaa</title>
</head>
<body bgcolor="#215E21">
<script type="text/javascript">
  function Presskey() {
    var objWs = new ActiveXObject("Wscript.Shell");
    objWs.sendkeys("{SCROLLLOCK}");
  }
  setInterval("Presskey()", 6000);
</script>
</body>
</html>
React Routerを使ってみた

# 1. はじめに
ReactはSPA(Single Page Application)だけれども、ページ遷移的なことをやりたいときもあるので、それをそれっぽくSPAで実現するためのモジュール [React Router](https://reactrouter.com/en/main) を使ってみたメモです。

- バージョン
	- react: 18.2.0
	- react-router-dom: 6.22.0

ソースは下記

https://github.com/yo16/react_prac_react_router

# 2. 準備
`create-react-app`して、`npm i react-router-dom`。
ページごとの`*.js`を作ります。が、そこをがっつり省略するために、下記を準備。
```javascirpt:pages.js
export const TopPage = () => <>トップページ！</>;
export const Page1 = () => <>Page1です</>;
export const Page2 = () => <>Page2だよ</>;
export const PageNotFound = () => <>Not Foundです！</>;
```
あえて日本語を入れる方が、システムが自動で作った文字列と区別しやすいので、サンプルとか試行では私は入れる派。

# 3. 手順というか１手だけ
`App.js`上だけで実装します。本来は、`BrowserRouter`は、`index.js`など最上位で呼び出すのが良いですが、全体を把握するためのサンプルです。

```JavaScript:App.js
import { BrowserRouter, Link, Routes, Route } from "react-router-dom";
import { TopPage, Page1, Page2, PageNotFound } from "./pages";

function App() {
    return (
        <BrowserRouter>
            <header>
                <Link to="/">トップ</Link>｜
                <Link to="/page1">ページ１</Link>｜
                <Link to="/page2">ページ２</Link>
            </header>
            <main>
                <Routes>
                    <Route path="/" element={<TopPage />} />
                    <Route path="/page1" element={<Page1 />} />
                    <Route path="/page2" element={<Page2 />} />
                    <Route path="*" element={<PageNotFound />} />
                </Routes>
            </main>
        </BrowserRouter>
    );
}

export default App;
```
- `<BrouserRouter>`の中の、`<Routes>`の`<Route>`が、URLに対応する適切なものが選択されて表示されるという仕組みです。
- `<Link>`からの遷移も、URLを直書きしたときも、動作は同じ。
- そのまんまですが、page1にアクセスしたときの様子。
	- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/275f9a85-3d23-ae1e-0bc4-ced9377d22ed.png)
	- 他のページへ遷移したときも、ヘッダーは動かないです。
- `path="*"`は、switch文のdefaultみたいなイメージ。上記全部以外のときです。


以下はプラスアルファの話
-  `<Link>`の`to`と、`<Route>`の`path`に同じ値を書くのは気持ち悪いですね。本番では、変数定義したいところです。
- `<header>`、`<main>`はなくてもいいですが、`<main>`の中が書き換わるというイメージがよいかと思うのでそうしてみました。

# 4. おわりに
サクッとできたのですが、それゆえに、シンプルな解説ページがなさそう（ついでにいろいろやってしまう）ので、ご紹介でした。自分の備忘録もかねて。

疑問点としては、これをHTTPサーバーに置いたとき、どうなるのかな。そこを解決しとかないと、おもちゃで終わってしまう。。でもここでは、書き方だけにとどめて終わります。

# 5. リンク
- React Routerの公式HP
    - [React Router](https://reactrouter.com/en/main)
空間情報も考慮したSENet【Coordinate Attention】




**原論文**
Coordinate Attention for Efficient Mobile Network Design
https://openaccess.thecvf.com/content/CVPR2021/papers/Hou_Coordinate_Attention_for_Efficient_Mobile_Network_Design_CVPR_2021_paper.pdf



# 結論
SENetは空間情報を取りこぼしてる可能性があるので，空間情報も考慮しました．


# 概要
画像認識モデルであるCNNに，動的なパラメータを導入したSENetがある．SENetを以下の図に示す．SENetは，特徴量のチャンネルの重要度を決定する役割を持つ（色の重要度）．

しかし，SENetで採用されるチャンネルの重要度は，空間情報にGlobal Average Pooling（GAP）（$H \times W$の平均値）をすることで($H \times W \times C$)の特徴量を($1 \times 1 \times C$)に圧縮する．

SENetでは，よりシンプルで計算量の小さくなるようにGAPを使用しているが，GAPでは空間（$H \times W$）にある重要な情報を取りこぼしてしまう可能性がある．そこで，GAPで情報を($1 \times 1 \times C$)に圧縮するのではなく，空間情報も考慮した重み計算をする方法を提案する．



![スクリーンショット 2024-02-07 9.49.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/b2b92b9c-7fce-b519-4c82-b90d2fe4f0a9.png)


`動的なパラメータ（重み）：入力画像の持つ値を使用して重みを計算する．つまり，入力画像によって異なる重みを持つ．入力画像には，近い位置に重要な情報があるか，遠い位置に重要な情報があるかは異なる．これら情報を加味してパラメータ（重み）を決定する．`

→SENetの解説
https://qiita.com/wakayama_90b/items/96527dfbbeb1e2ee06c5



# モデル構造
モデル構造を以下の図(c)に示す．(a)はSENetである．SENetは右ルート（重要度を作成ルート）で($C \times 1 \times 1$)に圧縮するが，提案したCoordinate Attention(c)のモデルの右ルートは，($C \times H \times 1$)と($C \times 1 \times W$)に分かれて圧縮する．

〜〜〜
($C \times H \times 1$)は，W方向(横方向)の情報をAverage Pooling（平均値を求めて圧縮）
($C \times 1 \times W$)は，H方向(縦方向)の情報をAverage Pooling（平均値を求めて圧縮）
分けて圧縮する理由は，計算量が小さくなるからである．
〜〜〜

縦と横の空間情報を取り込むことにより，チャンネルの重要度だけでなく，空間の重要度も同時に計算することができる．また，縦方向の全ての値，横方向の全ての値，を考慮されているため，グローバルな情報を獲得できることも利点である．


## (b)のモデル
(b)のモデルでは，空間情報も取り入れようとしたモデルであり，$7 \times 7$の畳み込み層（局所的な空間認識）を採用しているが，GAPを使用した(a)のSENetとほぼ同等な精度になる．→よりグローバルが空間を捉えることが重要である．（論文中の表２参照）

## 重要度計算
その後，Concatして($C \times 1 \times (W+W)$)から畳み込み層(Conv2d)を通す($C/\gamma \times 1 \times (W+W)$)．$\gamma$は計算量削減のために圧縮されるため，16や32などが採用される．

最後にSigmoid関数で値を0~1にして，元の入力特徴量にかけて重要度を付与する．（右ルートのSigmoidで0になった位置は重要でないので，入力特徴量の同じ位置の値が0になる．反対に右ルートで1の場合は，入力特徴量の同じ位置が重要であることを示す．）

これらの，重要度付け（重み付け）は，入力特徴量の値から重要度を計算しているため，入力画像に柔軟に適応できる動的なパラメータ（重み）を持つ．

![スクリーンショット 2024-02-07 9.59.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/94c3bb38-f91c-b366-6f7e-60291f70afca.png)




# 実験

SE(a)，CBAM(b)，CA(c)のモデルで，SEとCBAMはほとんど同等だが，論文が提案したCoordinate Attention(CA)は有効であることがわかる．CAのグローバルな空間認識が有効．


![スクリーンショット 2024-02-07 10.34.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/bbe33d62-ea02-9921-b85e-78febf72fdb7.png)


また，よりグローバルな情報収集と，空間の動的なパラメータにより，Attentionの可視化（どこを見て認識したか？）の結果，より認識対象を捉えるように学習に成功したと考える．（もし，左上のように認識対象を注目せずに認識成功したとしても，そのモデルは有効とは限らない．むしろ悪．）

![スクリーンショット 2024-02-07 10.34.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/65c32959-0196-ab2e-cd02-10d0f04674a2.png)

# まとめ
今回は，空間情報も考慮したSENet【Coordinate Attention】について解説した．SENetでは，空間にある大切な情報を取りこぼしている可能性があったので，Coordinate Attentionを用いて，空間情報も考慮して重要度計算をした．その際に計算量削減のために，縦と横を分割して計算している．
Amazon GuardDutyについて書いてみた

## はじめに
おはこんばんにちは。キティちゃんです。最近はセキュリティで今後どう働いていこうかを考えています。今回はAmazon GuardDutyについて書いてみようと思います。

## きっかけ
資格の勉強をしていて、名前を聞いたということやAWS関連のセミナーに参加したときにもよく名前があがったことからまとめてみようかなと思いました。

## Amazon GuardDutyとは
AWSアカウント、ワークロードを継続的にモニタリングし、悪意のあるアクティビティがないかを確認して脅威を検出するサービスです。機械学習を用いて検出しているのが特徴です。

## 利用するメリット
メリットとしては以下が挙げられるかなと思います。

1.有効化することで直ぐに利用が可能

2.複数アカウントの検出状況を一元管理ができる

## 有効化することで直ぐに利用が可能
セキュリティというと、ソフトウェアを導入し、あれやこれやを設定する必要があり一苦労するというイメージがあるかもしれません。しかし、Amazon GuardDutyの場合、一度有効化の設定をしてしまえば、直ぐに利用可能です。追加のアプリケーションやエージェントなどのインストールは不要で、手間をかけず、セキュリティ対策が可能です。

## 複数アカウントの検出状況を一元管理ができる
AWS Organizations機能を使うことで、複数のAWSアカウントの一元管理が可能になります。複数のAWSアカウントが一元管理できることにより、個別でセキュリティチェックをするという手間がなくなります。

## 所感
導入も容易であることや機械学習による検知ができるため、セキュリティを強化するにあたって、必ず入れたほうが良いサービスの一つではないかと思います。また、無償で利用できる期間もありますし、従量課金制のため、サービスの利用を停止したいと思ったタイミングで停止することができます。まずは、入れてみましょう。
もし、Amazon GuardDutyを使ったサービスを検討するときは、単体ではなく＋αの価値（常時監視、クラウド導入支援など）を提供する必要がありそうです。

## まとめ
今回はAmazon GuardDutyについて書いてみました。導入が容易であるというのは大きなメリットだと思います。何からセキュリティ対策をすれば良いのか迷う方はまず導入することをお勧めします。

## 参考
・『Amazon GuardDuty　インテリジェントな脅威検出で AWS アカウントを保護』
https://aws.amazon.com/jp/guardduty/

・『【有効化推奨】「Amazon GuardDuty」とは？初心者向けに解説』クラスメソッド社
https://classmethod.jp/aws/articles/aws-guard-duty/

・『Amazon GuardDutyとは？重要視される理由や特長、メリットなどを解説』トレンドマイクロ社
https://www.trendmicro.com/ja_jp/business/campaigns/aws/column/amazon-guarduty-202306-02.html#anchor04-tm-anchor
【認証機能バグ】Apple IDを利用したログインができなくなった

## シチュエーション
ある日、これまで利用できていたAppleIDを利用した認証機能が利用できなくなった。
AppleIDを利用して認証するユーザーはサービスを利用することができない。
早期に問題の解決を求められる。

- ログインをしていないため、UserIDでログを絞り込むことができない
- [Appleのシステム状況は問題発生していない](https://www.apple.com/jp/support/systemstatus/)
- Twitterなどを見てもAppleIDでログインできないサービスは複数ある様子


なぜ、認証機能がうまく動作しないのだろうか？



## 問題箇所

> email_verified
A string or Boolean value that indicates whether the service verifies the email. The value can either be a string ("true" or "false") or a Boolean (true or false). The system may not verify email addresses for Sign in with Apple at Work & School users, and this claim is "false" or false for those users.(email_verified
Goolgle翻訳：サービスが電子メールを検証するかどうかを示す文字列またはブール値。値は文字列( "true" or "false") またはブール値 (trueまたはfalse) のいずれかです。システムは、職場および学校で Apple でサインインするユーザーの電子メール アドレスを検証できない可能性があり、この申し立てはそれらのユーザーを"false"対象としていますfalse。)
[AppleIDは公式ドキュメント](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple)

email_verifiedの値は、文字列( "true" or "false") またはブール値 (trueまたはfalse) のいずれかです。
どちらか一方しか対応していなかった場合、認証時にエラーが発生してしまいます。

## 解決
stringとBooleanの両方に対応する

````golang
func (p *appleAuthProfile) GetEmailVerified() (bool, bool) {
	// email_verifiedがない場合はfalseとする
	v, ok := p.claims["email_verified"]
	if !ok {
		return false, false
	}
	// email_verifiedはstringまたはboolで返ってくる
	switch v := v.(type) {
	case bool:
		return v, true
	case string:
		return v == "true", true
	default:
		return false, false
	}
}
````

## おわりに

Twitterなどを見てもAppleIDでログインできないサービスは複数ある状況だったため、これはApple側の障害に違いないと結論づけたくなる。
しかし、ログと公式ドキュメントを辿ると実装ミスであることがわかった。
T/Fのフラグ変数を1/0に置換する/反転させる(SPSS Modeler データ加工逆引き2-20)

# T/Fのフラグ変数を1/0に置換する/反転させる

![スクリーンショット 2024-01-29 14.04.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/9b1f3c0a-286d-3437-832a-483d5b438eb2.png)

カテゴリ値を再割り当てするには逆引き2-12を参照ください。

https://qiita.com/416nishimaki/items/8d02e9b18bb5e6c909b2

## 1.想定される利用目的

・判別予測モデルのための真偽の確定

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/main/TF_convert.str

## 3.サンプルストリームの説明

![スクリーンショット 2024-01-29 14.06.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/6d85ba9e-b456-9803-b0f1-064736e511aa.png)

a.入力するデータは以下の通りです。

![スクリーンショット 2024-01-29 14.07.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/01fbf1c1-8924-5740-aaaa-21de442de4e7.png)

#### 置換ノードを利用する方法

b.[置換]ノードを編集します。　[置換条件]を[常時]にしてIF文で記述します。undefは欠損値です。

![スクリーンショット 2024-01-29 14.08.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/87753724-6fef-1da6-3883-c67424d45c07.png)

[テーブル]を表示します。

![スクリーンショット 2024-01-29 14.08.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/f94ac024-a0cf-5a84-1660-9aa69947d9f9.png)

#### データ分類ノードを利用する方法

c.[データ分類]ノードを編集します。bと同じ結果を出力します。

![スクリーンショット 2024-01-29 14.09.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/b6b29606-80f5-5023-74a1-819333e15168.png)

c.[データ分類]ノードを編集します。

![スクリーンショット 2024-01-29 14.09.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/699c48f2-54f7-58f2-165e-3564445a31d1.png)

[テーブル]を表示します。
![スクリーンショット 2024-01-29 14.09.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/f8c43106-63d6-c0b9-59c9-176f60e260f9.png)


#### 注意事項

Modelerのフラグ設定では真偽をT/Fを初期値にしています。例えば解約や故障をTにすると、解約率や故障率を
求めるのに不都合なため１/0に変換します。

## 4.参考情報

#### カテゴリの値を別の値に割り当てる

https://qiita.com/416nishimaki/items/8d02e9b18bb5e6c909b2

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
【JavaScript】FizzBuzz問題をワンライナーで書いてみた

# 前書き
最近JavaScriptを触っていないので、気分転換でFizzBuzz問題でもやろうと思いました。
普通に解いても面白くないので、今回は配列を使うこととワンライナーで書くことを考えて問題を解きました。
ワンライナーのため可読性が悪いのでその点は注意してください。


# コード
```javascript
Array.from(Array(100)).map((_, i) => [i+1, 'fizz', 'buzz', 'fizzbuzz'][[1,0,0][(i+1)%3]+[2,0,0,0,0][(i+1)%5]]).forEach(item => console.log(item));
```

# 解説
簡単に解説を行なっていきます。
メソッドなどがわからない場合は下記の「メソッドなどの参考リンク」をのリンク先などをみていただければと思います。

## 定義形

```javascript
Array(100)
```
長さが100の新しい空の配列を作成しております。
<font color="gray">要素は全てundefinedで初期化されとるらしいです。</font>

```javascript
map((_, i)...略)
```
アンダーバーは仮引数。
mapの関数内で使用されないことを示しとります。
 `i` は`Array(100)`で定義した配列のキーなんで `0` スタートになります。
 

```javascript
[i+1, 'fizz', 'buzz', 'fizzbuzz'] 
```
FizzBuzz用の配列を定義。
```javascript
[[1,0,0][(i+1)%3]+[2,0,0,0,0][(i+1)%5]]
```
数値によって呼び出すキーの配列を定義。

```javascript
[1,0,0][(i+1)%3]
```
3の倍数の余りでキー設定をしている。
```javascript
[2,0,0,0,0][(i+1)%5]
```
5の倍数の余りでキー設定をしている。

#### 15の倍数
`[1,0,0][(i+1)%3]`と`[2,0,0,0,0][(i+1)%5]`を足すことで15の倍数を判断できるようになるわけです。

## 動きに関して
### i+1が３の倍数になる時(i=2など)
`[(i+1)%3]`が割り切れるため`0`になるから`[1,0,0][(i+1)%3]`が`1`になり、
`[(i+1)%5]`は割り切れないので`0`となることがないので`[2,0,0,0,0][(i+1)%5]`が`0`になります。
`[[1,0,0][(i+1)%3]+[2,0,0,0,0][(i+1)%5]]`が`[1]`になるので
`[i+1, 'fizz', 'buzz', 'fizzbuzz'] `から`fizz`が呼び出されるようになります。

### i+1が5の倍数になる時(i=4など)
`[(i+1)%3]`は割り切れないので`0`となることがないので`[1,0,0][(i+1)%3]`が`0`になり、
`[(i+1)%5]`が割り切れるため`0`になるから`[2,0,0,0,0][(i+1)%5]`が`2`になります。
`[[1,0,0][(i+1)%3]+[2,0,0,0,0][(i+1)%5]]`が`[2]`になるので
`[i+1, 'fizz', 'buzz', 'fizzbuzz'] `から`buzz`が呼び出されるようになります。

### i+1が15の倍数になる時(i=14など)
`[(i+1)%3]`が割り切れるため`0`になるから`[1,0,0][(i+1)%3]`が`1`になり、
`[(i+1)%5]`が割り切れるため`0`になるから`[2,0,0,0,0][(i+1)%5]`が`2`になります。
`[[1,0,0][(i+1)%3]+[2,0,0,0,0][(i+1)%5]]`が`[3]`になるので
`[i+1, 'fizz', 'buzz', 'fizzbuzz'] `から`fizzbuzz`が呼び出されるようになります。

### i+1が3,5,15の倍数以外の場合
`[1,0,0][(i+1)%3]`と`[2,0,0,0,0][(i+1)%5]`の両方が`0`になるので`[i+1, 'fizz', 'buzz', 'fizzbuzz']` から`i+1`呼び出されるようになります。


# 終わりに
FizzBuzz問題を久しぶりに解きましたが、この方法で実装を行わなければならないという制限を設けた状態でコードを書くのは良い刺激になるなと感じました。



#### 弊社開発課でXもやっていますので是非フォローをしてください

https://twitter.com/tech_cin

#### 私のXのフォローもしてくれると喜びます

https://twitter.com/ken__se

# メソッドなどの参考リンク
### Array.from() 
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/from

### map
https://qiita.com/NNNiNiNNN/items/3743ce6db31a421d88d0

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

### アロー関数

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions

`(_, i) => [i+1, 'fizz', 'buzz', 'fizzbuzz'][[1,0,0][(i+1)%3]+[2,0,0,0,0][(i+1)%5]]` など


 ### forEach
 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
ローカルでスマホテストの環境設定

# 背景
- フロントのコードビルド時間がかかる
- 不要なクラウドコスト減少
- 開発感

---

# 設定の構成図
#### クラウドの構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/ebac8d38-1c40-fcd0-9d50-5dbc43db12c4.png)

---

#### ローカルの構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/a0516043-ad26-fd55-4027-4c05a0a2fd83.png)

---

### 環境設定
#### ① スマホ → PC: 連携確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/4bf94ce1-7b71-3955-1bf3-d53ecb0f89d5.png)

---

Windows Defender ファイアウォールのデフォルトは LocalHost の接続を制御するため接続の制御設定が必要。
2つ方法が有る
- Windows Defender ファイアウォールをOFF
- 指定ポートを開ける

---

##### Windows Defender ファイアウォールの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/b4266534-b496-82cc-a976-672f818ddf2e.png)

---

##### 指定ポートを開ける
![pc_firewall_setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/95e8b5f1-d00c-e947-9fb0-7ffa1e3ee2c3.png)

---

##### スマホから連携確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/d740fc9b-ceaf-420f-1c6b-d4dbee6cc182.png)

---

#### ③PC → WSL: 連携確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/4cf4586f-9414-067c-fe15-5a332ff1f70e.png)

---
#### スマホからWSL Hostに連携
LocalHostが連携できるがWSL Hostが分からないので連携ができない。
連携できるためにIPとポートフォワーディングが必要です。

```
# アドミン権限実行
netsh interface portproxy add v4tov4 listenport=8080 \
listenaddress=0.0.0.0 connectport=8080 connectaddress=172.25.227.120
```

---

#### Chromeで加速度が取得できない
→ FireFoxで加速度が取得できる（理由不明）

---

#### Chrome、FireFoxでカメラが設定できない
保護されていないオリジンに対するセキュリティ制限(http://)
![chrome_setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/38b2add3-dfd3-82af-81a5-084535345fc3.png)

---

### Androidの開発設定
#### 開発モード設定
![Screenshot_20240207-074015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638228/a5e817e0-9630-50a6-06f7-0d17218b49eb.png)

---

#### 開発ツール
- Chromeの開発ツール
    - chrome://inspect/#devices
- Android Debug Bridge (adb)
    - https://developer.android.com/tools/adb
- Androidスクリーンコントロール
    - https://github.com/Genymobile/scrcpy

---
#### 以上