OmniAICreator/Qiita-1.07M huggingface dataset:
そこに i はあるんか、という話

# 1. 今回記事の内容
知っている人は知っている話ですが、JavaScript の for文の中でクロージャを使う際、ちょっとした書き方の違いで意外な動きの違いを生むという話です。

# 2. コード例
以下の２つのコードを見て下さい。

``` JavaScript: ソース１
  console.log("1つ目:iがfor()の中にある場合");
  const a = [];
  for (let i = 0; i < 3; i++) { 
    a[i] = () => {
      console.log(i);
    };
  }
  a.forEach((e) => e());
  let i = 4;
  console.log('逆順にも回してみる');
  a.reverse().forEach((e) => e()); 
```
``` JavaScript: ソース２
  console.log("2つ目:iがfor()の外にある場合");
  const a = [];
  let i = 0;            // ここが違う
  for (; i < 3; i++) {
    a[i] = () => {
      console.log(i);
    };
  }
  a.forEach((e) => e());
  i = 4;
  console.log('逆順にも回してみる');
  a.reverse().forEach((e) => e());
```

ほんのちょっとした違いがあるだけのこの２つのソースの実行結果がどうなるか、それぞれ想像してみると面白いと思います。「え、同じじゃないの？」と思った人(~~お察しの通り、私のことなのですが~~)もいるのではないかと思います。


## 2-1. 実行結果
では、実際に動かしてみます。
``` : ソース１の実行結果
1つ目:iがfor()の中にある場合
0
1
2
逆順にも回してみる
2
1
0
```
``` : ソース２の実行結果
2つ目:iがfor()の外にある場合
3
3
3
逆順にも回してみる
4
4
4
```

実行結果が予想通りであった方は、もうこの後の記事を読む必要はないと思います。
以下、不思議に思った方向けの説明となります。

# 3. なぜそうなるのかについての考察
２つのソースの違いは、for文のカウント用変数 i を定義する位置が違うだけです。

``` JavaScript: ソース１(抜粋)
  for (let i = 0; i < 3; i++) { // for() の中でiを定義
    a[i] = () => {
      console.log(i);
    };
  }
```
``` JavaScript: ソース２(抜粋)
  let i = 0;            // for() の外でiを定義
  for (; i < 3; i++) {
    a[i] = () => {
      console.log(i);
    };
  }
```

__※2023.3.24 付記 コメントでクロージャについての認識誤りをご指摘いただき説明を修正しました。PECMM様ご教示ありがとうございます。__

　この２つの違いは、for文の中でa[]という配列に定義しているアロー関数 ``` ()=>{console.log(i) ``` から見て、変数 i の扱いが違うということだと思われます。ソース１では let i は for() の中にあり、そのことによってループするたびに別コンテキストの i がアロー関数にバインドされたクロージャを形成しています。ソース２では i はfor文の外に定義され関数とそれに付随して作られたクロージャから同じ変数が参照されているだけです。

　ソース１でもソース２でもそれぞれアロー関数がfor文内で３回定義され、a[0], a[1], a[2] へセットされています。そこまでは同じですが、ソース１ではその時点での変数 i（のコピー） が各アロー関数と一緒に各アロー関数内のローカルな変数 i としてバインドされ a[0]～a[2] へ保持されます。a[0]～a[2] に設定された関数オブジェクトの中にはそれぞれ別のコンテキストの i（のコピー）が存在することになります。ソース２では変数 i はアロー関数（とそのクロージャ）の外にあるので a[0]～a[2] に設定される３つのアロー関数から１つの同じ変数 i が参照されています。その結果、アロー関数が呼ばれた時点のiの値（この場合は3と4) が3回ずつ表示されるという実行結果になっています。ソース１の実行では、各クロージャにバインドされた時点のi（のコピー）の値が表示されています。

かなり不思議な動きですが、コメントでご紹介いただいた下記の記事に説明があります。

https://qiita.com/khond/items/2d22c6b297d58ec914f5

こちらの記事を見ると、i の定義位置を変えなくてもソース１の let を var に変えるだけで違いが出そうですね…やってみましょう。

``` JavaScript: ソース３
  console.log("3つ目:iがfor()の中にあるがvarで定義されている場合");
  const a = [];
  for (var i = 0; i < 3; i++) { // let を var にした
    a[i] = () => {
      console.log(i);
    };
  }
  a.forEach((e) => e());
  i = 4;
  console.log('逆順にも回してみる');
  a.reverse().forEach((e) => e());
```

``` : ソース３の実行結果（ソース２と同じ結果になる）
3つ目:iがfor()の中にあるがvarで定義されている場合
3
3
3
逆順にも回してみる
4
4
4
```
予想通りでした。

【2024.4 追記】var と const, let のスコープ扱いの違いに関しては、下記の記事でも似たような現象を扱っています。

https://qiita.com/Yudon66/items/db40c91c165bab98304d

# 4. まとめ
JavaScriptのfor文では、以下のようなちょっとした違いで、クロージャにバインドされる変数の扱いが変わってしまうという点に注意する必要があります。

* for() の中で i を letで定義　→ iはループごとに別コンテキストでバインドされる
* for() の外で i を letで定義　→ iは各関数から同じものが参照される
* for() の中で i を varで定義　→ iは各関数から同じものが参照される
 
 その前にまずクロージャを理解しておく必要がありますが、これについては検索すると色々出て来ますので、そちらをご参照いただければと思います。
 例えばこちらの記事など。

https://qiita.com/tkmd35/items/3567912380d2eb124561

ということで、JavaScript の文法はなかなかトリッキーな一面があるので注意が必要です。

今回は以上です。
ここまで読んでいただき、ありがとうございました。
Cakephpでsaveするとdatetimeが9時間進む!?

datetime型を含むデータセットをsave()すると，mysqlの方では9時間進んでしまっていました。

まずは原因の切り分け

MySQL側
```
SELECT NOW();
```
うん，日本時間


php側も確認
```
php -r 'phpinfo();' | grep 'timezone'
```
異常なし

となるとCakePHP側?

```config\app.php
defaultTimezone => env('APP_DEFAULT_TIMEZONE', 'Asia/Tokyo'),
```

```config\bootstrap.php
date_default_timezone_set(Configure::read('App.defaultTimezone'));
```
えー，合ってる。


patchEntityしたデータセットも'Asia/Tokyo'になってるし…と思ったら，これでした。

```config\app_local.php
'timezone' => '+09:00',
```
Datasourcesに設定があるなんて…デフォルトでコメントいれといて（泣）
【Google Cloud】Dataplexを用いたデータ完全性チェック方法

## はじめに
ご覧いただいた方の中に、bigqueryに格納されているデータの中に不正なデータや重複が発生している可能性があってもすぐに検知する方法がないと悩まれている方もいらっしゃるかと思います。

本記事では、GCPに搭載されているDataplexを用いたデータの完全性をチェックする方法について記載しております。

## 記事の対象者
+ bigqueryの管理を担当していてデータの完全性を担保したい方

## 結論
+ Dataplexを用いることで以下のデータチェックなどを行うことが可能となります
  + NULL値のチェック
  + 一意性チェック
  + 正規表現対象チェック
  + 範囲チェック

## 目次
1. Dataplexの設定
1. 実行後の確認方法
1. おわりに
 
## Dataplexの設定について
### Dataplex実行設定
実際にDataplexの設定を進めていきたいと思います。
まず始めに、コンソール画面から「Dataplex」-「データ品質」を選択してください。
画面上部の「データ品質スキャンを作成」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/fffd7255-06db-f058-1811-99515c266df6.png)

スキャンの定義を作成していきます。
「表示名」はDataplexの管理画面上で表示される名称になります。分かりやすい名称にしておきましょう。
※「ID」については、表示名に基づいて自動設定されます。
「スキャンするテーブル」には、データの完全性を確認したいテーブルを指定してください。指定したテーブルが格納されているリージョンについてもこの場で設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/815109b7-cde8-23d5-3b5b-3de66fc11b62.png)

次にフィルターやスケジュールなどの設定を行います。
「フィルター」に関しては、必要があれば設定してください。SQL文を記載する要領で問題ありません。
特定期間で繰り返し実行したい場合は、「スケジュール」を設定します。もし、手動での実行で問題ない場合は、オンデマンドで設定してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/024a6275-ed18-fa43-127d-1b90b94528ef.png)

上記まではDataplexを実行するための設定となっております、

### ルール設定
ここからは実際にテーブルに格納されているデータをチェックするための設定を行います。
まずは、「組み込みルールの種類」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/bc7101fc-8cec-2e8b-0c1f-ec6875c25a32.png)

「ルールの種類を選択」からチェックを行いたいルールを選択します。
今回は「NULL値チェック」、「一意性チェック」、「範囲チェック」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/e0bfc30f-35bd-9847-2a27-1e4a8f3602fc.png)

どの項目でどのルールを適用してチェックを行いたいかを選択します。
※全てを選択する必要はありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/039d0a9b-d816-3f44-d5ca-0fc88eabdca0.png)

