OmniAICreator/Qiita-1.07M huggingface dataset:
OSSのコントリビューターになれなかった話

# はじめに
本記事はHRBrain Advent Calendar 2022の23日目の記事です。

https://qiita.com/advent-calendar/2022/hrbrain
# コントリビューターとは
コントリビューター（contributor）とは貢献者のことで、OSS（オープンソースソフトウェア）開発においては、プロジェクトに貢献した人のことを指します。

# コントリビューターになるメリット
個人的には以下2点が大きなメリットだと思っています。

**1. 勉強になる**
普段利用させて頂いてるOSSを作っているつよつよエンジニアたちのソースコードに触れることで、とても勉強になると思います。

**2. GitHubプロフィールにOSSのアイコンが載る**
GitHubプロフィールは、転職活動等で見られることもあります。
その際に、有名なOSSのアイコンがOrganizationsに載っていると
**「こいつできるやつやん・・・」**
**「OSSコントリビュートしてるってことはそれだけ技術的な関心があるってことやな・・・」**
って思わせることができます。
私は勲章みたいなものだと思ってます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285733/e5d9f50d-340c-ce49-9c11-5dfff1b4ef0b.png)



# 実際にコントリビュートに挑戦してみた
私がコントリビュートに挑戦したのはvue-test-utils-getting-startedです。

https://github.com/vuejs/vue-test-utils-getting-started


開発でvue-test-utilsを使うことになり、getting-startedを試し見ることに。
READMEに書いてある手順どおり、 `npm install`をしたところ以下エラーが表示されました。
```
node-pre-gyp ERR! Tried to download(404): https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.1.2/fse-v1.1.2-node-v64-darwin-x64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for fsevents@1.1.2 and node@10.15.3 (node-v64 ABI) (falling back to source compile with node-gyp)
node-pre-gyp ERR! Tried to download(undefined): https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.1.2/fse-v1.1.2-node-v64-darwin-x64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for fsevents@1.1.2 and node@10.15.3 (node-v64 ABI) (falling back to source compile with node-gyp)
  SOLINK_MODULE(target) Release/.node
```
ざっくりエラーの内容としては、このプロジェクトで使用しているモジュールが古くて色々エラーが出ているという感じです。
この内容をチームメンバーに共有したところ
**「コントリビュートチャンスやで！！」**
と言われ、思い切ってコントリビュートに挑戦してみることにしました。

# PRを出すまでの流れ
まずは修正から。
リポジトリをforkして、修正を始めます。
モジュールアップデートは、[npm-check-updates](https://github.com/raineorshine/npm-check-updates)を使用しました。
package.jsonに書かれているnpmのバージョンを、一括で最新に書き変えてくれるNode.jsのモジュールでとても便利です。
そしていざPRを作成。
英語でPRの内容を書き、英語ができる方に添削までしてもらい、いざINREVIEWに。
チームではVue.js配下のコントリビューターになれるぞ！！！とプチお祭り状態。
あとは、マージされるのを待つだけ・・・のはずでした。

https://github.com/vuejs/vue-test-utils-getting-started/pull/2

# This repository has been archived by the owner
オーナーによって、リポジトリがアーカイブ化されました。
このリポジトリはread-onlyとなり、コントリビュートだけでなく、PRを閉じることもできなくなってしまいました。
そう、私はコントリビューターになれなかったのです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285733/28f4113d-4ede-a8ef-967e-e104856b0ce2.png)

# おわりに
こんな結末もきっとよくあることなのだと思います。
今回アーカイブ化されたのは、getting-startedくらいならメンテしなくてもいいかなという感じだと推測してます。

株式会社HRBrainではHRBrainにコントリビュートしてくれる仲間を募集しています。
エントリーお待ちしています！

https://www.hrbrain.co.jp/recruit
【JavaScript】Enterキーでformが送信されるのを防ぐ ~送信される場合とされない場合について~

## はじめに
Enterキーを押すとformが送信されるのを防ぐ。

この実装方法自体は調べればすぐに見つかったのだが、送信される場合とされない場合があったので疑問を感じた。

そこで調べてみると、`from`、`input`、`buttun`といったHTML要素の仕様について、色々と勉強になったので備忘録を書いておく。

## やりたいこと
`form`で`＜input type=”text”＞`にフォーカスしている時に、`Enterキー`を押すと送信されてしまう場合がある。
意図しない送信を防ぐ為、送信ボタンをクリックしたときだけ`submit`するようにする。

## 実装方法
### formタグにonsubmit="return false;"を追加する

以下のような感じに。

```html
<form onsubmit="return false;">
```

### 送信ボタンをtype="button"にする

送信ボタンを`type="button"`に変更する。
`onclick="submit();`でボタンを押したときだけ`submit`させるようにする。
（`input`要素の`submit`型は、ボタンとして描画される。）


```html
<input type="button" value="送信" onClick="submit();">
```

### フロント側のバリデーションを効かせたい

ただし上記の実装では、`input`に指定している`required`属性などフロント側のバリデーションは無視して送信されてしまう。
フロント側のバリデーションを効かせたい場合は、以下のようにJavaScriptで制御する。

```html
<script>
	function submitAfterValidate() {
        if (!form.reportValidity()) {
            return false;
        } else {
            form.submit();
        }
    }
</script>

// 中略

<input type="button" value="送信" onClick="submitAfterValidate();">
```

## 学んだこと備忘録
ここから先は、HTMLの`form`関連で学んだことの備忘録。

### formのaction属性

`action`属性は、どこにデータを送信するかを定義する。
値は相対または絶対URL。

```html
// 絶対URLの場合
<form action="https://example.com">

// 相対URLの場合（同一オリジン上の別のURLに送信する）
<form action="/example">

// 何も指定しなければ、フォームが表示されているページ自身へ送信する
<form>
```

### 入力欄でのEnterキー押下で、submitされる場合とされない場合

- `form`内に`submit`ボタンがある場合は、`Enter`キー押下により`submit`される。
※submitボタン：`<input type="submit">`もしくは`<button type="submit">`を指す。

```html
<form>
    <input type="text">
    <input type="text">
    <input type="submit" value="送信">
</form>
```


- `form`内に`submit`ボタンが無く、`<input type="text">`が1つだけであれば、`Enter`キー押下で`submit`される。

```html
<form>
    <input type="text">
    <input type="button" value="送信" onClick="submit();">
</form>
```

- `form`内に`submit`ボタンが無くても、`<input type="text">`が2つ以上あれば、`Enter`キー押下で`submit`されない。

```html
<form>
    <input type="text">
    <input type="text">
    <input type="button" value="送信" onClick="submit();">
</form>
```

※ただし、`form`内に`input`は2つだけど片方が`type='hidden'`だったり、片方が`textarea`の場合は`Enter`キー押下で`submit`される。

### 暗黙的送信（Implicit submission）
これらの挙動は、**暗黙的送信（Implicit submission）** という仕様によるものらしい。
https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission

ざっくり言うと、この仕様により、

- `submit`ボタンは無いがフォームの`input`要素が1つだけの場合
- フォームの`input`要素が複数あるが、有効な`submit`ボタンが存在する場合

は、暗黙的送信が行われるということ。

### type属性を省略したbuttonはsubmitボタンになる

ちなみに、`button`の`type`属性を省略すると、デフォルトで`type="submit"`になるらしい。

```html
<button>戻る</button>
```

https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element

これも意図しない挙動を引き起こしかねないので、覚えておこうと思う。

## さいごに
「Enterキーでformが送信されるのを防ぐ」という解決方法はすぐに見つかったが、やはりもう少し調べると色々勉強になることがあり、意図しない挙動を起こさない為にはきっちり理解することが大事だなと思った。

なぜこれで動くのか？なぜこの挙動になるのか？と、今後も疑問を持って知識を深めていきたい。

## 参考記事

https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission


https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element

https://zenn.dev/silurus/articles/b111b2de6cc8d2


https://www.softel.co.jp/blogs/tech/archives/3614


https://www.kanaya440.com/contents/tips/javascript/001.html
【AWS】Fargate導入時にハマったことと対応まとめ

# 概要
下記の記事を参考に、RailsアプリケーションがFargate上で動作するよう設定を行ったが、そのままでは動作せず。発生した事象と対応についてまとめ。

https://qiita.com/hatsu/items/22e11e94a0a981d78efa

# 環境
- アプリ
  - ruby 3.0.2
  - rails 6.1.4
  - mysql 8.0.31

- インフラ
基本的に元記事の通り。
HTTPSでアクセスできるようSSL化まで行っている、
ローカル→(HTTPS)→ALB→(HTTP)→Fargate⇄RDS
の状態。

# タスクを起動し、ドメイン名からアクセスすると、503 service temporarily unavalibanleエラーとなる
各種設定が完了したので、Fargateを起動しようと、下記操作を実施した。
- ECS/タスク定義/アクション/タスクの実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948830/0bb00bb3-b486-2e6c-fd50-4aa45ec6af95.png)

- ECS/クラスター/タスク/Runningにてタスクの起動を確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948830/27f51928-48e1-37c0-2785-b07f4d73478a.png)

タスク詳細のログでも正常に起動していることが確認できた。
しかし、この状態で、ドメイン名からアクセスをすると、503 service temporarily unavalibanleエラーとなる。

## 原因：サービスからではなくスタンドアロンでタスクを実行していた
タスクには、
- スタンドアロンのタスク
- サービスタスク

