OmniAICreator/Qiita-1.07M huggingface dataset:
HackTheBox Writeup: Meow

## 概要
HackTheBox:Meowのflagを入手する手順を記す。

## Port Scan
Nmapでスキャンをかける。
```terminal
$ nmap -v -oN ports meow.htb
Starting Nmap 7.92 ( https://nmap.org ) at 2022-09-13 10:55 EDT
Initiating Ping Scan at 10:55
Scanning meow.htb (10.129.213.24) [2 ports]
Completed Ping Scan at 10:55, 0.25s elapsed (1 total hosts)
Initiating Connect Scan at 10:55
Scanning meow.htb (10.129.213.24) [1000 ports]
Discovered open port 23/tcp on 10.129.213.24
Increasing send delay for 10.129.213.24 from 0 to 5 due to max_successful_tryno increase to 4
Completed Connect Scan at 10:55, 41.76s elapsed (1000 total ports)
Nmap scan report for meow.htb (10.129.213.24)
Host is up (0.25s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT     STATE    SERVICE
23/tcp   open     telnet
9876/tcp filtered sd

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 42.07 seconds
```

telnetが提供されていることが分かる。

## Telnet
Telnetに接続する。
```terminal
$ telnet meow.htb   
Trying 10.129.213.24...
Connected to meow.htb.
Escape character is '^]'.

  █  █         ▐▌     ▄█▄ █          ▄▄▄▄
  █▄▄█ ▀▀█ █▀▀ ▐▌▄▀    █  █▀█ █▀█    █▌▄█ ▄▀▀▄ ▀▄▀
  █  █ █▄█ █▄▄ ▐█▀▄    █  █ █ █▄▄    █▌▄█ ▀▄▄▀ █▀█

Meow login: 
```

入力を求められるので、とりあえずrootと入力する。
(rootとかadminをとりあえずで入力すると突破できる場面が多々ある)

```terminal
Meow login: root
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-77-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue 13 Sep 2022 02:59:37 PM UTC

  System load:           0.08
  Usage of /:            41.7% of 7.75GB
  Memory usage:          4%
  Swap usage:            0%
  Processes:             137
  Users logged in:       0
  IPv4 address for eth0: 10.129.213.24
  IPv6 address for eth0: dead:beef::250:56ff:fe96:4b83

 * Super-optimized for small spaces - read how we shrank the memory
   footprint of MicroK8s to make it the smallest full K8s around.

   https://ubuntu.com/blog/microk8s-memory-optimisation

75 updates can be applied immediately.
31 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Mon Sep  6 15:15:23 UTC 2021 from 10.10.14.18 on pts/0
root@Meow:~# ls
flag.txt  snap
root@Meow:~# cat flag.txt
```
無事ログインできたのでflag.txtを読み取り終了。
DBの種類について

# DBの種類について
## 初めに
システムの構築と並行して普段何となくの理解ですましいてたインフラ分野の知識をしっかり理解もしたく、この記事を書きます。1回目はDBの種類についてです。

AWSのRDSサービスを業務で触る機会があり、Oracle・PostgreSQLなどを触ったりしてきましたが、特に決められた種類をそのまま構築等していただけだったのでそれぞれの特徴・使い分けなどをちゃんと理解していませんでした。そこでDBエンジンの種類が色々あるのは知っているレベルの私が調べた結果をまとめてみます。

## データベースの種類
上記でデータベースの種類でOracle・PostgreSQLなどど書きましたが、それより大枠の種類もあります。（Oracle・PostgreSQLはリレーショナル型）

4種類に分類でき、以下の種類になります。
・階層型
・ネットワーク型
。リレーショナル型
。NoSQL型
|種類  |概要 |AWSサービス  |
|---|---|---|
|階層型 |ノードと呼ばれる特定情報の集まりでデータを蓄積。家系図のような構造。  |-  |
|ネットワーク型|階層型とデータの構造が近いが、重複データを持たず、複数の親データと直接結びつけて管理。  |-  |
|リレーショナル型 |表形式でデータが蓄積。  |RDS,Aurora等  |
|NoSQL型 |基本構造はリレーショナル型と同じだがSQLを使用しない |ElastiCache,DynamoDB等|

![スクリーンショット 2022-09-13 234315.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/91c6dc51-f05a-db6e-4bdc-255d82cc8184.png)

## リレーショナル型について
この4種類の中で一番使用する機会が多いであろうリレーショナル型に焦点をあてます。AWSサービスでいうところのRDSになります。（Auroraはサービスとして独立しておらずRDSのデータベースエンジンを選択する場面で選択できます）

RDSでは下記の6種類のDBエンジンが選べます

・MySQL
・MariaDB
・PostgresSQL
・Oracle
・MicrosoftSQL
・Aurora
　Aurora-MySQL
　Aurora-PostgreSQL

### MySQL
現在急速にシェアを伸ばしている。Oracle開発。無料で機能も豊富。Linux,Windows,Macでも稼働できる。ほかのDBシステムとの互換性に定評あり。
### MariaDB
MySQLから派生した。MySQLをベースにして新機能追加やソースオードの改善が組み込まれている。
### PostgresSQL
オープンソース。SQLとNoSQLを両方扱える。拡張性が高い。多くの追加機能を持っている。
### Oracle
Oracle社が開発。世界中のサイトで利用されている。自動化機能を備えていて、拡張やパッチ適用等の運用工ストを削減できる。
### MicrosoftSQL
Oracleと人気を二分にしている。Windows上で使用したい場合にお勧め。GUI操作で管理できる。
### Aurora
クラウド向けにAWSが開発したRDBのサービス。MySQLとPostgreSQLと互換性のあるバージョンがある。クラスター構成とインスタンスとストレージが分割されている。高可用性。
※RDSの中の1選択ですが、Auroraという1つのサービスとしてとらえたほうがわかりやすい印象です。
　一度仕事で触れましたがアーキテクチャの理解に結構時間がかかりました。。

## ログの種類について
タイトルとはずれてしまうんですが、DBのログを触る機会があったので簡単にまとめておきます。

・アラートログ
　DBインスタンスで発生した起動などの管理操作のメッセージ履歴。トラブル調査では初めにアラートログを確認する。
　→Linuxでいうところの/var/log/messageに近そう

・監査ログ
　データベースに対するユーザーのアクションを記録するファイル。意図しないデータベースに対する捜査の原因調査に使用する。
　→AWSでいうCloudTrailに近そう

・リスナーログ
　クライアントからの接続要求（クライアントのホスト名等）と、その要求の成功可否が出力される。

・トレースログ
　インスタンス上の各プロセス（バックグラウンドプロセス等）が個別のトレースファイルに情報を出力する。アラートログに「Error in file xxx.trc」のような出力がある場合などに確認する。
　→アプリログみたいなイメージ？
　

## まとめ
ここまで簡単に各データベースエンジンの特徴をまとめましたがはっきり言ってあんまり腑に落ちてはいないです。(笑)
シェアや無料or有料などの概要についてはわかりましたが細かい機能などについては実際設計を担当するとなった際にシステムの要件などを考慮して決めるものなのかなといったものなのだと思いました。

次回はLinuxのディストリビューション、bashなどのシェルについての記事を書こうかなと思っています。


♯# 参考ページ
https://meetsmore.com/product-services/databases/media/99426
https://www.acrovision.jp/career/?p=1912
https://offers.jp/media/programming/a_359
https://atmarkit.itmedia.co.jp/ait/articles/1704/07/news008_2.html
文字列の一部だけを取得する方法

はじめに
--
inputでユーザーが入力した値の一部だけを取得して画面に表示させたいことがありました。
色々と方法がありそうですが、自分が調べた内容を備忘録に残そうと思います。

.substring()で文字列の一部を取得する
--
文字列の一部を指定して取得するためには".substring"を使用します。
構文は下記になります。

~~~js
str.substring(indexStart[, indexEnd])
~~~

詳しい説明
--
[公式ドキュメント](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/substring)より引用して下記にまとめようと思います。

indexStart/indexEnd
--
・indexStart
取得する文字列の最初の文字の位置を指定する引数。
配列と同じように、一文字目の位置は0。

・indexEnd
文字列の中から取得しない文字の位置を指定する引数。
この引数は省略可能。
~~~
const str = 'Mozilla';

console.log(str.substring(1, 3));
//"oz"が表示される。
// １の位置の"o"から、3の位置にある"i"を含まない"oz"が取得される。

console.log(str.substring(2));
// "zilla"が表示される
// indexEndの引数がないため、２の位置以降の全ての文字列を取得する。
~~~


indexStartとindexEndの引数が等しい場合
--
indexStartとindexEndの引数が等しい場合は、空文字を返す。
~~~
const str = 'Mozilla';

console.log(str.substring(0, 0));
// ""(空文字）が返ってくる
~~~

・引数が0未満の場合/文字数を超えた引数が指定された場合
--
引数が0未満の場合は0に、
文字数を超えた引数が指定された場合は最後の文字の位置として扱われる。
~~~
const str = 'Mozilla';

console.log(str.substring(-45, 100));
//str.substring(0, 6)として扱われる
// "Mozilla"が表示される
~~~


indexStart が indexEnd より大きかった場合
--
indexStart が indexEnd より大きかった場合、引数が交換される
~~~
const str = 'Mozilla';

