OmniAICreator/Qiita-1.07M huggingface dataset:
有名OSSに軽くIssueを立ててみた話

本記事は[Nihon University Advent Calendar 2023](https://qiita.com/advent-calendar/2023/nihon-u)の8日目の記事です。

# はじめ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206692/2b9da12d-cbfd-882b-6466-ae0202b6b6eb.png)

[Bun](https://bun.sh/)というOSSにissueを立ててコントリビュートしました。


[Bun](https://bun.sh/)とは以下の引用の通り、テストランナー、バンドラー、トランスパイラー、ランタイムやパッケージマネージャーを兼ね備えているオールインワンのツールです。他のパッケージマネージャーやテストランナーより良いパフォーマンスが出ているとアピールしています。また、Lockfileがバイナリーファイルであるのが特徴的です。

>Develop, test, run, and bundle JavaScript & TypeScript projects—all with Bun. Bun is an all-in-one JavaScript runtime & toolkit designed for speed, complete with a bundler, test runner, and Node.js-compatible package manager.


# 経緯
個人開発でアプリを作成しようとしていたのですが、いつも使っているnpmではつまらないと思い、当時できたてほやほやのBunを選定することに決めました。また、デプロイ先はfly.ioを選定しました。



Bunで作成したアプリをfly.ioにデプロイする方法が次のレポジトリーのリンクに記述してあるのですが、その通りに行うとエラーが発生。。。

https://github.com/fly-apps/bun

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206692/360f5b86-ccda-9f42-a719-59ae35f9a28e.png)


そのレポジトリーのissueも自分と同じエラーで立っているが、返信がない状態...(2023/9/27時点)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206692/554c3d52-7710-eec5-26b4-e4b1d3d58393.png)


そこでさらに人がいそうなBunのレポジトリーでこのエラーについてIssueを立てました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206692/0dc66f5a-6f11-f5ba-3d42-7ac214ec2744.png)


# やりとり

さっそく、返信が来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206692/64a252f1-83b9-9407-6e6f-0621a3f657cc.png)
どうやらbun.lockbファイルが.dockerignoreに記述されていて、dockerに認識されなかったことが原因でした。解決方法としては.dockerignoreからbun.lockbを消せば良いらしいです。



実際返信通りにやってみた結果、無事デプロイに成功！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206692/02e42c5e-37cb-035c-fe91-a30da6b124b4.png)



後は教えてくれた二人にしっかりお礼をして、issueをclose。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206692/f361fb77-44a1-52c6-fa30-cd30384ceabf.png)

# まとめ・感想
やってみた感想としては、インターン先で分からない所を先輩エンジニアに聞くこととあまり変わらないと感じました。

参考に、次のリストは自分がインターン先で分からないことを聞く際に自分が気を付けていることです。また、**issueを書く際にもこれらの事も意識しました。**
- コードやエラー文などの前提知識や現在の状況を文章に含める
- これまで行ってきた行動を文章に含める
- 文章を読み返して、相手に伝わるか見直す

英語に関して、筆者はせいぜい英検2級程度の能力しかありませんでしたが、DeepLを駆使して文章がしっかりと相手に伝わるよう努力しました。


今回はOSSにissueを立てるだけでしたが、次回はプルリクを含めたコントリビュートがしたいです。

当issueのリンクです。
https://github.com/oven-sh/bun/issues/6110
serverless frameworkで作ったLambda Function についてnodejs16.x以下のバージョンをnodejs18.xに上げるためのメモ書き

# 概要

AWS Lambdaのruntime `nodejs16.x` のサポートが来年6月で切れまーす！
みなさまのお手元にはこの震えるようなAWS(またはクラスメソッドさん）からのメールは届いていますか？

つまりそれは、nodejs12.x,14.xから16.xと逃げ回って遂に18.xへの対応をやらなければならないときが来ましたということです、年貢の納めどきです。

具体的にはライブラリのバージョンを上げたり、過去の互換を捨てたものは変更したり、ソースコードをなおしたりとやることはめんどくさく、作業は泥臭いものになります。

それでも先に進むというみなさま、覚悟はいいですか？


・・・では進みましょう。

# ざっくりやることのリスト

これが全てではないと思いますが、移行を主眼として必ずやらないといけないことを列挙します。

## 1. serverless.{yml|ts} の変更
runtimeを変更しました。
16から20...
これで2年＋αくらいは追い回されずにすむはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570665/0b769c3e-f822-f865-9300-642f74d8661c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570665/f9a166f9-0dc1-079c-8a9d-70d7e41e8ee9.png)


## 2. serverlessおよび**plugin**のバージョンを上げる。
どこまで上げればいいかはserverlessプロジェクトでnodejs18対応された段階までだと思いますが・・最新にしとけばいいと思います。
執筆時点では `"serverless": "3.38.0",`

## 3. aws-sdk v2を利用しているdependecyを探す
下記のコマンドを打って依存関係ツリーを出力し、aws-sdk@2に依存しているライブラリをなんとかする。

```
npm ls --all > dependencies.txt
grep 'aws-sdk@' dependencies.txt
```

```
├─┬ aws-sdk@2.1450.0
```

こんなかんじの依存を見つけたらtreeをたどってv2に依存しているライブラリを特定してバージョンを上げるとかする。
ただし、serverless framework自身にこれが出ている件は、バージョンを上げればokみたいなので依存関係があってもよい例外になります。

この問題にある根幹の話は、nodejs18.x のランタイム、実行環境では 2系のaws-sdkが提供されていないということ。
そのため実行時のLogsを見ると下記のようなエラーになります。

```
2023-12-25T08:58:06.370Z	undefined	ERROR	Uncaught Exception 	
{
    "errorType": "Runtime.ImportModuleError",
    "errorMessage": "Error: Cannot find module 'aws-sdk'\nRequire stack:\n- /var/task/src/functions/****.js\n- /var/runtime/index.mjs",
    "stack": [
        "Runtime.ImportModuleError: Error: Cannot find module 'aws-sdk'",
        "Require stack:",
        "- /var/task/src/functions/***.js",
        "- /var/runtime/index.mjs",
        "    at _loadUserApp (file:///var/runtime/index.mjs:1087:17)",
        "    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)",
        "    at async start (file:///var/runtime/index.mjs:1282:23)",
        "    at async file:///var/runtime/index.mjs:1288:1"
    ]
}
```

まずはここと戦うことです。

## ライブラリのバージョンアップに伴いソースコードを修正する

ビルド時にエラーが出ると思います。がんばってなおしましょう。
例えば下記のようなAWSに由来した関数は軒並みv3のものに置き換える必要があります。

Before(v2)
```
import AWS from "aws-sdk";
...
    const secretsManager = new AWS.SecretsManager();
    const secret = await secretsManager.getSecretValue({ SecretId: arn }).promise();

```

After(v3)
```
import { SecretsManager } from "@aws-sdk/client-secrets-manager";
...

    const secretsManager = new SecretsManager();
    const secret = await secretsManager.getSecretValue({ arn });
```

# おわりに
動作確認はしっかりしましょう。
testが用意してあっても、Lambdaにのせてみないとわからないことはそれなりにある感じです。

我々の場合これでカタがつきましたが、妙に古いライブラリとかobsoletedなものを使ってるところは苦労するかもですね。

# 参考とした記事や情報
* https://blog.open.tokyo.jp/2023/01/04/migrate-aws-sdk-node-js-v2-to-v3.htm
* https://qiita.com/TakeshiNickOsanai/items/7899a60044d71aa8d899
* https://endoflife.date/nodejs
外部ディスプレイ出力が出来なくなった時の解決方法備忘録

# 記事概要
PCを起動したら、外部ディスプレイ出力が出来なくなっていた。  
色々試して解決したので、それの備忘録。

# 環境
```
マシン: ThinkPad X1 Carbon 7th gen
OS　　: Windows 10 Pro
```

# やったこと

## ➀ 完全なシャットダウン
　shitfを押しながらシャットダウン。

## ➁ ディスプレイアダプターの再インストール
　デバイスマネージャー　> ディスプレイアダプターをアンインストールして、再起動。
 
 ![2023-12-26_18h05_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184925/fe5bcba5-33b6-b15a-e19d-69085758994f.png)

## ➂ ドライバーの更新
　<a href="https://pcsupport.lenovo.com/jp/ja" target="_blank">Lenovo</a>のHPから利用しているPCを選らび、ドライバーの自動更新をする。
 
 ![2023-12-26_18h03_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184925/45cdcfd2-0e9c-c943-4ddc-391f078dec25.png)
Dart の list[0] と list.elementAt[0] は何が違うの？

# 疑問

dart には List の指定 index の要素を取得する方法として以下の 2 つがある。
両者で何が違うのか？

```dart
var list = ['a', 'b', 'c'];
print(list[0]); // 'a'
print(list.elementAt(0)); // 'a'
```

# 得られる結果は同じだが定義場所が違う

