OmniAICreator/Qiita-1.07M huggingface dataset:
Meta Quest Pro x MRTK ビルド時のエラー解消

## 何が起きたか

Meta Quest Pro と MRTKv2 を組み合わせて環境構築したところ下記のエラーが発生。

> Shader error in 'Mixed Reality Toolkit/Standard': Non system-generated input signature parameter () cannot appear after a system generated value. at line 775 (on ges3)

## 解消方法

Assets/MRTK/Shaders/MixedRealityStandard.shader を以下のように変更

```diff:MixedRealityStandard.shader:755行目
- fixed4 frag(v2f i, fixed facing : VFACE) : SV_Target
+ fixed4 frag(v2f i, bool facing : SV_IsFrontFace) : SV_Target
```

```diff:MixedRealityStandard.shader:956行目
- worldNormal = normalize(worldNormal) * facing;
+ worldNormal = normalize(worldNormal) * (facing ? 1.0 : -1.0);
```

```diff:MixedRealityStandard.shader:959行目
- worldNormal = normalize(i.worldNormal) * facing;
+ worldNormal = normalize(i.worldNormal) * (facing ? 1.0 : -1.0);
```

### 参考サイト
https://github.com/microsoft/MixedRealityToolkit-Unity/issues/10532#issuecomment-1358065414

## 確認環境

- Unity 2021.3.9f1
- Mixed Reality Toolkit Examples 2.8.3
- Mixed Reality Toolkit Extensions 2.8.3
- Mixed Reality Toolkit Foundation 2.8.3
- Mixed Reality Toolkit Standard Assets 2.8.3
- Oculus XR Plugin 3.0.2
- Oculus Integration SDK 49.0
Route53Resolver転送ルールの共有によるコスト削減

# はじめに
オンプレミスとの間での名前解決の転送に欠かせいないResolverの転送ルールと、エンドポイントの共有について書いていきたいと思います。

# シングルアカウントでの構成
まずは通常パターンです。
特定の名前解決に関して、オンプレミス等のDNSに転送したい場合は、Route53リゾルバルールの定義と、通信の出口となるアウトバウンドエンドポイントを作成します。
名前解決は、リゾルバを経由し、ルールにマッチした場合、転送先に指定したDNSサーバにアウトバウンドエンドポイント経由で行われます。
![スクリーンショット 2023-02-12 19.26.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584167/ecaf803c-1d8e-6b6e-076a-9b6d1054ed92.png)


# マルチアカウントでの構成
次にマルチアカウントでの構成を考えてみます。
普通に考えると、シングルアカウント構成の場合と同じく、対象のVPCそれぞれにリゾルバルールならびに、アウトバウンドエンドポイントを作成し、名前解決を行います。
※TransitGW等の記載は省略しています。
![スクリーンショット 2023-02-12 19.27.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584167/617f4b81-7181-552e-f8c1-701c527617f9.png)

# マルチアカウントでの構成（転送ルールの共有）
次に転送ルールの共有を行った場合の構成です。
この場合、まずリゾルバルールの共有を、アカウント間で共有します。
そうすると、共有したリゾルバルールで定義した名前解決をVPC-Aのアウトバウンドエンドポイント経由で名前解決することが可能です。この際、２つのVPC間を接続する必要はありません。また、アウトバウンドエンドポイントは１つに集約ができます。
![スクリーンショット 2023-02-12 19.27.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584167/564e2c62-dfcf-1deb-f44b-22fc886f5ecd.png)

# ２つの構成の比較
正直どちらもよいのでは？と思うかもしれませんが、２つの構成において、メリデメがそれぞれあります。
転送ルールを共有する場合のメリットはコストです。

0.125USD / 1 時間＊AZ数の料金がかかるため、安くはありません。アカウントが増えれば増えるだけ、このコストがかさみます。ルールを集約するとこのコストを削減することが可能です。ただし、ルールのメンテナンスが１アカウントに集約されるため、組織内で手続きや運用ルール等を事前に定めておく必要があります。

https://aws.amazon.com/jp/route53/pricing/

| 構成 | メリット | デメリット |
| --- | --- | --- |
| 転送ルール共有なし | ・アカウントごとに転送ルールを定義できるため、アカウントごとに組織が別れている場合などに調整が不要<br> | ・アウトバウンドエンドポイントのコストがアカウント数分かかる |
| 転送ルール共有あり | ・アウトバウンドエンドポイントのコストが１アカウント分のみとなる | ・転送ルールを１アカウントに集約するため、対象アカウントを管理している側で、ルールのメンテナンスが必要。組織が別れている場合などでは、運用が複雑になる可能性がある |

# まとめ
ハイブリッドクラウドでは名前解決が非常に重要な要素となります。
今回は外部への名前解決をどのように実装するのか、そのコストをどのように削減可能かを記載しました。
２つのメリット、デメリットを把握し最適な構成を選択していきましょう。

# 参考

https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/resolver-rules-managing.html#resolver-rules-managing-sharing
ExcelVBAとSeleniumでWebのプルダウンメニューの選択肢をExcelシートに一括で書き出す。ループ処理無し。

# やりたいこと
Webサイト上のプルダウンメニュー（HTMLのSelectタグ）の選択肢（Option）を
一括でExcelのシート上に書き出したい。
[イメージ]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/8b3892d4-60cd-b986-8819-1612c35188d8.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/1730765f-e4fa-8916-f075-0a7f508d9b31.png)

ただしループ処理を使うと選択肢が多い時に遅くなるので、
配列処理で一括で書き出したい。

# コード
コードです。前提として、SeleniumBasicとChromeDriverのインストールが完了しているものとします。
```vb
Sub Get_selectoptions()
  'Chrome起動
  Set Driver = New selenium.ChromeDriver
  
  '目的のサイトにアクセス
  Driver.Get "https://***"
  '目的のプルダウンメニューをオブジェクトとして取得
  Set myselect = Driver.FindElementByXPath("****")
  
  'プルダウンの選択肢をtextで一括取得し、改行(chr(10))で配列に分解する
  option_array = Split(myselect.text, Chr(10))
  
  '貼り付け先となるセル範囲を上記の配列でリサイズする。
  '貼り付ける値はTransposeで行列を逆転させると、縦方向に貼り付けが可能
  Selection.Resize(UBound(option_array)).Value = WorksheetFunction.Transpose(option_array)

End Sub
```

# 逆にExcelシートの内容をプルダウンに反映
上記と逆に、Excelシートの内容をプルダウンに反映したい場合
```vb
'プルダウンの選択肢を選択状態にする
Driver.FindElementsById("***").AsSelect.SelectByText hoge
```
のように、```AsSelect.SelectByText```で選択状態にできます。

# おわり
以上です。お疲れ様でした。
Gitでチェックアウトする際に同期されるかのまとめ

# 挨拶
初めまして、日本システム開発株式会社の鈴木です。
技術者として更なる向上を目指すためQiitaアウトプットをする取り組みを行っています。
技術者としては経験が浅く発信内容はとにかく試したものの覚書になります。
業務中git操作とローカルにあるファイルが更新されるタイミングを勘違いしていることがあったため本稿ではgit操作とローカルブランチのファイルが更新されるタイミングについてまとめます。

# テスト環境
githubにbranch_testリポジトリを作成しローカル環境にbranch_testディレクトリ（ディレクトリA）とbranch_test2ディレクトリ（ディレクトリB）を作成しておきます。

# 確認
ディレクトリAにgit cloneコマンドでbranch_testリポジトリ(mainブランチ)を複製後、以下のようなoperation.txtを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/35b57dd4-8956-f7cd-9fa6-53480ee85dcb.png)
この状態でコミット、プッシュまで行います。
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/b79f9243-edaa-de19-3a84-38ebb464fa33.png)

プッシュを行っているためこの段階ではリモートとローカルは同期されています。

続いてディレクトリBでクローン。
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/3d692364-7e25-c749-417d-5cde7605ea44.png)
この段階ではoperation.txtが生成され、**内容も最新です。**
ここで、new_branchブランチを作成し切り替えた後に、以下のように編集します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/e322388a-27f3-f4a8-da8a-54e988c3d3f6.png)
その後、プッシュを行いブランチを公開します。
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/0121e0e3-7407-df74-f785-f51f62e559ec.png)

再びディレクトリAに戻りfetch、new_branchに切り替え。
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/098d5b2f-6187-ab7f-b512-8e30ff0068a3.png)
ここまで行うとoperation.txtは「checkout」の記述がある **最新版が配置されます。**

new_branchにあるディレクトリBでoperation.txtを再び以下のように更新し、プッシュ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/005a53fd-d460-c8a0-d48d-f4fd83758869.png)
これでリモートのnew_branchブランチでもoperation.txtに「push after checkout」が記述されます。
この状態でnew_branchにあるディレクトリAでnew_branchブランチへチェックアウトを行うと、すでに指定のブランチであるため失敗、**最新版にはなりません** 。
![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/bacf825d-c203-56cd-2a91-05ab89151cb1.png)
さらにこの状態でローカル、リモートブランチをもとに新たなブランチを作成する場合、 **いずれの場合も最新版にはなりません。**