console.log(str.substring(7, 4));
// "lla"が表示される
// indexStartの引数が4,indexEndの引数が7に交換されている
~~~

参考
--
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/substring
【メモ】アクセス修飾子

Swiftにおいて、よく使うアクセス修飾子をメモした。

|修飾子|説明|
|------------|---------------------------------------------|
|open        |別モジュールから呼び出せる。継承やオーバーライドが可能|
|public      |別モジュールから呼び出せるが継承やオーバーライドが不可能|
|internal    |同モジュール内からのみ呼び出せる|
|fileprivate |同ファイル内からのみ呼び出せる|
|private     |同スコープ内からのみ呼び出せる|
【Unreal Engine】マテリアルのWorldAlignedTextureノードとWorldAlignedNormalノード

Unreal EngineのマテリアルでWorldAlignedTextureノードを使うとテクスチャをTriplanar Mappingすることができます。ノーマルマップをTriplanar Mappingする場合には、WorldAlignedNormalノードを使用します。WorldAlignedTextureノードもWorldAlignedNormalノードも実態はマテリアル関数なので、ノードの内部を見れば実装を確認することができます。

今回の検証に使用しているUnreal Engineのバージョンは5.0.3です。

## WorldAlignedTexture

BaseColorなどをTriplanar MappingするためにWorldAlignedTextureノードを使用します。

### インプット

- **TextureObject:** 使用するテクスチャ
- **TextureSize:** テクスチャタイリングにおける1タイルの大きさ
- **WorldPosition:** ワールド位置
- **Export Float4:** 出力にアルファも含めるか
- **World Space Noraml:** ワールド法線
- **ProjectionTransitionContrast:** プロジェクションの境界部分の鋭さ

`TextureObject`以外はデフォルト値が設定されています。

### アウトプット

- **XY Texture:** X方向、Y方向からの投影のブレンド
- **Z Texture:** Z方向からの投影
- **XYZ Texture:** X方向、Y方向、Z方向からの投影のブレンド

### 使用例

![Network_WorldAlignedTexture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/fab9e017-655c-e7d0-9cc4-09c6bf25a968.png)
![Preview_WorldAlignedTexture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/aabef3e4-4ddf-85ba-67fb-f49aaa02c523.png)

## WorldAlignedNormal

ノーマルマップをTriplanar MappingするにはWorldAlignedNormalノードを使用します。

### インプット

- **TextureObject:** 使用するテクスチャ
- **TextureSize:** テクスチャタイリングにおける1タイルの大きさ
- **WorldSpace:** ワールド座標系の法線を出力するか
- **Normal:** タンジェントスペースにおける上方向
- **ProjectionTransitionContrast:** プロジェクトションの境界部分の鋭さ
- **WorldPosition:** ワールド位置
- **Use High Quality Normals:** より高精度な法線計算をするか

`TextureObject`以外はデフォルト値が設定されています。

### アウトプット

- **XY Texture:**　X方向、Y方向からの投影のブレンド？
- **XYZ Texture:** X方向、Y方向、Z方向からの投影のブレンド
- **XYZFlatTop:** ???
- **Z Texture:** Z方向からの投影?

`XYZ Texture`以外のアウトプットは何を出力するか正確には理解できていませんが、主に`XYZ Texutre`アウトプットを使用することになると思います。

### 使用例

![Network_WorldAlignedNormal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/f6565a1e-701c-2b05-ec40-c1d92cabf554.png)
![Preview_WorldAlignedNormal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/5ee92a3a-3398-11e7-76f1-c5a8304aaca9.png)

WorldAlignedTextureノードと同じように`ProjectionTransitionContrast`で境界部分の鋭さを調整できますが、値を大きくすると以下のように不自然な法線となるので注意が必要です。
![Preview_WorldAlignedNormal_HighContrast.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/bec89c01-05e0-6a45-e90f-3911e6943518.png)


## WorldAlignedTexture + WorldAlignedNormal

WorldAlignedTextureノードとWorldAlignedNormalノードを組み合わせて使用すると次のようになります。
![Network_WorldAlignedTexture_Normal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/c42ac435-d56f-6265-9feb-3ac486eebbab.png)
![Preview_WorldAlignedTexture_Normal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/e64d6694-d54d-b6a2-5f9c-ca42d6aff8fa.png)

## 参考

