OmniAICreator/Qiita-1.07M huggingface dataset:
HTMLプロフェッショナル認定試験レベル1(ver2.5)備忘録

# はじめに
HTML認定試験のための勉強をしている。
なかなか覚えられないところのアウトプットを行う。

参考
- [HTML教科書 HTML5プロフェッショナル認定試験 レベル1 スピードマスター問題集 Ver2.5対応](https://www.amazon.co.jp/HTML%E6%95%99%E7%A7%91%E6%9B%B8-HTML5%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E8%AA%8D%E5%AE%9A%E8%A9%A6%E9%A8%93-%E3%83%AC%E3%83%99%E3%83%AB1-%E3%82%B9%E3%83%94%E3%83%BC%E3%83%89%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E5%95%8F%E9%A1%8C%E9%9B%86-Ver2-5%E5%AF%BE%E5%BF%9C/dp/479817646X)

 - [ping-t](https://ping-t.com/)

# HTTPヘッダーフィールド
一言で言うと...
サーバーやブラウザから送る（送られてくる）情報の説明書のようなもの。

主なヘッダーフィールド説明
| ヘッダーフィールド名 | 説明1 | 説明2 |
| ------- | ------- | ------- |
| Accept-Language | ブラウザが受け入れ可能な言語 | ブラウザがどの言語で送って欲しいか|
| Accept | クライアントが受け入れ可能なコンテンツタイプ | ブラウザなどが受け入れられるデータ形式 |
| Age | プロキシにキャッシュする秒数 | リソースが生成されてからの経過秒数 |
| Authorization | 認証情報 |  |
| Cache-Control | キャッシュの制御 | ブラウザなどが受け入れられるデータ形式 |
| Cookie | クッキーの送受信 | ブラウザが保持するCookieの内容 |
| Set-Cookie | Webサーバーが生成するCookieの内容 |  |
| Content-Encoding | 圧縮アルゴリズム | 圧縮形式 |
| Content-Length | メッセージボディのサイズ |  |
| Content-Language | ユーザー向けの言語情報 | メッセージボディのデータの言語 |
| Content-Type | コンテンツのメディアタイプ | メッセージボディのデータ形式 |
| Expires | リソースの有効期限 | いつまで見れるか |
| Host | サーバ名とポート |  |
| Last-Modified | リソースの最終更新情報 |  |
| Location | リダイレクト先のURL |  |
| Referer | 前のページのURL |  |
| User-Agent | リクエストしたブラウザを表す文字列 | クライアントの情報 |

# ベンダープレフィックス
| ベンダープレフィックス | 説明 | 由来 |
| ------- | ------- | ------- | 
| -moz- | Firefox | Mozillaが開発元
| -ms- | Internet Explorer | Microsoftが開発元
| -webkit- | Google Chrome、Safari | webkitエンジン
| -o- | Opera | Operaのo

# box-sizing
引用：https://zero-plus.io/media/box-sizing/
> content-box(初期値)：paddingとborderを要素のwidthとheightに含まない
border-box：paddingとborderを要素のwidthとheightに含む
inherit：親要素の指定を引き継ぐ![スクリーンショット 2023-09-02 14.11.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889120/090ff71d-7e15-6936-283f-b905ae97bed7.png)

border-boxでwidthを400pxとすると、、、
paddingが10px, borderが1pxの時。
表示領域の幅は、
```
400px - 10px * 2 - 1px * 2 = 378px
```
![スクリーンショット 2023-09-02 14.16.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889120/85900bb5-1601-543d-b0e4-868255852b69.png)

# WebSoketとWebRTC
### WebSoket
サーバーとクライアントがリアルタイムで**双方向通信**をするための技術。

### WebRTC
ブラウザ同士の**リアルタイム**で音声、動画、データ通信をするための技術。
プラグインや外部アプリケーションが不要。P2P通信が可能。

| 　比較 | WebSoket | WebRTC |
| ------- | ------- | ------- | 
| 用途 | データ双方向通信（チャットやゲーム） |　リアルタイム音声や動画通信
| 用途例 | チャットやゲーム |　ビデオ会議
| 接続方式 | サーバーとクライアント | ブラウザ間
| データの種類 | テキストやバイナリデータなど | 音声動画など（リアルタイム性）

# Basic認証とDigest認証
| 　比較 | Basic認証 | Digest認証 |
| ------- | ------- | ------- | 
| パスワード送信 | Base64 符号化 |　ハッシュ化
| セキュリティ| 低い |　高い

# media属性に指定できるメディアの種類
| 　メディア指定名 | 説明 | 
| ------- | ------- |
| all | 全てのメディア |　
| screen| 一般的なディスプレイ |
| print|  プリンター |
| projection| プロジェクター |
| handheld| 携帯電話などの画面の小さい機器 |
| braille| 点字ディスプレイ |
| embossed| 点字プリンタ |
| speech| 音声読み上げソフト |
| tty| ターミナルなどの文字幅が固定された機器 |
| tv| テレビ

# ジェネリックセンサー
- 環境光センサー
→スマホの画面明るさ
- 加速度センサー
→歩数計
- 重力センサー
→傾きを察知するゲームなどに使われる
- ジャイロスコープセンサー
→360度の動画やゲームで使われる

- 地理所在センサー
→地図アプリ
- 磁気センサー
→コンパスアプリ
- 絶対オリエンテーションセンサー
→高度なARアプリで使われる
- 相対オリエンテンションセンサー
→特定の場所からどのくらい歩いたか？
- 近隣センサー
→通話中にスマホを耳に近づけると画面が暗くなる
ニューラルネットワークの予測の不確実性（Monte Carlo dropout・概要編）

# はじめに
Monte Carlo dropoutで予測の不確実性を算出する手法の概要を説明します。


# 事前準備（変分ベイズ）
前提知識として必要なベイズ推論と変分推論について説明します。  

### ベイズ推論  
通常のニューラルネットワークでは、出力は変数$y$ですが、ベイズ推論では分布$p(y|x)$を考えます。  
分布が尖った形になっている場合は予測の不確実性が低く、裾が広い場合は不確実性が高いことになります。  

ラベルの分布は、パラメータの分布$p(\theta)$を考え、積分で$\theta$を消去することで求めます。  
$$
p(y|x) = \int p(y|x, \theta)p(\theta) {\rm d}\theta
$$

### 変分推論
パラメータの事後分布$p(\theta|X,Y)$を、計算しやすい分布$q(\theta)$で近似することを考えます。  
近似分布$q(\theta)$は、$p(\theta|X,Y)$とのKLダイバージェンスが小さければ、よい近似となります。  
$$
D_{KL}[q(\theta)||p(\theta|X,Y)] = \int q(\theta)\ln\frac{q(\theta)}{p(\theta|X,Y)} {\rm d}\theta
$$

しかし、直接最小化することは難しいため、データの周辺分布 $\ln p(X,Y)$ とその下界（ELBO）$\mathcal{L}(\xi)$ を考えます。  
これらと、上記KLダイバージェンスには、下記の関係があることが知られています。
$$
\ln p(X,Y) = \mathcal{L}(\xi) + D_{KL}[q(\theta;\xi)||p(\theta|X,Y)]
$$
ここで、$\xi$は$q(\theta)$の形を決めるパラメータで、変分推論では$\xi$を最適化します。  

この関係性を用いて、KLダイバージェンスを最小化する問題を、ELBOを最大化する問題に置き換えます。  
ELBOは下記で定義されます。
$$
\mathcal{L}(\xi) = \int q(\theta;\xi)\ln \frac{p(X,Y,\theta)}{q(\theta;\xi)} {\rm d}\theta
$$

同時確率を条件付き確率に書き換えると、$p(X,Y,\theta)=p(Y|X,\theta)p(X|\theta)p(\theta)$となり、$X$と$\theta$は独立のため $p(X,Y,\theta)=p(Y|X,\theta)p(X)p(\theta)$ と書くことができます。  
これをELBOに代入すると下記のようになります。

```math
\mathcal{L}(\xi) = \int q(\theta;\xi) \ln p(Y|X, \theta) {\rm d}\theta + \int q(\theta;\xi) \ln p(X) {\rm d}\theta + \int q(\theta;\xi) \ln \frac{p(\theta)}{q(\theta;\xi)} {\rm d}\theta

```
```math
= \mathbb{E}_{q(\theta;\xi)}[\ln p(Y|X, \theta)] + \ln p(X) - D_{KL}[q(\theta;\xi)||p(\theta)]
```

$\ln p(X)$は定数なので、ELBOを最大化するために、下記の負の対数尤度と$q(\theta)$とパラメータの事前分布とのKLダイバージェンスの和を最小化すればよいことが分かります。  
```math
\mathbb{E}_{q(\theta;\xi)}[-\ln p(Y|X, \theta)] + D_{KL}[q(\theta;\xi)||p(\theta)]
```

# Monte Carlo dropout
### 概要  
dropoutは、ニューラルネットワークの一部のユニットをランダムに不活化する操作です。  
不活化するユニットは、毎回ランダムに選ぶため、dropoutの操作ごとに異なるニューラルネットワークを得ることができます。  
この特性を利用して、dropoutの操作後のニューラルネットワークのパラメータを、$q(\theta;\xi)$からのサンプリングと考えます。  
つまり、負の対数尤度の期待値を最小化するために、各バッチでdropoutを適用し、そのパラメータでの負の対数尤度を最小化します。  


### 学習方法  
パラメータ$\theta$でのデータ$x$の予測を$p(y|x,\theta)=\mathcal{N}(f(x;\theta),\sigma^2)$、正解を$y$とすると、対数尤度は$\ln p(y|x,\theta)=-\frac{\ln 2\pi\sigma^2}{2} - \frac{(y-f(x;\theta))^2}{2\sigma^2}$となります。  
つまり、負の対数尤度を最小化するためには、2乗誤差を最小化すればよいことになります。

また、事前分布として、平均0の正規分布を仮定すれば、事前分布とのKLダイバージェンスを最小化するためには、$\theta$のL2ノルムを最小化すればよいことになります。

まとめると、各ミニバッチでdropoutを適用してパラメータ$\theta$をサンプリングし、平均二乗誤差とパラメータのL2ノルムを最小化します。  
$$
\mathcal{L} = \frac{1}{n} \sum_{i=1}^n (y_n - f(x_n;\theta))^2 + \alpha ||\theta||_2^2
$$
ここで、$\alpha$は、2つの項のバランスを調整するパラメータです。

### 不確実性の算出  
dropoutを推論時にも適用し、n個のパラメータ$\{\theta_1, \cdots, \theta_n\}$をサンプリングし、事後分布の期待値と分散を計算します。  

$$
\mu(y) = \frac{1}{n}\sum_{i=1}^n f(x;\theta_i)
$$
$$
{\rm Var}(y) = \sigma^2 + \frac{1}{n}\sum_{i=1}^n f(x;\theta_i)^T f(x;\theta_i) - \mu(y)^T \mu(y)
$$

### 参考資料
- Y. Gal and Z. Ghahramani, Dropout as a bayesian approximation: Representing model uncertainty in deep learning, ICML, 2016.
ASP.NET (React) でnpm installを使ってmaterial-uiをインストールしようとして躓いた話

# 開発環境
・JetBrains Rider 2023.2.1
・.NET 6.0

・react 18.2.0
・framer-motion 10.16.2
・material-ui 5.14.7 (@mui/material)

# なにがあったか
 Riderのターミナルから`npm install`をしようとした時、なぜかReactのバージョンが合わないだとかライブラリだとかエラーが出るようになった。

# 原因
　単純な話、**ライブラリをインストールするディレクトリを間違っていた。**

## なぜそうなるんか
RiderやVSCodeでも共通なのだが、直接ターミナルを開くと作業しているカレントディレクトリが開かれる。
我々C#erはNuGetなどでライブラリを入れる時、カレントディレクトリ内に`.csproj`ファイルが存在していなければエラーが発生する。

しかし、その感覚で`npm install`を行うと`package.json`と`node_modules`が存在していない場合は自動生成されてしまうため、**エラーで停止することがない。**

# 解決策
別にこれに限った話ではないが、コマンドを実行する際は**今いるディレクトリを確認する**

# 〆
気が付かぬうちにIDEに囚われてしまった人のためになればいいと思います。
PHPで数値を漢数字に変換

1～9999までの数字を漢数字に変換するプログラムが必要になったため、
今後必要になる可能性も考慮しての備忘になります。

```php:numberToKanji.php
function numberToKanji($number) {
    $kanjiDigits = array('零', '一', '二', '三', '四', '五', '六', '七', '八', '九');
    $kanjiUnits = array('', '十', '百', '千');
    $kanjiBigUnits = array('', '万', '億', '兆', '京'); // 追加の大字を必要に応じて増やすことができます

    if (!is_numeric($number) || $number < 0 || $number > 9999) {
        return '無効な入力';
    }

    $kanji = '';
    $numberStr = strval($number);
    $numberLen = strlen($numberStr);

    for ($i = 0; $i < $numberLen; $i++) {
        $digit = intval($numberStr[$i]);
        $unit = $numberLen - $i - 1;

        if ($digit !== 0) {
            if ($unit === 1 && $digit === 1) {
                $kanji .= $kanjiUnits[$unit]; // 十の場合は「十」を追加しない
            } elseif ($unit === 2 && $digit === 1) {
                $kanji .= '百'; // 百の場合は「一百」ではなく「百」と表示
            } elseif ($unit === 3 && $digit === 1) {
                $kanji .= '千'; // 千の場合は「一千」ではなく「千」と表示
            } else {
                $kanji .= $kanjiDigits[$digit] . $kanjiUnits[$unit];
            }
        } elseif ($unit === 0 && $numberLen === 1) {
            $kanji .= $kanjiDigits[0]; // ゼロの場合
        }

        // 大字を追加する
        if ($unit % 4 === 0 && $unit > 0) {
            $kanji .= $kanjiBigUnits[$unit / 4];
        }
    }

    return $kanji;
}
```
【データ基盤構築/AWS】AWSのEventBridgeでDMSが停止した時にSlackに通知を送るシステムを作る方法

# 今回の課題
AWSのDMSが停止してしまった時に、
Slackにアラート通知を飛ばすシステムの構築を行うことにした。

AWSのLambdaとEventBridgeを使用した。

## 実装手順
以下の手順で、DMSが停止してしまったときにSlackに通知が飛ぶように実装した。



### 1)Lambda関数を作成
#### 1)-1.Slackに通知を飛ばすコードを作成する
```lambda_function.py
import json
import requests
import os

def send_slack_alert(type, title, text):

    alert_channel = "[アラートを飛ばしたいSlackチャンネルのURLの末尾の10桁の文字列]"
    mention_text = ""
    alert_color = "#F30100"
    WEB_HOOK_URL = "https://hooks.slack.com/services/*******************"

    requests.post(WEB_HOOK_URL, data=json.dumps({
        "channel": alert_channel,
        "text" : mention_text,
        "attachments": [{
            "color": alert_color,
            "text":  text
        }]
    }))

def lambda_handler(event, context):

    type = 'error'
    title = 'DMSが停止した時のアラート'
    text = 'DMSが停止しました。'
    send_slack_alert(type, title, text)
    return {
        'statusCode': 200,
        'body': json.dumps(target + 'stopped')
    }
```


#### 1)-2.EventBridgeのイベントを読み込む権限を与える
上記のLambda関数を作成すると、 `[Lambda関数名]-role-********`というロールが同時に作成される。
そちらのロールに、 `AmazonEventBridgeReadOnlyAccess`というポリシーを持たせる。


### 2)Eventbridgeでルールを作成する。
#### 2)-1.ルールの詳細を定義
以下のページでルールの**名前**や**説明**を入力する。
ルールタイプは、**イベントパターンを持つルール**を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/4c845931-8bd0-27f1-b643-a10e94f46591.png)

#### 2)-2.イベントパターンを作成
次に進むと以下のようなページに飛ぶ。
ここで、**DMSが停止する**というイベントが発生した時に、
そのイベントを検知してくれる、イベントパターンを設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/86b3f096-6b73-94f1-54b5-8f40a2482d65.png)

