OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails】uglifierはterserに置き換えた方がいいかもな話


とあるプロジェクトである日突然にそれは訪れました。

デプロイ時の`assets:precompile`でエラーが発生し、デプロイに失敗するようになったのです。

config系の設定値は変えてないし、特にバージョンアップなどしてないし、変更したことといえばいくつかライブラリを追加した(nodeのパッケージ)のとReactのファイルをいくつか追加したぐらい🤔

同じような現象でハマる人が減りますようにという期待を込めて、情報共有として残しておきます。




# TL;DR
* sprockets + gemのuglifierを使用してjsのcompileをしている場合は、compile用のgemをterserに変更して、assets.rbも変更したほうが良さそう
* uglifierが使えるのはES6まで
* railsもterser推奨っぽい


# 何が起こった？
冒頭で概略は説明しましたが、デプロイ時に実際に出たエラーは以下のような感じです（プロジェクト名・ブランチ名の部分は伏せてあります）


```bash
# ...(略)

rake stdout: Nothing written
rake stderr: rake aborted!
Uglifier::Error:
/var/www/xxx/app/assets/config/manifest.js:2
/var/www/xxx/shared/bundle/ruby/3.0.0/gems/uglifier-4.2.0/lib/uglifier.rb:291:in `parse_result'
/var/www/xxx/shared/bundle/ruby/3.0.0/gems/uglifier-4.2.0/lib/uglifier.rb:221:in `run_uglifyjs'
/var/www/xxx/shared/bundle/ruby/3.0.0/gems/uglifier-4.2.0/lib/uglifier.rb:166:in `compile'

```

どうやら`Uglifier`のエラーのようです。しかしそれ以上のことはほとんどわかりません。。

# 調べてみる

uglifierのエラーでググってみると、ES6構文を使うにはjs_compressorの設定を書き変えるといいよーという記事がいくつかヒットします。
```ruby:production.rb
config.assets.js_compressor = Uglifier.new(harmony: true)
```

「いやこれはやってるっちゅーねん😅」

という想いを押し殺して根気よくいろいろ記事を漁ってみます。

そうすると同じような現象のissueが出てきました。↓

https://github.com/lautis/uglifier/issues/174

> The Safe Navigation / Optional Chaining operator (?.) was first introduced in ECMAScript 2020 (ES2020). For various reasons, Uglifier supports up to ES5 (ES6 with harmony: true). #43610 leads to (rails/sprockets#713), which mentions to use terser gem instead.

なにやらES6構文まではuglifierが使えるけど、ES2020とかになるとterserを使えとのことでした。

回答のリンクを辿ってみると、rails自体terserを推奨に変わっているようでした。↓

https://github.com/rails/sprockets/pull/713

この通り設定を変えて祈るようにデプロイしたところ無事デプロイ成功できました。

どうやら新しく追加したReactのファイル内にES7以降の構文が使われていたんでしょう。

（ただReactはTypeScriptで書いており、tsconfigのtargetはes5にしてあったので、sprocketsでcomplileされるときはes5の構文で渡されるのでは？とか思う部分もあるので、詳しい原因とか挙動については検証しきれていないです。）

# 具体的な設定
一応どのように設定したら良いか書いておきます（リンクのissueを見ればすぐわかりますが）

```diff_ruby: Gemfile
- gem 'uglifier'
+ gem 'terser'
```

```ruby: config/production.rb
config.assets.js_compressor = :terser
```

# さいごに
フロントエンドのビルドにwebpackerやwebpackだけを使っている場合はこのような問題は起こらないはずですが、レガシープロジェクトでどうしてもsprocketsをやめられない事情がある場合はterserに移行したほうが良さそうです。


もう少し詳しい事情をご存知のかたおりましたらコメントいただけると助かります
Java+GradleでOpenCV（JavaCV）を使う

# 前提

Gradle を使って Java のアプリケーションを作成します。
Gradle のインストール方法、基本的な使い方などについては記載しません。

筆者の実行環境は次の通りです。
```
$ gradle --version

------------------------------------------------------------
Gradle 7.4.2
------------------------------------------------------------

Build time:   2022-03-31 15:25:29 UTC
Revision:     540473b8118064efcc264694cbcaa4b677f61041

Kotlin:       1.5.31
Groovy:       3.0.9
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          11.0.11 (JetBrains s.r.o 11.0.11+9-b60-7590822)
OS:           Windows 10 10.0 amd64
```


# 手順

コマンドプロンプトから以下のコマンドを実行します。
```
# 作業用フォルダを作成し、カレントディレクトリを変更する。
$ mkdir hogehoge\work\TestJavaCv
$ cd hogehoge\work\TestJavaCv

# Java アプリケーションを初期化する。
# いくつか質問されるが、全てデフォルト設定（単純に Enter を押下）で問題なし。
$ gradle init --type java-application
```

<br>

生成された"**TestJavaCv\app\build.gradle**"に下記の変更を加え、OpenCV（JavaCV）の依存関係を追加します。
JavaCV と対応する OpenCV のバージョンの確認は次のファイルから確認できます。
URL: https://github.com/bytedeco/javacv/blob/＜JavaCV のバージョン(例：1.5.6)＞/pom.xml
```
dependencies {
    // Use JUnit test framework.
    testImplementation 'junit:junit:4.13.2'

    // This dependency is used by the application.
    implementation 'com.google.guava:guava:30.1.1-jre'

++    // OpenCV（JavaCV）の依存関係を追加。
++    implementation group: 'org.bytedeco', name: 'opencv-platform', version: '4.5.3-1.5.6'
}
```

<br>

試しに OpenCV（JavaCV）を使ってみます。
生成された"**TestJavaCv\app\src\main\java\TestJavaCv\App.java**"を以下の内容に変更します。（コピペしてください）
```
package TestJavaCv;

import org.bytedeco.opencv.global.opencv_highgui;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point;
import org.bytedeco.opencv.opencv_core.Scalar;
import org.opencv.core.CvType;

public class App {
    public String getGreeting() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        System.out.println(new App().getGreeting());


        // 480x270 の真っ白の画像を作成
        Mat mat = new Mat(270, 480, CvType.CV_8UC3, new Scalar(255, 255, 255, 255));

        // 中央に赤色の円を描画
        opencv_imgproc.circle(mat, new Point(mat.cols()/2, mat.rows()/2), mat.rows()/4, new Scalar(0,0,255,255), -1, 0, 0);

        // 画像の表示
        opencv_highgui.imshow("test", mat);
        opencv_highgui.waitKey(0);
    }
}
```

<br>

次のコマンドを実行することで、ビルド・実行が可能です。
```
$ gradle build
$ gradle run
```

先ほど記載したソースコードを実行すると、日本国旗っぽい画像（下図）が表示され、OpenCV（JavaCV）を利用できていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2617929/2f6b6e32-9e0b-c0cd-df0b-0c9ec55a911e.png)
OpenGL Textureに関するメモ書き

# OpenGLのテクスチャの取り扱いに関する自分用メモ
(勘で書いているのであまりあてにしないでください。自分へのメモ書きのつもりで書いています)
## テクスチャに関するポイント

### テクスチャスロット
 テクスチャスロットは描画されるテクスチャのスタックで、描画する際はここに置いてあるものを参照してテクスチャサンプリングを行う。テクスチャスロットは一回の描画単位(glDrawElements)で決定される。スロットの数はハードによって異なる(?)
 テクスチャをShaderに結び付ける際、『glUniform1i(自分のエンジンだとMaterial::SetTexUniform)』にはその ***テクスチャを割り当てている『テクスチャスロット番号』を指定する***
## テクスチャを使用するまでの手順
### テクスチャの生成
glGenTextures・glBindTexture・glTexParameteri・glTexImage2Dでテクスチャを生成する。このとき、そのテクスチャの識別用固有IDが一緒に返ってくる(ここまでは簡単)
### 描画
1. glActiveTextureに任意のテクスチャスロット番号(GL_TEXTUREi)を渡し、使用するテクスチャスロットをアクティブにする
2. glBindTextureでテクスチャをバインドする(第二引数には識別用の固有テクスチャIDを渡す)。このときステップ1でアクティブにしたテクスチャスロットにテクスチャが割り当てられる(おそらくglActiveTextureを使用しない場合は自動的にGL_TEXTURE0に割り当てられる？)
3. **glUniform1iにステップ1のテクスチャスロット番号を渡し、テクスチャをShaderに結び付ける**
4. 今のドローコール内の次のテクスチャをShaderに割り当てる(1～3を繰り返す)
5.  テクスチャの割り当てが終わったら描画を実行する
6. 描画して使い終わったら、もう一度glActiveTexture後、glBindTexture(GL_TEXTURE_2D, 0) でバインドを解除しておく(なんかこれをしとないと別のとこに影響して描画がおかしくなることがある？？？)  
7.  また別のオブジェクトの準備に移行する
``` 
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, mTextureID);

