OmniAICreator/Qiita-1.07M huggingface dataset:
36.LANのメディアアクセス制御

## LANの代表的三つの接続状態
LANは、複数のコンピューターや周辺機器をLANケーブルなどの伝送媒体を使って接続することで構成される。これらPCや機器を　ノード　という。

複数のノードでLANを構成する場合、接続の仕方にはいくつかの種類がある。ノードをどのように接続するのか　接続形態のことを
ネットワークトポロジー という。
スター型トポロジ　　　バス型トポロジ　　　リング型トポロジ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293109/fbe5e01f-f5ce-beaa-41b8-8edd2290ceba.png)
### データ交通整理を行うメディアアクセス制御方式
 どの接続形態においても、LANに接続されたノードはお互いにデータのやり取りが可能であり、場合によって複数のノードが同時に送信する場合が　衝突（コリジョン）が起こる。
　データの衝突が起こると送信出来なく、送信ルールを決めて制御することが必要。この制御は、
メディアアクセス制御（MAC）/媒体アクセス制御という。

代表的な方式はCSMA/CD方式、トークンパッシング方式、無線LANで用いられるCSMA/CA方式がある。

### 伝送路が空いていれば送信するCSMA/CD（Carrier Sense  Multiple Access with Collision Detection　　搬送波感知多重アクセス/衝突検出）
ノードが送信したい時、まず伝送路に他のノードがデータを送信しているかを確認。（キャリア検知）
この時、伝送路が空いていれば、データを送信開始。（早い者勝ち）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293109/a7d9352b-25ee-2a14-3016-d0f2fc5b1b9b.png)

IF　コリジョンが発生した場合、各ノードはそれを検知してデータを中止する。そこで、ランダムな時間を待った後にデータを再送を試す。
各ノードの　再送時間が　　乱数で計算する　　バラバラの時間を待つことでまたの衝突を防ぐ。

### 送信権を獲得して送信するトークンバッシング
送信権を確保するためのフリートークンを伝送路に巡回させ、フリートークンを獲得したノードだけがデータを送信することで、データの衝突を回避する方式でトークンバッシング方式という。

### 無線LANで使用する　CSMA/CA
伝送路が一定の時間、継続して空いていればデータを送信する
データを送信した後、データが正しく通信相手に届けられたかの
受信OK　のメッセージを（ACKフレーム）が返ってくるかどうかで判断する。
受信OK　のメッセージ
返ってきた場合　　OK
返ってこない場合　衝突発生と判断し、再送を行う。

### まとめ
集線装置が全てのノードを放射線状に接続する形態は、スター型という。
基幹ケーブルに、全てのノードを接続する形態をバス型という。
リング状に繋いだケーブルに、リング型。
CSMA/CD方式のLANに接続された各ノードは、伝送路が空いていれば送信を行う。コリジョンを検出したら、ランダムな時間を経過後に再度送信を行う。
送信権を確保するためのフリートークンを巡回させ、これを獲得したノードだけが送信を行うメディアアクセス制御をトークンバッシングという。

トークンバッシング方式をバス型のLANで使用する場合はトークンパス、リング型の場合はトークンリング。

CSMA/CA方式は、無線LANに使用されるメディアアクセス制御。
2023/8/8主にITとかセキュリティの記事

Microsoftが警告する「Word」を狙ったゼロデイ攻撃　回避するにはここを確認(8/4)
https://kn.itmedia.co.jp/kn/articles/2308/04/news088.html

週刊仮想通貨ニュース｜Binance Japanのサービス開始に注目集まる、ライトコインに半減期到来など(8/6)
https://coinpost.jp/?p=475966

ロシア、匿名でのオンラインサービス利用を不可能にする連邦法改正(8/6)
https://www.zaikei.co.jp/article/20230806/732661.html

JPモルガンCEOなどから反発の声…日銀YCC修正でもっとも影響を受けるのは米国「金融規制当局は金融規制強化を図る」(8/6)
https://mag.minkabu.jp/mag-sogo/20143/

「電池パスポート」欧州義務化、デンソーはQRコードでトレーサビリティー構築へ(8/7)
https://xtech.nikkei.com/atcl/nxt/column/18/01537/00902/

業務システムをSaaSに全面移行したトリドール、ゼロトラストもシンプル(8/7)
https://xtech.nikkei.com/atcl/nxt/column/18/00001/08284/

システム構築の胸突き八丁、ユーザーが「丸投げ」できない難関とは(8/7)
https://xtech.nikkei.com/atcl/nxt/column/18/01111/080300044/

MSが国内拠点で生成AIを提供、政府採用に不可欠な「機密情報」の取り扱いで先手(8/7)
https://xtech.nikkei.com/atcl/nxt/column/18/02423/080200047/

銀行・保険横断で客を知る、データ連係基盤の構築に注力するソニーFGの狙い(8/7)
https://xtech.nikkei.com/atcl/nxt/column/18/01159/072500046/

「SEで年収600万円弱のぼく、転職先選びの基準はいくら？」(8/7)
https://xtech.nikkei.com/atcl/nxt/column/18/02518/00018/
NVIDIA GeForce ドライバ 536.40 or 536.67のブラックアウトの不具合解決

# やったことの概要
まあほとんどタイトル通りなのですが一応解説を。
NVIDIA GeForceドライバのバージョン536.40以降には厄介なバグが存在しているようです。その内容とは、画面が突然ブラックアウトしてしまうこと。
Twitterなどの情報を見ると、ゲーム中に突然ブラックアウトしてゲームが続行不可能に…というパターンが多いみたいです。私の場合はパソコンがスリープで画面が消灯してそのまま帰らぬ人、ならぬ帰らぬグラボに…というパターンでした。

で、このバグの怖いところは**ドライバーのロールバックを行っても復旧しないことがある**ということです。ロールバック（＝過去バージョンへのダウングレード）で解決する場合もあるようですが、私の場合はそれだけでは解決しませんでした。
じゃあどうやって解決したの？ということでこれから実際の作業手順を解説していきます。

# 復旧作業の手順
## Step1: HDMIへの繋ぎ変え
まずは画面がつかないことには作業もなにもないので、画面をつけることから始めよう…と考えたのですが、ここで早速私は絶望しました。なぜなら**パソコンの電源を切ってコンセントを差し直しても復旧しなかったからです**（インターネット上の情報によると、通常はこの手順で回復するらしいです。もっとも、根本的な解決ではなく、次に再度ブラックアウトするまでの一時的なものでしょうが。なぜ私の場合だけ解決しなかったかは後ほどなんとなく見えてきます）。
が、奇跡的にHDMI接続ならば問題なく画面が映ることに気が付いたので、とりあえずしばらくの間はHDMIで作業を行っていきます。
…ですが、私はモニターのHDMI端子はPS5に使い、PCはDisplayPortで接続したいので、断じてこれで解決ではありません。
## Step2: ドライバのロールバック
画面が一時的に復旧したところで、まず試すのはこれでしょう。私は536.40の一つ前、536.23をNVIDIAの公式サイトからダウンロードし**クリーンインストールしましたが、DisplayPortは回復しませんでした**。
これだけで治る場合もあるようですが…残念。引き続き復旧方法を探っていきます。
## Step3: nvlddmkm.sysファイルの削除
「確かにクリーンインストールしたのに元の状況に戻らないの、なぁぜなぁぜ？」と思い調べてみたところ、どうやら**nvlddmkm.sysというファイルが残って悪さをし続けることがあるそうです**。Cドライブ内を検索してみると、確かに「nvlddmkm.sys」というファイルが**2つも**ありました。しかもプロパティを確認すると、**1つは作成日例のドライバのリリース日と同日**、どうやらビンゴのようです。
早速、このファイルを手動で削除しました。
<details><summary>手動でファイルを消すのが怖い方へ</summary>

~~Twitter~~Xにて「NVIDIAドライバ532.03まで戻せば治る」との情報を発見したのでこれを試しにクリーンインストールしてみました。すると、536.23のインストールでは消えなかったはずのnvlddmkm.sysファイルが見事に自動で消えておりました。おそらく手動でファイルを消すよりこちらの方が安全でしょう。
バージョンが大きく変わる場合は自動でキャッシュ削除のような働きをしてくれるということでしょうか？~~毎回ちゃんとやれよさぼるなよ~~

</details>

## Step4: "モニターの"コンセントを抜く
確かに余計なファイルを消したはずなのですが、それでも画面は復旧しませんでした。
…とここで、DisplayPortは接続の際に、私の思っている以上に様々な情報をやりとりし記憶しているということを知りました（といっても、私もまだまだ詳細は理解できておりません。気になる方は「displayport ホットプラグ信号」あたりでググって下さい）。
「接続情報を記憶し続ける」ということにビビっときた私は、その情報のリセットを試み、モニターのコンセントを差し直しました。
すると、見事にDisplayPortが復活しました。やったぜ！

DPってなんかUSB-PDなみに複雑なんすね。前にも突然画面が死んでモニターのコンセント差し直したらなぜか治ったことあったけど、あれもホットプラグ信号関連が原因だったのかなぁ…