##### イベントパターン作成の手順
上記のページで以下の手順で設定を行えば、
DMSが停止した時に検知イベントを検知するイベントパターンを設定することができる。
1. 作成のメソッドを**カスタムパターン(JSON エディタ)** に指定する。
2. 次にイベントパターンに、以下をペーストする。
```json
{
  "source": ["aws.dms"],
  "detail-type": ["DMS Replication Task State Change"],
  "region": ["ap-northeast-1"],
  "detail": {
    "eventType": ["REPLICATION_TASK_STOPPED"],
    "category": ["StateChange"]
  }
}
```
※**サンプルイベント**という項目で、検知したいイベントタイプを指定して、意図しているイベントを検知できているかテストをすることも可能です。

#### 2)-3.ターゲットを指定する
次に進むと以下のような画面に遷移する。
**機能**という項目に、`1)`で作成したLambdaの名前を選択してターゲットに指定する。

これによって、Slackにアラートを送るためのLambda関数のトリガーに、EventBridgeのルールが設定される。
DMSが停止した際に発生する`REPLICATION_TASK_STOPPED`というイベントをeventBridgeのルールが検知するようになる。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3838333537332f63383265346538302d633237392d303462392d333737662d3338646164623231346263642e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/94e793bc-18ba-03c2-7401-ce29918759c6.png)



あとは確認画面まで進み、**ルールの作成**をクリックすることで、DMS監視システムの構築が完了する。