m_material->SetTexUniform("_SrcTexture", 2);

Draw();

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, 0);
```
Crowd Worksの使い方


みなさん、学習したら今度は、お金稼ぎたいですよね！
そこで、今回は案件獲得のチャンスをGetできるサービスの一つ
「Crowd Works」の使い方の基礎をご紹介していきます。


### ３種類の案件

1.タスク型
2.応募型
3.コンペ型

> 1.タスク型

タスク型の案件は検索画面から絞り込みで探すことがで来ます。

![スクリーンショット 2022-07-03 11.01.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1314502/9e9404f4-0cfb-6567-8eab-a0d70872060e.png)


＜7月3日(日)付けでのタスク型の案件＞

![スクリーンショット 2022-07-03 11.02.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1314502/78439229-841c-0182-1014-041fc347402c.png)



タスク型の案件は誰でも、受けることができるので、実績をつくるのには、近道かもしれません。

> 2. 応募型のタスク

crowd works の中で一番主流な案件です。

まだ、駆け出しのエンジニアは、、、以下のポイントから探していくなが良いかも知れません。。。

＜主流ポイント＞
・案件の価格が安価なもの
・募集人数が比較的多いもの
・応募状況にて、応募人数が０のもの
・応募期限や納期が比較的近いもの
など、他にもたくさんございますが、以上のポイントを軸に探していくことが
早期獲得のチャンスにつながるでしょう。

レッツ、トライアンドエラーで案件獲得に励みましょう！

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
ご愛読ありがとうございました。
何か気づきや質問があれば、コメントお願いします。
新しい情報を取得するたび、更新していきます。

良ければ、LGTM、ストックよろしくお願いいたします！
Amplify Function を TypeScript で開発し、ESLint, Prettier で解析する CI/CD 環境

Amplify 便利ですよね。Amplify Function を TypeScript で実装し Lambda にデプロイする方法を調査しました。

本記事は [Amplify Docs の公式サイト](https://docs.amplify.aws/cli/function/build-options/)の解説を元に TypeScript を ESLint と Prettier で静的コード解析した上で Lambda にデプロイする一連の流れを説明します。

本題ではないものは割愛して公式サイトのリンクを掲載します。

# CI/CD 環境の考え方

https://qiita.com/t-kurasawa/items/89f7b8e963221c229add

基本となる考え方は上記記事と同じです。

- CI はソースコードの①静的コード解析→②テストを担う
- CD は③ビルド→④デプロイを担う


# 環境構築

#### [Amplify CLI をインストール](https://docs.amplify.aws/cli/start/install/)

`npm install -g @aws-amplify/cli`

#### TypeScript, ESLint, Prettier, husky のインストール

`package.json`

```json
{
  "devDependencies": {
    "@types/node": "^18.0.0",
    "@typescript-eslint/eslint-plugin": "^5.30.3",
    "@typescript-eslint/parser": "^5.30.3",
    "eslint": "^8.0.1",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.25.2",
    "eslint-plugin-n": "^15.0.0",
    "eslint-plugin-promise": "^6.0.0",
    "husky": "^8.0.1",
    "prettier": "^2.7.1",
    "typescript": "^4.7.4"
  }
}
```

# Amplify Function を TypeScript で開発
#### Amplify Function を自動生成

`amplify add function` で `generateReport` という名前でファンクションを自動生成します。すると `amplify/backend/function/generateReport/src` 配下にいくつかの JavaScript ファイル等が生成されています。

#### ファンクションを TypeScript で開発

`amplify/backend/function/generateReport/lib` 配下に TypeScript で開発したプログラムを格納します。

# CI/CD 環境準備

#### ESLint, Prettier で開発した TypeScript を静的ソースコード解析

[.eslintrc.json](https://eslint.org/) と [.prettierrc](https://prettier.io/) を準備してください。

`package.json`
```json
{
  "scripts": {
    "lint:fix": "prettier --write 'amplify/backend/function/**/lib/*.ts' && eslint --fix amplify/backend/function/**/lib/*.ts",
  }
}
```

#### [TypeScript をデプロイ用 JavaScript へトランスパイル](https://docs.amplify.aws/cli/function/#set-up-a-function)

`amplify push` コマンドは任意のスクリプト処理を実行してからLambda にデプロイするように設定出来ます。

`package.json` のスクリプトに TypeScript をトランスパイルする処理を書きます。
```json
{
  "scripts": {
    "amplify:generateReport": "cd amplify/backend/function/generateReport && tsc -p ./tsconfig.json && cd -"
  },
}
```

各ファンクションのフォルダ直下（`amplify/backend/function/generateReport`）に `tsconfig.json` を配置してください。

```json
{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "lib": ["dom", "esnext"],
    "module": "commonjs",
    "moduleResolution": "node",
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "outDir": "./src",
    "baseUrl": "./",
    "rootDir": "./lib",
    "paths": {
      "src": ["./lib"]
    }
  }
}
```

# CI/CD 実行

#### CI（継続的インテグレーション）

husky で git commit 前に lib 配下の TypeScript 開発ソースコードを ESLint, Prettier で静的コード解析します

`.husky/pre-commit`

```bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn lint:fix
```

#### CD（継続的デリバリ）
husky で git push 前に lib 配下の TypeScript 開発ソースコードを JavaScript にトランスパイルして src 配置して、Lambda にデプロイします。


`.husky/pre-push`

```bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

amplify push
```


最終的には以下のようなフォルダ構成になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/768dc3b1-d5ea-9a1f-8f74-115faa5e9ad7.png)

以上です。
IT謎解き #paiza


本記事は7/3に限定公開で作成、7/10に全体公開されました。
相談OKとありますがPOHとは趣を異にするものと思いますので…

## 01

```rb
puts 'NPKKE VLQEAEMH YEGKC'.tr('LFICPZSNHRMKOVETUGWAJXYDBQ','A-Z')
=> HELLO NAZOTOKI WORLD

c2
```

## 02

```rb
p 0b1110010001
=> 913

9sd
```

## 03

(3分待つしかなさそう)

```
m
```

## 04

URLに "FLAG_NZTKC" とある

```
Vk
```

## 05

```rb
puts Time.at(1660316400, in: '+09:00').strftime('%Y/%m/%d')
=> 2022/08/13

IH
```

## 06

```rb
require 'prime'
puts Prime.lazy.drop_while{|e|e<=29}.next
=> 31

B
```

## 07

vim
:q

```
yb
```

## 08

```rb
require 'prime'
puts Prime.lazy.each_cons(2).select{|x,y|y-x==2}.drop_while{|x,y|x<=101}.next.join(', ')
=> 107, 109

2
```

## 09

```rb
puts [97, 122, 105, 97, 112].map(&:chr).join
=> aziap

Js
```

## 10

(まあ、2択ですよね)
R

```
ZW
```

## 11

(これはシーザー暗号と言えるのか…?)

```rb
puts 'IZ*sZ'.chars.map{|e|(e.ord+7).chr}.join
=> "Pa1za"

1zC
```

## 12

```rb
x=31
100.times{x=(x * 41 + 59) % 265}
puts x
=> 21

g==
```

## 13

Base64...

```
c29sdmVkIHByb2JsZW1zCg==

solved problems
```

というのはミスリードで、
https://paiza.jp/nazotoki/c29sdmVkIHByb2JsZW1zCg==
に行くのが正解っぽい。

不正解時のヒントが「大きい」「小さい」と出るので、二分探索で
888
を導き出す。

## 14

13に正解するとキーワード欄が不自然に空白なので反転するとURLが現れる
画像ファイルをバイナリエディタで開くと
cG9seWdsb3QK
が表示される

以上で全問クリアとなります。
僕が使ってる git コマンドのエイリアスを紹介


## はじめに

@ohakutsu が alias の記事を書いていたので私も利用している alias を書いてみました

https://qiita.com/ohakutsu/items/c6abc4588c9d75e54230

## 設定してる Git aliase

`.gitconfig` や `.zshrc` は dotfiles レポジトリに保存しています

https://github.com/mziyut/dotfiles

その中で Git に関連するもの ( かつ よく使うもの ) だけ記載します

### Zsh

```zsh
alias g='git'
```

### Git

```sh
[alias]
	ad = add
	ci = commit
	co = checkout
	cop = !"git branch --all | tr -d '* ' | grep -v -e '->' | peco | sed -e 's+remotes/[^/]*/++g' | xargs git checkout"
	d1 = diff HEAD~
	d2 = diff HEAD~~
	d3 = diff HEAD~~~
	d4 = diff HEAD~~~~
	d5 = diff HEAD~~~~~
	dc = diff --cached
	delete-merged-branches = !git branch --merged | grep -vE '^\\*|master$|main$|develop$' | xargs -I % git branch -d %
	dmas = diff master
	dmai = diff main
	ds = diff --staged
	dw = diff --color-words
	fe = fetch
	ignore = "!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi"
	pl = pull
	st = status