# まとめ
長くなってしまったので手順をまとめておきます。
①HDMIへの繋ぎ変え
（PC、モニター両方のコンセントを差し直せば一時的には復旧する？）
②NVIDIA GeForceドライバ532.03のクリーンインストール
（ここで、余計なnvlddmkm.sysファイルが残っていないか確認しておきましょう）
③モニターのコンセントを差し直す
私の場合はこれで治りました。ここまでやればまぁ、たいていの環境では治るんじゃないでしょうか？
以上です。

# 23年10月追記
不具合発覚から二ヶ月ほどが経過しました。現時点でドライバは537.42までリリースされましたが、いずれにも不具合解消の文字はなく…
（それどころか、未確認情報ですが壊れたドライバを無理やり使い続けることでGPUが本当に破壊されるなんて話も…）

私もちょいちょいXなどで情報収集を継続していましたが、**やはり最近のドライバの中で最も安定しているのは532.03の模様**。
トラブルにあってから後悔しても遅いので、先手を打って532.03に乗り換えておくのが賢明かもしれません。なお、Windowsアップデートによって勝手に更新されることもあるためくれぐれも気を付けましょう。~~Microsoftなんとかしろや~~

また、ドライバの完全削除はクリーンインストールや手動削除をするのではなくDDUというツールを使うのが主流なようです。NVIDIAが信用できない方は活用してみましょう。

# 23年10月、ついに解決（？）
バージョン537.58でひっそりと修正されたようです。
実際、私も21日時点で最新の545.84の新機能であるVSR1.5（リニューアルされた動画の超解像機能）を使いたいがためにアップデートしましたが、目立ったトラブルには見舞われていません。
新しいドライバを要求する最新のゲーム等をやりたい方は537.58以降のドライバを試してみると良いかもしれません。

# for foreigners
If you worry about bug of NVIDIA GeForce driver 536.40 or later
1. use HDMI
2. download and clean-install GeForce driver 532.03
3. unplug your monitor

Try it!

# 環境
OS:Windows11 Pro
GPU:GeForce RTX 3090
ドライバ:GeForce GameReadyドライバ 536.67→532.03
【Android】WebViewを使ってみた③

## はじめに
WebViewの技術を使って、AndroidのアプリでWebページを表示してみようと思います。
また、webページからAndroidのプログラムのメソッドを呼び出してみたり、Android側のページに戻ったりもしてみようと思います。
プログラムソースがちょっと多めなので、複数回に分けて投稿しようと思います。

第三回目はwebページ側の実装です。

#### 計算画面（webページ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689436/de214956-c349-307f-951e-a8ac0058358d.png)

計算画面のhtmlになります。
Cookieの処理は気にしないでください。
モバイルとPCで開いた際にAndroid側のメソッドを呼び出すボタンの表示制御に使用しています。
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
	<title>sample</title>
	<meta charset="UTF-8">
	<script src="./test.js"></script>
	<style>
		.name-1 {
		outline:solid 4px red;
		}
	</style>
</head>
<body>
	<div>
		<input type="text" id="param_a" size="1" class="name-1">&emsp;+&emsp; 
		<input type="text" id="param_b" size="1" class="name-1">&emsp;=&emsp; 
		<input type="text" id="sumResult" size="1" class="name-1"></p>
	</div>
	<div>
		<input type="button" id="sum" value="計算" onclick="sum()">
	</div>
	<div>
		<input type="button" id="showMain" value="メイン画面に戻る" onclick="showMain()">
	</div>
	<script>
		if(getCookie() == 2){
    	console.log('getcookie');
    	document.getElementById("showMain").style.display ="none";
    	document.getElementById("sum").style.display ="none";
		}
	</script>
</body>
</html>

```

Android.sumとかAndroid.showMainがAndroid側のメソッドを呼び出している処理になります。
```javascript:test.js
let url = new URL(window.location.href);
// URLSearchParamsオブジェクトを取得
let params = url.searchParams;

// クエリパラメータを取得する。
let type = params.get('type');
if(type == null){
    type = 2; // typeがnullの場合は、PC版を表示する。
}

if (navigator.cookieEnabled)  // cookieが使えるか確認
{
    document.cookie = "type=" + type;
    alert(document.cookie);
}

// メイン画面に移動（Android）
function showMain(){
    Android.showMain();
}

// 足し算（Android）
function sum(){
    let sumResult = Android.sum(Number(document.getElementById('param_a').value),Number(document.getElementById('param_b').value));
    console.log(document.getElementById('param_a').value);
    console.log(document.getElementById('param_b').value);
    console.log(sumResult);
    document.getElementById('sumResult').value = sumResult;
}

// Cookieを取得する。
function getCookieArray(){
    var arr = new Array();
    if(document.cookie != ''){
        var tmp = document.cookie.split('; ');
        for(var i=0;i<tmp.length;i++){
            var data = tmp[i].split('=');
            arr[data[0]] = decodeURIComponent(data[1]);
        }
    }
    return arr;
}

function getCookie(){
    var arr = getCookieArray();
    var value = arr['type'];

    return value;
}
```
以上

三回に分けて説明していきましたが、いかがでしょうか。
WebViewだとAndroidの修正が少ないので楽ですね。
Andoroid側のスキルが無くてもwebページの知識があればスマホアプリを作ることができます。
もしわからない部分がありましたら、質問OKです。

## 関連リンク

https://qiita.com/mojapico/items/be37fcba7545756625e7

https://qiita.com/mojapico/items/a6ef2e741b80c88787c0

https://qiita.com/mojapico/items/09cd43293e503e3b49d2
LightGBM (GPU) で Error: No OpenCL Device Found

# 環境

- `nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu20.04`

# 問題

LightGBM において，`devide='gpu'` と指定すると，`Error: No OpenCL Device Found` というエラーが出て，実行できない場合がある[^1][^2][^3]．
[PyPL](https://pypi.org/project/lightgbm/) に記載されている通りにインストールしたがうまくいかず，公式の [LightGBM GPU Tutorial](https://lightgbm.readthedocs.io/en/latest/GPU-Tutorial.html) に記載されている方法では，必要になるパッケージが明らかでない．

# 解決策

公式の [Dockerfile for LightGBM GPU Version with Python](https://github.com/microsoft/LightGBM/blob/master/docker/gpu/dockerfile.gpu) を元に，本環境で実行できる Dockerfile を作成した．

### 必要なモジュールのインストール

公式の Dockerfile で指定されているパッケージに加えて，`ocl-icd-opencl-dev` が必要になった．

```dockerfile
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
curl \
bzip2 \
ca-certificates \
libglib2.0-0 \
libxext6 \
libsm6 \
libxrender1 \
git \
vim \
mercurial \
subversion \
cmake \
libboost-dev \
libboost-system-dev \
libboost-filesystem-dev \
gcc \
g++ \
ocl-icd-opencl-dev
```

### LightGBM のインストール

デフォルトでは，`/usr/local/cuda/lib64/libOpenCL.so` のパスで指定されていたが，`libOpenCL.so` が存在せず，エラーを吐いていたため，`/usr/local/cuda/lib64/libOpenCL.so.1` に変更した．
また，環境に応じて CUDA のバージョンを書き換える必要がある．

```dockerfile
RUN mkdir -p /etc/OpenCL/vendors && \
    echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd
RUN cd /usr/local/src && mkdir lightgbm && cd lightgbm && \
    git clone --recursive --branch stable --depth 1 https://github.com/microsoft/LightGBM && \
    cd LightGBM && mkdir build && cd build && \
    cmake -DUSE_GPU=1 -DOpenCL_LIBRARY=/usr/local/cuda/lib64/libOpenCL.so.1 -DOpenCL_INCLUDE_DIR=/usr/local/cuda/include/ .. && \
    make OPENCL_HEADERS=/usr/local/cuda-11.7/targets/x86_64-linux/include LIBOPENCL=/usr/local/cuda-11.7/targets/x86_64-linux/lib