最後に、リモートブランチをもとに作成したブランチにいるディレクトリBでpullを行うと、 **最新版に更新される。**
![画像7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641357/aa7035cc-f0f0-a1fd-1a38-9a38db894c1c.png)

# まとめ
cloneを行う→最新版に同期される
ローカルに存在しないブランチにcheckout→最新版に同期される
すでにローカルに存在するブランチにcheckout→最新版に同期されない
リモートに存在するブランチを元にブランチを作成→最新版に同期されない
pullを行う→最新版に同期される

ブランチ状態によりcheckoutだけで最新版になることは保証されないため、手順書などでは必ずpullするようにしましょう。
プログラミングを教えるときに伝えること

今NPOでボランティアをしているが、そこで主に伝えていること

# プログラミング
## 1. プルリクの前に美徳を確認すること
プログラミング以外には必要ないが、いいプログラミングを考える際に美徳が役に立つ

https://freelance-start.com/articles/575

## 2. コメントはできる限り書かないこと
https://qiita.com/hiro-hori/items/1cf28a6ac75db077c8f3

## 3. すべての処理(PG以外の作業も含まれる)は入力と変換と出力であり、入力と変換を改善すること

```js: test.js
// numberが入力にあたる
function test(number){

    // 内部処理が変換にあたる
    const result = number * 2;

    // resultが出力にあたる
    return result;
}
```

上記処理の場合、留意するべきは入力(number)と変換（number * 2）になる。
入力は正しいか？変換のもっとよいコーディングはないかを意識すること。