```

Ref: https://github.com/mziyut/dotfiles/blob/master/.gitconfig

## Reference

- https://github.com/mziyut/dotfiles
- https://qiita.com/ohakutsu/items/c6abc4588c9d75e54230
RaspberryPi4にDockerをインストールしてdata-rootを変更する

# やりたいこと

RaspberryPi4にDockerをインストールします。デフォルトだと、/var/lib/dockerがdockerが使用するデータのルートディレクトリになってますが、これを適当な場所に変更します。


# 手順

### 1.dockerをインストールする

```shell
sudo apt install docker.io
```


### 2.dockerのデータルートを設定

以下のファイルを作成します。ファイルが存在しないので新規作成です。

```shell:/etc/docker/daemon.json
{
    "data-root": "/data/app/main/docker"
}
```


### 3.dockerを再起動します

```shell
sudo systemctl restart docker.service
```

ちゃんと/data/app/main/dockerにそれっぽいファイルができていることを確認します。

```shell
sudo ls -l /data/app/main/docker
```

### 4./var/lib/docker/は不要なので削除します

```shell
sudo rm -rf /var/lib/docker
```

### 5.piユーザのサブグループにdockerグループを追加します

```shell
sudo usermod -aG docker pi
```
【2022年版】 ネットワークインターフェースの有効/無効化

# 【2022年版】 ネットワークインターフェースの有効/無効化

## はじめに

  - ネットワークインターフェイスの有効/無効化をしたい
  - 対象ネットワークインターフェイスは ```eth0``` とする

## 概要

  - 以下のコマンドを使う
    - ifconfig
    - ifdown
    - ifup
    - ip link set
    - nmcli connection

## 使用例

### ifconfig

  - 有効化

    ```terminal
    $ ifconfig eth0 up
    ```

  - 無効化

    ```terminal
    $ ifconfig eth0 down
    ```

### ifup

  - 有効化

    ```terminal
    # ifup eth0
    ```

### ifdown

  - 無効化

    ```terminal
    $ ifdown eth0
    ```

### ip link set

  - 有効化

    ```terminal
    $ ip link set eth0 up
    ```

  - 無効化

    ```terminal
    $ ip link set eth0 down
    ```

### nmcli connection

  - 有効化

    ```terminal
    $ nmcli connection up eth0
    ```

  - 無効化

    ```terminal
    $ nmcli connection down eth0
    ```

## おわりに

  - かんたんでしたね
btrfsでsubvolumeを作ってみる

# やりたいこと

btrfsのsubvolumeを作って、snapshotを作ってみる


# 手順

### 1.subvolumeを作る

```shell
sudo btrfs subvolume create /data/app/main
```

### 2.subvolumeができたことを確認する

```shell
sudo btrfs subvolume list /data/app
```

### 3.snapshot用のディレクトリを作る

```shell
sudo mkdir /data/app/snapshot
```

### 4.snapshotをとる

```shell
sudo btrfs subvolume snapshot /data/app/main /data/app/snapshot/20220702
```

### 5.snapshotを消す

```shell
sudo btrfs subvolum delete /data/app/snapshot/20220702
```
npm パッケージにOSネイティブファイルを入れて必要な物だけインストールさせる

npm パッケージに OS ネイティブのファイルを入れ複数プラットフォームに対応させたいが、容量等の問題で不要な物をインストールさせたくないというケースで、インストール時に必要なファイルだけ取得してくる方法を紹介します。

# 要約
ネイティブファイルのプラットフォーム毎にパッケージを作成し、package.json の `os` で対象 OS を指定します。
`--save-optional` で全プラットフォーム用のパッケージを参照すれば不要な物はスキップされます。

# サンプル
https://github.com/Hotspring-r/PlatformSpecificPackageTest

# 解説
サンプルファイルは4つのディレクトリがあり、src がパッケージを参照するソース。nativeTest が参照されるライブラリ、nativeTest-linux, nativeTest-win がそれぞれ linux, windows 用のネイティブファイルです。
src が nativeTest を、nativeTest が nativeTest-linux , nativeTest-win を参照します。

1つのリポジトリに複数の npm パッケージを入れるために [gitpkg.now.sh](https://gitpkg.now.sh) を使用しています。解説はこちらの記事をご覧ください。
[githubリポジトリのサブフォルダーからnpm installしたい時](https://qiita.com/taguchi_taguchi_taguchi/items/7d5ee48db84139e4b713)

## ネイティブファイル用パッケージ
nativeTest-linux , nativeTest-win はテスト用のネイティブファイルとして .sh , .cmd ファイルがおいてあり、echo で文字列を返します。
package.json の `os` でインストール対象になる OS を指定しているので、対象外の OS にインストールしようとすると失敗します。
https://www.startup-cloud.co.jp/liberty-technology/PublicItems/npm/package.json.html#os

windows 用パッケージを linux 環境にインストールしようとした例： ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153956/efb17fdc-3ce6-1444-1f66-0c1dcf34631d.png)
同様に `cpu` でアーキテクチャを指定することもできます。
https://www.startup-cloud.co.jp/liberty-technology/PublicItems/npm/package.json.html#cpu

## ライブラリ用パッケージ
nativeTest では上記ネイティブファイルを実行し、結果を取得します。
上記2パッケージを参照していますが、普通に参照すると非対応 OS でエラーになります。
`--save-optional` オプションを付けてインストールすることで非対応 OS でもエラーにならずスキップされます。
package.json には `dependencies` ではなく `optionalDependencies` に記述されます。
https://www.startup-cloud.co.jp/liberty-technology/PublicItems/npm/package.json.html#optionaldependencies
``` javascript 
{
  "name": "nativetest",
  ＜略＞
  "optionalDependencies": {
    "nativetest-linux": "https://gitpkg.now.sh/Hotspring-r/PlatformSpecificPackageTest/nativeTest-linux?main",
    "nativetest-win": "https://gitpkg.now.sh/Hotspring-r/PlatformSpecificPackageTest/nativeTest-win?main"
  }
}
```
## 本体
src では nativeTest を参照しています。
nativeTest がネイティブファイル用パッケージを参照しているため必要な物は自動でインストールされます。

## 動作確認
### Windows
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153956/5284cbac-4f4d-d513-4c4d-480e660cfee8.png)
Windows 環境では nativefile.cmd が実行され、Hello Windows! が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153956/2b0b72a9-4ad7-e651-d311-b57ebed46398.png)
native-linux はインストールされません。
### linux
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153956/978b48c3-b2ae-79a0-0048-2bba34161bc8.png)
linux 環境では nativefile.sh が実行され、Hello linux! が表示されます。
警告が出て windows 用パッケージのインストールがスキップされていますが、エラーにはなっていません。

windows で警告が出ない理由はよくわかりません。別の環境では出てたのでバージョンとかだと思います。
plunkerでjwt

# 概要

plunkerでjwtをデコードしてみた。
スクラッチでやってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/797e5e1c-d7b3-902c-05ac-14861b85c661.png)


# サンプルコード

```

document.querySelector("#decrypt").addEventListener("click", function() {
  const token = document.querySelector("#encrypted").value;
	const base64Url = token.split('.');
  const base0 = base64Url[0].replace(/-/g, '+').replace(/_/g, '/');
  const res0 = JSON.parse(decodeURIComponent(escape(window.atob(base0))));
  document.querySelector("#decrypted").value = JSON.stringify(res0);
  const base1 = base64Url[1].replace(/-/g, '+').replace(/_/g, '/');
  const res1 = JSON.parse(decodeURIComponent(escape(window.atob(base1))));
  document.querySelector("#decrypted").value += JSON.stringify(res1);
});