ENV PATH /usr/local/src/lightgbm/LightGBM:${PATH}
RUN /bin/bash -c "cd /usr/local/src/lightgbm/LightGBM && sh ./build-python.sh install --precompile"
```

# 参考資料

- [docker-cuda-asdf-py3-lightgbm-pytorch-pyg](https://github.com/syoka4156/docker-cuda-asdf-py3-lightgbm-pytorch-pyg/tree/main) において実行が確認できた．

[^1]: [Error: No OpenCL Device Found](https://github.com/microsoft/LightGBM/issues/586)
[^2]: [[gpu] [python] LightGBMError: No OpenCL device found](https://github.com/microsoft/LightGBM/issues/4497)
[^3]: [can not use lightgbm gpu in colab : LightGBMError: No OpenCL device found](https://stackoverflow.com/questions/75981883/can-not-use-lightgbm-gpu-in-colab-lightgbmerror-no-opencl-device-found)
GPIOをdigitalRead/digitalWriteを使わずに入出力

# GPIOの入出力
通常ArduinoでGPIOの読み込みや書き込みを行う場合、digitalReadやdigitalWriteを使います。
しかしdigitalReadやdigitalWriteは関数呼び出しとなるため、便利な反面遅いというデメリットがあります。
そこで処理を高速化するために、GPIOのレジスタから直接操作を行いました。
ピンの入出力やPullUpの設定といった初期化もレジスタで行うことはできますが、
入出力と比較してレジスタを直接操作するメリットが余りないので、本稿で扱いません。
# GPIOの入力（digitalReadの代用）
PORTx.IN のnビット目の状態が、PIN_PXnの状態となります。
例えばPIN_PB3のピンの状態を取得したい場合、PORTB.INの3bit目を確認します。
そこで下記のようにすればピンの状態を取得することが出来ます。
_BV(n)は組み込みのマクロで、n bit目だけがセット（1になる）された値を返します。
```cpp:main.cpp
uint8_t val;
val = PORTB.IN & _BV(3);
```
# GPIOの出力（digitalWriteの代用）
出力させる場合も入力の時とほとんど同じレジスタを扱います。
PORTx.IN のnビット目の状態が、PIN_PXnの状態となります。
例えばPIN_PB3のピンにHIGHを出力したい場合、PORTB.INの3bit目に1をセットします。
そこで下記のようにすればピンの状態を取得することが出来ます。
outputは出力させたいデータとします。
```cpp:digitalWriteの代用その１
uint8_t outval = PORTB.OUT;
outval = outval & ~_BV(n);
outval = outval | ((output & 0x01) << n);
PORTB.OUT = outval;
```
少しコードの説明をします。
入力より少しややこしい理由として、出力するものがHIGHかLOWかによって処理が変わるためです。
HIGHの場合、n bit目に1をセットしたいのでPORTB.OUTと_BV(n)のORで設定します。
LOWの場合、n bit目に0をセットしたいのでPORTB.OUTと_BV(n)を反転させた~_BV(n)をANDで設定します。
ただし遅くならないように、条件分岐を使わず単純な計算だけで設定しました。
最初は該当bitにANDを使い0をセットしました。次はoutputの値をORを使って設定しました。
## 1行で出力
下記のように1行で記述することも可能です。私はこれを関数マクロにして利用しています。
（val は出力させたい値、bitはピンのビット位置）
```cpp:1行バージョン
PORTB.OUT = (PORTB.OUT & ~_BV(bit)) | (((uint8_t) ((bool) val)) << bit);
```
## 複数を同時出力
また同じポート限定となりますが、同時に複数のピンへの出力も可能です。
（val1をPIN_PB3へ、val2をPIN_PB1へ出力させたい場合）
```cpp:同時出力
PORTA.OUT = (PORTA.OUT & ~(_BV(3) | _BV(1))) | ((val1 & 0x01) << 3) | ((val1 & 0x01) << 1);
```
# 最後に
次はCCLあたりを投稿する予定です。
気が向いたら、本稿の延長として割り込み設定なども調べて書いていきたいです。
【Rails】DeviseTokenAuthのNoMethodError (undefined method `downcase' for nil:NilClass)対処法


## 状況
Devise Token Authの設定に以下の項目を追加したところログイン時に`NoMethodError (undefined method `downcase' for nil:NilClass)`となりました。

```rb:devise_token_auth.rb
DeviseTokenAuth.setup do |config|

  config.headers_names = { "access-token": "access-token",
                           client: "client",
                           expiry: "expiry",
                           uid: "uid",
                           "token-type": "token-type" }

end
```

## 解消法

以下のように`authorization: "authorization"`を追記することで解消しました。

```rb:devise_token_auth.rb
DeviseTokenAuth.setup do |config|

  config.headers_names = { "access-token": "access-token",
                           client: "client",
                           expiry: "expires",
                           uid: "uid",
                           "token-type": "token-type",
                           authorization: "authorization" }

end
```

## 参考

https://github.com/lynndylanhurley/devise_token_auth/issues/1540
TwinMakerを使った3Dデジタルツインを爆速で作れるようにしました

# この記事を1行で

AWSのTwinMakerをReact Webアプリにするライブラリ（iot-app-kit）の環境構築が大変だったので、爆速で環境構築できるようにテンプレートを公開しました

## これまでは何が大変だった？

- 依存ライブラリが多く、バージョンが複雑で、なかなか整合性が取れない
- TwinMakerの起動の前に、AWSの認証情報の設定とTwinMakerのシーン構築が必要になる

## どう解決した？

- create-react-appみたいに、コマンド一発でテンプレートを導入できるようにしました
- 認証情報の設定なし、クラウド側の操作なしで、IoT App Kitが動くようにしました

# 爆速で構築する

Node.jsがインストールされていることが前提です。

```bash
npx @iak-extra/cli create ${作りたいアプリの名前}
```

このコマンドを1行叩くだけで完了です。  
AWSのアカウントも不要、バージョンの整合性管理も不要、動く状態になります。

### 動かす

npm startを実行してしばらく待つと、TwinMakerの画面が立ち上がって、3Dの部屋の中で初音ミクが踊り始めます。

### まとめ

この手順で作った3DアプリはAWSの利用料金が一切かかりませんので、気兼ねなくTwinMakerの機能や操作感を試すことができます。buildコマンドを実行すれば、そのまま静的なWebアプリとしてデプロイすることもできます。

もしクラウド上のIoTデータと同期させたいと思ったら、データソースを書き変えてください。リアルタイムのデータが3D空間に反映されるようになります。

# 今回公開したライブラリ

TwinMakerのタグを、ボタンやMMDに置き換えることができるライブラリも入れています。

https://github.com/ShotaOki/iot-app-kit-extra

今回のCLIはライブラリの一部として公開しました。
ライブラリそのものはNPMでダウンロードできるようにしています。

TwinMakerはなにしろ便利なツールですので、構築を簡単にすることで、利用する方が増えればいいなと思っています。
アーリーリターンについて

# はじめに
アーリーリターンはコーディングのテクニックです。
簡単に書き方等をご紹介したいと思います。

# 書き方
そもそもアーリーリターンって何か、というと「ネストが深くなった条件文を分解する」書き方です。
ネストが深くなると、可読性が低くなりどういう処理を行っているのか分かりにくくなります。
そこで、アーリーリターンという記述方法を用いることで可読性を上げます。
具体的には、`return`を用いてifなどの条件分岐のネストを減らして記述します。
## 記述例
### 適応前
Pythonでのサンプルを記述します。
以下のコードでは、ネストが深く、条件分岐が複雑になり返却値がどの階層なのかぱっと見わかりません。
```python
from datetime import date
import datetime

def isActiveUser(user: dict) -> bool:
    if user != None:
        if user["del"] != True:
            today = date.today()
            if user["start_date"] <= today:
                if user["end_date"] == None or today <= user["end_date"]:
                    return True
                else:
                    return False
            else:            
                return False
        else:
            return False
    else:
        return False
def main():
    deadline_period = datetime.timedelta(days=10)
    user = {
        'id':'id_1001',
        'name':'mike',
        'address':'japan',
        'tel_no':'000-0000-0000',
        'start_date': date.today(),
        'end_date':date.today() + deadline_period,
        'del': False
    }
    result = isActiveUser(user)
    if result == False:
        print("Activeなuserではありません")
    else:
        print("Activeなuserです。")
```

### 適応後
上記のサンプルをアーリーリターンで記述します。
アーリーリターン、つまりエラーパターンを早期に返却して、
最後に正常パターンの処理を記述する方法です。
メリットは、
- ネストを浅くすることができる
- エラーパターンを最初にチェックを入れているため、可読性が上がる

詳細は以下のサンプルを参照してください。
```python
from datetime import date
import datetime

def isActiveUser(user: dict) -> bool:
    if user == None:
        return False
    if user["del"] == False:
        return False
    today = date.today()
    if user["start_date"] > today:
        return False
    if user["end_date"] != None and user["end_date"] <= today:
        return False
    return True

def main():
    deadline_period = datetime.timedelta(days=10)
    user = {
        'id':'id_1001',
        'name':'mike',
        'address':'japan',
        'tel_no':'000-0000-0000',
        'start_date': date.today(),
        'end_date':date.today() + deadline_period,
        'del': False
    }
    result = isActiveUser(user)
    if result == False:
        print("Activeなuserではありません")
    print("Activeなuserです。")
```

# 具体的な書き方のコツ
- エラーパターンを最初にチェックする
    - 正常パターンで記述している人は、それを反転させる
- 正常パターンは処理の最後に記述する。
- if文が多くなっても条件を分けて記述した方が分かりやすい
- elseは記述しない方法を考えてみる

# おわりに
以上、アーリーリターンについてのまとめでした。
参考になればと思います。
ここまで読んでいただきありがとうございました。