選択が完了したらルール設定も以上となります。
※「範囲チェック」に関しては、チェックを行いたい範囲を設定する必要があるため、編集から以下のように最大・最小値を設定する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/b14ca554-ef35-87f9-65d6-93add4f72446.png)

全ての設定を行い、「作成」ボタンを押下することで完了となります。

 ## 実行後の確認
一覧画面より作成したDataplexを確認することが可能となります。
「前回の実行」時刻を確認して予定通りのスケジュールで実行されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/671dc720-a8e1-09f2-1bb9-c3a956ac4927.png)

詳細を開くと画面上部に設定したルール違反したかどうかを確認することが出来ます。
※今回の場合は、ルール違反が発生している状態となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/ee86819b-0267-2dad-958b-878a56ba28f7.png)

詳細分析を選択するとどのルールで違反を起こしているのかを確認することが出来ます。
※今回の場合は、「id」にて一意性違反を検知した形となります。
　どんなデータが違反を引き起こしているかは、下図の赤枠を選択して
 　「失敗したレコードを取得するクエリ」を取得することで確認することが可能となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/df5debdf-49d7-b883-dcda-efe6def9bd42.png)

## おわりに
Dataplexでどんなことが出来るのかを一部ですが、紹介させていただきました。
記載出来ておりませんが、他のルールを指定することで様々な観点からデータのチェックを行うことが可能となりますので、ご活用下さい。
本記事が、どなたかの役に立てたのであれば幸いです。
拝見頂き、ありがとうございました。
pry のエラーメッセージを短くする

`nokogiri`を使った処理をしてるとエラーが出たときにオブジェクトのテキスト量が多すぎてデフォルトの設定だと肝心のエラーメッセージを確認するためにコンソールを大量に巻き戻らないといけない

`Nokogiri::XML::Document`クラスのエラーでだけ表示を短くしたかったけど方法がわからなかったので例外全てを300文字以上表示しないように変えてみた。

```.pryrc
Pry.config.exception_handler = proc do |output, exception, _|
  output.puts "#{exception.class}: #{exception.message.truncate(300)}"
  output.puts "from #{exception.backtrace.first}"
end
```

もっとシンプルな解決策がありそうだけど見つからなかったので当面はこれで我慢しよう。

### 参考
https://github.com/pry/pry/wiki/Customization-and-configuration#Config_exception
OpenShift Virtualization

# OpenShift Virtualization というのがあります。
OpenShift Container Platform(以降、OCP と称します) に含まれている機能の一つです。
OCPは、コンテナをサービスを効率よく運用/利用するためのソリューションではありますが、
OpenShift Virtualization(以降、OCP-Virt と称します)は、KVM(Kernel-based Virtual Machine)を利用した仮想環境もOCP上でご利用いただけます。
# Red Hat の仮想化
余談なお話になりますが、
Red Hatから提供されているKVMベースの仮想化ソリューションをざっくりですが以下に並べてみました。(OCP-Virtを除く)
* Red Hat Enterprise Linux
    * Red Hat Enterprise Linux のKVMを利用した仮想環境
* Red Hat Virtualization(RH-V / 旧名 : Red Hat Enterprise Virtualization【RHEV】)
    * こちらの製品は、2024年10月31日にメンテナンスサポート、拡張サポート共に終了
    * v4.4 で、製品として提供を終了
* Red Hat OpenStack Platform
    * KVMを利用した、Compute Node が、OpenStack Platform の仮想環境

似たようなサービス/機能が複数あると使う方も、使う側も、選択する側も混乱しますね。
このような状況で、RH社からの資料をみると、KVMベースの仮想環境は、OCP-Virtへ集約するような記載がありました。