の２種類が存在する。
これまで起動していたのは、スタンドアロンのタスクであり、
**ALBを介したアクセスを実現するためには、サービスからタスクを起動する必要がある。**

> 参考

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/AWS_Fargate.html

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/ecs_run_task.html

https://zoo200.net/aws-tutorial-ecs-fargate/

## サービスタスクの起動
元記事に沿ってサービス自体は作成していたため、そちらを利用。

- ECS/クラスター/サービスタブ/対象サービスを選択/更新
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948830/8adc9458-fc42-ada9-9f6d-bef06f14bdc9.png)

- ```新しいデプロイの強制```にチェックを入れ、サービスの更新ボタンを押下

これで、サービスに紐付けられているタスクが起動する。

サービスから起動されたタスクは、対象タスクの詳細で、
```グループ service:サービス名```
となっている。


# タスクが起動→停止→再起動を繰り返しており、依然アクセスできない
上記までの操作で、サービスからタスクを実行することができたが、実行されたタスクが、自動的に起動→停止→再起動を繰り返している。
ALBに設定しているターゲットグループの```Health status details```は、```Health checks failed```となっている。


## 原因：ALBのヘルスチェックが失敗していることで、タスクが停止されていた

>参考

https://blog.serverworks.co.jp/fargate_healthcheck

（抜粋）
>ALBのヘルスチェックで異常と判定したターゲットに紐づくECSタスクはECSが停止します
そしてサービスに設定したタスクの数に達するまで新しいタスクを作成します

## ヘルスチェックが失敗する原因は？
### ①セキュリティグループの設定がうまくできていない
サービスタスクのセキュリティグループは、サービス作成時に設定する必要あり。
更新では修正できなかったため、作り直す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948830/ea79676e-48e2-1a49-adf1-bcef7bd0331b.png)

このセキュリティグループのインバウンドのルールにて、ALBからのアクセスを許可すればOK。
タスクのログにて、compile完了後であれば、```curl http://タスクIP```で疎通が確認できる状態となった。

しかし、compile完了とほぼ同時に、タスクが停止→再起動されてしまう。
この時点では、ALBに設定しているターゲットグループの```Health status details```は、```Health checks failed with these codes: [502]```となっている。

### ②アプリケーション起動完了前にヘルスチェックが実行されている

タスクのログでは、タスク起動直後から断続的にヘルスチェックが実行され、compile完了時点で規定の失敗回数に達してしまっていることで、ヘルスチェック失敗とみなされているように見受けられた。
アプリケーション起動完了後にヘルスチェックが開始されるようにするため、下記設定を行う。
- ECS/クラスター/サービスタブ/対象サービスを選択/更新
- ステップ3```ヘルスチェック の猶予期間```にて、十分な時間を設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948830/aa02d5fc-cd52-7bbf-e81d-e99c1d748528.png)

> 参考

https://dev.classmethod.jp/articles/tsnote-ecs-how-do-i-ecs-exec-on-an-ecs-task-that-is-terminating-immediately-due-to-a-health-check-failure/

ここまでの設定を行うことで、ブラウザ上で、ドメイン名からアプリケーションにアクセスすることができた。



# 最後に
より良い方法や間違い等ありましたらご指摘いただけますと幸いです！
【Combine】複数の値をまとめて監視する

# はじめに
ログイン画面などで全ての情報が入力されていない場合、ログインボタンを押せなくする動きを再現してみました。
複数の値をまとめて監視する方法を使用することで簡潔に書けたので紹介します。

# サンプルアプリ
![Simulator Screen Recording - iPhone 14 - 2022-12-15 at 21.16.34.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/d0cabd1b-b58e-26fc-b9bd-a39d0d7bba11.gif)

# 実装
### View
```swift
import SwiftUI

struct ContentView: View {
    @StateObject var viewModel = ViewModel()
    var body: some View {
        NavigationStack {
            List {
                Section {
                    TextField("氏名", text: $viewModel.name)
                    Stepper(value: $viewModel.age) {
                        Text("年齢: \(viewModel.age.description)")
                    }
                } header: {
                    Text("基本情報")
                }

                Section {
                    TextField("ユーザーネーム", text: $viewModel.username)
                    SecureField("パスワード", text: $viewModel.password)
                } header: {
                    Text("アカウント情報")
                }

                Section {
                    loginButton
                }
            }
            .listStyle(.insetGrouped)
            .navigationTitle("ログイン")
        }
    }

    private var loginButton: some View {
        Button {
        } label: {
            Text("ログイン")
                .font(.system(size: 20, weight: .black))
                .frame(maxWidth: .infinity, alignment: .center)
        }
        .disabled(viewModel.isEnableLoginButton)
    }
}
```

### ViewModel
```swift
import Combine

final class ViewModel: ObservableObject {
    @Published var name: String = ""
    @Published var age: Int = 0
    @Published var username: String = ""
    @Published var password: String = ""

    @Published var isEnableLoginButton: Bool = false

    init() {
        $name.combineLatest($age, $username, $password)
            .map { $0 == "" || $1 == 0 || $2 == "" || $3 == "" }
            .assign(to: &$isEnableLoginButton)
    }
}
```

# 解説
以下のコードでname, age, username, passwordを監視する指示を行っています。
```swift
$name.combineLatest($age, $username, $password)
```

以下のコードでそれぞれの値に入力が行われたかを判定しています。
```swift
.map { $0 == "" || $1 == 0 || $2 == "" || $3 == "" }
```
:::note info
`$0`には`name`の値
`$1`には`age`の値
`$2`には`username`の値
`$3`には`password`の値
:::

以下のコードでmapの結果を`isEnableLoginButton`に代入しています。
```swift
.assign(to: &$isEnableLoginButton)
```

# おわり
便利ですね
【UiPath】鋼の意思でReplaceする

はじめに
仕事で大文字小文字全角文字関係なくReplaceする必要があったため、記録として残します。
この記事は、UiPath Advent Calendar (produced with UiPath Friends) Advent Calendar 2022の16日目の記事です。

https://qiita.com/advent-calendar/2022/uipath


# 結論
ReplaceメソッドのCompareメソッドを使えば、
大文字小文字全角半角の区別なく鋼の意思でReplaceができます。
~~~
Strings.Replace("Aa　Ａａ","A","B",Compare:=CompareMethod.Text)
~~~

# 実際にやってみた
こんなシーケンスを作りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1846796/7f6ee2e7-be5d-f5dd-abed-508c74f762b6.png)

## Replaceしてるメッセージをログアクティビティの中身
文字列変数内の「A」を「B」に置換しています。

```
Strings.Replace(文字列,"A","B",Compare:=CompareMethod.Text)
```

## 実行結果
全角半角大文字小文字関係なく「A」が「B」に置換されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1846796/92c91305-3bf3-c84a-4460-349c6aef015c.png)

# 参考文献

https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.visualbasic.strings.replace?view=net-7.0

https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.visualbasic.comparemethod?view=net-7.0

# おわりに
使い方を間違えなければ非常に使えるものであると思います。
どーにもならなくなっている人達にこの記事が届けば幸いです。
【UE5】メッシュが「アンロード済み」になった場合の対処法

# 1.はじめに
どうも、ARIの名古屋支社に勤務している愛知県民こと、
新藏（にいくら）と申します♪
(/・ω・)/

前回の記事では、[Lumenが有効な場合と無効な場合の比較](https://qiita.com/Aichi_Lover/items/f066883995273157bbf3
 "【UE5】Lumenが有効な場合、無効な場合を比較してみた")について記載しました。

今回も引き続きUE5(Unreal Engine 5)の入門的な内容ですが、
**メッシュが「アンロード済み」になって見えなくなった時の対処法**
について記事にしたいと思います！

UE5について勉強中の方や同様の事象で困っている方の参考になれば幸いです。
(*^^)v

:::note warn
今回は対処法がメインで、根本的な原因までは言及できていません。
もし原因が分かる方がいらっしゃいましたら、コメントで教えていただけると助かります！
:::

ちなみに、12月は**ARIのアドベントカレンダ**もやっていますので、
もしよろしければ、こちらも応援お願いします♪

https://qiita.com/advent-calendar/2022/ari-group

https://qiita.com/advent-calendar/2022/aichi_lover_yomoyama

# 2.用語の説明
## メッシュとは

**メッシュとは、「3Dモデル」とほぼ同じ意味の言葉です。**
UE5を使用する際に配置するキャラクター、立方体、岩などはすべてメッシュとなります。

https://zenn.dev/daichi_gamedev/books/unreal-engine-tutorial/viewer/editor-word-3dmodel

# 3.事象の説明
まずは、メッシュが「アンロード済み」になると、どうなるのかを説明します。

3.1.以下の画像が初期状態となります。

|![000_初期状態.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/ba2baf8d-4b02-f428-20d1-26adf93ba5a5.png)|
|:--|

3.2.メッシュが「アンロード済み」になると、画面上では見えなくなります。

:::note info
私の場合はデモプレイを終了した後に、この現象が発生し、
最初は焦りました・・・
:::

|![010_アンロード済み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/1f8781c5-a651-bb11-5195-451ed03f60de.png)|
|:--|

# 4.メッシュが「アンロード済み」になった場合の対処法
では、本題の対処法を記載します。

4.1.画面上部の「ウィンドウ」を選択し、「ワールドセッティング」を選択します。