- [テクスチャリング \| Unreal Engine ドキュメント](https://docs.unrealengine.com/4.27/ja/RenderingAndGraphics/Materials/Functions/Reference/Texturing/)
【メモ】継承してみた

普段おまじないのようにviewDidLoadを記述していたが、それは内部的に継承をおこなっていることを知ったので、自分でClassの継承を実際に書いてみることにした。

```Swift
override func viewDidLoad(){
    super.viewDidLoad()
}
```

Playgroundにて、

```Swift
class Starbucks {
    func starbucks(){
        print("Starbucks")
    }
}

class Caffe : Starbucks {
    let name = "Tullys"

    func callName(){
        super.starbucks()
    }
}

let caffe = Caffe()
print(caffe.name)
caffe.callName()
```

結果は、以下の通りである。
```Swift
// Tullys
// starBucks
```

Caffeクラス内において、Starbucksクラスを継承している。なので、callName関数内で、superを使いStarbucksクラス内のstarbucks関数を呼び出すことができる。
E2Eテスト とは

## 勉強前イメージ

end to endのテスト？
最初から最後まで？
なにの・・・？

## 調査

### E2Eテスト とは

E2Eとはend to endテストの略で、ユーザが使用するのと同じようにシステムをテストすることです。
どういうことかというとユーザの操作種類問わずデータフローが適切に機能するかを確認し
具体的には現実で想定されるシナリオをシュミレートして行われます。

例えば、ログインのフォームだと以下のことが考えられます。

- IDとパスワードを正しく入力
- IDとパスワードを不正な値を入力
- IDまたはパスワードを空のまま入力
- ログインボタンを押す
- パスワードを忘れたボタンを押す

上記これらを実施することで期待通りに機能することを確認します。

E2Eテストはエンドユーザの行動に基づいてアプリケーションが正しく動作することを確認でき、バグを高い確率で検知できますが
とにかく時間がかかったり、テスト設計の考慮要素が多かったりデメリットもあります。
なので、重要なログイン機能だったり登録機能だけをE2Eテストを行うということもケースとしてあるそうです。

### 結合テストとの違い

上記のE2Eテストだと結合テストと似たようなことが書かれています。
そもそも結合テストはアプリケーションやコンポーネントを結合した状態でテストを行います。
しかし結合テストはすべてを結合させる必要はなく、
一部のコンポーネントだけを結合して結合テストを行うこともあります。

それに対してE2Eテストではすべてのアプリケーションやコンポーネントを結合した状態でテストを行います。
なので、より本番の環境に近い状態でテストを行うことができます。

## 勉強後イメージ

結合テストが最終かと思ったけど、E2Eテストの方がより本番に近い感じか・・・・

## 参考

- [【E2Eテスト実践ガイド】E2Eテストの実施方法からおすすめツール、現場での実践ポイントまで詳しく解説](https://www.praha-inc.com/lab/posts/e2e-testing)
- [E2E (エンドツーエンド) テストとは？](https://circleci.com/ja/blog/what-is-end-to-end-testing/#)
応用数学

# 問題１の気づき
最短経路を求める問題だった。
考える上で必要なことは、縦と横にどれくらい移動しなければならないか？を例として見つけなければならない。
そうすると最低でも一方向にどれくらいの区画を進まなければならないことがわかる。
```2方向全体の進む中から一方向の進むぶんだけを取り出す。```

# 問題2の気づき
平均待ち時間の公式が出てきた。
```窓口利用率を１ー窓口利用率で割って平均サービス時間を掛ける```と求まる。

# 気づき
難しい。
もっと勉強をしないといけない。
わからないところもたくさんあるけど公式を覚えて解いていくしか今のところこれしかないだろう。
ステージしたものをないことにする

```
git reset
```
* ```HEADを履歴の中で移動```させる。
* ```ステージや作業ツリーの内容をHEADに合わせる```ことにも使われる。
* ```HEADの内容をステージにコピー```する。

```
git reset --ファイル名
```
```HEADの状態に戻す```ことができる。

```
git reset --hard
```
作業ツリーの内容もHEADの状態にもどす。
```作業ツリーの内容が上書きされる```のでこれをするときは注意が必要。

### 気づき
```git reset --hard```をすると直前までの作業がなくなってしまうからか。

# 演習
```
hyoudoumasatomo@mbp training % vim hello.txt
```
```hello.txt
Hello!
I am a student.
hogehogehogehoge!!
hogehoge!!
hogehogematuri!!
```
```
************@mbp ******* % git add hello.txt
************@mbp ******* % git reset --hard
HEAD is now at ******** ++++++++++++
************@mbp ******* % vim hello.txt
```
```hello.txt
Hello!
I am a student.
hogehogehogehoge!!
hogehoge!!
```
確かにHEADの内容になっている。
Python 仮想環境作成方法 （venv, pyenv）


pyenvとvenvを用いて新たにPythonの仮想環境を作成する際の手順をまとめました。
なお、環境構築については、以下を参考にしてください。

- Windows (WSL)
    - [pyenv, venv](https://qiita.com/mukusuke421/items/51e1684614cab0cb78c3)
- Mac
    - [pyenv](https://zenn.dev/unsoluble_sugar/articles/283ebf698c307c)
    - [venv](https://hitori-sekai.com/python/venv/)

## 仮想環境作成方法

### pythonバージョンの指定

```
pyenv global <バージョン>
```

### 仮想環境を作成
作成するディレクトリで以下を実行。
```
python -m venv .venv
```
`.venv` というディレクトリが作成される。
このフォルダに仮想環境のライブラリ等の情報が保存される。

### 仮想環境を起動
```
source .venv/bin/activate
```

以下のように右端に `(仮想環境フォルダ名)` が表示されていれば、起動成功。
```
(.venv)$ python
```

### ライブラリをインストール
あとはpipで好きなライブラリをインストールすれば良い。
`requirement.txt` からインストールする場合は以下を実行。
```
pip install -r requirements.txt
```
OneDriveからデスクトップ奪還大作戦‼

## OneDriveで勝手にバックアップされて困ってませんか？
PC初心者だった私は自動バックアップで
デスクトップのPathがOneDrive配下にありました

### 何が困るのか？
GitでDesktopが標準で使えなくなります:sob:
これは本当に困っていました…
とりあえずドキュメントにフォルダを作ってしのいでました…

### どうしたらOneDriveから抜け出せる？
↓↓↓OneDriveのバックアップを停止する方法はこちらから↓↓↓
https://pasokon-labo.com/desktop-onedrive-undo/

上記の方法だけだと、同期は切れてもファイルたちはデスクトップに移行されませんでした

### ~/Desktopにするためには
#### ①デスクトップフォルダを右クリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/973380/c42c2434-662c-fb63-b265-3344e6752450.png)

#### ②プロパティをクリック
[場所]タブを開いて、標準に戻す
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/973380/6ea1ffe3-3112-83f8-a7ae-c81c65790185.png)

すると…
元通りになりました！
これでGitが使える！！
学習に戻ります！！！
UnityのDebug.Logでリッチテキストを有効にする


躓いたのでメモ。（Unityは2021.3.5f1）
## まずは結論から
この２行を Start() に追加すればOK！
```C#
void Start()
{
        GUIStyle style = new GUIStyle();
        style.richText = true;
}
```

これだけでリッチテキストが有効になるよ。やったね！

## 留意事項
>* デフォルトでは無効（style.richText = false）になってるらしい。（なんで！？）
>* 特にこだわりがなければ Start(){　～　} の中に入れておけば良いと思う
>* どこか一つのスクリプト内で記述しておけば、他のスクリプトでもリッチテキストは有効になる
>* 一度有効にすれば、上で書いた2行を消しても有効になったままだよ
>* リッチテキストはtrue、falseで有効、無効にできる…と思ったのですが、やってみたら
style.richText = false にしてもUnityを再起動してもリッチテキストは有効になったままになりました（何故…）

参考：[リッチテキスト-Unityマニュアル](https://docs.unity3d.com/ja/2021.3/Manual/StyledText.html)
ICML2022の量子化論文 (2)

# 概要

この記事では、[ICML2022](https://icml.cc/)の量子化論文を紹介します。[^1]
[その1](https://qiita.com/kyad/items/a33a45319b45cc81387d)

[^1]: 画像や数式は論文から引用しています。


# Fast Lossless Neural Compression with Integer-Only Discrete Flows

https://arxiv.org/abs/2206.08869

概要：H.264のロスレス圧縮 entropy codec の高速化。
新規性：従来最速のIDFより速い。
キモ：整数のみで推論できるようにし、LSQで学習している。また、Filter pruningする。
評価：ImageNet32, 64等で評価した。


# Secure Quantized Training for Deep Learning

https://arxiv.org/abs/2107.00501

概要：MPC (マルチパーティ計算。各人の入力から他の人の入力を隠したまま全体の結果を得る方法) で量子化学習を行う方法。
新規性：MPCによる学習で、従来よりも高速に学習できる。
キモ：MPCでは、データ転送のコストがGPUより大きいので、データを整数化する。また、exp等の演算を整数化する。
評価：MNISTやCIFAR, LeNetで実験した。


# Finding the Task-Optimal Low-Bit Sub-Distribution in Deep Neural Networks

https://arxiv.org/abs/2112.15139

概要：DGMS. 量子化をGaussian Mixture Modelでモデル化して量子化学習する方法。
新規性：量子化をGaussian Mixture Modelでモデル化した。STEを使わず、タスクのロスを直接最適化できるようにした。
キモ：量子化をこうモデル化する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/97a6351a-8082-d857-6cd9-6841eb328439.png)
評価：ResNet, SSDLite-MobileNetV2等で実験した。
【Python】文字列のリストから別のリストの要素を含む文字列を抽出する方法

## 環境
+ conda 4.12.0
+ Python 3.8.12.final.0

## コード
例）リスト `fruits` からリスト `filter` の要素（＝ア, イ, ウ, エ, オ）を含む文字列を抽出する。抽出後のリストを `fruits_filtered` とする。

```py:py
fruits = ["リンゴ", "イチゴ", "バナナ", "ブドウ", "ミカン", "キウイ", "アンズ"]
filter = ["ア", "イ", "ウ", "エ", "オ"]
fruits_filtered = [f for f in fruits if any((str in f) for str in filter)]
print(*fruits_filtered)  # イチゴ ブドウ キウイ アンズ
```

## コードの解説
### 内包表記
```py:内包表記の例
# 内包表記
odds = [i for i in range(10) if i % 2 == 1]

# 等価なコード
odds = []
for i in range(10):
    if i % 2 == 1:
        odds.append(i)
```

### any(iterable)
iterable のいずれかの要素が真ならば `True` を返す。iterable が空なら `False` を返す。
```py:any(iterable)の挙動
def any(iterable):
    for element in iterable:
        if element:
            return True
    return False
```


## 参考
https://note.nkmk.me/python-list-comprehension/

https://note.nkmk.me/python-all-any-usage/

https://bbh.bz/2019/11/16/python-list-technique/
Git コマンド 基本 + その他

## Git で出来ること

- ファイルのバージョン管理
- 以前の状態に戻せる
- チームでスムーズに開発できる


## GitHub で出来ること

- コードの共有
- コードレビュー
- OSS に参加


## Git 基本コマンド

### git init

ローカルリポジトリを新規に作成する。

```
$ git init
```

### git add , git commit

ローカルの変更内容をステージにあげる。ファイル名を指定。`.` は全ファイル。

```
$ git add <ファイル名>

$ git add .
```

ステージに上げたものを、コミットし、リポジトリにあげる。

```
$ git commit -m "コミットメッセージ"
```

### git diff , git status

リポジトリとワークツリーの差分をチェックする。

```
$ git diff
```

リポジトリとステージの差分をチェックする。

```
$ git diff --staged
```

変更ファイルをチェックする。

```
$ git status
```

### git log

変更履歴を確認する。

```
$ git log
```

### git restore

ワークツリーの変更を取り消す。

```
$ git restore <ファイル名>
```

ステージにあげた変更をワークツリーに戻す。

```
$ git restore -staged <ファイル名>
```


## ブランチ

### git branch

ブランチを作成する。

```
$ git branch <ブランチ名>
```

ブランチ一覧を表示する

```
$ git branch

$ git branch -a
```

### git switch

ブランチを切り替える。`-c` つけるとブランチを作成して切り替える。

```
$ git switch <ブランチ名>

$ git switch -c <ブランチ名>
```

### git merge

変更をマージする

```
$ git merge <ブランチ名>

$ git merge origin/<ブランチ名>
```

## git hub とのやりとり

### git config

初期設定。

```
$ git config --global user.name "XXX"
$ git config --global user.email "XXX@example.com"
```

### git remote

リポジトリを追加する。

```
$ git remote add origin <リモートURL>
```

### git push

リモートへ push する。

```
$ git push origin <ブランチ名>
```

### git pull

リモートから　pull する。(ワークツリーまでに反映する。)

```
$ git pull
```

### git fetch

リモートから　fetch する。(ローカルリポジトリまでに反映する。)

```
$ git fetch
```


## プルリク

https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request#creating-the-pull-request


## 

### 余計なファイルをコミットしてしまって、ignore したい

```
$ git rm --cached <ファイル名>
$ echo <ファイル名>  >> .gitignore
```

### 直前のコミットを無しにしたい

リモートリポジトリに取り込まれていない場合

```
# HEAD だけ元に戻す。
$ git reset --soft HEAD^

# HEAD と インデックスを元に戻す。
$ git reset HEAD^

# HEAD と インデックス、ワークツリーを元に戻す。
$ git reset --hard HEAD^
```

リモートリポジトリに取り込まれている場合

```
$ gi revert <コミット>
```

### 別のブランチにコミットしてしまった

```
$ git branch <別ブランチ>
$ git reset --soft HEAD^
$ git switch <別ブランチ>
```

### コミットを間違って消しちゃった

```
# コミット履歴を確認。
$ git reflog

# git reset する前の HEAD を指定。
$ git reset --hard <コミット>　
```

### ブランチを間違って消しちゃった

```
$ git reflog
$ git branch <ブランチ名> <コミット>
```

### コミットメッセージを間違えた

```
$ git commit --amend
```

### マージしたけどコンフリクトしまくって元に戻したい

```
$ git reset --hard ORIG_HEAD
```

### ブランチ名を間違えてつけた

```
$ git branch -m <ブランチ名>
```

### コミットはせずに変更を退避したいとき

```
$ git stash
$ git stash pop
```

### 誤ったコミットをpushしてしまった

```
$ git push origin :<ブランチ名>
$ git reset --hard <コミット>
$ git push origin <ブランチ名>
```

### 商用リリースをしてバグがあったので切り戻す

```
$ git log
$ git revert <マージコミット>
```
tz databaseのタイムゾーン名からWindowsのタイムゾーン名を検索するには

結論から言うと [ICUが提供する`ucal_getWindowsTimeZoneID`](https://unicode-org.github.io/icu-docs/apidoc/dev/icu4c/ucal_8h.html#ad901e6ea4638091e61f3624e9c23072e)を用いれば良い。ただし注意点として、tzdatabseのタイムゾーン名とWindowsが独自に持つタイムゾーン名は全射ではないので、やむにやまれず利用するくらいで。

```cpp
#include <iostream>
#include <string>
#include <string_view>
#include <optional>
#include <icu.h>
std::pair<std::optional<std::u16string>, std::optional<UErrorCode>> getWindowsTimeZoneID(std::u16string_view inna_tz_name)
{
    UErrorCode _{};
    const auto ret = ucal_getWindowsTimeZoneID(inna_tz_name.data(), inna_tz_name.size(), nullptr, -1, &_);
    std::u16string buf;
    buf.resize(ret);
    UErrorCode ec{};
    if (const auto ret2 = ucal_getWindowsTimeZoneID(inna_tz_name.data(), inna_tz_name.size(), buf.data(), buf.size() + 1, &ec); U_FAILURE(ec) || ret2 == 0) {
        return { std::nullopt, ec };
    }
    return { buf, std::nullopt };
}
int main()
{
    std::wcout.imbue(std::locale());
    for (auto&& name : { u"America/Los_Angeles", u"Asia/Tokyo"}) {
        auto&& [val, stat] = getWindowsTimeZoneID(name);
        if (val) {
            std::wcout << reinterpret_cast<const wchar_t*>(val->c_str()) << std::endl;
        }
        if (stat) {
            std::cerr << u_errorName(*stat) << std::endl;
        }
    }
}
```

以下の2つのライブラリとリンクが必要である。

- icuuc.lib
- icuin.lib


> https://qiita.com/x768/items/ba4059986bea178c5133
>
>Windowsのタイムゾーン名とtz databaseのタイムゾーン名の変換は、以下の表を使うとよいが、一対一の対応になっていないことに注意。

こうすると表を自分で持たなくてもなんとかなる。

## 注意点

`ucal_getWindowsTimeZoneID`で最後の引数に渡しているエラーコード変数へのポインタについて注意しなければならない。どういうわけかこの関数はエラーコードをセットする前に中身を読み取っている様子があるのだ。

1. 1回めの呼び出し時に油断して`nullptr`を渡すともれなくヌルポするから`nullptr`を渡してはいけない
1. 初期化されているエラーコード変数へのポインタである必要がある。エラーコードをセットする前に中身を読み取っているということは、未初期化で渡すとUBになるということである
1. 1回目と2回目で渡すエラーコード変数へのポインタは別のものでなければならない。
[SwiftUI] Menuが表示されているときにSheetが表示されない場合の応急措置

# はじめに
あくまで応急処置です。根本的な解決方法等ご存知の方コメントお待ちしております。

# 事象
Menuが表示されているときにSheetを表示させようとしても、表示されない
<img width="200" alt="sheet bug" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2620576/d651581d-ed90-1698-1d2d-57f2b1b66a8e.gif">

# バグが発生するコード
iOS15.5で確認
```swift
struct MenuAlert: View {
    @State var isPresented = false
    
    var body: some View {
        VStack {
            Menu("menu") {
                Text("a")
            }
            
            Spacer()
            
            Button("show sheet: \(isPresented.description)") {
                isPresented = true
            }
        }
        .sheet(isPresented: $isPresented) {
            Text("sheet is presented")
        }
    }
}
```
# 対処方法 
sheetを表示する前に以下のコードでmenuをdismissする

```swift
UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true)
```
```diff_swift
struct MenuAlert: View {
    @State var isPresented = false
    
    var body: some View {
        VStack {
            Menu("menu") {
                Text("a")
            }
            
            Spacer()
            
            Button("show sheet: \(isPresented.description)") {
+                UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true)
                isPresented = true
            }
        }
        .sheet(isPresented: $isPresented) {
            Text("sheet is presented")
        }
    }
}
```
# 不思議な点
以下のように、Spacerを除去すると正常に動作する
なぜ🤔
```diff_swift
struct MenuAlert: View {
    @State var isPresented = false
    
    var body: some View {
-        VStack {
+        VStack(spacing: 400) {
            Menu("menu") {
                Text("a")
            }
            
-           Spacer()

            Button("show sheet: \(isPresented.description)") {
                isPresented = true
            }
        }
        .sheet(isPresented: $isPresented) {
            Text("sheet is presented")
        }
    }
}
```
rasberry pi pico がPCに認識されない

電子工作初心者がrasberry pi pico　をPCに接続しようとしたところ、認識されずつまづきました。私同様のミスをする人もいるかと思いますので記事にします。


rasberry pi pico　は購入後利用するためにはファームウェアのインストールをし、pico内にプログラミング環境を整える手順が必要になります。
詳しい方法は他のわかりやすい記事を参照してみてください。


まず最初にpico上の白いボタン(bootsel)を押しながらmicro-usb端子を挿し、自分のPCに接続します。
(このbootselの押し忘れもつまづきやすいところかと思いますのでご注意を)


この段階で私はつまづきました。

端的に申し上げると、データ通信ができるusbケーブルを新たに購入することで解決しました。


私ははもはやなんの付属品だったかも不明のusbケーブルを使用していました。一応イヤホンを差し充電されていたため、断線していないと安心していましたが、ここに盲点がありました。


usbケーブルには充電しかできないものもあるようです。


もしかしたら安物イヤホン等に付属されているmicro-usbのケーブルは充電機能しかなく、データ通信ができないものが多いのかもしれません。


家電量販店でデータ通信可能と書かれているケーブルを購入しbootselを押しながら接続したところ、すんなり認識しました。


まとめです。
私同様、家に残っていたmicro-usbのケーブルを使用しつまづいている方は、micro-usbケーブルがデータ通信不可のものかもしれないため、他に原因(断線など)がなさそうであるなら、新たにケーブルを購入してみてください。
Dateクラスで日時の取得

## 日付に関わる処理に使えるのでメモ

### Dateクラスとは
Rubyの標準ライブラリの機能で日付を扱うためのクラスとして用意されている。
使うためにはまず下記の記述をする
```
require "date"
```
todayメソッドを使えば今日の日付を取得出来る
```
Date.today
```

他にもたくさんのメソッドがある
```
today = Date.today
today.year # 作成したDateオブジェクトから年を取得
today.mon # 作成したDateオブジェクトから月を取得
today.mday # 作成したDateオブジェクトから日を取得
today.wday # 作成したDateオブジェクトから曜日を0(日曜日)から6(土曜日)の整数で取得
```

wdayメソッドは曜日ごとに処理が変わるようなコードに使える
```
day = Date.today.wday
days = ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"]
 if day == 5
puts "今日は#{days[day]}だ!!"
else
 puts "今日は#{days[day]}"
end

出力結果
「今日は金曜日だ ！！！」
「今日は月曜日」
```

wdayメソッドで曜日を0(日曜日)から6(土曜日)の整数で取得
変数daysに配列で日曜日（0番）〜土曜日（6番目）まで文字列で格納。

配列5番目、つまり　金曜日だったら「今日は金曜日だ ！！！」が出力
それ以外の整数なら他の曜日が出力される
AWSでACLを作成してみた

お疲れ様ですー。すっかり涼しくなってきて秋を感じます。食欲の秋！ということでばくばく食べております。・・というわけで今回はAWSでACLを作ってみました。

AWSにはネットワークACLとセキュリティグループというファイヤーウォール的なものがあります。まずセキュリティグループとネットワークACLについて違いをみてましょう。

## ACLとセキュリティグループの違い
まずはセキュリティグループ。
セキュリティグループの特徴としてVPCに紐づいているものなので他のVPCだと利用することはできません。

なのでインスタンスを立ち上げる時もどのVPCに設置するかで使用できるセキュリティグループが変わります。

ステートフルなのでインバウンドで許可の設定をすればアウトバンドも許可されます。ちなみにコンソール画面では拒否の設定はありません。拒否したければ削除します。

ACLはインバウンド、アウトバンドの通信を許可・拒否のルールを複数作成することができます。それらのルールに番号を割り振り順序通りに適用されます。

ACLはステートレスなのでインバウンドで許可してもアウトバンドは許可になりません。なのでインスタンスから外部への通信をしたい場合は、アウトバンドの許可をする必要があります。

またACLはVPC内に入るかを許可するルールです。ACLは通過することはできてもEC2インスタンスのセキュリティグループで許可されていなければインスタンスと通信することはできません。ACLはネットワークACLともいいNACLと表記されます。


■セキュリティグループのコンソール画面
![スクリーンショット 2022-09-13 21.02.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1828177/1cec78cd-a6d3-cf42-204d-7dcbd607c227.png)
このようにセキュリティグループでは拒否する設定ができません。

■ACLのコンソール画面
![スクリーンショット 2022-09-13 20.54.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1828177/2e2122a9-ec42-d8ba-cdbc-2b95d4ac59d6.png)
編集のボタンからAllow(許可)、Deny(拒否)の設定ができます。


## セキュリティグループの設定
［VPC］-[セキュリティグループ]-[セキュリティグループを作成]

![スクリーンショット 2022-09-13 21.39.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1828177/dc6b0e59-ada2-c9e0-6597-d7303e7d1a0b.png)

下のインバウンドルール、アウトバンドルールで設定します。設定したタイプのプロトコル、ポート番号、ソースのIPアドレスの通信を許可します。
拒否したい場合はルールを削除する、もしくはセキュリティグループ自体を削除します。

## ACLの設定

［VPC］-[ネットワーク ACL]-[ネットワーク ACL を作成]
![スクリーンショット 2022-09-13 21.51.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1828177/aa1387bb-46d3-5a91-8bda-131ed5a10f63.png)

名前や紐付けるVPCを設定します。
![スクリーンショット 2022-09-13 21.59.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1828177/4b9efcd9-ffbe-d3a4-bf86-ea1089443ff3.png)
作成すると［ネットワークACL］の画面に戻り編集したいACLにチェックを入れます。下にタブが表示されます。


![スクリーンショット 2022-09-13 8.26.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1828177/c37e6d45-2938-52c1-0436-04b6b0fcb273.png)
ルール番号を入力し送信先を設定、そしてこれらの通信の許可をするのか拒否するのかルールを決めます。

番号の低い順に優先されるので
・100番のルールを適用する
・100番に当てはまらない場合は110番のルールを適用
・110番にも当てはまらない場合は、120番のルールを適用

ということになります。

そしてどれも当てはまらない場合は全て拒否する。といったルールになります。

またキャプチャの画像には入っていませんがアウトバンドルールにはエフェメラルポートの設定が必要です。

## エフェメラルポートとは
サーバーがクライアント(PCなど)に通信をする際に通す一時的なポートのことを言います。一般的には1024-65535を使用します。

ザクっと抽象的にいうと自由に使用できるポート番号のことをいうらしいです。

もしACLを設定していざサーバーに入ろうとすると「できない！」となる場合はエフェメラルポートが設定されていない可能性があります。

その逆でSSHやHTTPなどの決まった使用用途で使われるポート番号のことをウェルノウンポートといいます。

![スクリーンショット 2022-09-10 10.52.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1828177/0900c7e8-783d-343a-bbdf-e84dc500c87e.png)

こちらの表も参考までに。

これまでサーバに入れなかった出来事が何度かありましたがこれでどこを確認すればわかるようになりました！
【UiPath】Orchestrator への HTTP 要求 (Orchestrator HTTP Request) でOCから情報を取得してみる

**Orchestrator への HTTP 要求 (Orchestrator HTTP Request)** を使ってOCから情報を取得してみます。
正直よくわかっていないので本当に取得するだけです。実践例とかも特にありません。ご容赦ください。

### パラメータ
設定するパラメータは以下の通りです。
前提として Orchestrator に接続している必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/de3becca-3a06-56b5-10f8-a1f8f76ba4e1.png)

色々とありますが、最低限赤線引いた部分だけ設定すれば動かせます。
**メソッド**は今回は取得なので`Get`を設定します。
**JSON 応答** はString型で返るので適当なString型変数を当ててください。
**エンドポイントの相対パス** は `/odata/Jobs`のような形の文字列で指定します。
`Jobs`の部分に他に何を指定できるかは以下の公式ドキュメントを参照してください。

https://docs.uipath.com/orchestrator/lang-ja/v2020.10/reference/logical-resources-and-metadata

なお、View権限が無いパスについては取得できません。
既定のロールでの権限については以下を参照してください。

https://docs.uipath.com/orchestrator/lang-ja/v2020.10/docs/default-roles

### 返り値
- HTMLのような値が返ってきたらパスの入力に誤りがある可能性があります。別の値を試すなどしてみてください。
- 指定したパスに対してView権限が無い場合は「You are not authorized!」を含んだ文字列が返ります。
- パスが正しく入力されView権限も有る場合は、取得した情報がJSON形式の文字列で返ります。

本来他にも色々出来ると思いますが、とりあえずここまでです…。

## 参考
https://docs.uipath.com/activities/lang-ja/docs/orchestrator-http-request
RF PowerとSSID, BSSID

RF Powerというのは、無線電波の強さのことです。

この強さは、dBmとmW(milliwatt)で表すことができます。

この、電波の強さを知ることで、私たちは、無線機器がどのくらいの範囲の通信をカバーしているのかがわかります。

では、dBmとmWで何が違うの？っと思ったと思います。違いは、指数対数スケールなのか、線形スケールなのかの違いです。以下の表を見てください。

| 距離(m) | dBm 信号 | mW 信号 |
| --- | --- | --- |
| 1 | -20 | .0098911 |
| 10 | -40 | .0000989 |
| 20 | -46 | .0000247 |
| 100 | -60 | .000001 |
| 1000 | -80 | .0000000099 |

mWはデータを線形的に表現して、dBmはデータを対数的に表現します

# APの配置方法

- 50%の電力で電波を出しているAP(number1と名付けます)を設置します。そのして、dBmを測るソフトウェアで、-67dBmになる場所をマップで記録します。そしたら、AP(number2と名付けます)が電波を出したときに-67dBmになる場所がAP(number1)の-67dBmになる場所と15~20%重なるように設置します。
- もう一つ考慮することがあります。それは、SNR(Signal to Noise Ratio)という、特定の場所から、ノイズの電波とAPからの電波の強さを時系列にまとめたグラフを使う方法です。APからの電波は、ノイズからの電波よりも10~20dB強くある必要があります。

# WLANのSSIDとBSSIDについて

- SSIDというのは、ローカルネットワークの名前です。そして、BSSIDは、ローカルネットワークをさらに細分化したネットワークの名前です。
- なぜこのようなことをするのかというと、ネットワークに接続している人が歩き回った時に接続しているアクセスポイントを切り替えるためです。
- 例えば、アリスさんがアクセスポイントAに繋いでいるとします。しかし、別のところに移動したとします、そのとき、BSSIDを使っていれば、アクセスポイントBに接続できます。もしBSSIDを使っていなければ、無線に名前がないので、どこのアクセスポイントに接続すればいいのかわからなくなります。
- このとき、アクセスポイントを管理するコントローラーも必要になります。このコントローラーがあることで、接続しているアクセスポイントが切り替わったとしても、ログイン状態を維持することができます
switch文利用の注意点について(忘れないように)

本日実務で久しぶりにswitch文を実装する機会があったので、
Java silverにて学んだことをもう1度おさらいで備忘録として残そうかと思います。


## Switch文利用の注意点
注意点は3つです。
基本的には、統合開発環境(eclipseなど)が赤線で教えてくれますが、
最初から知っていれば無駄な修正時間も省けます。


### ①：case文の処理後は、break or returnを忘れない

```java
String status = "open";
int i = 0;
switch (status) {
  case "open":
    i++;
  case "close":
    i++;
    break;//ここまで処理が実行されてしまう
}
```

これは統合環境(eclipseなど)でも赤線を引っ張られないので、記載漏れがあった場合、
テスト時に気づく必要があります。

case文に該当すれば、その中の処理が実施されますが、breakもしくはreturnをしないと次のcase文まで実行してしまいます。


### ②：case文で指定する値は定数でなければならない
```java

public class A {

  String status;

  public void setStatus(String sts) {
    this.status = sts;
  }

  public static void main(String[] args) {
    int i = 0;
    switch (status) {//statusが変数はエラー
      case "open":
        i++;
      case "close":
        i++;
        break;
    }
  }
}
```

上記のコードで言えば、変数宣言時のstatusをstaticに変更する必要があります。


### ③：default文は必ず実行されるものではないが、書き順が大事

switch文1行目のdefault文は、必ず実行されてしまいます。

```java
String status = "open";
int i = 0;
switch (status) {
  default://必ず実行されてしまう
    i++;
    break;
  case "open":
    i++;
    break;
  case "close":
    i++;
    break;
}
```

逆に最後に持ってくると、どのcaseにも該当しなかった場合に必ず実行される処理になる。

```java
String status = "open";
int i = 0;
switch (status) {
  case "open":
    i++;
    break;
  case "close":
    i++;
    break;
  default://どのcaseにも該当しなかった場合にのみ実行
    i++;
    break;
}
```


## 終わりに

switch文は実務では利用することも少なく、見る機会も少ないです。
結局if文の方が便利で慣れ親しんでいるからでしょうか。

ですが、switch文を利用した方が見やすくなる時もあります。
覚えておいて損はないし、これからも使えそうであれば使っていこうと思います。
Enumとの相性が良いのかなと個人的には思いました。
【Rails】options_from_collection_for_selectの使い方

<h1>実現したいこと</h1>
<p>ECサイトの注文情報を入力する画面で、<br>
既に登録されている配送先を、セレクトボックスから選択できるラジオボタンを作る。</p>
 <h1>ざっくり手順</h1>
<p>1. form_withでデータを送る準備をする<br>
2. radio_bottunを設置する<br>
3. セレクトボックスに登録済みの住所を選択肢として表示させる
<h1>1. form_withでデータを送る準備をする</h1>

```ruby:orders/new.html.erb
<%= form_with model: @order, url: orders_confirm_path do |f| %>
<% end %>
```


<h2>解説</h2>
form_withの引数の意味をよく忘れてしまうためここにメモとして残しておきます。<br>
・ model: @order...保存したいテーブルのインスタンス<br>（Ordersテーブルに新たに情報を追加したいのでコントローラーで@order = Order.newと定義する。）<br>
・ url: orders_confirm_path...フォームに入力された情報を飛ばす先のパス　(今回は注文確認画面)


<h1>radio_bottunを設置する</h1>

```ruby:orders/new.html.erb
<%= form_with model: @order, url: orders_confirm_path do |f| %>
  <%= f.radio_button :address_option, 1 %>　#追記部分
  <%= f.label :address_option, "登録済住所から選択" %>　#追記部分
 <% end %>
```
<h2>解説</h2>
・:address_option...どのカラムに保存したいかを指定。<br>
　(今回は何の住所をラジオボタンで選択したか、を保存するカラムが（必要）ないため適当なカラム名を指定し、一時的に保存する用に使う)<br>
・1...このラジオボタンを選択したら、1という値をデータとして保存するよの意味。<br>
・f.label...radio_bottunに名前をつける。<br>
・<%= f.label :カラム名, "表示する値" %>

<h1>セレクトボックスに登録済住所を選択肢として表示させる</h1>

```ruby:orders/new.html.erb
<%= form_with model: @order, url: orders_confirm_path do |f| %>
  <%= f.radio_button :address_option, 1 %>　
  <%= f.label :address_option, "登録済住所から選択" %>
    <%= f.select :address_id, options_from_collection_for_select(Address.all, :id, :address_display) %>#追記部分
<% end %>
```
<h2>解説</h2>
・f.selectでセレクトボックスを作る<br>
・:address_id...どのカラムに保存したいかを指定。<br>
　(今回はどの住所をセレクトボックス内で選択したか、を保存するカラムが（必要）ないため適当なカラム名を指定し、一時的に保存する用に使う)<br>
・options_from_collection_for_select...モデルの情報を引っ張ってきてセレクトボックスを作る。<br>
・（引数１）Address.all...どのモデルからデータを引っ張ってくるかを指定。（今回はAddressテーブルの全て）<br>
・（引数2）:id...セレクトボックスで何を選択したかはAddressテーブルのidを使ってデータとして引き渡すよ。<br>
・（引数３）::address_display...ビューで表示させるもの<br>
※今回はAddressテーブル内の郵便番号、住所、宛名をまとめて表示させたいため、Addressモデルに3つまとめて表示させるためのメソッドを定義する。<br>

```ruby:models/address.rb
  def address_display
  '〒' + postal_code + ' ' + address + ' ' + name
  end
```

<h1>おわりに</h1>
学習したことの記録として初めて記事を書いたので、理解が間違っている部分がありましたらご教示いただけますと嬉しいです。
neovimのLSPによるpythonの補完で、opencvの補完が正常に効かない

半年くらい前にvscodeからneovimに乗り換えたのですが、opencvの補完だけが正常に動いてくれないということがあって悩んでいました。numpyとかは普通に補完が効くのですが、例えば以下のようなコードを書いてみると、

```
import cv2

img = cv2.imread('sample.png')
cv2.imshow('img', img)
cv2.waitKey(0)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733597/4ef4c147-2a01-f652-ba9c-771ecbffe8a9.png)

こんな風にneovim上で怒られてしまいます。ただし、ターミナル上では問題なくこのコードは動きます。

## 解決策
https://github.com/emacs-lsp/lsp-pyright/issues/41

このissueを参考にしました。
以下のようにターミナル上でコマンドを打つと解決します。

```
$ pip install mypy
$ python3 -c 'import cv2; print(cv2)'
$ stubgen -m cv2 -o {cv2-package-folder}
$ cd {cv2-package-folder}
$ mv cv2.pyi __init__.pyi
```

1行目で、opencvが入っているディレクトリが出力されます。例えば次のようなものです。
```
<module 'cv2' from '/opt/homebrew/var/pyenv/versions/test/lib/python3.9/site-packages/cv2/__init__.py'>
```
ここのfrom以下の
```
/opt/homebrew/var/pyenv/versions/test/lib/python3.9/site-packages/cv2
```
が、{cv2-package-folder}を指しています。
あとは上記のコマンド通りに行えば大丈夫なはずです。
[応用情報技術者試験】平成30年春期_問4を解いてみた

## 応用情報技術者試験の平成30年春期、問4を解いてみます。

### 問題
サンプリング周波数40kHz，量子化ビット数16ビットでA/D変換したモノラル音声の1秒間のデータ量は、何kバイトとなるか。ここで、1kバイトは1,000バイトとする。

:::note warn 
### 選択肢
ア\.20
イ\.40
ウ\.80
エ\.640
:::

それでは解いていきましょう。


### 解説
まずは用語解説から、、、
・サンプリング周波数：標本化において、1秒間にアナログ音声からデータを取得する回数
・量子化　　　　　　：標本化で得られた数値を整数などの離散値で近似すること
・A/D変換　　　　　 ：Analog/Digital Conversion つまりアナログ信号をディジタル信号へ変換すること

サンプリング周波数が40kHzということは、1秒間でアナログ音声からデータを取得する回数が40,000回。
量子化ビット数16ビットのため、１秒間で変換できるデータ量は、40,000回×16ビット＝640,000ビット。
よって、640kビットのデータ量を変換したということがわかる。
問題問われているのは何kバイトか、なので単位をそろえると、640kビット÷8　=80kバイト

**よって答え80kバイト**
値型、参照型とは？

普段何気なく、このような形で値渡しをおこなっていた。

```Swift
var a = 0
var b = a

b = 1
print("a: \(a)")
print("b: \(b)")

a = 5
b = a
print("b2: \(b)")

let c = 0
c = b
print("c: \(c)")
```

もちろん結果は以下の通りである。

```Swift
a: 0
b: 1
b2: 5
Cannot assign to value: 'c' is a 'let' constant
```

しかし、値型と参照型を全くもって理解していなかったので、ここにメモを残す。

# 値型とは？
Swiftで基本的に用いられるString, Int, Array, Dictionaryなどは全て値型である。
なので、上記に記述されている内容も値型であり、代入や関数に引数として渡される際に値がコピーされる。また、代入や演算によって前のデータは変更されることはない。

具体的に、上記の内容で、bが8に変わったからといって、aが8になることはありえない。

# 参照型とは？
参照型とは代入や関数に引数として渡される際に値そのものではなく、データ自体への参照を渡すデータ型のことをいう。
例：　クラスとクロージャは参照型

具体的な例を以下に記す。

```Swift
class CafeClass {
    var name: String
    var place: String

    init(name: String, place: String) {
        self.name = name
        self.place = place
    }
}
let cafeClass = CafeClass(name: "Starubucks", place: "Mejiro")
cafeClass.place = "Ikebukuro"
print("cafeClass.place: \(cafeClass.place)")

// 以下がプリントされる。
// cafeClass.place: Ikebukuro
```

ここで違和感を感じた方もいると思う。なぜなら、
```Swift
let cafeClass = CafeClass(name: "Starubucks", place: "Mejiro")
cafeClass.place = "Ikebukuro"
```
こちらのcafeClassは静的であるにも関わらず、"Ikebukuro"に置き換わっているからだ。

なぜこのようになるかというと、
参照型はデータ自体へアクセスするからである。

全く同じ内容をstruct内でやってみると、

```Swift
struct CafeStruct {
    var name: String
    var place: String

    init(name: String, place: String) {
        self.name = name
        self.place = place
    }
}

let cafeStruct = CafeStruct(name: "Starbucks", place: "Mejiro")
cafeStruct.place = "Ikebukuro"
print("cafeStruct.place: \(cafeStruct.place)")

// 以下のエラーとなる。
// Cannot assign to property: 'cafeStruct' is a 'let' constant
```
なぜなら、CafeStructの方は普段よく使う値型だからである。

さらに、参照型は以下のような記述において、

```Swift
class CafeClass {
    var name: String
    var place: String

    init(name: String, place: String) {
        self.name = name
        self.place = place
    }
}
let cafeClassA = CafeClass(name: "Starubucks", place: "Mejiro")
let cafeClassB = cafeClassA
cafeClassB.place = "Naha"

print("cafeClassA.place: \(cafeClassA.place)")
print("cafeClassB.place: \(cafeClassB.place)")

// 以下がプリントされる。
// cafeClassA.place: Naha
// cafeClassB.place: Naha
```

CafeClass自体の構造体にアクセスすることで、cafeClassA自体の値も置き換わる。
LeetCodeWeekly310-D: LISをRangeMaxQuery(セグ木)で求める(項の差制限のあるLIS)

選択する数字に制限のあるLISを求めます。以下のLISは厳密な増加のみを考えます。

LISの代表的な求め方として
- 1: $A[i]$ = 長さiのLISの中で末尾の最小値 をもって二分探索
- 2: $B[i]$ = 末尾の値がiであるLISの長さ をもって区間Maxクエリ、1点更新
の2つがあります。ここでは"2"のアプローチをとります。


# 題材: 隣り合う項の差がk以内のLIS
例えば以下のようなLISを求められます。
- 各要素の差が$k$以内であるようなLIS

https://leetcode.com/contest/weekly-contest-310/problems/longest-increasing-subsequence-ii/

例1: nums = $[4,2,1,4,3,4,5,8,15]$, k = 3のとき、5。 制限のないLISでは$[1,3,4,5,8,15]$が作れますが、8と15はk=3よりも大きく離れているのでこの問題で有効なLISではないです。

例2: num = $[2,1,3,4]$ k= $1$のとき、$[2,3,4]$で2

# 二分探索のLIS解法
多くのLIS解法で用いられる`A[i] = 長さiのLISの中で末尾の最小値`を記録した二分探索で求める方法を二分探索のLISの求め方とします。詳細は以下のような記事を参照してください。

https://perogram.hateblo.jp/entry/2019/07/27/051604

さて、今回のように制限のある場合にも`Aを更新するときにk以内かを確認すればうまくいくのでは？`と考えるかもしれませんがこれはうまくいきません。

上記の例2入力の$[2,1,3,4]$を例にとって示します。まず、$2$を処理し、$A = [3]$となります。$1$を処理するとき、同じ1文字までのLISしかできないならば、3より1の方が好ましいので$A = [1]$に更新されます。次に$3$を処理しますが(k以内かを見るとして)1には続けられないので捨てます。$4$も同様です。こうして、$[2,3,4]$となってほしいですが$[1]$と出力されます。

このように二分探索のLISの求め方では過去の数字を覚えていないため、$x$という値があった際に差が$k$以内という条件を満たせる値が過去にあったかが記録できません。

# RMQを使ったLIS(セグ木など)
二分探索でLISを求める手法では過去にどんな数字があったのかを覚えていないため、今回の問題が解けません。先ほどの例2では$2$を処理した際にそれを覚えておけばそのあとに続けられました。

これを行うために`B[i] = 末尾の値がiであるLISの長さ`としましょう。もし、kの制限がないとするなら、入力$a_1, a_2 \cdots a_n$があったとき、$B[a_i]$ = $max(B[0], B[1], \cdots B[a_i-1]) + 1$として求められます。これを工夫せずは求めると$O(a_i)$の計算量ですが、セグメント木などで1点更新のRange Maxを管理しておけば$O(log a_i)$で求められます。

例2を例にとると、長さ5(0-4)のBの配列を考えると、$[0,0,0,0,0]$ -> $[0,0,1,0,0]$ -> $[0,1,1,0,0]$ -> $[0,1,1,2,0]$ -> $[0,1,1,2,3]$となり、その最大値3がLIS長です。

## 座標圧縮の活用
ただし、セグ木は入力の値の上限が$M$とすると空間計算量$O(M)$となり、$a_i < 1e18$などの大きい場合に対応できません。この場合は座標圧縮を行えば、入力の個数$N$に対して$O(N)$となり競技プログラミングの問題などでは対応が可能です。

# 実装(座圧なし)
```c++
#include <atcoder/segtree>
#include <vector>
using namespace std;
using namespace atcoder;
int op(int a, int b) { return max(a, b); }
int e() { return -1; }
#define M 1000000 // 大きな数を扱うなら適当に座標圧縮する
int solve(vector<int> &input, int k){
    int ans = -1;
    segtree<int, op, e> seg(M);
    for(auto &r: input){
        int l = max(0, r - k);
        int lislen = max(1, seg.prod(l, r) + 1);
        seg.set(r, lislen);
        ans = max(ans , lislen);
    }
    return ans;
}
int main() {
    vector<int> a;
    a = {4,2,1,4,3,4,5,8,15};
    cout << solve(a, 3) << "\n"; // 5
    a = {2,1,3,4};
    cout << solve(a, 1) << "\n"; // 3
    a = {7,4,5,1,8,12,4,7};
    cout << solve(a, 5) << "\n"; // 4
    a = {1,5};
    cout << solve(a, 1) << "\n"; // 1
}
```
zabbixで消費電力監視。SwitchBotプラグミニ(W2001400-GH)

スマホアプリでは、グラフが一日単位なので分単位で様子を見られるよう、zabbixに登録します。
PS5ってどれだけ電気使ってるんだろう？ということです。

用意する物
SwitchBotプラグミニ(W2001400-GH)
 https://www.green-house.co.jp/products/switchbot-plug-mini/
2.4GHzのwifiアクセスポイント


前準備
スマホアプリSwitchBotより、セットアップします。
1.右上の「＋」ボタンを押し、デバイスの追加画面で「プラグミニ(JP)」を選択
2.プラグミニをコンセントに刺し、横の電源ボタンを長押し
3.2.4GHzのwifiに接続します
4.名前とかは適当に

設定ネタ用意
1.スマートフォンアプリ内の「プロフィール」、「設定」を選択
2.「アプリバージョン」を１０回タップ（途中変化しません）
3.「開発者向けオプション」が増えるので、選択
4.トークンを作業用PCに持ってきます。

値が取得できるか確認
1.デバイスID取得
$ curl -H "Authorization:＜アプリから取得したトークン＞" -X GET "https://api.switch-bot.com/v1.0/devices" | jq

  "statusCode": 100,
  "body": {
    "deviceList": [
      {
        "deviceId": "6055F9XXXXXX",　←これがデバイスID
        "deviceName": "プラグミニ 76",
        "deviceType": "Plug Mini (JP)",
        "enableCloudService": true,
        "hubDeviceId": "000000000000"
      }
    ],
    "infraredRemoteList": []
  },
  "message": "success"
}
2.現在値の取得
$ curl -X GET "https://api.switch-bot.com/v1.0/devices/＜デバイスID＞/status" -H "Authorization: ＜アプリから取得したトークン＞" -H "Content-Type: application/json" | jq 

{
  "statusCode": 100,
  "body": {
    "deviceId": "6055F9XXXXXX",
    "deviceType": "Plug Mini (JP)",
    "hubDeviceId": "6055F9XXXXXX",
    "power": "on",
    "voltage": 101.5,　←電圧(V)
    "weight": 0.9,　←消費電力(W)
    "electricityOfDay": 678,
    "electricCurrent": 0.66　←電流(A)
  },
  "message": "success"
}

zabbix設定
1.テンプレート作成
「設定」→「テンプレート」を選択、右上の「テンプレートの作成」を選択します。
テンプレート名：Switchbot Plug Mini_JP
グループ：Templates/Modules これが適切かは不明・・・

2.アイテムの作成
テンプレートを開き、右上の「アイテムの作成」を選択します。
■タブ：アイテム
名前：switchbot.plugmini.json
タイプ：HTTPエージェント
キー：switchbot.plugmini.json
データ型：テキスト
https://api.switch-bot.com/v1.0/devices/＜デバイスID＞/status
ヘッダー：
|名前 | 値 |
|:-:|:-:|
| Authorization | ＜アプリから取得したトークン＞ |
| Content-Type  |application/json   |

■タブ：保存前処理
保存前処理の設定
|名前 | パラメータ |
|:-:|:-:|
|JSONPath|$.body|
|データ型：|テキスト|

以上を入力し、「テスト」をクリックし「値の取得とテスト」を行いエラーが発生しなければ
保存します。

3.値を取得するアイテムの作成
右上の「アイテムの作成」を選択します。
■タブ：アイテム
名前：voltage
タイプ：依存アイテム
キー：voltage
データ型：数値 (浮動小数)
マスターアイテム：Switchbot Plug Mini_JP: switchbot.plugmini.json
単位：V
■タブ：保存前処理
|名前 | パラメータ |
|:-:|:-:|
|JSONPath|$.body.voltage|

データ型：数値 (浮動小数)

以上を入力し保存します。
同様に、weight、electricityOfDay、electricCurrentも追加しておきます。
先に作成した、voltageを開いて複製して作成すると楽です。

4.右上の「グラフの作成」を選択します。
作成したアイテムお好きに作成。

5.右上の「ホストの作成」を選択します。
ホスト名：Plug Mini_PS5
テンプレート：Switchbot Plug Mini_JP
グループ：Templates/Modules
追加します。

しばらく待つと、値が取得され、グラフができてきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551483/28b050c5-04ad-cf67-4633-32623547f8f4.png)
【Java基礎】インターフェース

# はじめに
最近Java基礎の研修を受けました。学生時代にJavaを授業で習って基礎は身につけていたのですが、忘れていた内容もあったので備忘録として書き残してみます。

この記事では、**Javaの基礎的な内容に関してまとめていきます**。
今回は**インターフェース**です。



# インターフェースとは
**インターフェース**とは、原則として、**publicな抽象メソッドだけを宣言できるクラスのようなもの**です。コンストラクタも宣言することができません。また、**インスタンス化できない**のも特徴です。


# インターフェースの宣言
インターフェースは以下のように宣言します。
```java:インターフェースの形式
修飾子 interface インターフェース名 {
    インターフェースのメンバ
}
```


## メソッド
インターフェースには、publicな抽象メソッドが宣言できます。
```java:抽象メソッドの宣言例
interface Booking {
    public abstract String getTitle();
    List<String> getContent();  // public abstractは省略できる
}
```
    

## フィールド
インターフェースでは、`public static final`なフィールド（定数）のみ宣言できます。
```java:フィールドの宣言例
interface Booking {
    public static final String NAME = "Qiita_Official";
    int PRICE = 1000;  // public static finalは省略できる
}
```



# インターフェースの実装
インターフェースは単独でインスタンス化できません。インスタンス化には**実装クラス**が必要です。実装クラスとは、インターフェースの抽象メソッドを全てオーバーライドした具象クラスのことです。
実装クラスを宣言することを**インターフェースを実装する**と呼びます。

インターフェースは以下のように実装します。
```java:実装クラスの形式
修飾子 class クラス名 implements インターフェース名 {
    // 抽象メソッドをオーバーライド
}
```

```java:実装クラスの例
class Introduction implements Booking {
    // この時点ではコンパイルエラー
}
```


## メソッドのオーバーライド
実装クラスは、インターフェースの抽象メソッドを全てオーバーライドする必要があります。
```java:実装クラスの例
class Introduction implements Booking {
    private String title;

    public Introduction(String title) {
        this.title = title;
    }

    @Override 
    public String getTitle() {
        return title;
    }

    @Override 
    public List<String> getContent() {
        return List.of(
            "Qiitaの投稿方法について紹介している本です。",
            "簡単な記事を1つ投稿することを目標としています。"
        );
    }
}
```

実装クラスも通常のクラスです。フィールドやメソッド、コンストラクタを宣言できます。



## インターフェースの複数実装
1つのクラスで複数のインターフェースを実装することができます。

```java:新しいインターフェース
interface Writing {
    void write();
}
```

複数のインターフェースを実装するときは、それぞれのインターフェースが持つ抽象メソッドを全てオーバーライドします。
```java:複数インターフェースの実装例
class Conclusion implements Booking, Writing {

    @Override 
    public String getTitle() {
        return "要旨";
    }

    @Override 
    public List<String> getContent() {
        return List.of(
            "Qiitaの投稿方法について紹介している本です。",
            "簡単な記事を1つ投稿することを目標としています。"
        );
    }

    @Override 
    public void write() {
        List<String> content = getContent();
        for (String line : content) {
            System.out.println(line);
        }
    }

}
```



# まとめ
今回の記事で紹介したインターフェースと、前回紹介した継承を利用することで、簡潔にコードを記述できるようになります。上手に実装していくことで、javaで美しいコードが書けるように頑張りましょう！
作りたいものから逆算して学ぶFireStore、例えば予約システム②

[「作りたいものから逆算して学ぶFireStore 、例えば予約システム ①」](https://qiita.com/yasumasa_01/items/6d29a5dd1fec2b0881b3)からの続きの記事になります。

FirestoreのarrayUnionとarrayRemoveを説明するために、実用的テーストを入れてシンプルに作ろうと思ったら、知識不足を思い知ることに！

[気になるかたはGitHubでご覧ください！FireStore9BasicTechnique](https://github.com/yahsmassa/FireStore9BasicTechnique)
## 結論
#### 配列を階層に持つと関連データ処理が予想外に大変になります。やりながら後悔しました。ただカレンダーコンポーネントではそういうデータ形式を使ったりすると思うので、必要に応じてそういうデータ構造にすれば良いと思います。
##### とりあえず作成したものを画面で見てください。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259753/c70a79f4-afba-7e05-17c4-b4d904109ffa.png">

それでもって、arrayUnionとarrayRemoveを使って、増減する配列部分がこれ
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259753/e4e6e1b2-0810-8ae9-d1b0-39f936e380e5.png">
画面右のreserveArrayの０とか１っていうのが、予約を登録するたびに増えてきます。
一覧画面の右のCancelボタンを押すと、配列の要素が削除されます。

###### 大変だったこと

- 登録するときの存在チェックなど
- 削除するとき複数の配列から特定の配列を探さなくてはならない
- 階層型のデータを表で表すとき、変換しないと使いにくい
- Material UIのフォーム（慣れたら使いやすそう）
- フォームの状態管理（useForm.tsというところでやってます）
- 日付と時間の計算処理 (util.tsでやってます)
- 配列のデータ階層はすっきり書きにくい

でした。失敗したことで、自分の知識が足りないところがいろいろわかりました。
arrayUnionは使うのは一瞬ですね。登録する時のTry部分１行のみ
```firebaseAdvance.ts
export const addReserve = async (
  ymd: string,
  staffNo: number,
  clientName: string,
  menu: string,
  startTime: string,
  endTime: string
) => {
  const id = getStaffReserveId(ymd, staffNo);
  const docRef = doc(db, "staff_reserve", id);
  const mydoc = await getDoc(docRef);
  if (mydoc.exists()) {
    const reserve = makeReserveObject(clientName, menu, startTime, endTime);
    try {
      await updateDoc(docRef, {
        reserveArray: arrayUnion(reserve),
      });
    } catch (error) {
      Swal.fire("addReserveRecord", "Can't add Reserve Data", "error");
    }
  } else {
    addStaffReserve(ymd, staffNo, clientName, menu, startTime, endTime);
  }
  Swal.fire("Reserve Success");
};
```
arrayRemoveも使うのは一瞬、同じく下のTry部分だけ１行
```firebaseAdvance.ts
export const removeReserve = async (
  ymd: string,
  staffNo: number,
  startTime: string,
  endTime: string
) => {
  const id = getStaffReserveId(ymd, staffNo);
  const staffReserveRef = doc(db, "staff_reserve", id);
  const myDoc = await getDoc(staffReserveRef);
  if (!myDoc.exists()) {
    Swal.fire("removeReserveRecord", "Can't Find StaffReserveData", "error");
    return;
  }
  const ExistReserve = myDoc.data() as StaffReserve;
  const reserve = findReserve(ExistReserve, startTime, endTime);
  if (reserve) {
    try {
      await updateDoc(staffReserveRef, {
        reserveArray: arrayRemove(reserve),
      });
    } catch (error) {
      Swal.fire("removeReserveRecord", "Can't Edit Record", "error");
    }
  } else {
    Swal.fire("removeReserveRecord", "Can't Find Reserve", "error");
  }
  Swal.fire("removeReserveRecord", "Reserve is Canceld", "success");
};

```
記事にするのやめようと思いましたが、Githubのコードを眺めたら、もしかして使えるフレーズがいくつか探せるかもしれません。

自分的には、useFormのところや、存在チェック、階層のあるデータをStateで持ったときの部分削除処理とか、日付系の関数を作ったとこは、他で役に立ちそうで良かった感じです。

今回、プログラミングは考えるより、慣れろを実感しました。
残念なことに、今回はFireStoreはあまり関係なかったかも。
【UiPath】データテーブルの列名で繰り返し処理する

たまに必要になる列方向の繰り返しについてです。
**繰り返し (コレクションの各要素) (For Each)** アクティビティで、
**DataTable.Columns** プロパティを使って処理します。

- 実装例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/98d9620e-1ecf-6155-c0ad-ad7f9d924656.png)
- 繰り返し (コレクションの各要素) のプロパティ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/4d37278c-66f8-a2fc-7c75-b7d81f652735.png)
- 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/b081e5f5-ad4c-f32f-73cc-5e5808d9597d.png)

他にも色々方法あると思いますがこれがシンプルで良いかなと思います。


## 参考
https://docs.uipath.com/activities/lang-ja/docs/for-each

https://docs.microsoft.com/ja-jp/dotnet/api/system.data.datatable.columns?view=net-6.0
react-router-dom v6でログインしているユーザーだけがアクセスできるようにする(ネストにしても画面が変わらない)

# はじめに

Webサイトを作るのに必要なログイン部分に時間を使ったのでまとめていきます
react-router-dom v6に対応しています

# 問題

react-router-dom v6を利用しています
Recoil(useContext)でグローバルに`isLogin`というフラグを用意して、`true`の時にはログイン済みとして、`false`の時はログイン後の画面に直接アクセスするとログイン画面にリダイレクトするようにしたいです

# 解決方法

以下のように設定することで実現できました

```tsx:Authenticated.tsx
import React from "react";
import { Outlet } from "react-router-dom";

export const Authenticated = () => {
  return (
    <>
      <Outlet />;
    </>
  );
};
```

```tsx:router.tsx
      <Route
        path="/"
        element={
          isLogin ? <Authenticated /> : <Navigate to="/sign_in" replace />
        }
      >
        <Route index element={<Home />} />
        <Route path="setting" element={<Setting />} />
      </Route>
```

ポイントは`<Outlet />`を利用することでした
Routerでネストにしたときにネストしたコンポーネントが表示されるのは`<Outlet />と書いたところです
これを書かないとネストしても画面が変わらないという現象が起きるので注意が必要です

なので、<Outlet>の箇所がURLによって切り替えられるようにしました

ログインしているユーザーだけがアクセスできるようにする仕組みは`element`の箇所で3項演算することで制御しています

# おわりに

思ったよりも実現に時間がかかりました
誰かの参考になればと思います

# 参考

https://www.robinwieruch.de/react-router-nested-routes/