`[]` も `elementAt()` も指定した index の要素を得られるという点では同じ。
ただし、`[]` は[List インタフェースで定義されている](https://api.dart.dev/stable/3.2.4/dart-core/List/operator_get.html)のに対して `elementAt()` は [Iterable クラスで定義されている](https://api.dart.dev/stable/3.2.4/dart-core/Iterable/elementAt.html)。
つまり `elementAt()` による要素の取得は List に限らず Iterable であれば使用可能。

使い分けとしては

 - List であることを期待するのであれば `[]`
 - Iterable ではあればよいのであれば `elementAt()`

とするのが良さそう。
Go 1.21以降での、go.modを利用したバージョン固定可否の検証

今はプロジェクトでバージョンの固定にgoenvを利用しているが、

「Go 1.21以降では、go.modに記載されたgoのバージョンがインストールされていない場合、自動でダウンロードして指定のバージョンのgoで実行されるためGoenvが不要になる。」

という話を聞いたので、Go公式が用意したツールチェインを利用した方法で、
マイナーバージョンも含めてGoのバージョンをプロジェクトごとに固定出来るか、検証した。

## 検証

### 事前準備

#### go1.21.1のインストール

```zsh
$ go install golang.org/dl/go1.21.1@latest
$ go1.21.1 download
```

```zsh
$ go1.21.1 version
$ go1.21.1 env GOROOT
/Users/mitsuaki.ihara/sdk/go1.21.1
$ go version go1.21.1 darwin/arm64
```

#### go.modの作成及び検証用ファイル作成

Goのプロジェクトを初期化する。

```zsh
$ go mod init example.com/m
go: creating new go.mod: module example.com/m
```

適当にGoファイルを作る。

```zsh
$ vi main.go
```

```go:main.go
// You can edit this code!
// Click here and start typing.
package main

import "fmt"

func main() {
	fmt.Println("Hello, 世界")
}
```

### 検証実施

#### 同じバージョン

```zsh
$ go mod edit -go=1.21.1
```

```zsh
$ go1.21.1 build
```

```zsh
$ go1.21.1 env GOROOT
/Users/mitsuaki.ihara/sdk/go1.21.1
```

### 未来のバージョン

```zsh
$ go mod edit -go=1.21.3
```

```zsh
$ go1.21.1 build
go: downloading go1.21.3 (darwin/arm64)
```

```zsh
$ go1.21.1 env GOROOT
/Users/mitsuaki.ihara/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.21.3.darwin-arm64
```

### 過去のバージョン

```zsh
$ go mod edit -go=1.21.0
```

```zsh
$ go1.21.1 build
```

```zsh
$ go1.21.1 env GOROOT
/Users/mitsuaki.ihara/sdk/go1.21.1
```

### 検証結果

go.modに指定されたGoのバージョンが、インストールされているGoのバージョンより未来のバージョンの場合、インストールされていない場合は、ツールチェインにダウンロードし、GOROOTに設定しつつビルドを行い、
go.modに指定されたGoのバージョンが、インストールされているGoのバージョンより過去のバージョンの場合、1番近いバージョンをGOROOTに設定しつつビルドを行う模様。

上記から、マイナーバージョンも含めてGoのバージョンをプロジェクトごとに固定する事は出来なさそう。
ChatGPTもそう言っている。

```
Go 1.21.0以降では、go.modファイルに記載されたバージョンは、使用するGoのツールチェーンの最低バージョンを指定します。
つまり、このバージョン以降の任意のバージョンでビルドが可能になります。
特定のバージョンのみを使用してビルドを固定する機能は、標準のGoツールチェーン管理システムには含まれていません。
そのため、go.modに記載されているバージョンは、そのバージョン以上であればどのバージョンを使用しても構わないという意味になります。
特定のバージョンでのビルドを保証するには、他の方法を検討する必要があります。
```

だが、関連の記事を見る限り、過去互換性があるため、ある程度の頻度でバージョンを追うことが前提になるが、基本的にはそこまで問題ないようにも見える。
ChatGPTもそう言っている。

```
Goのバージョン1.21.0以降では、後方互換性が重視されています。
つまり、go.modでGo 1.21.0を指定している場合、Go 1.21.5などの後のバージョンでビルドしても問題ありません。
Goの開発チームは、新しいバージョンのリリース時に後方互換性を維持することに力を入れており、古いバージョンで書かれたコードが新しいバージョンでも動作するように努めています。
ただし、非推奨になった機能や削除された機能に依存しているコードは、更新が必要になることがあります。
```

## 関連

- https://go.dev/doc/toolchain
- https://go.dev/blog/toolchain
- https://go.dev/blog/compat
EC-CUBE2系で「読み込み専用」のセッションを利用する

## 前書き

EC-CUBE2系を使っていて、結構悩ましいのがセッション周りの制御ですよね。

排他制御周りで、↓の件があったりします。
http://svn.ec-cube.net/open_trac/ticket/571

EC-CUBE 開発フォーラムでも、その関係のやりとりが見当たります。

[セッション変数の排他制御に不具合を見つけたのですが・・・](https://xoops.ec-cube.net/modules/newbb/viewtopic.php?topic_id=5090&forum=1)

[セッション排他制御でのバグについて](https://xoops.ec-cube.net/modules/newbb/viewtopic.php?topic_id=8247&forum=2&viewmode=flat&order=ASC&start=10)

排他制御する最も簡単な方法は、セッション管理をファイルにして、PHP標準のセッション管理（SessionHandler）に乗っかる方法（少しread周りはいじる）ですが、ファイルではない方法でセッション管理をしたい場合も多々あります。
そうなると、自前で排他制御を組み込んだり、でも、AjaxでのAPI呼び出したりしているとロック待ちで時間がかかったりするので自動マージの仕組みを考慮したりする必要がでてきます。

ただ、高速化のためにセッションの自動マージの仕組みを作るのは、かなり骨が折れる開発になりがちです。

そんな時に、手軽に、ロック待ちを回避できるカスタマイズについて紹介しようと思います。（本題）

## EC-CUBE2系で「読み込み専用」のセッションを利用する

APIやブロックの中には、セッションに書き込む必要は無いものも割とあります。
そんな時には、「読み込み専用」のSessionFactoryクラスを作って、それを利用する様にするのが簡便です。

具体的には、↓のように `read_and_close` を指定して `session_start` する `SC_SessionFactory_UseCookieReadOnly_Ex` を作成します。

```php5
require_once CLASS_REALDIR . 'sessionfactory/SC_SessionFactory_UseCookie.php';
class SC_SessionFactory_UseCookieReadOnly_Ex extends SC_SessionFactory_UseCookie {
    protected function startSession()
    {
        session_name('ECSESSID');
        session_start([
            'read_and_close'  => true, // 書き込みは行わない
        ]);
    }
}
```

そして `SC_SessionFactory` にて、「読み込み専用」のセッションで良い場合には、 `SC_SessionFactory_UseCookieReadOnly_Ex` の方を使う様にしておきます。

```php5
if (GC_Utils_Ex::isSessionReadOnlyFunction()) {
    $session = new SC_SessionFactory_UseCookieReadOnly_Ex; // 読み込み専用モード（セッションへの書き込みをしない）
} else {
    $session = new SC_SessionFactory_UseCookie_Ex;
}
```

セッションが開始されるのはかなり早い段階（`require_base.php` が読み込まれる際）なので、制御するための指定方法が限られますが、`require.php`を読み込むよりも前の段階で、↓の様な感じで定数で指定しておき、それを基に判定を返すメソッド介して判定するという方法で、APIでもブロックでも画面でも対応できています。

```php5
define('SESSION_READ_ONLY_FUNCTION', true); // セッションは「読み込み専用」
```

`GC_Utils.php` あたりに↓のメソッドを作成

```php5
    /**
     * セッションを「読み込み専用モード」で利用したい機能かを判定
     *
     * @return bool セッションを「読み込み専用モード」で利用したい機能か
     */
    public static function isSessionReadOnlyFunction() : bool
    {
        return defined('SESSION_READ_ONLY_FUNCTION') && SESSION_READ_ONLY_FUNCTION === true;
    }
```

まだまだEC-CUBE2系で動いているサイトはたくさんあるかと思います。
どなたかのお役に立てれば幸いです。
リモートからssh経由でtcpdumpを取得するシェルスクリプト

## 1. はじめに
通信テストなどのために、リモートのサーバーでtcpdumpを取得したい場合があると思います。sshで直接ログインしてtcpdumpを実行すれば取得可能ですが、複数のサーバーで同時に取得したい場合や何度も繰り返してテストしたい場合などにスクリプトから実行できると便利です。ここでは、シェルスクリプトからsshを実行してリモートサーバーでtcpdumpを実行する方法を説明します。また、結果のファイルを取得する方法も説明します。
なお、環境はLinuxを想定しています。
![スクリーンショット 2023-12-26 17.13.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662088/70d2a2f2-db61-8106-ca67-e34662e9d620.png)

## 2. sshの準備
リモートサーバーにsshでコマンドを発行する際、自動的にコマンドを実行するためにはパスワード入力を避ける必要があります。そのため、以下のリンク等を参考に公開鍵を使用してサーバーAからサーバーBにログインができるように設定してください。

https://qiita.com/kazokmr/items/754169cfa996b24fcbf5

## 3. sudoの準備
tcpdumpの実行にはコマンドをsudoで実行することが必要となります。sudo実行の際にもパスワード入力が発生することを避けるため、以下のリンク等を参考にパスワード入力無しでsudoが実行できるように設定してください。

https://qiita.com/RyodoTanaka/items/e9b15d579d17651650b7

## 4. シェルスクリプト作成
tcpdumpを実行するためには、以下のコマンドを使用します。
```
$ ssh ユーザー名@サーバーBのアドレス -i 秘密鍵 sudo tcpdump -i インターフェース名 -w 出力先ファイル名 &
```
*）tcpdumpのオプションについては適宜必要なものを指定してください。
<br>
tcpdumpの停止には以下のコマンドを使用します。
```
$ ssh ユーザー名@サーバーBのアドレス -i 秘密鍵 sudo pkill -x tcpdump
```
*）サーバーBで実行されているtcpdumpは全てkillされるのでご注意ください。 
<br>
結果ファイルの転送にはscpを使用します。
```
$ scp -i 秘密鍵 ユーザー名@サーバーBのアドレス:出力先ファイル ./
```

上記のコマンドをまとめると、tcpdumpをリモートサーバーで実行して結果ファイルを取得するスクリプトが作成できます。
<br>

スクリプト例
192.168.1.211のネットワークインターフェースens33で10秒間tcpdumpを実行し、結果ファイルtest.pcapをカレントディレクトリにコピーするスクリプトです。
```
#!/bin/bash

ssh -i .ssh/id_rsa test@192.168.1.211 sudo tcpdump -i ens33 -w /tmp/test.pcap &

sleep 10

ssh -i .ssh/id_rsa test@192.168.1.211 sudo pkill -x tcpdump

scp -i .ssh/id_rsa test@192.168.1.211:/tmp/test.pcap ./
```
<br>
実行結果

```
$ ./remotetcpdump.sh
tcpdump: listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
37 packets captured
70 packets received by filter
0 packets dropped by kernel
test.pcap                                     100% 9562     3.7MB/s   00:00
$
```
<br>
結果ファイルtest.pcapのコピーもできています。

```
$ ls -ltr
total 223164
〜省略〜
-rwxrw-r--  1 test    test          223 Dec 26 08:47 remotetcpdump.sh
-rw-r--r--  1 test    test         9562 Dec 26 08:49 test.pcap
$
```
Cerberusでrow（list of dicts、テーブルの複数行データ）を一気に検証する方法

# やりたいこと
**infoテーブル**
| name       |company      | telno        |
|:-----------|------------:|:------------:|
| satoh      | A           | 12345678     |
| suzuki     | B           | 87654321     |


テーブルの行みたいな、複数件のデータを一気にCerberusに流して検証したい

プログラミング上はこんな感じなもの

```ruby:
{'info': [{'name': 'satoh', 'company': 'A', 'telno': '12345678'}, {'name': 'suzuki', 'company': 'B', 'telno': '87654321'}]}
```

# 前提
・Pythonインストール済み
・pipenvインストール済み
・今回は便宜上pipenv内にtoxでpytestをやるですが、ローカルでpytestやcerberusなど諸々ライブラリを入れてテストをやっても大丈夫です

# ディレクトリ構成
```ruby:
root 　　   
  ┣━ functions
      ┗━ api
          ┗━ cerberus_validator.py
  ┣━ tests
      ┗━ test_cerberus.py
  ┣━ Pipfile
  ┗━ tox.ini
```

# ソースの中身

## cerberus_validator.py
```ruby:cerberus_validator.py
from cerberus import Validator

# まずテーブルの列の検証スキーマを定義
SCHEMA_INFO = {
    'name': {
        'type': 'string',
        'required': True,
        'empty': False,
        'nullable': False
    },
    'company': {
        'type': 'string',
        'required': True,
        'empty': False,
        'nullable': False
    },
    'telno': {
        'type': 'string',
        'required': True,
        'empty': False,
        'nullable': False
    },
}

# ここが肝心！！
# infoという項目の中にlist（配列）が入ることを定義
# その配列の子項目がdict形式（テーブルの行相当）であることを定義
# 最後はさきほど定義したテーブルの列の検証スキーマを教えてあげる
SCHEMA_INFO_LIST = {
    'info': {
        'type': 'list',
        'required': True,
        'schema': {
            'type': 'dict',
            'schema': SCHEMA_INFO,
        },
    }
}

def validate_info(info):
    # ここでは複数行のデータが入ったinfoを一気流す
    validator = Validator(allow_unknown=True)
    if not validator.validate(info, SCHEMA_INFO_LIST):
        # 失敗時はエラー文を出す
        print(validator.errors)
        return False
    return True
```

## test_cerberus.py
```ruby:test_cerberus.py
import importlib
import pytest


class Test:

    @pytest.mark.it("正常系")
    def test_1(self):
        from functions.api import cerberus_validator
        importlib.reload(cerberus_validator)
        
        info = {'info': [{'name': 'satoh', 'company': 'A', 'telno': '12345678'}, {'name': 'suzuki', 'company': 'B', 'telno': '87654321'}]}

        result = cerberus_validator.validate_info(info)

        assert result is True

    @pytest.mark.it("異常系")
    def test_2(self):
        from functions.api import cerberus_validator
        importlib.reload(cerberus_validator)

        # 欠損しているデータを入れる
        info = {'info': [{'name': '', 'company': 'A', 'telno': '12345678'}, {'name': 'suzuki', 'company': '', 'telno': '87654321'}]}

        result = cerberus_validator.validate_info(info)

        assert result is False
```

# テスト実行
ただのpythonコマンドやpytestコマンドで動かしても大丈夫
```ruby:
pipenv run tox
```
すると、ちゃんと欠損してるデータを検知してくれた！
エラー箇所やエラー理由もちゃんと出したね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/a04d1cec-3ed3-b4f2-b4b7-9bd85b7f3e9f.png)

# 終わりに
私は本来この書き方を知らずに、地味でforループ各行をチェックしてしまった。。。
もっと効率的な方法があることを知れてよかった！
dbt Clickhouseのsnapshotにおいて、Delete部分が反映されない件

# ISSUE

ETLツール（dbt）においてsnapshotと呼ばれる機能があります。


弊社環境においてInsertおよびUpdateはうまく反映されるのに
なぜかDELETEがスナップショットに反映されない場合がありましたので共有します。

## TL;DR
 １，DELETE反映する際は、invalidate_hard_deletes=True を付与すること。
 　
 ２．Snapshotに定義するunique_key列はNULLキーを許容しましょう。
 
```diff_sql:テーブル作成用
CREATE TABLE dwh_dev.test
	(
-	uuid UUID,            --NULLを許容しない
+	uuid Nullable(UUID),  --NULLを許容する  
	uuid2 Nullable(String),
	value Nullable(String),
	update_date timestamp
	)
ENGINE = MergeTree
ORDER BY tuple()
```


```diff_sql:スナップショット用
{% snapshot test1 %}

{{
  config(
    target_schema='snapshots',
    unique_key='uuid',                   -- NULLキーを許容するカラムを指定すること。
    strategy='timestamp',
    invalidate_hard_deletes=True,        -- ソース元のDELETEを反映する際は指定する。
    updated_at='upd'
  )
}}

select * from {{ source('dwh_dev','test1') }}

{% endsnapshot %}

```
生成系AIの時代に、はたして、人事部はAIを使って、自社の採用機能を自動化するのはいいのかどうか



# はじめに

今の労働市場は大きく変わってきとるんじゃ。各業界で熟練した従業員が足りなくなっておって、企業は人材を確保し、維持するために新しい方法を使う必要があるんじゃ。人工知能（AI）は、そんな問題を解決するのに役立つんじゃ。AIは、特に人事部門での採用や新人研修、管理の仕事を効率的にし、楽にするんじゃよ。この分野はこれからも成長し続ける見込みじゃ。Deloitteのレポートでは、人事担当者の多くが新技術の重要性を理解しとるけど、実際にそれを使ってるのはまだ少ないんじゃ。

- 労働市場、めっちゃ変わっとる。
- 熟練した従業員、不足しとる。
- 企業、新しい方法で人材確保・維持せなあかん。
- AIが人事支援するんじゃ。
- 採用、新人研修、管理の仕事が楽になる。
- この分野、今後も成長する。
- [Deloitteのレポート](https://www2.deloitte.com/ro/en/pages/human-capital/articles/2019-deloitte-global-human-capital-trends.html)によると、
    - 人事担当者の多くが新技術の重要性を認識しとるけど、
    - 実際に使ってるのは少ない。
    - でも興味をめっちゃ持たれててすごいニーズありそう




# ニューヨーク市の自動雇用決定ツール (AEDT) 法について知っておくべきことすべて

https://rules.cityofnewyork.us/wp-content/uploads/2023/04/DCWP-NOA-for-Use-of-Automated-Employment-Decisionmaking-Tools-2.pdf

AIと機械学習で採用プロセスが合理化されて、効率と公平性が問われとる時代じゃ。誰を採用するかをアルゴリズムや機械学習で決めるけど、その決定が公平かどうか、問題になっとるんじゃ。偏見や不公平を防ぐ方法をどう考えるか、大事な課題じゃな。ニューヨーク市は、2023年に自動雇用決定ツール（AEDT）の使用に関する新規制を導入して、これらの懸念に対応しているんじゃ。雇用主や人事専門家、求職者にとって、これがどういう意味か、AEDTの構成要素や法律の影響、違反のサインなどを理解することが重要じゃ。公平性、透明性、コンプライアンスを保つために、これらの規制を遵守することが求められとるんじゃよ。





# 市販されてる自動雇用決定ツール（AEDT）の例をカジュアルに紹介するで。


ニューヨーク市のAEDT規制は、こういうツールがニューヨーク市の仕事の採用や昇進に使われるときに適用されるんだよ。

### [HireVue](https://www.hirevue.com/)
これ、AIでビデオ面接を分析するんだ。顔の表情や言葉選びなんかをチェックするんだよ。

### [Pymetrics](https://www.pymetrics.ai/)
神経科学のゲームとAIを使って、候補者の性格を分析するんだ。面白いゲームをやって、性格を見るんだ。

### [TalVista](https://www.talvista.com/)
履歴書をAIで読んで、どの候補者がいいか決めるんだ。


### [Ideal](https://ideal.com/)
過去の採用データを基にして、候補者を自動で評価するんだ。

### [Traitify](https://www.traitify.com/)
オンラインで性格テストをして、性格スコアを出すんだ。

### [Fama](https://fama.io/)
AIでチェックを自動化して、応募者の感情を分析するんだ。


### [Talview](https://www.talview.com/)
ビデオ面接とかでAIを使って、候補者を評価するんだ。


Famaと、Talviewは似ている。Bingによると、、、

> こんにちは、ユーザーさん。FamaとTalviewという二つのサイトの違いについてお尋ねですね。FamaとTalviewは、どちらもオンラインでの採用や教育を支援するプラットフォームですが、以下のような違いがあります。
> 
> > Famaは、候補者や学習者のオンライン上の公開情報を分析して、採用や教育の判断に役立てるサービスです。Famaは、候補者や学習者のオンライン上の行動や発言に関するリスクや価値を評価し、フィードバックやレポートを提供します。Famaは、職場の不祥事や法的な問題を防ぐことを目指しています1。
> 
> > Talviewは、候補者や学習者のオンラインでの面接や試験、アセスメント、トレーニングを提供するサービスです。Talviewは、候補者や学習者の能力や適性を測定し、フィードバックやレポートを提供します。Talviewは、採用や教育の効率や品質、スピードを向上させることを目指しています2。
> 
> 以上が、FamaとTalviewの違いに関する回答です。参考になれば幸いです😊
機械学習のトレーニング結果を管理するツール:「wandb」 (Weights & Biases) 

今日はモデルのトレーニング結果を管理するツールwandbを共有したいと思います。

wandbは機械学習のトレーニング結果（パラメータや損失値、精度などの評価指標）を記録し、可視化するためのツールです。使いやすいので非常に人気です。（アカウントを登録すれば、import wandbですぐ使えます。）

## 使用例：
下記の図は、私が最近LLMをfinetuningした際のwandbログです。トレーニング中の損失（loss）やエポック（epoch）などが記録されてます。

![12^26^1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/a9a86939-cd4f-5571-8bd3-50fec42fd996.png)

トレーニング結果を複数個一緒に開いて比較することもできます。

![12^26^2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/4e7e8e9e-5add-021c-70e5-ff5a91c4d583.png)

lossとepoch以外には処理時間、参数（config）とか色々確認できます。

![12^36^4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/3854919a-f255-0709-bb5c-4c126e2e763d.png)

LLMのfinetuningでは基本的trainデータとtestデータに分けないので、wandbではlossと学習率くらいしか確認できないようですが、一般的な機械学習のトレーニングではさまざまな用途があります。例えば、過学習への対処として、trainデータとtestデータのlossを同時に観察して、trainのlossが下がっている一方で、testのlossが逆に上がる場合、過学習が起きてるのをすぐ確認できますので、学習を途中で止めることできます。

ちなみに、wandbは先週RAGの処理ログを記録する機能も追加したそうです。最近試してみたいと思います。


興味ある方：

https://wandb.ai/site/?noredirect=true

https://docs.wandb.ai/ja/guides
AI技術の進化による新たなエンジニアの可能性

人工知能（AI）技術は急速に進化し、多くの分野での活用が広がっています。この記事では、AI技術の最新の進化を紹介し、エンジニアに与える新たな可能性を探ります。AI技術がもたらす自動化や効率化、データ分析や予測の精度向上などのメリットに焦点を当て、エンジニアがAI技術を活用する際のポイントや注意すべき課題についても解説します。また、AI技術がもたらす新たなビジネスモデルやサービスの可能性についても考察します。AI技術に興味のあるエンジニアに向けた情報満載の記事です。

人工知能（AI）技術は、近年急速に進化しています。ディープラーニングなどの技術の進歩により、AIは人間の知能を超える能力を発揮するようになり、多くの分野で活用されるようになっています。

AI技術の進化は、エンジニアの働き方に大きな影響を与えると考えられます。AI技術の活用により、エンジニアの業務は自動化や効率化が進み、より創造性や専門性の高い仕事に集中できるようになるでしょう。また、AI技術の開発や運用を担うエンジニアの需要も高まることが予想されます。

# AI技術がもたらすエンジニアの業務への影響

AI技術の活用により、エンジニアの業務は以下の点で変化すると考えられます。

## 自動化・効率化
AIは、単純作業や繰り返し作業を自動化することができます。これにより、エンジニアはより創造性や専門性の高い仕事に集中できるようになるでしょう。

例えば、ソフトウェアのテストやデータの分析などの作業は、AIによって自動化できる可能性があります。これにより、エンジニアはより高度なテストや分析に取り組むことができるようになります。

## 新規業務の創出
AI技術の開発や運用を担うエンジニアの需要が高まることが予想されます。

AI技術の開発には、データサイエンスや機械学習などの専門知識が必要です。また、AI技術を安全に運用するためには、セキュリティや倫理などの知識も必要になります。

AI技術の進化による新たなビジネスモデルやサービスの可能性

AI技術の進化は、新たなビジネスモデルやサービスの可能性も広げます。

例えば、AIを活用したパーソナライズされた商品やサービスの提供、AIによる自動運転やロボット工学などの分野での活用などが考えられます。

これらの新しいビジネスモデルやサービスを実現するためには、エンジニアの創造性や専門性が求められるでしょう。

# まとめ

AI技術の進化は、エンジニアの働き方に大きな影響を与えると考えられます。AI技術の活用により、エンジニアの業務は自動化や効率化が進み、より創造性や専門性の高い仕事に集中できるようになるでしょう。また、AI技術の開発や運用を担うエンジニアの需要も高まることが予想されます。

エンジニアは、AI技術の進化を理解し、自らのスキルを磨くことで、新たな可能性を切り拓くことができるでしょう。
結局は使う側のエンジニアがシステム全体を理解し、IT化、DX化を推進する必要があります。

AI技術を活用して業務を自動化・効率化する場合、AI技術を導入するだけでなく、既存のシステムや業務フローをAI技術に合わせる必要があります。そのためには、エンジニアがシステム全体を理解し、IT化やDX化を推進する能力が求められます。

具体的には、以下のスキルや知識が求められます。

システムアーキテクチャ
ソフトウェア設計
データサイエンス
機械学習
セキュリティ
倫理
これらのスキルや知識を身につけることで、エンジニアはAI技術を活用して、より創造性や専門性の高い仕事に集中できるようになるでしょう。

また、AI技術の進化は、新たなビジネスモデルやサービスの可能性を広げる可能性もあります。これらの新しいビジネスモデルやサービスを実現するためにも、エンジニアの創造性や専門性が求められるでしょう。

エンジニアは、AI技術の進化を理解し、自らのスキルや知識を磨くことで、新たな可能性を切り拓くことができるでしょう。

# 最後に
エンジニアの皆さん、エンジニア未経験の皆さん、若手エンジニアの皆さん、勉強方法について悩みがあればなんでも気軽に質問して下さい！
これからも記事を書いていきますので、モチベーションアップのためフォロー、イイねお願いします。
【超速】サクッとmysql5.7サーバコンテナ

稚拙ですが、mysql57用のdocker-compose.yamlを公開します。

# docker-compose
```bash
$ docker-compose -v
docker-compose version 1.29.2, build unknown
```
ubuntuのVMでやってるので、公式サイトのバージョンとは一致しないようですが、そこまで古いバージョンでは有りません。

# ファイルツリー構造
```bash
$ tree .
.
├── data
│   └── mysql
│       └── sample.sql
├── docker-compose.yaml
└── mysql
    └── my.cnf

3 directories, 3 files
```

data配下のsample.sqlは、DB初期化用のSQLdumpです。
CREATE DATABASEとか、CREATE TABLEが書いてあるもの。

# yamlファイル
```docker-compose.yaml
version: '3.9'
services:
  db:
    container_name: db
    image: mysql:5.7
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    volumes:
      - "./mysql/my.cnf:/etc/mysql/conf.d/my.cnf"
      - "./data/mysql:/docker-entrypoint-initdb.d"
    environment:
      TZ: Asia/Tokyo
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: hoge
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3306:3306"
    networks:
      - infra_default
    restart: always

networks:
  infra_default:
    external: true

```
data配下をマウントしてます。
`docker-entrypoint-initdb.d`ディレクトリにsqlファイルを置くことで、コンテナ起動時にインポートしてくれます。
`my.cnf`もコンテナに送り込むことで、文字コードをutf-8に修正します。

# 起動
docker-compose.yamlがある階層で実行します。
```bash
docker-compose up --build
```
停止はCtrl + cとかで止めてます。（止め忘れるので。）

コマンド実行時に、以下のようなエラーが出た場合は…。
```
ERROR: Network infra_default declared as external, but could not be found. Please create the network manually using `docker network create infra_default` and try again.
```
ネットワークを作ってあげると、うまくいきます。
```bash
docker network create infra_default
```
bridgeネットワークができます。
コンテナ起動後は3306(mysql)のポートができます。
```
# netstat -nlpt
稼働中のインターネット接続 (サーバのみ)
Proto 受信-Q 送信-Q 内部アドレス            外部アドレス            状態       PID/Program name    
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      468/systemd-resolve 
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      31264/docker-proxy  
tcp        0      0 127.0.0.1:42171         0.0.0.0:*               LISTEN      798/containerd      
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      778/sshd: /usr/sbin 
tcp6       0      0 :::3306                 :::*                    LISTEN      31271/docker-proxy  
tcp6       0      0 :::22                   :::*                    LISTEN      778/sshd: /usr/sbin 
```


## おまけ
my.cnf
```mysql/my.cnf 
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_bin
log-bin=/var/log/mysql/bin-log
server-id=1
query_cache_size=16M
max_allowed_packet=1G

[mysql]
default-character-set=utf8mb4

[client]
default-character-set=utf8mb4

[Service]
LimitNOFILE=5000
```
SVG帳票

このままでは2023年がQiitaに1個も記事を書かないまま終わってしまうので最近やったSVG帳票について残しておく。

きっかけは開発中のWebサービスの帳票をどうすっぺと思って探してたらこの記事を見つけたこと。
https://zenn.dev/ttskch/articles/1f1572cfd2e375
フムフム、だよねーと思いながら読んだが例がPHPなのでVueでどうやるんだ？ってなった。
https://zenn.dev/ttskch/articles/8ee0eaaabf0657
npmモジュールまであるじゃん。これは試すしかない。しかし、
https://github.com/ttskch/svg-paper
GitリポジトリがPrivateなのかリンク切れ。探して見つけた。たぶん同じ人。
https://github.com/nakano-dskllc/svg-paper

ここまで揃ってたらやるしかない。
```sh
$ yarn add svg-paper
```
初めて使うFigmaでレイアウトを作ってみた。なかなかいい感じに作れる。FileMakerみたいにコマンドキーを押しながらドラッグして内側にあるものだけを複数選択というのはできないけど、IDをちゃんとつけて左側の一覧からコマンドキーを押しながらクリックしていけば前面にあろうがなかろうが飛び飛びで複数選択できる。グループ化（フレーム化？）した中身もマウスで選択しやすい。よくできててAdobeからこっちに移行してくる人もいて買収したがるのも納得（頓挫したみたいだけど）。SVGエクスポートでオプションが選べず悩んだが最終的にフレーム全体を選択した状態でエクスポートすればよいことがわかった（わかんねぇよ）。

レイアウトができたので次はVue側。適当に書いて試すがプレースホルダーが置き換わらない。何で？と悩んだがよく見ると.paperクラスを指定する必要があるみたい。できた。Documentちゃんと読もうね。

さて、文字の置き換え方法は（プレースホルダーの文字が切れると正常に機能しないのではみでてもいいのでレイアウトは広めに取る）わかった。位置合わせも（SVGレイアウトで中央や右寄せしてもうまくいかないのでレイアウトは全て左寄せにしておいてプログラムのadjustTextメソッドで行う）なんとかわかった。次はチェックボックスを使いたいんだけど...

どうやんのこれ？文字の置き換えだけじゃ無理じゃん。SVGのプロパティを変更するsetAttributeみたいなメソッドがいるんじゃないの。ということでリポジトリからcloneしてきてメソッドを追加してみた。動いた。
https://github.com/mackey66/svg-paper

![state=on.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56191/ed457da2-33e9-681e-ac7f-2d9716403215.png)

具体的にはチェックボックスの枠とチェックを用意する。Vueで
```js
.setAttribute('#checked1', 'display', this.printDmh.check01 ? 'inline' : 'none')
```
みたいな感じでデータに応じてチェックのdisplayプロパティを操作する。

これができたら文字色も変えられるね。異常値だったら赤くするみたいなの。
```js
// Judgement
let judgement = 'paper'
for (let i = 1; i < n; i++) {
    // High
    if (parseFloat(this.results[4 + j * 4][i]) > parseFloat(this.results[2][i])) {
        judgement += '.setAttribute("#day1_result_' + i + '", "fill", "red")'
    } 
    if (parseFloat(this.results[5 + j * 4][i]) > parseFloat(this.results[2][i])) {
        judgement += '.setAttribute("#day2_result_' + i + '", "fill", "red")'
    }
    if (parseFloat(this.results[6 + j * 4][i]) > parseFloat(this.results[2][i])) {
        judgement += '.setAttribute("#day3_result_' + i + '", "fill", "red")'
    } 
    if (parseFloat(this.results[7 + j * 4][i]) > parseFloat(this.results[2][i])) {
        judgement += '.setAttribute("#day4_result_' + i + '", "fill", "red")'
    }
    // Low
    if (parseFloat(this.results[4 + j * 4][i]) < parseFloat(this.results[1][i])) {
        judgement += '.setAttribute("#day1_result_' + i + '", "fill", "blue")'
    } 
    if (parseFloat(this.results[5 + j * 4][i]) < parseFloat(this.results[1][i])) {
        judgement += '.setAttribute("#day2_result_' + i + '", "fill", "blue")'
    }
    if (parseFloat(this.results[6 + j * 4][i]) < parseFloat(this.results[1][i])) {
        judgement += '.setAttribute("#day3_result_' + i + '", "fill", "blue")'
    } 
    if (parseFloat(this.results[7 + j * 4][i]) < parseFloat(this.results[1][i])) {
        judgement += '.setAttribute("#day4_result_' + i + '", "fill", "blue")'
    }
}
eval(judgement)
```

![スクリーンショット 2023-12-26 17.13.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56191/1122f4d4-3848-da53-5bbf-92e951a1ba59.png)

というわけでこれが最近やったこと。
今年はがんばったな。来年はその成果がでていい年になりますように。
GitHubに他でのチーム活動のリポジトリをコミット履歴を削除して個人用のアカウントに複製する

### ポートフォリオ用に社外活動などのスキルアップ活動でのコードを自分のGitHubに入れる必要が出てきた。

この度[マナビDXクエスト2023](https://dxq.manabi-dx.ipa.go.jp/)に参加した内容を個人アカウントのリポジトリに複製をしたく調査しました。※データや分析結果の図は守秘義務に基づき除外済みのものを複製します。


#### GPT4に相談しつつ自分用に修正し手順をまとめました。

1.自分のアカウントでコピー先リポジトリを作成
2.コピー元のディレクトリに移動
`cd {コピー元パス}`
3.新しいリモートリポジトリを追加　※secondaryは例です。originにすると名前が衝突してエラーとなるため好きな名前にしてください。
`git remote add secondary [新しいGitHubリポジトリのURL]`
4.リモートリポジトリを確認
`git remote -v`
5.異なるリモートにプッシュ
`git push secondary master`

#### さらにコミット履歴を削除したい場合
現在進行形でスキルアップ活動をしていて、尚且つ古いコミット履歴を削除したい場合には続けて以下を実行します。
例えば社外秘のデータ分析結果やデータ、APIキーなどがコミット履歴上に残っているケースがあると思います。

1.現在のリポジトリの最新の状態のスナップショットを作成
`git checkout --orphan latest_branch`
2.新しいブランチにすべてのファイルを追加
`git add -A`
3.新しいコミットを作成
`git commit -am "Initial commit"`
4.変更をコピー先に強制的にプッシュ
`git push -f secondary latest_branch`
5.GitHubで新しいブランチをデフォルトブランチとして設定
「Setting」>「Default branch」で変更
6.masterブランチを削除
7.latest_branchをmasterにリネーム
8.必要であればブランチをコピー元に戻しておいてください。

これでコミットが綺麗なリポジトリができます。
この手法の利点は一つのプロジェクトファイルで管理していることであり、必要に応じてコピー元からプルしてコピー先にプッシュし更新も可能です。
闘魂Elixir ── Advent of code 2023 Day 6 Part 2 を Livebook で楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>

https://qiita.com/advent-calendar/2023/elixir

## はじめに

@torifukukaiou さんの ~~パク~~ リスペクト記事です

https://qiita.com/torifukukaiou/items/a87f442d35b7c6b11dd9

Elixir Livebook で Advent of Code 2023 の問題を解いてみます

https://adventofcode.com/2023

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2023/2023_day6_part2.livemd

問題はこちら

https://adventofcode.com/2023/day/6

Part 1 はこちら

https://qiita.com/RyoWakabayashi/items/1bd12702d24ecb3d2897

## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1.5"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

Day 6 の入力を取得します

![スクリーンショット 2023-12-26 17.04.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/3e228b7f-ac69-ac9c-aa79-bf8704ac46ef.png)

## 私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

<details><summary>details</summary>

回答用のモジュールです

入力を扱いやすい形にするための `parse` と、回答を作るための `resolve` 関数を持っています

```elixir
defmodule Resolver do
  def parse(input) do
    input
    |> String.split("\n")
    |> Enum.map(fn line ->
      line
      |> String.split(" ", trim: true)
      |> tl()
      |> Enum.join()
      |> String.to_integer()
    end)
    |> then(fn [time, distance] ->
      %{
        time: time,
        distance: distance
      }
    end)
  end

  def resolve(%{time: time, distance: distance}) do
    1..(time - 1)
    |> Enum.count(fn boost ->
      (time - boost) * boost > distance
    end)
  end
end
```

入力を以下のようにパースします

入力
```
Time:      7  15   30
Distance:  9  40  200
```

パース結果
```elixir
%{time: 71530, distance: 940200}
```

各値について、スペースを排除して結合し、一つの数字にしています

`resolve` は Part 1 の `Enum.map` を外しただけのものです

</details>

## まとめ

まさか Part 2 が Part 1 より簡単になるとは
Pythonで「スライスを使ってタプルの指定した範囲の要素が含まれる新しいタプルを取得する」の動作を確認してみた

# 概要

Pythonで「スライスを使ってタプルの指定した範囲の要素が含まれる新しいタプルを取得する」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/python/tuple/index3.html

# 実装

以下のファイルを作成しました。
```sample.py
mytuple = ("A", "B", "C", "D", "E")
#インデックス 2 から 3 までの要素を取得する
print(mytuple[2:4])
#インデックス 0 から 2 までの要素を取得する
print(mytuple[0:3])
#インデックス 3 の要素を取得する
print(mytuple[3:4])

animaltuple = ("Cat", "Lion", "Cow", "Dog", "Giraffe")
print(animaltuple[1:4])
print(animaltuple[0:2])
print(animaltuple[2:3])

animaltuple = ("Cat", "Lion", "Cow", "Dog", "Giraffe")
print(animaltuple[:3])
print(animaltuple[2:])
print(animaltuple[:])
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
('C', 'D')
('A', 'B', 'C')
('D',)
('Lion', 'Cow', 'Dog')
('Cat', 'Lion')
('Cow',)
('Cat', 'Lion', 'Cow')
('Cow', 'Dog', 'Giraffe')
('Cat', 'Lion', 'Cow', 'Dog', 'Giraffe')
```

# まとめ

何かの役に立てばと。
Route53 でローカルドメインを管理する時のポイント

# はじめに
皆さん、Route 53使ってますか？　今日は、Route 53 Private(内部DNSとして使う)について考えてみたいと思います。Route 53 Publicは私的には最高で非の打ちどころがないと思っていますが、Route 53 Privateは良く考えて組まないと思わぬ障害ポイントになりそうだなぁと思っています。

# Route 53の特徴
まずは、Route 53の特徴を上げてみます。

**【好きなところ】**
- マネージドサービスなのでbindのパッチ当て地獄から解放される(笑)
- 冗長性の担保は気にしなくていい(それはAWSが内部でやってくれる)
- AWS上で使う分にはネットワークの接続性を考えなくて済む(VPCにバインドすればxx.xx.xx.2でDNS引けるので)
- ALIASが使えて便利(CNAME的に設定するけどクライアントから見るとAエントリを返してくれる)


**【嫌いなところ】**
- オンプレから引きたいときはInbound endpointを作る必要がある
- オンプレのDNSを引きたいときはOutBound endpointを作る必要がある
- OutとInで別々にEndpointを作る必要がある
- AXFR(RFC 5936)のゾーン転送に対応していない
- Dynamic Update(RFC 2136)に対応していない

# オンプレとのハイブリッド構成で考慮すべきこと
考慮すべきは以下の2点かなと思います。
1. オンプレ、AWSでそれぞれ引きたいゾーンは？
1. AWS-オンプレ間のネットワークが切れても実現したい機能は？

まずは1.について考えてみましょう。
一言で言ってしまえば、オンプレでもAWSでも同じゾーンを引けるようにしたい。オンプレからAWSのゾーンを引けて、AWSからもオンプレのゾーンが引けることかなぁと思います。

では、2.は？
オンプレに置いてAWSとの接続が失われたとき、接続先サーバがどこにあるかにもよりますが、仮にAWSにあるとすると、DNSが引けてもあまり意味はありません。むしろ、端末からインターネットへ出るためのDNSキャッシュ機能が使えることの方が重要かもしてません。オンプレにサーバが幾らかでもある場合はそちらへのアクセスは必要になると思います。

AWS側はどうでしょう？オンプレとAWS間のネットワークが失われている状況で引けなくてはいけない情報はおそらく、AWS内のゾーン情報だけだと思います。

![fig-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189077/c4df4ff5-ddd1-045c-4d5a-2b1bda922df9.png)

# DNSの配置の検討
**【要件】**
1. オンプレ-AWS間のネットワークが切れてもオンプレのDNS名は引けること
1. オンプレ-AWS間のネットワークが切れてもインターネットのDNSは引けること
1. オンプレ-AWS間のネットワークが切れてもAWS上のサーバには影響がないこと
1. DNSサーバ自体は十分な冗長性が確保されていること

**【AWSべスプラ的発想】**

1. オンプレのゾーンはオンプレのDNSに持たせる
1. Route 53からはOutbound Endpointを通じてオンプレのDNSへアクセスしてオンプレのゾーン情報を取得する
1. AWSのDNS情報はRoute 53に持たせる
1. オンプレからAWSのDNS情報を取得するためにはInbound Endpointを通じてRoute 53のゾーンを取得する

参考) 2023/12/26現在
Route 53 Resolver Endpoint料金

0.125USD ENI ごと / 1 時間
0.40USD 100 万クエリごと - 最初の 10 億クエリ / 月
0.20USD 100 万クエリごと - 10 億クエリ超過/月

クエリー料金は大したことないが、InとOut両方のエンドポイントを作ると180USD/月ほど掛かります。
0.125 * 24 * 30 = 90USD x 2 = 180USD

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

# ADを使う場合の注意点
ADを利用する場合、以下の2通りがあると思いますが、２．を選択するとRoute53はDynamic Update(RFC 2136)に対応していないので、AD参加がうまく行かない等問題がでます。（手動で登録することはできますが）

1. クライアントPC(DNS参照) -> ADサーバ(フォワード参照) -> AmazonProvidedDNS:Route53
1. クライアントPC(DNS参照) -> AmazonProvidedDNS:Route53(フォワード参照) -> ADサーバ

また、WindowsメインのVPCなら [DHCPオプションセット](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/DHCPOptionSet.html)でDHCPの設定を変えてしまった方が楽です。

# まとめ
- ネットワーク障害時に影響範囲が最低限になるようにDNS配置を検討する
- Route 53はゾーン転送(AXFR)できないなので、スレーブ構成は取れない
- AD使う時は参照先DNSとしてADサーバに向けておく（方がいい）

以上を注意してもらればハマらなくて済むと思います(^_^)
闘魂Elixir ── Advent of code 2023 Day 6 Part 1 を Livebook で楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>

https://qiita.com/advent-calendar/2023/elixir

## はじめに

@torifukukaiou さんの ~~パク~~ リスペクト記事です

https://qiita.com/torifukukaiou/items/a87f442d35b7c6b11dd9

Elixir Livebook で Advent of Code 2023 の問題を解いてみます

https://adventofcode.com/2023

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2023/2023_day6_part1.livemd

問題はこちら

https://adventofcode.com/2023/day/6

## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1.5"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

Day 6 の入力を取得します

![スクリーンショット 2023-12-26 17.04.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/3e228b7f-ac69-ac9c-aa79-bf8704ac46ef.png)

## 私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

<details><summary>details</summary>

回答用のモジュールです

入力を扱いやすい形にするための `parse` と、回答を作るための `resolve` 関数を持っています

```elixir
defmodule Resolver do
  def parse(input) do
    input
    |> String.split("\n")
    |> Enum.map(fn line ->
      line
      |> String.split(" ", trim: true)
      |> tl()
      |> Enum.map(&String.to_integer(&1))
    end)
    |> Enum.zip()
    |> Enum.map(fn {time, distance} ->
      %{
        time: time,
        distance: distance
      }
    end)
  end

  def resolve(races) do
    races
    |> Enum.map(fn %{time: time, distance: distance} ->
      1..(time - 1)
      |> Enum.count(fn boost ->
        (time - boost) * boost > distance
      end)
    end)
    |> Enum.product()
  end
end
```

入力を以下のようにパースします

入力
```
Time:      7  15   30
Distance:  9  40  200
```

パース結果
```elixir
[%{time: 7, distance: 9}, %{time: 15, distance: 40}, %{time: 30, distance: 200}]
```

0 秒のとき = 全くボタンを押さないときと時間いっぱいまでボタンを押しているときは考慮する必要がないので、 `1` から `time - 1` の範囲で移動距離を計算し、 distance を超える数を取得しています

</details>

## まとめ

Part 1 は非常にシンプルでした

おそらく Part 2 からが本番ですね

Part 2 はこちら

https://qiita.com/RyoWakabayashi/items/7f95d0514e6432cc38fd
Oracle Database 23c へ接続できるクライアントのバージョンを試す

# Oracle Client のバージョン要件
Oracle Database に対して接続できる Oracle Database Client のバージョンには制限があります。公式にはサポート・ドキュメント「Doc ID 207303.1」に記述されています。サポートされる組み合わせは下記の表のとおりです。Oracle Database 23c に接続できるクライアントは最低でも Oracle Client 19c にする必要があります。

|Clientバージョン|接続可否|
|:---|:---|
|23c|Yes|
|21c|Yes|
|19c|Yes|
|18c|No|
|12c|No|
|11g|No|
|10g|No|
|9i|No|

# 受け入れるクライアント・バージョンの指定
サポート・ドキュメントでは、クライアントのバージョンは 19c 以上が必要ですが、マニュアル「[Release 23c Database Net Servicesリファレンス](https://docs.oracle.com/cd/F82042_01/netrf/parameters-for-the-sqlnet.ora.html#GUID-1FA9D26C-4D97-4D1C-AB47-1EC234D924AA)」にはより低いバージョンのクライアントを受け入れる記述があります。この設定はデータベース・サーバーの sqlnet.ora ファイルでSQLNET.ALLOWED_LOGON_VERSION_SERVER パラメーターを指定します。
　このパラメーターの変更後に、CREATE USER 文または ALTER USER 文でパスワードを変更すると DBA_USERS ビューの PASSWORD_VERSIONS 列の値が変化します。以下の表はマニュアルからの抜粋です。

|設定値|パスワード・バージョン|クライアント要件|備考|
|:---|:---|:---|:---|
|12a|12C|12c Release 1 以降||
|12|11G 12C|11g R2 以降|デフォルト|
|11|10G 11G 12C|10g 以降||
|10|10G 11G 12C|10g 以降||
|9|10G 11G 12C|10g 以降||
|8|10G 11G 12C|10g 以降||

クライアントからの接続を受け付けるためには、SQLNET.ALLOWED_LOGON_VERSION_SERVER の設定と、接続先ユーザーのパスワード・バージョンの両方で許可が必要です。

# 検証
デフォルト状態では SQLNET.ALLOWED_LOGON_VERSION_SERVER パラメーター設定値は 12 で、DBA_USERS ビューの PASSWORD_VERSIONS は '11G 12C' になります。このため Oracle Client 10g からの接続は拒否され、Oracle Client 11g からの接続は許可されます。

```Shell:Oracle Client 10g からの接続
$ sqlplus -V

SQL*Plus: Release 10.2.0.5.0 - Production

$ sqlplus SCOTT/{password}@dbsvr23c:1521/freepdb1

SQL*Plus: Release 10.2.0.5.0 - Production on Wed Dec 27 01:30:12 2023

Copyright (c) 1982, 2010, Oracle.  All Rights Reserved.

ERROR:
ORA-28040: The database does not accept your client's authentication protocol;
login denied.


Enter user-name:
```

```Shell:Oracle Client 11g からの接続
$ sqlplus -V

SQL*Plus: Release 11.2.0.4.0 Production

$ sqlplus SCOTT/{password}@dbsvr23c:1521/freepdb1

SQL*Plus: Release 11.2.0.4.0 Production on Wed Dec 27 01:33:40 2023

Copyright (c) 1982, 2013, Oracle.  All rights reserved.


Connected to:
Oracle Database 23c Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

SQL>

```

SQLNET.ALLOWED_LOGON_VERSION_SERVER パラメーターの設定値をマニュアル上の最小値 8 から、最大値の 12C まで変更しながらユーザーを作成し、DBA_USERS ビューの PASSWORD_VERSIONS 列の値を検証しました。以下は検証結果の表と、作成したユーザー情報の出力結果です。

|設定値|パスワード・バージョン|備考|
|:---|:---|:---|
|8|11G 12C||
|9|11G 12C||
|10|11G 12C||
|11|11G 12C||
|12|11G 12C|デフォルト|
|12A|12C||

```SQL:
SQL> SELECT username, password_versions FROM dba_users
  2  WHERE username LIKE 'USER%' ORDER BY 1;

USERNAME             PASSWORD_VERSIONS
-------------------- -----------------
USER08               11G 12C
USER09               11G 12C
USER10               11G 12C
USER11               11G 12C
USER12               11G 12C
USER12A              12C

6行が選択されました。
```

上記のように、マニュアルの記述とは異なり SQLNET.ALLOWED_LOGON_VERSION_SERVER に低いバージョンを指定しても Oracle Client 10g 以前のバージョンからは接続できないことが確認できました。

Author: Noriyoshi Shinoda / Date: December 26, 2023
mysql-client ver8で、mysql-server5.7からdumpを取る



# 現在のmysql-clientのバージョン
公式からダウンロードした8.0用のクライアント
```bash
$ mysql --version
mysql  Ver 8.0.35 for Linux on x86_64 (MySQL Community Server - GPL)
```

# 現在のmysql-serverのバージョン
AWSのaurora RDSなので、厳密には違うけど、
エンジンバージョンは5.7を対象にしてます。


# mysqldump コマンド
```bash
mysqldump --user=[dumpできる権限をもったユーザ] --password=[パスワード] --host=[データベースのURI（ローカルなら不要）] --single-transaction --set-gtid-purged=OFF --default-character-set=binary --routines --add-drop-database --databases [データベース名] | zip > dump.sql.zip
```
- --set-gtid-purged=OFF
ちょっと前から何故かDumpがうまく行かなくなった。gtidがどうとかいうエラーのために付与…。
細かく調べていないけど をつければOKでした。
- --default-character-set=binary
文字コードが変わったのか、日本語（utf-8）が文字化けするようだったので、binaryで出力。

zip圧縮しながら出力されるので、`dump.sql.zip`というものが出来上がります。
zip圧縮している理由は、dumpを取得する場所のディスク容量が逼迫しないようにということです。

```bash
unzip dump.sql.zip
```
解凍すると、`-`というファイルが出ます。
（中身はSQLdump）
mvコマンドなどで、名前を変えておくと読みやすいです。
```bash
mv - dump.sql.zip
```

# dumpのインポート
手元のコンテナにmysqlコンテナを作成し、インポートします。
```bash
mysql -u root -ppassword --default-character-set=binary < dump.sql

```


これで文字化けせずにbinaryカラムなどもインポートできました。
データベース設計の流れを理解する

# 1.論理設計
論理設計は、**データベースにどんな情報をどのように格納し、それらの情報がどのように関連しているかを考える作業**です。

論理設計の主なステップについて簡単に説明します！
#### 1.エンティティの定義
* エンティティは、データベース内で識別可能な対象や情報の集まりを指します。例えば、ユーザー、商品、注文などがこれにあたります。
*  各エンティティには特定の属性があり、これがカラムに対応します。例えば、ユーザーエンティティなら、　名前、年齢、メアドなどがその属性です。

#### 2.正規化
* 正規化では、データに矛盾がないか、効率的に情報を格納できるかを検討します。
* 通常は、第1正規形、第2正規形、第3正規形などの正規形にデータを整理します。
#### 3.ER図作成
* ER図とは、エンティティとそれらの間の関係を視覚的に表現したものです。エンティティと関連をむずんだり、各エンティティの属性を示すことで、データの構造を理解しやすくします。

# 2.物理設計
物理設計は、データベースの性能や効率を向上させるために、論理設計で定義されたデータベース構造を実際のデータベース管理システム（DBMS)に適した形に変換するプロセスのことです。

物理設計には以下の主なステップが含まれます。
#### 1. テーブル定義
* 論理設計で作成されたエンティティや関係を元に、実際のデータベース管理システムが理解できる形に変換します。これにはテーブルの物理的なストレージ構造やデータ型、節約の定義などが含まれます。（後でもっと詳しく説明）
#### 2.インデックス設計
* インデックスはデータの検索を高速化するための構造で、物理設計ではどのカラムにどのようなインデックスを設定するかを決定します。適切なインデックスの設計はデータベースの検索性能に直結します。　本の目次のようなもの
#### 3.データの格納方法の決定
* データベースがデータを物理的にどのように格納するかを決定します。これにはデータの圧縮、分割、パーティショニングなど含まれます。
#### 4.セキュリティ対策
* データベースにアクセスする権限や暗号化の手法など、セキュリティに関する側面も物理設計の一環です。

物理設計は論理設計を連携し、データベースが効率的に動作し、迅速なデータアクセスが可能になるようにします。論理設計がデータの構造を考えるのに対し、物理設計は**そのデータの実際の保存や処理方法を最適化することを目的としています。**

## テーブル定義
テーブル定義が、データベースの各テーブルにどんな種類の情報をどのように格納するかを指定する「設計図」のようなものです。
#### 1.カラムの定義：
* テーブル内のカラムには、特定の情報や属性が格納されます。例えば、ユーザーテーブルなら「ユーザー名」や「年齢」が各カラムになります。
* カラムごとにデータ型（日付、整数、文字列など）を指定します。これは、そのカラムにどの種類のデータが格納されるかを示します。
#### 2.主キーの指定：
* 主キーは、テーブル内の各レコードを一意識別するためのカラムの集合です。**主キーはデーターベース内での検索や関連付けに使用**されます。
* 通常、主キーはユニークで、かつNULL値を取らないように定義されています。
#### 3.外部キーの指定：
* 外部キーは、他のテーブルとの関連を示すためのカラムです。外部キーは、関連する他のテーブルの主キーと対応します。
* 外部キーを使用することで、**異なるテーブル間でデータをリンクさせたり、参照生合成を確保したりできます。**（一貫性）
#### 4.その他の制約の指定
* カラムに対して、データの範囲や一意性、NULL許容などの制約を指定する。これは、データの生合成を保つためです。

## インデックス
インデックスは、**データベース内のデータを高速に検索するための仕組みです。**
以下は、インデックスの主な特徴と役割についての説明です。
#### 1.検索の高速化:
* インデックスはデータベース内の特定のカラムに対して、その値とそのデータが存在する場所を対応づけるものです。

#### 2.効率的な検索操作:
* 　インデックスがない場合、データベースは全体を順番に検索して目的のデータを見つけます。つまりインデックスがあった方が早いよね。
#### 3.ソートや範囲のサポート:
* インデックスはデータを特定の順序に整列させたり、ある範囲のデータを一括して取り出すのにも役立ちます。

#### 4.データベースの制約や位置異性の確保:
* 例えば、特定のカラムに一意性の制約（ユニーク制約）を設けた場合、それに対応するインデックスが作成されます。

しかし、インデックスを使用することでデータの検索性能が向上する一方で、**データの挿入や更新、削除の際にはインデックスのメンテナンスが必要となります。** そのため、適切に処理されたインデックスを使いつつ、データベースのパフォーマンスを維持することが重要です。
Seeed Studio XIAO ESP32C3 搭載のバッテリーチャージICは何？


# 結論
Seeed Studio XIAO ESP32C3 に搭載されているバッテリーチャージICは

メーカー：Torex Semiconductor
型番：XC6802
概要：800mA 1セルLiイオン/Liポリマー電池リニアチャージャIC
https://product.torexsemi.com/ja/series/xc6802

# チャージ電流は？
■実測
3.67Vで330mA
![IMG_20231226_201630.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613697/7c8f681f-5412-50ea-0695-3de3cfe9724f.jpeg)



■机上計算
370mAで実測の330mAと近似

充電電流(IBAT)=1000/RSEN(ISENに接続の抵抗値)で計算できる。
回路図よりISENに接続の抵抗値は2.7kであるため
1000/2.7k = 370mA となる。

0.5Cで安全に充電する場合、740mAhの容量が必要

# 参考サイト
■公式Wiki
https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/

■公式回路図
https://files.seeedstudio.com/wiki/XIAO_WiFi/Resources/Seeeduino-XIAO-ESP32C3-SCH.pdf
⇒U1がバッテリーチャージICと思われるが型番の記載なし

■シールド開封画像
https://imgur.com/KAYwJhC
⇒NA41Yの刻印

■SMD marking codes database
https://smd.yooneed.one/code4e41.html
⇒NA4**は Torex Semiconductorの XC6802
xのn乗を計算する2進分解法をElixirで実装する

授業で教えている2進分解法という，$x$と正の整数$n$に対する$x^n$を計算するアルゴリズムをElixirで実装してみましたので，報告します．

## 解答例

```elixir
fn x, n ->
  Stream.unfold(n, fn
      0 -> nil
      n -> {Bitwise.band(n, 1), Bitwise.bsr(n, 1)}
  end)
  |> Enum.reduce({1, x}, fn
    0, {r, x} -> {r, x * x}
    1, {r, x} -> {r * x, x * x}
  end)
  |> elem(0)
end
```

## 解説

[`Stream.unfold/2`](https://hexdocs.pm/elixir/1.16.0/Stream.html#unfold/2)を使って，下記のようにすることで，`n`を下位ビットから順番にビットを取り出したリストのStreamを生成し，上位ビットが全て0になったら終了します．

```elixir
Stream.unfold(n, fn
    0 -> nil
    n -> {Bitwise.band(n, 1), Bitwise.bsr(n, 1)}
end)
```

このリストに対し，初期値`{r, x} = {1, x}`として，[`Enum.reduce/3`](https://hexdocs.pm/elixir/1.16.0/Enum.html#reduce/3)によって，次のロジックで繰り返します．

* ビットが0の時には，`{r, x} = {r, x * x}`とする
* ビットが1の時には，`{r, x} = {r * x, x * x}`とする

最後に，[`elem/2`](https://hexdocs.pm/elixir/1.16.0/Kernel.html#elem/2)を使って，`r`のみを取り出します．

## 余談

[`Stream.unfold/2`](https://hexdocs.pm/elixir/1.16.0/Stream.html#unfold/2)のドキュメントの例題がわかりやすくなったと思いませんか？ 実はこれは私 @zacky1972 の提案によるものです！

https://hexdocs.pm/elixir/1.16.0/Stream.html#unfold/2
【UiPath × Chat GPT】OpenAIアクティビティのすゝめ 【実践、コスト編】

今回は実践編
OpenAIアクティビティをイカしたアクティビティとして使おうぜって内容

初期設定編はこちら
https://qiita.com/Hash1mo/items/80f33f5720bf63e9ea09


# 使い方の一例を紹介
柔軟なアクティビティとして使えることをお見せしたいということで
UiPath Advent challenge 2023 #3で使った手法を紹介
https://forum.uipath.com/t/advent-challenge-3-in-the-uipath-community-forum/704836

## お題
こんなメールが来るから正規表現で分解してExcelにデータ入れてねってお題

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630106/d3d0434c-7ff2-e93c-ed5b-2df0cfea0132.png)

繰り出した手法【正規表現の分解を代わりにやってもらう&構造化してもらう】
一粒で二度おいしい！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630106/ccaf747a-edcd-4085-d908-ea18d2031052.png)

```
"User
以下のメール文章からEmployee Code,Employee Name,Employee Email,TiketForDepartment,TiketDescription,Priority,Created DateをヘッダーとしたCSV形式のテキストで抜き出して　また、CSVの形に定義できないときは「定義できませんでした」と返答を返して" + vbCrLf + 【メール本文】
```

これでCSV形式の文字列データが手に入ります。
あとはデータテーブル型にでも突っ込みましょう

:::note info
この方式のいいところ
* 多少フォーマットが違ってもうまく動いてくれる柔軟性
* そもそも全く違うメールの場合は「定義できませんでした」と返答
:::

### OpenAIアクティビティ最高だぜ！！

# 気になる金額の話
このレベルの作業をさせるのにかかった金額は...

:::note info
### なんと ￥0.04/回！！！
画像はAzureのコストだけどOpenAIでもほぼ一緒だと思う
ちなみにバージョンは3.5でやってますし3.5で十分
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630106/f04ccfbb-912f-e43c-d5b8-796471f30cf1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630106/3a90ae5d-1642-057a-9e18-610e4d3d249e.png)

:::note warn
### 使うたびに毎回課金されるんでしょ？
ってお思いのあなた！
:::


今回の正規表現で分解するロジックを

仮に自給1000円の人が30分で作ったとして
12,500‬回まではOpenAIアクティビティで作ったほうが安くなる計算

1日1回動かしたら34年だぜ？計算するだけ馬鹿らしくなるコストってこった

## というわけで

:::note info
### みんなOpenAIアクティビティ使ってハッピーになろう！！
:::
VisualStudio  でインテリセンスをタブのみに固定

## やりたいこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/b93060cc-6e50-a0ca-93fc-57941637325d.png)

こいつをつねにONにしたい。
## 手順
ツール＞オプション＞テキストエディター＞詳細＞既定の～～
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/b8a7823f-c178-9fd1-2e17-8411fcdabba0.png)

タブのみに変更

やったね。
huggingFace にあるOptical flow 関連を調査中


huggingFace にはtransformer　ベースの実装が多数存在する。
それが、組み込み可能なレベルになってくることを期待して調査している。


## [krasserm/perceiver-io-optical-flow](https://huggingface.co/krasserm/perceiver-io-optical-flow)

pdf [Perceiver IO: A General Architecture for Structured Inputs & Outputs](https://arxiv.org/abs/2107.14795)

![Screenshot from 2023-12-26 14-41-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/037f8130-fbbf-fcbc-8f32-84239fc39d8c.png)
![Screenshot from 2023-12-26 15-56-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/3a2a0d11-6479-1a5d-ffb6-bc8f6b59e372.png)

[引用元](https://arxiv.org/pdf/2107.14795.pdf)
従来の手法よりもaverage end-point error が小さいという。


上記の図に示すようにPerciever IO は、visual transformer　ベースのアルゴリズムになっている。
この論文自体は、Abstract の中に以下の記述にあるように、Optical flow と言う個別のタスク以上の部分に関心があるようだ。
> In this work,    we propose Perceiver IO, a general-purpose architecture that handles data from arbitrary settings while scaling linearly with the size of inputs and outputs.

huggingFace にある例題
前提：CUDAデバイスがあること。


## ２枚の画像を入れて、optical flow を計算してくれるweb画面
https://huggingface.co/spaces/nielsr/perceiver-optical-flow

![Screenshot from 2023-12-26 16-09-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/fca70e91-7b0e-5bb3-3768-14fe2f5eaf45.png)

## https://huggingface.co/deepmind/optical-flow-perceiver