```

# 成果物

https://embed.plnkr.co/plunk/OmZKUmyp4ZwL9vp7


以上。
AWS RDSデータベースエンジンAuroraの用語要点まとめ（自分用メモ

Amazon Aurora
Amazonが設計・開発したMySQL/PostgreSQL互換のデータベースエンジン。フルマネージド型サービスであるAmazon RDSで利用可能なデータベースエンジンですので、データベースのスケーリング（拡張、縮小）、高可用性、バックアップ、OS/データベースソフトウェアへのパッチ、サーバーの電源やメンテナンスなどはRDS（AWS）によって管理。

RDSの他のデータベースエンジンと比べた時のAuroraの特徴：

●データベースインスタンスとストレージが分離したアーキテクチャ
Auroraはデータベースインスタンスとストレージが分離しており、柔軟な構成が可能。手動でのデータベース管理が不要なサーバーレス構成や、最大15台のレプリカインスタンス（参照専用のインスタンス）を構成することもできます。

●複数のデータコピーと自動修復機能などによるストレージの高い耐障害性
ストレージは、デフォルトで3つのAZに2つずつ（計6つ）のデータコピーが作成。これらのストレージは「クラスタボリューム」というクラスタ構成で管理。
Auroraのクラスタボリューム内のストレージは互いに監視しあっており、データの破損が発生しても自動で検出、修復。

●レプリカインスタンスの自動フェイルオーバーによる高可用性
データベースインスタンスは、書き込みを行うプライマリインスタンスを1台、参照専用のレプリカインスタンス（リードレプリカ）を最大で15台作成することができます。
レプリカインスタンスはデフォルトでプライマリインスタンスと異なるAZに作成され、プライマリインスタンスに障害が発生した場合は自動でフェイルオーバー（切り替え）とプライマリインスタンスへの昇格が行われます。
RDSのその他のデータベースエンジンはスタンバイ用のインスタンスとリードレプリカは別々のインスタンスですが、Auroraではリードレプリカがスタンバイインスタンスを兼ねている。

●最大64TBまでスケール可能な拡張性
ストレージの容量は、最大で64TBまで自動的に拡張されます（RDSの他のデータベースエンジンの最大サイズは16TB）。データの増加に伴って拡張されていくため、必要な容量を計算して事前にプロビジョニング（予約）する、といった手間は必要ありません。

【Auroraのエンドポイント】
Auroraでは、インスタンスへアクセスするためのエンドポイント（接続先）を用途ごとに分けています。
クラスターエンドポイントは更新も参照も行うことができますが、参照クエリが多いと更新処理を圧迫してしまいます。用途ごとにエンドポイントを使い分けることで負荷を分散し、全体的なパフォーマンス改善を図ることができます。
なお、レプリカインスタンスが複数台あった場合、読み取りエンドポイントへのリクエストは各インスタンスへ均等に割り振られます。

また、フェイルオーバーが発生してもアプリケーションはエンドポイントを切り替える必要はありません。レプリカインスタンスからプライマリインスタンスへの昇格が自動的に行われるように、クラスターエンドポイントの接続先インスタンスも自動で切り替えが行われ、運用を継続できます。

【Amazon Aurora Global Database（Aurora グローバルデータベース）】
Auroraデータベースを複数のリージョンにまたがって運用できるサービス。例えば、Aリージョンで稼働しているデータベースをBリージョンにも配置できる。Auroraグローバルデータベースを使用しても、ユーザーは複数のリージョンのデータベースを管理する必要はありません。データはプライマリとして稼働しているメインのリージョンからセカンダリリージョンへレプリケートされます。

グローバルデータベースの大きな利点
・データベースアクセスを世界中から高速に行える（レイテンシの向上）
・リージョン単位で発生した大規模な障害の災害対策

異なるリージョンからデータを読み取りたい場合はリードレプリカを異なるリージョンに配置することもできますが、Auroraグローバルデータベースは書き込みも異なるリージョンから行えます。
また、Auroraグローバルデータベースは災害復旧時に非常に高い効果を発揮。プライマリリージョンのデータベースが停止した場合、セカンダリリージョンのデータベースを自動で昇格（フェイルオーバー）させ運用を継続できます。Auroraグローバルデータベースでは、一般的にディザスタリカバリの指標として使用されるRPO（目標復旧時点）を 1秒、RTO（目標復旧時間）を1分未満と定めています。

※RPO（Recovery Point Objective：目標復旧時点） ... どの時点までのデータを復旧させるか。データベースの更新頻度が高い場合は、0秒（停止直前）のデータ復旧が求められる。
※RTO（Recovery Time Objective：目標復旧時間） ... どのくらいの時間で（いつまでに）復旧させるか。サービスやシステムを停止していられる時間。
Tenable.io_SDK_for_Pythonでスキャン結果を自動エクスポートする

# Tenable.io_SDK_for_Pythonでスキャン結果を自動エクスポートする
**1.環境**
OS：Windows10
Python3.8.xx(Pythonのパスは通しておく)

**2.前準備**
Tenalbe.ioでアカウントの作成
Tenalbe.ioでスキャン作成、検査対象のスキャンが完了している

**3.手順**
**3.1.APIキーの取得**
Tenalbe.ioでAPIを叩くにはAPIキーで認証を通過する必要があります。
アカウントの設定画面のAPIの項目でGenerateボタンを押して
Access KeyとSecret Keyを表示させて
内容をメモして下さい。

**3.2.Tenale.io SDK for Pythonのインストール**
コマンドプロンプトにて以下を実行
```
pip install tenable_io
```

***3.3.作業用ディレクトリの作成***
```
mkdir tio
cd tio
```

***3.4.自動エクスポート用スクリプト作成***
{スキャン名1}
{スキャン名2}
{スキャン名3}
{スキャン名4}
{アクセスキー}
{シークレットキー}
{プロキシサーバURL}
は環境に合わせて文字列を置き換えて下さい。

```text:scan_list.txt
{スキャン名1}
{スキャン名2}
{スキャン名3}
{スキャン名4}
```
プロキシを通さない場合のスクリプト
```python:scan_result_export_non_proxy.py
from tenable_io.client import TenableIOClient
from tenable_io.api.scans import ScanExportRequest
import re

with open('scan_list.txt', 'r') as f:
    kw_list = f.read().split("\n")

client = TenableIOClient(access_key='{アクセスキー}', secret_key='{シークレットキー}')
scans = {scan.name: scan.id for scan in client.scans_api.list().scans}

for kw_name in kw_list:

  scan = client.scan_helper.id(scans[fr'{kw_name}'])

  filename = re.sub(r'\\|\.|\s', '_', fr'{kw_name}')+'.html'
  print(filename)

  scan.download(fr'{filename}', format='html',chapter='vuln_by_plugin')
```
プロキシを通す場合のスクリプト
```python:scan_result_export_proxy.py
from tenable_io.client import TenableIOClient
from tenable_io.api.scans import ScanExportRequest
import re
import os.path


os.environ['https_proxy'] = 'http://{プロキシサーバURL}/'

with open('scan_list.txt', 'r') as f:
    kw_list = f.read().split("\n")

client = TenableIOClient(access_key='{アクセスキー}', secret_key='[シークレットキー}')
scans = {scan.name: scan.id for scan in client.scans_api.list().scans}

for kw_name in kw_list:

  scan = client.scan_helper.id(scans[fr'{kw_name}'])

  filename = re.sub(r'\\|\.|\s|\/', '_', fr'{kw_name}')+'.html'
  print(filename)

  scan.download(fr'{filename}', format='html',chapter='vuln_by_plugin')
```
***3.5.スクリプトの実行***
プロキシが無い環境では、
scan_result_export_non_proxy.py
プロキシがある環境では、
scan_result_export_proxy.py
を実行して下さい。

scan_result_export_proxy.pyでSSL証明書のエラーが出た場合は、
環境で使用するCA証明書をPythonプログラムのディレクトリにある
certificate.pem
に追記して下さい。

***4.まとめ***
4時間近く掛かっていたスキャン結果のエクスポートが自動で出来るようになり、
かなり楽になりました。
Elasticsearchで見る検索エンジンの仕組み(2): Kibanaインストール編

##### [前回] [Elasticsearchで見る検索エンジンの仕組み(1): Elasticsearchインストール編](https://qiita.com/mingchun_zhao/items/4dc9833389bd7edda84d)

## はじめに

前回は、Elasticsearchをインストールしました。
今回は、Kibanaをインストールし、クエリ実行します。

## Kibanaとは

- フロントエンドアプリで、Elasticsearchでインデックスされたデータに対し検索と可視化を行う
    - クエリを実行し、データを検索
    - チャートでデータを視覚的に分析
- Elastic Stackクラスターを監視/管理/保護するためのユーザーインターフェース
- [Githubのソースコードリポジトリ](https://github.com/elastic/kibana)

## Kibanaをインストール

- [Windows版Kibana](https://www.elastic.co/jp/downloads/kibana)をダウンロード

- zipを解凍し、`kibana-8.3.1`フォルダーを作業フォルダーに移動
    - `C:\es\kibana-8.3.1`

- 環境変数を設定
    - `KIBANA_HOME`を追加(上記の導入フォルダー)
        - `C:\es\kibana-8.3.1`
    - `PATH`に`%KIBANA_HOME%\bin`を追加

## Kibanaを起動

- Elasticsearchを起動(起動していない場合)

```powershell
PS C:\es> elasticsearch
```

- Kibanaを実行

```powershell
PS C:\es> kibana
```

## ブラウザからKibanaに接続

- `http://localhost:5601/`にアクセス
    - [Elasticsearch初期起動時](https://qiita.com/mingchun_zhao/items/4dc9833389bd7edda84d#elasticsearch%E3%82%92%E8%B5%B7%E5%8B%95)に控えた、Kibanaの登録トークンを入力
    - `Configure Elastic`ボタンをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/944639a4-2427-fce4-6e69-7f168c6ce84f.png)