## 4. 可能な限り、定常作業は自動化すること、ただしプルリクを上げる際は自動出力されたものでも責任を持つこと
[lint](https://e-words.jp/w/lint.html)なども積極的に使うべきだが、最後はプログラムに対して責任を持つこと。
なぜこの変数名にしたのか、なぜ関数を作成したのかについて説明する必要がある。

## 5. キーボードからバグが生まれる
キーボードでプログラミングをするたびにバグが生まれていく。プログラミングは最小限にすること。矛盾するようだが、プログラミングをしないことが一番望ましい。

## 6. 人を責めるな、仕組みを責めよ
https://toyokeizai.net/articles/-/191557?page=2#:~:text=%E3%81%93%E3%81%AE%E7%BF%92%E6%85%A3%E3%81%AF%E3%80%81%E3%80%8C%E4%BA%BA%E3%82%92,%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%A7%E3%81%99%E3%80%82


# 日々の過ごし方
## 1. 最新情報をキャッチすること、また発信すること

いつもしていること
1. RSSリーダー([inoreader](https://www.inoreader.com/language/japanese)がおすすめ)に気になるサイトなどを登録しておく
    - 何も思いつかない人は[prtimes](https://prtimes.jp/)がいいだろう
1. 日々RSSリーダーにきた情報を確認して、Notionに登録(登録は[Notion Web Clipper](https://www.notion.so/ja-jp/web-clipper)を利用している)
1. 登録した内容をアウトプット
    - 私はnoteにbookmark一覧を出している([記事例](https://note.com/karada1/n/n7f902936bca8))

## 2. 本をできる限り読むこと
図書館はすでに契約している本のサブスクです。大学図書館含め、積極的に活用しましょう。

本のメリットは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172695/6f1fb5b6-34d9-494a-403e-c9be5f5120d9.png)

また、技術書以外も読むこと

https://atmarkit.itmedia.co.jp/ait/articles/2108/11/news006.html

おすすめ
- [市場をつくる](https://www.keio-up.co.jp/np/isbn/9784766427837)
    - システムも含めて、あらゆるものに2元論は避けるべき
        - 例：AIはすべてを解決する、AIは破滅の始まりなど
- [コンテナ物語](https://www.amazon.co.jp/dp/4822245640)

## 3. 悩んだときは、選択肢を列挙すること
https://qiita.com/little_hand_s/items/9d1bb19daa54ae346914

どんなに実現可能性が低いものでも選択肢を列挙すること。
そうするとその中から比較検討ができるようになる。

## 4. 工夫すること

例えば新入社員の方が発表前に緊張してそうであればアロマをそっと差し入れたり、
例えば肌寒い日の社員旅行に温かいゆず茶を水筒に入れて持っていったり、
そんな工夫（またはしなくてもいいけど、したほうがいいこと）をチャレンジすることが大事。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172695/e00944ae-3f9a-3289-8e17-2c3ba52b3fc1.png)

```
工夫とは、既存のものに手を加えて、より良くすることです。工夫をすることで、効率や効果を向上させることができます。

工夫には、様々なメリットがあります。

効率の向上：工夫することで、同じ量の作業をより短い時間で行うことができます。
効果の向上：工夫することで、同じ時間でより良い結果を得ることができます。
創造性の向上：工夫することで、新しいアイデアを生み出すことができます。
問題解決能力の向上：工夫することで、問題を解決するための新しい方法を見つけることができます。
コミュニケーション能力の向上：工夫することで、自分の考えを他人に伝え、理解してもらいやすくなります。
工夫は、仕事や勉強、日常生活など、あらゆる場面で役立ちます。工夫をすることで、より効率的で効果的な生活を送ることができます。

工夫をするためのコツをいくつか紹介します。

問題意識を持つ：工夫をするためには、まず問題意識を持つことが大切です。問題意識を持つことで、工夫の方向性が見えてきます。
固定観念にとらわれない：工夫をするためには、固定観念にとらわれない発想が大切です。既成の考え方に囚われず、新しいアイデアを生み出しましょう。
失敗を恐れない：工夫をするためには、失敗を恐れないことが大切です。失敗を恐れず、様々なことに挑戦することで、新しいアイデアを生み出すことができます。
工夫は、誰でも身につけることができるスキルです。工夫をすることで、より充実した人生を送ることができます。
```

詳細はこの歌詞参照

https://www.uta-net.com/song/90059/

https://www.youtube.com/watch?v=eSZ3DXhAd_g
サッカーの試合データを収集したい〜データ分析〜

# はじめに
昨日2/17(金)サッカーのJリーグが開幕しました！
結果は、横浜Fマリノス 2-1 川崎フロンターレ
横浜Fマリノスの勝利！！

サッカーの試合が見るのが好きな私がエンジニアとしてサッカーの試合をデータで分析するならと考え
データ収集のために良いインプットとなるサイト・情報源はあるかなと探していたところ
規約違反に反しなかった場合であれば、スポナビサイトをスクレイピングして、試合データを収集してみたかったですが、断念。

https://soccer.yahoo.co.jp/jleague/category/j1/game/2023021701/info?gk=2

そのため、サッカーの試合データがCSVやAPIで公開されているサイトを調べてみました。

Kaggleのサイトもありますが、以前書いた記事があるので
興味ある方はこちらをご覧ください

https://qiita.com/wooooo/items/ab55104b4ae031291a62

# FootyStats
こちらのサイトはおそらく世界一有名なサッカーの試合データ、統計データを扱っているサイトではないでしょうか？
無料で試合情報を閲覧することが可能で、古い試合であれば無料でCSVデータのダウンロードが可能です。
有料会員になると、公開されているAPIの使用が可能となり、最新の試合データが収集できます。
普通にサイト上の試合データを見るだけで面白いので、サッカーマニアの人が好きなサイトだと思います。

https://footystats.org/jp/japan/j1-league

※追記
無料会員制度があり、無料でAPIの使用が可能ですが
情報は限られていました。多くのデータが欲しい場合は有料会員が良いと思います。
また、無料会員の場合はAPIのコール間隔が長めに設定されています。


## 番外編
CSVやAPIが公開されていませんがサッカーのデータが閲覧できるサイトです

# J. League Data Site
こちらのサイトは、J1・J2・J3の1993年シーズンから現在まで試合データを閲覧できるサイトです

https://data.j-league.or.jp/SFTD01/

# J.league.jp
Jリーグ公式サイトのJ.league.jpです
試合日程やニュース、試合結果、スタッツなどが閲覧できます

https://www.jleague.jp/

# FootBall LAB
FootBallLABはDataStaduimが運営しているサッカー×データをコンセプトにしたサイトです。
試合データや、データに基づいたさまざまなコラムの閲覧が可能です
・[ワールドカップ直近５大会で数値はどう変わったか](https://www.football-lab.jp/column/entry/842/)
・[トラッキングから生まれる新データ 3.方向転換と加速・減速](https://www.football-lab.jp/column/entry/836/)
・[時間帯と点差でデータはどう変化するか](https://www.football-lab.jp/column/entry/835/)

https://www.football-lab.jp/


Twitterを見ていたところ
Jクラブ経営情報のデータをダウンロードできるサイトを作成された方がいらっしゃいました

[@cieloazul310 さん](https://twitter.com/cieloazul310)

https://twitter.com/cieloazul310/status/1297091197580673024?s=20
Objective-C超入門

Objective-C基本学習のメモ用記事です。

# ログ出力
`NSLog(@"hoge");`でログの出力ができる
エスケープ`\`を使うことで`"`の表示や改行を行える。
```
//例
`NSLog(@"こんにちは\n\"ov\"");`
//出力結果
2023-02-18 14:35:40.448922+0900 ov-c_firt[80283:14092901] こんにちは
"ov"
```


# 変数

`型名 変数名;`のように型と変数名を宣言する事で変数が使える。

複数の変数の宣言方法は次のようにできる`int a,b,c;`

変数の方には「整数型：`int`など」「浮動小数店型:`float`など」「文字形：`char`」「ブール型：`BOOL`」などがる

変数を宣言した後、値を代入することができる。
```
int a; //変数の宣言
a = 5; //値の代入
NSLog(@"変数aの値は%dです\n", a); //格納されている値の表示
//出力結果
2023-04-02 15:24:38.330455+0900 ov-c_firt[90730:27441053] 変数aの値は5です
//複数の変数をログに出力する場合
NSLog(@"変数aの値は%dです。変数bは%dです。\n", a, b); //順に入る
```
変数の宣言と代入を同時に行うことを初期化という
`int a = 5;`

# 演算
インクリメン演算で間違えそうなこと
```
int a1;
int a2;
int b1=1;
int b2=1;

a1= ++b1;
a2 = b2++;

a1の値は2; a2の値は1; b1の値は2; b2の値は2;
//違い
a1=++b1; => b1+=1;
            a1=b1;
a2=b2++; => a2=b2;
            b2+=1;
```

# 条件分岐
論理式　YESの場合は1、NOの場合は0の数値を返す仕組み

```
        int a = 1;
        if(a > 0)
            NSLog(@"if文による条件分岐に入りました\n");
        NSLog(@"if文の練習用プログラムです");

//a=1の時の実行結果
if文による条件分岐に入りました
if文の練習用プログラムです
//a=-1の時の実行結果
if文の練習用プログラムです
```
if分による条件分岐は「次の文を実行するかどうか」の分岐なので「if文の練習用プログラムです」は実行される
複数の命令を実行させるには`{}`を使う
```
        if(a > 0) {
            NSLog(@"if文による条件分岐に入りました\n");
            NSLog(@"複数の命令実行\n");
        }
        NSLog(@"if文の練習用プログラムです");
```
else,else if
```
if(条件A){
    処理A
} else if(条件B) {
    処理B
} else {
    処理C
 }
```
Linuxディストリビューションの確認方法

# はじめに
よくDockerを扱うのですが、イメージにソフトウェアを足したい場面が増えてきました。

とした時にふと疑問点が。。。
今使ってるイメージって何系のLinuxだっけ？

ということでLinuxのディストリビューションを確認する方法を改めて調べました。
[クラスメソッドさんの記事](https://dev.classmethod.jp/articles/linux-os-version/)を大変参考とさせていただきました。

# 環境(docker)
検証イメージ：mysql

# 結論
## 「/etc」の「xxx-release」ファイルを確認
「/etc」に「xxx-release」形式のファイルが格納されています。
私の場合、mysqlイメージを使用していたので「system-release」ファイルをcatコマンドで確認してみます。

```shell
sh-4.4# cat /etc/system-release
Oracle Linux Server release 8.7
```

ディストリビューションを確認出来ました！

# Dockerの場合の補足
## 使用イメージのDockerfileから確認
Dockerの場合、そもそもDockerfileを確認すれば把握出来そうですね。
DockerHubのページからDockerfileの[リンク](https://github.com/docker-library/mysql/blob/358c2e5ab6cd24b86a20a871820ecbc67a244368/8.0/Dockerfile.oracle
)を飛んでも同様の内容を確認出来ました。

# 参考文献
https://dev.classmethod.jp/articles/linux-os-version/

https://github.com/docker-library/mysql/blob/358c2e5ab6cd24b86a20a871820ecbc67a244368/8.0/Dockerfile.oracle
GitとGitHubを基本からまとめてみた【GitHubでチーム開発する方法】

## チーム開発の流れ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939638/81b52ed7-499b-af80-5c90-3696d9a01ade.png)

## ブランチ：分岐して開発

①ブランチを作成する

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

②ブランチ一覧を表示する

```
$ git branch

//Githubのリモートブランチの一覧を表示したい場合
$ git branch　-a
```

③ブランチを切り替える

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

//ブランチを新規作成して切り替える
$ git switch -c  <ブランチ名>
```

④ブランチの変更をマージする

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

//ブランチを新規作成して切り替える
$ git merge origin/main
        <リモート名><ブランチ名>
```

## Githubトークンの取得方法

アクセストークンとは、コマンド ラインまたは API を使用して GitHub への認証を行うときに、パスワードの代わりに personal access token を使用することができる。

① ページの右上でプロフィールをクリックし、[Setting] をクリックする

② 左側のサイドバーで、[Setting] をクリックする

③ 左側のサイドバーの「Developer Setting」、「Personal accces token」、「Token（classic）」をクリックする

④ 「新しいトークンの生成」をクリックし、[有効期限] で、トークンの有効期限を選択する

⑤ sourceTreeなど、github clone を使用する際、下記の形で使用する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939638/a2e091b7-f9d4-6f78-7fdb-1d70b9bdab4a.png)


```
https://[新しいトークン]@github.com/sample/sample.git

```


## 参考サイト
[【Git入門講座 合併版】この動画1本でGitとGitHubの基礎をゼロからマスター！【初心者向け】](https://www.youtube.com/watch?v=WHwuNP4kalU&t=1970s)
[gitコマンドの使い方　～ git merge ～ ](https://snowsystem.net/git/git-command/git-merge/)
[Github Docs](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
とある開発環境をChatOps × CFn(EC2) から Github Actions × AWS Copilot CLI化した話

# 取り組んだ背景
- ✅ Elasticsearch 👉 Opensearch移設後の開発環境への影響を受け、開発環境も変更が必要
- ✅ 特定のサーバの技術負債化 👉 コンテナ化して気軽にアプデできる状態で扱いたい
- ✅ 別環境におけるAWS Copilot化の成功実績
- ✅ Github ActionsやCircleCIがスタンダードなので、もうJenkinsから離れたい😭😭😭

# Before × After
## 👷 環境作成
### Before
![before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/f5870c84-cd36-d94e-8516-877c8c6a094e.png)
![before-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/031f73d8-13a9-343d-2441-cb4cef011d3b.png)


### After
![after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/a887a866-99cc-902a-74be-fafef0581e36.png)
![after-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/54e470c4-725a-415a-b282-ce267533b250.png)
![after-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/e5b2c96a-eb1b-619e-fdaa-211077d4ac32.png)

## 🚀 デプロイ
### Before
![before-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/c7565574-a530-b621-ed3e-f14d44c3a68f.png)

## After(デプロイ)
![after-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/ce102592-3f33-3f65-cd4f-1b06ad69ade6.png)

# ❓どうやったのか
- タイトル通りで、大きくはAWS Copilot CLIを利用し、Github Actions上で実行
- これまで闇に葬ってきたDocker開発環境も利用し、WebやOpensearch,MySQLのイメージを作成し、Copilotデプロイ可能にした

# 💦ハマったところ
### 💦 **WEBとBackendの複数サービス起動と互いに通信させるのが難しかった**
- バックエンドはService Discoveryを利用して互いを接続👍
- 今だとService Connectもいけるっぽい👀

### 💦 **開発環境だが、利用用途にUnitテストやE2Eテストがあり、データ管理に悩んだ**
- Mysql,Opensearchそれぞれに移行前環境と同等のデータ入りの状態でコンテナ起動が必要
- Volume共有してない、データを入れた状態のコンテナをECRへコミット、プッシュすることで解決👍(イメージサイズがでかいのが難点💦)

### 💦 **WEBはECSタスクの環境変数利用がされるがバッチがされない😭**
- copilot svc execにてバッチ処理実行時に環境変数を指定して実行することで解決👍

# 💬残った課題
### 💬 AWS Marketplaceのインスタンスを利用してるEC2サーバのコンテナ化ができない・・・・

### 💬 AWS Copilot CLIのアップデートに伴って微妙に挙動が変わるのでメンテがちょっとつらい
Dart言語の基礎 #01 - データ型、変数・関数

Flutterでアプリを開発するにあたって開発言語であるDartについて理解する必要があると考えたので、Dartの基礎を学習しはじめました。

https://www.udemy.com/course/flutter-dart/

# Dartについて

FlutterはAndroid・iOS、デスクトップアプリを開発することが可能なフレームワークです。Flutterの開発には、Googleが開発したDartという言語を使います。Dartを極めて大雑把に要約すると、JavaScriptの拡張性・メンテナンス性を改善し大規模システムに適した仕様とした言語です。

メリットとしてはJavaScriptに似ているので学習ハードルが低いこと・Flutterに使用されているので将来性が高いことですが、デメリットは日本語情報がまだまだ少ないことです。

## データ型・変数・関数
### データ型の基礎

変数に使えるデータ型の基礎として、`int, String, bool`の3つがあります。これはそれぞれ整数・文字列・真偽値を扱うのに用いるデータ型です。
変数の定義は、`データ型 変数名 = 値;`　の構文で行います。

```dart
void main(){
  int intVal = 123;
  String strVal = "Elen";
  bool boolVal = true;
  
  print(intVal);
  print(strVal);
  print(boolVal);
}
```

```dart
123
Elen
true
```
### リスト型
リスト型を使うと、Pythonのコレクションの様に複数の値を格納できます。Pythonとは違い、リストに含まれるデータ型を明示する必要があります。

```dart
void main(){
  List<int> numberList = [0,1,3,4];
  List<String> nameList = ["Elen","Mikasa","Armin"];
  
  print(numberList);
  print(nameList);
  print(numberList[0]);
  print(nameList[1]);

}
```

```dart
[0, 1, 3, 4]
[Elen, Mikasa, Armin]
0
Mikasa
```
リスト型には、あとから値を加えることもできます。
また、イテレーターを使った処理を行うのにlengthメソッドをよく使います。

```dart
void main(){
  List<String> nameList = ["Elen","Mikasa","Armin"];
  nameList.add("Jean");
  print(nameList);
  print(nameList.length);
}
```

```dart
[Elen, Mikasa, Armin, Jean]
4
```
### マップ型
キーに対応する値を格納するには、マップ型を使います。
マップ型は、Pythonの辞書型の様に値と値を1対1対応にしたい時に使います。

```dart
void main(){
  Map<int, String> nameMap = {1:"Elen", 2:"Mikasa"};
  
  print(nameMap);
  print(nameMap[1]);
  
  nameMap[3] = "Armin";
  print(nameMap[3]);
  
}
```

```dart
{1: Elen, 2: Mikasa}
Elen
Armin
```

### 型推論
変数を定義する際にvarで定義すると、型推論を行えます。
型推論とは、データの型を自動で割り振る機能です。

```dart
void main(){
  var name = "Elen";
  var number = 123
  
  print(name);
  print(number);
}
```

```dart
Elen
123
```

### 関数
関数とは、メソッド・関数処理をまとめたものです。
```dart
void main(){
  void printNumber(int x, int y){
    int number = 0;
    print(number + x + y);
  }
  
  printNumber(123, 567);
}
```

```dart
690
```
### フューチャー関数
フューチャー関数は、非同期処理を行いたい時に使います。
非同期処理を行えば、時間のかかる処理による遅延を起こさずに指定時間後に確実に処理を実行できます。

```dart
void main(){
  Future<void> test() async{

    print("処理開始");
    //3行後に確実に終了させる
    Future.delayed(Duration(seconds:3)); 
    print("処理完了");
  }

  test();
}
```

```dart
処理開始
処理完了
```

### ウィジェット
ウィジェットは、主にFlutterのUIを構成するコンポーネントです。
大雑把に表すと、UIを制作したい時に使うデータ型という理解をしています。DartPadでは、Flutterのパッケージをインポートすることもできます。

```dart
import "package:flutter/material.dart";

void main(){
  Widget txt = Text("Elen");
  Widget container = Container(width:10, height:5);
  Widget icon = Icon(Icons.keyboard);
  Widget column = Column();
}
```

### Nullセーフティー
Dartでは、int・String等にnull値を格納するとエラーとなってしまいます。`int?`と記述すると、null値を格納できるnullセーフティーに対応した型にできます。また変数がnullである場合、どの値として処理するかというnullチェックもできます
```dart
void main(){
  int? num01 = null;
  String? num02 = null;
  
  void sum(int? x){
    //xがnullである場合は、0として処理する
    print((x ?? 0) + 1);
  }
  
  sum(num01);
}
```
```dart
1
```

今回は基礎の基礎であるデータ型・変数と関数について学びました。次回以降はfor文・if文、またオブジェクト指向な書き方などを学んでいきます。全3回ほどになる予定です。
【SwiftUI】Xcodeの背景を黒にする方法

Xcode Version 14.2(14C18)
## はじめに
Xcodeの画面が真っ白で目が疲れる…カッコ良い黒画面に変更します。


## 
1. メニューバーの「Xcode」から「Settings...」をクリック。
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143487/7a9a3e88-8ab5-fe4f-3ddc-e369ac83d62a.png)
2.「General」の「Appearance」から「Dark」を選ぶ。
![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143487/0b60b0b5-0c9d-1980-ebf3-1dfd896263af.png)

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143487/fb83876f-4dbb-6354-afcd-909d9911ad5d.png)
3.これで全体がDark配色になりました。
![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143487/7d72d113-6872-e4af-cfac-fd98cabe5a25.png)

![006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143487/8bf746c9-ed98-0047-0c81-b322ff510b53.png)
4.次にメニューバーの「Editor」から「Theme」を選び「Default(Dark)」を選ぶ。
![007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143487/beba7663-a5ca-a433-12e5-f17c96f54ee4.png)
これでエディタエリアも黒くなりました。
![008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143487/03ff1c4d-1b9c-88ed-6b33-e327044bdf8e.png)
##
end.
【Mysql】Generated Columnを使ったactiveなデータに対してユニーク制約を設定する方法

アクティブなデータにのみユニーク制約をかけたい時の実装方法として、Generated Columnを使った複合ユニーク制約の掛け方について記載します。

前提として、Mysql ver5.7以降である必要があるのでご注意を。

### 手順

・Generated column(仮想生成カラム)を定義
・ユニークにしたいカラムと組み合わせた複合ユニーク制約をかける

### 例
以下はアクティブなユーザーのメールアドレスのみユニークにしたい、というケースの実装例です。

```.php
<?php declare(strict_types=1);

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('is_active')->nullable()->virtualAs('IF(ISNULL(deleted_at), 1, NULL)');

            $table->unique(['email', 'is_active']);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropUnique(['email', 'is_active']);
            $table->dropColumn('is_active');
        });
    }
};
```

生のALTER文なら以下のようになります。

```.sql
ALTER TABLE `users` ADD `is_active` varchar(255) as (IF(ISNULL(deleted_at), 1, NULL)); 
ALTER TABLE `users` ADD UNIQUE `users_email_is_active_unique`(`email`, `is_active`);
```

unique制約がかかっている状態においてもnullの値のカラムの複数存在は許容されるので、
・`is_active = 1`かつ同じ`email`のデータ常に1つであるべき
・`is_active = null`の場合は同じ`email`を許容する

という制約になります。
データ例↓

```
+----+------------------------+---------------------+-----------+
| id | email                  | deleted_at          | is_active |
+----+------------------------+---------------------+-----------+
|  1 | hoge@example.com       | 2023-02-18 05:03:55 | NULL      |
|  2 | hoge@example.com       | 2023-02-18 05:04:12 | NULL      |
|  3 | hoge@example.com       | NULL                | 1         |
+----+------------------------+---------------------+-----------+
```

### 補足
Generated columnの値が2とか3とか、1以外、になったら意図に反したデータができちゃうんじゃないか？
と思ったのですが、その心配はありませんでした。

INSERT文、UPDATE文でGenerated columnの値を設定しようとすると、ちゃんとエラーを吐いてくれます。
```
Error Code: 3105. The value specified for generated column 'is_active' in table 'users' is not allowed.
```

> カラム定義に含まれる式から値が計算されるカラム。 カラム値は格納されませんが、BEFORE トリガーの直後に行が読み取られたときに評価されます。 仮想生成カラムは記憶域を取りません。 InnoDB では、仮想生成カラムのセカンダリインデックスがサポートされます。
MySQL 用語集:仮想生成カラム

↑の通り、**Generated Columnはそもそも実際にデータを格納するカラムではない**ため、クエリで値を入れることができないようです。
LaravelのEloquent ORMで言うところのアクセサみたいですね。

### 参考

https://dev.mysql.com/doc/refman/8.0/ja/glossary.html#glos_virtual_generated_column

https://takuma-it.com/logical-deletion-and-unique-constraint-compatibility/

https://qiita.com/taruhachi/items/bb78d92efa67b6936201

https://r17n.page/2021/03/21/mysql-soft-deletion-with-unique-constraint/
【備忘録】なぜかよく忘れるPython文法①

# なぜかよく忘れるPython文法①

【目的】よく忘れるPythonの文法について復習する

#### 文字列フォーマット
文字列フォーマットとは埋め込み機能であり、変数などの値を文字列などに埋め込む
```Python:文字列フォーマット
    print("{0}さんの身長は{1:.1f}cm、体重は{2:.1f}kgです。".format("太郎", 170, 70.5))
```
```:出力
    太郎さんの身長は170.0cm、体重は70.5kgです。
```
基本的に、「インデックス、小数点何桁まで表示するか、型」の順で入力する。
【例】{ 2:.1f }は、インデックスが2（70.5）で小数点を一桁まで、float型で出力する。

#### zip関数
それぞれ異なるリストを同時に取り出して処理する
```Python:zip関数
    for one,two in zip([1, 2, 3], [11, 12, 13]):
        print(one, "と" ,two)
```
```:出力
    1 と 11
    2 と 12
    3 と 13
```
それぞれのリストからインデックスが同じものを抽出してfor文によってすべて表示させる。
【例】それぞれのリストからインデックスが0である1と11を抜き出して出力する


#### 無名関数
名前のない関数でコードを簡素化するために使用される。
```Python:無名関数
    (lambda a, b: a * b)(3, 10)
```
```:出力
    30
```
「lambda (引数) : (処理)」という記述の仕方をする。

#### map関数
高階関数で、イテレータを返す関数である。
```Python:map関数
    list(map(lambda x: x * 2, [1, 2, 3, 4]))
```
```:出力
    [2, 4, 6, 8]
```
関数mapは第１引数に関数、第２引数にイテラブルをとる。
【例】リスト内の各要素に対して無名関数で処理したものをリスト化する

#### filter関数
map関数と同様にイテラブルをもらってイテレータを返す関数。違いは第１引数に真理値をとる関数を指定するということのみ。
```Python:filter関数
    def pos(x):
        if x > 0:
            return True
        else:
            return False

    list(filter(pos, [1, -9, 2, 4, -5])
```
```:出力
    [1, 2, 4]
```
filter関数は、第１引数の真理値がTrueになったもののみを抽出する。
【例】pos関数で定義したように、リスト内の要素が正のものだけを抽出する

#### reduce関数
シーケンス内の要素を関数によって順番に統合をし、最終的に１つの値を返す。
```Python:無名関数
    from functools import reduce

    total = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])
    print(total)

```
```:出力
    15
```
map関数は第１引数に関数、第２引数にイテラブルをとる。
【例】リスト内の各要素を和として統合する
【Salesforce】フローでSet型変数を利用する方法

# はじめに
Set型変数は重複を排除できる配列の変数型です。
フローでは通常のList型の変数は標準で使用することができますが、Set型変数は標準では定義されていません。
ここではフローでSet型の変数を使用する方法を紹介します。

# 実現方法
標準では存在しないデータ型を利用するためにカスタムでデータ型を定義します。
フローの変数定義ではApex型という選択肢があり、Apexで定義したカスタムのデータ型を利用することができます。
Set型を利用するために、Apexでカスタムのデータ型を作ります。

# 実装例
以下のようなApexクラスを定義します。
フローとのインターフェース用に```collection```という変数を定義し、get・setプロパティで値の受け渡しをします。フローからこのApexを参照するために```@AuraEnabled```アノテーションを付与します。
setプロパティから```collection```変数に値がセットされる時に、内部的にSet型の変数に変換します。
getプロパティでは内部的に保持しているSet型の変数をList型の変数に変換して値を返します。
```Java:SetForFlow.apxc
public class SetForFlow {
	
    // 内部保持用のSet型変数
    private Set<String> innerSet;
    
    @AuraEnabled
    public List<String> collection {
        						       get {
                                           return new List<String>(this.innerSet);
                                       } 
        							   set {
                                           this.innerSet = new Set<String>(value);
                                       }
    								}
    
}
```

# 動作検証
画面フローを使って検証をします。
新規リソースから以下のように変数を作成します。
データ型はApex型、Apexクラスは先程作成した```SetForFlow```を指定します。
```SetForFlow```型自体が配列をもつデータ型なので、「複数の値を許可」をオンにする必要はありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878697/083f7f11-167a-03cc-9c9a-f997a7dc025e.png)

割り当ての要素を追加し以下のように設定します。
新規リソースで定義した```FlowValues```変数に値をセットします。
値の受け渡しは```FlowValues```で定義された```collection```変数を介して行います。
値「B」と値「C」はそれぞれ2回セットされており、リスト内で重複する値となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878697/503abf50-33d5-4732-bf7b-f072264d29d8.png)

値の確認用に画面要素を配置し、表示テキストコンポーネントで```FlowValues```変数の値を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878697/600f8319-58d3-31f9-f668-37a93ee5f162.png)

フロ－全体では以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878697/219a3fce-5db6-5b7f-7ae4-b45ed4589aa4.png)

# 動作結果
フローを実行すると以下のような結果となります。
複数回セットされた値「B」、値「C」とも重複排除されて配列に格納されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878697/fee64ed9-f43d-d33b-33be-66a441bce1d3.png)

# まとめ
今回はフロー標準では存在しないデータ型を使用する方法としてApex型の変数を紹介しました。
複雑な階層構造をもつデータや、フローでは実現が大変な処理を内部的に保持するデータ型を使いたい場合はApex型変数が有効な実現の選択肢となります。フロー自体が複雑になる場合は、複雑な部分をApexに切り出すことでフロー単体での可読性や保守性が向上するメリットもあるので活用してみてください。
【GitHub Actions】ログ出力をグループ化して見やすくする

# はじめに

僕は今まで「GitHub Actionsのログ出力が見づらい問題」に悩まされていました。
唐突ですが、以下のworkflowを実行してみましょう。

```yml:main.yml
name: main
on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.x'
          architecture: 'x64'
      - name: Run Python
        run: |
          python -m pip install --upgrade pip
          pip install opencv-python
          pip install Pillow
          pip install python-dotenv
          pip install selenium
          python main.py
```

パッケージはログ出力の見づらさが伝われば良いので、テキトーに選びました。
main.pyは以下のようになっています。

```python:main.py
print('Hello World')
```

実行すると以下のようになりました。

![グループ化無](https://raw.githubusercontent.com/SoniPana/Qiita_SoniPana/main/image/23/02/18/group_n.gif)

...見づらいです。ぱっと見「Hello World」がどこにあるのか分かりません。
どうにかしてログ出力を見やすくする方法はないかと調べていたところ、公式のドキュメントで以下のようなものを見つけました。

https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines

```group```を使えばログ出力をグループ化することができるようです。

何故かこれに関する記事がQiitaで1つも見つからなかったので、備忘録として残しておきます。

# 1.ymlファイルの修正

main.ymlを以下のように修正します。(2行加えるだけですが...)

```yml:main.yml
      # 省略
      - name: Run Python
        run: |
          echo "::group::pip install --upgrade pip"
          python -m pip install --upgrade pip
          pip install opencv-python
          pip install Pillow
          pip install python-dotenv
          pip install selenium
          echo "::endgroup::"
          python main.py
```

```echo "::group::<グループ名>"```でログ出力をグループ化できます。(グループ名は任意)
```echo "::endgroup::"```でグループ化を終了します。

# 2.実行

実行すると以下のようになりました。

![グループ化有](https://raw.githubusercontent.com/SoniPana/Qiita_SoniPana/main/image/23/02/18/group.png)

すごくスッキリしました。
グループ名の部分を押すと展開できます。

![グループ化有](https://raw.githubusercontent.com/SoniPana/Qiita_SoniPana/main/image/23/02/18/group_y.gif)

# 例

以下のリポジトリに今回のコードが置いてあります。

https://github.com/Geusen-Qiita/log-group
リレーモジュールを使ってみた

amazonで購入したこちらのリレーモジュールをArduino Nanoから制御してみました．


![Screenshot from 2023-02-18 14-00-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/3a84e7fc-0044-9624-099e-0ec826853854.png)

https://www.amazon.co.jp/gp/product/B07W5MZ2C7/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1


# 配線

![Screenshot from 2023-02-18 14-01-53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/5f506ee4-6093-818b-3161-c1c05bfbd7eb.png)


[DCプラスに接続] --- Arduino 5V
[DCマイナスに接続] --- Arduino GND
[信号トリガーターミナル] --- Arduino D2


# プログラム

```cpp:relay_on_off.cpp
#include <Arduino.h>
#define RELAY_PIN 2
void setup() {
    pinMode(RELAY_PIN, OUTPUT);
    Serial.begin(9600);
}
void loop() {
    Serial.println("Hello Arduino");
    digitalWrite(RELAY_PIN, HIGH); delay(1000);
    digitalWrite(RELAY_PIN, LOW);  delay(1000);
}
```

# 結果

![IMG_7392_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/6785a126-f8ba-f5e8-6e10-3dcce85d7821.gif)
【FileMaker】える、知っているか？ポータルの件数はスクロールバーの有無で違う

そんなタイトルですが、DETHNOTEは怖くて観れない私です。
すみません、ちょっと使ってみたかっただけです。

# 結論
まず結論から言うと、レイアウトに配置したポータルのスクロールバーの有無設定で、取得される件数が違ってきます。
えー、、、知らんかった。
よくよく考えると、「そうですよね」となりますが。

# 現象

## スクリプト
こんなスクリプトを回しました。
![スクリーンショット 2023-02-17 16.59.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/e697f1e1-7f47-e7c3-3ab0-86a8400c403e.png)
ポータル内に移動して、ポータルの行をカウントしています。
ポータルの移動で、最後まできたらLoopを出てカウントを終了します。

## ポータル設定
ポータルのスクロールバー指定は、こちらです。
![スクリーンショット 2023-02-18 14.03.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/9a03b7be-b877-6db5-ca4c-aa5518d71603.png)
「垂直スクロールを許可」にチェックが入っているか、いないか、です。

## ケース1 : ポータルにスクロールバーがある
「垂直スクロールを許可」にチェックが入って「**いる**」設定です。
![スクリーンショット 2023-02-17 16.54.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/63ae3e85-f245-0d86-3bb6-cf0526cb3077.png)
ポータルはスクロールした先まで進めますので、実際の明細件数とLoopで計算した明細件数は一致します。

## ケース2 : ポータルにスクロールバーがなかった
「垂直スクロールを許可」にチェックが入って「**いない**」設定です。
![スクリーンショット 2023-02-17 16.54.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/23e68a88-f369-91ee-b520-72909b2fb298.png)
実際の明細件数は11件ですが、ポータルのスクロールバーで見えないレコードへの移動ができなかったので、ポータル指定の９件分のカウントしかされませんでした。


## ケース3 : ポータルにスクロールバーがなかった　＆　見えている最終レコードからスタート
では、「垂直スクロールを許可」にチェックが入って「**いない**」設定で、ポータルに表示してある最終レコード、今回の例では９レコード目を起点にした場合はどうでしょう。
スクリプトで、起点を指定しました。
![スクリーンショット 2023-02-18 13.55.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/ece6f7a4-9e0f-778a-a2a4-239b35d93e71.png)

結果は、ご想像通りで、、、
![スクリーンショット 2023-02-18 13.54.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/c8ca1da8-fc5b-7594-b6e2-b179e8691fdd.png)
起点の9件目しかカウントされず、Loopで計算した明細件数は1件になります。

# まとめ
ポータルのスクロールバー、結構重要な役割を果たしていましたね。
また、レイアウトがデータそのものに紐づいているのではなく、レイアウトのツール設定に左右されるのも、レイアウトがキーとなるFileMakerならではの仕様だなと思いました。

# うっかりする場面
通常使うレイアウトではデータの移動ができないと困るのでスクロールバーがなかったら気づくと思うのですが、スクリプトの中からポータルのデータを拾うために作業レイアウトなどにポータルを設置した際など、スクロールバーを設置していなくて今回のようなケースが起こるかもしれません。
まさに、現場でも同じようなことが起こり、教訓として記事にしました。
📖「良いコード／悪いコードで学ぶ設計入門」（第１章 悪しき構造の弊害を知覚する）を読んだ感想

## はじめに
- 以下の書籍を読んだ感想などをまとめていきます。第１章〜第１７章まであり、１章ごとに記事にしていきたいと思います。

https://gihyo.jp/book/2022/978-4-297-12783-1

## 読むきっかけ
- ITエンジニアのみなさんとおすすめの本を選ぶイベント「ITエンジニア本大賞2023」の「技術書部門大賞」に選ばれたことで読んでみようと思いました。

https://www.shoeisha.co.jp/campaign/award/result


## 感想　（第１章 悪しき構造の弊害を知覚する）

#### とにかく読みやすい、分かりやすい本でした！！

「悪いコード」を悪魔と例え、それを知覚することで退治できるような対応（設計技術）を学んでいくスタイル。「悪いコード」を知覚する為には、「良いコード」を理解した上でギャップ（違和感）を感じることが出来れば知覚に繋がる。


![良いコード悪いコード2.001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3144766/4d34d486-cf1a-ac21-44e6-e8b6cd59b36b.png)

![良いコード悪いコード2.002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3144766/3eb0c2a1-de94-5df7-f7c4-195f3dc9b49c.png)



**[ 学んだこと ]**
- 実際に書かれた「悪いコード」を元に、何が悪しき構造になり弊害を生んでいくのかが書かれているので、とても分かりやすく学びになりました。悪しき命名（技術駆動命名、連番命名）は何の変数なのか何のメソッドなのか**直感的に分かりづらくなる**ことでコードを理解するのに時間がかかる弊害が生まれちゃう。
他にも条件分岐のネスト（入れ子構造）をし過ぎると**ブロック内の見通しが悪くなる**し、変数のスコープが複雑になり追いづらくなる。低凝集な構造（処理など共通化されいない、データ構成もバラバラの状態）は修正漏れにも繋がったり重複コードを生み出したりメンテしづらくなる。


シンプルに「なるほどな！」と腹落ち。第１章で書かれているような悪いコードは書いたことないが、悪いコードを読むことによって自分の中で知見が深くなり**知覚**ができるようになると感じました。


## 次回
https://qiita.com/tomonac/items/1b290c380f80e7fdc60d
dobot magician ioの仕様

![Screenshot from 2023-02-18 13-54-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/f921b40f-a834-761c-0b4d-a1b6bfb6f965.png)
![Screenshot from 2023-02-18 13-53-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/0f2d5534-bd86-0f11-6676-82bfa3590448.png)

EIO10 : 5V / 1A
BigQueryで扱うクエリ色々

案件先でBigQueryを扱う中で、いくつか学べたデータ型などがあるのでご紹介していきます。

## INTEGERとNUMERICの違い
データの数値型の違いがイマイチよくわからなかったのですが、
数値型には以下の種類があるようです。
>INT64（エイリアス: INT、SMALLINT、INTEGER、BIGINT、TINYINT、BYTEINT）
NUMERIC（エイリアス: DECIMAL）
BIGNUMERIC（エイリアス: BIGDECIMAL）
FLOAT64

なんの違いがあるのかというのが以下になります。

### INTEGER = 整数型
整数型というのは小数部分を持たない数値の型を指します。

```sql
123
0xABC
-123
```

### NUMERIC = 小数型
小数型の値は、固定の小数点以下の精度とスケールを持つ数値です。精度は、数値に含まれる桁数です。スケールは小数点以下の桁数です。

```sql
SELECT NUMERIC '0';
SELECT NUMERIC '123456';
SELECT NUMERIC '-3.14';
SELECT NUMERIC '-0.54321';
SELECT NUMERIC '1.23456e05';
SELECT NUMERIC '-9.876e-3';
```
NUMERICの方が整数型も扱える分、データ型の範囲が大きいので、データの幅が大きいば場合はこちらを使ったほうが良いです。

## SAFE_CASTとCASTの違い
次は変換関数の違いです。正直これは違いが分かっても用途がわからないと難しかったです。

### CAST
CAST構文は、式の結果の型を他の型に変換する必要があることを示す目的でクエリが使用されます。

CAST を使用する場合、Google 標準 SQL でそのキャスティングを実行できなければクエリは失敗します。このようなエラーの発生を防ぐには、SAFE_CAST を使用します。

次のクエリを実行すると、x が 1 の場合は "true" になります。その他の非 NULL 値の場合は "false" に、x が NULL の場合は NULL になります。
```sql
CAST(x=1 AS STRING)
```

### SAFE_CAST
CAST を使用する場合、Google 標準 SQL でそのキャスティングを実行できなければクエリは失敗します。たとえば、次のクエリによってエラーが発生します。

```sql
SELECT CAST("apple" AS INT64) AS not_a_number;
```
このようなエラーからクエリを守るには、SAFE_CAST を使用できます。SAFE_CAST はエラーの代わりに NULL を返すという点を除き、CAST とまったく同じです。

```sql
SELECT SAFE_CAST("apple" AS INT64) AS not_a_number;

+--------------+
| not_a_number |
+--------------+
| NULL         |
+--------------+
```

## 文字列関数

### CONCAT
1 つ以上の値を 1 つに連結します。すべての値が BYTES か、STRING にキャスト可能なデータ型である必要があります。
入力引数が NULL の場合、この関数は NULL を返します。
```sql
SELECT CONCAT('T.P.', ' ', 'Bar') as author;

+---------------------+
| author              |
+---------------------+
| T.P. Bar            |
+---------------------+
```
```sql

With Employees AS
  (SELECT
    'John' AS first_name,
    'Doe' AS last_name
  UNION ALL
  SELECT
    'Jane' AS first_name,
    'Smith' AS last_name
  UNION ALL
  SELECT
    'Joe' AS first_name,
    'Jackson' AS last_name)

SELECT
  CONCAT(first_name, ' ', last_name)
  AS full_name
FROM Employees;

+---------------------+
| full_name           |
+---------------------+
| John Doe            |
| Jane Smith          |
| Joe Jackson         |
+---------------------+
```
## 参考サイト

https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types?hl=ja#numeric_types

https://cloud.google.com/bigquery/docs/reference/standard-sql/conversion_functions?hl=ja#safe_casting

https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions?hl=ja#concat

## まとめ
まだSQLの少しの知識を扱っただけなのですが、日々アウトプット&インプット頑張ります！
日付、曜日のsql - その月の第1月曜


## 日付、曜日で使うものメモ　（snowflake）
```sql
-- 日本時間の今日
SET TODAY = TO_DATE(convert_timezone('Asia/Tokyo', current_timestamp()));

SELECT
-- 曜日 str
to_varchar($TODAY, 'DY'),

-- 出力曜日は WEEK_START セッションパラメーターによって制御　　これは0又は1の場合
-- その週の月曜日
DATE_TRUNC('week', $TODAY),
-- その週の日曜日
LAST_DAY($TODAY, 'week'),

-- 第一月曜
DATEADD(day,-TRUNC((DATE_PART(day,DATE_TRUNC('week', $TODAY))-1)/7)*7, DATE_TRUNC('week', $TODAY)),

-- その月の最後の日
LAST_DAY($TODAY),
LAST_DAY($TODAY, 'month'),
-- その年の最後の日
LAST_DAY($TODAY, 'year')
;
```
## snowflakeの"WEEK_START"について
https://docs.snowflake.com/ja/sql-reference/parameters#label-week-start
https://docs.snowflake.com/ja/sql-reference/functions-date-time#label-calendar-weeks-weekdays
```sql
SELECT DAYOFWEEK(convert_timezone('Asia/Tokyo', current_timestamp()));
```
これで今日の曜日が何でかえってくるかでわかる。
Railsで「現在から三日前まで」などの期間指定の方法

Railsで期間指定の方法を検索すると、１日前（.yesterday）とか一日の開始時（.beginning_of_day）とか今日一日（.all_day）とか今週いっぱい（.all_week）…などはやまほどひっかかるが、「現在から三日前までの範囲」などの指定はぜんぜん出てこない。検索の仕方が悪いのかもしれないが。

一応描いておくと

```ruby
Model.where(created_at: Time.now - 3.days..Time.now)
```

といった感じで、``..``を挟んで前に過去（例では現時点から三日前）の時間指定、後ろに後の時間（例では現在）をおくだけ。簡単だけど、案外全然出てこないので困ってたので備忘録としてかいておきます。今日の00時以降だとか、今週だけとかは他に一杯あるのでそっちを参考にしてください。
PHPで鍵認証でsftp通信する

# はじめに
仕事の関係でsftp通信スクリプトをphpで作ることになったので簡単なサンプルを残す

# 前提
以下の環境で実施
接続元サーバ：10.0.1.4
接続元ユーザ：azureuser
接続先サーバ：10.0.1.5
接続先ユーザ：azureuser
php version:5.6（両方とも）

# 手順
## 鍵ファイルを作成する
下記を参考に、
接続元サーバに「秘密鍵ファイル」
接続先サーバに「公開鍵ファイル」
を配置する

https://qiita.com/watyanabe164/private/c206a118a6aff91d0c21

## sftpできるようにする準備
### 接続元サーバ
特になし、鍵ファイルだけ準備しておくように。

### 接続先サーバ
鍵認証を許可する設定を入れる

```
vi /etc/ssh/sshd_config
```

下記のオプションを有効化する

```
PubkeyAuthentication yes
```

sshd再起動

```
systemctl restart sshd
```

## php5.6とssh2をインストール（接続元サーバ

### php5.6インストール

```
yum -y install epel-release
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
yum -y install php56-php php56-php-cli php56-php-common php56-php-devel php56-php-gd php56-php-mbstring php56-php-mysqlnd php56-php-pdo php56-php-xml
ln -s /opt/remi/php56/root/usr/bin/php /usr/bin/php
php -v
```

### ssh2インストール

```
yum -y install php-pear
yum -y install php-devel
yum -y install php56-php-ssh2
yum -y install libssh2-devel
pecl install ssh2-0.12
```

php.ini編集する

```
sudo vi /etc/php.ini

↓↓末尾にコレ入れる
extension=ssh2.so
```

（多分やらなくていいけど）apache再起動

```
systemctl restart httpd
```

## スクリプトを作成する（接続元サーバ
今回は接続元サーバにおいてあるファイルを、接続先サーバにアップロードするphpスクリプトを作成します
これを、/home/azureuser/配下に保管

```:upload_file.php
<?php
$local_file = '/home/azureuser/hello.txt';
$remote_file = '/home/azureuser/hello.txt';

$connection = ssh2_connect('10.0.1.5', 22);
ssh2_auth_pubkey_file($connection, 'azureuser', '/home/azureuser/.ssh/id_rsa.pub', '/home/azureuser/.ssh/id_rsa');

$sftp = ssh2_sftp($connection);

$local_handle = fopen($local_file, 'r');
$remote_handle = fopen("ssh2.sftp://{$sftp}{$remote_file}", 'w');

$read = 0;
$length = filesize($local_file);

while ($read < $length && ($buffer = fread($local_handle, $length - $read))) {
    $read += strlen($buffer);
    if (fwrite($remote_handle, $buffer) === false) {
        fclose($remote_handle);
        fclose($local_handle);
        die("ファイル書き込み中にエラーが発生しました。");
    }
}

fclose($remote_handle);
fclose($local_handle);

echo "アップロードが完了しました。\n";
?>
```

hello.txtも/home/azureuser/配下に保管

```:hello.txt
Hello, world!
```

## php実行

```
cd /home/azureuser/
php upload_file.php
```

## 接続先サーバにファイルがアップロードされている確認する（接続先サーバ

```
ll /home/azure/hello.txt
```
terraformのoutputでList型とMap型で出力する方法

## やりたいこと
ループしているリソースをOutputで出力するときには、Outputもループさせて出力するのがいいと思う。
以下の場合は、Map型のリソースなので、Mapで出力してあげるほうがたぶんいい。
一応使い分けるられるように２パターン書いてます。

## サンプル

```hcl
locals {
  files = [
    {
      content = "aaa"
      name    = "hello1"
    },
    {
      content = "bbb"
      name    = "hello2"
    },
    {
      content = "ccc"
      name    = "hello3"
    },
  ]
}

resource "local_file" "hello" {
  for_each = { for i in local.files : i.name => i }
  content  = each.value.content
  filename = each.value.name
}

## list型で出力する例
output "list" {
  value = values(local_file.hello).*.content
}


## map型で出力する例
output "map" {
  value = {
    for k, v in local_file.hello : k => v.content
  }
}
```



出力

```
Outputs:

list = [
  "aaa",
  "bbb",
  "ccc",
]
map = {
  "hello1" = "aaa"
  "hello2" = "bbb"
  "hello3" = "ccc"
}
```
JavaScriptでバブルソートの計算時間を測って比べてみた

# 問題提起:
JavaScriptでバブルソートを実装する際に、
sort関数とfor文のどちらを使用するのがいいのかが
気になったのでまとめておく。

# 結論：

一般に、JavaScriptが提供するsort()メソッドは、forループを使ってバブルソートのアルゴリズムを実装するよりも高速に処理することができます。これは、sort() メソッドは高度に最適化された組み込みメソッドであり、JavaScript エンジンの低レベルの実装を利用するためです。

sort()メソッドはTimsortと呼ばれる高度に最適化されたアルゴリズムを使用しており、これはバブルソートのアルゴリズムよりもはるかに高速です。

また、高速化だけでなく、sort()メソッドは、バブルソートのアルゴリズムをforループで実装するよりも簡潔で読みやすいという特徴もあります。
したがって、バブルソートを使う特別な理由（アルゴリズムを教えるためなど）がない限り、一般的にはJavaScriptが提供するsort()メソッドを使うほうがよいでしょう。


# 計算時間を確かめる方法

## 1.Console.time()とconsole.timeEnd()
Console.time()とconsole.timeEnd()メソッドは、コードの特定の部分の実行にかかった時間を測定するために使用することができます。
以下はその例です。

```main.js
console.time('myFunction');
// Call your function here
myFunction();
console.timeEnd('myFunction');
```
myFunction()メソッドの実行にかかった時間をコンソールに出力します。

## 2.performance.now()
performance.now()メソッドは、コードの特定のセクションの実行にかかった時間を測定するために使用できる高解像度のタイムスタンプを返します。以下はその例です。

```main.js
const t0 = performance.now();
// Call your function here
myFunction();
const t1 = performance.now();
console.log(`Time taken: ${t1 - t0} milliseconds.`);
```
myFunction()メソッドの実行にかかった時間をコンソールに出力します。

# 実際に比べてみる

以下の3つの関数を実行するのにかかる時間をconsole.timeとconsole.timeEndEndを使って計測してみます。

## 比べるコード

```main.js
const arr = [20,10,30,60,50,90,70,40] //8

function bubbleSort(array){
  let len = array.length;
  for(let i = 0; i < len; i++){
    for(let x = 0; x < len -i; x++){
      if(array[x] > array[x+1]){
        [array[x], array[x+1]] = [array[x+1], array[x]];
      }
    }
  }
  return array
}

function bubbleSort2(array) {
  let i,j,n;
  for (i = 0; i < array.length -1; i++){ 
    for (j = 0; j < array.length - i - 1; j++){
      if (array[j] > array[j + 1]){
        n = array[j];
        array[j] = array[j + 1];
        array[j + 1] = n;
      }
    }
  }
  return array
}

function timSort(array){
  array.sort((a,b)=>{a-b})
}

console.time('bubbleSort');
bubbleSort(arr)
console.timeEnd('bubbleSort');

console.time('bubbleSort2');
bubbleSort2(arr)
console.timeEnd('bubbleSort2');

console.time('timSort');
timSort(arr)
console.timeEnd('timSort');
```

## 結果
試行回数3回の結果が以下の通りです。

timSortの方がはやいことがわかりました。

![スクリーンショット 2023-02-18 12.25.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631096/f07cb714-cca4-830c-f7fd-bec39dd9f442.png)
![スクリーンショット 2023-02-18 12.25.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631096/b6d8f554-71de-f3c8-a014-c17f49dcd270.png)
![スクリーンショット 2023-02-18 12.25.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631096/3792e151-2648-f538-775e-5f187e47959b.png)
フリーダイヤルのみ抽出する　正規表現

# はじめに

正規表現がわからんので自分用の解説に記述しておきます！

今回実行したいミッションは
* 配列内にある電話番号のフリーダイヤル(0120)のみと一致する事！
* 「0120」に続く部分は、3桁3桁のみを許容する事！
* 「0120-xxx-xxx」または「0120(xxx)xxx」の記述のみ許容する事！
* 取り出したフリーダイヤルを新たな配列に格納する事！

~~~ruby
phone_numbers = ["0120-111-111", "080-1111-1111", "0120(111)111, "0120444444"
~~~

# 正規表現

↓今回実現したいミッションのうち3つを実行していく。

* 配列内にある電話番号のフリーダイヤル(0120)のみと一致する事！
* 「0120」に続く部分は、3桁3桁のみを許容する事！
* 「0120-xxx-xxx」または「0120(xxx)xxx」の記述のみ許容する事！

### 用いた正規表現
| 正規表現 | 意味 |
| :----: | :----: |
|  \A  |  直後の文字が先頭にある文字列にマッチ  |
|  [ ]  | 角括弧で囲まれた文字のいずれか1個マッチ   |
| \d  | 数字にマッチ |
| { n,m } | 直前の文字が少なくともn回、多くてもm回出現するものにマッチ |
| \z | 直前の文字が末尾にある文字列にマッチ |


~~~ruby 雛形.rb
def extract_free_dial(numbers)
end

phone_numbers = ["0120-111-111", "080-1111-1111", "0120(111)111", "0120444444"]
  
puts extract_free_dial(phone_numbers)
~~~

###### フリーダイヤルの正規表現
~~~ruby
(/\A0120[-(]\d{3}[-)]\d{3}\z/)
~~~

| 正規表現 | 意味 |
| :----: | :----: |
|  \A0120  |  直後の文字が0120の文字列とマッチ  |
|  [ -( ]  | 「 - 」または　「 ( 」の文字のいずれか1個とマッチ |
| \d  | 数字にマッチ |
| { 3 } | 直前の数字(\d)が3回の文字列とマッチ |
| [ - ) ] | 「 - 」または　「 - ) 」の文字のいずれか1個とマッチ |
| \z | 直前の文字(\d{3})つまり数字が3個並んだ文字列とマッチ |

~~~ruby 雛形.rb
def extract_free_dial(numbers)
    number.match(/\A0120[-(]\d{3}[-)]\d{3}\z/) != nil
end

phone_numbers = ["0120-111-111", "080-1111-1111", "0120(111)111", "0120444444"]
  
puts extract_free_dial(phone_numbers)
~~~

* 配列内にある電話番号のフリーダイヤル(0120)のみと一致する事！
* 「0120」に続く部分は、3桁3桁のみを許容する事！
* 「0120-xxx-xxx」または「0120(xxx)xxx」の記述のみ許容する事！

↑以上の正規表現で今回したいミッションが3つ実行できた！
# 条件分岐

↓条件分岐で実行したいミッションは

* 取り出したフリーダイヤルを新たな配列に格納する事！

① まずは新たに格納する配列を設定する。
~~~ruby
free_dials = []
~~~

② `phone_number`配列から要素を一つずつ取り出すので`eachメソッド`を使用。
~~~ruby
numbers.each do |number|
end
~~~

③ `if文`を用いて条件分岐していく
~~~ruby
def extract_free_dial(numbers)
    free_dials = []
    i = 0
    numbers.each do |number|
      if number.match(/\A0120[-(]\d{3}[-)]\d{3}\z/) != nil
      free_dials << numbers[i]
      end
      i += 1
    end
    return free_dials
end

  phone_numbers = ["0120-111-111", "080-1111-1111", "0120(111)111", "0120444444"]

  puts extract_free_dial(phone_numbers)
~~~

さっき作成した正規表現を用いて
`!= nil`　→ `nilでは無い` →`条件に一致している`　`if文`を作成する。
~~~ruby
if number.match(/\A0120[-(]\d{3}[-)]\d{3}\z/) != nil
~~~

当てはまる電話番号を`free_dials`の配列に格納する。
~~~ruby
free_dials << numbers[i]
~~~

最後に`return free_dials`でfree_dialsの値を戻り値として返す。

# 最後に

今回実行したいミッション
* 配列内にある電話番号のフリーダイヤル(0120)のみと一致する事！
* 「0120」に続く部分は、3桁3桁のみを許容する事！
* 「0120-xxx-xxx」または「0120(xxx)xxx」の記述のみ許容する事！
* 取り出したフリーダイヤルを新たな配列に格納する事！ 

以上で全ての実装できました！

かなり限定的な使用方法ですが備忘録に残すことで頭の中が整理できました！
まだまだ知識不足な部分が多いですが、日々精進して参ります/._./
[VBS]今日のトリビア いつの間にかASCW、ChrWが使えるようになっている

# バージョン情報には掲載がない
[バージョン情報 2009](https://learn.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392490(v=msdn.10))

# 関数のリストにもない
[VBScriptの関数](https://learn.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392480(v=msdn.10))
ここで記載されているのはChrとASCのみである。
もともとVBScriptのファイル(.vbs)はANSI(Shift-Jis)形式だけで`UTF-8`はエラーになる。
[【VBScript】Windows10でmsgboxが文字化けする原因と対策 ](https://www.depthbomb.net/?p=2356)
なのでメモ帳のデフォルトがUTF-8になったためトラブルになる。

# 内部処理はUTF-16
[msgbox での文字化け @ 掲示板](https://www.petitmonte.com/bbs/answers?question_id=16581)
>  まず、VBScriptの文字列は、内部で UCS-2/UTF-16として保持されています。
そのため、UTF-8なバイトデータを渡しても、利用できません。

# このためサロゲートペアとなる

[Working with character values beyond ChrW(65535) in VbScript](https://stackoverflow.com/questions/43244780/working-with-character-values-beyond-chrw65535-in-vbscript)
ChrWは使えるもののUTF-16なのでサロゲートペアになる。Shift-JisのVBSではサロゲートペアで表記しなければならない。

# 公式のサンプルにはごくまれに使われ、解説もない

https://learn.microsoft.com/ja-jp/windows/win32/hyperv_v2/getvirtualsystemthumbnailimage-msvm-virtualsystemmanagementservice
今回発見できたのはこれだけだった。
公式の解説や新機能の説明はVBSにはない。

# XP時代から使えていた
[WSH(VBScript) で Unicode 固有文字を表示/リダイレクトするには](http://blog.livedoor.jp/sage_p/archives/51818829.html)
>ということは、ロケールによって変わらない Ascii の文字にエンコードするプログラムを介して、子プロセスを実行して、親プロセスの WSH が Unicode にデコードすれば、正しく表示できるというわけです。 ただし、Windows XP の VBScript の ChrW にバグがあって、U+8000 以上の文字コードを文字に変換できません。Windows 7 なら大丈夫です。 U+10000 以上の文字（サロゲート・ペア）は、コマンド・プロンプト、Power Shell とも Windows 7 でもサポートしていません。 ちなみにメモ帳はサポートしています。

と、このようにChrWは当たり前に使われているのだが、なぜかVBSに含まれていることは公式の解説には見当たらない。
VBのサブセットだから当然使えるということなのかもしれないが。
selemiumでiframe内のページにアクセス

### iframe内のページにアクセスする場合

```
driver = webdriver.Chrome()

# iframe内のページにスイッチ
driver.switch_to.frame(driver.find_element_by_name(iframe name))

# HTMLを取得
print(driver.page_source)

```

#### iframe内のページにフォーカスする場合は

```
driver.switch_to.default_content()
```

#### iframe内のHTMLをパースする例

```
from bs4 import BeautifulSoup

bs = BeautifulSoup(driver.page_source, features='html.parser')
```