# まとめ
DMSの`REPLICATION_TASK_STOPPED`というイベントを検知するEventBridgeのルールを作成して、
そちらをトリガーにLambdaが実行されるようにすることで、DMSが停止した時にSlackに通知が飛ぶようなシステムを構築することができた。

AWS EventBridgeでは、他にも色々なイベントパターンを検知することができそうなので、AWSの様々なリソースの動きを監視するのに便利そうだなと感じた。
【チートシート】【Javascript】AtCoder(アルゴリズム)の問題を解く際に覚えておくべきメソッド一覧

## 前提
- コード例は全てJavascriptです
- AtCoderに興味ない方でも文法チェックシートとしても利用できます

## 標準出力
### 一つの文字列を標準入力
```javascript
function main(input) {
  const a = input.split(" ");

  // コードを入れる

}

main(require("fs").readFileSync("/dev/stdin", "utf8"));
```

### 一つの数字を標準入力
```javascript
function main(input) {
  const a = Number(input.split(" "));

  // コードを入れる

}

main(require("fs").readFileSync("/dev/stdin", "utf8"));
```

### 2つ以上の文字列を連続で標準入力
```javascript
function main(input) {
  const args = input.split('\n');
  const words = args[0].split(' ');
  const a = words[0];
  const b = words[1];

  // コードを入れる

}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

### 2つ以上の数字を連続で標準入力
```javascript
function main(input) {
  const args = input.split('\n');
  const nums = args[0].split(' ');
  const a = Number(nums[0]);
  const b = Number(nums[1]);

  // コードを入れる

}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

## 文字列
### 文字列の長さ
```javascript
const str = '大阪府大阪市西区千代崎3丁目中2-1';
console.log(str.length) // 18
```

### 先頭と後ろの空白を削除する
```javascript
const str = '　東京都千代田区霞が関1-2-3　　霞が関ビル　　';
console.log(str.trim()); // 東京都千代田区霞が関1-2-3　　霞が関ビル
```

### 文字列内の空白も削除する
```javascript
const str = '　東京都千代田区霞が関1-2-3　　霞が関ビル　　';
console.log(str.replace(/\s+/g, '')); // 東京都千代田区霞が関1-2-3霞が関ビル
```

### 一つの文字列を別の文字列へ置き換える
```javascript
const str = '大阪府大阪市西区千代崎3丁目中2-1';
console.log(str.replace('大阪', '京都'));　// '京都府大阪市西区千代崎3丁目中2-1'
```

### 文字列が含まれるか判定
```javascript
const str = '大阪府大阪市西区千代崎3丁目中2-1';
if (str.includes('大阪府')) {
  //strに'大阪府'を含む場合の処理
  console.log('大阪の住所'); // '大阪の住所'
} else {
  //strに'大阪府'を含まれない場合の処理
  console.log('違うよ');
}
```

|正規表現|説明|
|--|--|
|\s|一つ以上の空白文字|
|+|回以上繰り返されること|
|g|マッチしたすべてのパターンを一括で置換|

## for
```javascript
let str = '';

for (let i = 0; i < 9; i++) {
  str = str + i;
}
console.log(str); // "012345678"
```

## 配列
### 配列の中身を展開
```javascript
const array = [1,2,3]
// ...(Spread構文を使うと配列の要素を全て展開できる)
console.log(...array) // 1,2,3
```

### 要素を先頭から追加
```javascript
const array = [2,4,6]
array.push(8)
console.log(array) // 2,4,6,8
```

### 要素を後ろから追加
```javascript
const array = [2,4,6]
array.unshift(8);
console.log(...array); // 8,2,4,6
```

### 文字列を配列に
```javascript
const str = 'hello';
const arr = [...str];
console.log(arr); // ['h', 'e', 'l', 'l', 'o']
```

###　配列を文字列に
```javascript
const arr = ['h', 'e', 'l', 'l', 'o']
const str = arr.join(",")
console.log(str) // 'hello'
```

### インデックスを指定して取り出す(スライス)
```javascript
const arr = ['h', 'e', 'l', 'l', 'o']
console.log(arr.slice(1,3)) // ['e', 'l']
console.log(arr.slice(0,3)) // ['h', 'e', 'l']
console.log(arr.slice(-1)) // ['o']
```

## map
### 配列の各要素を2倍にする
```javascript
var items = [1, 2, 3, 4, 5];

var result = items.map(function (value) {
  //配列の各要素を2倍にする
  return value * 2;
});

console.log(result);　// [2, 4, 6, 8, 10]
```

## まとめ
今後もアルゴリズムの勉強をするつもりなので問題を解いて新たにわかったメソッドなどがあれば逐一追記していく予定です

## 参考
https://qiita.com/cotton11aq/items/a8b93d61fca8f83ffaae
VueでDebounceのUnitテストを行う

# はじめに

Vueを用いて検索ボックスを実装することになりました
そこでテストするのに時間がかかったのでまとめておきます

# 問題

テスト駆動開発で検索ボックスを作ろうとしています
検索ボックスは0.5秒入力がなかった際に`emit`が走って親コンポーネントにイベントが飛ぶようにします

テストの設計としては

まず適当な値を入力して`emit`が1度も実行されていないことを確認
0.5秒後に再度`emit`が実行されたかを検証して1回実行されていればOK

このテストを書こうとして`0.5秒`後にテストのアサーションをするのに迷いました

# 解決方法

以下が最終的にできたコードです

```ts:search.spec.ts
import KeywordFilter from '@/KeywordFilter.vue'
import { mount } from '@vue/test-utils'

describe('KeywordFilter', () => {
  test('入力を止めたタイミングで検索をする', async (done) => {
    const wrapper = mount(keywordFilter)
    wrapper.find('.search-box').setValue('test')

    await wrapper.vm.$nextTick()
    expect(wrapper.emitted().changeKeyword).toBeFalsy()

    setTimeout(() => {
      expect(wrapper.emitted().changeKeyword.length).toBe(1)
      done()
    }, 500)
  })
})
```

ポイントは

```ts
test('入力を止めたタイミングで検索をする', async (done) => {
```

ここでasyncの終了を知らせる`done`を引数に渡して
0.5秒たったあとに`done()`を呼ぶことです

これをしないとテストは最初のアサーションだけして0.5秒待たずに終了してしまいます

なので結果的に0.5秒後にemitされることを検証せずにおわりテストは成功してしまいます

# おわりに

asyncにdoneというのがあるのを知らなかったので学びになりました
なので記事にしてみました
2023: Week 35 - HR Month - Transfers / Preppin'Data / Tableau Prep

# Challenge Preppin'Data 2023:Week 35

## 概要
### 従業員の異動件数を集計する

従業員の各月ごとの勤務データがあります。
そのデータには、勤務先のDCコードが入っいます。
勤務した月のデータしか、勤務データにもっていないです。

* 異動データの特徴
1 異動した場合、dc_nbrが次の月のレコードから変更になる。
2 異動した場合、異動元の最後のレコードのleave_dateに異動日が設定される。
3 異動した場合、異動先の最初のレコードのtenure_monthsが0リセットされる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/494ad027-236d-3c88-4f3d-f942217afad8.png)

* 集計上の注意点
従業員が 1 つの DC から別の DC に異動するか、従業員が退職し、その後別の DC に再雇用されるかが区別されていません。そのため、2 か月以内であれば、従業員は退職すると仮定します。
たとえば、従業員が 5 月に DC #1 で勤務し、6 月は勤務せず、7 月に DC2 #2 で勤務した場合、これは異動としてカウントされます。


以下は、インプットデータを時系列に並べたものです。縦が従業員ID、横が月、各フィールドにDCの値を置いて色付けしてます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/a5e59d07-125b-6584-257a-2037648200f6.png)

## 問題のページ（英語）※ここからデータをダウンロード
https://preppindata.blogspot.com/2023/08/2023-week-35-hr-month-transfers.html

## 出題者の回答のページ（英語）※動画あり
https://preppindata.blogspot.com/2023/09/2023-week-35-solution.html

## 自分の解決法

まず、データ取り込み時に来ない使わないデータは削除しておきます。
次に、異動した月のデータ（異動元）を洗い出し、その時のDC番号をフラグとして設定します。
ここでLookup関数を使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/3ad32b0c-0cc2-4d6d-afaa-e9d7308367aa.png)


今回Total行とDCごとの行を作るのでため、分けて考えます。
最後に全部のデータを結合し、計算フィールドで計算を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/b7e4d3b9-397b-d047-ad63-3b3b567cd065.png)
【Python】OpenCVを使った動画から画像の生成

## はじめに
当記事では１秒単位で動画を読み込んで、画像の選択範囲部分を画像として保存することを目的としています。

### この記事の対象者
　Python * OpenCVを使って：
　　・動画を読み込みたい方
　　・フレーム指定で処理をループさせたい方
　　・範囲選択部分を画像として保存したい方

### 動作環境
　・Python：3.10.2
　・opencv-python：4.8.0.76