- Kibana起動ターミナルに表示される認証コードを、ブラウザに入力
    - `Verify`ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/4c73ffd8-bcea-d66e-5f6c-72cd3164f502.png)

- ブラウザで、Elasticsearchの`elastic`ユーザとパスワードを入力し、ログイン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/ff787df9-2178-78f6-44c9-29384bb6dca4.png)

- Welcome画面で、`Add integrations`をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/4b71ee74-a73f-d93e-964e-ed6c20210564.png)

- `Integrations`画面が表示される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/0364cd7f-b3f6-5f0f-1b0c-6c2037ef7137.png)

## Dev Toolsを使ってみる

- 左サイドバーから`Dev Tools`をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/5c467735-bb62-3f30-6271-c3eae0703edc.png)

- コンソールに、クエリを記載し、実行ボタン▶をクリック
    - ドキュメントをインデクシング
    - ドキュメントを取得
```
# index a doc
PUT index/_doc/1
{
  "body": "here"
}

# and get it ...
GET index/_doc/1
```

- コンソールの右に、クエリ結果が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/dcd76958-ccdc-056c-5773-c1959635918b.png)


## おわりに

Kibanaをインストールし、クエリを実行してみました。
次回は、さまざまなクエリを実行してみます。お楽しみに。

[次回] [Elasticsearchで見る検索エンジンの仕組み(3): インデックス/トークナイズ編](https://qiita.com/mingchun_zhao/items/00a62daff310010b08dd)
Databricksにおけるハイパーパラメーターチューニング

[Hyperparameter tuning \| Databricks on AWS](https://docs.databricks.com/applications/machine-learning/automl-hyperparam-tuning/index.html) [2022/6/14時点]の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

Databricks機械学習ランタイムには、モデル選択とハイパーパラメーターチューニングのプロセスを自動化するオープンソースツールであるHyperoptが組み込まれています。

# Hyperoptによるハイパーパラメーターチューニング

Databricks機械学習ランタイムには、分散処理を用いたハイパーパラメーターチューニング、モデル選択を推進するPythonライブラリである[Hyperopt](https://github.com/hyperopt/hyperopt)が含まれています。Hyperoptを用いることで、あなたが定義する探索空間においてアルゴリズムやハイパーパラメーターを変化させながら、一連のPythonモデルをスキャンすることができます。HyperoptはApache Spark MLlibやHorovodのような分散MLアルゴリズムや、scikit-learnやTensorFlowのようなシングルマシンのMLモデルでも動作します。

Hyperoptを用いる基本的なステップは以下のようになります。

1. 最小化する目的関数を定義します。通常、これはトレーニングあるいは検証時の損失となります。
1. ハイパーパラメーター探索空間を定義します。Hyperoptでは、一つのランの中で異なるMLアルゴリズムを比較できるように、条件付き探索空間を定義することができます。
1. 探索アルゴリズムを指定します。決定論的グリッドサーチよりも効率的にハイパーパラメーター空間を探索できるように、Hyperoptは確率論的チューニングアルゴリズムを使用します。
1. Hyperoptの関数である`fmin()`を実行します。`fmin()`は以前のステップで定義した項目を受け取り、目的関数を最小化するハイパーパラメーターのセットを特定します。

scikit-learnアルゴリズムでHyperoptをクイックに使い始めるには以下をご覧ください。

- [Parallelize hyperparameter tuning with scikit\-learn and MLflow](https://docs.databricks.com/applications/machine-learning/automl-hyperparam-tuning/hyperopt-spark-mlflow-integration.html)
- [Compare multiple model types using scikit\-learn, Hyperopt, and MLflow](https://docs.databricks.com/applications/machine-learning/automl-hyperparam-tuning/hyperopt-model-selection.html)

Hyperoptがどのように動作するのかの詳細や、他のサンプルについては以下をご覧ください。

- [Hyperoptのコンセプト](https://qiita.com/taka_yayoi/items/238ecf8b038151b84bc1)
- [Use distributed training algorithms with Hyperopt](https://docs.databricks.com/applications/machine-learning/automl-hyperparam-tuning/hyperopt-distributed-ml.html)
- [ベストプラクティス：DatabricksにおけるHyperoptを用いたハイパーパラメーターチューニング](https://qiita.com/taka_yayoi/items/db49a1bf2e7c96c6f6f4)

# 自動化MLflowトラッキング

:::note
**注意**
Databricksランタイム10.1ML以降が動作するクラスターにおいてはMLlib自動化MLflowトラッキングは非推奨となり、Databricksランタイム10.2ML以降ではデフォルトで無効化されます。代わりに、デフォルトで有効化されている[Databricksオートロギング](https://qiita.com/taka_yayoi/items/5a777b3e90948c4744db)の`mlflow.pyspark.ml.autolog()`を呼び出して、[MLflow PySpark ML autologging](https://www.mlflow.org/docs/latest/python_api/mlflow.pyspark.ml.html#mlflow.pyspark.ml.autolog)を使用してください。

Databricksランタイム10.2ML以降で古いMLlib自動化MLflowトラッキングを使用するには、[Spark設定](https://qiita.com/taka_yayoi/items/8d951b660cd87c6c5f18#spark%E3%81%AE%E8%A8%AD%E5%AE%9A)で`spark.databricks.mlflow.trackMLlib.enabled true`と`spark.databricks.mlflow.autologging.enabled false`を設定してください。
:::

- [Apache Spark MLlib and automated MLflow tracking](https://docs.databricks.com/applications/machine-learning/automl-hyperparam-tuning/mllib-mlflow-integration.html)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
Apex Mobile モニターに接続して、PS5のコントローラーでゲームする

# Apex Legends Mobileをモニターに繋いで、PS5のコントローラーでプレイする。

## 概要

[Apex Legends Mobile](https://www.ea.com/ja-jp/games/apex-legends/apex-legends-mobile)とは面白いゲームです。
最近これにハマっておりまして、iPhoneだと、画面が小さいのでモニターに写して、PS5のコントローラーでプレイしてみたいと考えるようになり。
この記事を書くに至りました。

## 必要なもの

[HDMIケーブル](https://www.amazon.co.jp/Amazon%E3%83%99%E3%83%BC%E3%82%B7%E3%83%83%E3%82%AF-%E3%83%8F%E3%82%A4%E3%82%B9%E3%83%94%E3%83%BC%E3%83%89-HDMI%E3%82%B1%E3%83%BC%E3%83%96%E3%83%AB-0-9m-%E3%82%BF%E3%82%A4%E3%83%97A%E3%82%AA%E3%82%B9/dp/B014I8SSD0/ref=asc_df_B014I8SIJY/?tag=jpgo-22&linkCode=df0&hvadid=204351229344&hvpos=&hvnetw=g&hvrand=18220073710237881871&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009309&hvtargid=pla-501748991032&th=1)

![Screenshot 2022-07-03 at 9.17.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31394/e11d8037-2179-e7c0-7a7a-ce6393c855af.png)

[Lightning - Digital AVアダプタ](https://www.apple.com/jp/shop/product/MD826AM/A/lightning-digital-av%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF)

![Screenshot 2022-07-03 at 9.19.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31394/06659c64-5335-67d9-8aac-1aab054389ef.png)
![Screenshot 2022-07-03 at 9.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31394/ec979765-ee8e-7d75-9168-d46045685ecb.png)

モニターに関してはお家にあるものや、ご自身の好みに合ったものをお使いになるのが良いかと思います。
私は自宅に合った下記のメーカーのものを使ってます。
HDMI端子のインターフェイスが実装されてるモニターで良いと思います。
HDMIじゃないとiPhoneとモニターを繋ぐことができないのかどうかは定かではありませんのであしからず。

[BenQ GL2480 アイケアモニター (24インチ/フルHD/TN/ノングレア/1ms/75Hz/輝度自動調整機能(B.I.)搭載/ブルーライト軽減/フリッカーフリー/HDMI/D-sub/DVI)](https://www.amazon.co.jp/%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4-GL2480-%E8%BC%9D%E5%BA%A6%E8%87%AA%E5%8B%95%E8%AA%BF%E6%95%B4-%E3%83%96%E3%83%AB%E3%83%BC%E3%83%A9%E3%82%A4%E3%83%88%E8%BB%BD%E6%B8%9B-%E3%83%95%E3%83%AA%E3%83%83%E3%82%AB%E3%83%BC%E3%83%95%E3%83%AA%E3%83%BC/dp/B07X3WMRPB/ref=asc_df_B07X3WMRPB/?tag=jpgo-22&linkCode=df0&hvadid=343264651612&hvpos=&hvnetw=g&hvrand=570550226558238768&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009309&hvtargid=pla-873407502407&psc=1&th=1&psc=1)

![Screenshot 2022-07-03 at 9.25.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31394/69683afd-eaaf-3283-993a-d51475920147.png)


[【純正品】DualSense ワイヤレスコントローラー (CFI-ZCT1J)](https://www.amazon.co.jp/%E3%82%BD%E3%83%8B%E3%83%BC%E3%83%BB%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96%E3%82%A8%E3%83%B3%E3%82%BF%E3%83%86%E3%82%A4%E3%83%B3%E3%83%A1%E3%83%B3%E3%83%88-%E3%80%90%E7%B4%94%E6%AD%A3%E5%93%81%E3%80%91DualSense-%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%AC%E3%82%B9%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC-CFI-ZCT1J/dp/B08GG1QSRR)

![Screenshot 2022-07-03 at 9.26.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31394/7fcf28aa-5c29-249d-1f16-cb18a63ec7bd.png)


これらの機器を購入していただけるとモニターでApexをプレイする事ができます。
接続の仕方はHDMIケーブルとApple社製のLigihtingケーブルを接続し、それをiPhoneやiPadに接続するとできます。
既存のDBからマイグレーションファイルを作成する

Laravelのバージョン
```bash
php artisan --version
Laravel Framework 9.17.0
```
"kitloong/laravel-migrations-generator"をインストール
```bash
composer require "kitloong/laravel-migrations-generator"
```
`migrate:generate` を実行
```bash
 php artisan  migrate:generate
```
マイグレーションファイルが生成された
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/670f7526-995c-a101-e8b5-0b41e7955423.png)
テスト用DBにマイグレーションを実行すると以下のエラーが発生
```bash
php artisan migrate --env=testing

Fatal error: Cannot declare class CreatePersonalAccessTokensTable, because the name is already in use in /opt/database/migrations/2022_07_03_085626_create_personal_access_tokens_table.php on line 7

In 2022_07_03_085626_create_personal_access_tokens_table.php line 7:

  Cannot declare class CreatePersonalAccessTokensTable, because the name is already in use  
```
sancumのライブラリに同じクラス名が使われていたので、自前のマイグレーションファイルに含まれるとクラス名がかぶってエラーになる様子
`vendor/laravel/sanctum/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php`
`migrate:generate` で生成された `2022_07_03_085626_create_personal_access_tokens_table.php` を削除してから再度実行
今度は正常に実行された
```bash
php artisan migrate --env=testing

Migrating: 2019_12_14_000001_create_personal_access_tokens_table
Migrated:  2019_12_14_000001_create_personal_access_tokens_table (270.76ms)
・・・
Migrating: 2022_07_03_085626_create_failed_jobs_table
Migrated:  2022_07_03_085626_create_failed_jobs_table (164.55ms)
Migrating: 2022_07_03_085626_create_password_resets_table
Migrated:  2022_07_03_085626_create_password_resets_table (161.97ms)
Migrating: 2022_07_03_085626_create_users_table
Migrated:  2022_07_03_085626_create_users_table (110.53ms)
Migrating: 2022_07_03_085627_add_foreign_keys_to_article_category_table
Migrated:  2022_07_03_085627_add_foreign_keys_to_article_category_table (386.56ms)

```
`migrate:generate` で生成された `2022_07_03_085626_create_personal_access_tokens_table.php` を削除していたものの、`personal_access_tokens` のテーブル自体は作成されていた。
&nbsp;
migrations テーブルを見るとsancumに含まれていたファイル名で実行されている形跡がある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/4dcbb4ad-f0b3-bdfc-d23e-0f92de95c0f1.png)
試しに vendor以下のマイグレーションファイルを削除すると`personal_access_tokens` テーブルが作成されなかった。
おそらくmigrate実行時にvendor以下のライブラリ等に含まれるマイグレーションファイルも読み込んで実行してくれるものと思われる
TypescriptによるReactコンポーネントの書き方

## VSCodeの拡張機能をインストール
VSCodeの拡張機能から、「react」と検索すると、以下が候補に挙がってくるのでインストールする。
Reactのスニペットを使えるようになる。

- ES7+ React/Redux/React-Native snippets
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1327509/8c125696-b148-7911-e960-cc13c04dc5f8.png)


## Reactコンポーネントのひな型

tsxファイルを作成し、「rafce」と入力し、Enterを押すと、Reactコンポーネントのひな型が入力される。

```ts
import React from 'react'

const Sample = () => {
  return (
    <div>Sample</div>
  )
}

export default Sample
```

## Typescriptによる、Propsの型を指定
```diff
import React from 'react'
 
+ type Props = {
+   id: string
+   name: string
+ }


- const Sample = () => {
+ const Sample = ({id, name}: Props) => {
  return (
    <div>Sample</div>
  )
}

export default Sample
```

### VSCodeのユーザースニペット登録

「Ctrl + Shift + P」で、ユーザースニペットを選択する。
初回登録時は、ファイル名を聞かれるので、任意の名前を付ける。（globalなど）
ユーザースニペットに以下のように書いておくと、「Props」と打つと、型宣言のひな型が入力される。

```ts
"Props": {
  "prefix": "Props",
  "body": ["type Props = {", "\t$1", "}"]
}
```
（小ネタ）Markdownで空行を記載する方法

## この記事の目的

Markdownで空行を記載する方法を記載します。

Markdownで空行は`<br>`を記載すれば、実現できます。  
しかしながら、VSCode でmarkdownlintを有効に設定している場合、
以下のような警告が表示され、気持ち悪く思う方も居ると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2708851/8cf2b70c-1b80-0e47-8fff-520153c9062d.png)

この警告は、MarkdownでHTMLは直接記載しない方が良いですよ。という内容です。
[MD033 - Inline HTML](https://github.com/DavidAnson/markdownlint/blob/v0.25.1/doc/Rules.md#md033)

そこで

## Markdownで空行を記載する方法

Markdownで空行を記載する方法は、  
`&nbsp;`の後に半角空白を２個
です。

これならmarkdownlintも警告を出しません。

```text

この行と  
&nbsp;  
この行の間に空行を入れる  

```

👇表示された状態
この行と  
&nbsp;  
この行の間に空行を入れる
TextMeshProのRichTextTagがあまりにも面倒なので便利なメソッドを作った

# はじめに
ちょっとしたテキスト表現を使おうとするとタグを書かなきゃいけなくて、しかも書くのが面倒なのでメソッドがあったら便利だろうと思い作ってみました。
こんな感じに書きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2281232/65656513-8703-afaf-8075-0e5048a34485.png)
# 動作環境
Unity 2021.3.1f or Higher
TextMeshPro 3.0.6 or Highr
# 導入方法
1. 「[**ココ**](https://github.com/Blood421/TMP_TagGen)」からTagGen.unitypackageをダウンロード&インポートします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2281232/5b1660a3-8b16-2b4f-fbdf-b47a35fe0df2.png)

2. C#スクリプトにて「using TextMeshProTagGen;」を一番上の部分に書きます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2281232/fb2c6490-1064-67d2-e50e-8b003947eef5.png)

3. TagGen.Alphaなど色々と使えるようになります！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2281232/fd26353c-87dd-8113-4298-59160aced9f6.png)

さらにStringでやり取りしてるためこんなこともできます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2281232/a9d11c43-df8f-ee3c-97aa-113d07ab13bd.png)


Demo付属なのでまずはDemoSceneとTextTagDebugを開いてみましょう！
実行するとこんな感じです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2281232/aa06b197-b8d0-9126-0cee-d45a20526989.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2281232/346d0cdd-d235-2f15-1763-0f07ed4fea0e.png)

「[**TextMeshPro公式ドキュメント**](https://docs.unity3d.com/Packages/com.unity.textmeshpro@4.0/manual/RichTextSprite.html)」にあるタグは全て網羅してあり、動作デバッグ済みです！

# さいごに
これで面倒なタグ入力は必要なくなったのでバリバリRichTextTagを使って色んな表現ができますね！
少しでもテキスト表現をいじるときの助けになれば幸いです。
CDNオンリーでReactを動かしてみた


これだけで良かった。


```react
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<div id="root"></div>
<script type="text/babel">
        let dom = document.querySelector("#root");
        const { useEffect } = React;
        const App = () => {
            useEffect(() => {
                    console.log("Processed useEffect");
                })
            return(
                <div>
                    <p> CDN only で Reactが使えるか確認中 </p>
                </div>
            );
        }
        ReactDOM.render(<App />, dom);
</script>

```

### 参考にしたリンク
- [cdnjs : react](https://cdnjs.com/libraries/react)
- [cdnjs : react-dom](https://cdnjs.com/libraries/react-dom)
- [Reactの基礎【JSX編】](https://zenn.dev/web_tips/articles/330b10817b24f2)
- [React公式 : CDNリンク](https://ja.reactjs.org/docs/cdn-links.html)
Github CLIで「直近24時間以内に更新されたPR」を抽出する

[Github CLI](https://cli.github.com/)はGithubに対する様々な操作をコマンドラインから実行できる便利なツールです。

最近自分が関わっているプロジェクトで「直近24時間以内に更新されたPRの番号とブランチ名の一覧」を抽出してバッチ処理をしたいという要件があり、Github CLIを使ってこれを実現しました。

<br>

# Github CLIの準備
Github CLIはHomebrewでインストールできます。

```bash
$ brew install gh
```

<br>

ghコマンドでGithubにアクセスするためには事前に認証しておく必要があります。
認証方法にはいくつかありますが、バッチサーバ上で実行する必要があったためGithubのパーソナルアクセストークンを使用した認証方法を使いました。
以下のコマンドで認証できます。

```bash
$ export GITHUB_PERSONAL_ACCESS_TOKEN=xxxxxxxxxxxx

$ echo ${GITHUB_PERSONAL_ACCESS_TOKEN} | gh auth login --with-token
```

<br>

なお、パーソナルアクセストークンには最低限`repo`と`read:org`のスコープの権限を与えておく必要があります。

![20210729184006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/b6e00984-f743-8c66-07c6-1d1f89322e8c.png)

<br>

# 条件指定でプルリクエストを抽出する
「直近24時間以内に更新されたPRの番号とブランチ名の一覧」を抽出するコマンドは以下のとおりです。

```bash
$ updated=`date -j -v-24H +"%Y-%m-%dT%H:00"`

$ gh pr list \
    --state open \
    --search "updated:>$updated" \
    --jq ".[] | [.number, .headRefName]|@csv" \
    --json number,headRefName \
    | awk -F, '{print $1,$2}' \
    | sed -e 's/"//g'

100 feature/foo
101 feature/bar
102 feature/baz
```

<br>

- `gh pr list`でプルリクエストの一覧を取得します。
- `--state open`でオープン中のプルリクエストに絞ります
- `--search`で細かい条件指定が可能です。ここでは特定の時刻移行に更新があったものを抽出するようにしています
- `--jq`でjqコマンドの記法でJSONレスポンスから値を取り出すことができます
- `--json`でJSONレスポンスに含める要素を指定します。ここではプルリクエストの番号とブランチ名が必要だったのでその2つを指定しています

<br>

`--search`に指定する検索条件はGithubのプルリクエスト・Issue検索クエリの記法になっています。
こちらにドキュメントがあります。

https://docs.github.com/ja/github/searching-for-information-on-github/searching-on-github/searching-issues-and-pull-requests

<br>

コマンドでやる前に、Githubのプルリクエストの検索画面でクエリを色々試しておくと良いかもしれません。

![20210729185217.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/de976653-5705-96e4-13d8-efca85a0d221.png)
OAuth2.0のユーザーテーブル設計

![oauth2.0-1024x416.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/c4aecebb-df6c-799a-c9af-97dd043b1e0b.png)
一昔前のユーザー登録は`username`と`password`を入力して貰い、DBのデータと一致していればログイン成功の判定を出してましたが、
今風のWebサービスは`github`、`google`アカウントログインなどの外部認証サービスを使用することも少なくありません。

この記事では、そういった外部認認証を使用することが前提のユーザーテーブルの設計を軽く紹介します。

### ベーシックのユーザーテーブル構成

`username`と`password`を使用して認証する、一番ベーシックなテーブル構成、外部認証の使用は想定しない。

:boy_tone1:テーブル: *users* 
- id: 主キー
- username: ユーザーネーム
- password: パスワード
- register_time: ログイン時間


| id | username | password |register_time |
|:-----------|------------:|:------------:|------------:|
| 1       | Tomas        | 12345         |1636800366716 |
| 2     | peter      | 654321       |1636800316716 |

### 改良版ユーザーテーブル構成
`users`テーブルは`ベーシック`のままで、外部認証用のテーブルを追加します。

:spy:`github`認証用のテーブル: github_auth 


- id: 主キー
- user_id:ユーザーテーブルid
- uid: githubのID
- access_token: 外部認証用のtoken
- access_expire: tokenの有効時間

| id | user_id | uid |access_token |access_sxpire |
|:-----------|------------:|:------------:|------------:|------------:|
| 1       | 1        | 12345         |1636800366716 |1636800366716 |
| 2     | 2      | 654321       |1636800316716 |1636800316716 |

以上のテーブル構成は外部認証の条件には満たしますが、
:point_up_tone1:認証パターン増やすたびに、それに使用されるテーブルも増えていくため、非常に面倒です。:frowning2:

### OAuth2.0対応ユーザーテーブル構成

:boy_tone1:ユーザー基本データ管理用のテーブル: users
- id: 主キー
- nickname: 表示名
- avatar: 表示アイコン

:spy:認証データ管理用のテーブル: user_auths
- id: 主キー
- user_id: `users`の外部キー
- identity_type: ログインタイプ(メール、 Githubなど)
- identifier: 該当ログインタイプの識別子(メールアドレス、 githubユーザー名など)
- credential:クレデンシャル(外部サービス発行されたtoken,認証コードなど)

この構成の特徴は、`users`テーブルに認証関連のデータを持たない、表示用のニックネーム、アイコン情報などの基礎情報のみ保有します。
認証関連の全てのデータは`user_auths`に保管されます、`users`テーブルとは１対多の関係になります。

#### users

| id | nickname | avatar |
|:-----------|------------:|:------------:|
| 1       | Tomas        | avatar_url         |
| 2     | peter      | avatar_url       |

#### user_auths

| id | user_id | identity_type | identifier| credential|
|:-----------|------------:|:------------:|:------------:| :------------:|
| 1       | 1        | email         |tomas@example.com| password_md5|
| 2     | 1      | phone       |1234567890|password_md5|

ユーザーからログインのリクエストが来た際に、まずは`ログインタイプ`を判断をします。
携帯番号登録を例に挙げると、`select * from user_auths where identity_type='phone' and identifier='携帯番号'`、もしデータ存在する場合、認証コードとデータの`credential`と比較し、一致すれば、user_id使って`users`からデータ取得して返します。

github認証使用する場合、`select * from user_auths where identity_type='github' and identifier='github_id'`,もしデータあればログイン成功し、新しいtokenで更新します。
SwiftのComputed PropertiesはFunction内でも宣言できる

SwiftのComputed PropertiesはFunction内でも宣言できます。

```swift
struct State {
    var foo = "foo"
}

var state = State()

func testComputedProp() {
    var result: Bool {  // ここにComputed Propertiesが宣言できる！
        someLogic(str: state.foo)
    }
    print(result)
    state.foo = "bar"
    print(result)
}

func someLogic(str: String) -> Bool {
    return str == "bar"
}

testComputedProp()

// 以下の順で出力される
// false
// true
```

<br>

限定的な具体例になっちゃいますが、、  
TCAのReducerを実装してるときに、同じデータ取得のコードをあちこちに書いていました。

```swift
switch action {
    case .onAppear:
        ...
        state.cursor = nil
        return environment.userRepository  // 全く同じコードがあちこちに...
            .fetchList(cursor: state.cursor)
            .catchToEffect(Action.fetchListResponse)

    case let .fetchListResponse(.success(entity)):
        ...
        state.cursor = entity.cursor
        return .none

    case .rowOnAppear:
        ...
        return environment.userRepository  // 全く同じコードがあちこちに...
            .fetchList(cursor: state.cursor)
            .catchToEffect(Action.fetchListResponse)
```

<br>

でも、Computed Propertiesを使うと`fetchList`を書くだけでよくなるので、コードがスッキリします。

```swift
switch action {
    var fetchList: Effect<Action, Never> {
        environment.userRepository
            .fetchList(cursor: state.cursor)
            .catchToEffect(Action.fetchListResponse)
    }

    case .onAppear:
        ...
        state.cursor = nil
        return fetchList  // これだけでOK

    case let .fetchListResponse(.success(entity)):
        ...
        state.cursor = entity.cursor
        return .none

    case .rowOnAppear:
        ...
        return fetchList  // これだけでOK
```

<br>

...Functionでも良いんですけどね。

```swift
switch action {
    func fetchList() -> Effect<Action, Never> {
        environment.userRepository
            .fetchList(cursor: state.cursor)
            .catchToEffect(Action.fetchListResponse)
    }

    case .onAppear:
        ...
        state.cursor = nil
        return fetchList()  // これだけでOK

    case let .fetchListResponse(.success(entity)):
        ...
        state.cursor = entity.cursor
        return .none

    case .rowOnAppear:
        ...
        return fetchList()  // これだけでOK
```
Swiftで[String: Any]型の等価性チェックをする

Swiftで以下のコードはコンパイルエラーになります。  
Any型がEquatableに準拠していないというのが理由です。

```swift
let dict1: [String: Any] = ["foo": "bar"]
let dict2: [String: Any] = ["foo": "bar"]
print(dict1 == dict2)  // Protocol 'Any' as a type cannot conform to 'Equatable'
```

<br>

そこで、以下のように[String: Any]をNSDictionaryにキャストして比較します。  
こうするとコンパイルすることができ、結果は`true`になります。
**※この方法では正しい比較ができないケースがあります。次項を参照してください**

```swift
let dict1: [String: Any] = ["foo": "bar"]
let dict2: [String: Any] = ["foo": "bar"]
print(dict1 as NSDictionary == dict2 as NSDictionary)  // true
```

<br>

SwiftではDictionaryとNSDictionaryをシームレスに相互変換することができます。

そして、NSDictionaryはNSObjectのサブクラスであるため、Equatableに準拠しています。

これによって上記の比較が可能になります。

<br>

## 2023/1/6追記
以下の例は一見`true`になりそうですが、結果は`false`になります。

```swift
struct Bar: Equatable {
  let bar: Int
}

let dict1: [String: Any] = ["foo": Bar(bar: 1)]
let dict2: [String: Any] = ["foo": Bar(bar: 1)]
print(dict1 as NSDictionary == dict2 as NSDictionary)  // false
```

<br>

BarをHashableに準拠させると`true`になります。

```swift
struct Bar: Hashable {
  let bar: Int
}

let dict1: [String: Any] = ["foo": Bar(bar: 1)]
let dict2: [String: Any] = ["foo": Bar(bar: 1)]
print(dict1 as NSDictionary == dict2 as NSDictionary)  // true
```

NSDictionary同士の比較はNSObjectProtocolの[isEqual(_:)](https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418795-isequal)メソッドを使用しています。
このメソッドは2つのオブジェクトのハッシュ値が同じである場合に`true`を返すようになっています。
Hashableに準拠させることでハッシュの比較が正しくできるようになり、期待通りの結果が得られるようになるのだと思います。

<br>

## 参考

https://github.com/Quick/Nimble/issues/585
LaravelをAPIサーバーで利用するときのページネーションの実装（ページあたりの件数、現ページindexの指定方法）

Nuxt/Laravel、SSRでの業務システムの開発に携わっているのですが、LaravelをAPIサーバとして使うときの実装でややハマったのでメモ。
# pagenate()メソッドの仕様
クエリビルダ or Eloquentクエリでのpagenate()メソッドですが、今までの案件で見てきたソースの記述だと
```php5
User::where('id', '>', '100')->paginate(15); //1ページあたり15件づつ取得する
```
このような数値型の引数が１つだけ渡され「1ページあたりの数」のみを指定している実装しか見たことがなかったのですが
ページネーションって、「**1ページあたりの数**」と「**現在のページインデックス**」の２つの値が必要じゃない？？と疑問に思ったところなんと、**pagenate()は自動でGETリクエストのパラメータ`page`の値を現在のページ番号として参照しているのでした。**
フロントに.blade利用しているときはlinks()を利用すれば上記の仕様に合わせてページリンクを出力するというブラックボックス化されています。
但し、対応してるのはGETのみであり、POSTに`page`パラメータで数値渡しても機能してくれませんでした。
（取得系のエンドポイントまでも全てPOSTでルーティングされてる変な設計の案件でこの壁にぶつかった。）
# 「1ページあたりの件数」「現ページインデックス」を指定してページネーションを実装する方法
HTTPメソッドにPOST使いたい時orパラメータ名に「page」以外を使いたいときは「**1ページあたりの数**」と「**現在のページ数**」を明示的に引数に渡します。
```php5
User::paginate(
    $perPage, // 1ページあたりの件数
    ['*'],
    'page', 
    $currentPage // 現在のページインデックス値
);
```
第2,3引数は上記の定数で良いと思います。

:::note info
¥Illuminate¥Database¥Query¥Builder::paginate()を見る感じ
第4引数が存在すれば第3引数$pageNameは参照されてないっぽいです。
未検証ですが第4引数無しにして、現在のインデックスを持つクエリ文字列名を$pageNameに指定すればそれでも動くんじゃないかな
:::

# APIが返すJSONデータ
paginate()はLengthAwarePaginator型を返し、データは下記の構造になります。jsonで返され、フロント側でもこのオブジェクトを扱うことになります。
```php5
{
    "total":13, // 全ページのアイテム総数
    "per_page":3, // 1ページあたりの件数
    "current_page":1, // 現ページのインデックス
    "last_page":5, // 最終ページのインデックス
    "next_page_url":"http:\/\/localhost:8000\/list?page=2", // 次のページのURLフルパス
    "prev_page_url":null, // 前のページのURLフルパス
    "from":1, // ページ内１要素目のアイテムインデックス（○～○件／全○件中）の表示に使える
    "to":3, // ページ内最後の要素のアイテムのインデックス（○～○件／全○件中）の表示に使える
    "data":[
        // データ。連想配列の配列
    ]
}
```
# 参考
https://pgmemo.tokyo/data/archives/1278.html
https://www.slideshare.net/ShoheiOkada/laravel-paginate
AWS 認定 データベース – 専門知識(DBS-C01)の合格記録


# はじめに
2022年7月にAWS 認定 データベース – 専門知識（AWS Certified Database - Specialty）に合格しました。

早速ですが、具体的に何をしたのか？
まずは、試験日を設定をして、申し込みを済ませました。

目標
・勉強開始～2週間後を試験日に設定しました

前提
・2021年8月のAWSのソリューションアーキテクト取得済
・実務DBはDynamoDBのみ使用したことあり
・オンプレのDBはmysql、oracle、sqlserverは使用したことあり
・社会人のため、日中は仕事
・TOEIC 800点

# 勉強
- 毎日、夜に約4時間勉強
- DBごとの特徴を整理するのが大変

# やったこと

- AWS Black Belt 
　youtubedで
　・データベースの選定
　・RDS、Aurora、DynamoDB..etc のそれぞれの解説
　
- AWS
AWS Skill Builder
https://explore.skillbuilder.aws/learn/signin

  - AWS Certified Database - Specialty Official Practice Question Set (DBS-C01 - English)
   　英語版のみ無料で模擬試験（20問）を公開し、解説がついています。
　　 ※日本語翻訳可能

- Umedy
よくセールしているので、セールで購入するのがお勧め

  - AWS Certified Database Specialty 2022 
英語教材の動画で字幕の1.75倍速で学習しました。
※toiec700程度あれば、十分わかる内容かと思います。
https://www.udemy.com/share/103o843@6BRnKUQTf9bCio11o9gqwHBEp72dTuQwC1bdBRuR8f9jkqQD8WivoiiBw0V2jZkhTw==/

  - Practice Exam | AWS Certified Database Specialty
英語教材ですが、日本語翻訳可能。
解答解説でAWSの参考文献を紹介しているので、全部読む
※ただ、日本語の翻訳が分かりにくい箇所等は英語で確認が必要（本番試験も同様）
https://www.udemy.com/share/103Xag3@kKV__l2oPJgWq_A6W_23T4RVQC3cBmfs5OvMOatibrDLHcawnaCKedY1Bm4YKlnBlw==/

- AWS 「よくある質問」
各DBごとの「よくある質問」をさらっと読む
https://aws.amazon.com/jp/rds/faqs/

- AWSナレッジセンター
トラブルシューティングを一通り読む
https://aws.amazon.com/jp/premiumsupport/knowledge-center/

- AWSのコンソール
  cloudFormation、DynamoDBのみ触った
　※RDS、Auroraはハンズオンで作成・変更、フェールオーバーやると理解が早いと思います。

## 試験
- きちんと問題を読んで、内容を理解する。
・現状
・want
・must
・解決方法

- 日本語翻訳が分かりにくい場合は、一度英語にして、日本語で読んだ内容と同じか確認

## 最後に
資格で勉強したことが、そのまま実務で行かせるような環境やユースケースになることは少ないかとは思います。
ただ、知見が増え、事前にDB周りの問題が起きないよう予防し、周りの方の知見が増えていき、より開発がスムーズになればと思います。