# 参考文献
[早期リターンを書こう](https://zenn.dev/media_engine/articles/early_return "早期リターンを書こう")
ライブラリの選定基準

## 参考サイト
https://applis.io/posts/criteria-for-selecting-libraries

https://zenn.dev/goldsaya/articles/da6c8e9f9cee29

https://zenn.dev/koniman/articles/906ba76776f616dcd977

https://synamon.hatenablog.com/entry/technology-selection-for-library



## 上記サイトでよく見られるし、個人的にも重要だなと思った観点
今回は、新規で導入するというわけではなく、既に使われているものの代替となるライブラリを探すといった状況、みたいな感じのライブラリ選定基準を自分なりに抽出する。

### 機能面 
- 入れ替え元のライブラリと同じようなことができるかどうかを確認
- 長く使えるかどうか？
・リリースされての経過時間を確認
・ライブラリ更新頻度の確認
・開発元の確認

### 導入 
- 調べたらたくさん使用例でてくるか？たくさん使われているか？
- 導入に時間やお金がどれぐらいかかるか？
- オフィシャルかどうか？

### 保守性
- ライブラリのReadmeが拡充されている
- ランニングコスト
- 問い合わせ窓口の存在

## まとめ
まだ更新中
[baserCMS]複数レコードを一括で追加・更新するサンプル


1画面内で、複数レコードを一括で追加・更新する場面があり、あまりない状況だったので、あれこれ考えてみたのですが、CakePHPには「saveMany」という一括更新用のメソッドがあったので見てみることにしました。

見てみた結果はサンプルプラグインとして残してます。
データ構造としては、baserCMSのブログカテゴリ1つに対して、複数のレコードが紐づく場面がサンプルです。
ついでに baserCMSのHelperEventである bcListTableShowHead, bcListTableShowRow も使ってます。



## 想定している対象者
- baserCMSでウェブサイトを制作をしている方
- PHPer


## サンプル

- https://github.com/fuchigam1/SampleMultiRecord

![sc_blog_category_index.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26110/6909595c-63a0-b76c-8036-b7e3a6517680.png "sc_blog_category_index.png")

![sc_sample_multi_record.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26110/437facc1-9b91-edeb-5a06-abfe665c594c.png "sc_sample_multi_record.png")


## 複数レコードを一括処理する

すごく特殊なことをする必要はなく、saveMany() にデータを渡してあげれば一気に保存してくれます。
https://github.com/fuchigam1/SampleMultiRecord/blob/a06ac130f967981ba3087231c979cc8bc203df97/Controller/SampleMultiRecordsController.php#L46

強いて挙げれば、view側で複数の形式を準備してあげることです。

```php
<?php for ($i = 1; $i < 4; $i++): ?>
<?php echo $this->BcForm->input('SampleMultiRecord.'. $i .'.id', ['type' => 'hidden']) ?>
<?php echo $this->BcForm->input('SampleMultiRecord.'. $i .'.title', [
	'type' => 'text', 'size' => 80,
	'data-input-text-size' => 'full-counter',
	'placeholder' => 'サンプルテキスト',
]) ?>
<?php echo $this->BcForm->error('SampleMultiRecord.'. $i .'.title') ?>
<?php endfor ?>
```

サンプルのviewはこちら。
https://github.com/fuchigam1/SampleMultiRecord/blob/main/View/SampleMultiRecords/admin/form.php#L24


ポイントとしては、error についても同じ形式で準備しておくと、バリデーションチェック時にエラーメッセージも該当行で表示できます。

最初はさすがにエラーメッセージはゴニョゴニョしないと表示できないだろうなぁ、セッションにでも取っておいて出してあげれば済むかとか思っていたんですが、なんのことはないそのまま行けちゃったというね、便利ですね。


## ブログカテゴリ一覧画面に任意の列を追加する

SampleMultiRecordHelperEventListener で BcListTable.showHead, BcListTable.showRow を用いて実現します。

- https://github.com/fuchigam1/SampleMultiRecord/blob/main/Event/SampleMultiRecordHelperEventListener.php

サンプルでは ```$View = $event->subject();``` も使ってますが、実際のところ ```$event-data``` 使っておけば良いです。


## まとめ

別にeachでやってsaveしても良いのですが、save時のcreate, updateを考えることなく実現できるのがメリットですね。
レコード毎に追加・編集画面を作るまでもないときには、saveManyを用いるのが便利です。


### 参考記事

- https://book.cakephp.org/2/ja/models/saving-your-data.html#model-savemany-array-data-null-array-options-array
Observation-Centric SORT: Rethinking SORT for Robust Multi-Object Tracking

# はじめに

論文を読んだので詳細をまとめる。
指摘、議論大歓迎

# 情報

後日追加予定

# 詳細

## Motivation

★motion model-based Multi Obejct Trackingの開発を目的としている。

ただしmotion model-based MOT(特にSORT)にはKalman filterを用いていることにより課題が3点あると考えられている。

1. 高いframe rateを要求するため、位置推定時に乗るノイズの影響を増大させる。
1. 未検出であってもKalman filterが軌道予測をし続けるので、実測値との誤差が増える。
1. 近年の物体検出器の発展を考えるとKalman filterのみで軌道予測するのは現実的ではない(実測値を使えればいいのにSORTでは考慮されていない)。

![SORTとOC-SORTの結果の違い、SORTの場合ダンスのような複雑な動きには対応できない。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043769/9913f503-f569-477e-a5ca-670bc2b3a125.png)

## 提案手法

★Predictionに頼った軌道予測ではなく、実測値を基に更新された軌道予測により、従来では難しかった複雑でかつocculusionが発生する状況にロバストなmotion model-based MOTを作成した(Observation-Centric SORT)。

1. Observation-Centric Re-Update(ORU)
1. Observation-Centric Momentum(OCM)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043769/b73b673b-0ee9-5e5d-77db-b7272d7d42bb.png)

ORUの構想は以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043769/38913f7b-0a3d-6c9a-6ae0-4087fcc5bae6.png)

## 実験結果

### Datasets