|![020_ワールドセッティングを開く.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/66e452a4-8ab6-2ac4-ef84-82e540bdbf04.png)|
|:--|

4.2.画面右側にて、「ワールドセッティング」タブを選択し、「ストリーミングを有効化」を選択します。

|![030_ストリーミングを有効化をチェック.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/62a8ca4b-f284-4001-0d81-48413447376b.png)|
|:--|

4.3.その後、再度「ストリーミングを有効化」を選択します。

|![040_ストリーミングを有効化のチェックを外す.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/be62b428-125f-8df0-8997-1d37b926e2ab.png)|
|:--|

4.4.確認ウィンドウが表示されるので、「はい」を選択します。

|![050_はいを選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/859db120-a628-24ad-860b-06626aaa734c.png)|
|:--|

4.5.「アンロード済み」が解除され、メッシュが見えるようになります。

|![060_アンロード済みが解除される.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/5bc8626e-b47a-f370-926d-01db49ceb2d7.png)|
|:--|

# 5.おわりに
ここまで読んで下さり、ありがとうございます！！！
(^^)

最初は急にメッシュが見えなくなり、誤操作で削除してしまったのかと焦りましたが、
どうにか対処することができて安心しました。

引き続き、何かしら記事を書いていきたいと思います♪
(:3_ヽ)_
なでしこでハノイの塔を解く

なでしこを使って、パズルのハノイの塔を解いてみましょう。

# ハノイの塔とは

ルールに沿って杭に刺した円盤を移動させるパズルです。

> ハノイの塔（ハノイのとう、Tower of Hanoi）は、パズルの一種。 ... ハノイの塔は、フランスの数学者エドゥアール・リュカが1883年に発売したゲーム『ハノイの塔』がルーツである ...
> 解が再帰的な構造をしているということから、この解の手順を表示させるという問題は、再帰的なコンピュータ・プログラムの単純な例題として多用されている。
> [ハノイの塔(Wikipedia)](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%8E%E3%82%A4%E3%81%AE%E5%A1%94)

https://commons.wikimedia.org/wiki/File:Tower_of_Hanoi.jpeg

## ハノイの塔のルール

以下のルールに従ってすべての円盤を右端の杭に移動させられれば完成です。

- 3本の杭と、中央に穴の開いた大きさの異なる複数の円盤から構成される。
- 最初はすべての円盤が左端の杭に小さいものが上になるように順に積み重ねられている。
- 円盤を一回に一枚ずつどれかの杭に移動させることができるが、小さな円盤の上に大きな円盤を乗せることはできない。

## 解法は？

解法もWikipediaにありますので、詳しくはそちらを確認しましょう。
再帰を使うと簡単に解くことができます。

# なでしこ3で解く方法

なでしこ3で解くには、次のようなプログラムを記述します。簡易エディタか、貯蔵庫で次のプログラムを実行してみましょう。

```
●(SRCからDESへ)円盤移動とは
　　「・{SRC}から{DES}へ移動」と表示。
ここまで。

●(円盤数をSRCからDESへTMPで)ハノイ解読とは
　　もし、円盤数=1ならば：
　　　　SRCからDESへ円盤移動
　　もし、円盤数が2以上ならば：
　　　　# 円盤数より上の円盤を待避用の杭に移動
　　　　(円盤数-1)をSRCからTMPへDESでハノイ解読。
　　　　# 一番下の円盤を目的地に移動
　　　　SRCからDESへ円盤移動
　　　　# 待避用の杭に移動した円盤を目的地に移動
　　　　(円盤数-1)をTMPからDESへSRCでハノイ解読。
ここまで。

# 解法を表示する
 3を「A」から「C」へ「B」でハノイ解読。
```

実行すると下記のようになります。

![スクリーンショット 2022-12-15 21.01.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/09109683-cd59-f11f-8bb1-c95edb573d9c.png)

# まとめ

再帰を使うと、簡単にハノイの塔を解けます。再帰って便利ですね。
ジングルベルのなる頃に(出題編)

# はじめに
この記事は、LIGHTzアドベントカレンダー2022の16日目の記事です。
クリスマスまであと9日でございます．

@KTasknこと、たすく、です。[２日目](https://qiita.com/KTaskn/items/9911a47f31787420da40)，[9日目](https://qiita.com/KTaskn/items/5ef5c054a09a2796e0b8)に引き続き，CVネタでも書こうかと思ったのですが，イマイチまとまらなかったため，別のネタでいきます．

大学院通っていると，研究はもちろんなんですけど，講義にもでないといけなくて，ちょくちょく仕事を抜けて講義にでているんたりするんですが，大学院の講義ってxxx特論とかいって，やっぱり超専門的なことなんですよね．
そのなかで，アルゴリズムの講義のなかでおもしろい問題があったので，その改題を今回は紹介します．

# 問題

あなたが勤める出版社でハガキ懸賞を行うことになった。
応募期間に次々に応募ハガキが届く。
あなたは**応募者全員に等しくチャンスを与えたい**と考えているが、
一方で，届いたハガキを保管するスペースを用意できないため，
返信が必要である当選ハガキを除き，ハガキは都度処分したいと考えている．
応募総数がわからないタイミングで公平な取捨選択は可能だろうか？

つまり，下記の条件を満たすアルゴリズムを答えよ

* **応募総数がわからない状況で当選ハガキを決める**
* **すべての応募ハガキの当選確率は同じである**
* **当選ハガキの件数分だけ保管スペースを用意できる**
* **落選と判断したハガキはすぐ処分する**

(10点)
ちょっと一息。SvelteKitのエラーページを猫に頼んでみた。

# はじめに

皆さんは`HTTP Cats`というものをご存じでしょうか

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/cb844c21-403f-0b40-e5b2-c45a5b7c7b76.png)

このように`https://http.cat/[status_code]`の`[status_code]`の部分に`200`みたいに入れることで...

![200.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/73ab9253-8ca9-d1cc-9e67-1f0098987ffb.jpeg)

のように猫の画像＋ステータスコードを表示することができます。

`SvelteKit`の`+error.svelte`というエラー時に表示させるページにこの猫ちゃんを登場させて、エラーページを和ませたい。


# 実装

```vue:+error.svelte
<script>
  import { page } from '$app/stores';
</script>

<img src="https://http.cat/{$page.status}" alt="{$page.status}_cat">
```

終わり...ｗ

### 404

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/2fc4985e-0640-23e2-c44b-1d4c6f375691.png)

### 500

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/a3ffe677-2e38-ef54-3033-75147ec379c4.png)

`SvelteKit`さえ構築できれば誰でも実装できそうですね。
ここに気を付ける。プログラミング初心者のタイプミス一覧

<h4>はじめに</h4>
プログラミングの勉強を始めて数か月が経ちましたが、プログラムが動かなかった理由のほとんどがタイプミスでした。<br>
私（および他の初心者様）が今後活用できたらと思い、初心者（私）のタイプミス一覧を作ります。（ミスが発生しましたらまたアップデートしていきます）

<h4>タイプミス一覧</h4>

| 正 | 誤 |どこが？|
|:-:|:-:|:-:|
| text  | test  |xをsにした|
| result  |  reslt |uが抜けた |
| String |  Strin | gが抜けた|
| String  |  Sting | rが抜けた|
|String | Stirng　|　rとiが入れ替わっている|
|println|printn|lが抜けた|
| : | ; | ;を:にした（Python)|
| ; | : | :を;にした（Java）|
| > | >> | >が一つ多い|
|<%= if( ) %>|<%=if( ) %>|スペースが抜けた|
|);|)|;が抜けた|
|||
|||
HTTPキャッシュとRails

HTTPにはキャッシュの機能がありますが、Rails標準でも意外なところまで組み付けてあったりします。

## 記事の守備範囲

この記事では、Railsが動的に生成する箇所のキャッシュを中心に考えます。事前に生成して、送信にRailsが直接関与しないこともあるアセット類については、考慮の対象から除外します。

## HTTPのキャッシュ

まず、HTTPのキャッシュには大きく分けて2通りの役割があります。

* キャッシュがある状態で全く通信を行わず、キャッシュした結果をそのまま利用する
* キャッシュのある状態で更新確認のための通信を行い、変化がなければ再利用する

そして、キャッシュされたものには2つの状態があります。

* fresh…キャッシュを信じて、通信せずに利用して問題ないことを示しています。
* stale…キャッシュが古くなっている、という状況です。

### Cache-Controlヘッダ

HTTPキャッシュの指示のために、`Cache-Control`というHTTPヘッダが存在します。詳細は[MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Cache-Control)に譲りますが、ある程度まとめておきます。

* `no-store`…一切のキャッシュ禁止
* `must-revalidate`…staleなキャッシュを使う前に更新確認を行う
* `max-age`…キャッシュがfreshである期間の設定
* `no-cache`…最初からstaleなキャッシュであるとの宣言（`must-revalidate, max-age=0`と同様）。**キャッシュしないという意味ではない**。
* `private`…キャッシュが共有不可能であることを示す。
* `public`‥キャッシュが共有可能であることを示す。
 * なお、`private`も`public`も入れなかった場合、どちらで扱われるかは他のディレクティブの設定によります。ただし、Railsから使う場合は「`public`を指定しなければ`private`が自動で入る」という動作が組んであるので、デフォルトを気にする必要はあまりありません。

## Rails標準の動作

Rails標準では、以下のように動作します。

