OmniAICreator/Qiita-1.07M huggingface dataset:
ドメイン駆動設計入門#2 境界付けられたコンテキスト

### はじめに
本日はドメイン駆動設計の境界付けられたコンテキストについてまとめます。

本記事は以下の内容を備忘のため記載しています。
[境界づけられたコンテキスト 概念編 - ドメイン駆動設計用語解説](DDD][https://little-hands.hatenablog.com/entry/2017/11/28/bouded-context-concept)
非常に参考になるので是非ご確認ください。

前回の記事は[こちら](https://qiita.com/haykubo/items/ea08d5b48b8eb215b618)

### 境界付けられたコンテキスト
ドメイン駆動設計の公式referenceでは境界付けられたコンテキストは以下のように定義されています。

```html
bounded	context
A description of a boundary (typically a subsystem,	or the work	of a particular	team) within 
which a particular model is	defined	and	applicable.	
```

日本語に訳すと、特定のモデルが定義される境界（ex.サブシステム、特定のチームの作業）を記述したもの。
特定のモデルが定義され、適用される境界の記述。	といった意味を示します。

前回の記事でも書いたように、
ドメイン駆動設計は、開発者一人で実践するものではなく、周りの人を巻き込み、すべての人(設計者、開発者、ドメイン駆動設計のエキスパート)が同じ意味でドメインモデルを理解し使えることが重要です。

参照した記事にあるれがわかりやすかったため、ECサイトの開発を例に以下を記述します。

ECサイトで商品を販売するシステムを例に考えます。その場合関係者はざっと、商品の販売部の人間・開発者・設計者の3者になります。
この時、商品というモデルは3者の間で同じ認識のものを共有することができます。

```html
----商品モデル----
・商品名
・値段
・在庫
...
```

次に販売から配送までをシステムで管理する場合を想像します。関係者は先ほどの3者に加えて配送部の人間もかかわってくると思います。このとき、商品モデルに対して全関係者が同じ認識を持つことができるでしょうか。

```html
★販売部の人間の認識
----商品モデル----
・商品名
・値段
・在庫
...

★配送部の人間の認識
----商品モデル----
・商品名
・配送先
・配送状況
...
```

上記からわかるように、同じ商品モデルでも関係者によって認識は異なります。
上記の認識を一つのモデルに無理やりまとめたとしても、

```html
----商品モデル----
・商品名
・値段
・在庫
・商品名
・配送先
・配送状況
```

ごちゃごちゃしたモデルになってしまい、これを実際に設計からコードに落とし込むことは難しくなります。
また経理部や人事部の領域までシステム管理するとなるともうなにがなんだかわかりません。
<b>システムが大規模になるにつれて、全関係者で認識を合わせることは難しくなっている</b>ことがわかります。

### 境界付けられたコンテキストを用いた分割
前述した、関係者が増えるにつれて認識の統一が難しくなってくることはどのようにドメイン駆動設計では解消することができるのでしょうか。そこで出てくるのが、本記事のタイトルにもある境界付けられたコンテキストです。ドメイン駆動設計では大きなシステムを「境界づけられたコンテキスト」に分割し、それぞれの中でモデル、言語の統一を実現し、関係者間での認識を揃えることができます。


まずコンテキストの意味は以下の通りです。
ITの分野では、利用者の意図や状況、環境などの総体を表したり、同じ処理や記述でも状況に応じて動作などが異なる場合に、その選択基準となる判断材料や条件などを指す場合が多い。
参照元 : [e-words](https://e-words.jp/w/%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88.html)
こちらの記事も参考になるのでご確認ください。
[プログラミングでよく見かける"コンテキスト(context)って何？](https://qiita.com/dojyorin/items/0bd3ef167991cfc703b1)

実際に例にあった商品の販売システムで考えてみます。境界付けられたコンテキストによる分割を行うと以下のようになります。

```html
----販売コンテキスト----
・商品モデル
　・商品名
　・値段
　・在庫
　...

----配送コンテキスト----
・商品モデル
　・商品名
　・配送先
　・配送状況
　...
```

コンテキストを販売・配送と分割し、「販売コンテキスト」「配送コンテキスト」それぞれが一つの「境界づけられたコンテキスト」となっています。
それぞれのコンテキスト内で商品モデルが定義されているため、関係者の中で「商品モデル」の認識を統一することが可能になります。

### まとめ
ここまで読んで境界付けられたコンテキストのイメージはついたでしょうか。
ドメイン駆動設計では前回の記事でも記載した通り、統一した認識のモデルを実際のコードに落とし込みます。価値あるソフトウェアを構築するために、関係者間で認識を合わせ、モデルを統一し実際にコードに落とし込むために、この境界付けられたコンテキストを理解する必要があると思います。
今後もドメイン駆動設計についてまとめていきます。参考にした記事も記載しますので、そこもおってみていただけると理解が深まると考えています。

次回は境界づけられたコンテキストを実装に落とすところまで記載しようと思います。

### 参考
[境界づけられたコンテキスト 概念編 - ドメイン駆動設計用語解説](DDD][https://little-hands.hatenablog.com/entry/2017/11/28/bouded-context-concept)

[ドメイン駆動設計入門 #1 ドメイン駆動設計とは](https://qiita.com/haykubo/items/ea08d5b48b8eb215b618)
Rustの文字列を理解する

## 始めに

Rustの文字列型には`String`と`&str`があります。
正直違いがよく分かっておらず`String`は可変長、`&str`は固定長くらいの
イメージしかなかったので、今回内部の仕組みを調べてまとめました。

ベクタやスライスの話が出てくるのでぜひ[前回の記事](https://qiita.com/k-yanai60/items/26bf1d2e372042eff022)も参考にどうぞ。

## String

`String`は標準ライブラリが提供する型です。
実体はバイト列のベクタ(`Vec<u8>`)なので、追加や削除が可能です。
文字列はヒープに格納されます。

### Stringのコピー

`String`をコピーするには`clone`を呼び出します。
するとヒープにある文字列も丸ごとコピーされます。
このように要素も含め全てコピーすることを**ディープコピー**と言います。

```rust
let s1: String = String::from("ABC");
let s2: String = s1.clone();
```

![stringcopy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693350/a8519379-8884-4547-8229-1f75f656a43a.png)

## &str

`&str`はプリミティブな型です。
実体はバイト列のスライス(`&[u8]`)です。
`&str`となるのは`String`のスライスや文字列リテラル等です。
文字列リテラルとはソースコードにべた書きされている文字列のことです。

```rust
let s1: String = String::from("Hello World!!"); // これはString
let s2: &str = &s1[1..4]; // Stringのスライスは&str
let s3: &str = "ABC 123"; // 文字列リテラルは&str
let s4: &str = &s3[0..2]; // 文字列リテラルのスライスも&str
```

### 文字列リテラル

この文字列リテラルは少し変わった特徴を持っています。
文字列リテラルは**静的領域**というスタックでもヒープでもない領域に格納されます。
静的領域に格納されるデータには以下のような特徴があります。

* プログラムの実行開始から終了まで常に存在している

そのため、文字列リテラルの型は厳密には`&'static str`という表記になります。
`'static`はその変数のライフタイム(生存期間)がプログラム実行中の全期間であることを示しています。

### なぜ文字列リテラルは`&str`なのか

文字列リテラルとは静的領域というスタックから離れた場所にあるバイト列です。
そのバイト列を参照するためにスライスのポインタを用いています。
文字列リテラル自体を所有せず**参照**しているため、型は`str`ではなく`&str`となります。

以下の様な場合のメモリ配置は下図の通りです。

```rust
let s: &str = "ABC";
```

![literal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693350/ad3167e4-2846-20b8-af73-838dece04233.png)

## &str → String

`&str`を`String`に変換するには`String::from`や`to_string`を使います。
この時、ヒープに文字列リテラルと同じ文字列がコピーされます。
文字列リテラルは常に静的領域に存在し続けます。

```rust
let s1: String = String::from("ABC");
let s2: String = "DEF".to_string();
```

![&str2string.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693350/4de8fc38-5d0b-bad2-166e-ed871e859b49.png)


## String → &str

`String`を`&str`に変換するにはStringの参照やスライスを取得します。
この場合はヒープに文字列がコピーされることはありません。
変数`s2`も`s3`も同じヒープを参照しています。

```rust
let s1: String = String::from("ABCDE");
let s2: &str = &s1;
let s3: &str = &s1[2..4];
```

![string2&str.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693350/1971956b-7b5c-84cb-deff-3aab800d068c.png)


## 文字列の連結

文字列を連結させるには`String + &str`の演算を行います。
左側の変数は文字列が追加されるため必ず`String`でなければいけません。
右側の変数は`&str`（文字列リテラル、`String`の参照やスライス）となります。

```rust
let mut s1: String = String::from("ABC");
let s2: String = String::from("DEF");
s1 = s1 + "!?" + &s2;
```

![concat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693350/21611546-dc26-3db7-cbfc-2b0a541e753e.png)


## おわりに

やはりRustは低レイヤーの知識がないと理解するのが難しいです。
C/C++のような低水準言語に近い言語だと改めて実感しました。

## 参考文献

https://note.com/marupeke296/n/n9b69cc5b45d4

https://text.baldanders.info/rust-lang/character-string-1/

https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-Add%3C%26%27_%20str%3E
LaravelのpaginationをSQL直接実行で利用する

# はじめに
Laravelのpaginationを利用するにはクエリビルダまたはEloquentクエリでpaginateメソッドを使用することで簡単にできます。
しかし、何重もサブクエリを定義しているSQLをクエリビルダやEloquentクエリで記述するには困難なので直接SQLを実行したい場合があると思いますが、その場合はpaginateメソッドを使用することができません。

今回は直接SQLを実行した場合でもLaravelのpaginationを利用する方法を紹介します。

※Laravelのpaginationにはいくつか種類がありますが、今回紹介するのはpaginateメソッドで利用できるものにフォーカスしています

# paginationを実現するには

paginateメソッドを実行した時の返り値は`Illuminate\Pagination\LengthAwarePaginator`です。
このインスタンスがpagination機能で必要なメソッドを持っているので、SQLを直接実行して取得したデータを`LengthAwarePaginator`に設定することでpagination機能を実現することができます。

### LengthAwarePaginatorのインタスタンスを取得する
LengthAwarePaginatorのコンストラクタには以下の引数を設定する必要があります
```php
item: 表示するアイテム
total: アイテムの総数
perPage: 1ページの表示数
currentPage: 現在のページ番号
```

上記の各値をまず取得します
```php
// 表示アイテムを取得する為のクエリ(サンプルの為、シンプルなものにしています)
$query = 'SELECT id, name FROM users ORDER BY id';

// 現在のページ番号
$currentPage = \Illuminate\Pagination\Paginator::resolveCurrentPage();
// 1ページの表示数
$perPage = 10;
// 表示するアイテムを取得
$results = \DB::select("{$query} LIMIT :per_page OFFSET :offset", [
    'per_page' => $perPage,
    'offset' => $currentPage * $perPage - $perPage
]);

// アイテムの総数を取得
$total = \DB::selectOne("SELECT count(*) AS cnt FROM ({$query}) AS counter");

// LengthAwarePaginatorのインタスタンスを取得
$pagination = new \Illuminate\Pagination\LengthAwarePaginator(
    $results,
    $total->cnt,
    $perPage,
    $currentPage,
);
```

### paginationのリンクにパラメーターを追加する
LengthAwarePaginatorのインタスタンスで生成されるリンク(次のページや前のページ等)にはページ番号(page)しかパラメーターが設定されていません。
リンクに任意の値を設定したい場合はLengthAwarePaginatorのコンストラクタにオプションを設定する必要があります。
以下はページ番号(page)以外のリクエストパラメーターをリンクに設定します。
```php
$pagination = new LengthAwarePaginator(
    $results,
    $total->cnt,
    $perPage,
    $currentPage,
    [
        'path' => sprintf(
            '%s%s',
            request()->url(),
            request()->except('page')
                ? '?' . http_build_query(request()->except('page'))
                : ''
        )
    ]
);
```
# 最後に
今回はSQLを直接実行した場合でもLaravelのpaginationを利用する方法を紹介しました。
paginationはよく利用する機能なので同じインスタンスで利用できるようになれば開発の手間が軽減されます。
公式ドキュメントにも説明はありますが詳しくは書かれていないので、この記事が参考になれば幸いです。
https://readouble.com/laravel/9.x/ja/pagination.html#manually-creating-a-paginator
SATySFiをWindows 10のVSCode上で使ってみる

# 環境
WSL2 を使って LaTax を実行できている状態から SATySFi をインストールしていきます。

# Ubuntu にインストール
以下の記事を参考にインストールしました。私は「satyrographos を使ったインストール」で簡単にできました。

https://qiita.com/Blank71/items/37cb773f55e614bad947

Ubuntu ターミナル上で、
```
$ sudo apt update -y && sudo apt upgrade -y
$ sudo apt install opam

$ opam init
$ eval $(opam env)

$ ocaml --version
The OCaml toplevel, version 4.08.1

$ opam switch create 4.12.0
$ eval $(opam env)
$ ocaml --version
The OCaml toplevel, version 4.12.0

$ opam repository add --all-switches satysfi-external https://github.com/gfngfn/satysfi-external-repo.git
$ opam repository add --all-switches satyrographos-repo https://github.com/na4zagin3/satyrographos-repo.git

$ opam install satysfi satysfi-dist satyrographos

$ satysfi --version
SATySFi version 0.0.7
```
ここまで来たら成功なはずです。

# VSCode で使う
「SATySFi Workshop」という拡張機能をダウンロードしましょう。

以下、適当に試した結果コンパイルできたというだけで、最適行動できているかはわかりません。

(1) ダウンロードしたら、その拡張機能の設定を開いて、「Satysfi-workshop: Executable」を「/home/YOURNAME/.opam/4.12.0/bin/satysfi」に変更する。opamのバージョンなどは都度調べてください。たとえば、エクスプローラで「//wsl$」と入力するとWSLファイルに移動できます。

(1') 「Build: When」を「onSave」に変えると、ファイルを保存したときに自動でコンパイラされるので便利です。

(2) 「/home/YOURNAME」内にフォルダを作ってファイルを作成しましょう。Ubuntuターミナルから、
```
~$ mkdir test
~$ cd test
~/test$ touch test.saty
~/test$ code test.saty
```
とすると VSCode が開いて test.saty の編集画面になっているはずです。あとはドキュメントを書いて保存して実行すれば大丈夫なはずです、エラーが起きたら VSCode をリロードしてみてください。「F1 -> reload と打つ -> ウィンドウの再読み込み」でできます。

# できなかったこと
Windows 上の .saty ファイルをいじろうとするとエラーが出てうまくいきませんでした。

# 今後やりたいこと
(1) Ubuntu を通さないでもう少し楽に実行できるようにしたい。
(2) .saty ファイルを実行すると aux と pdf ファイルが作成されるが、これを out フォルダに作成させたい。





# まとめ
WSL 上のファイルを Ubuntu を使って実行すればとりあえず動く。

# 参考

https://qiita.com/Blank71/items/37cb773f55e614bad947

https://qiita.com/na4zagin3/items/a6e025c17ef991a4c923

https://qiita.com/pickoba/items/efe59538253c4a6ea5f8#%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%81%AE%E6%9B%B4%E6%96%B0%E6%94%B9%E5%96%84

https://qiita.com/quzq/items/1096c638c0d86795be13

https://qiita.com/arene-calix/items/41d8d4ba572f1d652727
apple-touch-startup-imageをクライアント側で自動生成する

# apple-touch-startup-image ?
PWAは簡単にいうとWebページをネイティブアプリかのようにインストール可能にする技術。
インストールの際にどんな感じでネイティブアプリっぽく振る舞えばよいかを端末に伝えるのがmanifest.json。

アプリのアイコンや表示するアプリ名もそこで指定するのだがAndroidだとそれらの情報からスプラッシュ画面をいい感じに自動生成してくれる。
![splash.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/d9d80230-480d-d3da-af3f-6acafd25938f.jpeg)


iOSはというとそんな気の利いたことはしてくれず真っ白な画面が代わりに表示される。
が、一応スプラッシュ画面を表示する手段はSafari大好き独自規格で用意されている。
ページのheadに`<link rel="apple-touch-startup-image" href="url/to/splash.png">`を入れるとこれを表示してくれるらしい。

*楽勝じゃん。*

そう思っていた時期が私にもありました。

# 解像度問題
さてでは適当にアプリのアイコンのurlをそのままぶち込んで…

表示されない。

調べると用意する画像が画面サイズぴったりで作る必要があるとのこと。
つまり同じ内容でサイズが違うだけの画像を十数枚用意する必要があり、
同じ内容でurlが違うだけのlinkタグを十数行書く必要がある。

おのれSafari案件ですね。

どうしたもんかなとネットの海を彷徨っていたら

https://web.dev/learn/pwa/enhancements/

https://github.com/GoogleChromeLabs/pwacompat

えっ……クライアント側で生成して反映されるのか……
ogpではそんなこと出来なかったよな……


# 画像が読み込まれるタイミングについて
pwacompatはmanifest.json等から情報をかき集めてapple-touch-startup-imageを生成する機能を有している。
canvasでレンダリングしてdataurlにしてheadにぶち込んでいる。

scriptタグの記載位置については指定が無いうえ、jsであとから読み込むのもいいよねとreadmeに書いてある。
どうやらapple-touch-iconと同じようにホーム画面に追加する瞬間に例のlinkタグがあれば良いような気がする。

# 実装
```js
navigator.standalone==false&&requestAnimationFrame(w=>{const img=new Image();img.onload=()=>{
	w={c:document.createElement('canvas'),w:screen.width*devicePixelRatio,h:screen.height*devicePixelRatio};
	const draw=([cw,ch])=>{
		w.c.width=cw;w.c.height=ch;const ctx=w.c.getContext('2d'),{width:iw,height:ih}=img,s=Math.min(cw/iw,ch/ih);
		ctx.drawImage(img,0,0,1,1,0,0,cw,ch);ctx.drawImage(img,0,0,iw,ih,(cw-iw*s)/2,(ch-ih*s)/2,iw*s,ih*s);return w.c.toDataURL();
	};
	document.head.insertAdjacentHTML('beforeend',[[draw([w.w,w.h]),'portrait'],[draw([w.h,w.w]),'landscape']].map(x=>`<link rel="apple-touch-startup-image" href="${x[0]}" media="(orientation:${x[1]})">`).join(''));
};img.src='path/to/teaser.png';});
```
githubのogp用に生成した16:9くらいのアイコンと名前が入った画像が手元にあったのでそれを流用することにした。
![teaser.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/2d0fddb3-0d33-7db5-90b7-e9a57ffbdc10.png)

PWAで動いていないiOSを検出するためにnavigator.standalone==falseを使っている。
screen.width(height)*devicePixelRatioで画面の解像度を計算する。
それをcanvasに当てて持ってきた画像をそこにピッタリ入るように描く。
背景色として画像の左上の色を使っている。
出来上がったらdataurlにしてlinkタグに流す。

縦横を入れ替えて同様の手順で横向きの画像も作成する。
![iOSでスプラッシュ画面 縦](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/24fbd06d-4cd4-7483-1bd2-b7f7a94f63af.jpeg)
![iOSでスプラッシュ画面 横](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/ada9a039-1dec-70ab-7a7f-d309ddfbb076.jpeg)
こっちの方がかっこいいじゃん!
標準でスプラッシュ画面いじれる規格が欲しいね!!

めでたしめでたし。


# まとめ
- iOSのpwaでスプラッシュを表示するにはapple-touch-startup-imageを使う
- 端末の解像度ぴったりの画像が必要だがクライアント側で生成して使える。

今回はpwacompatに倣ってdataurlにしたが時間がかかっても良いということはつまりObjectURLでも良い気がする。
そしてそれをindexeddbに保存して……
まだ改良の余地はありそう。
ブログで有料記事を書けるようにした件（Django／WordPress）


僕のWordPressのブログ内で試験的に有料記事を書きはじめました。note.comの「この続きをみるには」のようなものではなく、文章の一部一部が読めない構造です。

会員登録などは必要なく、2クリックで支払い、ライセンスコードの取得までできます。
また購入後にはゲストアカウントが自動で作成され、自動生成されたメールアドレスとパスワードでログインできます。
ログインすると購入したサービスの一覧などが確認できます。

お支払い方法には信頼の置けるペイメントサービスプロバイダーであるStripeを採用し、クレジットカード他、Apple pay、Google payなどで支払えます。

以下はデモの有料記事です：

[WindowsのWSL Bashで"chmod"がエラーになる・実行できない](https://yuis-programming.com/?p=3481)

この記事で使用できるライセンスコードを準備しておきました。
以下のライセンスコードを入力すると見れるようになります。

**bc292db4-97c6-469d-83ea-03c77d4c330b**

以下に購入までの一連の流れを画像付きで紹介します。

支払いモデルのネットワーク図：

![ネットワーク図](https://yuis.xsrv.jp/images/ss/tmp2%20%282%29.jpg)

まず、ユーザーは記事を見つけます。
有料記事ではライセンスキー認証のカードが表示され、隠れた文字についてはその文字数をカウントして"(n文字)"のように表示されます。

![有料記事の認知。文字が隠されている状態](https://yuis.xsrv.jp/images/ss/ShareX-220801T111614-Ne29BLET~chrome-Windows%E3%81%AEWSL_Bash%E3%81%A7chmod%E3%81%8C%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8B%E3%83%BB%E5%AE%9F%E8%A1%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84_-_%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E3%80%8C.png)

上記の"購入する"リンクをクリック(タップ)すると、次のような支払い確認ページに移動します。

![支払い確認ページ](https://yuis.xsrv.jp/images/ss/ShareX-220801T105643-ndrGygf8~chrome-YuipApps_-_Google_Chrome.png)

画面の青色の次へ進むボタンを押すと、Stripeの支払いページへ移動します。
支払いはGoogle Pay、Apple Pay、クレジットカードなどが可能です。

![Stripe支払いページ](https://yuis.xsrv.jp/images/ss/ShareX-220801T110159-xTfzqK15~chrome-yuipro_-_Google_Chrome.png)

支払いが正常に完了すると、すぐにライセンスキーが発行され、画面に表示されます。

![ライセンスキー発行](https://yuis.xsrv.jp/images/ss/ShareX-220801T110753-tfly9D7J~chrome-YuipApps_-_Google_Chrome.png)

記事に戻り、発行されたライセンスキーを入力して画面黄色の"Send"ボタンを押して送信します。

![有料記事](https://yuis.xsrv.jp/images/ss/ShareX-220801T112536-ER76ukD8~chrome-Windows%E3%81%AEWSL_Bash%E3%81%A7chmod%E3%81%8C%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8B%E3%83%BB%E5%AE%9F%E8%A1%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84_-_%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E3%80%8C.png)

隠れた文字が表示され、有料記事が見れるようになりました。

主な使用技術：

- PHP, WordPress API .. およそ50行
- python, django .. およそ2000行
- python, jinja html .. およそ500行
- JavaScript, reactjs, css, html .. およそ500行
- その他, webpack.config, shell .. およそ100行

記事： [ブログの有料記事を実装しました](https://yuis-programming.com/?p=3750)
前職(研究開発)と現職(スマホアプリ開発)の比較

# はじめに
前職(研究開発)と現職(スマホアプリ開発)が割と対照的だったので比較。
あくまで私が経験したことなので、全ての会社がそうであるとは限らない。

# 前職 (研究開発)
大企業で画像認識の研究開発。

**主な業務**
・ニューラルネットワークを用いた画像学習/画像認識精度の評価/パラメータ調整。Visual Studio C++で社内独自のライブラリやツールを使用。データの受け渡しは外付けHDD。
・資料作り(精度評価・考察など/ExcelやPowerPointを使用)

**その他業務**
・朝礼
・研修(コンプラ/マナー/電話応対/特許関連)
・ポスター作成・発表
・社内昇格面接・資料作成
・飲み会取りまとめ
・社内イベント運営(出し物などの作成)
・上司と面談(隔週)
・課の会議(毎週)
・部の会議(毎月)
・輪講会(毎月)
・他にも色んなミーティング

**良かった点**
・長期休暇(年末年始/GW/お盆)が長かった。
・フレックスタイム制だったり、服装自由だったりと時代の変化に合わせた制度を取り入れていた。

**悪かった点**
・レガシーな開発環境だったり、社内独自のツールを使っていたりしたので、技術力の成長が見込めなかった。年配の方が多かったのが原因の一つかも。
・複雑なシステムだったので、他PCで環境構築するのに丸1日とられることもあった。
・資料作りやその他業務に時間を取られて、本業に割く時間が少なくなっていた。
・役割分担があやふやだった。

**転職理由**
モダンな環境で働いてスキルアップに繋げたかったため。

# 現職 (スマホアプリ開発)
ベンチャー企業でAndroidアプリ開発。

**主な業務**
・動作仕様/デザインデータを基に、レイアウト/動作/通信処理などの作成。Android StudioでKotlinを使用。Google/サードパーティ製のライブラリを使用。バージョン管理はGit。

**その他業務**
・週報

**良かった点**
・モダンな開発環境なので、作業効率が良い。
・Gitを使っているためバージョン管理が楽。
・その他業務がほぼ無く、資料作りの業務も無くなった(週報はテキスト形式なのですぐ終わる)ので、本業に集中できる。
・チャットツールでコミュニケーションを行うので、忙しい時に話しかけられない。
・エンジニアとPMの関係がフラット。
・個人でAndroidアプリの開発ができるスキルが身につく(個人アプリをGoogle Playにリリースできるようになる)。

**悪かった点**
・長期休暇(年末年始/GW/お盆)が短い。(有休は取れるので、長くしようと思えば自分で長くできる)
・フレックスタイム制ではなくなった。(出社時刻が前職よりも1時間遅くなったので不便はない)

# 表で比較してまとめた
|      |  大企業(研究開発)  |  ベンチャー企業(スマホアプリ開発)  |
| ---- | ---- | ---- |
| プログラミング言語/開発環境 |  古い  |  ***新しい***  |
| バージョン管理/データ受け渡し |  HDDで手渡し  |  ***Git***  |
| 雑務  |  多い  |  ***少ない***  |
| 残業  |  多い  |  ***ほぼない***  |
| 長期休暇  |  ***長い***  |  短い  |
| 会社の知名度  | ***ある***  |  ない  |

# おわりに
人によると思うが、私の場合は転職して正解だった。
ただ、前職は当時新卒だった私を雇ってくれて感謝しています。
Chatworkのデータをcsvでバックアップ その２


## Chatworkのデータをcsvでバックアップしておきたい！
ということで書いたこちらの記事
[ChatWorkのデータをcsvバックアップ．ついでにSlackへ・・・](https://qiita.com/saikickers/items/2e348feafe86b46fc0af)

ですが，久しぶりに見たら動きそうにないので少し修正しました．
上の記事はモバイルUA想定で作成しましたが，今回普通にWeb版を開いてそのままで動作するように修正しました．またSlack用にと思っていた処理を除いて，汎用的にcsvでとりあえずバックアップしておきたい用に作成しました．

出力したcsvをうインポート先でうまくできるかは不明なので，整形したりそれぞれ加工する必要はあるかと思います．

**やっていることは，ブラウザで読み込んだhtmlの構造をみて，整形し，コンソールに表示しているだけです**


## 手順説明

1. web版のchatworkを表示してログイン
2. chrome開発者ツールのコンソールを表示
3. **スクロールしまくってバックアップしたいとこまで読み込む**
4. 以下のjavascriptを開発者ツールのコンソールから実行
5. コンソールに整形されたデータが出力される & backup.csvがダウンロードされる


こちらを開発者ツールのコンソールにコピペしてエンターキーを押してください！
↓↓↓↓↓
~~~javascript
//出力用の配列
let arr = [
    ['timeStamp', 'user', 'text']
]
let cachDate;
let cashUser;

//タイムラインのチャット部分を取得し，投稿の数だけループ
$('#_timeLine').find('._message').each((idx, item) => {

    //この変数に一行分（一投稿）のデータを入れていきます
    let field = []

    //日付を抜き出して挿入
    if ($(item).find('._timeStamp').length > 0) {
        var t =  $(item).find('._timeStamp').text().trim();
        field.push( '"'+ t +'"' );
    } else {
        field.push('');
    }

    //ユーザー名を挿入．連続投稿はユーザー名が無いパターンがあるので前投稿のキャッシュで埋める
    if ($(item).find('._speakerName').length > 0) {
        var name = $(item).find('._speakerName').text();
        if(name===''){          
            field.push( '"' + cashUser +'"' );          
        }
        else{
            field.push( '"' + name +'"' );
            cashUser = name;
         }
    }
    else {
        field.push( '"' + cashUser +'"' );
    }

    //本文を抜き出して挿入
    const message = $(item).find('pre').text().replace(/(\r\n|\n|\r)/g, "");
    field.push( '"'+ message +'"' );
    arr.push(field)
});

//コンソール出力&csv出力用に整形
let csvString = '';
arr.forEach((value) => {
  const arrString = value[0] + ','  + value[1] + ','  + value[2] + ','  + value[3];
  console.log( arrString );
  csvString += arrString + "\n";
});

//csv出力
const blob =new Blob([csvString],{type:"text/csv"}); 
const link =document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download ="backup.csv";
link.click();

~~~


手でコピペするよりは楽になるかと思います！
VSCodeが重いor不具合があるときに読む記事

# Extension Bisect を実行してトラブルシューティング
コマンドパレットで`Help: Start Extension Bisect`を入力すると拡張機能のトラブルシューティングが開始される。まず、全拡張機能が無効化され、段階的に拡張機能を有効化していき問題のある箇所を特定できる。

# 拡張機能の無効化・アンインストール
コマンドパレットで`Developer: Startup Performance`を入力して数値が大きい拡張機能をみつけて無効にするかアンインストールする。

# ファイルの監視対象から除外

ファイル数が多いディレクトリ、および、モジュールやライブラリのようなコーディングしないファイルをVSCodeのファイルの監視対象から除外する。

自分の場合、この設定のお陰でCPU使用率が10~20%で推移していた状態から0~2%になった。

```json-doc
{
	"files.watcherExclude": {
		"**/.git/objects/**": true,
		"**/.git/subtree-cache/**": true,
		"**/.histroy/**": true,
		"**/.ipynb_checkpoints/**": true,
		"**/node_modules/**": true,
		"**/out/**": true
    }
}
```

## この書き方はNG

```json-doc
{
	"files.watcherExclude": {
		"**/.git/objects": true,
		"**/.git/subtree-cache": true,
		"**/.histroy": true,
		"**/.ipynb_checkpoints": true,
		"**/node_modules": true,
		"**/out": true
    }
}
```
ネットワーク3Dカメラサーバー ビューアの作成

# はじめに
前回の続きとして、NanoPiやRaspberry Piで稼働するネットワーク3Dカメラのレシーバ部分を簡単にWindows環境で作成してみました。

https://qiita.com/nextEDGE-aeroTAP/items/6b81447aff41e9956787

# 得られる結果
作成したアプリを実行すると、画面上にネットワーク3Dカメラの画像と情報をリアルタイムで表示することができます。
現時点では、MJPEGとして読み込んで表示しているだけですが、物体検出などの処理を追加することで監視カメラシステムの開発が可能になります。
サンプルでは、NanoPi 4, Raspberry Pi4に接続したaeroTAP 3D USBカメラからの画像(2つ)をリアルタイムで表示しています。

![IpGrabber.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568972/630f9e38-5d0b-74d8-6a82-bc59f75a6e38.jpeg)

# 準備するもの
Windows 10 or 11 64Bit環境

プログラムのダウンロード
ビルドしたものをGitHubにアップしました。
https://github.com/Taisuke-S/Network3DCameraConsole

# ソースコードとビルドについて

Openframeworks とofIpVideoGrabber を使っています。
Visual Studio 2019環境でビルドしました。

https://openframeworks.cc/ja/

https://github.com/bakercp/ofxIpVideoGrabber

# ビルド時の注意

## コンパイル エラー 'Poco/URI.h':No such file or directory
Includeに以下を追加してください。
\of_v0.11.2_vs2017\addons\ofxPoco\libs\poco\include
同時にLibraryパスに以下を追加
\of_v0.11.2_vs2017\addons\ofxPoco\libs\poco\lib\vs\x64\Release

## リンクエラー 外部シンボル __imp_GetAdaptersInfo は未解決です
リンカーの追加依存ファイルに以下を追加します。
iphlpapi.lib

# 3Dカメラサーバーの指定
data\streams.json ファイルをエディタで開いてネットワークサーバーをリストします。
例: 2台の3Dカメラサーバーに接続するように設定
```perl:
[
    { "url": "http://192.168.3.69:8000/camera/mjpeg" },
    { "url": "http://192.168.1.131:8000/camera/mjpeg" }
]
```

# その他ヒント
   ofApp.h ファイルには、画面に表示するカメラの数と表示スタイルを定義している変数があります。サンプルでは、以下のように値を変更しています。
- 2台のカメラの同時表示
- 1行2列での表示


```perl:
    std::size_t numCameras = 2;
    std::size_t numCameraRows = 1;
    std::size_t numCameraColumns = 2;
```
CP4DaaSでデータ加工-分析-視覚化を実施してみた（第三回：CP4DaaSのプロジェクト内でデータ接続）

## 概要
本連載では、売上明細のマスタデータや顧客マスターデータなどのデータをIBM Cloud Object Storageにファイル転送及び、Db2 Warehouse on Cloudへロードしたのちに、CP4DaaS上のツールである「データ・リファイナリー」、「ダッシュボード・エディター(IBM Cognos Dashboard Embedded)」「SPSS Modeler」を用いて、データ加工から各商品の売上高、また年度/月度などデータの可視化までを実施する。

### 記事一覧
第一回：IBM Cloud Object Storageへファイル転送
第二回：Db2 Warehouse　on Cloudへロード
**第三回：プロジェクト内でデータ接続(本記事)**
第四回：[資産をデータ・リファイナリー（整形）](https://qiita.com/Tiger-Kid/items/4dc15fd65602274a256e)
第五回：[SPSS Modelerを用いてテーブルの結合](https://qiita.com/Tiger-Kid/items/af42be0c60df67438d17)
第六回：[ダッシュボード・エディター(IBM Cognos Dashboard Embedded)を用いてレポート作成](https://qiita.com/Tiger-Kid/items/7ccf96cfb73328eba497)

## 本編
#### プロジェクトの作成
CP4DaaSまたは、Watson Studioにログインする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/ab3d9d78-15ff-e984-ac53-2c3f74a7c1d8.png)


ハンバーガーメニューから「すべてのプロジェクトの表示」を選択し、プロジェクト一覧を表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/a8cea137-7818-fbf2-a14b-e905fecf376d.png)


プロジェクト一覧から「新規プロジェクト」にて、プロジェクトを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/2de5254d-b2d5-e26e-487c-b9ebb2223281.png)

新規プロジェクトにて、「名前」、「ストレージ」を選択して作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/b9d932d8-4ae6-ef61-5824-fb57ac5ae51b.png)

数クリックでプロジェクトを作成できた。続いて、作成された本プロジェクトに、分析資産及びツールを導入する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/c78d2e49-3be4-5214-c7c3-385ead036631.png)

#### プロジェクト内に分析で使用するDBの接続
新規資産から、使用するツールを選択することができる。これらのツールはプロジェクトを使用する様々なスキルレベル及び目的によって異なっている。まずは分析に使用するDBの接続を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/8cf73a80-5334-d41f-8e9e-79d731d318ff.png)

接続するDBを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/e2dcb212-1f8b-8f77-295e-2bb5fd14a5aa.png)

接続に必要な情報を入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/577010ed-0c08-bc8b-57ce-ae6b12d04e05.png)

本記事では、接続の詳細として、「データベース」、「ホスト名またはIPアドレス」、資格情報として、「ユーザー名」、「パスワード」がある。
これらの情報の取得方法は以下の通りである。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/d4ac2c84-d547-ff72-fb06-e598e9670b50.png)

接続するDB(本記事ではDb2 Warehouse)にログイン。
左側に表示されている設定を選択後、上側に表示されている「接続」を選択し、「接続構成リソース」から必要な情報を取得する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/3edcc05e-fdd3-3744-beb5-9108b948934c.png)


接続に必要な情報を入力後、「接続のテスト」を行い、成功を確認後、作成をする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/7fc5bb94-ee39-1bbd-a370-9ada96ac4d6a.png)

資産に接続したDBが追加されていることを確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2505349/e57ad7c6-a7cd-86b0-ec70-c6a35f7203b7.png)
CCNA（200-301）で不合格だった受験記録


## この記事の要約
試験合格のための準備として市販の教科書（白本）
と問題集（黒本）以外にも教材が必要であること。

## 概要
2022年7月31日にCCNA（200-301）に受験したものの不合格ではあったが、
受験体験記を投稿することで反面教師として今後の受験者の合格率アップにつながればと思い投稿した

## ターゲット層
・CCNAに興味がある人
・これからCCNAに受験予定の人
そのためCCNAについての説明などは省略

## 背景
8月に社内のCisco製のスイッチの設定や
調査及び改善をするために5月から勉強を始めた。
スイッチについては全く触ったことがなかったので、
一度体系的に学ぶ必要があると思い、CCNAの本を教科書代わりに利用することにした。

## CCNAの学びから得たこと

### ネットワークの理解
　Ipv4のサブネット計算や、パケットのデータの流れや
　ルーティングの経路の決め方等ほぼ知らなかったことを学べた。
### スイッチの操作方法
　スイッチをCUIで操作するための方法を学び、
　実機を通して何を操作するとまずいのかがわかった。
　モード変更やshow系のコマンドなら入力しても問題ないとか。
### 関心の幅が広がった
　ネットワークの回線が速いといわれている
　NURO光やAU光がダークファイバを使っているだとか。
  任天堂製品のオンラインゲームのping値1桁に下げられないか
　調べたけど距離的な問題はどうしても解決できなさそうで凹んだりとか。

## CCNAの受験動機
　実は5月の段階では受験する気はなかったのだけど、
　6月あたりから勉強した証として残したい気持ちが湧いてきた。

## CCNAの勉強方法
　そもそもの参考書は古かったので情報が足りなかった。
　![iOS の画像 (13).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2105909/7507a078-9d6a-185e-c925-9f5596ca00b7.jpeg)

### 白本と黒本を購入。
　分厚さは白本と黒本どちらもほぼ同じ。
　分厚さの比較
![iOS の画像 (14).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2105909/9a15326d-dd18-eb50-9f4d-6fcd39601bc2.jpeg)

　なお、3カ月勉強したLPIC201（本の左側の分厚さ）との比較しても約2倍ほどの分厚さ
![iOS の画像 (15).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2105909/991769aa-9de4-9d16-6d9c-4fc1fff9b8b9.jpeg)
（一発合格なんて、全然違うじゃん！などとは思っていない......）

勉強時間:150時間ほど

・白本1周
わからないところはネットで調べる。
・黒本2週
　┗1周目で間違えたところにチェックをつけて、2週目はチェックした箇所を解いた
・実機を社内で借りてコマンドの勉強。

## 受験概要

　場所:テストセンター
　受験費用:税抜33,600円
　制限時間:120分
　問題数:100問
　問題形式:選択問題、複数選択問題、分類分け

## 試験感想
・試験時間について
　120分以内に100問解く必要があるが、問題によって
　10秒以内に回答できるものもあり案外時間が30分ほど余った
　
・Cisco語について
　試験内容は英語の為、日本語に翻訳された内容が
　読みづらいとのうわさがあったが実際はそうでもなかった。
　理解出来ないのは環境のせいでもなく自分のせい。

・試験内容について
　暗記すると解ける問題からトラブルシューティング等さまざま
　体感でロンゲストマッチやコストの優先等を問われる問題が多かった。

## どうしたら合格ができそうか

・パケットトレーサーで検証時間を増やしてシミュレーション問題の理解を深める
　┗堅実にネットワークの実力がつきそう
・ping-tでひたすら問題を解く
　┗LPICのときにはこれで乗り切った感がある。
・9tutという過去問を網羅しているサイトがあるらしいので登録する
　┗問題丸暗記は合格後負い目があるのでお勧めしない
　
参考
　[ネットワークエンジニアとして](https://www.infraexpert.com/)
　[試験概要](https://www.cisco.com/c/ja_jp/training-events/training-certifications/exams/current-list/ccna-200-301.html)
Dataloader records not showing up in global search.

インデックスの作成タイミングが違うようです。知らんかった。


[Dataloader records not showing up in global search.](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000ISwJTSA1)

When we do bulk data load through api, it takes time for indexing. When you do same thing from UI it's faster. There is no way to trigger indexing after bulk data load.
API 経由でデータを一括読み込みすると、インデックス作成に時間がかかります。 UIから同じことをすると、より高速になります。データの一括読み込み後にインデックス作成をトリガーする方法はありません。
 

[Global Search on Records from Data Loader Not Working](https://developer.salesforce.com/forums/?id=906F0000000B2w3IAC)


確かに技術のブログで解説されていた。

[Salesforce Bulk Data Loads and Full-Text Search Indexes](https://developer.salesforce.com/blogs/engineering/2014/02/salesforce-bulk-data-loads-and-full-text-search-indexes)
istioctl installが失敗する

[Calico公式の手順](https://projectcalico.docs.tigera.io/security/app-layer-policy)に従って、Istioをインストールしようとしたら、`Install Istio`の手順で次のエラーメッセージが出て困った話。
```bash
$ istioctl install -y
✔ Istio core installed
✘ Istiod encountered an error: failed to wait for resource: resources not ready after 5m0s: timed out waiting for the condition
```

## 環境
- Debian 11.4
- Kubernetes 1.21-13-00
- Calico 3.23.3
- Istio 1.13.2
- シングルノード環境

## 解決方法
マスターノードへのtaintを外す必要がありました。
次のコマンドでマスターノードへのtaintを外します。
```
$ kubectl taint nodes --all node-role.kubernetes.io/master-
```
taintとは汚れの意味で、nodeに紐づきます。
nodeにtaintが付いているとPodが起動できないことがあり、マスターノードにはデフォルトでtaintが付いています。
これによって、`csi-node-driver`という名前のPodが起動せず、`istioctl install`が失敗するようでした。
[シングルノード環境でのCalicoインストール手順(公式)](https://projectcalico.docs.tigera.io/getting-started/kubernetes/quickstart)にもtaintを外すように書いてありますが、見落としていました。

## 参考
[シングルノード環境でのCalicoインストール手順(公式)](https://projectcalico.docs.tigera.io/getting-started/kubernetes/quickstart)
[timed out waiting for the condition Deployment/istio-system/istiod](https://github.com/istio/istio/issues/22677)
[TaintとToleration](https://kubernetes.io/ja/docs/concepts/scheduling-eviction/taint-and-toleration/)
Linuxコマンドをまとめる(自分用)

## 実行中プロセス表示
```
ps
```
## プロセスを終了させる
```
kill [PID] 
```
## ディレクトリの操作
```
// カレントディレクトリの確認
pwd

// ファイルなどを一覧表示
ls

// ファイルとディレクトリの区別をして表示
ls -F

// 隠しファイルを表示
ls -Fa

// ホームディレクトリへ移動
cd
cd ~

// ルートディレクトリ(システム)へ移動する
cd /

// 一つ上の階層のディレクトリへ移動する
cd ../

// ホームディレクトリの中の特定のディレクトリに移動する
例： Directory1/Directory2に移動する場合
cd Directory1/Directory2

//どこかのディレクトリから直でどこかのディレクトリへ移動する
例： Directory1/Directory2　から　Directory-A/Directory-Bに移動する場合
cd ~/Directory-A/Directory-B

// ディレクトリを作成する
例：testというディレクトリを作る
mkdir test

// ディレクトリを削除する
例：testというディレクトリを削除する
rmdir test
```

## ファイルやディレクトリの操作
```
// 空のファイルを作成する
例：testFileという殻のファイルを作成する
touch testFile

// ファイルやディレクトリをコピーする
例：Directory-AをDirectory-Bにコピーベント
ｃｐ -R Directory-A Directory-B

// ファイルやディレクトリを移動させる
例：Directory-AにあるtestFileをDirectory-Bへ移動する
cd Directory-A
mv testFile Directory-B

// ファイルやディレクトリの名前を変更する
例：Directory-BにあるtestFileをTestFileに名前を変える
mv testFile TestFile
同ディレクトリの場合はファイル名の変更になる

// ファイルを削除する
例：TestFileを削除する
rm TestFile

// ディレクトリを削除する
例：Directory-Cを削除する
rm -R Directory-C
```

## パーミッション(権限)
```
// 権限を確認する
ls -la

結果の例
-rw------- user root 4096 jul 12 11:05 .zshrc
-rw-r--r-- user root 省略
(パーミッション ユーザ グループ 最終更新日時　ファイル名) 

// パーミッションの変更
chmod パーミッション ファイル名

r:読み取り、w:書き込み、x:実行
rwx:111(7),rw-:110(6),r-x:101(5),r--:100(4),-wx:011(3),-w-:010(2),--x:001(1),---:000(0)

111や110などは2進表記。
rwx r-- -wx(rwxr---wx)の場合は"743"となる

// testFileのパーミッションを変える
例：パーミッションを743に変えてみる
chmod 743 testFile

// ファイルの所有者を変更する
例：testFileの所有者をuser2へ変える
chown user2 testFile

// ファイルのグループを変更する
例：testFileのグループをrootへ
chgrp root testFile


```
nginxとtomcatの連携をansibleで書いてみた

# はじめに
先日作成した記事の工程をさくっとAnsibleのplaybookで作成してみました。

https://qiita.com/m0chim0chi/items/f83b0a1a359588d76145

Ansibleの設定はすでにできているものとして、playbookのみ記載しています。

### バージョン
OS AmazonLinux2
nginx 1.20.0
JDK 1.8.0_332
tomcat 7.0.76

# playbook

```yml
- hosts: 172.31.0.0　#Ansibleを流される側のIPアドレス
  gather_facts: no　#リモートのOSの情報を取得しない
  become: yes　#rootユーザーで実行する（sudoで実行）

  tasks:
  - name: enable corretto8
    shell: "amazon-linux-extras enable corretto8"
    changed_when: false
#corretto8のトピックを有効にする
#changed_whenの設定で結果に関わらず次のタスクを実行
#（何度playbookを流してもエラーが出ない設定）

  - name: install java
    yum: name={{ item }}
    with_items:
     - java-1.8.0-amazon-corretto
     - java-1.8.0-amazon-corretto-devel

  - name: install tomcat
    yum: name={{ item }}
    with_items:
     - tomcat
     - tomcat-webapps
     - tomcat-admin-webapps

  - name: enable nginx
    shell: "amazon-linux-extras enable nginx1"
    changed_when: false

  - name: install nginx
    yum:
      name: nginx

  - name: setup proxy
    lineinfile:
      path: /etc/nginx/nginx.conf
      insertbefore: '        error_page'
      line: "\n        location / {\n        proxy_pass http://172.31.0.0:8080/;\n        }\n"
      firstmatch: yes
#nginxの設定ファイルに書き込み、リクエストをtomcatに流すproxyを設定
#最初にマッチした'        error_page'を含む行の上に設定を書き込む

  - name: start nginx and tomcat
    systemd:
      name: "{{ item }}"
      state: restarted
      enabled: yes
    with_items:
      - nginx
      - tomcat
```

# 終わりに
プロキシの設定で思う位置に書き込みができず苦戦しました。
実際このplaybookを何度も同じサーバーに流すと、プロキシの設定が流した回数分書き込まれてしまうので、一発限りのplaybookかな、と思います。
【個人開発】Next.js + 無料Api + Vercelでそれっぽいアプリを爆速で作ってみた

# はじめに
最近のマイブームがNext.jsなので、Next.jsを使って何か作りたいなぁと思ってた所、[pokeApi](https://pokeapi.co/)の存在を知り（何番煎じ）、ポケモン世代の心に火が付き作成を決意。本人はWEBベンチャーに未経験で入社し4年くらいのひよっこです。普段はRailsとVueを触っています。

ちなみに転職活動とかもしてるのでそれと並行でさくさくっと作りました。

## 結論から

[PokemonNavigation](https://pokemon-navigation.vercel.app/)

![スクリーンショット 2022-08-01 9.20.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241708/fbe0b6dd-e268-6c01-08fe-431bfc4fbb36.png)

![スクリーンショット 2022-08-01 9.20.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241708/a1ab0fcb-6a78-45c3-0795-96e76191fe66.png)

![スクリーンショット 2022-08-10 17.38.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241708/79914313-5200-a6eb-1092-e86011e7e691.png)

![スクリーンショット 2022-08-10 17.38.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241708/1685c7c1-5a6d-d391-20fc-3080ad610bab.png)

これを作りました。
技術的にはぶっ飛んだ事もしておらずApiを叩いて表示するシンプルなアプリケーションです。
こだわりポイントは初代Game Boyをかなり意識しちゃってるデザインにしてます。

実はまだまだ調整したかったり面倒臭くて後回しにしている所も多くまだ改良を続けるつもりなんですが、作成しようと思ってから、10日程度の合間時間を使って作成しました。vercelだとHello world的なデプロイは一瞬で行けますし。おそらく専業で齧りついて作ると2日とかでいけるんじゃないでしょうか？

## 使用技術について
まず前提としてオールフリー（鯖無料）を貫いています。
自分の中の個人開発の鉄則みたいなものがあって、マネタイズを期待するわけでないものは無料構成を貫いたほうがいいです。そうするとバックエンドとかのアプリは作成が厳しくなるんですが、お金が発生しないのに維持費を払い続けると人の心は折れやすくなります。

インフラはフロントで使うNext.jsと親和性が高いVercelで、バックエンドはSSRとpokeApiにお任せしてます。使用したライブラリはreact-form-hook、mui、react-chartjs-2、nes.css、Pokenode-tsって感じでこれから改良する度に増えると思われます。

個人的に使いたかったのがNes.cssで、開発が止まってるようであれですが、GameBoyなデザインをする上でとっても素敵だなと前々から思っていて、ドット絵なデザインのアプリを作る上で使いたかったので採用しました。まだまだ有効活用出来てないのでこれからの改良で出番を増やします。

外部のApiをお借りしてる以上（というか内部でも必要な事ですが）、キャッシュは必要でどうしようかと思ったらPokenode-tsさんがキャッシュ機能付きなのでありがたく使用させて頂きました。

個人開発の鉄則その2みたいな感じですが（いや個人じゃなくてもかも）、車輪の再開発はしたくないと私は考えていて、使えるライブラリやツールがあればガンガン使って行った方がいいです。開発におけるコストは時間なので、自前実装しなくていいものは先人の知恵に任せます。

## 最近の状態管理トレンド
Vueを普段から触れてる身からするとreduxかなぁと思ってましたが、ReactデフォルトのuseStateを使う派閥も増えてるようで、useStateを選択しました。Next.jsとreduxがそこまで相性がよくない（とのこと）のと今回の要件だと複雑化を生みそうだったので控えました。他だとRecoilというものも選択肢としてはあるようなのですが、概ねuseStateかReduxの２大派閥という感じに見えました。

## 考えないと行けない事
- 日本語化できないかなぁ。（pokeApiが日本語対応している部分が一部で全てを日本語化出来ない為）
- 型をサボってる。（とりあえず公開したかったので思いっきりさぼってます。対応します）
- 新規ページを増やす。（Apiの負荷が増える為、要検討）
- デザインとか機能を増やす整える（まだ弄りたい所がありすぎるので）
- バグを潰す（突貫な所もありバグもあると思うので潰す）
- カスタムドメインどうしよ（つけてもいいけどつけなくてもいい、無料ドメインとかになるのでどちらにしろ微妙だし・・・）

## 後書き
普段Rails＋Vueなんですが、今転職活動してて思ったことがあり、どちらかというとバックよりだよなぁと思ってたんですが、鯖代かかるし個人だとRailsで開発してなくて、大体鯖代がケチれるフロント方面の事しか触ってないなぁと思い。もしかしたら自分の勘違いでフロントよりなのかもしれない。

いい所見つかったらいいなぁ
ストレージを使うまでの流れ（ファイルシステム・マウント） 

# はじめに
本記事は先日アップした記事の続きになります。

https://qiita.com/m0chim0chi/items/265b28d61f6e6eeea54d

ストレージを使用するまでに以下の作業が必要になります。
1. ストレージをパーティションに分ける
2. パーティションにファイルシステムを入れる
3. パーティションにファイルをマウントする

前回の記事で1についてまとめたので、本記事では2と3について触れていきます。

# ファイルシステムとは
一言でいうと`ファイルを管理するもの`です。
ストレージを使用するときに、ファイルシステムは必須と言えます。

### ファイルシステムのイメージ
ファイルシステムはパーティションの中に入れるものです。
イメージとして、パーティションが家の骨組みとするなら、ファイルシステムは壁紙やフローリングなどです。
骨組みだけではまだ住むことはできないので、壁紙やフローリングが住むためには必須になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724001/cfd4d359-6f4c-e2a5-d503-f12746c56880.png)


## ファイルシステムがやっていること
実際には以下のようなことを行っています。
* ディスクの空き容量確保
* ディレクトリ名、ファイル名のサポート
* ディスクに保存されたファイルの物理位置

データを保存したときに、データはディスクに書き込まれます。
ファイルシステムがなければ、データを呼び出すためにいちいちディスクの保存位置を覚えておき、指定しなければなりません。
ファイルシステムがあることで、どのデータがディスクのどこに保存されているのかを管理しておいてくれるので、ファイル名を指定するだけでデータを呼び出してくれるようになっています。

<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724001/3d688680-f40a-8db9-a903-db7a4704459a.png">

## ファイルシステムの種類
ファイルシステムにも種類があります。
機能面に違いがあるので、適当なシステムを選択して使用する必要があります。
|ファイルシステム|説明|
|:---|:---|
|ext2|Linuxの標準ファイルシステム|
|ext3|ext2にジャーナリング機能を加えたファイルシステム|
|ext4|ext3を機能拡張したファイルシステム|
|XFS|RHEL/CentOSで標準のファイルシステム|
|JFS|IBM社が開発したジャーナリングファイルシステム|
|Btrfs|高度な機能を備えたファイルシステム|
|iso9660|CD-ROMのファイルシステム|
|UDF|DVD-ROMのファイルシステム|
|msdos|MS-DOSのファイルシステム|

参考：[Linux教科書 LinuCレベル1 Version 10.0対応](https://www.amazon.co.jp/Linux%E6%95%99%E7%A7%91%E6%9B%B8-LinuC%E3%83%AC%E3%83%99%E3%83%AB1-Version-10-0%E5%AF%BE%E5%BF%9C-%E4%B8%AD%E5%B3%B6/dp/4798166162)

# マウントとは
マウントとは`ファイルをパーティションに紐づけること`です。
マウントを行うことでストレージとファイルと紐づけて使用できるようになります。

### マウントのイメージ
ファイルシステムを入れたパーティションにファイルをマウントします。
位置関係は下の図のようになります。
イメージとして、ファイルをマウントすることは住んだ時に使用する家具を入れるようなもので、これを設置してやっと住むことができるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724001/3aa59ffc-7126-3757-7110-424427097398.png)

# まとめ
非常に簡単にストレージを使用するまでの流れを説明しました。
1. ストレージをパーティションに分ける
2. パーティションにファイルシステムを入れる
3. パーティションにファイルをマウントする

この工程を行うことで、ストレージが使用できるようになり、適切に設定をすれば、障害発生時に被害を最小で抑えることができます。

今回学習して、普段あまり意識せずにファイルを使っていましたが、仕組みを理解して使っていくことは何かあった時に重要だなと感じました。

# 参考サイト
[Linuxのパーティションとファイルシステムとマウント](https://ameblo.jp/bakery-diary/entry-12639340661.html)
[素晴らしきファイルシステムのデータ管理](https://monoist.itmedia.co.jp/mn/articles/1003/02/news112.html)
PostgreSQLでUUIDが長すぎるのでBase64と相互変換してみる

# 目的
テーブル分割を主キーで行いたいです。ここでの主キーはUUIDです。PostgreSQLのテーブル名は63byteなのでテーブル分割した先のテーブル名にUUIDを付けてしまうと長すぎて問題になります。

UUIDは36文字なので残りは27文字です。
```
table01234567890123456789_{uuid}
```

UUIDをbase64にすると22文字(==は省く)になり残り41文字でだいぶつかえます。
```
table01234567890123456789012345678901234_{base64}
```

そこで相互変換するストアードプロシージャを書きました。
ちなみにテーブル名に記号が付くとエラーになるのでダブルクォーテーションでかこんでください。

```sql
create table "mEp+mUwlS9aGKIijHxS/" (id int);
```

# ストアードプロシージャ
```sql
CREATE OR REPLACE FUNCTION uv_uuid_to_base64 (
  p_uuid UUID DEFAULT NULL
) RETURNS TEXT AS $FUNCTION$
DECLARE
BEGIN
  RETURN replace(encode(decode(translate(p_uuid::TEXT, '-', ''), 'hex'), 'base64'), '==' ,'');
END;
$FUNCTION$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION uv_base64_to_uuid (
  p_base64 TEXT DEFAULT NULL
) RETURNS UUID AS $FUNCTION$
DECLARE
  w_pre_uuid TEXT;
BEGIN
  w_pre_uuid := encode(decode(p_base64 || '==', 'base64'), 'hex');
  RETURN (
    substr(w_pre_uuid, 1, 8) || '-' || 
    substr(w_pre_uuid, 9, 4) || '-' || 
    substr(w_pre_uuid, 13, 4) || '-' || 
    substr(w_pre_uuid, 17, 4)  || '-' || 
    substr(w_pre_uuid, 21))::UUID;
END;
$FUNCTION$ LANGUAGE plpgsql;
```
【備忘録】QGroundControlをAndroid にインストールする

## はじめに
今回はAndroid版のQGroundControlのインストール方法について記載します。

MissionPlannerは設定が細かく出来るのが利点ですが、一方で常にPCやタブレットPCを常に持ち歩かなければならないのが難点です（端末を持ち歩くのは意外と手間です）
ですので設定に関してはMissionPlannerで行い、同じルートを動かす場合はAndroid版のQGroundControlを使用して対応をしています。
QGroundControlのwebサイトではAPK（Android Application Package）版を入れる方法を推奨していましたのでその方法について解説します。

:::note info

QGroundControlはPlayストアからダウンロードできますが、機種によって一部の機能が使えないというワナにハマりますので注意が必要です。

:::

## 動作環境
|項目|詳細|
|-|-|
|端末|pixcel 5|
|OS|Android 12|
|GCS|QGroundControl（Android APK 64 bit版）|

## installの流れ
1.APKファイルをスマートフォンにダウンロードする
2.APKファイルをビルドしてスマートフォンへインストールする


## 1.APKファイルのダウンロード
#### ● APKファイルの入手先
QGroundControlの[Download and Install](https://docs.qgroundcontrol.com/master/en/getting_started/download_and_install.html)を開きAndroidの項目を確認するとAPK（Android Application Package）版が記載されている項目がありますので64bit版をタップしてダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064722/c6d9eaa7-3958-cb37-48a0-d86e2e02fd93.png)

#### ●アラートへの対応
APK形式のファイルをダウンロードする場合、アラートが出るのでダウンロードを続行を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064722/1ea2f43a-787b-e749-7825-2eda35ed41c3.png)

#### ●ダウンロード
ダウンロード続行をタップすると、APKファイルのダウンロードが始まります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064722/f533d8b1-b844-24f7-782f-cca3fe2545b2.png)

## 2.QGroundControlのインストール
APKファイルのダウンロードが完了したらインストールを行います。
ダウンロードしたAPKファイルをタップすればビルド⇒インストールが行われます。

:::note info

APMファイルをインストールしようとすると、いくつかアラートが表示されます。
アプリを許可してインストール出来るようにしてください。

:::

アプリの許可が終ると、以下の様な画面が表示されインストール出来るようになります。
インストールをタップするとインストールがはじまります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064722/05df667f-694e-a459-7c84-884fb680ce68.png)

インストールが完了すると、以下の様な画面が表示されます。
インストール後、設定を行いたい場合は「開く」をタップ，後で行う場合は「完了」をタップしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064722/c07eba37-81ef-86b7-865c-22bb600b64fa.png)

## 終わりに
[こちら](https://qiita.com/Fumi_Saito/items/4e3056e2382a405a349d)で記載しているMAVProxy経由でスマートフォンへデータを転送するように設定すれば「PC」と「スマートフォン」双方から機体を動かす事が出来るようになります。
【Salesforce】データローダガイド

# ポップアップメッセージ

### 新しいレコードを追加したり、既存のレコードを更新することを選択した場合、実行しようとしているアクションは元に戻すことができません。

you have chosen to add new records and/or update existing records.
the action you aer about to take cannnot be undone.
are you sure you want to proceeed?

### CSVエラーです。無効なCSVファイル形式です。別のファイルを選択してください。CSVファイルからヘッダー行を取得する際にエラーが発生しました。

CSV Error: Invalid CSV file format.
Please select a different file.
Error getting header row from the CSV file;

### 初期化に成功しました。操作には1件のレコードが含まれます。

Initialization succeeded.
Your operation will contain 1 records.

### 新しいレコードを挿入することを選択しました。[はい]をクリックして開始します。続行しますか？

You have chosen to insert new records. Click Yes to begin.
Do you want to proceed?

### CSVエラーです。CSVファイル形式が無効です。0行目の読み込みエラー：データ列数(104)がヘッダ列数(2)を超えています。

CSV Error: Inavalid CSV file format. Please select a different file.Error reading row #0: the number of data columns (104) exceeds the number of columns in the header (2)

### このQueryLocator（org XXXXXXXX, path / XXXXXXX.cursor）のクエリカーソルデータを見つけることができません。

Unable to find query cursor data for this QueryLocator (org XXXXXXXX, path / XXXXXXX.cursor),please retry your query.

SalesforceのメンテナンスとDataloaderの処理が重なった場合、稀に発生する
対応方法は、リトライ、一度の処理量を減らす方法

# エラーメッセージを確認する

もし結果がエラーだった場合、出力された[errorXXXXXXXXXXXXXXX.csv]のERROR列に記載される。

入力規則が原因でエラーだった場合、入力規則で指定したエラーメッセージを表示する。

Apexの場合、Attempt to de-reference a null objectのように表示する。
※System.DebugをApexに差し込んで確認が必要。

### 値を正しいデータ型に変換する際にエラーが発生しました。日付の解析に失敗しました: null

Error converting value to correct data type: Failed to parse date: null

# 外字をデータローダで対応した結果を確認する

下記のような外字をデータローダで入れると[?]になる

＜例＞
◗, ㈶, 𠮷, 犛, 庨, 詅, 憓, 雞, 坒, 澍, 珹, 俠, 祛, 䕃, 㔟, 隂, 柗, 宁, 庨 , 萊 ,ø , 䑓

𠮷田 太郎(よしだ たろう)さんの場合、[?田 太郎]で作成されてしまう。

# ExportしたcsvファイルをExcelで表示した場合の挙動

https://twitter.com/rkobayashi0704/status/1552972212688281600?s=20&t=lRmqA-YT6jeI3FjtlB0adA

# データローダ使用時の注意点

### トリガは動かしてもよいか？
※レコード作成時、番号を割り振るが、既にCSVデータで割り振り済みの場合、トリガを無効化する必要がある。など

### 入力規則は動かしてもよいか？
※値が入ってないとエラーになるが、一旦データを入れたい場合、無効化する必要がある。など

### Bulk APIを使用するか？
カスタム設定などで保持している値から採番を行う場合、採番の値が重複してしまう可能性がある。

### 外字を使用するか？
上記で記載しているが、外字を使用すると[?]になるため、修正またはApexでの対応が必要。

### 結果を確認したか？また結果を確認できる方法を準備しているか？
トリガやフローなどで想定外の動きになっているかはお客様よりも前に発見すること。


# リンク

[データローダガイド](https://developer.salesforce.com/docs/atlas.ja-jp.dataLoader.meta/dataLoader/data_loader.htm)

[DataLoaderを使いこなそう](https://base.terrasky.co.jp/articles/C5Pk7)

[データローダのインストール手順](https://help.salesforce.com/s/articleView?id=000317204&type=1)

[データローダ使用時の注意事項](https://help.salesforce.com/s/articleView?id=000328727&type=1)

[データローダの使用とCSVファイルの作成についての便利ワザ・注意点](https://qiita.com/K-SNG/items/9fb28f3ef34494dd45f3)
2022年08月何故かベストアンサーをつけてくれない質問


# トレイルヘッド

+ [cannot able to perform verify step , while adding List name ,](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000ISk8x)
+ [データ インポート ウィザード](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HEbLY)

# Apex trigger

+ [How can I get the contact owners the same as the account owners?](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HEbFp)


+ [Testclass for Fileupload using restapi](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HEghQSAT)

# 数式


[Validation Rule](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HFEK7)
Unity で NuGet パッケージを利用する

# はじめに

Unity で NuGet のパッケージを利用したい場合は結構な頻度であります。

- 自前でパッケージをダウンロードして必要なプラットフォームの dll などを手動でコピーする
- [NuGet for Unity](https://github.com/GlitchEnzo/NuGetForUnity)を利用してパッケージをダウンロードする

上記の場合、自分でプラットフォームを選択したり、パッケージのバージョンが選択できなかったりと不便が多いのですが、今回紹介する [UnityNuGet](https://github.com/xoofx/UnityNuGet) は Unity Package Manager(UPM) を通してパッケージとしてインポート出来ますので非常に便利です。

ただし、Unity NuGet では全ての NuGet パッケージが使用できるのではなく、一部の厳選されたパッケージのみが対象となっているようですので、パッケージによっては利用できないものもあります。

## Unity NuGet の使用方法

設定方法は非常に簡単でプロジェクトの `Packages/manifest.json` に以下のスコープを追加するだけです。

```json
{
  "scopedRegistries": [
    {
      "name": "Unity NuGet",
      "url": "https://unitynuget-registry.azurewebsites.net",
      "scopes": [
        "org.nuget"
      ]
    }
  ],
  "dependencies": {
     ...
  }
}
```

## パッケージの確認

正常にスコープが追加できた場合、以下の画像のように『Project Settings > Package Manager』に『Unity NuGet』が追加されているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19224/4e2d6387-a7bf-e54f-8c8f-426a3551e9ee.png)

また、パッケージマネージャーウィンドウで『My Registries』を選択すると、NuGet パッケージのものは『パッケージ名（NuGet）』と表示されているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19224/2d017034-91df-8631-6b2b-e873993f2cf1.png)

あとは通常の UPM と同じように『Install』を選択してパッケージをインストールすることが可能です。

# さいごに

私の環境では Unity NuGet で配信されていないパッケージは手動でインストールし、Unity NuGet でインストールできるものはそれで管理するようにしています。

これまでは手動でインストール、もしくは NuGet for Unity しか選択肢がありませんでしたが、Unity NuGet によってパッケージ管理ができるようになりますので、一度試してもらってよいかと思います。
Linux SSHとそれぞれの認証方法について（自分用メモ

SSH（Secure SHell）とは、暗号化を用いたリモートホストの遠隔操作用のプロトコル。
ネットワーク経由で他のコンピュータに接続して操作する場合に使用。
SSHでは通信内容が暗号化されますが、同じ遠隔操作用のプロトコルであるTELNETでは通信内容が暗号化されないためパスワードや情報を盗み見られる可能性があるので、SSHでのリモート接続の方がより安全。

クライアントがSSHでサーバへログインする際、ホスト認証とユーザ認証が行われます。

・ホスト認証
ホスト認証は、SSHクライアントが接続先のリモートホスト（SSHサーバ）が正しいホストかどうかを確認する（なりすましを防ぐ）ために行います。
クライアントからの接続時に、リモートホストは自身の公開鍵をSSHクライアントに送信します。SSHクライアントは受け取った公開鍵と、SSHクライアントの「~/.ssh/known_hosts」ファイルに格納されているSSHサーバの公開鍵を比べることで正しいホストかどうかを確認します。（「~」はそのユーザのホームディレクトリを示します。）

初めて接続する際はSSHクライアントの「~/.ssh/known_hosts」ファイルにSSHサーバの公開鍵が格納されていないため、サーバの公開鍵を登録するかどうか問われます。「yes」と入力すると「~/.ssh/known_hosts」に登録されます。2回目以降は問われません

SSHサーバの公開鍵と秘密鍵はOpenSSHをインストールする際「/etc/ssh」ディレクトリ配下に作成され、「known_hosts」ファイルにはホスト名・IPアドレス、鍵の種類、ホストの公開鍵が格納されます

・ユーザ認証
ユーザ認証は、SSHクライアントで接続してくるユーザが正当なユーザかどうかを確認するために行います。
ユーザ認証にはパスワード方式と公開鍵方式の2種類。

パスワード方式...ローカルでのログインと同様に、接続ユーザのID/パスワードで認証する
公開鍵方式...公開鍵と秘密鍵の組み合わせで認証する。パスワードを使用せず、鍵を持つ者がログインできる

公開鍵方式を使用する場合は、ユーザごとに一対の公開鍵と秘密鍵を作成して、公開鍵の方をSSHサーバの「~/.ssh/authorized_keys」に登録しておきます。サーバはSSH接続を受け付けた際、登録されている公開鍵とユーザの秘密鍵のペアが一致するかどうかを確認します。一致しなければログインさせません。これによりパスワード方式よりもセキュリティ上強固なユーザ認証を実現します。



【SSHの設定】
ここでは、CentOS 7 + OpenSSH（SSHのソフトウェア）で構成したSSHサーバへ、公開鍵方式で接続する例

CentOS 7には標準でOpenSSHがインストールされています。
OpenSSHのデフォルトのユーザ認証はパスワード方式です。

1. sshdサービスの起動
接続先のSSHサーバ上で、SSHのサーバプログラムであるsshdサービスを起動しておきます。

# systemctl start sshd

2. 鍵ペアの作成
SSH接続するユーザごとに「ssh-keygen」コマンドを使用して公開鍵と秘密鍵のペアを作成します。

書式：
　ssh-keygen [-t 鍵の種類]
※-tオプションを省略した場合はRSAの鍵ペアが作成されます。

SSHクライアント/SSHサーバのいずれかで作成できますが、ここではSSHクライアント上で作成します。
ssh-keygenコマンド実行時にユーザのホームディレクトリ（ログインディレクトリ）に「.ssh」というディレクトリが作成され、公開鍵と秘密鍵が格納されます。

3. 鍵の配置
ユーザの公開鍵「id_rsa.pub」はサーバ上に、ユーザの秘密鍵「id_rsa」はクライアント上に配置します。
ここではクライアント上で作成した公開鍵「id_rsa.pub」をサーバにコピーします。鍵ファイルはUSBメモリに保存して運んだり、scpコマンド（SSHを使用したファイル転送）で安全に転送します。

転送したユーザの公開鍵は、サーバの認証鍵リスト「authorized_keys」ファイルに登録しておきます。

4. SSHサーバの設定の変更
SSHサーバの設定ファイル「/etc/ssh/sshd_config」の次の設定項目を変更します。

PasswordAuthentication no　　← パスワード認証を無効にする
PermitRootLogin no　　　　　　← rootユーザ（システム管理者）でのログインを禁止する

変更を反映するために、sshdサービスに設定ファイルを再読み込みさせます。

# systemctl reload sshd

5. SSH接続
sshコマンドでクライアントからサーバに接続します。ログイン後はリモートホストでの操作が可能。

書式：
　ssh [オプション] [SSH接続ユーザ名@]SSHサーバアドレス
※「SSH接続ユーザ名@」を省略した場合は、実行しているユーザ名をSSH接続ユーザ名として接続

6. SSH接続の切断
SSHサーバからログアウトするにはexitコマンドかlogoutコマンドで切断。また、Ctrl+D（CtrlキーとDを同時に押す）で制御コードEOF（End Of File: ファイルの終端を示す）を送信することによっても、bashが終了しSSH接続が切断。
歴史的PIアドレス とは

## 勉強前イメージ

IPアドレスとは違うの？

## 調査

### 歴史的PIアドレス とは

PIアドレスは Provider Independent Address の略で
歴史的PIアドレスはインターネットが本格化する前にプロバイダを介さず
InterNICと呼ばれる組織がIPアドレスを管理しており、直接割り当てられていました。
そのIPアドレスのことを指します。
InterNICは現在はICANNになっています。

現在のIPアドレスはプロバイダがユーザの配布する形となっていて
ユーザがIPアドレスを使用したい場合はプロバイダ経由でIPアドレスを割り当ててもらうという形になっている。
それ以前は上記のように直接割り当てられていました。

JPNICは2004年から以下のような理由で上記のような歴史的PIアドレスの回収を進めています。

- IPv4の残りIPアドレスが少なくなってきている
- PIアドレスが現在も使われていない可能性がある
- IPアドレスの不正利用を防ぐため

### IPアドレスの種類

- PA(Provider Aggregatable)アドレス
	- プロバイダが持つIPアドレス帯
- PI(Provider Independent)アドレス
	- プロバイダが管理していないIPアドレス

PIアドレスを運用するには簡単ではなくて
独立したネットワーク間の制御のためAS番号を持ったり、トランジットプロバイダに依頼したりしないといけないので
費用が高くつき、通常のユーザがPIアドレスを使用することはないです。
現在はルートDNSやTLD DNSサーバなど公共性の高い組織ではPIアドレスを使用して優先的に割り当てられます。

## 勉強後イメージ

そんなアドレスあるんや・・・知らんかった。。
確かにルートDNSの管理ってどこのプロバイダ？とか思うわ
昔から割り当てられてたところは未だにPIアドレスを持ってる感じなんかね。

## 参考

- [PIアドレス](https://www.wdic.org/w/WDIC/PI%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9)
- [歴史的PIアドレス](https://xtech.nikkei.com/it/article/Keyword/20080527/304206/)
- [歴史的PIアドレスの管理
について](https://www.nii.ac.jp/openforum/upload/c4_setsumeikai2019_jpnic_20191028.pdf)
- [PIアドレスって何ですか？](https://atmarkit.itmedia.co.jp/fnetwork/dnstips/036.html)
【GitHub Actions】平日のみ実行する

# 概要
GitHub Actionsの実行スケジュールでは分、時、日、月に加えて曜日まで指定することができる。
平日のみ実行する場合の記載方法を以下に記す。

# 書き方
cron構文では以下のようにスケジュールを指定する。
```
┌────────────── 分 (0 - 59)
│ ┌───────────── 時間 (0 - 23)
│ │ ┌───────────── 日 (1 - 31)
│ │ │ ┌───────────── 月 (1 - 12)
│ │ │ │ ┌───────────── 曜日 (0 - 6) (日曜日から土曜日)
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
* * * * * 
```

https://en.wikipedia.org/wiki/Cron#Overview

平日のみ実行の場合は以下。
```yml
on:
  schedule:
    cron:
      - '0 0 * * 1-5'
```

:::note warn
日本時間で実行日時を指定するときは時差(約9時間)を考慮する必要がある。
上記の例では平日9時に実行されるが、例えば平日8時に実行したい場合は曜日の指定を0-4(日~木)にする等の調整が必要なので注意。
:::