### 読み込む動画について
　・Windows標準の『クロック』アプリでストップウォッチ機能を１分ほど録画したもの
　・動画内容は以下
　　・フレーム幅：1920
　　・フレーム高：1080
　　・フレーム率：60フレーム/秒

　※動画の一部をgif化したもの↓
![test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3532224/51865a8e-9bcf-abe5-196d-32dfc3a9b0ba.gif)

### フォルダ構成
フォルダ構成は以下の通り。
読み込み対象の動画ファイルは[movie]フォルダに格納。
結果は[ret]フォルダに[image_インデックス番号.jpg]というファイル名で格納していきます。
```
root/
    ├movie/
        └sample.mp4
    ├ret/
        ├image_0.jpg
        └image_1.jpg
         …
    └ readMovie.py
```

## プログラム制御
### 処理全容
```python:readMovie.py
import cv2

FILEPATH = "./movie/sample.mp4" # 動画ファイルの相対パス

# 動画ファイルを読み込む
video = cv2.VideoCapture(FILEPATH)

# 動画情報の取得
frameAll = int(video.get(cv2.CAP_PROP_FRAME_COUNT)) # 動画の総フレームを取得
framerate = int(video.get(cv2.CAP_PROP_FPS)) # 動画フレームレートを取得(当サンプルでは[60]を返す)

# ファイル出力用のインデックス初期化
idx = 0

# 動画1秒単位でのループ処理(※1)
for i in range(0, frameAll, framerate):
    # 動画指定秒数での動画読み込み
    video.set(cv2.CAP_PROP_POS_FRAMES, i)
    ret, image = video.read() # [ret]はread()の処理結果、[image]は処理画像が格納される

    # read()が正常終了した場合に画像ファイル出力を実行
    if ret == True:
        # 画像ファイルとして保存(※2)
        cv2.imwrite('{}{}{}'.format('./ret/image_', idx, '.jpg'), image[390:590, 590:1320]) 

        # ファイル出力用のインデックスをインクリメント
        idx += 1
    else:
        break
```

### ※1部分
以下のrange部分について、rangeの引数は[range(start, stop, step)]となるため、以下値を与えている。
　①[stop=動画の総フレーム]
　②[step=指定秒数毎のフレーム数]

どちらもVideoCaptureのプロパティから取得することが可能(参考リンクを参照)。
当処理では事前処理として『動画情報の取得』部分で各値を取得している。

動画のフレームレートを[step]に与えることで、１秒毎の動画読み込みが可能となる。
(使用する動画ファイルが60FPSのため、[step=30]とした場合は0.5秒毎の動画読み込み処理となる)

```python
for i in range(0, frameAll, framerate):
    #略
else:
```

### ※2部分
imwrite()部分について、受ける引数は[cv2.imwrite(filename, img[, params])となる。
(詳細は参考リンクを参照)

第一引数部分に関しては『保存先+ファイル名+インデックス+拡張子』という文字列を成形しているだけなので割愛。

第二引数部分に関して、[video.read()]で返却された画像について、以下範囲指定をした結果を渡しているイメージ。
範囲指定をしない[image]だけを与えた場合、範囲指定なしの画像を渡すことになる。
　①Y軸部分を390px～590px
　②X軸部分を590px～1320px

```python
cv2.imwrite('{}{}{}'.format('./ret/image_', idx, '.jpg'), image[390:590, 590:1320]) 
```

## 出力結果
フォルダキャプチャの切り抜きですが、結果は以下のようになります。
jpg形式で画像を出力することができました。

![出力結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3532224/3c6c1562-e503-178f-c6a7-5f4a9fb413d2.png)


## おわりに
処理を構築してみて思ったのですが、『動画の指定範囲を画像として保存する』という機会は実生活でほぼないかと思います。
画像認識等で指定秒数毎に画像の一部範囲を読み込んでOCRで文字認識させるといったことに派生できたらと思います。


## 参考
　・OpenCVのドキュメンテーション：VideoCaptureProperties
https://docs.opencv.org/3.4/d4/d15/group__videoio__flags__base.html#gaeb8dd9c89c10a5c63c139bf7c4f5704d

　・imwrite()メソッドのドキュメンテーション
https://docs.opencv.org/3.4/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce
jq コマンドでフィルタリング後の件数を取得する

# 元データ

<details><summary>sample.json</summary>

```json:sample.json
[
  {
    "id": "1611",
    "datetime": "1960-11-04T21:59:55.719Z",
    "tags": [
      "アニメ"
    ]
  },
  {
    "id": "1780",
    "datetime": "1961-02-02T21:13:43.411Z",
    "tags": [
      "映画",
      "スポーツ"
    ]
  },
  {
    "id": "1710",
    "datetime": "1961-03-22T04:37:54.779Z",
    "tags": [
      "スポーツ",
      "小説",
      "プログラミング",
      "漫画"
    ]
  },
  {
    "id": "596",
    "datetime": "1961-04-28T11:42:35.446Z",
    "tags": [
      "スポーツ",
      "音楽"
    ]
  },
  {
    "id": "1070",
    "datetime": "1961-07-23T01:43:18.617Z",
    "tags": [
      "漫画",
      "ゲーム"
    ]
  },
  {
    "id": "1146",
    "datetime": "1961-12-08T13:34:12.188Z",
    "tags": [
      "文学",
      "映画",
      "歴史",
      "メモ"
    ]
  },
  {
    "id": "1292",
    "datetime": "1963-05-12T09:49:42.865Z",
    "tags": [
      "歴史",
      "メモ"
    ]
  },
  {
    "id": "1481",
    "datetime": "1964-06-25T21:19:14.486Z",
    "tags": [
      "文学"
    ]
  },
]
```
</details>

# コマンド

例えば、`datetime` が 1961 年のデータしたい場合はこんな感じ。

```bash|コンソール
cat sample.json | jq 'map(select(.datetime | contains("1961-"))) | length'
```

- `map(select(〜))` で、配列に対してフィルタリング。
- `select(.datetime | contains("1961-")` で `datetime` に `1961-` を含むものを選択。
- `| length` でフィルタリング後の件数を取得。
【Vue.js】開発サーバー初回ビルドまでの環境構築手順

# ◆本記事を作成した背景
Vue.jsの環境構築を行ったのでその振り返りとして手順をまとめました。
Vue.jsの[**クイックスタート**](https://ja.vuejs.org/guide/quick-start.html#creating-a-vue-application)を参考しました。

# 1. Node.jsのインストール確認
```
node -v
```

:::note warn
前提条件としてNode.jsのバージョンは16.0 以上とされています。(2023/09/02時点)
> - 参考元：[クイックスタート](https://ja.vuejs.org/guide/quick-start.html#creating-a-vue-application)
:::

# 2. プロジェクトの作成
Node.jsのインストールが確認出来たら以下のコマンドを実行します。
このコマンド実行すると`Project name`と`No,Yes`で選択するオプションの入力が求められます。
よくわからなければ全て`No`でも次に進めます。

:::note warn
`Project name`はそのままフォルダ名となりますので注意が必要です。
:::

```
npm create vue@latest
```
今回は`vue_hoge`というプロジェクト名で作成しました。
うまくいけば以下のような表示が見られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/841085e6-cae9-20c0-039b-fcc14b6392e0.png)

# 3.開発サーバーのビルド
以下のように作成したプロジェクトのフォルダに移動します。
（今回は`vue_hoge`というプロジェクト名）
```
cd vue_hoge
```

次に以下のコマンドでパッケージをインストールします。
```
npm install
```

次のコマンドを実行し開発サーバーを起動します。
```
npm run dev
```
実行すると`Local:`の項目にlocalhostでアクセスするURLが表示されるので、ブラウザからこのURLにアクセスします。
うまく起動できると以下の画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/039a9b42-e5d8-b71a-a327-b192b7e5319a.png)

# ◆参考サイト
https://ja.vuejs.org/guide/quick-start.html#creating-a-vue-application
RHEL8でDPDK22(LTS) SDKを試す ①インストール

### はじめに
我が家のNATサーバとなっている、ベアメタルのRHEL8.8機にDPDK対応のNIC（Intel I350）が入っているので、DPDK SDKの最新LTS(22.11.2)を入れてみました。そのときのメモです。

注：本記事記載の操作はrootアカウントで行っています。十分ご注意ください。

```
# cat /etc/redhat-release
Red Hat Enterprise Linux release 8.8 (Ootpa)
# lspci | grep Ethernet
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (2) I219-V
01:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
01:00.1 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
```

### まず、python3.8のインストール
DPDK22はpython3.6ではビルドできず、python3.7以降にする必要があります。

```
# python3 -V
Python 3.6.8
# yum install python38
# python3 -V
Python 3.8.16
# pip3 -V
pip 19.3.1 from /usr/lib/python3.8/site-packages/pip (python 3.8)
```

### つづいてMeson/Ninjaのインストール

```
# pip3 install pyelftools
# pip3 install meson ninja
# meson --version
1.2.1
# ninja --version
1.11.1.git.kitware.jobserver-1
```

### DPDK22のソースをダウンロードしてビルド/インストール

LTS（long term support）バージョンを入れないと余計な苦労をするハメになるので、ちゃんと[ここ](https://core.dpdk.org/download/)から最新LTSバージョンをダウンロードします。

なお、2023/9/1時点のLTSは22.11.2となっています。

```
# cd /home
# wget https://fast.dpdk.org/rel/dpdk-22.11.2.tar.xz
# tar xJvf dpdk-22.11.2.tar.xz
```

Meson/Ninjaでビルド/インストールします。

```
# cd dpdk-stable-22.11.2/
# meson build
# cd build
# ninja
# ninja install
```
以上でビルドとインストールは完了。恐ろしく簡単でした(時間はかかります)。/usr/local/binや
/usr/local/includeにSDKの各種ファイルがちゃんとインストールされています。

```
# modprobe vfio-pci
# modprobe uio_pci_generic
# /usr/local/bin/dpdk-devbind.py -s

Network devices using kernel driver
===================================
0000:00:1f.6 'Ethernet Connection (2) I219-V 15b8' if=eno1 drv=e1000e unused=vfio-pci,uio_pci_generic *Active*
0000:01:00.0 'I350 Gigabit Network Connection 1521' if=enp1s0f0 drv=igb unused=vfio-pci,uio_pci_generic *Active*
0000:01:00.1 'I350 Gigabit Network Connection 1521' if=enp1s0f1 drv=igb unused=vfio-pci,uio_pci_generic *Active*
（後略）
```

DPDK対応ドライバのvfio-pciやuio_pci_genericも使えそうです。

### 今後

dpdk-devbindとかDPDK22の各種ツールを試してみたいと思います。
Ubuntuの入れて便利になったツール・設定3選

# はじめに

会社で別チームに1週間遊びに行ったときに色々便利になるツールを教えてもらったので、今後私がいれるときのメモ用を兼ねて残しておきます

# 1. terminator

terminatorはキーバインドが利用できるemulatorなので、画面分割が手軽にできるようになります

まずはインストールします

```
$ sudo apt update
$ sudo apt install terminator
```

アプリが追加されているので起動します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/a232cc6b-c543-9ac2-e657-77af1b63dcd0.png)

画面分割は`shift+ctrl + e`で垂直分割
`shift+ctrl + o`で水平分割ができます

https://ryonakagami.github.io/2020/12/22/ubuntu-terminator/

# 2. fzf

fzfは`ctrl + r`での履歴からのコマンド検索を便利にしてくれます

インストールします

```
$ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
$ ~/.fzf/install
```

`ctrl + r`をすると補完が効いていい感じになります
`alt + c`をするとディレクトリを選択して`cd`までしてくれます

## 以下のエラーが出た場合

```
unknown option: --scheme=history
```

以下を実行してターミナルを再起動させると動きました

```
$ sudo apt purge fzf
```

https://ryonakagami.github.io/2020/12/22/ubuntu-terminator/

# 3. CapsLockをctrlにかえる

これは設定になります

```
$ sudo vi /etc/default/keyboard
```

以下の箇所を変更します

```keybord
XKBOPTIONS=""
↓
XKBOPTIONS="ctrl:nocaps"
```

PCを再起動すると`CapsLock`が`Ctrl`として使えるようになります

うまく行かない場合は以下を設定してから再起動をするとできるかもしれません

https://qiita.com/peachft/items/c5de9a0224a6e710ba1d

# おわりに

あとはエイリアスをはるとかなり効率よくかいはつができます
Vimももうちょっと使いこなせるようになりたいです

# 参考

https://ryonakagami.github.io/2020/12/22/ubuntu-terminator/

https://ryonakagami.github.io/2020/12/22/ubuntu-terminator/
Render.com の使い方

Render.com に静的なサイトを公開する方法です。
Gitlab と連携させます。

## ソースファイル
Gitlab に
public/index.html というファイルを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/82bd8c0e-eb8b-8b80-2c65-096d56f46af2.png)