- [MOT17](https://motchallenge.net/data/MOT17/)
- [MOT20](https://motchallenge.net/data/MOT20/)
- [KITTI](https://www.cvlibs.net/datasets/kitti/eval_mots.php)
- [DanceTrack](https://dancetrack.github.io/)
- [CroHD](https://paperswithcode.com/sota/multiple-object-tracking-on-crohd)
    - 群衆Trackingのdatasetだが詳細不明

detectorは[YOLOX](https://github.com/Megvii-BaseDetection/YOLOX)、学習は[ByteTrack](https://github.com/ifzhang/ByteTrack)で実施

> なぜByteTrackで学習させたweightじゃないとだめなのか不明、他のモデルでも同様に学習器としてByteTrackが用いられている。

### Benchmark Result

> 最新の情報はPaper with Codeの[Multiple Object Tracking](https://paperswithcode.com/task/multiple-object-tracking)や[MOTChallenge](https://paperswithcode.com/dataset/motchallenge)を見てもらえると参考になる

評価指標のうちHOTAがMOTを網羅した評価指標と呼ばれており、MOT ChallengeではHOTAが他のモデルに比べ高い結果を得られた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043769/36820354-87ed-d771-7c38-2fcc6dd67179.png)

複雑な動きをするDanceTrackのdatasetに関しては差が顕著に表れている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043769/53aa77c3-095a-7dd3-5788-dba36eb72d3a.png)

今回検討したmodulesの評価をしたのが以下の結果、OCMがDanceのような複雑な動きをする対象を追跡するのに役に立つことが実験より分かった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043769/2657b4e5-fe80-a975-8ab6-f69e2a831ee5.png)
【Python / Pyxel】AttributeError: module 'pyxel' has no attribute 'MOUSE_LEFT_BUTTON'が発生したときの対処法/主なキー定義の確認

# はじめに
AttributeError: module 'pyxel' has no attribute 'MOUSE_LEFT_BUTTON'というエラーが何回か発生したので、忘備録としてこの記事を書いてみました。

この記事では、現時点のPyxelの最新バージョンであるバージョン1.9.18を使っています。


## この記事の対象者
この記事の対象者は以下のような人です。

- 下記のコードを動かした際に、
```python
if pyxel.btn(pyxel.MOUSE_LEFT_BUTTON):
```

```python
AttributeError: module 'pyxel' has no attribute 'MOUSE_LEFT_BUTTON'
```

上記のエラーが出てしまった方

- 主なキー定義を軽く確認したい方

# エラーが出てしまう原因
```python
if pyxel.btn(pyxel.MOUSE_LEFT_BUTTON):
```
上記のコードでは左クリックを押したかどうかを調べるために、MOUSE_LEFT_BUTTONを使おうとしていますが、先述のエラーが出てしまいます。その原因はPyxelのバージョン1.9.18の[キー定義を確認する](https://github.com/kitao/pyxel/blob/v1.9.18/python/pyxel/__init__.pyi)と左クリックの定義はMOUSE_LEFT_BUTTONではなく、**MOUSE_BUTTON_LEFT**となっており、MOUSE_LEFT_BUTTONは存在しないためです。

MOUSE_LEFT_BUTTONを使ってしまっていた原因は、Pyxelのバージョン1.43の[キー定義を確認する](https://github.com/kitao/pyxel/blob/v1.4.3/pyxel/__init__.py)とわかります。

バージョン1.43ではMOUSE_LEFT_BUTTONが左クリックの定義となっており、その頃の古いソースコードを使ってしまったため、MOUSE_LEFT_BUTTONが使われてしまったものだと思われます。

# エラーを解決する方法
```python
if pyxel.btn(pyxel.MOUSE_LEFT_BUTTON):
```
上記のコードを
```python
if pyxel.btn(pyxel.MOUSE_BUTTON_LEFT):
```
に書き直しましょう。
MOUSE_LEFT_BUTTONをMOUSE_BUTTON_LEFTに書き換えるだけですね。

# キー定義を簡単に確認したい

今回見ていったキー定義は[こちら](https://github.com/kitao/pyxel/blob/v1.9.18/python/pyxel/__init__.pyi)で確認できますが、少し長いので主要なものを表にまとめてみました。

### マウス

|ボタン  |キー定義  |
|---|---|
|左クリック  |MOUSE_BUTTON_LEFT  |
|右クリック  |MOUSE_BUTTON_RIGHT  |

### 上下左右キー

|ボタン  |キー定義  |
|---|---|
|上キー  |KEY_UP  |
|下キー  |KEY_DOWN  |
|左キー  |KEY_LEFT  |
|右キー  |KEY_RIGHT  |

### 数字

|ボタン  |キー定義  |
|---|---|
|0 |KEY_0  |
|1  |KEY_1  |
|2  |KEY_2  |
|3  |KEY_3  |
|4 |KEY_4  |
|5  |KEY_5  |
|6  |KEY_6  |
|7  |KEY_7  |
|8 |KEY_8  |
|9  |KEY_9  |

### 英字

|ボタン  |キー定義  |
|---|---|
|A |KEY_A  |
|B  |KEY_B  |
|C  |KEY_C  |
|D  |KEY_D  |
|E |KEY_E  |
|F  |KEY_F  |
|G  |KEY_G  |
|H  |KEY_H  |
|I |KEY_I |
|J  |KEY_J  |
|K |KEY_K  |
|L  |KEY_L  |
|M  |KEY_M  |
|N  |KEY_N  |
|O |KEY_O  |
|P  |KEY_P  |
|Q  |KEY_Q  |
|R  |KEY_R  |
|S |KEY_S |
|T  |KEY_T  |
|U |KEY_U  |
|V  |KEY_V  |
|W  |KEY_W  |
|X  |KEY_X  |
|Y |KEY_Y |
|Z  |KEY_Z  |

### その他の主要なキー

|ボタン  |キー定義  |
|---|---|
|スペースキー |KEY_SPACE  |
|バックスペースキー |KEY_BACKSPACE  |
|エンターキー |KEY_RETURN  |
|プラスキー |KEY_PLUS  |
|マイナスキー |KEY_MINUS  |


# まとめ
Pyxelのバージョン1.9.18のキー定義を確認して、エラーを解決していきました。
参考にしていただけたら幸いです。
ではみなさま、よきPyxelライフを。
ExcelVBA：いろいろ(更新中)

## 前書
* 自分の勉強メモです。ご参考まで。

## ファイル操作関連
* ファイルが既に開いたかどうか
```VB:VBAソース
Function IsOpened(filename) As Boolean
    Dim wb As Workbook
    For Each wb In Workbooks
        If wb.Name = filename Then
            IsOpened = True
            Exit Function
        End If
    Next wb
    IsOpened = False
End Function

Function IsExist(filename) As Boolean
    If Dir(filename) = "" Then
        IsExist = False
    Else
        IsExist = True
    End If
End Function
```
【Swift】TCAでのアラートの表示方法

# はじめに
https://qiita.com/SNQ-2001/items/26035e88e1959f3876fc

以前、「【SwiftUI】TCAでアラートを実装する」という記事を書きましたが、
TCA独自のアラート表示方法があったのでそちらの方法を記録しておきます

# 実装
```diff_swift
import SwiftUI
import ComposableArchitecture

struct ContentView: View {
    @ObservedObject private var viewStore: ViewStoreOf<Feature>
    
    let store: StoreOf<Feature>
    
    init(store: StoreOf<Feature>) {
        self.store = store
        self.viewStore = ViewStore(store, observe: { $0 })
    }

    var body: some View {
        Button {
            viewStore.send(.buttonTapped)
        } label: {
            Text("テスト")
        }
+       .alert(store: store.scope(state: \.$alert, action: Feature.Action.alert))
    }
}
```
```diff_swift
import ComposableArchitecture

struct Feature: Reducer {
    struct State: Equatable {
+       @PresentationState var alert: AlertState<Action.Alert>?
    }

    enum Action: Equatable {
        case buttonTapped
+       case alert(PresentationAction<Alert>)
        
+       public enum Alert: Equatable {
+           /* アラートのボタンにアクションを追加したい場合はここにActionを追加 */
+       }
    }
    
    func reduce(into state: inout State, action: Action) -> Effect<Action> {
        switch action {
        case .buttonTapped:
+           state.alert = .init(title: .init("アラートです"))
            return .none
+       case .alert:
+           return .none
        }
    }
}
```

# おわり
TCAは独自実装が多いので学習コストが高いです、、、
macOSのBlenderでシステムコンソールを出す方法

## 背景

Windowsであれば、Blenderの`ウィンドウ`メニューの`システムコンソール切替え`でBlenderのコンソール画面を出せますが、macOSのBlenderにはこのメニューがありません。

macOSでは、先にターミナル画面を開いておいて次のようにコマンドを実行すると、そのターミナル画面がコンソール画面の代わりになります。

```sh
/Applications/Blender.app/Contents/MacOS/Blender
```

## やりたいこと

- macOSでターミナル画面が開くBlenderアプリケーション（以降ではBlenderConsole.app）の作成

## アプリケーションの構成

背景で説明したコマンドをアプリケーションにするには、下記の構成でファイルを作成します（括弧内は内容です）。BlenderConsoleがアプリケーション名です。

* BlenderConsole.app
    * Contents
        * Info.plist（設定ファイル）
        * MacOS
            * blender.sh（コマンドのスクリプト）
        * Resources
            * blender icon.icns（アイコン）

`BlenderConsole.app`は、どこに置いてもよいですが、今回は、`/Applications`に置きます。

## BlenderConsole.appの作成

Blender本体がインストールされている状態で、管理者権限のあるユーザのシェルで次を実行してください。

```sh
mkdir -p /Applications/BlenderConsole.app/Contents/{MacOS,Resources}
cp /Applications/Blender.app/Contents/Resources/blender_icon.icns \
   /Applications/BlenderConsole.app/Contents/Resources/

cat << EOF >> /Applications/BlenderConsole.app/Contents/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleExecutable</key>
    <string>blender.sh</string>
    <key>CFBundleIconFile</key>
    <string>blender_icon</string>
</dict>
</plist>
EOF

cat << EOF >> /Applications/BlenderConsole.app/Contents/MacOS/blender.sh
#!/bin/bash
open /Applications/Blender.app/Contents/MacOS/Blender
EOF

chmod +x /Applications/BlenderConsole.app/Contents/MacOS/blender.sh
```

アプリケーションフォルダのBlenderConsoleでターミナル画面が開くBlenderを実行できます。

※　実行は自己責任でお願いします。

## ターミナル画面を自動で消すための設定

BlenderConsoleを実行すると、ターミナル画面と一緒にBlenderが起動します。しかし、Blender終了時にターミナル画面が残ってしまいます。手動で消してもよいですが、次のようにすると自動で消えるようになります。

- ターミナルを起動している状態で、ターミナルメニューの設定（⌘＋，）で設定画面を開く
- プロファイルタブの`シェルの終了時`を`シェルが正常に終了した場合は閉じる`にする

## Dockに追加

アプリケーションフォルダのBlenderConsoleをDockにドラッグしてください。

## BlenderConsole.appの内容の確認

アプリケーションフォルダのBlenderConsoleを右クリックして`パッケージの内容を表示`を選んでください。

## BlenderConsole.appの削除

アプリケーションフォルダのBlenderConsoleを削除してください。

以上
Crystalで深い多重ループを楽に書くマクロ


前回の記事の続きです。
https://qiita.com/theanine/items/9462b79b83c1aba412bd

前回の記事で多次元の配列を簡単に作るmacroを作りました。
多次元配列を作ると、各次元ごとにループをかけていくので、深いネストのループになりがちです。

前回取り上げたAtCoderの問題では10重ループとなりました。

```crystal
(0..n1).each do |i1|
  (0..n2).each do |i2|
    (0..n3).each do |i3|
      (0..n4).each do |i4|
        (0..n5).each do |i5|
          (0..n6).each do |i6|
            (0..n7).each do |i7|
              (0..n8).each do |i8|
                (0..n9).each do |i9|
                  (0..n10).each do |i10|
                    何かの処理
                  end
                end
              end
            end
          end
        end
      end
    end
  end
end
```
どうせ、コピペで書いていくので、書くのはそこまで大変ではないですが、変更とかあるとしんどいですね。
そこで、前回に引き続きmacroで楽をしましょう。

## macroのブロック

Crystalのmacroは高機能で、ブロックを受け取ることもできます。

https://crystal-lang.org/api/1.9.2/Crystal/Macros/Block.html

args, bodyでブロックの引数や中身などにも分けて取得できて色々できそうですね。これを使って、多重ループマクロを作ってみます

## 多重ループマクロ

ということで以下のようなものを作ってみました。

```crystal
macro rep(*a, &block)
  {% for i in 0...a.size %}
    ({{a[i]}}).each do |{{block.args[i]}}|
  {% end %} 
  {{ block.body }}
  {% for i in 0...a.size %}
    end
  {% end %}
end

```

使い方は以下のようにします。eachメソッドを持つオブジェクトを引数で渡せば良いです。範囲や配列、タプルなどを渡すことができます。


```crystal
rep(1..2, {3,4,5}, 0..1) do |i, j, k|
  puts "#{i} #{j} #{k}"
end
```
これを実行すると以下のようにできます。

```
1 3 0
1 3 1
1 4 0
1 4 1
1 5 0
1 5 1
2 3 0
2 3 1
2 4 0
2 4 1
2 5 0
2 5 1
```

これで深いループもブロックのネストを深くせずにかけます。

冒頭で取り上げた10重ループは
```crystal
rep(0..n1, 0..n2, 0..n3, 0..n4, 0..n5, 0..n6, 0..n7, 0..n8, 0..n9, 0..n10) do |i1, i2, i3, i4, i5, i6, i7, i8, i9, i10|
  何らかの処理
end
```
となります。
TypeScriptで余剰なプロパティが検出されない件とその解決策



## 問題の背景

TypeScriptは、デフォルトでオブジェクトリテラルの型を緩めて解釈します。すなわち、オブジェクトに含まれる余剰なプロパティを無視されてしまいます。例えば、次のようなコードではエラーは発生しません。

```typescript
type User = {
    name: string;
}

function putStorage(user: User) {
     window.sessionStorage.setItem('user', JSON.stringify(user));
}

const john = {
    name: "John",
    age: 30 // 余剰なプロパティ
};

putStorage(john); // エラーなし
```

この例の場合、渡されたオブジェクトをsession storageに保存しているため、
全く予期せぬ値がsession Storageに保管されてしまっていても、静的エラーで気づくことができません。



## StrictPropertyCheck型の導入

`StrictPropertyCheck` という型を作成します。これは、余剰なプロパティをエラーとして検出するために使用します。

```typescript
type StrictPropertyCheck<T, TExpected> = keyof T extends keyof TExpected ? T: `${Exclude<Extract<keyof T,string|number>, Extract<keyof TExpected,string|number>>} is excess property `;


```

この型は、2つの型引数を受け取ります。

1. `T`：検査対象のオブジェクト型。
2. `TExpected`：期待されるプロパティの型。

T のプロパティが TExpected のプロパティと一致する場合、T をそのまま返します。これは、型チェックが成功したことを示します。

T のプロパティのいずれかが TExpected のプロパティと一致しない場合（Tに余剰プロパティが含まれる場合）エラーメッセージを生成します。このエラーメッセージには、T 型の余剰プロパティが含まれていることを示す情報が含まれます。

※`keyof`では予測される型は`string | number | symbol`であり
`symbol`型はオブジェクトリテラルで出力できないため`string | number`だけ出力するようにしています。

## StrictPropertyCheckの活用

これを活用して、余剰なプロパティをエラーとして検出する関数を作成します。

```typescript

type StrictPropertyCheck<T, TExpected> = keyof T extends keyof TExpected ? T: `${Exclude<Extract<keyof T,string|number>, Extract<keyof TExpected,string|number>>} is excess property `;

type User = {
    name: string;
}

function putStorage<T extends User>(user: StrictPropertyCheck<T,User>) {
     window.sessionStorage.setItem('user', JSON.stringify(user));
}

const john = {
    name: "John",
    age: 30 ,// 余剰なプロパティ
};

putStorage(john); // エラー： Argument of type '{ name: string; age: number; }' is not assignable to parameter of type '"age is excess property "'
```


このように、`StrictPropertyCheck` 型を使用することで、余剰なプロパティが関数の呼び出し時にエラーとして検出されるようになりました。
【Android】アニメーションの後の動きや速度を制御するinterpolatorについて【Kotlin】



# はじめに
今回は、Androidアプリ開発中の中でアニメーション時に出てきた __interpolator__について気になったので、調べて記事にしました。
それぞれ　どんな感じなのか動画にして残しておきます。
# 一覧表

|クラス|説明（Android developersから抜粋）|
|:---|:---|
|AccelerateDecelerateInterpolator|開始時と終了時にはゆっくりで、途中で加速|
|AccelerateInterpolator|開始時はゆっくりで、その後加速|
|AnticipateOvershootInterpolator|逆戻りしてからはずみを付けて進み、目的の値を過ぎてから最終値に落ち着く|
|BounceInterpolator|終了時にバウンド|
|CycleInterpolator|指定した回数だけアニメーションを繰り返す|
|DecelerateInterpolator|最初は速くて、減速する|
|LinearInterpolator|速度は一定|
|OvershootInterpolator|はずみを付けて進んで、最終値を過ぎてから、逆戻り|


# 実践

```
interpolator = AccelerateDecelerateInterpolator()
```
![ezgif.com-video-to-gif (7).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/55b6e8df-55d0-e9bd-6559-605e9962ecea.gif)


```
interpolator = AccelerateInterpolator()
```
![ezgif.com-video-to-gif (6).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/57b79663-ad1f-4c7e-1b83-88600a02266c.gif)

```
interpolator = AnticipateOvershootInterpolator()
```
![ezgif.com-video-to-gif (5).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/a6dd8ec7-0142-4a78-5f64-9314f0317643.gif)

```
interpolator = BounceInterpolator()
```
![ezgif.com-video-to-gif (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/fc0fdff1-8a08-a387-de5b-c6b4fc9fc150.gif)

```
interpolator = CycleInterpolator()
```
![ezgif.com-video-to-gif (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/a89d5b41-e6ad-8e02-e7e6-f8c24059b4a1.gif)

```
interpolator = DecelerateInterpolator()
```
![ezgif.com-video-to-gif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/8aff9b69-3751-6619-5654-eab7872425d0.gif)

```
interpolator = LinearInterpolator()
```
![ezgif.com-video-to-gif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/11c1aafd-b1ac-9de4-087a-dcd13f75d5f8.gif)

```
interpolator = OvershootInterpolator()
```
![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/9515c13c-8bdd-b828-8f74-f496b91c70d4.gif)



# 参考
https://zenn.dev/issyu_39/articles/f2b8c349faee12
MagicGrabberとは

[MagicGrabber](https://qiita.com/SatoNobuhiro/items/c66aa4bdadcbd348b0a5)とはRaspberry Piにインストールする「リモートフォレンジック支援ツール」です。このツールは「遠隔にある、**ネットワークにつながっていない端末**に対して、フォレンジックができる」のです。

つまり下記の画像のように、遠隔でフォレンジックをすることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3502616/be84bd8b-a73f-af3c-e94a-5006da00056c.png)


少し技術力のある方であれば、「いやいや、それはRaspberry Piがネットワークルーターになっているだけでしょ？」と思うかもしれません。それは違います、フォレンジック対象の端末とRaspberry Piはネットワーク接続されていません。MagicGrabberは、「フォレンジック対象の端末と直接ネットワーク接続せずに遠隔操作できる」のです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3502616/98269e3f-3235-62c8-70ed-31ee331e3dbb.png)

ではどのように、ネットワーク接続せずに、フォレンジック担当者に対して遠隔操作を提供するのでしょうか？それはLinux USB Gadget Driverという機能を使用して、Raspberry PiがUSBキーボードとUSBメモリとして動作することで、フォレンジック担当者に対して遠隔操作を提供します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3502616/c9c9066d-a79e-eeb5-d560-ca235c6dfee0.png)

フォレンジック対象の端末と直接ネットワーク接続されていないため、ウイルスの横感染を防ぎつつ、遠隔操作し、フォレンジックを行うことができるのです。
これは下記の場合にとても有効に働きます。
+ ネットワーク全体がウイルスに感染してしまって、ロックダウンしている拠点へのフォレンジック
+ 工場の端末など、独立したネットワークにある端末へのフォレンジック
+ ネットワークにはつながっているが、FWなどがあり、直接接続できない端末へのフォレンジック
です。
整列する時間を測る

# これは何？

https://qiita.com/fsdg-adachi_h/items/9d91e53d6ff4e5753b05

という記事に関する追加情報

例によって私にはコメントを書くことができないのでこうして記事を書いた。

# データ

バブルソートということで、比較と入れ替えを行う。
比較の回数はデータに依存しないと思う（自信ない）けど、入れ替えの回数はデータに依存するので、データによって処理時間が変わる。

手元で「10000要素を5000回バブルソート」を go で書いたバイナリで実行したところ、

|種|平均(秒)|標準偏差(秒)|
|:--|:--|:--|
|固定|0.05362|0.0014|
|乱数|0.05495|0.0018|

という具合で、データを変えると時間のばらつきが大きくなることがわかる。

今回はバブルソートの時間が知りたいというよりも、なんか時間のかかる処理をさせてその差を見たいということだと思うので、逆順に整列済みのデータを与えるのが良いと思った。

# go の乱数

go の乱数が

```go:go
	// 乱数で配列を初期化
	rand.Seed(time.Now().UnixNano())
```

となっていたけど、これは deprecated。

```
Deprecated: Programs that call Seed and then expect a specific sequence of results from the global random source (using functions such as Int) can be broken when a dependency changes how much it consumes from the global random source. To avoid such breakages, programs that need a specific result sequence should use NewRand(NewSource(seed)) to obtain a random generator that other packages cannot access.
```

雑にまとめると「君の知らないパッケージでグローバル乱数使うかもしれないから、 `rand.Seed` 使っても同じシーケンスにはならないかもよ。というわけで、 `rand.Seed` は非推奨」ということ。

# Python の JIT

@ratorato さんの [コメント](https://qiita.com/fsdg-adachi_h/items/9d91e53d6ff4e5753b05#comment-6fa5543cc7625b1d04de) で気がついたので、JIT で試してみた。

```shell:shell
$ pip install numba 
```

としてから

```python:python
# 略
from numba import jit

# 略

# バブルソートアルゴリズムを実行する関数
@jit(nopython=True)
def bubblesort(array):
    # 以下略
```

と改変したコードを動かした。

||出力（抜粋）|
|:--|:--|
|元のコード (JIT なし)|24.13283 seconds.|
|改変後 (JIT 有効)|1.39359 seconds.|

なるほど速い。

# JavaScript (node) のこと

node の中身のことは全然知らないんだけど、Number を単なる 64bit 浮動小数点数として持っているとは思えない。おそらく C言語的に書くと

```C:想像
struct Number{
  something s;
  union {
    int32_t i32;
    uint32_t u32;
    double d;
  } v;
};
```

のようになっていて、Number 一個で 96bit か 128bit ぐらいあるんだと思う。
だとすると、32bit 固定長でやっている Java なんかとくらべるとどうしても交換操作が遅くなる。

実際 `new Array(ARRAY_SIZE);` を `new Int32Array(ARRAY_SIZE);` に変えるだけで 1割以上速くなる。

比較操作については、最適化器に気づかれていて整数比較が走っているように見える。

というのは
`array[i] = Math.floor(Math.random() * 0x7FFFFFFF);` を `array[i] = 0.1+Math.floor(Math.random() * 0x7FFFFFFF);` に変えると 3割以上遅くなる。

まとめると

|実装|元のコードを 1.00 とした時間|
|:--|:--|
|元のコード|1.00|
|`Int32Array` を利用|0.87|
|`0.1` 加算|1.36|

という感じ。


# Python と多倍長整数

一方 Python では多倍長整数となっている。
多倍長整数は普通の整数よりずっと遅いのが普通なので、コンパイラかどうかという話とは別のハンデを負っている。

Go や Java で多倍長整数版をつくるとだいぶ遅いと思う。試してないけど。
Xcodeでファイル名を変更する方法

現在xCodeでiOS開発の勉強中でファイル名を変更したいことがありました。

Xcode Version 14.2


```TestView.swift
struct TestView: View {
    var body: some View {
        Text("Hello, World!")
    }
}
```

こちらのTestViewの名前を変更する場合は
`TestView`の上で右クリックをし、Refactor -> Renameをクリックします。
その後変更したい名前を入力して、エンターをすると変更できます。

スペルミスなどに後で気付いた時など使ってみるといいと思います。
u-bootとfat

fatが読めるu-bootでSATAのディスクからカーネルを読み込むようにしました。

いろいろ試して、何故かMBRで最初のパーティションだとだめで、二つ目のパーティションだと、NetBSDのfatの/bootが読めました。

なので最初にダミーのパーティションをおきます。

u-bootの環境変数はこう設定しました。

```
fatload ide 1:1 4000000 netbsd-openrdbase.ub;bootm 4000000
```

特定のu-bootのバグかもしれません。確認に時間がかかるので、勘違いしている可能性もあります。

cfiの場合はflashにカーネルを焼くのですが、このターゲットはNANDなので手順が分からないので、HDにカーネルを置いてます。

このパーティションはNetBSDでも見えているので、アップデートがOS上でファイルの書き換えで出来るので便利です。
VertexAI pipelineでtar.gzファイルからデータ抽出＆BigQueryに投入

# 1.はじめに
* ①tar.gzファイル（複数のcsvファイルが入ってる）を解凍、②解凍ファイル中から必要なcsvを指定してBigQueryにロードする、という作業を現在colaborator上で行っている
* 毎回手動でやるのが面倒になってきたので、もっとうまい方法ないかと検討したところ、WorkflowとVertex AI Pipelineが候補に挙がる。
* どうもPipelineの方が色々自由度が高そうなので、そちらで実行してみた。
 
# 2.コード
* いろいろ試行錯誤して最後に実行できたコード
* 必要なライブラリのインストールや設定は省略するけど、後から見るとすっきりした書き方で便利なのがよくわかった。速度もcolaboratoryの時の5～10倍くらいですごく早く処理が終わる！
* 今持っている手動実行する系のものはこちらに移してしまおうと思えた。

*本来は機械学習のパイプラインも構築できるみたいなので、そちらも試す予定。

```python
# componentを作る
@component(
    packages_to_install=[
        "google-cloud-storage",
        "pandas",
    ],
    base_image="python:3.9",
    output_component_file="unzip_data.yaml"
)
def unzip_data(
    PROJECT_ID : str,
    bucket: str,
    url: str,
    date: str,
    #stat: Output[stat],
)->str:
    from google.cloud import storage

    # 'Pulling' demo .csv data from a know location in GCS

    storage_client = storage.Client(PROJECT_ID)
    bucket = storage_client.get_bucket(bucket)
    blob = bucket.blob(url)
    blob.download_to_filename('temp.tar.gz')

    import tarfile

    # tar.gzファイルを開く
    with tarfile.open('temp.tar.gz', 'r:gz') as tar:
        tar.extractall()


    #解凍ファイルのうち必要なファイルをＧＣＳにアップロード
    # 格納するGCSのPathを指定(/xxx/yyy.csv)的な
    gcs_path = str(date) + "/***.csv"
    blob_gcs = bucket.blob(gcs_path)
    # ローカルのファイルパスを指定
    local_path = "***.csv"
    blob_gcs.upload_from_filename(local_path)

    return date
    


@component(
    packages_to_install=["google-cloud-bigquery","google-cloud-storage"],
    base_image="python:3.9",
    output_component_file="unzip_data.yaml"
    )
def load_data_to_gbq(
    inputd: str,
    ) -> None:
    from google.cloud import bigquery

    # Construct a BigQuery client object.
    client = bigquery.Client(project="***")

    # TODO(developer): Set table_id to the ID of the table to create.

    date= inputd
    table_id = "my-project.my-dataset.my-table_{}".format(date)

    job_config = bigquery.LoadJobConfig(
    schema=[
    bigquery.SchemaField("uuid", "STRING"),
    bigquery.SchemaField("name", "STRING"),
    #~~色々
    ],
    skip_leading_rows=1,
    # The source format defaults to CSV, so the line below is optional.
    source_format=bigquery.SourceFormat.CSV,
    write_disposition=bigquery.job.WriteDisposition.WRITE_TRUNCATE

    )

    #unzip_dataでuploadしたファイルと同じ場所
    uri = "gs://***/"+ str(date) + "/***.csv"

    load_job = client.load_table_from_uri(
        uri, table_id, job_config=job_config,
    )  # Make an API request.

    load_job.result()  # Waits for the job to complete.

    destination_table = client.get_table(table_id)  # Make an API request.



# Building the 'PIPELINE'

@dsl.pipeline(
    pipeline_root=PIPELINE_ROOT,
    name="***-pipeline",  # Your own naming for the pipeline.
    )
def my_pipeline(
    PROJECT_ID: str = "my-project",
    url: str = "***/***.tar.gz",
    bucket: str = "***",
    date : str = "20230901"
    ):
    dataset_task = unzip_data(PROJECT_ID=PROJECT_ID,bucket=bucket, url=url,date=date)
    load_data_to_gbq(inputd=dataset_task.output)

    #dimensions = report_data(inputd=dataset_task.output)



```
【TypeScript】ユニオン型から少なくとも1つをキーとするオブジェクト型を生成する

この記事ではユニオン型から少なくとも1つをキーとするオブジェクトを生成する方法を紹介します。
具体的には以下のような`Union`を受け取って
```ts
type Union = 'a' | 'b' | 'c' | 'd' | 'e';
```
以下のような型を生成するような型を作ります。バリューはなんでもいいですが、以下簡単のため`string`で考えます。
```ts
type AtLeastOneRequiredObject =
  | {
      a: string;
      b?: string;
      c?: string;
      d?: string;
      e?: string;
    }
  | {
      a?: string;
      b: string;
      c?: string;
      d?: string;
      e?: string;
    }
  | {
      a?: string;
      b?: string;
      c: string;
      d?: string;
      e?: string;
    }
  | {
      a?: string;
      b?: string;
      c?: string;
      d: string;
      e?: string;
    }
  | {
      a?: string;
      b?: string;
      c?: string;
      d?: string;
      e: string;
    };
```
このようにオブジェクト全体を定義するのと面倒くさいのに加えてミスが発生しやすいので、ユニオンを型引数として渡すことでこれと同様の型を自動で生成する型を作ります。
それを実現したのが以下の型です。
```ts
type AtLeastOneRequiredObject<
  T extends string | number | symbol,
  U extends T = T,
> = U extends any
  ? {
      [K in T as K extends U ? never : K]?: string;
    } & {
      [K in U]: string;
    }
  : never;
```
`AtLeastOneRequiredObject<Union>`とすることで、求めていた型が手に入ります。


## 解説
まずはこの部分に注目します。
```ts
{
  [K in T as K extends U ? never : K]?: string;
} & {
  [K in U]: string;
}
```
`T`には`Union`、`U`には`Union`の一部のどれかが渡って来たとします。ここでは`U`に`a`が渡っていたと考えます。
```ts
{
  [K in T as K extends U ? never : K]?: string;
}
```
前半の部分は`Union`から`U`を除いた値でキーを構成して以下のようなオブジェクトを作ります。
```ts
{
  b?: string;
  c?: string;
  d?: string;
  e?: string;
}
```
そして、
```ts
{
  [K in U]: string;
}
```
この部分は以下のようになります。
```ts
{
  a: string;
}
```
つまり、注目した部分は以下のような型となります。
```ts
{
  b?: string;
  c?: string;
  d?: string;
  e?: string;
} & {
  a: string;
}
```
この型は見た目は違いますが、以下の型と同じような振る舞いをします。
```ts
{
  a: string;
  b?: string;
  c?: string;
  d?: string;
  e?: string;
}
```

次に全体を見る前に`extends`の性質を振り返ってみます。
```ts
(X | Y | Z) extends　A
```
このように左にユニオン型が置かれた、この型は
```ts
(X extends A) | (Y extends A) | (Z extends A)
```
のように扱われます。
それを踏まえて全体を見てみると
```ts
U extends any
  ? {
      [K in T as K extends U ? never : K]?: string;
    } & {
      [K in U]: string;
    }
  : never;
```
`T`と`U`が`'a' | 'b'`だとすると以下のように分解されます。
```ts
({
  [K in 'a' | 'b' as K extends 'a' ? never : K]?: string;
} & {
  [K in 'a']: string;
}) | ({
  [K in 'a' | 'b' as K extends 'b' ? never : K]?: string;
} & {
  [K in 'b']: string;
})
```
これは以下のようになります。
```ts
({
  b?: string
} & {
  a: string
}) | ({
  a?: string
} & {
  b: string
})
```
これは最初に求めていた以下の型と同じように扱えます。
```ts
{
  a: string;
  b?: string;
} | {
  a?: string;
  b: string;
}
```
つまり、`extends`の性質を用いてユニオンの一部の型だけが必須となるようなオブジェクト型のユニオン型を形成するようにして生成しています。

## おわりに
`Partial<Record<Union, string>>`から`{}`を除くような方法など他にも表現する手段があると思います。良い手法があればコメントなどに記述していただければ幸いです。
場合によってはインデントを揃えなくてもよいのではないか説

## 言いたいこと

これは横に長くて見にくい。

```js:例1
function isHoge(param) {
    return param === "ほげほげ" || param === "ほげ！" || param === "ほげら" || param === "HOGE";
}
```

これは見やすいが論理演算子はケツを見ないと分からないのがダルい。

```js:例2
function isHoge(param) {
    return param === "ほげほげ" ||
           param === "ほげ！" ||
           param === "ほげら" ||
           param === "HOGE";
}
```

これは頭がガタガタしててなんか気持ち悪い。

```js:例3
function isHoge(param) {
    return param === "ほげほげ"
           || param === "ほげ！"
           || param === "ほげら"
           || param === "HOGE";
}
```

こうすると見やすくない？

```js:例4
function isHoge(param) {
    return param === "ほげほげ"
        || param === "ほげ！"
        || param === "ほげら" 
        || param === "HOGE";
}
```

以上

突っ込まれるのがシャクなので先手を打ちますがsomeは知ってます。
dockerをマルチプラットフォーム用にビルドする

## 目的
dockerを異なるアーキテクチャ間で用いる場合に少し苦労したので、備忘録を残す

## 準備
最初の状態ではマルチプラットフォームビルドに対応していない
```bash
docker buildx create --use
```

## ビルド
```bash
docker buildx build --platform linux/amd64,linux/arm64 .
```
platformの例
- linux/amd64
- linux/arm64
- linux/arm/v7
- darwin


コンテキストを指定する事も出来る
```bash
docker buildx build --build-context project=path/to/project/source .
# docker buildx build --build-context project=https://github.com/myuser/project.git .
```
[Terraform]ネストされたmapから関数values,keysを使って値を取得する

# はじめに
これまであまり使わなかったが、terraformの関数`values`,`keys`を使うケースがあったので使い方を記載する。
さらに、__ネストされたmapから取得する方法も記載する。__

公式ページは以下

https://developer.hashicorp.com/terraform/language/functions/values

https://developer.hashicorp.com/terraform/language/functions/keys

# mapで記載された場合の取得方法
mapにて以下のように記載があったとする。
```terraform:terraform.tf
variable "subnet" {
 type    = map
 default = {}
}
```
```terraform:terraform.tfvars
subnet = {
  "1a" = "10.0.0.0/20",
  "1c" = "10.0.16.0/20",
  "1d" = "10.0.32.0/20"
}
```
この場合、それぞれの値を取得したい際は、関数`values`を使用すればvaluesが取得できる。
この際は`map`から`list`となる。
```terraform:
output "subnet" {
  value = values(var.subnet)
}
```
```terraform:--- result ---
tolist([
  "10.0.0.0/20",
  "10.0.16.0/20",
  "10.0.32.0/20",
])
```
keyの値を取得したい際は、関数`keys`を使用すればkeyが取得できる。
```terraform:
output "subnet_key" {
  value = keys(var.subnet)
}
```
```terraform:--- result ---
tolist([
  "1a",
  "1c",
  "1d",
])
```


# ネストされたmapから特定の値を取得したいとき
ここからが本題。mapにてネストされた以下のような記載があったとする。
```terraform:terraform.tf
variable "subnet_nest" {
  type = map(object({    
    az            = string
    subnet_public = string
  }))
  default = {}
}
```
```terraform:terraform.tfvars
subnet_nest = {
  "1a" = {
    az                 = "ap-northeast-1a"
    subnet_public      = "10.0.0.0/20"
  },
  "1c" = {
    az                 = "ap-northeast-1c"
    subnet_public      = "10.0.16.0/20"
  },
  "1d" = {
    az                 = "ap-northeast-1d"
    subnet_public      = "10.0.32.0/20"
  }
}
```
先程と同様にすると、以下のように複数の値が取得できる
```terraform:
output "subnet_nest" {
  value = values(var.subnet_nest)
}
```

```terraform:--- result ---
tolist([
  {
    "az" = "ap-northeast-1a"
    "subnet_public" = "10.0.0.0/20"
  },
  {
    "az" = "ap-northeast-1c"
    "subnet_public" = "10.0.16.0/20"
  },
  {
    "az" = "ap-northeast-1d"
    "subnet_public" = "10.0.32.0/20"
  },
])
```
ここから特定の値を出力したい際は以下のように設定する
```terraform:
output "subnet_nest_az" {
  value = values(var.subnet_nest)[*].az
}
```
```terraform:--- result ---
tolist([
  "ap-northeast-1a",
  "ap-northeast-1c",
  "ap-northeast-1d",
])
```
```terraform:
output "subnet_nest_cidr" {
  value = values(var.subnet_nest)[*].subnet_public
}
```
```terraform:--- result ---
tolist([
  "10.0.0.0/20",
  "10.0.16.0/20",
  "10.0.32.0/20",
])
```

key取得は同様
```terraform:
output "subnet_nest_key" {
  value = keys(var.subnet_nest)
}
```
```terraform:--- result ---
tolist([
  "1a",
  "1c",
  "1d",
])
```

# その他
ネストされたmapを扱うときは取得方法なども合わせて調べると良い。
あとは、mapのkeyとvalueを入れ替える関数[transpose](https://developer.hashicorp.com/terraform/language/functions/transpose)のあるのでいずれ試してみたい。