* ビューの中身からETagを生成
* レスポンスは`must-revalidate, max-age=0, private`で送信
* 次回に`If-None-Match`でETagが正しかった場合、レスポンス本体は返さず`304 Not Modified`で応答

ということで、同じレスポンスを返したい場合、内容の**転送**負荷は削減されることになります。ビューを生成してからETagでチェックするため、不必要にキャッシュが残る心配はないのですが、ビュー処理の負荷は消えないことになります。

## シナリオ別の設定

### 一定時間キャッシュを残したい

キャッシュを一定時間残して、その間はリクエストも行わないようにしたい、という場合、コントローラーで`expires_in`というメソッドを使えます。

なお、その時間内はキャッシュの更新がされませんので、「残ってしまってもかまわない状況で使う」、「元データが変更になった際にはURLごと変更する」、「一定時間ごとにデータが変わる状況で、変わる時点までのキャッシュを行う」など、何かしらの戦略が必要となります。

### 一切キャッシュさせない

これも、Rails 7では`no_store`メソッドが登場していますが、それ以前のバージョンでは`request.cache_control.replace(no_store: true)`のようにデータを書き換える必要があります。

### Not Modified時の処理負荷を軽減したい

最終更新日時や特定の値などで、ビュー全体を描画しなくてもキャッシュの有効無効を判定できる場合、`stale?`というメソッドが有用です。

`:etag`や`:last_modified`などに条件を設定して、それらの条件をリクエストと照合して、レスポンスボディ不要となれば、**`304 Not Modified`のレスポンスを生成した上で**`false`を返します。`return if stale?`のようにしてコントローラーから抜けてしまえば、それ以降の処理は不要となります。

## 外部リンク

* [ActionDispatch::Http::Cacheのソース](https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/http/cache.rb)
* [ActionController::ConditionalGet](https://api.rubyonrails.org/classes/ActionController/ConditionalGet.html)、[ソース](https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal/conditional_get.rb)
【Visual Studio 2019 for Mac】「かな」「英数」キーが入力されず半角スペースが入力される

# 環境
- Visual Studio Community 2019 for Mac (version 8.10.4)
  - version 8.10.25 でも同様の問題を確認しました。([リリースノート](https://learn.microsoft.com/ja-jp/visualstudio/releasenotes/vs2019-mac-relnotes))
  - macOS BigSur 11.3.1
  - MacBook Air (M1, 2020)

# 解決策
キーボードの入力ソースを「日本語 - ローマ字入力」のみにして、英字にチェックを入れる
![スクリーンショット 2022-12-15 18.20.31のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/3b04a443-197a-de2f-0d5f-a145cd52a402.png)

# 根本的な原因
デフォルトの英数文字の入力ソースである「ABC」との相性が悪い。
「ABC」を入力ソースに選択しているとき、VisualStudio上で「かなキー」、「英数キー」を押すとスペース入力になってしまう。
なので、これを用いないで他で代用する手段を考えます。
![スクリーンショット 2022-12-15 18.17.39のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/5eebd812-6c6e-a6a6-487c-b3b59ba284ac.png)

# 設定方法
システム環境設定を開いて、「キーボード」を選択。
![スクリーンショット 2022-12-15 19.25.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/d83b8201-79aa-ccec-07c7-1f418a1806b7.png)

「入力ソース」を選択。
![スクリーンショット 2022-12-15 19.26.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/737a9994-6b93-64bf-92e6-88763dc753d9.png)

「日本語 - ローマ字入力」を選択して、英字にチェックを入れます。
![スクリーンショット 2022-12-15 18.17.51のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/3d97e008-66f8-9e55-0946-61af6c000043.png)

これで、「日本語 - ローマ字入力」を用いて英字入力ができるようになりました。

VisualStudioを開き、mac左上のメニューバーから「英字」もしくは「ひらがな」を選択して、かなキー・英数キーを押せば無事に切り替えられると思います。
![スクリーンショット 2022-12-15 18.18.09のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/0a00738d-7157-bdc0-9b05-2dd224f5901c.png)
再度言いますが、「ABC」を入力ソースに選択しているとき、VisualStudio上で「かなキー」、「英数キー」を押すとスペース入力になってしまうので気をつけましょう。

# 設定方法(おまけ)

最初から入力ソースが「ABC」にならないように、設定から消してしまいましょう。
「ABC」を選んだ状態で、左下の「-」ボタンを押すことで「ABC」を入力ソースから外すことができます。
（冒頭の解決策と同じです。）
![スクリーンショット 2022-12-15 18.17.39のコピー2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/57098c22-a44b-81eb-10b5-71f2dc87f0d4.png)
![スクリーンショット 2022-12-15 18.20.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/bbf778c3-3c12-1c6e-269e-1f98c5601ca2.png)
カタカナ入力はお好みでいいと思います。


# 備考

比較的新しめのmacbook(macOS?)ではデフォルトの設定として、英数入力は「ABC」が入力ソースになっているようです。

他の記事では、google日本語入力を代用することを推奨していますが、最新のmacOSだとgoogle日本語入力がうまく導入できない問題があったため、この方法が良いと思われます。
あとgoogle日本語入力だと変換候補のUIがちょっとかっこよくないし……。
変数を美しく書いてみよう！


# はじめに
前回リーダブルコードを読んで[コメントを美しく書いてみよう！](https://qiita.com/ryuji_i3/items/857435ebe0211e93d6af)　を記載しました。
今回は本の内容から、変数の書き方に焦点を当てて記載していきます！
**参考文献：リーダブルコード**

これまでの経験と本の内容を合わせて、それっぽいコードをサンプルに記載してまとめていきます！


## 不要な変数は削除する
不要な変数はなるべく削除したほうがいいとのことです。
理由としては以下の二点があげられます。
- 変数が多いと変数を追跡するのが難しくなる
- 変数が頻繁に変更されると現在の値を把握するのが難しくなる

```
        // 住所を取得
        $address = $getAddressData(zipcode);
        if ($address) { 
            ････
        }
```
この例では、関数内にaddressは一度しか使われていないことを前提とします。

if文の中身は住所があるかないかをみているだけです。変数がここでしか使われていないため、関数をif内に直接移動させて、$addressを削除しても良さそうです。


## 定義の位置を下げる
たまに関数の先頭で変数が全て定義されているコードをみます。
例えば以下のようなコードです。

```
        // 住所を取得
        $address = $getAddressData(zipcode);
        // 電話番号を取得
        $phonenumber = $getPhonenumberData(hoge);
        ...
        ...
        ...
        if ($address) { 
            ････
        }
```
実際に使用するのはずっと先だとしても、このように先頭にまとめて変数が定義されているコードを見かけます。
まとまっていると見やすそうですが、最初から全ての変数を知る必要はないので、使う直前に移動するほうがいいとされています。
また先頭に羅列すると、後で不要になった場合に消し忘れて残されたままというのもよく見かけてきました。
そういった無駄な変数も、処理の直前に記載することで消し忘れの防止につながります。

## javascriptのグローバル変数には気を付けよう
グローバルスコープの取り扱いには気を付けたほうが良いです。（基本はグローバル変数は使わない）
意図せずグローバル変数にしてしまっている場合もあるので、以下の例を見て今一度グローバル変数を使ってないか気を付けましょう！

```
var f = function() {
  for(i =0; i <10; i +=1) {
    …
  }
}
```
こちらの例ではiがグローバル変数になってしまってます。別の関数でvarのない同じ名前の関数をつくってしまうと、影響がでてしまいます。

## 変数は一度だけ書き込むものだと理解する
**永続的に変更されない変数**は使いやすいとされています。仮に変数の値を入れ替えなくてはいけないことになっても、変更箇所はなるべく少なくした方が良いです。
Reactの場合は基本的に**const**を利用して、値が変更されない変数にすることを心がけたほうが良いです。

## まとめ
・不要な変数は削除する
・変数の定義は直前に書く
・グローバル変数にならないように気を付ける
・一度だけ書き込む変数を使う
モデル駆動型アプリのOffice365連携

モデル駆動型アプリはデータ管理に特化したアプリで、そこをより便利にする機能があります。
それがOffice365連携です！
モデル駆動型アプリには標準でOffice365連携ができるような仕組みがあります。

# Office365連携種類
1. Excel / Word テンプレート
1. Excel を使ったデータ操作
1. SharePoint 連携
1. OneDrive for Business 連携
1. OneNote 連携
1. 公開予定のおすすめ機能

一つずつ見ていきましょう。
最後に<font color="RoyalBlue">**今後公開予定のおすすめ機能**</font>についてもご紹介します。

# <font color="Green">Excel</font> / <font color="MediumBlue">Word</font> テンプレート
テンプレートを作成しておくことで、Dataverseのデータを挿入したドキュメントの自動生成が可能です。
このようにテンプレートを保存しておくと、出力の操作をするだけで簡単に報告書や詳細書などを作成することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/5dc64bc6-28b1-ae7c-fba1-69b0c7e6d8b0.png)

#  <font color="Green">Excel</font>を使ったデータ操作
次は特にExcel操作に慣れている人におすすめの機能です。
- DataverseのデータをExcelを使って一括で追加・編集・抽出が可能
- SQLなどの知識がなくてもデータベースのデータを活用可能
- モデル駆動型アプリではアプリ上で直接Excel Onlineの立ち上げが可能
- ExcelのクライアントアプリでもアドインによりDataverseへの接続が可能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/2fb20bdb-c076-49b2-cab9-441021441c20.png)


# <font color="DarkCyan">SharePoint</font> 連携
ドキュメント管理が得意なSharepointとの連携です。
- モデル駆動型アプリではレコードに関連するドキュメントの保存先としてSharePointと連携が可能
- Dataverseのファイル容量を節約
- SharePoint のドキュメント管理機能の恩恵を受けることが可能
例：アクセス権限、チェックイン、チェックアウト、検索

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/ed27f1fb-e32e-f996-90cd-544745900757.png)

# <font color="DeepSkyBlue">OneDrive for Business</font> 連携
Sharepointと似ている機能ですが、公開範囲が変わります。ユーザーのユースケースに合わせて使い分けてみてください。
- Dataverseのレコードに紐づける形で個人のドキュメントを管理することが可能
- SharePoint 統合と機能的にはほぼ同じだが、公開範囲が個人になる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/49f529a2-003d-bf34-9b9c-b91def965f23.png)