## Render.com の設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/3f5c4e3c-7c88-e9ec-992a-3ee60cfee652.png)

Name: storytelling
Repository: https://gitlab.com/ekzemplaro/storytelling
Branch: master
Root Directory: public
Publish Directory: ./

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/761666ea-f3c0-1ae0-70c6-848864e8f666.png)


## デプロイ
Manual Deploy をクリック
![render_sep0201.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/456e49de-50a6-b8ab-876a-ac5281ea5b3b.png)

## 作成されたページ
https://storytelling-5q5w.onrender.com/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/4969c9c5-e6b1-6824-8903-315ae0c7c921.png)
Unity初心者の失敗記録

# はじめに
この記事はUnity初心者の私が、ゲーム作成の過程で躓いたエラーとその時の対処をまとめた備忘録的な内容となっています。
今後内容の追加、変更を行う場合があります。


参考にさせて頂いたHP
Unity入門の森
https://3dunity.org/game-create-lesson/music-game/
使用しているツールはUnity2022.3.7f1とVisual　Studio Community　2022です。


# ミスと対処方法

・ゲームの動作を確認しながら操作したデータが一部消える

※プレイモード（▷ボタンでon,off）を終了しないままHierarchyのオブジェクトやコードを変更しても、プレイモードを終了した時に一部変更が保存されずにプレイモード開始時にロールバックされる。

→▷ボタンが青色になっているとプレイモードになっているので作業を行う場合は一旦プレイモードを中断する必要があります。画面の動きが少ない場合、▷ボタンの横のポーズボタンで止めている場合は特に混乱しがちなので今どんな状態かを逐次確認が必要です。



・Visual Studioでエラー検出されないのにUnity側ではエラーが発生する。

※一番多く発生した問題です。

→class宣言文などのスペルミス、public、privateの間違いなどの宣言部分での間違い、または宣言の過不足によるエラーの場合が多かったです。


・ゲーム画面でノーツが意図しない挙動（画面上のパネルを流れずに宙を舞う）をしてしまう。

原因：コードのミスでノーツを重ねて配置していたため、そのノーツに他のノーツが衝突する、という事を繰り返すしノーツが意図しない挙動をしていました。

→Sceneで画面を確認する事で問題を発見できました。ゲーム画面で何か意図しない挙動をする際にはScene側で画面を確認すると問題が見つかるかもしれません。
Unsafe legacy renegotiation disabled.

## はじめに
node.js 16が2023年9月11日にサポート終了することに伴いnode.js 18にバージョンアップをおこなった。その際に発生した事象の対応方法についてまとめる。

## 発生事象
axiosで他システムとの通信時に下記のエラーが発生した。
```
EPROTO B8150000:error:0A000152:SSL routines:final_renegotiate:unsafe legacy renegotiation disabled
```
エラーの内容としては、危険なSSLのリゴシネーションが拒否されているとのこと。
node.js 18以前はSSLのリゴシネーションがデフォルトで許可されていたが、CVE-2009-3555の脆弱性に対処するためにデフォルトで許可しないように対応されたことが原因となっている。全ての通信でSSLのリゴシネーションの許可が必要になる訳ではないので、必要に応じて対処してあげる必要がある。

## 対応策
バージョンアップ後に動作確認を行ったところ、axiosの引数にhttpsAgentがあるので、Agentを生成して`secureOptions`に
`crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT`を設定してあげることで従来通りの通信ができるようになる。


```js:axios.js
import crypto from 'crypto';
import https from 'https';


const allowLegacyRenegotiationforNodeJsOptions = {
  httpsAgent: new https.Agent({
    secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,
  }),
};

function makeRequest(url: string, data: object) {
  return axios({
    ...allowLegacyRenegotiationforNodeJsOptions,
    url,
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    method: 'POST',
    data: { some: 'data' },
  });
}
```

## 参考
https://dev.to/johnnyreilly/nodejs-18-axios-and-unsafe-legacy-renegotiation-disabled-18ki

https://stackoverflow.com/questions/74324019/allow-legacy-renegotiation-for-nodejs/74600467#74600467

https://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2009-3555
CloudRunでstart and then listen on the port defined by the PORT environment variableエラーがでる

# はじめに

Rustで作ったAPIをCloudRunにデプロイしました
以下を参考にしました

https://zenn.dev/kowaremonoid/articles/7e077f9eb4439b

しかしうまくいかなかったのでまとめます

# 問題

デプロイしたとこ以下のエラーが出ました

```
Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable.
```

# 解決方法

CloudRunではデフォルトでポートを`8080`にする必要がありました
しかし、私の環境では`10500`で起動していました

```rust:main.rs
    let addr = SocketAddr::from(([0, 0, 0, 0], 10500));
```

`8080`になおしたところうまくデプロイできました

```rust:main.rs
    let addr = SocketAddr::from(([0, 0, 0, 0], 8080));
```