# OCP-Virt で認定およびサポートされているゲストOSは?
OCP-Virt で認定およびサポートされているゲストOSの詳細情報は、[こちら](https://access.redhat.com/ja/articles/1390803/#ocpvirt) をご確認ください。
- Red Hat
    - Red Hat Enterprise Linux 6, 7, 8, 9 (すべて64bitのみ)
- Windows系
    - Windows 11, 10 (すべて64bitのみ)
    - Windows Server 2012R2, 2016, 2019, 2022 (すべて64bitのみ)

# さいごに
今回は、OCP-Virtというものの紹介をしてみました。
あまり、表立って目立たない機能ではありますが、昨今のIT業界事情のこともあり、
今後、少しづつかと思いますが、見かける機能だと感じています。
Windowsライセンス認証方式（MAK、KMS）の違い

## 認証方式の違い
WindowsServerでは2つのライセンス認証方式がある。
・MAC
・KMS

現場でKMSでのライセンス認証について調査したため書き留めておく。
MAKとKMSの違いを大まかにまとめると以下の通り。
| 認証方式 | 説明 | 備考 |
|:-:|:-:|:-:|
| MAK  |各PCがMicrosoftにアクセスし、直接ライセンス認証する。   | 小規模な環境向き  |
| KMS  |KMSホストを経由し25台以上のKMSクライアントPCに対し、ライセンス認証を行う。   |  大規模な環境向き|


 ## MAK
 Multiple Activation Keyの略称。
各PCがインターネット経由でMicrosoftにアクセスし、ライセンス認証を行う。
オフライン環境下でも、Microsoftのコールセンターに連絡し、MAK認証コードを取得できる。

MAKには以下の特徴がある。

1. 1つの認証キーで多数のPCをアクティベーションできる
2. ライセンスキーの認証回数に上限が設定されている（Microsoftに上限回数を増やせる）

後述するが、KMSは少なくとも25台以上のKMSクライアントPCを認証しないと全ての認証が行えなくなる。そのためMAKは比較的小規模な環境に適している。

## KMS
Key Management Serviceの略称。
KMSホストとしてライセンス認証サーバを構築する。各PCはライセンス認証サーバを経由してMicrosoftにアクセスし、ライセンス認証を行う。
MAKと同様に、オフライン環境下でも、Microsoftのコールセンター経由で認証コードを取得できる。

KMSには以下の特徴がある。
1. KMSホスト（ライセンス認証サーバ）を構築する必要がある
2. 各サーバ、PC（KMSクライアント）が、KMSホストに対してライセンス認証を行う
3. 各サーバ、PC（KMSクライアント）は**180日**ごとに再認証が必要
4. KMSホスト（ライセンス認証サーバ）は、認証リクエストを行ったKMSクライアントの情報を**30日**保持する
5. デフォルト設定では、**7日間毎**に有効期限の延長（アクティベーション）を行う
6. KMSホストが認証する各サーバ、PC（KMSクライアント）は、最低25台必要


### KMSの注意点
KMSクライアントがライセンス認証されると、**180日間**のライセンス認証有効期間が与えられる。
KMSクライアントがKMSホストに接続できなくなっても、オフライン状態でもライセンスが有効なため、直ちにライセンス認証が外れることはない。
KMSホストが持つKMSクライアント情報は**30日以上**経過すると削除されるため、KMSクライアントが**25台**を下回る恐れがある。
**25台**を下回るとKMSクライアントは全てのライセンス認証を行えなくなる。定期的にKMSホストとの通信を行うことで回避できる。
ユーザが長期休暇等で離席する場合注意が必要。


## 参考文献
[MAK](https://the-simple.jp/what-is-a-mak-multiple-activation-key-explain-how-windows-activation-works-and-how-to-use-it)
[KMS](https://mytech-blog.com/kms/)
[KMSのライセンス数下限](https://learn.microsoft.com/ja-jp/windows-server/get-started/kms-create-host)
AWS AppFlow 接続先情報を変更するために「フローを編集」をクリックするとエラーが出る

## 概要

AppFlowの接続先の認証情報が代わった。送信元接続の情報を変えようとフローの詳細画面からアクションを開き「フローを編集」をクリックしたらエラーが出たので自分の場合の解決方法を簡単にメモする。

## エラー内容

```
Error while communicating to connector: HttpClient error executing/parsing response given request object due to 接続先の情報
```

## 解消方法

そもそも、送信元接続の情報変更は、フローの編集画面からではなく、フローの詳細画面の「送信元接続」の下にある「別の接続を選択」をクリックして変更すれば良い。
接続が確立されている、「送信元接続」を選択できれば、「フローを編集」をクリックしてもエラーにならない。
マイナビのハッカソン型インターンで優勝した話

マイナビのハッカソン型インターン「フルスタック開発プログラム」に参加し、グランプリ賞を獲得することができました:tada:

![PXL_20240116_000514709.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143089/e29db3b4-90dd-f43c-5c88-17877643bac9.jpeg)

インターンを振り返りつつ感想などをまとめます！

# ハッカソンの概要

\<NDA>の\<NDA>による\<NDA>のためのプロダクトが用意されており、そのサービスを1万ユーザーから10万ユーザーにグロースさせるという目標が与えられました。
10万ユーザーに合わせたインフラ設計やユーザー獲得のための機能改善・新規機能開発を行いました。
1チーム4人で割り振られ、そこにインフラメンターとアプリメンターが付いてくださりました。
4日間と8日間のインターンがありましたが、私は時間の都合上4日間の方に参加しました。

フルスタック開発というだけあってインフラ設計からバックエンド・フロントエンドもできるといったほぼ全てを行える充実したインターンでした！

# 初日

最初にチーム発表がされ、その後自己紹介や、簡単なレクリエーションを行いました。
ハッカソンを進めていくうえで、リーダーを決める必要があったのですが、お互いにめちゃくちゃ遠慮して結局自分がリーダーになりました。
正直風邪をひいていたのでリーダーは避けたかったのですが、その後のサービス選定などで結局リーダーっぽい動きをしていたのでやってよかったです。

# インフラ設計

AWS固定でインフラ設計を行っていきました。

現状課題としてEC2にコンテナ化されたWeb・API・DBがすべて入っていたため、ほぼ0からのインフラ設計となりました。

メンバー3名はクラウドを触った経験が無くAWSへの知識差があったため、サービス選定の際にそれぞれのメリット・デメリットや関係性を説明しつつ全員で選定を行いました。
また、その説明と同時並行でインフラ構成の図を自分以外の3名に作成していただきました。
AWS全く触ったことが無かったそうなのですが、流れまで完璧に図へ落とし込んでおりその理解力に驚きました...

こんなこと考慮するといいよ〜と予め資料に課題感が書いてあるため、それを参考にしつつ、可用性やセキュリティ、運用・保守性など様々なことを考慮しながら設計を進めました。

↓2日目に出来上がった構成図(モザイク加工してあります)

![mosaic (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3143089/f0e2d5a4-af4b-ddf0-b418-cfd83ad32068.png)


わからないことがあれば気軽にインフラメンターさんに聞けるため、AWSの知識がほぼ0でもなんとかなると思います。
私はCI/CD周りでわからないことあったのでメンターさんに聞きまくりましたが、快く一緒に調べていただけました。

構成レビュー会では、お褒めの言葉を頂きつつも、考慮不足の点を丁寧に教えていただき大変勉強になりました！

# Webアプリ開発

2日目の午後からWebアプリ開発のワークが始まりました。
といっても最初から手を動かすのではなく、以下のように進めていきました。

1. ターゲット・コンセプト・ベネフィットを考える
2. サービスの改善点を見つける
3. 優先度を決める
4. 役割分担し各々のタスクを決める

上記手順を真剣に行ったことが、結果に繋がったのではないでしょうか。

タスクを決める際、せっかくならこのインターンで挑戦的なことをしたいと思っていたので、私はAIを使用した重めの新規機能開発にしました。

サービスはTypeScript/Next.jsで書かれており、普段バックエンドをメインにしている私にとってはほとんど経験がありませんでしたが、なんとか締め切り1時間前ぐらいに終わらせることができました。

TypeScriptは型による補完や早期エラー発見に繋がってありがたいなという思いと、例外的な場合でも型に合わせなくてはいけない大変さがありました。
any使ったら負けだと思って、歯食いしばってコーディングしてました。
昨今TypeScript好きな人が多いですが、しっかり言語仕様まで学べばたしかにハマりそうな予感はしました。

ちなみにどんな開発を行っていたかの詳細は、サービス内容がわかってしまう可能性があるため伏せさせていただきます。
インターンに参加してからのお楽しみというやつです。

# 成果発表・結果

最終日にインフラとWebアプリの両方を含めた成果発表を行いました。
私たちのチームは最後だったので少し緊張しましたが、説明やデモも問題無く終わり、無事に良い発表ができたと思います。

結果として**グランプリ賞**をいただくことができました！

評価されていた点としては色々ありましたが、まず個人的にはスライドがとても良かったと思っています。
メンバーの方にデザインつよつよの方がいたので、アイコンやグラフを使用しつつシンプルで見やすいスライドを作成していただけました。

また、技術的な点を多く評価していただけました。インフラにしろwebアプリにしろ、かなり挑戦できていたのではないかと思います。

ですがグランプリ賞にあたってはビジネスにどう貢献しているか、という部分がとても重要視されていた気がします。

私たちのチームはアプリワーク初期に、どのような機能を実装したら顧客が増えるか、如何にユーザーを獲得するかの分析を重点的に行いました。
そのおかげか、「目的が一貫しており、目標のユーザー数10万人の達成方法が現実性のあるものになっていた」と好評を得ることができました。

また+αとして機能レベルでマネタイズを考慮していたチームは私たちだけだったので、その点も評価いただけました。

施策・インフラ・アプリにおいて、どのような課題・目的があり、それをどう解決するか全員で議論し発表で伝えられた結果、グランプリ賞を獲得することができたんじゃないかな〜と思います。

# インターンに対する感想

ハッカソンと言えば0からサービスを作成するイメージですが、グロースに焦点を当てるという点が面白かったです。
実際の業務でも 0->1 より既存サービスをグロースさせる方が圧倒的に多いと思うので良い経験になりました。

巷におけるフルスタックインターンは「フルスタック(フロントエンド・バックエンド)」ということが多いですが、マイナビのインターンではインフラ設計から始められるので、なんでもやってみたいフルスタックエンジニア志望の方にぜひオススメです！

# 全体の感想

風邪をひきつつもなんとか気合で乗り切ることができ、さらにグランプリ賞までいただけて達成感でいっぱいです！
教えられそうな部分などは積極的に知識共有し、少しはチームの役に立てたんじゃないかと思います。

また各々の得意分野が異なっていたおかげで、適材適所にタスクを割り振り円滑に進めていくことができました。
メンバーと支えてくださったメンターの方に大感謝です！

ありがとうございました！！
【Flutter】custom_lint：nullableな変数に対するアンラップは避けよう

こちらは以下の続きになります。

https://qiita.com/kurogoma939/items/cfefb0eec1e2e8b14302

## 背景

APIなどを用いて実装する場合、nullableな変数を扱うことは多いと思います。
その際、当然nullチェックをすると思うのですがよく以下のような書き方をしていませんか？

```dart
if (state.user != null) {
  print(state.user!.name);
}
```

このように、`state.user!`とアンラップしていますが、一応事前にnullチェックをしているので問題はありません。
しかし、全体でこういうのも変数に入れて避けていきたいという方針があったためlintルールを自作することにしました。

ルール設定後は以下のように回避できます。

```dart
final user = state.user;

if (user != null) {
  print(user.name);
}
```

一度変数に格納することでnullチェック後にアンラップする必要がなくなります。

## 実装

```dart
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

class NullableUnwrapWarning extends DartLintRule {
  const NullableUnwrapWarning()
      : super(
          code: _code,
        );

  static const _code = LintCode(
    name: 'nullable_unwrap_warning',
    problemMessage:
        'nullableな変数に対して!演算子を使用してアンラップしています。nullチェックを行うか、?演算子を使用することを検討してください。',
    errorSeverity: ErrorSeverity.WARNING,
  );

  @override
  void run(
    CustomLintResolver resolver,
    ErrorReporter reporter,
    CustomLintContext context,
  ) {
    context.registry.addPostfixExpression((node) {
      if (node.operator.type == TokenType.BANG) {
        final operandType = node.operand.staticType;
        if (operandType != null &&
            operandType.nullabilitySuffix == NullabilitySuffix.question) {
          reporter.reportErrorForNode(_code, node);
        }
      }
    });
  }
}
```

設定したら`getLintRules`に入れて`flutter pub get`をして適応しましょう。

```dart
PluginBase createPlugin() => _MyCustomLinter();

class _MyCustomLinter extends PluginBase {
  @override
  List<LintRule> getLintRules(CustomLintConfigs configs) => [
        // 各lintルールを定義したクラスを配置していく
        const NullableUnwrapWarning(),
      ];
}
```
【Flutter】custom_lint：ifのネストは避けよう

こちらは以下の続きになります。

https://qiita.com/kurogoma939/items/cfefb0eec1e2e8b14302

## 背景

リーダブルコードや良いコード・悪いコードなどあらゆるところで「深いネストは避けよう」と言われることが多いと思います。
Flutterの場合、ウィジェットのネストが深くなるのは場合によって致し方ない&ルール化してしまうと可読性を逆に落とすのでは？と思い、今回はロジックのif文でのネストに注目してルール設定をしました。
if > if >...とネストするのは2重までとし、原則早期returnなどをして欲しいという思いがあります。

## 実装

```dart
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

class IfNestingLimit extends DartLintRule {
  const IfNestingLimit()
      : super(
          code: _code,
        );

  static const _code = LintCode(
    name: 'if_nesting_limit',
    problemMessage: 'ifのネスト階層は2つまでにしてください',
    errorSeverity: ErrorSeverity.WARNING,
  );

  @override
  void run(
    CustomLintResolver resolver,
    ErrorReporter reporter,
    CustomLintContext context,
  ) {
    context.registry.addIfStatement((node) {
      _checkIfNestingLimit(node, reporter);
    });
  }

  void _checkIfNestingLimit(IfStatement node, ErrorReporter reporter) {
    int nestingLevel = 0;
    AstNode? currentNode = node;

    while (currentNode != null) {
      if (currentNode is IfStatement && currentNode.elseStatement == null) {
        nestingLevel++;
      }
      currentNode = currentNode.parent;
    }

    if (nestingLevel > 2) {
      reporter.reportErrorForNode(_code, node);
    }
  }
}
```

```dart
PluginBase createPlugin() => _MyCustomLinter();

class _MyCustomLinter extends PluginBase {
  @override
  List<LintRule> getLintRules(CustomLintConfigs configs) => [
        // 各lintルールを定義したクラスを配置していく
        const IfNestingLimit(),
      ];
}
```
【Flutter】custom_lint：enumはifではなくswitchを用いよう

こちらは以下の続きになります。

https://qiita.com/kurogoma939/items/cfefb0eec1e2e8b14302

## 背景

Flutterはenumが充実しており、様々な活用方法が増えてきています。
もちろん条件分岐で考慮漏れが減ることもメリットの一つだと思います。
しかし、条件分岐の際にswitch文（or 式）を用いれば考慮漏れが減るのですがifを用いてしまうとうっかり考慮漏れが発生してしまう場合があります。
そのため、これをルールで弾くことにしました。

## 実装

```dart
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

class PreferSwitchOverIfWithEnum extends DartLintRule {
  const PreferSwitchOverIfWithEnum() : super(code: _code);

  static const _code = LintCode(
    name: 'prefer_switch_over_if_with_enum',
    problemMessage: 'Use switch instead of if when comparing enums',
    errorSeverity: ErrorSeverity.WARNING,
  );

  @override
  void run(
    CustomLintResolver resolver,
    ErrorReporter reporter,
    CustomLintContext context,
  ) {
    context.registry.addIfStatement((node) {
      // ifでEnumを比較しているかチェック
      final condition = node.expression;
      if (condition is BinaryExpression) {
        final leftOperand = condition.leftOperand;
        final rightOperand = condition.rightOperand;

        if (leftOperand is Identifier && rightOperand is Identifier) {
          final leftElement = leftOperand.staticElement;
          final rightElement = rightOperand.staticElement;

          if (leftElement is PropertyAccessorElement &&
              rightElement is PropertyAccessorElement) {
            final leftType = leftElement.variable.type;
            final rightType = rightElement.variable.type;

            if (leftType is InterfaceType &&
                rightType is InterfaceType &&
                leftType.element.kind == ElementKind.ENUM &&
                rightType.element.kind == ElementKind.ENUM) {
              reporter.reportErrorForNode(_code, node);
            }
          }
        }
      }
    });
  }
}
```

また、ルール設定した際は`getLintRules`への追加もお忘れなく。

```dart
PluginBase createPlugin() => _MyCustomLinter();

class _MyCustomLinter extends PluginBase {
  @override
  List<LintRule> getLintRules(CustomLintConfigs configs) => [
        // 各lintルールを定義したクラスを配置していく
        const PreferSwitchOverIfWithEnum(),
      ];
}
```
【Flutter】custom_lint：buildメソッド内部でのref.readは避けよう

こちらは以下の続きになります。

https://qiita.com/kurogoma939/items/cfefb0eec1e2e8b14302

## 背景
Riverpodを用いる際、stateの参照を行う場合にref.readやref.watchを用いることができますが、ref.readの場合思い通りにリビルドされなかったりとバグの要因にもなり得るためbuildメソッド内部では`ref.watch`で統一したいところです。
そのため、ref.readで変数定義はしないような制約を設けました。

https://riverpod.dev/ja/docs/essentials/do_dont


```dart
// This is the entrypoint of our custom linter
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

/// メソッド呼び出し時にWidgetRefクラスのreadメソッドが呼ばれているかをチェックする

class NoRefReadVariableDeclarationInBuildMethod extends DartLintRule {
  const NoRefReadVariableDeclarationInBuildMethod() : super(code: _code);

  static const _code = LintCode(
    name: 'no_ref_read_variable_declaration_in_build_method',
    problemMessage: 'buildメソッド内部での変数定義時にref.readは使用しないでください',
    errorSeverity: ErrorSeverity.ERROR,
  );

  @override
  void run(
    CustomLintResolver resolver,
    ErrorReporter reporter,
    CustomLintContext context,
  ) {
    context.registry.addMethodInvocation((node) {
      if (_isWidgetRefReadMethodInBuildMethod(node, resolver)) {
        reporter.reportErrorForNode(_code, node);
      }
    });
  }

  bool _isWidgetRefReadMethodInBuildMethod(
    AstNode node,
    CustomLintResolver resolver,
  ) {
    final buildMethod = node.thisOrAncestorOfType<MethodDeclaration>();
    if (buildMethod == null || buildMethod.name.lexeme != 'build') {
      return false;
    }

    if (node is MethodInvocation) {
      final target = node.target;
      final methodName = node.methodName.name;
      if (target is SimpleIdentifier &&
          target.name == 'ref' &&
          methodName == 'read') {
        final parent = node.parent;
        if (parent is VariableDeclaration && parent.initializer == node) {
          return true;
        }
      }
    }

    return false;
  }
}

```

ただ力技が否めないのでもう少しいい方法があればコメントいただきたいです！

クラス定義をしたら、忘れず前回の記事にある`getLintRules`にも追加しておきましょう。
```dart
PluginBase createPlugin() => _MyCustomLinter();

class _MyCustomLinter extends PluginBase {
  @override
  List<LintRule> getLintRules(CustomLintConfigs configs) => [
        // 各lintルールを定義したクラスを配置していく
        const NoRefReadVariableDeclarationInBuildMethod(),
      ];
}
```
Oralce から データ移行する際の TRIM と 空白の NULL 化の仕様検討メモ

## 移行方針概要

Oracle から他データベースに移行する際には次の仕様を移行する必要があり、移行先のデータベースにてどのように扱う方針を検討する必要がある。末尾のスペースを削除する必要があり、本記事ではその処理を RTRIM として記載する。

1. CHAR 型にて不足している桁数に足りない場合にスペースをうめること
2. 空白（例：``）の文字型を NULL として扱うこと *1
3. Oracle SQL*Loader にて PRESERVE BLANKS  を設定している場合、かつ、position 関数を利用していない場合に、CHAR 型、DATE 型、および、数値型の半角スペースを RTRIM すること *2
4. Oracle SQL*Loader にて PRESERVE BLANKS  を設定してない場合、かつ、position 関数を利用している場合に、CHAR 型、DATE 型、および、数値型の全角スペースと半角スペースを RTRIM すること

*1 CHAR 型の RTRIM を実行する場合には、CHAR 型のスペースを RTRIM したカラムをスペースと同等に扱う必要があり、NULL に変換するべきではない。

*2 RTRIM の対象のデータ型について、下記のドキュメントに記載あり。

> - `CHAR`データ型
>
> - 日時および期間データ型
>
> - 数値型
>
>     ```PlainText
>     EXTERNAL
>     ```
>
>     データ型:
>
>     - `INTEGER` `EXTERNAL`
>     - `FLOAT` `EXTERNAL`
>     - (パック)`DECIMAL` `EXTERNAL`
>     - `ZONED`(10進)`EXTERNAL`

引用元：[空白の切捨てが可能なデータ型 (oracle.com)](https://docs.oracle.com/cd/E57425_01/121/SUTIL/GUID-84765118-3731-4D76-BBAD-E481882B7BC6.htm)

## 移行方針

取り込みプログラム、ファイル形式、および、オプション別の、対応方法を次表に整理する。

| 取り込みプログラム | ファイル形式                | オプション1          | RTRIM 対応                                                   |
| ------------------ | --------------------------- | -------------------- | ------------------------------------------------------------ |
| Pro*C              | CSV（区切り文字区切り形式） | -                    | CHAR 型のカラムの半角スペースを RTRIMプログラムにて TRIM （or RTRIM）処理しているカラムの半角スペースを TRIM（or RTRIM） |
| Pro*C              | バイト区切りの固定長形式    | -                    | CHAR 型のカラムの半角スペースを RTRIMプログラムにて TRIM （or RTRIM）処理しているカラムの半角スペースを TRIM（or RTRIM） |
| SQL*Loader         | CSV（区切り文字区切り形式） | PRESERVE BLANKS なし | CHAR 型、DATE 型、および、数値型が設定されているカラムの半角スペースを RTRIMプログラムにて TRIM （or RTRIM）処理しているカラムの半角スペースを TRIM（or RTRIM) |
| SQL*Loader         | CSV（区切り文字区切り形式） | PRESERVE BLANKS あり | CHAR 型のカラムの半角スペースを RTRIMプログラムにて TRIM （or RTRIM）処理しているカラムの半角スペースを TRIM（or RTRIM) |
| SQL*Loader         | バイト区切りの固定長形式    | PRESERVE BLANKS なし | CHAR 型、DATE 型、および、数値型が設定されているカラムの全角スペースと半角スペースを RTRIMプログラムにて TRIM （or RTRIM）処理しているカラムの半角スペースを TRIM（or RTRIM) |
| SQL*Loader         | バイト区切りの固定長形式    | PRESERVE BLANKS あり | CHAR 型のカラムの半角スペースを RTRIMプログラムにて TRIM （or RTRIM）処理しているカラムの半角スペースを TRIM（or RTRIM) |





| 取り込みプログラム | ファイル形式                | オプション1          | 空白を NULL 化の対応            |
| ------------------ | --------------------------- | -------------------- | ------------------------------- |
| Pro*C              | CSV（区切り文字区切り形式） | -                    | すべての文字型のカラムを実施    |
| Pro*C              | バイト区切りの固定長形式    | -                    | CHAR 型以外の文字型に対して実施 |
| SQL*Loader         | CSV（区切り文字区切り形式） | PRESERVE BLANKS あり | すべての文字型のカラムを実施    |
| SQL*Loader         | CSV（区切り文字区切り形式） | PRESERVE BLANKS なし | すべての文字型のカラムを実施    |
| SQL*Loader         | バイト区切りの固定長形式    | PRESERVE BLANKS あり | CHAR 型以外の文字型に対して実施 |
| SQL*Loader         | バイト区切りの固定長形式    | PRESERVE BLANKS なし | CHAR 型以外の文字型に対して実施 |
SQLLineageを作ってみた（ベータ版リリース🎁）

# はじめに :writing_hand:
**SQL Lineage**という言葉をご存じでしょうか。

"リネージュ"か"リネージ"か日本語特有の問題が出ますが、とりあえず私は"リネージ"でいきます。
英単語のlineageは、系統とか血統という意味です。ゲームで20年以上前から、リネージュというのがありますが、同じ単語です。
スペルが難しいので私は、"LINE"と"AGE"が組み合わさって、祖先にさかのぼる系統図の線をイメージして覚えてます。

さてそのリネージですが、SQLと合わせて、**SQL Lineage**というものがあります。with句を使ったりした複雑なSQLで、最終的なselectで使う列って、おおもとはどこから来てるんだっけ？というのを図示するものです。

テーブル単位だけでなく、列単位で、どこから来ているのか知りたくなります。カラムレベルリネージと言われます。

そのツールはいくつか出てるのですが、使い勝手とか、機能過多とか、見た目とかでしっくりこなさすぎるので、作ってみることにしました。有償のサービスもあるけど、これそんなに難しい話じゃなくない？という安易な考えもあり。

# 要件・技術 :point_up:
- クライアント
    - 要件：ブラウザで動く
    - 技術：React
- サーバー
    - 要件：どこかのPaaSで動くREST API
    - 技術：Node.jsのexpress

### 開発開始時の私のスキル :thinking:
- フロントエンド開発経験
    - 仕事ではなし
    - プライベートの独学のみ
    - JavaScriptは昔から触っていて好き
- サーバー開発経験
    - REST APIの設計・開発は、pythonで経験あり
- Node関係
    - Node.jsは独学
    - React、expressともに初
        - ※いつかしっかりやってみたかった思いはずっとあった

# 作ってみた（現時点。初期）:confetti_ball:
https://sql-parse-client-202403.an.r.appspot.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/206b0024-28e1-4c90-9221-70dcb9054094.png)

入れたクエリ
```sql
with t_a1 as (
  select
    id,
    col1 as col_a1
  from
    t_a
)
select
  t_a1.id,
  t_a1.col_a1,
  t_b.coll_b
from
  t_a1,
  t_b
```
モチベアップのために、リネージの部分を先行して実装しました！
Lineage なのか visualizer なのか viewer なのか、ブレすぎてることに今気づきました！:laughing:

## インフラ面 :level_slider:
クライアントはGAE、サーバーはRenderに置いてあります。いずれも無料枠。

Renderは無料だと15分くらいでspin downしてしまい、その後起動に数分(!)かかります。一度起動すれば速いんですが、最初だけお待ちください。:bow:
F12のコンソールで、クエリが出た後に何もなくじっとしてるときは、サーバーを待ってます。

## コード :page_with_curl:
３つのリポジトリを使っています。

### 1. クライアント
Reactのアプリです。
これをGAEに置いています。

https://github.com/yo16/sql_parse_client_202403

### 2. APIサーバー
expressで作ってます。
これをRenderに置いています。
CORSの設定に割と躓きましたが、なんとかクリア。

https://github.com/yo16/express_sql_parser_202403

### 3. SQLパーサー
expressで使っているnode moduleです。githubにアップして、expressではgithubから読みこむ形。npmへの公開は、汎用的でないので不要と思ってます。

この中でさらに、[taozhi8833998/node-sql-parser](https://github.com/taozhi8833998/node-sql-parser) を使ってます。私のモジュールは、この機械的なパーサーの結果を読み解いて、クライアントで使う目的に合わせて、加工したり情報を落としたりしてます。

https://github.com/yo16/sql_parse_202403


# 今後アップデート内容:construction_worker:
いまのところ、上の方が優先度高。
- コンパネ対応（緑のところ）
    - テーブル間の線の表示/非表示のチェックボックス
    - 列間の線の表示/非表示のチェックボックス
    - DBの方言対応（今はハードコーディングでBigQueryです。）
    - マウス操作で全体の移動、拡大/縮小
    - テーブルか列のクリック or マウスホバーで、その系統を強調
    - 文字サイズやスペースの調整ができる機能
    - エクスポート機能
        - PDF
        - クリップボード（Officeに貼り付けられる形だと嬉しいが、技術はまだ不明）
- SQLファイルをドロップしたら読む対応
- where句の対応（どう表現するか未定）
- エラーハンドリング
- 複数のSQLファイルを混在
- デザイン、見た目
- インフラ整備
    - Renderが休まない仕組み？ or 有償化
    - 引っ越し、k8s化
- ログイン機能
    - 過去のクエリの保存、呼び出し
- 課金機能
    - 保存
    - エクスポート機能？
- 随時、クエリのテストとデバッグ

たっぷりありますね・・・。:skull:

最終的な姿は、ログインせずとも大体使えるけど、保存とかエクスポートのプラスアルファ機能を課金に持っていけたらって思ってます！:money_mouth:
または特定の企業向けのクローズドなシステムとして、他のシステムと結合したり。

# おわりに :grinning:
ボロボロだろうがなんだろうが、早く第一弾をリリースしたかったんですが、時間がかかってしまいました。ようやく簡単なクエリなら動くようになりました。
触ってみていただけたら嬉しいです！

https://sql-parse-client-202403.an.r.appspot.com/

もろもろの機能要望、アドバイス、バグ報告、応援等、なんでもコメントでいただけるとありがたいです！:grinning:📣

よろしくお願いします！
【Mac/iPhone/iPad】Apple Musicトライアル期間中に機能を解除する

# 現象
「Apple Music」の無料トライアル期間中にサブスクリプションの解約を申請した。
しかし、有効期限は6月まで残っており、「Apple Music」の機能を解除できなかった。
（「iPhone 15 Pro」を購入した際の特典。）

# 実行環境
* macOS : macOS Sonoma 14.4（23E214）
* iOS : 17.4

# 対応
Appleに問い合わせをしたが、無料トライアル期間中の機能の解除はできないとのこと。
有効期限が来るまで「Apple Music」の機能が付随された「ミュージック」アプリを使い続けるしか無い。
（問い合わせ日時：2024年3月21日12時20分）
【Flutter】custom_lint：セットアップ

## はじめに

Flutterでレビュー負担軽減のためにcustom_lintを用いて自作のlintルールを設定しました。
手順等忘れないため記録として残します。

また、ルール別に記事を書くのでここでは目次＋セットアップの紹介としたいと思います。

## 設定したlintルール一覧
- buildメソッド内部でref.readを用いるのは避けよう
- enumはifではなくswitchを用いよう
- ifのネストは2階層までにしよう
- nullabelの変数に対するアンラップは避けよう


## セットアップ

### 1. ディレクトリの用意
lint用にディレクトリを用意します。
プロジェクト直下に以下のようなディレクトリ構造を用意してください。

```
└─ packages/my_custom_lint/
  ├─ lib/
  │  ├─ my_custom_lint.dart
     // この下は任意です
  │  ├─ if_nesting_limit.dart
  │  ├─ no_ref_read_variable_declaration_in_build_.dart
  │  ├─ nullable_unwrap_warning.dart
  │  └─ prefer_switch_over_if_with_enum.dart
  ├─ pubspec.lock
  └─ pubspec.yaml
```

### 2. 必要な設定

:::note
`my_custom_lint`としている箇所は同じ名前で統一するようにしてください。
:::

`pubspec.yaml`にはlint設定に必要なパッケージを記載します。
記載したら一度`flutter pub get`をしておいてください。

```packages/my_custom_lint/pubspec.yaml
name: my_custom_lint
environment:
  sdk: ">=3.0.0 <4.0.0"

dependencies:
  analyzer: ^6.2.0
  analyzer_plugin: ^0.11.3
  custom_lint_builder: ^0.6.1
```
```packages/my_custom_lint/my_custom_lint.dart
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'package:my_custom_lint/if_nesting_limit.dart';
import 'package:my_custom_lint/no_ref_read_variable_declaration_in_build_method.dart';
import 'package:my_custom_lint/prefer_switch_over_if_with_enum.dart';

PluginBase createPlugin() => _MyCustomLinter();

class _MyCustomLinter extends PluginBase {
  @override
  List<LintRule> getLintRules(CustomLintConfigs configs) => [
        // 各lintルールを定義したクラスを配置していく
        const NoRefReadVariableDeclarationInBuildMethod(),
        const PreferSwitchOverIfWithEnum(),
        const IfNestingLimit(),
        const NullableUnwrapWarning(),
      ];
}
```

次に、プロジェクト直下の`pubspec.yaml`に上記のlint用パッケージを追加します。
custom_lintパッケージと同時に以下のように定義してください。

```pubspec.yaml
dev_dependencies:
  custom_lint: ^0.6.0
  my_custom_lint:
    path: packages/my_custom_lint
```

あとは`flutter pub get`をすれば適応が完了します。若干リロードに時差があるかもしれないのでうまく読みこまれない場合はlintの書き方の見直しやIDEの再起動をしてみてください。
【Mac/iPhone/iPad】iTunes Storeにおいて「購入済み」に全ての楽曲が表示されない

# 現象
iTunes Storeにおいて、「購入済み」一覧にこれまで購入した楽曲のうち最近購入した一部の楽曲しか表示されない。

# 実行環境
* macOS : macOS Sonoma 14.4（23E214）
* iOS : 17.4

# 原因
Appleに電話で問い合わせたところ「しばらくすると」自動的に非表示になるとのこと。
なお、「しばらく」の具体的な日数は回答していただけなかった。
（問い合わせ日時：2024年3月21日12時20分）

# 対応方法
Appleに問い合わせし、本人確認を行なった上で再表示を依頼する。
この時、購入した項目が多いほど処理に時間がかかり、長い時間待つ必要がある。
（私の場合、楽曲数は不明だが30分超保留のままだった。）
ZED SDK のTemperatureData 型

## 想定する読者
stereolabsのzed2, zed mini, zed x などのステレオカメラの利用者
いまどきのステレオカメラは何ができるのかを知りたい人

## 前提
ZED SDK 4.0
Ubuntu 20.04
ZED2i
Python 版のAPI


## Temperature Sensors 
pyzed.sl.TemperatureData 型
メソッド
get(location)

公式ドキュメント [Temperature](https://www.stereolabs.com/docs/sensors/temperature)
2024.03.19 時点では、temperature データについてのドキュメントが、実装との乖離を生じています。

## [web ページ上のコード例](https://www.stereolabs.com/docs/sensors/temperature#using-the-api)
2024.3.21 時点の引用

```.py:
temperature_data = sl.SensorsData.TemperatureData()
temperature_data = sensor_data.temperature
temperature_left = temperature_data.get(sl.SensorsData.TemperatureData.SENSOR_LOCATION.ONBOARD_LEFT)
temperature_right = temperature_data.get(sl.SensorsData.TemperatureData.SENSOR_LOCATION.ONBOARD_RIGHT)
temperature_imu = temperature_data.get(sl.SensorsData.TemperatureData.SENSOR_LOCATION.IMU)
temperature_barometer = temperature_data.get(sl.SensorsData.TemperatureData.SENSOR_LOCATION.BAROMETER)
```

## 動作したコード例　2024.3.21 時点

```.py:
temperature_data = sl.SensorsData.TemperatureData()

temperature_left = temperature_data.get(sl.SENSOR_LOCATION.ONBOARD_LEFT)
temperature_right = temperature_data.get(sl.SENSOR_LOCATION.ONBOARD_RIGHT)
temperature_imu = temperature_data.get(sl.SENSOR_LOCATION.IMU)
temperature_barometer = temperature_data.get(sl.SENSOR_LOCATION.BAROMETER)

```

### 解決方法
- TemperatureData()を利用しているコードをzed-sdk のリポジトリの中から検索する。
- pycharm などを使って、フォルダの中を一括検索すれば、利用例が見つかる。
- その結果、上記のwebのドキュメントの記述と、利用例の違いに気づいた。
JavaScriptで複素数クラスを作る

# 概要
JavaScriptで数値計算するたに前に[JavaScriptが実行できるテストページ](https://qiita.com/I-Yasusi/items/8180ca49f12fb0464cde)を作った。
そのテストページには四則演算子をBabelを使ってJavaScriptでなんちゃって演算子オーバーロード化してある](https://qiita.com/I-Yasusi/items/ad0f174e8d5f14d598b9)。
その演算子オーバーロードを使ったクラスの例として作った複素数クラスについて解説する。
作ったものはGithubの[https://github.com/T-Yasusi/t-yasusi.github.io/blob/main/js/modules/calc/class/Complex.js](https://github.com/T-Yasusi/t-yasusi.github.io/blob/main/js/modules/calc/class/Complex.js)においてあります。

## TypeScriptによる擬似メソッド列挙
```ts
Complex{
   constructor(real :number, imag :number);
   
   re() : number // 実部の別名
   im() : number // 虚部の別名
   abs2() : number // 絶対値の二乗
   abs() : number // 絶対値
   arg() : number // 偏角
   minus() : Complex // -z
   reverse(): Complex // 逆数
   conj() : Complex // 複素共役

   add(a : number | Complex) : Complex // 足し算
   sub(a : number | Complex) : Complex // 引き算
   mul(a : number | Complex) : Complex // 掛け算
   div(a : number | Complex) : Complex // 割り算

   toString() : string 
   toTex() : string // MathJax用
   toEffNum(n : number) : string // 浮動点少数以下の定義付き 
}
```
四則演算は数字でも複素数でも受けられるように内部では実装する。


## 実際のソースコード
### コンストラクタとユーティリティメソッド

`toString` `toTex` `toEffNum`は割愛する。

```js:Complex.js
class Complex{
    constructor(a, b){
        this.real=a;
        this.imag=b;
    }

    set re(a){ this.real=a; }
    get re(){ return this.real; }
    set im(a){ this.imag=a; }
    get im(){ return this.imag; }

    abs2(){ return this.real*this.real+this.imag*this.imag; }
    abs(){ return Math.sqrt(this.real*this.real+this.imag*this.imag); }
    arg(){ return Math.atan2(this.imag, this.real); }
    minus(){ return new Complex(-this.real, -this.imag); }
    reverse(){
        const r2=this.abs2();
        return new Complex(this.real/r2, -this.imag/r2);
    }
    conj(){ return new Complex(this.real, -this.imag); }
```
絶対値は内部で`Math.sqrt`を呼んでいるので`abs2`のほうが高速(気になるほどではないが)

### 四則演算子
```js:Complex.js
    add(a){
        if( typeof(a)==='number' ) return new Complex(this.real+a, this.imag);
        if( (a instanceof Complex)===true ) return new Complex(this.real+a.real, this.imag+a.imag);

        throw new Error(`!!! Complex.add error !!! args=typeof(a)`+typeof(a));
    }
    sub(a){
        if( typeof(a)==='number' ) return new Complex(this.real-a, this.imag);
        if( (a instanceof Complex)===true ) return new Complex(this.real-a.real, this.imag-a.imag);

        throw new Error(`!!! Complex.sub error !!! args=typeof(a)`);
    }
    mul(a){
        if( typeof(a)==='number' ) return new Complex(a*this.real, a*this.imag);
        if( (a instanceof Complex)===true ) return new Complex(this.real*a.real-this.imag*a.imag, this.real*a.imag+this.imag*a.real);

        throw new Error(`!!! Complex.mul error !!! args=typeof(a)`);
    }
    div(a){
        if( typeof(a)==='number' ) return new Complex(this.real/a, this.imag/a);
        if( (a instanceof Complex)===true ) return this.mul(a.reverse());

        throw new Error(`!!! Complex.div error !!! args=typeof(a)`);
    }
```
先に解説したように引数は数値でも複素数クラスでも受けられるようにしておきそれ以外が来たときは例外を飛ばすようにしておく
【kintone】格納先フィールド名が不明だが、文字列でレコード検索したい時の解決策！

2024-04-15 使用しているプラグイン名を「どこどこ検索コンテナ」から「文字列検索コンテナ」に変更いたしました。

# はじめに
・レコードに登録されているはずのレコードを、なかなか見つけ出すことができない！
・絞り込みしたいんだけど、どのフィールドだったかな?


これを標準機能で解決する方法は、全体検索で検索するか、特定のアプリ内の一覧画面の絞り込みでとにかく該当しそうなフィールドで「含む」を設定する事を、思いつきます。
![標準機能の解決案](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744766/00642d15-5240-dd0f-be40-fad768cb3106.png)

でも、これを毎回、しかも、データが蓄積されるほど現場のユーザにとってはストレス。
そういう時は、プラグインをインストールするのも一つの手です。
そこで、プラグインを使って該当レコードを簡単に探す方法をやってみました。

今回は直感的なインターフェースでオススメの[Hoku Systemの、**文字列検索コンテナ プラグイン**](https://hoku-system.stores.jp/items/65d6b73aa2eab20200c6ab2f)を使用しました。


# 「文字列検索コンテナ」プラグインを使ってみた
**◆キーワードを入力して検索ボタンを押すだけ**
![Hoku System 文字列検索コンテナプラグイン 一覧画面 文字列検索コンテナ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744766/5597e21d-6d79-a4fb-49d0-5bd66879f6d3.png)
一覧画面に検索コンテナが自動で表示される。
アプリ内の**文字列入力系のフィールド**が自動で検出される。

**◆検索対象のフィールドを自動でピックアップし表示**
![フィールド選択コンテナイメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744766/7f0d9772-31dd-742c-3e58-cc427c09eab8.png)
絞り込みの対象のフィールドが表示されているが、検索に含めたくないフィールドはクリックで選択設定＆解除できる。

**◆設定も簡単だった**
![Hoku System 文字列検索コンテナプラグイン 設定画面 ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744766/a6cbd7d1-4e67-3c09-ef38-6d55dc0ff12f.png)

通常通り権限を持っている人が、プラグインの設定をするんだけど、この時の設定は、検索コンテナを使いたい一覧名のチェックして保存ボタンを押して完了！


# 「文字列検索コンテナ」プラグインについて
**プラグイン 公式HP**
[Hoku System 文字列検索コンテナ プラグイン](https://hoku-system.stores.jp/items/65d423e1e6c05c016b1cdea0)
[Hoku System 文字列検索コンテナ プラグイン【体験版・無料】](https://hoku-system.stores.jp/items/65d6b73aa2eab20200c6ab2f)

**機能**
・ kintone の一覧画面で、レコードを簡単に検索する事ができるプラグイン。
・一覧画面に、検索コンテナが表示されるので、キーワードを入力する事ができる。
・検索コンテナは、一覧毎に表示・非表示を切り替える事が出来る。
・一覧の条件を含めて検索が行われる。
**魅力**
・どのフィールドに入力されているものかを意識しなくても検索できる。
・kintone の標準機能にある「絞り込み」と同じしくみで動作する。（検索結果の表示もkintoneの標準の絞り込み時と同じになる）
・一覧名が「（すべて）」の時の文字列検索にはAPIが一回も使用されないので、大人数で使用してもAPI発行数を気にする必要がない。

# おわりに
標準機能でできない事・煩わしい事はプラグインの導入や、カスタマイズでどうにかなる事が多々あります。

https://hoku-system.stores.jp/

皆様の毎日作業がよりスムーズに行われるよう願っています。
Auto annotation DIY 

# 勝手にアノテーション

:::note info
ターゲット
- ちょっとAIやってみたい
- 有名どころの物体検出とちょっと違うものを使いたい
- 自分で作ったデータをアノテーションさせて学習したい
- 最後は検出できるようにしたい
:::
**(私自身も大したスキルがないので参考になるかですが）**


<details><summary>English Summary1</summary>

:::note info
Information
- Easy to develop original model base object detection
- It is acceptable for you to annotate accuracy
- the person who can improve annotation, labeling and other function by your self (please check src directory saved 2 samples for modify)
- Easy try to use object dection with original dataset
:::
</details>


## YOLOなど有名どころの学習済みモデルではプリセットIDあり
- ラベルIDが割り当てられている場合、学習しなくても物体検出の凄さを体感できる
- 熟成されているので検出力が高い

<details><summary>English Summary2</summary>

:::note info
Information
- Like a YOLO which is famous object detection model, have been already trained many object with labeling
:::

</details>

# 業務用ならアノテーションのプロに頼むかツールで頑張るか
## famous annotation tools

https://github.com/jsbroks/coco-annotator

https://labelstud.io/guide/labeling.html

https://github.com/labelmeai/labelme

- 基本的にどれも使い勝手、一長一短ありますので、お好みで


<details><summary>English Summary3</summary>

:::note info
Information
- In general, we can use annotation software for the data accuracy
- But It is very tough for us to do it. haha--

:::

</details>

# 軽くオートアノテーションツールを作ってみる
- 精度はそこそこ
- 余計なものはNMS(Non-Maximum Suppression,)の調整でなんとかする
- 似たようなデータを集めてみる

https://github.com/mi-kaneyon/auto_annotation

**クローンすると一通りのディレクトリとファイルが入ってきます**
- RAW ディレクトリにアノテーション用のデータを入れます
- データはなるべく属性がそろっている方がいいと思います（人物中など）

## オートアノテーションしてみると
![annotationsample.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155177/3f94eaef-dc97-76bd-d7aa-458e01077ab5.jpeg)

- モデルはFasterRCNN_ResNet50
- こちらのもっている情報が大いに関係している
- ラベル付与スクリプトも別途作ってはあります（改良求む）

<details><summary>English Summary3</summary>

## Auto annotation sample
![annotationsample.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155177/3f94eaef-dc97-76bd-d7aa-458e01077ab5.jpeg)

1. using model is FasterRCNN_ResNet50
1. If you want to detect specific person or object, you can use custom model code in the src sub directory.

</details>

# 最後に
- 一般人のPCと初級レベルのスキルでは思い描いているレベルのオートアノテーションはまだまだ。頑張ろうっと。
- 手軽に使えるので、適当にそれっぽい画像を集めて検出を楽しんでください。
大学・大学院時代の反省

# 概要
今年3月に大学院を卒業することになりました。
しかし私の大学生活は、主に研究をうまく進めることができず、かなり反省点の多いものとなりました。

そこで、新社会人としてのスタートを切る前に、これまでの失敗を振り返り、今後同じ失敗をしないように何をするべきかを考えてみました。
これから大学や大学院に進学する方々には、「こんな人間にはならない」という反面教師として見てもらえれば嬉しいです。

# 反省点

#### 長期的な目標・計画を立てるのが苦手
	
* エピソード：学会までの期間に、調査・実装にどれくらいの時間を使い、いつから実験を始め、いつから論文を書き始めるかの計画を立てて行動することができなかった。その結果、目標設定した学会に何度も投稿することができず、研究の方針を何度も変更せざるを得なくなった
* 分析
    * 物事の取捨選択ができず、実現可能性の高い計画を立てるのが苦手
    * 設定したタスクの難易度に対して、自分の能力が不足している
* 打ち手：SMARTの法則で目標を立て、具体的な短期目標へと落とし込む

#### 先延ばし癖がある

* エピソード：研究で「こうしたらよいのでは」という方向性がでてきた直後、急激にやる気がなくなって暫く趣味にのめり込んでしまった
* 分析：興味があることに対しての好奇心が勝ってしまい、面倒なタスクに手を出すのがおっくうになる。面倒なタスクに手を出すことによる新たな問題の発覚が怖い
    * ピアーズ・スティール氏いわく、先延ばしには3つのタイプがあり、その中でもトム型は「衝動にかられやすい、目先の欲求を満たすことを優先」してしまう。私はこのトム型の傾向が強そう
* 打ち手
    * 行動分析を行う → やめたい行動のきっかけや行為、結果を置き換えるトレーニング（環境を変える）
    * 10秒アクションの実践（少しでもいいからまずは手をつける！）
    * スモールゴールを設定（小さい成功体験を積んで自分に自信をつける）

#### 取り組んでいるタスクの問題点に気づけない、または気づいてもそれを無視してしまう
* エピソード
    * アドバイスを十分に理解していないにも関わらず、その場で「わかりました」と答えてしまい、後になってやはりわからなかったという事態が頻繁に発生した
    * 相手の意見で不明な部分に対しての疑問や自分なりの考えを主張できず、言われたらそのまま鵜呑みにしてしまう事が多かった
* 分析
    * 思い込みが激しい
    * 知識不足・経験不足なため、自分の判断に自信がない
* 打ち手
    * タスクに対する知識を身に着ける（自分の判断に自信を持てるようにする）
    * 不明点について15分は自分で解決を試み、15分経って解決しない場合他人に聞く（Googleの15分ルール）

#### 相手を説得する力が足りない
* エピソード：研究における自身の考え・実験内容を説明したが、何度も質問され、結局相手の疑問を払しょくできることができなかった
* 分析
    * 言語化能力・読解力不足で、認識の齟齬が発生する
    * 取り組んでいるタスクに対する理解が乏しい
* 打ち手
    * 相手の立場を理解する：相手が前提を全て知っているわけではないし、時間がたてば忘れる。「相手に理解してもらう」事を前提とした主張が必要
    * 言語化能力・読解力を身に着ける。ロジカルシンキングを身に着ける→自分の主張に自信を持てるようにする

#### 自身でアイディアを考え検討する力が不足している（ゼロイチ）

* エピソード：自分でアイデアを検討し、実験も行ったが、数ヶ月後にそれが不可能だと判断し、後戻りすることになってしまった。アドバイスをそのまま鵜呑みにし、後で自分の中で理解ができていなかったことが判明した
* 分析
    * 自分で考えることに対する苦手意識が強い（自信がない、失敗を恐れている）
    * 発想力が無い
* 打ち手
    * デザイン思考力をつける
    * 日ごろから5W1Hやマトリックスによって論理的にアイディアを考える
    * アイディアに対する理解を深めることを忘れない（why? so what?を繰り返す）

# まとめ

今回は自分の中で特に問題だと感じた反省点を上げましたが、自己分析をすることで自分が持つ課題を大量に見つけることができました。
そしてそれらの多くは社会人になっても大事になる要素が多いと考えられるので、少しでも改善できるように頑張っていこうと思います。


# 参考サイト
https://www.kaonavi.jp/dictionary/smart-criteria/

http://books.cccmh.co.jp/list/detail/847/
PowerShellで環境変数Pathを操作する

# What's？

タイトルどおりですが、とてもとてもよく忘れるのでメモということで。

# 環境

```powershell
PS C:\Users\xxxxx> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      19041  4046


```

# PowerShellで環境変数Pathにアクセスする

まず、PowerShellの環境変数に関するドキュメントはこちら。

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-5.1

PowerShellで環境変数を扱うには、3つの方法が用意されているようです。

- 変数の構文
  - `$Env:<variable-name>`
- 環境プロバイダーと項目コマンドレット
  - `Copy-Item`、`Set-Item`、`Get-Item`、`Remove-Item`
- NET System.Environment クラス
  - `[Environment]::SetEnvironmentVariable`、`[Environment]::GetEnvironmentVariable`

今回は変数の構文（`$Env:<variable-name>`）を使っていこうとおもいます。

## 環境変数Pathの内容を表示する

```powershell
PS C:\Users\xxxxx> $Env:Path
＜環境変数Pathの内容＞
```

## 環境変数Pathにパスを追加する

末尾に追加。

```powershell
PS C:\Users\xxxxx> $Env:Path+=";＜追加したいパス＞"
```

先頭に追加。

```powershell
PS C:\Users\xxxxx> $Env:Path="＜追加したいパス＞;"+$Env:Path
```

内容自体を変えたい場合は、まるっと差し替えたらいいかなと…。

```powershell
PS C:\Users\xxxxx> $Env:Path="＜パスごとに;で区切った内容＞"
```

## 他の方法を使ってハマったこと

こちらのドキュメントに書かれているのですが、Windowsの環境変数には3つのスコープがあります。

- マシン (またはシステム) のスコープ
- ユーザー スコープ
- プロセスのスコープ

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-5.1

`System.Environment`クラス以外の方法で環境変数Pathを見るとマシンスコープとユーザースコープが足されたものが表示されるのですが、`System.Environment`クラスで見るとそれぞれ独立して表示されます。

```powershell
# マシンスコープ
PS C:\Users\xxxxx> [Environment]::GetEnvironmentVariable("Path","Machine")

# ユーザースコープ
PS C:\Users\xxxxx> [Environment]::GetEnvironmentVariable("Path","User")
```

なので、こちらの値を元にPathを組み立てる場合は片方のスコープしか見ていないとPathの内容が欠落する…みたいなことになります。

このあたりを残しておきたかったのが、今回の内容を書いたきっかけですね。
【Swift】子クラスの実装ミスを根絶するrequired init

# 目次
[1.required initとは？](#1-requiredinitとは？)
[2.実例](#2-実例)
[3.おわりに](#3-おわりに)

# 1. required initとは？
`required init`とは「イニシャライザにのみ使用できる」、「`required init`をもつクラスを継承する(サブ)クラスでは必ず実装しなければならない」と言った性質を持つ修飾子付きのイニシャライザです。
これを実装することにより、複数人で開発する際のイニシャライザの実装忘れの防止や、設計の共通認識を持つことができます。

#2. 実例
早速コードを見てみます。
~~~swift:required.swift
class Human() {
    var name: String
    var age: Int

    required init(name: String, age: Int) {
        self.name = name
        self.age = age
        print("called Human class initializer")
    }
}

class Suzuki: Human {
    required init(name: String, age: Int) {
        //　ここで必ず親クラスのinitの処理をする！
        super.init(name: name, age: Int)
    }
}
~~~
親クラスに`required init`がいることによって、必ず親クラスのinitの処理をしなければなりません。
ここでは、***Humanクラスを継承したいのであれば、必ず名前と年齢を定義(初期化)しなければいけません。***
これにより、子クラスでは必ず、親クラスの`name`と`age`の初期化をしなければならないので名前の年齢どちらかを忘れた子クラスが誕生する心配はないですね！

#3. おわりに
いかがでしたでしょうか？`required init`によって、子クラスで親クラスのinitを強制的に実装させることで、子クラスの必要要素の実装・定義忘れも撲滅されます！
ヒューマンエラー根絶に一役買うってわけですね！
BigQueryでUNNESTをLEFT JOINすると空のARRAYでも行が残る

BigQueryで こういう Nest したレコードがあったとします。

```sql
WITH a as (
SELECT * 
FROM UNNEST([
  STRUCT(1 as id, [1, 2] as data),
  STRUCT(2 as id, [] as data),
  STRUCT(3 as id, NULL as data)
  ])
)

SELECT * FROM a
```

| 行 | id | data |
| --- | --- | --- |
| 1 | 1 | 1 |
|  |  | 2 |
| 2 | 2 | _(0 rows)_ |
| 3 | 3 | _(0 rows)_ |


---------

普通に?(よくサンプルにあるように) 
`FROM a, UNNEST(data) as data` という形で UNNESTすると、
レコード数が0 だったりNULLだったりすると、行そのものが消えます。

```sql
WITH a as (
SELECT * 
FROM UNNEST([
  STRUCT(1 as id, [1, 2] as data),
  STRUCT(2 as id, [] as data),
  STRUCT(3 as id, NULL as data)
  ])
)

SELECT
  id,
  data
FROM a, UNNEST(data) as data
```

| 行 | id | data |
| --- | --- | --- |
| 1 | 1 | 1 |
| 2 | 1 | 2 |

これはこれで嬉しいときもありますが、残したい時もあります。


-------------

そういうときは、`LEFT JOIN UNNEST(data) as data` とすると残るのです。

```sql
WITH a as (
SELECT * 
FROM UNNEST([
  STRUCT(1 as id, [1, 2] as data),
  STRUCT(2 as id, [] as data),
  STRUCT(3 as id, NULL as data)
  ])
)

SELECT
  id,
  data
FROM a
LEFT JOIN UNNEST(data) as data
```

| 行 | id | data |
| --- | --- | --- |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | null |
| 4 | 3 | null |


知らなかった...
【Kotlin*Spring】登録画面_複数フォームのバインディング方法



# 本記事の内容

以下図のような、フォームクラスを複数使用した場合のフォームクラスの作成方法とHTMLとのバインディングについて下記に記す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1202056/ceb7c24e-b8c6-7563-1f0a-d56f05575641.png)

## ■Controllerクラス
```kotlin:AccountController.kt
@Controller
class AccountController {

    @GetMapping("/account/form/") 
    fun init(model: Model) {
        // Formクラスのインスタンスを渡す
        // 第一引数にModelに追加する際の属性名を指定できるが省略可能。
        // 省略した場合、accountCreateForm（クラス名の先頭を小文字にした値）で追加される。
        model.addAttribute(new AccoutnCreateForm()) 
        // View返却
        return "account/userCreateForm"
    }
}
```


## ■Formクラス
```kotlin:AccountCreateForm .kt
data class AccountCreateForm implements Serializable (
    private const val serialVerisionUID = 1L
    // アカウント情報
    val accountForm: AccountForm,
    // カード情報
    val card: CardForm,
)
```

```kotlin:AccountForm.kt
data class AccountForm implements Serializable (
    private const val serialVerisionUID = 1L
    // 名前
    val userName: String,
    // E-mail
    val email: String,
)
```

```kotlin:CardForm.kt
data class AccountCreateForm implements Serializable (
    private const val serialVerisionUID = 1L
    // 番号
    val no: String,
    // 期限
    val validMonth: String,
)
```

## ■HTML（バインディングの記載方法）
```html:userCreateForm.html（該当箇所のイメージのみ）
    <form th:action="@{/user/confirm/}" th:object="${accountCreateForm}" th:method="post">
    
        <label>名前</label>
        <input type="text" th:field="*{account.userName}">

        <label>E-mail</label>
        <input type="text" th:field="*{account.email}">

        <label>番号</label>
        <input type="text" th:field="*{card.no}">

        <label>期限</label>
        <input type="text" th:field="*{card.validMonth}">

    </form>
```