# <font color="Purple">OneNote</font> 連携
OneNoteをレコードと紐づけて保存することができるので、普段OneNoteでメモを取っている人におすすめです。
- Dataverseのレコードに紐づく形でOneNoteを連携可能
- 通常のメモでは表現できないリッチな表現が可能
- 保存先はSharePoint
    - OneNote連携のためにはSharePoint 統合の機能の設定が必須

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/7420c780-abf2-9935-4a20-cddf91e0a1ad.png)

# <font color="RoyalBlue">**公開予定のおすすめ機能**</font>

（2023/10　追記
こちらの機能はリリースノートから削除され、実装未定となりました。😨
いつかできることを祈って残しておきますが、現状まだ使えない状態です。
）

~~まだ使えるようにはなっていないのですが、今後、使えるようになる予定の機能として
<font color="RoyalBlue">**Teams連携**</font>があります。
アプリの中でTeamsを開くことができるというものです。
また、レコードを紐づけてチャットを始めることもできるので、アプリ内のデータについての相談がしやすくなります。~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/89cc17f9-15f1-c6e8-b6e7-3371d70f4389.png)

~~2023年3月プレビュー開始予定です。楽しみですね！~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/cff8134a-5510-13e1-ea13-ad2e7ce4ea96.png)

https://learn.microsoft.com/ja-jp/power-platform-release-plan/2022wave2/power-apps/use-teams-chat-others-app
Glideについての初歩的な知識

Glideと聞くと、10年くらい前にGlide OSというものがあったんだよなぁと思い出すのです。今で言うChromeOSと同じコンセプトだったと思います。それとは全然関係ないGlideです。

# ジャンル
ノーコード/ローコード・ウエブ・アプリ開発

# プラットホーム

1. ウェブ

# 料金

1. Free
    - アプリとページ　最大3つまで
    - チームメンバー　2名
    - ゲスト利用者　無制限
    - 一般利用者　100
    - プライベート利用者　3
    - プロジェクトごとのデータ　500レコード
    - ファイルストレージ　200MB
1. Starter ($25/月)
    - アプリとページ　最大5つまで
    - チームメンバー　5名
    - ゲスト利用者　無制限
    - 一般利用者　1,000
    - プライベート利用者　10
    - プロジェクトごとのデータ　5,000レコード
    - ファイルストレージ　5GB
    - カスタムドメイン
1. Pro ($99/月)
    - アプリとページ　無制限
    - チームメンバー　10名
    - ゲスト利用者　無制限
    - 一般利用者　5,000
    - プライベート利用者　50
    - プロジェクトごとのデータ　25,000レコード
    - ファイルストレージ　50GB
    - カスタムドメイン
    - Basic API
    - カラムの保護
    - バーコードスキャナ
1. Business ($249/月)
    - アプリとページ　無制限
    - チームメンバー　25名
    - ゲスト利用者　無制限
    - 一般利用者　10,000
    - プライベート利用者　100
    - プロジェクトごとのデータ　25,000レコード
    - ファイルストレージ　1TB
    - カスタムドメイン
    - BASIC API
    - Advanced API
    - カラムの保護
    - バーコードスキャナ
    - オフラインでレコードを追加
1. Enterprise ($799/月)
    - アプリとページ　無制限
    - チームメンバー　カスタム
    - ゲスト利用者　カスタム
    - 一般利用者　カスタム
    - プライベート利用者　カスタム
    - プロジェクトごとのデータ　100,000
    - ファイルストレージ　カスタム
    - カスタムドメイン
    - BASIC API
    - Advanced API
    - カラムの保護
    - バーコードスキャナ
    - オフラインでレコードを追加
    - ドメイン監視

https://www.glideapps.com/pricing

# 概要
 David Siegelは、共同創業者となるJason Smith, Mark Probst and Antonio Garcia Apreaとともにマイクロソフトが2016年に買収したXamarinで働いていました。彼らは、企業がモバイルアプリを構築することの難しさを目の当たりにしており、2年後にスタートアップを立ち上げることにしました。

　「世界的な大企業がモバイル戦略を進めるのにどれほど必死になっているか、また、モバイルアプリの開発にどれほど手間と費用がかかるかを目の当たりにしました。そして、スマートフォンがデビューしてから10年経っても、大きな進歩は見られなかった」とSiegel氏は語ってます。

　創業者たちは、市場に出ているノーコードツールでは充分でないと考え、Google Sheetsをデータソースとして、非常に迅速にモバイルアプリを作成できるサービス「Glide」を開発しました。

　Siegelは、現場に出て顧客と話すことと、ツールを作る行為に惚れ込まないことを大切にしています。

# 機能
　Glideが利用するデータベースは、ビルトインのGlide TablesかGoogle Drive上のGoogle Sheets、OneDrive上のExcel、Airtableが利用できます。

　試しに Aritable のテーブルに接続させると、すぐに以下のような画面が表示されます。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/14cdf6cf-88b9-7425-c107-bb1cd95301d8.png"/>

　レスポンシブデザインが作成でき、種類はスマホ、タブレット、そしてそれぞれAndroidとiPhone,iPadが選択できます。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/005af284-899f-b885-7dac-19b6464de623.png"/>

 データソースをGoogle Sheetsに出来ることもあり、初心者が最初のアプリ作成が非常に早く行うことができ、その後で改良を加えていく形になり、とても学習しやすいアプリだと思います。
【Mac】sed: RE error: illegal byte sequence 対処法

## 状況

sedコマンドを次のように実行した際に表題のエラーが発生しました。  

```terminal
$ grep -lr 'sample' . | xargs sed -i '' "s/sample/SAMPLE/g"
sed: RE error: illegal byte sequence
```

## 対処法

sedコマンドを実行する際にロケール設定を変更することでエラーが発生しなくなります。  

```terminal
grep -lr 'sample' . | LC_ALL=C xargs sed -i '' "s/sample/SAMPLE/g"
```
MLOps における機械学習モデルモニタリングについて

MLOps（Machine Learning Operations）とは、機械学習モデルのライフサイクル全体を管理するためのフレームワークです。これには、モデルのトレーニング、テスト、デプロイ、モニタリング、および改善が含まれます。

モデルモニタリングとは、機械学習モデルが適切に動作しているかどうかを監視することを指します。これは、モデルが予測の精度を維持しているか、データの特性が変化していないか、そしてその他の問題が発生していないかを確認するために行われます。

モデルモニタリングには、様々な手法があります。例えば、モデルの予測と実際の値を比較することで、モデルの精度を測定することができます。また、モデルの出力として得られる統計量を定期的に収集し、モデルの精度が変化していないかを確認することもできます。

また、モデルのモニタリングは、データの特性が変化していないかを確認するためにも役立ちます。例えば、特定のカテゴリのデータが増えたり減ったりしているかを見ることで、モデルがそのような変化に適応できるかを確認することができます。

さらに、モデルモニタリングは、モデルに障害が発生した場合に早期に検出するためにも重要です。例えば、モデルがクラッシュしたり、不正な入力データを処理したりすると、そのような問題を早期に発見することができます。

以上が、MLOps における機械学習モデルモニタリングについての簡単な説明
PCセッティング覚書(WSL2)

### 新規購入したPCにWSL2を設定した覚書

新しく買ったWindows 11のPCにWSL2を設定した自分用メモ。

#### PowerShell 7

PowerShellを起動したら
```
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows
```
なんて出るもんだから、とりあえずPowerShellをアップデートしてみる。

Wingetによるインストールが推奨なので、それに従って実行。

```powershell
winget search Microsoft.PowerShell
```

```powershell
'msstore' ソースを使用するには、使用する前に次の契約を表示する必要があります。
Terms of Transaction: https://aka.ms/microsoft-store-terms-of-transaction
ソースが正常に機能するには、現在のマシンの 2 文字の地理的リージョンをバックエンド サービスに送信する必要があります (例: "US")。
すべてのソース契約条件に同意しますか?
[Y] はい  [N] いいえ:
```
ストアに関する同意が必要らしい。リンク先を確認の上許諾。

```powershell
名前       ID                           バージョン ソース
----------------------------------------------------------
PowerShell Microsoft.PowerShell         7.3.1.0    winget
PowerShell Microsoft.PowerShell.Preview 7.3.101.0  winget
```
無印版をインストールすることにする。

```powershell
winget install --id Microsoft.Powershell --source winget
```