# おわりに

無事にファーストリリースができてよかったです

# 参考

https://zenn.dev/kowaremonoid/articles/7e077f9eb4439b
RustでCORS設定を入れたのに効かない

# はじめに

自分でWebサイトを作っており、ある程度デプロイができそうだったので、フロントエンドをFirebase、バックエンド(Rust)をCloudRunにデプロイしました

しかし、CORSエラーになってしまったのでまとめます

# 問題

```
Access to fetch at 'https://hoge-api.com' from origin 'https://hogehoge.jp' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
```

このエラーが出たので以下を参考にCORSの設定をしました

https://qiita.com/raiga0310/items/3b67cd83a04703c73d62

しかし何故かエラーになってしまい困っていました
単純なのでなにをすればいいのかわかりませんでした

# 解決方法

これは単なるぼんミスでアクセスするAPIのオリジンを間違えていました
CloudRunのオリジンだったので似ていて見逃していました

ちゃんと確認しましょう

# おわりに

久しぶりに自分のミスでつまづきました
気をつけましょう

# 参考

https://qiita.com/raiga0310/items/3b67cd83a04703c73d62
sentry issueの棚卸し

 ## sentry cliをインストール

https://docs.sentry.io/product/cli/installation/?original_referrer=https%3A%2F%2Fwww.google.com%2F
```
curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION="2.20.6" sh

sentry-cli --help


```

## 構成と認証

```
sentry-cli login

This helps you signing in your sentry-cli with an authentication token.
If you do not yet have a token ready we can bring up a browser for you
to create a token now.

Sentry server: sentry.io
Open browser now? [y/n] y
Enter your token: 
Valid token for user xxx@yyy

Stored token in /Users/xxyy/.sentryclirc


```

![Screen Shot 2023-09-02 at 12.15.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606196/250e39cd-55f8-4b96-814e-243524c5dab3.png)

## issueの棚卸し

```
sentry-cli issues list --org ${ORG_NAME} -p ${PROJECT_NAME}

+------------+--------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------+-------+
| Issue ID   | Short ID                       | Title                                                                                                                                         | Last seen                   | Status     | Level |
+------------+--------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------+-------+


```

- event数とuser数取得できないのか。。。
【Jackson】デシリアライズ時に「nullならデフォルト引数」を実現する2通りの方法【Kotlin】

`jackson-module-kotlin`では、デシリアライズ時に`JSON`上の`undefined`と`null`が区別されており、デフォルト引数が利用されるのは`undefined`の場合のみです。
`null`の場合にもデフォルト引数を利用したい場合、2通りの方法が考えられます。

## NullIsSameAsDefaultを有効化する
1つ目は、`KotlinFeature.NullIsSameAsDefault`を有効化する方法です。
この方法は、全体へこの機能を適用したい場合に有効です。

```kotlin
import com.fasterxml.jackson.databind.ObjectMapper
import io.github.projectmapk.jackson.module.kogera.KotlinFeature
import io.github.projectmapk.jackson.module.kogera.KotlinModule

val module = KotlinModule.Builder().enable(KotlinFeature.NullIsSameAsDefault).build()
val mapper = ObjectMapper().registerModule(module)
```

## JsonSetter(nulls = Nulls.SKIP)
2つ目は、パラメータに`JsonSetter(nulls = Nulls.SKIP)`を付与する方法です。
この方法は、プロパティ毎の特別な挙動を表現したい場合に有効です。

ただし、この機能は執筆時現在リリースされておらず、`jackson-module-kotlin 2.16`を待つ必要が有ります。

```kotlin
import com.fasterxml.jackson.annotation.JsonSetter
import com.fasterxml.jackson.annotation.Nulls

data class Data(@JsonSetter(nulls = Nulls.SKIP) val v: Int = -1)
```
Pythonで文字列加工「余計な空白文字を取り除く」

# 前書き
Pythonで文字列を扱っていると余計な空白文字がやたら並んでいる文章に遭遇して、その後の処理で困ることがありました。

例）`「I have a　　　pen.」`

この記事では、`a`と`pen.`の間にある余計な空白文字を取り除き、`I have a pen.`のように整った文字列に組み直すコードを共有したいと思います。

追記：
個人的に「これはうまくできたな」と思うコードを、『Pythonで文字列加工』と題して記事に残そうという思いで書いています。(シリーズ化するかは未定......)

もっと良い方法があればどんどんツッコミもらえると嬉しいです！

# 開発環境
Google Colaboratory

# 本題
```Python:
' '.join([i for i in text.split(' ') if i != ''])
```

上記が、前書きで説明した文字列加工を実現するためのコードである。

このコードのポイントとしては内包表記、文字列メソッド`join()`、`split()`の３つ

以降に処理の流れを、順を追って説明する。

## 手順①

まずは、空白文字とそれ以外を分けて考える。

そこで、`split()`を用いる。splitの引数には`' '(半角スペース)`を指定する。
```Python
text = "I have a    pen." # 例：「a」と「pen.」の間にのみ余計な空白文字が存在している。

print(text.split(' '))
# 出力
# ['I', '', 'have', '', 'a', '', '', '', '', 'pen.']
```

## 手順②
空白文字を基準に分割された文字列がリスト型として取得できたら、これらを一つひとつif文に掛ける。

このとき、条件式に`''`を除くような指定を行うことで、空白文字を除いた要素のみが残る。

```Python:
str_list = []

for i in text.split():
  if i != '':
    str_list.append(i)
  else:
    continue
```

```python:
print(str_list)
# 出力
['I', 'have', 'a', 'pen.']
```

## 手順③
空白文字を除いた要素のみのリストが取得出来たら、最後はそれらを元の文字列へと、ひとまとめにする。

ここで`join()`を使う。

リストを引数に、その要素は`' '`で連結される。
```Python:
print(' '.join(str_list))
# 出力
# I have a pen.
```

以上が処理の流れの説明である。

## 内包表記の利用について
内包表記を利用することで上記手順に記載のコードを1行にまとめることができますが、内包表記の詳しい説明については、ここでは割愛します。

# 使用例
```Python:
text = "I have a    pen."
text = ' '.join([i for i in text.split(' ') if i != ''])
print(text)
# 出力
# I have a pen.
```

# 終わりに
最近は卒論の研究活動はじめ、Pythonを触ることのほうが多くなってしまい、Webアプリ開発の勉強にまったく手が回せていないです。1日がもっと長い時間あれば......

密かに計画していた月いち更新も半年を迎えたところで途絶えてしまいましたT_T
が、ここで投げ出すことはしないよう頑張ります!

学生生活も残りわずかとなりましたが、卒業は確定ではないので気を引き締めて残りの期間も駆け抜けたいと思います。
画像を一括でWebP変換し、元画像を削除するyarnコマンドを作成

## WebP変換をコマンドで叩けるようにしたい
これまで画像のWebP変換にはGoogle製の [squoosh](https://squoosh.app/) を使用していたんですが、毎回手動で行うのも面倒なので、コマンドで叩けるようにしたい。

## Squoosh CLIは非推奨になってしまった
この場合の方法としてはSquoosh CLIを使うのが一般的だったようですが、既にこれが開発打ち切りとなり利用が非推奨になっています。

巷でWebP変換の方法を漁ると、まだこのSquoosh CLIでの方法がたくさん出てきますね。

## sharp-cliが良さそう
Squoosh CLIの代替になるようなライブラリを探した結果、使い勝手と最終更新日を考慮してsharp-cliに行きつきました。
https://www.npmjs.com/package/sharp-cli

## コマンド作成

前提として、jpg,jpeg,pngは全てWebPに変換できるように。svgとicoは対象外としました。

自分の場合はNext.jsのプロジェクトということで、基本画像はpublic/imagesフォルダ内に格納しているので、対象ディレクトリの指定も設けておきます。

加えて、WebP変換後には元画像を削除するように、以下のスクリプトを自作。非同期処理はしてないです。

```
// scripts/deleteOriginalImages.mjs

import glob from 'glob';
import fs from 'fs';

glob('public/images/**/*.@(jpg|jpeg|png)', (err, files) => {
  if (err) {
    console.error(err);
    process.exit(1);
  }

  files.forEach(file => {
    fs.unlink(file, err => {
      if (err) {
        console.error(err);
        process.exit(1);
      }
      console.log(`Deleted: ${file}`);
    });
  });
});
```
結果的に、package.jsonに仕込むコマンドは以下のようになりました。
```
"convert-webp": "sharp -i \"public/images/**/*.@(jpg|jpeg|png)\" -f webp -o {dir} && node scripts/deleteOriginalImages.mjs"
```

これで、`yarn convert-webp`を叩けば一括でWebP変換＆元画像削除を実現できます。

加えて、huskyでjpgなどが検知されたらエラーを吐く設定をしておくと良さそうですね。
【Laravel】ルーティングは優先度に注意して設定する

Laravelのルーティングは「**上から設定された順番に実行される**」という特性がある。
今回は、このルーティングの優先度によって生じるエラーの例と対応策を紹介する。
間違った点があればご指摘いただけますと幸いです。

## エラー発生例
Laravelのルーティングは、「**上から登録されている順番に実行される**」という特性がある。

この特性を知らずにルーティングを設定すると予期しないエラーが発生する恐れがある。
特に、**ルートパラメータを使用するとき**にエラーが起きやすい。

例えば、以下のルーティングファイルで、「/user/create」にアクセスしようとすると、404エラーが発生する。

```php:web.php
Route::get('/user/{id}', [UserController::class, 'show']);
Route::get('/user/create', [UserController::class, 'create']);
```
## エラー要因
ルーティングは上から順番に実行されるため、１つ上の「/user/{id}」を実行しまったのが原因である。
「/user/create」の「create」が「/user/{id}」のルートパラメータidと同じ位置にあるため、createがルートパラメータとして渡されてしまう。
その結果、意図しないコントローラ内のアクションメソッドを実行してしまいエラーに繋がってしまった。

## 対応策
ルーティングの優先度による上記のようなエラーを避けるための対応策をいくつか紹介する。

### 順番を変える
ルーティングの順番を変えると簡単にエラーを回避できる。
```php:web.php
Route::get('/user/create', [UserController::class, 'create']);
Route::get('/user/{id}', [UserController::class, 'show']);
```
しかし、この方法だとルーティングを追加・更新する度に順番を入れ替える必要も出てくるので、あまりおすすめはできない。
そこで、次に紹介するwhereメソッドを使用した正規表現パターンによる制約がおすすめである。

### 正規表現で制約を付ける
ルートインスタンスのメソッドを使用することで、指定したルートパラメータに正規表現パターンの制約を付けることができる。

#### whereメソッド (単体で制約したい場合)
ルーティング単体で使用するルートパラメータに制約を付けたい場合はwhereメソッドを使用する。

例えば、ルートパラメータidが数字の時しか実行しないようにしたい場合、以下のようにwhereメソッドで制約を付けることができる
```php:web.php
Route::get('/user/{id}', [UserController::class, 'show'])
    ->where('id', '[0-9]+');
Route::get('/user/create', [UserController::class, 'create']);
```

#### patternメソッド (グローバルで制約したい場合)
グローバルでルートパラメータに制約を付けたい場合はpatternメソッドを使用する。

patternメソッドは **App\Providers\RouteServiceProvider**クラス内の**bootメソッド**で定義する。
```php:RouteServiceProvider.php
public function boot(): void
{
    Route::pattern('id', '[0-9]+');
}
```
上記の正規表現パターン定義によって、ルーティングで使用するルートパラメータidは数値のみしか受け付けないという制約が自動的に適用される。
```php:web.php
Route::get('/user/{id}', [UserController::class, 'show'])
// idが数値の場合のみ受け付ける
```
「id」のように同じ名前のルートパラメータに同じ正規表現パターンの制約を付けたい場合は、whereメソッドを用いて１つ１つ単体で定義するより、patternメソッドを用いてbootメソッド内で一括でパターン定義する方が便利である。

---
参考サイト
　- [Laravel 8.x ルーティング](https://readouble.com/laravel/8.x/ja/routing.html)
　- [Laravel 404 Not Foundエラーはルーティング順に原因があった](https://zenn.dev/keitaro_code/articles/632ef95cad98a4)
iPhoneを遠隔でiTunesに接続する

今更ながらのiTunes。

# 結論
USBデバイスサーバーを使う。
使えたのはIODATAのWN-DS/US-HSという機種。

 

 

## 追記
ローカルネットAとBはVPNで接続されていて、それぞれのドメインでアドレスは違うとする。

ローカルネットBに接続されているデバイスサーバーに対してローカルネットAのWindowsからnet.USBというソフトを使用して接続する。

元々ローカルネットで使用する予定の機器なので、VPNで予めネットワーク構成を組んでおく必要があります。

 

## 追記２
最初はソフトウェア上でできないか探していたけどなかった。

USB over EthernetやUSB over IPといったワードで検索すると、ソフトウェアで上記を再現したソフトが出てくる。

ただ、iPhoneは「USBメモリ」としてのデバイスIDと「電話」としてのデバイスIDを持っている？
最初にUSBメモリとして認識し、その後電話デバイスとして認識するっぽい。

IODATA以外の製品ではiTunesから同期することができなかった。

BuffaloのLDV-2UHも同様。それ以外は試していません。
スイッチにつながっている機械をコマンドから確認する。

# 概要

帳簿には、このL2スイッチのこのポートにはサーバXXのeth1がつながっているはずだが、それを確認するには現地で目視するしかないのか？→そんな時は、スイッチ(サーバ)上で以下のコマンドを実行することで確認できる。

*今回実行するコマンドは、メーカ事に異なる可能性があるので、コマンドの詳細自体は各種調べる必要がある。

# 目星のあるサーバとスイッチにログインできる場合。

## スイッチ上での確認

スイッチ上で以下のコマンドを実行し、ポートが上がっているか、そもそもケーブルが刺さっているかを確認する。

```
show interfaces
```
すると、各ポートの情報を見ることができる。何番ポートにケーブルが刺さっているのか、それがTrunkポート（複数のvlanを通す）ものかなどを確認できる。

参考サイト
https://www.infraexpert.com/study/catalyst5.html

その後、以下のコマンドを実行し、各ポートの先につながっているmacアドレスを確認する。
```
show mac-address
```

参考サイト
https://www.infraexpert.com/study/catalyst7.html

ここで、写っているmacアドレスを控えておくこと。

## サーバ上での確認

以下のコマンドを実行する。
```
ip a
```
その後、`link/ether`の後に続く12個の英数字(macaddress)を、先ほど`show mac-address`での結果から比較して、当てはまるものがあるか確認する。
```:出力例
81: eth0@if82: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03　（←ここ。）   brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
```

ここが当てはまっていれば、該当のスイッチには、同じmacアドレスを使用しているインターフェイスが接続されている。


# サーバにログインできず、ipアドレスのみがわかっている場合。

IPMIのポートなどはSSHして確認するというわけにもいかず、スイッチだけのコマンド操作で完結させたいと思うこともあるかと思われる。その時は以下の手順を実行する。

## L2スイッチでの操作

目星のあるL2スイッチで、サーバの持つIPアドレスをL2スイッチ自身が持っている場合、以下のコマンドを実行する。
```
ping 対象の持つIP

show arp
```
show arpで、pingを実行したIPアドレスに紐づく　macアドレスを確認する。
L2スイッチ自身に対象と同じネットワークセグメントのIPを持っていない場合は、同NWセグのIPを持つサーバorネットワーク機器にて上記のコマンドを実行する。サーバの場合は、`ip n`コマンドを実施して、ipアドレスとmacアドレスの対応を確認すること。

その後、L2スイッチ上で、以下のコマンドを実行し、対象のmacアドレスが先にあるポートを確認する。
```
show mac-address
```

参考サイト

https://atnetwork.info/ccna2/arp07.html

https://maku.blog/p/p7q7n4i/
【備忘】JAWS-UG 大阪「AWSのセキュリティサービス＆ソリューション座談会」の内容メモ

最近プライベートでオフラインイベントにちょいちょい参加し始めたので、備忘録ベースで記事化していきたいと思います。今回は2023年8月31日、JAWS-UG 大阪「AWS のセキュリティサービス＆ソリューション座談会」に現地参加したのでその内容共有です。

https://jawsugosaka.doorkeeper.jp/events/161561

# AWS RDK 〜AWS ConfigのカスタムルールをLambdaで書くときに使うツールキット〜
* RDK(Rule Development Kit)はAWS Configルールのカスタムルールを作成を支援するキット
* カスタムルールはLambdaかGuardで書けるが、RDKはLambdaで書く。
* AWS SAMのようなイメージと紹介されていたが、確かにツール導入から実装までの手順がすごく似ていた。SAMの触り方は詳細手順付きでQiitaでまとめているので、良ければご一読ください。

https://qiita.com/vallack5296/items/95e861bf18db0e541e89

* 使うためにはS3やIAM等、他サービスの権限が必要。最低限必要なポリシーは下記Gitを参照。

https://github.com/awslabs/aws-config-rdk/blob/master/policy/rdk-minimum-permissions.json


# ガードレールを運用しよう(仮)
ガードレール自体の内容は省略しますが、話の流れで出てきた下記ツールの存在を知れたのが大きかったです。
* AtlantisというTerraformのCIツールがある。試しに触って記事化したい。

https://www.runatlantis.io/

* tfsecというTerraformのコードをセキュリティのベストプラクティスに基づいてスキャンする仕組みがある。GitHubActionsにも使える。

https://github.com/aquasecurity/tfsec

# AWSはどのようにセキュリティ文化を育んでいるか
* AWSにおけるセキュリティ人材育成の仕組みを解説していた。
* AWSではサービスを開発するチームと、セキュリティチームは分かれている。
* 開発要員は増える一方、セキュリティ要員はまだまだ少ないため、開発チーム内でセキュリティ人材を育成するAWS Security Guardiansという仕組みがある。導入した後の実績として、セキュリティレビュー完了までの時間が 26.9%（21 万日以上）短縮された。
* セキュリティを考慮する際、脅威モデリングのアプローチ方法を紹介したAWS公式のブログ記事やThreat modeling for buildersのWorkshopなどが紹介されていた。

https://aws.amazon.com/jp/blogs/news/how-to-approach-threat-modeling/

https://catalog.workshops.aws/threatmodel/en-US


* AWSが監査を受けたレポートはAWS Artifactにまとめられており、「AWSの責任についてはここを読んでくれ！その他の部分の監査については任せた！」なんて荒業もできるっぽい。（ここは少し語弊あるかもです）

# 感想
今回はじめてJAWSイベントに参加しました。参加して良かったと感じた点は、知らないサービスや普段自分であまり勉強しない分野の知識が得られた点です。社内外のイベント参加は今後も意識的に回数を増やしていきたいところです。

一方反省点としては、オフラインに関わらず他のエンジニアの方と交流がほぼ出来なかった点です。ここはもう恐れず自分から話かけるしかないと思っていますが、まだ少々心理的なハードルが高い状態です汗。この一年でなんとかしたい…！
あともう一つ、記憶が新しいうちに聞いた内容をさっさと記事化すべきでした。メモしていなかったオフライン限定の内容は時間がたったら忘れていました。次からは遅くとも次の日までには記事にするとか、最初からブログに乗せる想定のメモをする等で対策します。

今後も色々参加することになると思いますが、可能な限り記事化します。
【React状態管理7】valtio


# 概要

React の状態管理の 1 つである、`Valtio`(ヴァルシオ)について学んだことをメモします。

# 学習内容

- [valtio とは](#valtio-とは)
- [導入方法](#導入方法)
- [設定方法](#設定方法)

# Valtio とは

Zustand や Jotai と同じ会社が作っているライブラリ。初心者向けで使いやすい。
コンポーネント側で状態を設定し、全体に渡す。
valtio は React 外で動く。

## 特長

- Proxy によりクライアントの複雑性を吸収するため、破壊的メソッドのようなことを考える必要がない
- 記述量が少なく、簡単に使える
- レンダリングの最適化も自動で行われる

# 導入方法

## インストール方法

```bash
$ yarn add valtio
```

# 設定方法

1. `proxy`により、管理したいデータを`store`に保存する

```javascript
export const store = proxy({ todos: [] });
```

2. `useSnapshot`を用いて、`store`で管理するデータを呼び出す。

```javascript
const { todos } = useSnapshot(store);
```

## 使用例

```javascript:state/todos.ts
import { Todo } from "src/types";
import { proxy } from "valtio";

// データtodosをstoreで管理する
export const store = proxy<{todos: Todo[]}>({ todos: [
    { id: 1, text: "foo", isDone: false },
    { id: 2, text: "bar", isDone: true },
    ]
});

// store内のデータtodosの要素isDoneを更新する
export const toggleIsDone = (id: Todo["id"]) => {
    store.todos.forEach((todo) => {
        todo.isDone = todo.id == id ? !todo.isDone : todo.isDone;
    });
};

// store内のデータtodosに新規のtodoを追加する
export const addTodo = (text: Todo["text"]) => {
    store.todos.push({id: store.todos.length + 1, text, isDone: false});
}
```

```javascript:pages/index.tsx
import type { NextPage } from "next";
import { store, toggleIsDone } from "src/state/todo";
import { useSnapshot } from "valtio";

const Home: NextPage = () => {
  const { todos } = useSnapshot(store); // storeのデータtodosを取得する

  return (
    <div>
      <h2>TODO一覧</h2>
      {todos.map((todo) => (
        <div key={todo.id}>
          <label style={{ fontSize: "2rem" }}>
            <input
              type="checkbox"
              checked={todo.isDone}
              onChange={() => toggleIsDone(todo.id)} // storeのデータtodos内の値を更新する
              style={{ width: "1.5rem", height: "1.5rem" }}
            />
            {todo.text}
          </label>
        </div>
      ))}
    </div>
  );
};

export default Home;
```

```javascript:pages/add.tsx
import type { NextPage } from "next";
import { ComponentProps } from "react";
import { addTodo } from "src/state/todo";

const Add: NextPage = () => {
  const handleSubmit: ComponentProps<"form">["onSubmit"] = (e) => {
    e.preventDefault();
    addTodo(e.currentTarget.text.value); // storeのデータtodosに新規の値を追加する
    e.currentTarget.reset();
  };

  return (
    <div>
      <h3>TODO追加</h3>
      <form onSubmit={handleSubmit}>
        <input type="text" name="text" autoComplete="off" required />
        <button>追加</button>
      </form>
    </div>
  );
};

export default Add;
```

# 参考

[IT Kingdom](https://it-kingdom.com)
[Valtio 公式ページ](https://valtio.pmnd.rs/docs/introduction/getting-started)
[GitHub リポジトリ](https://github.com/yamashin01/react_state_management/tree/main/Valtio01)
データの取得と複製 画像ファイルを E01 形式から dd 形式に変換する


◆目的
E01 および dd は、ハードディスク、USB ドライブなどのストレージ デバイスのビット単位のコピーを保存するためのフォレンジック イメージ ファイル形式です。

Linux コマンドを使用して E01 ファイル形式を dd ファイル形式に変換する方法を理解できるようにすることです。

◆概要
xmount ツールについて、さらなる分析のために Linux ワークステーション上で E01 イメージ ファイルを dd イメージ ファイルに変換する方法を理解するのに役立ちます。

１．
対象の画像内のWindows_Evidence_001.E01ファイルを確認します。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477527/bea5e1bb-6f9f-df20-456b-c5c2fe95c5ca.png)

01ファイル形式のイメージ ファイルをddファイル形式に変換します。
これを行うには、<INS> xmountツール</INS>をインストールする必要があります。

２．
ランチャー パネルから[ターミナル]アイコンをクリックして、コマンド ライン ターミナルを起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477527/0bb378ed-e012-81c5-4532-055f3b5f24da.png)

３．
コマンドラインターミナルが起動します。アプリケーションをインストールするには、端末のroot権限が必要です。

そこで、「 sudo su 」と入力してEnterを押します。パスワードの入力を求められます。パスワードとして「toor 」と入力し、 Enterを押します。

ここで、次のスクリーンショットに示すように、ルート端末に入ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477527/2378ccb8-bb25-2ec2-2b75-a8861cbd8e09.png)

４．
xmountをインストールするには、コマンドapt-get install -y xmount を入力してEnterを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477527/3f3db0c1-f638-91a2-bcc5-0a106bad332f.png)

※インターネット接続に問題が発生した場合は、コマンドifdown -aに続いてifup -aを実行します。次に、コマンドapt-get install -y xmountを実行します。

※別のプロセスが apt コマンドを使用している場合、apt-get install -y xmount コマンドは実行されません。このシナリオでは、Ubuntu Forensics仮想マシンを再起動し、 xmountのコマンドを実行すると、上記のスクリーンショットに示すように正常に実行されます。

５．
共有ディレクトリから証拠ファイルをマウントすることはできません。したがって、Windows_Evidence_001.E01ファイルを共有ディレクトリからUbuntu のホームディレクトリにコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477527/936011e4-f0b1-35e8-fed5-c9c78d24fd4a.png)

６．
xmount を使用して E01 ファイルを変換してマウントするには、ターミナルでコマンドxmount --in ewf Windows_Evidence_001.E01 /home/jason/Documentsを実行します。このコマンドは、E01 ファイルを dd ファイルに変換し、Documentsフォルダーにマウントします。

<h6><INS>注意</INS></h6>
コマンドを実行する前に、マウント ディレクトリが空であることを確認してください。新しい空のフォルダーを作成し、作成した空のフォルダーの場所をマウント ディレクトリに指定することもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477527/76f0c13a-8c95-cfab-1b01-2fc6436d5070.png)

７．
マウントされたドライブ (ここでは、Documents ) がシステム上に作成されます。

８.
次のスクリーンショットに示すように、マウントされたドキュメントディレクトリをクリックしてWindows_Evidence_001.ddファイルを見つけます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477527/a783d8fc-de5e-8a16-9d0a-ed34f86700c4.png)

9、
このようにして、E01 ファイルを dd ファイル形式に変換してさらに調べることができます。


10
調査者の次のタスクは、このファイルをマシンにマウントし、その内容を表示することです。証拠ファイルのマウントについては、次で説明します。

開いているウィンドウをすべて閉じます。