```powershell
見つかりました PowerShell [Microsoft.PowerShell] バージョン 7.3.1.0
このアプリケーションは所有者からライセンス供与されます。
Microsoft はサードパーティのパッケージに対して責任を負わず、ライセンスも付与しません。
Downloading https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/PowerShell-7.3.1-win-x64.msi
  ██████████████████████████████   101 MB /  101 MB
インストーラーハッシュが正常に検証されました
パッケージのインストールを開始しています...
インストールが完了しました
```
インストールの完了。以降はPowerShell 7で作業していく。
PowerShell 7を管理者として実行(Run as Administrator)。

#### WSL2

コマンド一行打つだけらしい。

```powershell
wsl --install
```

```powershell
インストール中: Linux 用 Windows サブシステム
Linux 用 Windows サブシステム はインストールされました。
インストール中: Ubuntu
Ubuntu はインストールされました。
要求された操作は正常に終了しました。変更を有効にするには、システムを再起動する必要があります。
```

再起動が必要らしいので、素直に再起動する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071549/d1bb5373-8589-8dfe-cfc8-039b6f5a814a.png)

Ubuntuの画面が出た。ユーザ名とパスワードを聞かれるので登録。

とりあえずUbuntuのアップデートもしておく。

```shell
sudo apt update && sudo apt upgrade
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071549/a6a25ace-968d-9377-44a4-066fb38ad180.png)

スタートメニューに追加されており、ここから起動できているので、セットアップはできた感じ。
実際の使用に関してはまた別途。
アメリカでのインターンシップを経て、自分に不足していると感じたこと。

## 自己紹介

こんにちは、CDLE youth運営メンバーの櫻田です。

僕は大学3年の終わりから休学して、 1年弱ニューヨークに行きました。行った後数ヶ月後、紆余曲折ありなんとか念願のインターンシップを獲得することになりました。

インターンシップをした企業は、某大銀行のシステム管理などを請け負うSlerでした。その中で僕に与えられた業務はいくつかありましたが、最も重要だったものは、あるリスク値を表示するBIのデモを作成することでした。最終日には、この機能について銀行側のマネージャーの方にプレゼンする機会を頂きやりがいを感じられました。インターンシップをするにあたり沢山の人にお世話になり、感謝しています。

## 自分に不足していたこと


さて本題の自分に不足していたことになります。ソフトスキル、ハードスキルどちらもいくつかあります。また、今回インターンシップを始める前に不足していると気づいていたこと(CSの知識、高度なコーディング能力など)は省きます。僕も駆け出しのエンジニア故お見苦しい点あるかと思いますが、お付き合いください、、、

### 英文メール作成能力
裏方であるエンジニアというポジションゆえかもしれませんが、オフィス内では比較的カジュアルな英語で話します。一方メール作成となると、フォーマルな英語やメール固有の英語表現を用いて、アメリカのメール文化に則って伝えることになります。メールの文章自体は、インタラクティブでないので一度きりで、正確かつ簡潔かつフォーマルな文章を伝える能力が重要です。ちなみに僕が書いたメールの文章を上司に見てもらった時は、構成から表現から全て添削されました。
ですので日常生活での英会話とオフィスで使う英会話の2つに加え、英文メールの書き方(アカデミックライティング)、この3つを分けてそれぞれ高いレベルを保つことが必要かと思います。

### プレゼンスキル
学部の授業で行うレポート発表会とは異なり、ビジネスの現場でのプレゼンは相手を説得して、投資なり採用なり何らかの行動に結びつけさせることが目的になります。
インターン最終日に僕のプレゼンを聞き終えたマネージャーの方にはこのようにアドバイスを頂きました。

「多くの人が自分が言いたいことや知っていることを全て言い切るだけのプレゼンになりがちだが、重要なのは相手が聞きたいことを先回りして伝えることだ。」

批判的な目で見ている相手を説得するには入念な準備が必要です。他人のプレゼンを見ていると、いざ自分がやるとき勇気さえ出せば、堂々と良いプレゼンが出来ると思ってしまいますが、実際には小手先の勇気ではどうにもなりません。
良いプレゼンをするためには、地道に良書を読みながら場数を踏む他ないと思いました。
![](https://www.memecreator.org/static/images/memes/4160828.jpg)
### ミーティングの目的意識
コードのアルゴリズムについて疑問があった時に、メンターの方にzoomミーティングをセットアップしていただいたことがありました。そのミーティングの中で、僕が今の自分の状況を説明してる時に上司が僕の説明を遮って、
「結局何のためのミーティングなの？」
と強めに言われました。かなりヘコみました。
ミーティングには目的意識を持ちましょう。英語で説明することに必死で、相手の視点を意識する余裕がありませんでした。稚拙な英語だからこそ、ポイントファーストで。

### 自分について
これは仕事やキャリアの枠組みを超えて言えることだと思いますが、他人と信頼関係を築くには自分を知ってもらう必要があります。そのために言葉を使ってあれこれ自分のことを伝えようとする訳ですが、その時自分自身自分のことが分からない、言葉にできないことに気づきます。
アメリカでたくさんの人に会って、自分が好きなことや、ニュースに関する自分の意見など聞かれましたが、どうも正確に自分の意見を答えられない。自分はカラッポな人間なのかとも思いましたが、自分の意見を意識するようになって、その原因は世間の意見が気になるばかりに自分の素直な気持ちを無視していたからだと気づきました。参考:[鬱ごはん123話](https://twitter.com/utsugohan/status/1416990260517433344?s=61&t=pjz-MerCYOaqkhgcgHJpXA")
自分の素直な気持ちを大切にすることが、自己アピールのために重要だと気づきました。

### MLB
日本でも野球は人気ですが、ニューヨークでは皆今日の天気よりヤンキースの試合結果を気にしていました。バーやレストランでも野球が見れるので、最低限知っていないと飲みに行った時に彼らの話しの輪に入れません。MLBやNFLなど見始めると、すぐ人と仲良くなれたり、友達や同僚も観戦に行けたりアメリカでのQOLが上がると思います。

## 地道に一歩ずつ
今回挙げたことは、抽象的なことも多くすぐに改善できることばかりではありません。むしろ改善して忘れての繰り返しだと思うので、地道に少しずつ成長していくものだと思って一緒に頑張りましょう。最後まで読んでいただきありがとうございます。
![](https://i.redd.it/py5cwvnaekc81.jpg)
【Alpine.js】x-modelで簡単な検索機能を実装

# 公式ドキュメントで見つけました。
　↓ 実際の挙動はこちらからで確認できます。

https://alpinejs.dev/start-here#building-a-search-input

これだけで簡単に検索機能が実装できる。
```html
<div
    x-data="{
        search: '',
        items: ['foo', 'bar', 'baz'],
        get filteredItems() {
            return this.items.filter(
                i => i.startsWith(this.search)
            )
        }
    }"
>
    <input x-model="search" placeholder="Search...">
 
    <ul>
        <template x-for="item in filteredItems" :key="item">
            <li x-text="item"></li>
        </template>
    </ul>
</div>
```

↓ ここのコードで分かる通り、入力した文字列の始めに一致する(startWith)ものを検索しています。
```
    get filteredItems() {
        return this.items.filter(
            i => i.startsWith(this.search)
```

::: note
<b>getについて</b>
getはAlpine.jsの機能ではなく、JavaScriptの機能です。
動的なプロパティの変化を反映させるためのもので、これをゲッター(getter)と呼びます。

※筆者は実際に使ったことは無いので、間違えてたらすみません。正確な情報を知りたい方は下記公式ドキュメントに目を通しておいてください。
:::
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get

# 仕組み
①x-modelでinputに入力された文字をsearchに格納する。
②searchの入力と同時に、getで動的にfilteredItems()を実行して配列から検索をする。

# まとめ
実際に検索機能を生のJavaScriptで書いたことありますが、結構時間かかりました。
それに比べてなんじゃこれは。トッテモ楽に書ける。
Alpine.js最高オブザイヤー受賞。
paiza.ioでelixir その146

# 概要
paiza.ioでelixirやってみた。
練習問題やってみた。
構想編

# 練習問題
俺cpuのアセンブラから、x64アセンブラを生成せよ。
下のコードから、下の下のコードを生成せよ。

```
  push  1  
  set  a	
  push  1	
  set  b	
label30:
  get  a		
  get  b		
  *				
  set  c		
  get  c		
  push  10		
  /				
  push  48		
  +				
  out			
  get  c		
  push  10		
  %				
  push  48		
  +				
  out			
  push  32		
  out			
  push  ','		
  out
  push  32
  out
  get  a
  push  1
  +
  set  a
  get  a
  push  10
  <
  jz  label30
  push  10
  out
  get  b
  push  1
  +
  set  b
  push  1
  set  a
  get  b
  push  10
  <
  jz  label30
bye:
  bye


```

```
        mov 	$1, %r11
		mov 	%r11, %r13
		mov		$1, %r11
		mov		%r11, %r14
label30:
		mov 	%r13, %r11
		mov		%r14, %r12
		mov		%r11, %rax
		mul		%r12
		mov		%rax, %r11
		mov		%r11, %r15
		mov		%r15, %r11
		mov		$10, %r12
  		mov		%r11, %rax
		div		%r12
		mov		%rax, %r11
		mov		$48, %r12
		mov		%r11, %rax
		add		%r12
		mov		%rax, %r11
		lea	 	msg(%rip), %rdi
		mov   	%r11, %rax;
		mov	    %rax, (%rdi)
		mov   	$1, %rax;
		mov   	$1, %rdi;
		mov   	$msg, %rsi;
		mov   	$1, %rdx;
		syscall;
bye:
  mov   	$60, %rax;
	syscall;


```

# 方針
- ソースは、\nと"  "でsplitする。
- ステートメントで、関数に飛ぶ
- データ構造

```
%{u:""}
```

# 俺cpu ニーモニック

俺cpuは、スタックマシーンです。

|ニーモニック	|意味	|stackの状態|code|
|:---|:--|:--|:--|
|%	|stack-1,stackの剰余を求める。	|1個減る|f004|
|+	|stack-1,stackの加算を求める。	|1個減る|f000|
|/	|stack-1,stackの除算を求める。	|1個減る|f005|
|*	|stack-1,stackの乗算を求める。	|1個減る|f002|
|-	|stack-1,stackの減算を求める。	|1個減る|f001|
|=	|stack-1,stackの等しいを求める。	|1個減る|f00a|
|<	|stack-1,stackの大小を求める。	|1個減る|f00e|
|push 13	    |stackに整数13を積む。	        |1個増える|1001|
|set a	    |変数aにstackを入れる。	|1個減る|300i|
|get a	    |stackに、変数aの値を入れる。	|1個増える|200i|
|out 	    |stackを文字で印字する。	|1個減る|e000|
|jz label	    |stackが真ならlabelへ飛ぶ。       |1個減る|500i|
|jp label	    |無条件でlabelへ飛ぶ。		|変化無し|400i|
|end        |停止                        |変化無し|0000|

以上。
command line windowをちゃんと使いたい

vimを閉じたときに`q:`とタイプして「何か開いちゃったあわあわ」となったことはありませんか？
Vimを使い始めたころはよく間違って開いてしまうことが多かったです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1438460/d48d9442-85d1-df3c-c22e-01e55e7ac95f.png)

# 基本
基本的にできることは、ウィンドウ上でコマンドと検索の履歴閲覧と編集、再実行です。 
再度実行したいコマンド(検索)にカーソルを乗せてエンターを押すことで再実行することができます。

## 開き方
冒頭でも書きましたが、`q:`で開くことができますが、 
他にも以下で開くことができます。 

| `/`の検索履歴 | `?`の検索履歴 | コマンド入力中に開く |
| --- | --- | --- |
| `/q` | `?q` | `Ctrl-f` |

## 閉じ方
名前の通り、Vimのwindowで開いています。 
なのでノーマルモードで`:q`を使うことで閉じれます。
(インサートモードの際はノーマルモードに切り替えてから)

## できること
基本的にはwindowで開いているだけなので、 
Vimの編集で使える機能は使うことができます。 
(これをあまり分かっていなかった僕は上下に移動してエンターを押すだけでした)

### 検索 
window上で検索ができます。 
以前のコマンドを実行したいときに便利です。 
そこまで使う頻度は無いですが、
Vimの正規表現も使って検索ができるのでまれに輝きます。

### 編集 
オペレータを使って編集や置換もできます。 
コマンドライン上で編集するよりも慣れているはずですし、便利なので
一度実行したコマンドを編集して再実行するときはCommand-line windowを使うようになりました。


# おまけ
冒頭のように間違えて開くのが嫌な僕は、以下のようにキーバインドを消しています。
```.vimrc
vim.keymap.set("n", "q:", "<Nop>", { noremap = true, silent = true })
vim.keymap.set("n", "q/", "<Nop>", { noremap = true, silent = true })
vim.keymap.set("n", "q?", "<Nop>", { noremap = true, silent = true })
```
加えて、`:`や`/`を使ったときに常にコマンドラインウィンドウを開いています。

コマンドラインでVimのような操作ができないことに辛い思いをしている方は、以下の設定をおすすめしたいです。
```.vimrc
vim.keymap.set("n", ":", "q:i", { noremap = true, silent = true })
vim.keymap.set("n", "q/", "q/i", { noremap = true, silent = true })
```

# おわりに
いかがでしたでしょうか。
慣れてくると使い勝手が良くなってくると思います。
読んでいただきありがとうございます。
MySQL闇歴史　エピローグ

いろいろ思うところがあって始めたMySQL闇歴史 Advent Calendar。昔話ばかりだからサクッと書けると思いきや、念のための調べ物に手間取ったり、そこから意外な現状を発見したりで書くのに時間がかかったけど面白かった。ぶっちゃけこれでも本当に笑えないような闇が深すぎる話は書いてない。

昔話なんて誰も興味ないかな、とか思わず手短にストレートにぶっちゃけた方がいいのだろう。無知のまま失礼な言動を振りかざして開発チームからこっちに「あいつはなんなんだ？」みたいなことを言われることになるよりよさげ。企業として開発している製品である以上、GitHub含めて表に出ている情報なんてごく一部だし、バグデータベースも公開されてる情報だけではいろいろ経緯が見えないことも多すぎるし。

![バグデータベース-ログイン無し](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102878/4628674a-552a-09fd-b20b-0ff3a0862e6a.png)
*↑バグデータベースにログインしない状態で hypergraph で検索した結果*

![バグデータベース-開発者権限ログイン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102878/9babeb6b-4b29-c036-45bc-7145ea527b2a.png)
*↑バグデータベースに開発者としてログインした状態で hypergraph で検索した結果(項目は画像加工でマスク)*

今回取り上げなかったけど次点だったのがLaunchpad上のMySQLのページ。
![LaunchpadMySQL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102878/cf7cd5c1-6e1c-218d-ec31-1b63a9156fdb.png)
*https://launchpad.net/mysql*
2015年ごろまではここにもコミュニティ向けの情報が集められていたので、特にプロジェクトのところがネタの宝庫になっていて気になるものが散見される。

ほかに思いついたネタは以下の通り。
- SunによるMySQL発表の現場で起きた騒動のあれやこれ
- OracleによるSun発表の現場で起きた騒動のあれやこれ
- MySQL社の謎の出張旅費規程
- リファレンスマニュアルの隣接著作権
- 「私たちの」フォーク
- 約束された未来だったはずのフォーク
- 幻のMySQLアプライアンス

面白かったけど来年はもういいかな。っていうかそもそも一人でアドベントカレンダーが完走できるほど闇が積み上がっていただきたくない。

最後までお読みいただいたみなさま、本当にありがとうございました。

メリークリスマス＆よいお年を！
代入がうまくいかない理由とポインタによる解決

# はじめに
今回は最近C言語の授業で習ったポインタという概念について書いていこうと思います。

# ポインタを習う前の私
まず,2つの整数値を入れ替える関数をつかったプログラムを次のように考えてみた。
```c:swap.c
#include<stdio.h>

void swap(int x, int y){ /*2つの整数を入れ替える関数*/
int temp = x;
x = y;
y = temp;
}

int main(void){
int a, b;
printf("整数Aを入力してください："); 
scanf("%d", &a); /*変数Aの値をキーボードから取得*/
printf("整数Bを入力してください："); 
scanf("%d", &b); /*変数Bの値をキーボードから取得*/

swap(a, b);

printf("整数Aと整数Bの値を入れ替えました\n");
printf("整数A：%d\n", a);
printf("整数B：%d", b);
return 0;
}
```
これを実行してみると、、、![スクリーンショット_20221215_180138.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3060656/93305332-dd0a-9606-1cc6-3f43aac92723.png)
あれ？なんで変わってないの？

# ダメだった理由
結論から言うと値渡しによる引数の受渡しが一方通行だからです。どういうことかというと, main関数から関数swapを呼び出す際に渡されるのが, 実引数a,bの値であって仮引数はコピーにすぎないのです。つまり, 関数の中で仮引数のx, yを変更したとしても, オリジナルのa, bの値に影響は及ばないのです。じゃあ,交換した値を`return`で関数swapに返却させればよいのではと思うかもしれませんが, 関数は2個以上の値を返却することができません。
ここで便利なのがポインタなのです。

# ポインタとは？
変数をデータを入れる箱と考えると, ポインタは箱のアドレスを入れる箱のことです。アドレスとはどこに格納されているのかという場所を表します。
ポインタを使うためには,ある変数のアドレスを求めるアドレス演算子`&`,アドレスを保持するための変数であるポインタ変数`*`という二つの記号を主に使います。
ex)
```c:list1.c
int x=0, y=0;
int *p;  /*ポインタ変数*pを宣言*/
p = &x;  /*xのアドレスを*pに代入*/
*P = 10; /**pに格納されているxの値を10に更新*/
y = *P;  /*yに*pに格納されているxの値を代入*/
```

# ポインタを使ってリベンジ
2つの整数値を入れ替える関数をつかったプログラムをポインタを使って修正すると,
```c:swap2.c
#include<stdio.h>

void swap(int *x, int *y){ /*2つの整数を入れ替える関数*/
int temp = *x;
*x = *y;
*y = temp;
}

int main(void){
int a, b;
printf("整数Aを入力してください："); 
scanf("%d", &a); /*変数Aの値をキーボードから取得*/
printf("整数Bを入力してください："); 
scanf("%d", &b); /*変数Bの値をキーボードから取得*/

swap(&a, &b);

printf("整数Aと整数Bの値を入れ替えました\n");
printf("整数A：%d\n", a);
printf("整数B：%d", b);
return 0;
}
```
これを実行してみると、、、![スクリーンショット_20221215_191038.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3060656/4138db37-d4a1-af2e-2a1a-961270cb9d20.png)
今回はうまくいきましたね！

# おわりに
今回はポインタという概念の初歩的なことについて書いていきました。
初めての記事で読みにくかったかもしれませんが, 最後まで見ていただきありがとうございました！
ネットワーク初心者がOSSにちょびっとコントリビュートした話

# 概要

これは[BBSakura Networks アドベントカレンダー2022](https://adventar.org/calendars/7980)の15日目の記事です。

https://adventar.org/calendars/7980

どうも、最近インターネット業界に入ってきたネットワーク初心者です。
netflow / sflow を触る機会があったので今回はその辺りについて書こうと思います。
「OSSにコントリビュートした」と言うとプルリクあげたんだなってなりそうですけど、そんなレベルではなくてイシューあげたことで機能追加に貢献できたかもなって話です。

# そもそも netflow / sflow って？
一言で言うと、トラフィックの内訳情報をもつ「フローデータ」のことです。
このフローデータをうまくデコード・パースすることによって自身の欲しいトラフィック情報を取得していく感じになります。


# OSSにイシューを投げて解決するまでの流れ

↑の netflow / sflow をパースするライブラリとして今回使ったのが以下のpmacctというもので、実際にnetflowを処理するのをnfacctd、sflowを処理するのをsfacctdと言います。

https://github.com/pmacct/pmacct

ほとんどPaoloさんひとりでメンテしているっぽい？です（すごい！）
JANOG36に登壇されていたらしいのでネットワーク業界の人は知っている人も多いんですかね。。。？
https://www.janog.gr.jp/meeting/janog36/program/opnet

## とりあえずトラフィックデータ見てみる！

スイッチにsflowの設定を入れて、サーバー側でsfacctdを使って雑にcsvにトラフィックデータを吐かせたのが始まりです。
このとき初めて知ったんですけど、netflowと違ってsflowはすーごい量のパケット（フローデータ）が飛んでくるんですよね。

## それで、ここからが今回の話
csvを眺めていると「特定のポートだけトラフィックデータがない」ことに気づきます。

初めはsflowの設定が間違っていてうまくフローを投げられていないのかな〜くらいに考えてました。
ただ、sflowを受け付けているサーバー側のパケットをWiresharkで覗いてみると、問題のポートのsflow自体はサーバーまで到達していることが確認できたので、「じゃあsfacctdでパケットの中身をパースするときに何か問題起きてるのかな？」となりました。
ちなみに、パケットキャプチャの中身を見ていて気づいたのですが、トラフィックデータをcsv化してくれないポートでは**Q-in-Q**のトラフィックが流れていたんですよね。他のポートではQ-in-Q使ってなかったのでこいつをパースするときに問題があるのでは？と。

### ということで実際にソースの中身を見に行ってQ-in-Qの処理（VLANタグの処理）がどうなってるかいざ確認！

どういうふうに処理しているか確認しよー
あわよくば初めてプルリクとか投げてみよー
投げてみよー
みよー、
、、、
orz

はい。僕の実力ではどの辺でVLANタグの処理をしているかくらいまでしか分からず、どう処理を追加したらいいかが分かりませんでした。。。

ということで、プルリク出してみたいという気持ちを抑えつつも**イシューに投げました！**

https://github.com/pmacct/pmacct/issues/626


## 結果

イシューあげたら割とすぐ返事が来まして、メールでパケットの詳細を送りつつ少しやりとりしただけで爆速で直してもらえました！（Paoloさん優しい！！）
一人でうじうじ悩んだりコードを読んだりしていたのがあほらしくなるくらい爆速でしたね。。。

コミット履歴見ると、処理するEtherTypeの変数を追加してその中でC-TAGのVLANまで処理できるようにした感じかな、と。
もうちょっと（いやかなり）頑張ってコード読みこんだら初プルリクあげれたかもなあ。。。とか思ってみたりw

ただまあ、OSSに関わること自体はそこまでハードル高くないと感じた（大規模でなければ）ので、これからもプルリクとかイシュー上げていこうと思えた良い経験でした！
また、それなりのOSSをメンテしている人は技術的にも人間的にも優れてる人多いんだろうなあとも感じられたのは良かったですね。サンプル数1ですが。
ということで次こそはOSSにプルリク出してみたい！！
TSS ：閾値署名の紹介

ブロックチェーンを利用する際にプライベートキーを使いますが、プライベートキーのセキュアな管理方法については、ずっと研究されています。その中の１つは、Threshold Signature Scheme（TSS）という方法があります。

## TSS とは
TSS とは、Threshold Signature Scheme の略語であり、マルチパーティ計算（multi-party computation、略語 MPC）技術の１種です。
イメージ的には

- １つのプライベートキーを複数個の断片に分ける
- 複数個の断片から、閾値個の断片を集めれば、元のプライベートキーを復元できる

例えば総個数 3 、閾値が 2 の場合は、プライベートキーを３つの断片に分けて、その中任意の２つの断片を集めれば、元のプライベートキーを復元できます。

## なぜできる？
数学の話になるので、数学が下手な私はあんまり説明できませんが、ベースは、連立方程式です。連立方程式において未知数を求めるためには、未知数個数分の関係式があれば解けます。
非常に分かりやすい記事があったので、そちらを参照してください。

![](https://atmarkit.itmedia.co.jp/fsecurity/special/53tsss/tsss02.gif)

参照元：https://atmarkit.itmedia.co.jp/fsecurity/special/53tsss/tsss02.html

## マルチサインとの違い
似ているものとしてマルチサインもありますが、比較してみました

  | TSS | マルチサイン
-- | :--: | :--:
プライベートキーの数 | １つ | 複数
ブロックチェーン側の対応 | なし | 必要
断片が他所で流用できる | できない | できる

最後の他所での流用というのは、マルチサインの場合は各自自分が持っているのがフルのプライベートキーである為、普通にアドレスとして使えて署名したりなどもちろんできます。一方、TSS の断片は、フルのプライベートキーではない為、１つの断片だけで署名したりはできません。
これも不便と思う側面がありますが、逆にセキュリティ的にはよい側面ではあります。

要するに、TSS の断片は１つ漏れても、それだけでは何もできないので、被害は発生しません。マルチサインの場合、フルなプライベートキーであるため、漏れたら、そのアカウントが持っている資産がなくなる恐れがあります。

## まとめ
あんまり分かっていなかった TSS 、結構セキュアで、これからいろいろ活用できそうなイメージですね。
OracleDBからBigQueryへのETLで文字化けを解決する

# 初めに
レガシーシステムのOracleDBデータをBigQueryへETLする必要があり、GCPのDataflowでETLをしましたが、
日本語のデータが文字化けしていたので、その回避した経験を記述します。


# 簡単に言えば
1. 文字列byte化してクエリ、BigQueryへBYTES型で格納
1. BigqueryのUDFを設定してBYTEからcp932形式の文字変換


# 処理順番

### Oracle クエリ
```sql
SELECT
    UTL_RAW.CAST_TO_RAW(NAME) AS NAME,
    ...
    other_columns
FROM MEMBERS
WHERE condition
```

### Dataflowの設定
Dataflow 提供テンプレートの JDBC to BigQueryで簡単にETLの設定ができる
※ 各設定値はサンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983876/8a5cdc49-ac1a-00f8-af43-cd95a0eada74.png)



### UDF(user defined function)の設定とクエリ
BigQueryでは、SQL式またはJavaScriptコードを使ってクエリで利用する関数を作成できる。

https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions#javascript-udf-structure

#### 文字変換ライブラリ iconv-lite

https://github.com/ashtuchkin/iconv-lite

こちらのライブラリはこれは jsファイルを提供してないので webpack でパッケージングする必要がありました。
※ webpackでパッケージングするとき参考にした記事：https://dev.classmethod.jp/articles/bigquery-javascript-udf/
パッケージングしたjsファイルはGCPプロジェクトのクラウドストレージにアップロードします。


#### UDF定義とクエリ実行
``` sql
CREATE TEMP FUNCTION conv_test(x ARRAY<INTEGER>)
RETURNS STRING
LANGUAGE js AS """
return iconv_for_udf.decode(x, "CP932")
"""
OPTIONS (
  library = ["gs://project_gcp_storage/iconv-lite_bq-udf.js"]
)
;

select 
    NAME,
    conv_test(TO_CODE_POINTS(MEMBERID)) as converted_name
FROM `project.dataset.MEMBERS`
```


※ iconv-liteのdecode関数は buffer を引数として扱うのでクエリでBuffer Arrayに変換してUDFを呼び出す必要があった
 iconv-liteの例(from iconv-lite github)
```javascript
var iconv = require('iconv-lite');

// Convert from an encoded buffer to a js string.
str = iconv.decode(Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]), 'win1251');

// Convert from a js string to an encoded buffer.
buf = iconv.encode("Sample input string", 'win1251');

// Check if encoding is supported
iconv.encodingExists("us-ascii")
```

### 結果
![スクリーンショット_20221209_163404.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983876/0f353729-d35d-2f78-1dff-8010312938c6.jpeg)


# まとめ
やり方、色々あると思いますが、チーム内のシステムに適用するための方法を探す中で一番簡単にできそうなやり方でした。
辿り着くまでは大変だったが、完成した流れは簡単でシンプルでした。
レガシーシステムのETLがまた今後あるかは別にして、なかなか良い勉強でした。