OmniAICreator/Qiita-1.07M huggingface dataset:
ポーカー判定 PHP

なんとなくポーカーの役を判定するコードを書いてみる。参考なし。最適化はしない。


```php
<?php
define('SPADE', 0);
define('CLUB', 1);
define('HEART', 2);
define('DIAMOND', 3);
$suit = [SPADE, CLUB, HEART, DIAMOND];

// ランダムでカードを選択（重複は考慮しない）
$cards = array_map(fn() => [0 => array_rand($suit), 1 => random_int(0, 13)], range(1,5));

// 判定
$result = judge($cards);

// 出力
$mark = [SPADE=>"♠", CLUB=>"♣", HEART=>"♥", DIAMOND=>"♦"];
$c = array_map(fn($v) => $v[1]==0?'JOKER':$mark[$v[0]].$v[1], $cards);
echo implode(', ', $c) . " : ". $result . PHP_EOL;


function judge($cards) {
	$joker = 0; // JOKERの枚数
	foreach ($cards as $k => $card) {
		if ($card[1]==1) {
			$cards[$k][1] = 14; // 1 は 14 とする
		} else if ($card[1]==0) {
			// JOKERの場合、配列から削除
			unset($cards[$k]);
			$joker++;
		}
	}
	if ($joker==5) return "ロイヤルストレートフラッシュ";

	// スートと数字を分離
	$suit = array_column($cards, 0);
	$number = array_column($cards, 1);
	$max = max($number);
	$min = min($number);


	// フラッシュ判定
	$suit_count = array_count_values($suit); // スートの数
	$isFlush = (count($suit_count)==1);

	// 数字の数
	$number_count = array_count_values($number);
	// ペア数
	$pair = [1=>0,2=>0,3=>0,4=>0,5=>0];
	foreach ($number_count as $v) $pair[$v]++;

	// ストレート判定（ペアがなく、最小値と最大値の差が4以下）
	$isStraight = ($pair[1]==count($cards) && ($max - $min) <= 4);

	// 強い順に判定
	if ($isFlush && $isStraight && $min >= 10) {
		// jokerの枚数に関わらず min≧10 で判定可能
		return "ロイヤルストレートフラッシュ";
	} else if ($isFlush && $isStraight) {
		return "ストレートフラッシュ";
	} else if ($pair[5] == 1 // イカサマ
			|| $pair[4] == 1 && $joker == 1
			|| $pair[3] == 1 && $joker == 2
			|| $pair[2] == 1 && $joker == 3
			|| $joker >= 4) {
		return "ファイブカード";
	} else if ($pair[4] == 1
			|| $pair[3] == 1 && $joker == 1
			|| $pair[2] == 1 && $joker == 2
			|| $joker == 3) {
		return "フォーカード";
	} else if ($pair[2] == 1 && $pair[3] == 1
			|| $pair[2] == 2 && $joker == 1
			|| $pair[3] == 1 && $joker == 2) {
		return "フルハウス";
	} else if ($isFlush) {
		return "フラッシュ";
	} else if ($pair[1]==count($number) && $isStraight) {
		return "ストレート";
	} else if ($pair[3] == 1 || $pair[2] == 1 && $joker == 1 || $joker == 2) {
		return "スリーカード";
	} else if ($pair[2] == 2) {
		return "ツーペア";
	} else if ($pair[2] == 1 || $joker == 1) {
		return "ワンペア";
	} else {
		return "役なし";
	}
}
```

結果（何回か適当に）
```
♠1, ♦8, ♥8, ♠10, ♦11 : ワンペア
♣11, ♥10, ♥10, ♣10, ♥10 : フォーカード
JOKER, ♥1, ♥10, ♠1, ♣12 : スリーカード
♣10, ♠9, JOKER, ♣12, ♠10 : スリーカード
♥6, ♥7, ♣10, ♥8, JOKER : ストレート
♦4, ♥3, ♠6, ♠2, JOKER : ストレート
♠10, ♥11, ♠12, ♠13, JOKER : ストレート
♠9, ♠4, ♠11, ♠8, ♠2 : フラッシュ
♣11, ♠5, ♣5, JOKER, ♠11 : フルハウス
JOKER, JOKER, ♦13, JOKER, ♥3 : フォーカード
♠10, ♠11, ♠12, ♠13, ♠1 : ロイヤルストレートフラッシュ
JOKER, ♠11, ♠12, ♠13, ♠1 : ロイヤルストレートフラッシュ
♠9, ♠11, ♠12, ♠13, JOKER : ストレートフラッシュ
```
Flutter : MVVMでriverpodを使った画面表示時の書き方

## やりたいこと
画面表示時にAPIを介して値を取得し、画面表示したい。
refを使って他のプロバイダのstateを変更したい。　⇦　これが厄介だった

## 問題
・ConsumerWidgetにはiOSの様にviewDidLoadなどの細かいlifecycleが提供されていない
・viewModelProviderを生成する時に下記のエラーが出る（プロバイダーの生成中に他のプロバイダーの値は変えちゃダメだよ的なやつ）
`Providers are not allowed to modify other providers during their initialization.`

## 簡単な方法
1. viewModelの生成時にコンストラクタで値取得を行う
→ refを通して他のプロバイダーのstateを変更しようとするとcrashする。（変更しないのであれば問題ない）
2. FutureProviderを使う
→ loadingやerrorなどの処理を個別に書いたりしないといけないので少し面倒。今回のMVVMに合わせて実装をするのが難しくなる
3. Consumerを重ねる → これを解説します

## コード
```dart: HogePage
class HogePage extends ConsumerWidget {
  const HogePage({
    Key? key,
  }) : super(key:key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final provider = hogeViewModelProvider;
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      ref.read(provider.notifier).initialize();
    });
    return Consumer(
      builder: (_, widgetRef, __) {
        final state = widgetRef.watch(provider);
      }
    }
  }
}
```

```dart: HogeViewModel
final hogeViewModelProvider = StateNotifierProvider.autoDispose<bool>((ref) {
  return HogeViewModel(false, reader: ref.read);
});
class HogeViewModel extends StateNotifier<bool> {
  HogeViewModel(bool state, { required this.reader }) : super(state);

  final Reader reader;

  void initialize() {
     // ここに画面表示時の処理を記載する
  }
}
```
S3トリガのLambdaを作成する際の注意点について

## 事象
今回、AWS S3にファイルがputされたことをトリガに起動するLambdaを作成したのですが、ファイルサイズが大きいファイルを該当のS3バケットにアップロードした際にイベント通知がされずLambdaが起動しないというトラブルがありました。
その原因と対策を共有させて頂きます。

## 原因
そもそもS3には様々なイベント通知のタイプが存在します。

S3トリガのLambdaを作成する場合は、トリガーとしてS3バケットに対してどのようなアクションがあった時に通知を送るかを設定する必要があります。

今回の場合は、S3にファイルが配置(PUT)された時にLambdaを起動させたかったので、以下のPUTのイベントタイプを設定しました。

イベントタイプ：s3:ObjectCreated:Put

AWSのドキュメントを見て頂くと全てのイベント通知のタイプを確認できます。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/notification-how-to-event-types-and-destinations.html

しかし、AWSによるとサイズが大きいファイルをS3にアップロードする場合、特にアップロード方法を指定しなければS3PUTではなくS3マルチアップロードが実行されることがあるそうです。

そのため、ファイルサイズが大きいファイルをS3にアップロードした場合、S3PUTのイベントが通知されなかったのでLambdaが起動しませんでした。

## 解決策

解決策は、Lambdaのトリガーに該当のS3バケットのPUTイベントだけでなく、マルチアップロードイベントも設定することです。

要は、Lambdaに以下の2つをトリガーとして設定すれば良いだけです。

* s3:ObjectCreated:Put
* s3:ObjectCreated:MultipartUpload

ちなみにトリガーの設定方法はLambdaからでもS3からでもどちらでも設定可能です。

![スクリーンショット 2022-06-01 17.48.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572340/3906d3f9-d1ea-8c42-db3a-a5fe2ab5156a.png)

![スクリーンショット 2022-06-01 17.50.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572340/1d4a711d-aad5-da55-e21c-50ca3684dff0.png)


## まとめ

S3にファイルがアップロードされた際にLambda等にイベントを通知する場合、PUTイベントだけだとファイルサイズが大きいファイルをアップロードした際に、マルチアップロードイベントが実行されてPUTイベントが通知されないことがありますのでご注意下さい。
個人開発のCIで使用しているDocker運用が狙ってないのに効率良かった話

現在、CIのなかで行なっている自動テスト、lintをする際、`develop` blanchでbuildしたDocker imageを使用していた

当時作った僕は浅はかだったため、「テストの実行もできてるしよき！」と思っていた

しかし、今になって

「あれ？`develop`の内容でbuildしたimageを使っているから作業ブランチで更新した内容が反映されていないんじゃね？」

と思った。
このことは当時の自分も若干感じていたのか`develop`のimageでは作業ブランチで行なった`gem`とかがインストールされていないと気づいておりworkflow内で`bundle install`を実行していた

しかし、ソースコードはどうだろうか

`develop` blanchのimageをそのまま使っていたとしたらソースコードは`develop` blanchの内容のままなはず

そこで、rspecの内容をわざと失敗させて反映されているかどうか確認したところ

**しっかりテストが失敗していた**

どこで反映されたんだ？と思いworkflowで行われているjobのログを辿ってみた

そこにはしっかりソースコードが反映される様な処理が行われていた

そう、`volume`である

まず、jobが実行されている仮想インスタンスの内部はどうなっているのだろうか
確認してみた

job実行後の現在のパス
```shell
pwd
=>  /home/runner/work/choco_backend/choco_backend
```

repositoryの名前を参照して`repo/repo`というディレクトリが作成されている

次にGithub Actionsといえば`actions/checkout@v2`だと思うが、これはPRのpushされた時の最新のコミットをfetchしてくるので

```shell
pwd
=>  /home/runner/work/choco_backend/choco_backend
ls
=>
Gemfile.lock
README.md
Rakefile
app
appspec.yaml
bin
config
config.ru
db
docker-compose.development.yml
entrypoint.sh
lib
log
public
spec
storage
taskdef.json
tmp
vendor
```
の様にソースコードがfetchされている

これを念頭においてjobで行われているcontainer作成時のログを見てみよう

```shell:initialize_container
/usr/bin/docker create --name bf55af69c5bc485cb5c6b9fe9f329d5c_ghcrionysdinchoco_backenddevelop_7bd346 --label 6a6825 --workdir /__w/choco_backend/choco_backend --network github_network_2f593213afaf4a4088e9760be1f49aad  -e "RAILS_ENV=test" -e "HOME=/github/home" -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work":"/__w" -v "/home/runner/runners/2.285.1/externals":"/__e":ro -v "/home/runner/work/_temp":"/__w/_temp" -v "/home/runner/work/_actions":"/__w/_actions" -v "/opt/hostedtoolcache":"/__t" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" --entrypoint "tail" ghcr.io/nysdin/choco_backend:develop "-f" "/dev/null"
```

 このログでは、コンテナの作成を行なっている。そのオプションで`-v`が指定されているではないか！

注目すべきは以下のオプション指定
`-v "/home/runner/work":"/__w"`
これによってコンテナ内に`/__w/choco_backend/choco_backend/<rails project>`が存在することになる

そして作業ディレクトリが`--workdir /__w/choco_backend/choco_backend `と指定されているので`docker exec <id> bundle exec rspec`などが実行できるというわけだ！！

ところでタイトルにもある様にこれのどこが効率が良いんだって話になるが、通常（？）新しい環境でDocker Containerを起動させる時ローカルにあるDockerfileからimageを１から作成してやると思う

しかし、今回の場合だとimageを`develop` blanchで作成されたものを指定している
これにより、１からの`image`作成をすることなく`develop` blanchとの差分（主に新しく追加したgem)だけ高速化できるというわけだ

当初の自分はここまで詳細を把握していたわけではなかったと思うが思わぬ産物！

Github Actionsで行われている挙動を把握することによりこれがいかに効率よかったのかを改めて実感できたよかった〜〜〜
[c++] set/map で最大/最小値を求める

## Motivation
set および map のデータ構造で、複数のクエリにより継続的にデータ集合が変わる場面において、各状態の集合に対して高速に最大値/最小値を求める方法について書き記す。

## Experiment
`std::max_element` を用いた方法と、`std::set:rbegin` を用いた2種類の方法で、集合の最大値を求める。
処理内容は、以下の通り。
1. 集合にデータを投入する。(N = 10,000)
2. N 回のクエリを実行する。
    2.1. 集合の最大値を取得する。
    2.2. その値を表示する。
    2.3. これを集合から削除する。
3. 2 に要した時間を計測、表示する。
 

### `max_element` を使用した場合 → 計算量 O(N)
max_element については[こちら](https://cpprefjp.github.io/reference/algorithm/max_element.html)を参照。

```c++
#include <stdio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
using namespace std;
using namespace std::chrono;

int main(void){
	set<int> s;
    // 1. データ投入
	int n = 10000;
	for(int i = 0; i < n; i++) {
		s.insert(i);
	}

	// 計測開始
	auto start = high_resolution_clock::now();

	int num_of_loops = n;
	while(num_of_loops--) {
		// 2.1. 最大値を取得
		int max = *max_element(s.begin(), s.end());

        // 2.2. 表示する。表示は省略
        // cout << "max:" << max << endl;

		// 最大値を削除
		s.erase(max);
	}
	// 計測終了
	auto stop = high_resolution_clock::now();
	auto duration = duration_cast<milliseconds>(stop - start);

    // 3. 計測時間の表示
	cout << "It took " << duration.count() << " ms." << endl;
}
```

これを10回行った結果の平均値は `1724ms` であった。

### `rbegin` を使用した場合 → 計算量 O(1)
rbegin については[こちら](https://cpprefjp.github.io/reference/set/set/rbegin.html)を参照。

```c++
#include <stdio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
using namespace std;
using namespace std::chrono;

int main(void){
	set<int> s;
    // 1. データ投入
	int n = 10000;
	for(int i = 0; i < n; i++) {
		s.insert(i);
	}

	// 計測開始
	auto start = high_resolution_clock::now();

	int num_of_loops = n;
	while(num_of_loops--) {
		// 2.1. 最大値を取得
		int max = *s.rbegin();

        // 2.2. 表示する。表示は省略
        // cout << "max:" << max << endl;

		// 最大値を削除
		s.erase(max);
	}
	// 計測終了
	auto stop = high_resolution_clock::now();
	auto duration = duration_cast<milliseconds>(stop - start);

    // 3. 計測時間の表示
	cout << "It took " << duration.count() << " ms." << endl;
}
```

これを10回行った結果の平均値は `6ms` であった。
**今回のケースでは、286倍の短縮に繋がったことになる。**

また、最小値の場合も
- `max_element` → `min_element`
- `rbegin` → `begin`

に対応しているため、最小値を取得する箇所で、`int max = *s.begin()` とすることで O(1) での処理が可能である。

#### map でも同じ。
この場合、begin や rbegin によって返されるのがイテレータであるが、同様のロジックが適用される。

## Conclusion
set や map の最大/最小値取得には、`rbegin`/`begin`を使うべし。
CodePiplineのDeploy StageでInstall eventsが一生続いた話

# 結論
CodeDeployなどログを直接確認できないサービスにおいては、その処理に関連するサービス、リソースのところに行き何か手がかりとなるものがないか探すのが良い！

# 事案

CodePiplineを実行しDeploy stageの段階に来たときに

`Step 1. Deploying replacement task set`
`Deployment lifecycle events`が`install`

にて`in progress`の状態で一生止まっていた

直接ログ確認などができずどうしたものかと悩んでいた
冷静に考えてみると`Deploying replacement task set`ということでタスクの切り替えを行なっている段階ということでタスク関連であると

そこで今回のデプロイで使用されているタスク定義を調べた

`CodeDeploy > Deploy > Deployments > Deploy`
画面にて`Revision details`からRevisionの詳細画面にいくと`appspec.yaml`を確認することができる

![スクリーンショット 2021-12-29 21.54.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276522/eb4a2122-1e28-f79d-c787-88503e564422.png)


ここから使用されている当該バージョンタスク定義の詳細を見に行き設定がしっかりなされているかを確認した

今回の場合で言うと`appspec.yaml`の`TaskDefinition`は`taskdef.json`ファイルに記述したタスク定義となっているのでファイル内容に誤りがないかを確認した

基本的に`taskdef.json`はあらかじめ作成しておいたタスク定義をjson formatでコピーしたものであり修正箇所というと`image`プロパティを`<IMAGE1_NAME>`にする箇所なのでそこのチェックをしたが誤りを見つけることはできなかった

次にタスクを実行させる場面に原因があると思いECS Serviceからタスク実行ログが見るのでそこの確認をしに行った

するとタスク実行停止イベントの山のように存在していた笑

停止されたタスクの停止理由の箇所を確認するとGreen DeploymentにてHealthcheckの設定が`/healthcheck`となっていた

通常であればこれが普通の設定であるが今回テスト的に実行していたので`/healthcheck`パスに何も設定しておらず`/`しかレスポンスが返ってこない状況であった

今回の収穫としては、CodeDeployではCodeBuildのようなログを直接確認できるものはないのでDeployの各段階で行なっている処理に関連するサービス、リソースを確認していくことが重要であるという知見を得た
【論文読み】オートエンコーダを用いた地震計の時系列異常検知

## はじめに

こんにちは。論文を読んだ結果の紹介記事です。  
今回紹介するのは、「オートエンコーダを用いた地震計の時系列異常検知」という論文です。  

- タイトル：オートエンコーダを用いた地震計の時系列異常検知
- 出典：郭家寧, et al.; 人工知能学会, 2020  
- URL：https://www.jstage.jst.go.jp/article/pjsai/JSAI2020/0/JSAI2020_4L2GS1303/_pdf/-char/ja  


## 概要
地震計の時系列データで、経年劣化の場合、明示的にある時刻から異常と判断する根拠がない。
そのため、正常・異常の正解ラベルのないデータから異常検知を行う必要がある。
データ総量は約6PB、１拠点あたりで約130TB以上。


## 技術的特徴
- オートエンコーダーを使用  
- 教師なし異常検知  
- ダウンサンプリング  
- フーリエ変換   
- データ格納はGCP, BigQuery  
- 推論はMicrosoft Azure Machine Learning  
- 可視化はTableau  

## 想定される適用例
- 時系列データでの異常検知全般


## 参考
- [オートエンコーダを用いた地震計の時系列異常検知](https://www.jstage.jst.go.jp/article/pjsai/JSAI2020/0/JSAI2020_4L2GS1303/_pdf/-char/ja)
Google Apps Script(GAS)でダウ先物価格をスプレッドシートにスクレイピング

趣味の投資で情報収集をもっと効率的にできたらと思い、GASを使ってダウなどの指数をスプレッドシートに取り込むだけのスクリプトを書いてみました。
---

基本素人でエンジニアでもなく文系で元フリーターなので、書き方とか変かもしれませんがそこらへんは多めに見てください。
何かアドバイスなどあればそれは逆に嬉しいです。

# 前提条件
1. 指数の数値を取り込むだけ
1. 基本的に指数のページは可変（後からスプレッドシート状で変えられるよう）にする
1. トリガーで定期的に更新

# 機能要件
1. スプレッドシートの黄色枠（A2～C2）に必要情報を入力
1. トリガーで定期実行

# 事前準備

## cheerioライブラリの登録
まず上記のライブラリの登録が必要で、GASの画面の「ライブラリの+」をクリックしてcheerioのライブラリIDを入れる

1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0

![20220531_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2694062/37151c50-3dcd-33d3-39f1-9a4abbf02888.png)

## スプレッドシートの準備

1. スプレッドシートに「指数」シートを用意
1. A1、B1、C1、D1にそれぞれ「取得指数ページURL」「セレクトid_価格」「指数名」「指数価格」と入力
1. A2、B2、C2に必要なURL、id、指数名を手書き入力
![20220531_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2694062/e7a92985-54a3-53c7-8bf9-1acbd90eeb81.png)

これで事前準備は完了


# コードと設定
具体的なコードは下記の通り（スプレッドシートIDなどはご自身の環境に読み替えてください）
```:コード.gs
function dow() {
const ss = SpreadsheetApp.openById("任意のスプレッドシートID");
const sh = ss.getSheetByName("指数");
const sisu_url = sh.getRange("A2").getValue();
const select_id_kakaku = sh.getRange("B2").getValue();

var dowsaki = UrlFetchApp.fetch(sisu_url).getContentText();
var $ = Cheerio.load(dowsaki); 
var $titles = $(select_id_kakaku);
$titles.each(function(index, element) {
  Logger.log($(element).text());
  sh.getRange("D2").setValue($(element).text())
});  
  
}
```


上記のコードをGASの画面に入力し動作するか実際に動かして確認
![20220531_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2694062/277eae0d-7bc3-a8ff-2cf5-6b60ec8d7884.png)

ちゃんととれてる！

トリガー設定については左メニューの時計のアイコンをクリックして
![20220531_4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2694062/b2596621-a6b2-0c3f-1a65-2425c6f367e1.png)

こんな感じで登録すれば、1時間に一度このdowのスクリプトが動き指数価格が更新される

これを応用していけばスプレッドシートに自分の好きな情報を集約して効率よく投資情報を確認できる



# まとめ
今回は比較的簡単なコードで指数価格を自動更新できるスクリプトを書いてみた
初心者なので変な書き方になっているかもしれないので、一つ一つ勉強して直していこうとは思う・・・

このコードにさらにslack通知機能をつけたいと思い、別で作ってスクリプトを作ってみました。
もし興味のあるかたはどうぞ
https://minrich.net/programming/scraping_index_slack/
既存ファイルを新しいGithubにあげる方法

## 目次
[1. 背景](#1-背景)
[2. Githubでのレポジトリ(リモートレポジトリ)の作成](#2-Githubでのレポジトリ(リモートレポジトリ)の作成)
[3. ローカルレポジトリの操作](#3-ローカルレポジトリの操作)
[4. 結果](#4-結果)


## 1. 背景
筆者はgitに慣れておらず、既存のローカルファイルを新しくgithubにアップロードし管理しようとした際に苦戦したので、解決方法、ロードマップをまとめる。

## 2. Githubでのレポジトリの作成
まず、Githubにて今回push(アップロード)するためのレポジトリを作成する。  
以下の画面からレポジトリを作成する。  
![Screen Shot 2022-06-01 at 16.37.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811712/a52eb868-ba8f-f43b-903e-e5f8b1aaa700.png)
- Repository name: レポジトリ名を入力
- Description: レポジトリの概要説明(option)
- PUblic/Private: このレポジトリを公開するかどうか
- **Add a README file**: README.mdをあらかじめレポジトリに含めるかどうか(**チェックしない**)
- **Add .gitignore**: .gitignoreをあらかじめレポジトリに含めるかどうか(**None**)
- **Choose a license**: licenseの設定(**None**)

ここで注意が必要なのが**Add a README file**、**Add .gitignore**と***Choose a license*の三つ。  
この三つが選択され、あらかじめリポジトリ内に含まれていると、ローカルからpushした際(後述)に以下のようになってしまい、Github(リモートレポジトリ)に反映できない。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811712/08f2ece7-483d-e6c1-7bb8-03cbfafa1b8e.png)
筆者はここに引っかかって苦労した。  
ここまで間違いなく選択しレポジトリを作成できれば以下の通りの画面に遷移する。
![Screen Shot 2022-06-01 at 16.52.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811712/3e9f009a-5aaa-4961-2e22-f528e7c54f45.png)

! README, gitignore, licenseに関しては後からでも追加できるため問題ない。

## 3. ローカルレポジトリの操作
ローカルでの操作は序盤のgitのローカルレポジトリ化以降は基本的に上の画像での
**...or push an existing repository from the command line** の通りである。
今回筆者は以下のローカルファイルをGithubにあげるものとする。  
```Linux
~/ $ cd test && ls

# output
hello.py  hello.txt

~/test/ $ git init

# outout
Initialized empty Git repository in /Users/<Username>/test/.git/

~/test/[master] $ git add .
~/test/[master+] $ git commit -m "init commit"
~/test/[master] $ git remote add origin https://github.com/ryuichi-hirano/test.git
~/test/[master] $ git branch -M main
~/test/[main] $ git push -u origin main

# output
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 290 bytes | 290.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/ryuichi-hirano/test.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.
```

## 4. 結果

![Screen Shot 2022-06-01 at 17.06.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811712/6784c55f-21df-d4a3-67a2-f5ef006ac8aa.png)

以上で、上の画像のようにGithub(リモートレポジトリ)に上げ、つなげることができる。
README、gitignore、licenseなどが含まれてしまうとローカルリポジトリとGithub(リモートレポジトリ)の初期段階での構成が違うということで先述の通り **There isn't anything to compare**と表示されてしまうようだった。
【基本情報技術者】データベース

基本情報技術者試験の分野「データベース」についてご紹介いたします。
## データベース
データベースは、**一定の規則に従って関連性のあるデータを蓄積したもの。**
一言で言うと、**整理した情報の集まり**のことを指します。

データベースの例を挙げると、以下のようなものがあります。
・電話帳
・ショッピングサイトの商品一覧
・サービスの会員情報
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/97e20a47-b59e-2737-ca3f-761b369bd11e.png)

## データモデル
データモデルとは、**情報システムが取り扱う現実世界の対象をデータ集合として表現するため、対象を表す情報を抽象化して一定の構造や形式で記述したもの。**
データモデルには、親子関係の木構造で表現する階層モデル、子が複数の親をもつ網状で表現するネットワークモデル、2次元の表で表現する関係モデルがあります。

### 関係モデル
関係モデルとは、データの関係を数学モデル(集合論など)で表現したものです。
これをコンピュータに実装したのが関係データベースです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/b2879c0f-f1d3-f81f-622c-9536926f888a.png)

### 関係データベース
**行と列から構成されるデータを2次元の表によって管理するデーターベース。**
相互の表中の列の値を用いて関係付けられているのが特徴。
**リレーショナルデータベース**とも呼ばれる。表（テーブル）は行（レコード）と列（フィールド）によって形成されています。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/4554bad9-c896-d5a2-aed8-7a99398ac7f7.png)


## スキーマ
**スキーマは、データの形式や性質、他のデータとの関連などデータの定義の集合。**
主に、**外部・概念・内部**の3つのスキーマが用いられ、**3層スキーマ**と呼ばれている。なぜ3層に分けるかというと、3層に分けていればひとつのスキーマに変更があっても、残りの2つには影響しないからです。開発の現場では、仕様変更はつきものです。その都度データベース全体に影響があっては、時間ばかりかかってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/6cfc9e9f-9735-3a9b-7cac-47433884cdce.png)
| 名前 | 説明 |
|:-------:|:--------|
|**外部スキーマ**|**利用者**やアプリケーションからみたデータベースの構造。|
|**概念スキーマ**|**開発者**から見たデータ項目やデータベースの構造。|
|**内部スキーマ**|**データベース**を記録媒体にデータに格納するための物理的な構造。|

## データベース管理システム（DBMS）
**複数の利用者で大量のデータを共同利用できるように管理するソフトウェアのこと。**
コンピューター上のデータベースの整理やデータの検索、更新、共有などを行うソフトウェア。その他の機能としては、保全機能、障害回復機能、機密保護機能がある。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/e147ae4b-73e0-3c44-acf9-27cef3d05770.png)
フィード、マイクロフォーマットとは

# フィード(Webサイトなどの更新履歴を配信するためのファイル)
ブログやニュースなどの更新が頻繁に行われているWebサイトで使われている。
フィードの中身は主にハイパーリンクの集まり。
フィードを読み込むことでサイトに行かなくても情報を取ることができる。

### 思ったこと
フィードを取り込むとはどういうこと？

# RSS、Atom(形式)
フィードでは古くからある形式だ。
現在はRDFという記述言語をベースとして
```RSS1.0```と```RSS2.0```という２つの系列に分裂して開発されている。
それぞれ違いがある。
### RSS1.0
構文が複雑、表現は豊富
### RSS2.0
構文は単純、表現は放棄

また有志の集まりで```AtoM```という形式も構築されている。

# フィードリーダー(ソフトウェア）
Web上のフィードを取得し、管理するためのソフトウェア
定期的に登録されたフィードをチェックし、更新情報をユーザーに閲覧できるようにする機能を持つ。

# ポッドキャスト（手法）
RSSを通してWeb上に公開することで音楽をインターネット上に配信する手法

# マイクロフォーマット（書式)
Webページ中に意味を表現する記述を埋め込むための書式
例
この文字列は電話番号を表しているなどの情報を埋め込む。

# Webページに意味を埋め込む
これを有効にすることによってコンピュータから読み込んで自律的に情報を理解して処理する```セマンティックWeb```を実現できる。
情報管理やスケジュール管理などに利用できるものが増えている。

# いろいろなフォーマット(情報を埋め込む書式は統一されていない)
マイクロフォーマットはmicorformatsコミニュティという団体より用途に応じて定義され、仕様が公開されている。
またマイクロフォーマット以外にもマイクロデータ、PDFa、Schema.orgなどのいろいろな団体が開発しており、統一されていない。
異なるディメンジョンを移動できるSpigotプラグインを作る

## はじめに
サラっと書きます。
Spigot API 1.18.2 のAPIを用いて開発しています。
それ以前のバージョンのAPIでの動作については保証しません。
## ワールド間(ディメンジョン間)を移動するには
ワールド間を移動するには
```
player.teleport(Location型の引数)
```
でできます。
ですがこれだけでは移動することはできません。
幾つかのステップを踏まねばなりません。というわけで1つずつ見ていきましょう。

## ファーストステップ
今回は例としてオーバーワールドの指定座標へ移動するコードを用います。


まずは移動先のワールドを読み込みましょう。
読み込まないとエラーを出して動きません。
```
WorldCreator loadWorld = new WorldCreator("world");
```
と書いてWorldCreator型の変数を定義して代入しましょう。

使用するときはworldの部分をワールド名に変更してください。
(ワールド名が分からないときはワールドデータのフォルダ名を参照すると良き)

## セカンドステップ
次にcreateWorldしましょう。
既にワールドが作成されていてもcreateWorldは必須です。
この段階で読み込むのでとりあえず書いておけば大丈夫です。
```
Bukkit.createWorld(loadWorld);
```
(上記のコードでファーストステップで作成したオーバーワールドを読み込んでいます。)

## サードステップ
それができたらLocation型の変数を定義してDouble型の値を代入しましょう。
Double型の値はx座標、y座標、z座標のそれぞれの分を用意しなくてはいけません。
```
double x = 0.0;
double y = 70.0;
double z = 0.0;
```
各座標に代入↑
```
Location worldLocation = new Location(Bukkit.getWorld("world"),x,y,z);
```
座標は必ずxyzの順番で書きましょう。

## ラストステップ
ここまで来たらあとはテレポートするコードを書くだけです。
最初に書いたコードをここで書きます。
```
player.teleport(worldLocation);
```

## 注意点

コマンドを受け取った時にワールドのロードを実行するよう記述すると、サーバーを立ち上げて最初にこのコマンドを使う際にロードされるので動作が重くなり、タイムアウトなどで接続が切断されてしまうことがあります。
なのでファーストステップとセカンドステップはプラグインの起動時に行うように記述することをお勧めします。
(onEnableの中)

## おわり
おわりです。良いプラグインライフを。
自己紹介

# 自己紹介

どうも御手洗健太です。HALという学校でプログラミングを学んでおります。初めて記事を書かせて頂きますのでまずは自己紹介

## 技術スタック

***

ないです。（迫真）と言いたいけど専門学校でやってきた言語ですと
- JAVA
- kotlin
- PHP
- python

です

## qiitaで記事を書く理由
***

学んだことをアウトプットするためです。
記事を書くことでモチベUPと学んだことへの吸収率UPが目的かな

## 最後に一言

***

よろぴく
testing.postgresql 及び  testing.mysqld ライブラリを使ってみたときの備忘録

# 概要
- `testing.postgresql` 及び `testing.mysqld` は、テストを実行する際に MySQL / PostgreSQL を自動的に起動し、テストが終了したあとに MySQL / PostgreSQL も終了するという動きをしてくれるライブラリ。
- テストする際に本物の MySQL や PostgreSQL が必要な場合に使える。
- DB系のテストでsqlalchemy + インメモリデータベース や mock ライブラリを使ってテストを実行しようとしていたが、あるプログラムをマルチプロセスで動かす可能性が出てきたため今回このライブラリを試してみることにした。

# 参考
https://github.com/tk0miya/testing.mysqld

https://github.com/tk0miya/testing.postgresql

# 環境
```
# Pythonのバージョンを確認
python --version
> Python 3.7.3

# testing.mysqldのインストール
> pip install testing.mysqld

# testing.postgresqlのインストール
> pip install testing.postgresql

# SQLAlchemyのインストール
> pip install SQLAlchemy

# psycopg2のインストール
> pip install psycopg2

# pymysqlのインストール
> pip install pymysql
```

# 準備
以下のようにPythonで書く。

### PostgreSQLの場合
```python:test_postgresql.py
import testing.postgresql
from sqlalchemy import create_engine
import psycopg2

# Lanuch new PostgreSQL server
with testing.postgresql.Postgresql() as postgresql:
    # connect to PostgreSQL
    engine = create_engine(postgresql.url())

    with psycopg2.connect(**postgresql.dsn()) as conn:
        with conn.cursor() as cursor:
            cursor.execute("CREATE TABLE hello(id int, value varchar(256))")
            cursor.execute("INSERT INTO hello values(1, 'hello'), (2, 'ciao')")
            conn.commit()
            cursor.execute("SELECT * from hello")
            rows = cursor.fetchall()
            print(rows)
```

### MySQLの場合
```python:test_mysqld.py
import testing.mysqld
from sqlalchemy import create_engine
import pymysql

# Lanuch new MySQL server
with testing.mysqld.Mysqld() as mysqld:
    # connect to MySQL
    engine = create_engine(mysqld.url())

    with pymysql.connect(**mysqld.dsn()) as conn:
        with conn.cursor() as cursor:
            cursor.execute("CREATE TABLE hello(id int, value varchar(256))")
            cursor.execute("INSERT INTO hello values(1, 'hello'), (2, 'ciao')")
            conn.commit()
            cursor.execute("SELECT * from hello")
            rows = cursor.fetchall()
            print(rows)
```

# 結果
```
[(1, 'hello'), (2, 'ciao')]
```
DockerでDBを建てて、同じ様な感じでテストを行ったことがあるが、結構実行に時間が掛かっていた。それに比べ、こちらは実行速度も早いのでいい感じ。

# 補足
MySQL / PostgreSQLそれぞれのバージョンだが、自分のローカルにインストールしてあるデータベースのバージョン情報を取得して、それと同じバージョンで建ててくれるよう。
DNSサーバーとは

# DNSサーバーとは
人間様は通常サイトの判別にドメイン名を使用している(google.comなど)
しかし、💻にとってはドメイン名ではそのサイトがどこにあるかの判別ができず、そのドメインからIPアドレスに変換する作業が必要になる。
このドメイン名とIPアドレスの変換作業を担っているのがDNSサーバーである

# DNSサーバーの種類
DNSサーバーには役割の違いで２種類存在する

## フルリゾルバー(DNSキャッシュサーバー)
人間がドメイン名を指定した際に💻が最初にリクエストする先のサーバーである。
フルリゾルバーで解決できるドメイン名に関してはそのまま直で💻にIP アドレスを返す。
しかし、フルリゾルバーが全てのドメイン名<=>IPアドレス解決ができるわけではないので、解決できなかった時に問い合わせする先がもう１種類のDNSサーバーである権威DNSサーバーである。
この権威DNSサーバーへの問い合わせによって得られた結果を
フルリゾルバー自身が知らないドメイン名<=>IPアドレス変換を権威DNSサーバーに問い合わせた結果を💻に返すことになる。
また、この権威DNSサーバーへの問い合わせを毎回するのは非効率なので問い合わせ結果をキャッシュする機能が備わっている。これがDNSキャッシュサーバーとも言われる所以である。

## 権威DNSサーバー（DNSコンテンツサーバー)
自分の管理しているドメイン名<=>IPアドレス解決の情報を教えてあげるサーバーのこと。
権威DNSサーバーは自信が保有するゾーンファイルを基にレスポンスを返す。
またフルリゾルバーからリクエストされた権威DNSサーバーが全て解決できることはなく、その権威DNSサーバー自信が解決できなくともゾーンファイルを参照し、このDNSサーバーなら知っているかもという内容を基にそのDNSサーバーの宛先をフルリゾルバーに返すこともある。

## ゾーンファイル
権威DNSサーバーが管理しているドメインの情報が記載されているファイル

ゾーンファイルにはドメイン<=>IPアドレスの対応表だけでなく、そのドメインはあちらのDNSサーバーに任せているよといった内容、自信が管理しているゾーンの管理情報などが記載されている。

# DNSレコードタイプ
## Aレコード
IPv4でホスト名とIPアドレスの関連付けを定義する種類のDNSレコード

## AAAAレコード
IPv6でホスト名とIPアドレスの関連付けをする種類のDNSレコード

## PTRレコード
IPアドレスからホスト名を参照する場合の逆引きに使用される種類のDNSレコード

## MXレコード
対象ドメイン宛のメール配送先ホスト名を定義する種類のDNSレコード

メール転送先のホスト名はAレコードで登録しておく必要があある

## SOAレコード
ドメインのゾーンの管理のために情報を設定するために利用する種類のDNSレコード

書式
```text
【ドメイン名】     【クラス名】 SOA 【DNSサーバのドメイン名】 【連絡先】 (
        【シリアル番号】
        【更新チェックの間隔】
        【リトライ間隔】
        【問い合わせ諦めるぜ期間】
        【ネガティブキャッシュの有効期限】 )
```

- DNSサーバーのドメイン名: ゾーンファイルの基となるデータを持つネームサーバの名前
- 連絡先: このドメインの管理者のメールアドレス
- シリアル番号: ゾーンファイルのバージョンを表す数字
- 問い合わせ諦めるぜ期間: 何らかの理由でゾーン情報のリフレッシュができない状態が続いた場合、セカンダリネームサーバが持っているデータをどれだけの時間利用してもよいかを示す
- ネガティブキャッシュの有効期限: ネガティブキャッシュとは、存在しないドメイン名であるという情報のキャッシュを意味する

## NSレコード
ドメインのゾーン情報を管理する種類のDNSレコード

NSレコードはゾーン情報を管理するネームサーバのサーバを指定しますが、ドメイン自身のDNSサーバを定義するケースと、サブドメインのDNSサーバを定義するケースがある

## SPFレコード
送信者からスパムが送信されるのを防止する種類のDNSレコード

## TXTレコード
ホスト名に関連付けるテキスト情報を定義する種類のDNSレコード
DNSサーバ上でテキスト情報を設定する際に使用するもので、送信ドメイン認証の認証情報といった内容を記述する

あるゾーンに対する権威（オーソリティ）を持つ権威サーバー（権威DNSサーバー）を指定するためのリソースレコードです。ゾーンを委任する際に使用され、複数台の権威サーバーがある場合には、その数だけNSリソースレコードをゾーンファイルに記述する必要がある

## CNAMEレコード
ドメインやホスト名の別名を定義する種類のDNSレコード
Python備忘録(入門) ※編集中

本記事はPython学習を始めた筆者が、備忘録として残したい内容を記述します。
[参考](https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BPython%E5%85%A5%E9%96%80-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E5%9B%BD%E6%9C%AC%E5%A4%A7%E6%82%9F/dp/4295006327)

備忘録
-
**■変数名のルール**
・予約語は使用できない
　識別子として使用できない単語が存在する。
　利用している環境での予約語は下記で参照可能。
```python
import keyword
print(keyword.kwlist)
```
・先頭に_を2つ付けた名前は原則として使用しない。
　Pythonでは特別な用途で使用することになっている。


**■基礎**
・値はデータ型の制約があるが、変数はデータ型に縛られない。
・割り算の算術演算子
　除算（少数）：/
　割り算の商（整数）：//
・f-string
　文字列の直前に「f」を付けると、数値が格納された変数名を{}の中に直接指定できる。
**例**
```python
print(f'名前は{name}、年齢は{age}歳、身長は{height}cmです。')
```
・改行しないprint関数
 「end=''」は改行しないことを指示する。
```python
print('Hello', end='')
print('World')
```


**■コレクション**
・リスト末尾に値追加
```
リスト.append(追加したい値)
```
・リスト：[要素]、タプル：('要素',)
・ディクショナリ：{キー:値}、セット：{値}
・集合演算
　和集合：|
　差集合：-
　積集合：&
　対象差：^


**■条件分岐**
・インデント
　pythonではインデントでブロック（範囲）が指定される。
・三項条件演算子
```python
値1 if 条件式 else 値2
```


**■繰り返し**
・while文：繰り返す回数の目途が立たないときに使う。
・for文：繰り返す回数の目途が立つときに使う。
・range関数
　0以上n未満までの範囲の整数列に評価される。
```python
range(n)
```
・isinstance関数
　データがデータ型と一致したらTrueに置き換わる。
```python
isinstance(データ, データ型)
```


**■関数、引数**
・関数名の衝突による上書き（注意点）
　既に定義されている関数と同様の名前を付けると、以前の関数は呼び出せなくなってしまう。
・デフォルト引数の制約
　デフォルト引数が指定された仮引数より後ろに、デフォルト引数がない仮引数を定義してはならない。
・引数にキーワードを指定した関数呼び出し
　実引数として列挙された順番にかかわらず、値は指定された仮引数に引き渡される。
```python
関数名(仮引数名1=実引数1,仮引数名2=実引数2,...)
```
・可変長引数を引用した関数定義
　呼び出し時にn個以上の実引数を指定できる。
```python
def関数名(仮引数名1,仮引数名2,...,*仮引数名n):
```
・ディクショナリを用いた可変長引数
　仮引数の前に付ける「*」を2つにする。

**■オブジェクト**
・メソッドの呼び出し
```python
オブジェクト.メソッド名(引数...)
```

**■モジュール**
・
localhostで立ち上げアプリをスマホからアクセスする方法[Android , iPhone]

## 概要
開発中のWebサイトの表示確認を実機で手軽にできる方法を紹介いたします！
Android,iPhoneだと若干勝手が違うので詳しく解説いたします。

## 今回使用した端末 
[PC]
Mac Book Pro (Monterey)

[スマホ]
iPhone SE2 (iOS 15)
Galaxy Note 8　(Android 8)


## 前提条件
- PCとスマホが同じWifiに接続されていること
- PC上でローカルアプリが立ち上がっていること

## 手順 [iphone]
### 準備
- 設定アプリを開く
- [Wi-Fi] -> 接続しているWi-Fiの「iアイコン」押下
- HTTPプロキシの「プロシキを構成」　-> 「手動」を押下
- 画像のようにlocalhostで立ち上がっているアプリの情報を入力
※サーバー、ポートの情報は各自の環境のものを入れてください
![IMG_9A37A159AA9C-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2580122/1523984a-12c3-5f69-27cc-c2aff1d45b95.jpeg)

### 動作確認
PCで接続しているURLの「localhost」の部分を、PCのマシン名に置換する必要があるそうです。

マシン名確認手順
　Macの「システム環境設定」->「共有」のコンピュータ名

## 手順 [Android]
※Androidの方のみWi-fi経由でのアクセスができませんでした。
なので、ここでは有線での動作確認方法を書きます。
### 準備
- Android端末とPCをケーブルで接続する
- Galaxyの場合、USBデバッギングをONにする。
- Chromeでアクセス「chrome://inspect/#devices」
- 上記サイトの「Remote Target」に端末名が表示されます。
- 上記サイトの「Port forwarding...」を押下し、ローカルホストアプリのポートフォワーディングを設定する  
※Android端末側で接続するポート番号になります。


### 動作確認
iPhoneと異なり、PCでローカルアプリに接続するURLに上記でポートフォワーディングしたポートを結合します。

※ポートフォワーディングを9000番にした場合
```
http://localhost:９０００/top
```





## 参考サイト
https://www.suzu6.net/posts/141-android-to-pc-localhost/

https://qiita.com/yamshta/items/4517a9b904c2c7f908ed
３週目Springboot 

第3週目スプリングブート
スプリングブートはウェブプログラムを簡単に早く作れるようにサポートするウェブフレームワークだ。 ウェブフレームワークという表現を初めて聞く人のために、しばらくウェブフレームワークを説明してみる。
簡単に言えば、ウェブフレームワークはウェブプログラムを作るためのスターターキットだと考えればいい。 そして、ジャバで作られたウェブフレームワークの一つがスプリングブートだ。

スプリングブートは丈夫なウェブフレームワーク
セキュリティに丈夫
スプリングブートの代わりにスプリングだけを使ってウェブアプリケーションを開発するなら、ウェブアプリケーションを実行できるトムキャットのようなWAS(WebApplicationServer)が必要だ。 WASの種類（Tomcat、Weblogic、WebSphere、JBoss、Jeusなど）は非常に多様であり、設定方式もまちまちであるため、WASについて学ぶべき内容も相当である。 しかし、スプリングブートにはトムキャットサーバーが内蔵されており、設定も自動的に適用されるため、皆さんはWASに対して全く気を使う必要がない。 さらに、配布されるjarファイルにもトムキャットサーバーが内蔵されて実行されるので、互いに異なるWASによって発生する問題も消える。

JPAとは？
スプリングブートはJPA(JavaPersistenceAPI)を使ってデータベースを処理する。 JPAはジャワ陣営でORM(Object-RelationalMapping)の技術標準として使用するインターフェースの母音である

練習
clone　H2コンソル作成
https://github.com/cunp/springboot-practice
![스크린샷 2022-06-01 오후 4.48.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662675/b5802101-808a-645e-000a-acf347cbd61c.png)
IBM Cloudの「クライアントとサイト間の VPN サーバー」（ベータ版）でOpenVPN Connectを使用する場合

## はじめに

「クライアントとサイト間の VPN サーバー」（ベータ版）を使用して、PCとVPCの間でVPNを張る手順は、こちらの記事で詳しく解説されています。

https://qiita.com/y_tama/items/16987e07842262cd9068

その後、OpenVPN Connectを使用する場合にもう一手間必要だったので、そのメモ。

## クライアント証明書をPKCS#12形式に変換

先の記事で作成したクライアント証明書はOpenVPNにインポート可能な形式では無いため、PKCS#12形式に変換する必要があります。

https://openvpn.net/faq/how-do-i-use-a-client-certificate-and-private-key-from-the-android-keychain/

先の記事を例にすると、easyrsaを実行したディレクトリで以下を実行します。パスワードを2回聞かれるので、任意のものを入力。インポート時に使用します。

```
$ openssl pkcs12 -inkey pki/private/client1.vpn.ibm.com.key -export -out pki/issued/client1.vpn.ibm.com.pfx -in pki/issued/client1.vpn.ibm.com.crt -name client1.vpn.ibm.com
Enter Export Password:
Verifying - Enter Export Password:
```

## クライアント証明書をOpenVPN Connectにインポート

メニューから「Certificates & Tokens」をクリック

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/5df4761d-e2b3-7204-1a6f-647f4303d702.png" width="400">

「ADD CERTIFICATE」をクリック。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/808332c2-1f37-f950-2a5b-0e1480e35de2.png" width="400">

拡張子ptxのファイルを選択し、「開く」。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/65ebab24-e9df-1ae9-b839-7764adbd301b.png" width="700">

パスワードを聞かれるので、証明書を変換した際に入力したパスワードを入力。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/d0b7a65e-6d3a-37e3-92ea-6ec1effe737b.png" width="400">

無事インポートされます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/b76dad07-6f8d-2d27-4184-0de8b3ff89ee.png" width="400">

## プロファイル作成と接続

先の記事の手順の「OpenVPNクライアントソフトにOVPNファイルを読み込み」に沿って、OpenVPN ConnectにOVPNファイルを取り込む時の画面の以下のところで、「Assign」をクリックし、先にインポートした証明書を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/a443ffa8-b674-aeb5-a17f-d19a7406be62.png" width="400">

そのまま「CONNECT」で接続します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/b3b2f109-57bf-edfb-b07a-1142f5b5e6da.png" width="400">

無事接続出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/843ff942-7d63-8835-0cf2-661ab71a1200.png)
EC2 インスタンスタイプ〜t系〜

EC2(Elastic Computing Cloud)のサーバーには構成要素がいくつかある。
EC2は仮想サーバーであるが、実態として存在するサーバーの構成要素とほぼ対応しており

- AMI
- インスタンスタイプ
-  EBS
- ENI

が存在する。
今回は、特にインスタンスタイプの１つであるT系に注目する

# インスタンスタイプ
先にインスタンスタイプについて軽く

インスタンスタイプの構成要素にCPU、メモリ、ストレージ、ネットワークキャパシティーがある。

`t2.micro` などと表記され、先頭の`t`はファミリー名と呼ばれ、種類によってそれぞれ異なるユースケースに合わせたスペックを持つ。
例えばm系ならば汎用インスタンスと呼ばれ、バランスの取れたコンピューティング、メモリ、ネットワークのリソースを提供しており、c系では、コンピューティング最適化インスタンスと呼ばれ、高パフォーマンスプロセッサの恩恵を受けるコンピューティングバウンドなアプリケーションに最適である。

その隣の数字は世代を表している

`.`の右側はインスタンスのサイズを表しており`nano` `micro`などが存在し、CPU、メモリーなどのスペックを決める。

[インスタンスタイプ 公式ドキュメント](https://aws.amazon.com/jp/ec2/instance-types/)

# バーストインスタンス
`T4g` `T3a` `T3` `T2`のインスタンスタイプは、バーストインスタンスと呼ばれる。

このバーストインスタンスでは、CPU使用率にベースラインが存在し、このベースラインを越えた（バースト）CPU使用率で稼働させることができる。そして、この越えたCPU使用率の分に対してのみ料金を支払うことになる。この支払いには「CPUクレジット」と呼ばれるものが使用される。

バーストインスタンスのCPU使用率がベースラインを下回っている間は、継続的にCPUクレジットを獲得し、ベースラインを上回っている間は、継続的に CPUクレジットを消費する。獲得、消費されるCPUクレジットの量は、CPU使用率によって変わる。

獲得したクレジットが消費よりも大きい場合、差額のクレジットが蓄積クレジットとして蓄えられ、あとでベースラインを越えてCPU使用率をバーストさせるときに使用する。

> ベースラインを上回っている間は、CPUクレジットの獲得も行っている。しかし、消費のほうが多くなっているので事実上CPUクレジットが消費されていることになる。

 CPUクレジットが消費される際の挙動には、スタンダードモードとUnlimitedモードが存在する

## スタンダードモード
消費したクレジットが獲得したクレジットよりも多い場合、インスタンスは、ベースラインを越えて CPU 使用率をバーストさせるために、蓄積されたクレジットを使用する。蓄積されたクレジットがない場合、インスタンスは徐々にCPU使用率をベースラインまで低下させ、クレジットが蓄積されるまでベースラインを越えてバーストさせることができなくなる。

## Unlimitedモード
CPU使用率がベースラインを越えてバーストした時、最初に蓄積されたクレジットを消費する。蓄積されたクレジットがなくなった場合、インスタンスは余剰クレジットを消費してバーストを維持する。その後、CPU使用率がベースラインを下回った場合、獲得したクレジットを使用して、先に消費した余剰クレジットに対して支払う。
しかし、２４時間の平均CPU使用率がベースラインを越えるとインスタンスは追加使用量に対して vCPU 時間あたりの一定の追加料金で請求される。

[バーストパフォーマンスインスタンスに関する主要な概念と定義](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/burstable-credits-baseline-concepts.html)

[バーストパフォーマンス(T系)インスタンスの特徴を理解して上手に利用しよう](https://aws.amazon.com/jp/blogs/startup/burstable-performance-instances/)
LaravelでAWS SDK for PHP 3.x のAPIを実行すると権限エラーが起きる

# 環境と前提条件
- Laravel8
- AWS SDK for PHP 3.x(https://github.com/aws/aws-sdk-php) をcomposerでインストールして利用
- .envファイルにAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY を設定している

# 症状
AWS SDKのAPIを実行すると以下のエラーが発生してしまう。
```
Aws\Exception\CredentialsException 

  Error retrieving credentials from the instance profile metadata service. (cURL error 7: Failed to connect to 169.254.169.254 port 80: Connection refused (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for http://169.254.169.254/latest/meta-data/iam/security-credentials/)
```

権限のエラーっぽい。
悩んだ末に解決できたので原因と解決策をまとめておきます。

# 原因
.envを書き換えた時に、癖で `php artisan config:cache` を実行していたのが原因でした。
これが原因で、AWS SDKから各種キーの内容が参照できなくなっていた。

### もう少し詳しく解説
AWS SDK for PHPではAWSのキーの参照をgetenv()で行なっています

laravel-app/vendor/aws/aws-sdk-php/src/Credentials/CredentialProvider.phpの300行目あたり

```

    public static function env()
    {
        return function () {
            // Use credentials from environment variables, if available
            $key = getenv(self::ENV_KEY);
            $secret = getenv(self::ENV_SECRET);
            ....
         
```

そして、Laravelでは`php artisan config:cache`を行うと設定ファイルをキャッシュしてしまい、env(), getenv()の実行結果はNULLになってしまいます。

参照: 【Laravel】.envの項目をenvやgetenv関数で取得できない場合の対策 (https://e-seventh.com/laravel-unable-to-read-env/)

これにより、AWS SDKでAPIを実行した時にAWSの認証キーを取得できずにエラーが起きるという流れでした。

# 解決策
その1, 2のどちらかで解決できます。

## その1
configのキャッシュをクリアすれば、getenv()で認証キーが取得できるようになりエラーが解決されます。

```
php artisan cache:clear
```

そもそもconfigキャッシュを使わないという道もありそうだが、それはちょっとという方は「その2」を試してみてください。


## その2
Laravel用のSDK（ https://github.com/aws/aws-sdk-php-laravel ） を使えば解決できそうです。
こちらはこれから試しますが、ざっと見た所.envの内容の読み込みをconfigで行なっているので、問題は起きなそうです。

Laravel用のSDKがあればそちらを使おう！！
AWS: Root User と AdministratorAccess Policyの権限の違い

ルートユーザーは全権限がある。

そのため、アカウント管理のベストプラクティスとしてIAM Userを作りそれぞれのユーザーに相応の権限（ポリシー）を付与するのが良い。

しかし、ポリシーの中に `Administrtor Access`というものがある。
これは管理者権限を持つものだが、ふと疑問に思った。

これはルートユーザーとの権限の差異はどこにあるのか？と。

そこで調べてみた〜〜〜！

クラメソさんがもう記事書いてた
https://dev.classmethod.jp/articles/only_aws_account/

aws公式ドキュメントにも載ってた。（ルートユーザーしかできないこと）
https://docs.aws.amazon.com/ja_jp/general/latest/gr/root-vs-iam.html#aws_tasks-that-require-root

**ルートユーザーしかできないこと(重要そうなの抜粋)**
- ルートユーザーの権限情報の変更
- 請求およびコストマネジメントコンソールへの IAM アクセスを有効にする
- AWSアカウント解約
- AWSサポートプランの変更
- 支払オプションの変更、または削除
~Codepipline~ CodeCommit変更の検出方法

# 概要
`CodePipline`では、ソースコードリポジトリへの変更を検出することでCodePiplineが実行される。
この検出方法にはポーリング型とプッシュ型が存在する

# Poll型
ソースコードリポジトリが変更されたかどうかをポーリングによって検出する
ポーリングとは、複数のクライアント端末の状態を管理・制御する方式で、ホスト端末が接続されているクライアント端末の状態を決められた順番で問い合わせる
[ポーリングとは](https://atmarkit.itmedia.co.jp/aig/07wcr/polling.html#:~:text=%E3%83%87%E3%83%BC%E3%82%BF%E8%BB%A2%E9%80%81%E6%96%B9%E5%BC%8F%E3%81%AE1,%E3%81%97%E3%83%9B%E3%82%B9%E3%83%88%E3%81%8C%E5%8F%97%E4%BF%A1%E3%81%99%E3%82%8B%E3%80%82)

# Push型（イベント駆動）
https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#action-requirements

 AWSリソースは状態の変更が発生するとイベントを生成する
このイベントをCloudWatch Eventsに発行することでCodePiplineの実行を促す

## メリット
- Polling型では順番がくるまで状態変更を発行できなかったが、Push型では即時にイベントを発行できる
- 制限の引き上げ。変更をポーリングするパイプラインに比べて、CodePipeline は、より多くのイベントベースのパイプラインをサポートできます。
- 多数のパイプラインでのエクスペリエンスの向上。お客様によっては、多数のパイプラインでのコードの変更を調べるためにリポジトリを継続的にポーリングすることで、スロットリングまたはコストの増加が発生する場合があります。これらの問題はイベントを使用することで回避できます。


[CloudWatch eventsについて](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/WhatIsCloudWatchEvents.html)

# CloudFormationでの設定

```yaml:CloudWatchEvent
  AmazonCloudWatchEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        source:
          - aws.codecommit
        detail-type:
          - CodeCommit Repository State Change
        resources:
          - Fn::Join:
              - ''
              - - 'arn:aws:codecommit:'
                - !Ref 'AWS::Region'
                - ':'
                - !Ref 'AWS::AccountId'
                - ':'
                - !Ref CodeCommitRepositoryName
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - main
      Targets:
        - Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
          RoleArn: !GetAtt CloudwatchEventRole.Arn
          Id: codepipeline-AppPipeline
```


CloudWatch Eventsを使う場合`PollForSourceChanges` propertyを`false`にしておかないとイベント検出が２回発生してしまう

```yaml:Codepipeline
      Stages:
        - Name: Source
          Actions:
            - Name: SourceAction
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: '1'
                Provider: CodeCommit
              Configuration:
                RepositoryName: !Ref CodeCommitRepositoryName
                PollForSourceChanges: false
                BranchName: main
              RunOrder: 1
              OutputArtifacts:
                - Name: App
```
個人的に勉強になったシステム設計の本を紹介してみる

## はじめに

買ってよかった技術書を紹介しよう！イベントの参加記事です。

https://qiita.com/official-events/8746fa99d4e403fad3d1

## 紹介する本

はじめよう！システム設計～要件定義のその後に
羽生章洋　著

https://gihyo.jp/book/2018/978-4-7741-9539-1

## どんな本？
基本的なシステムとは何かから始まり、要件定義という仕事、
システム設計について可愛いイラストで分かりやすく説明されています。

システム設計については、いわゆる3層アーキテクチャをメインに、
フロント側のUIデザインやバック側の存在意義について、
DBのテーブル設計の方法などがシステム構築の流れを通して解説されています。

初心者向けかと思いきや、
個人的にコラムが結構面白くて中級者～の方でも読み応えがあるかと思います。

## こんな人にオススメ
・現在、システム開発の上流工程に関わっている人
・これから関わる人
・システム設計ってなにしてるの？って人

200ページ程なので、
ガッツリ読むのはちょっと…という方にも良いかと思います。

電子版でも読めるそうなので、
気になった方は是非！
Pimax イヤホン 3種類をレビュー SMAS KDMAS DMAS

SMAS
![EgNy-ylfRaSyTKuRkP0iZw.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/f75ff648-6a53-0177-eea3-719df6eface3.jpeg)
標準で付いてくることが多いもの。単品売りはないです。
驚異的な小ささ。小さいスピーカしか入ってないんでしょうね。
装着感は一番良いです。耳に触れないし軽い。

音はボリュームを100%にしてなんとか使える音が聞こえます。それでもどこか遠くで電話してる会話が聞こえてるような感じ。100均のイヤフォン以下です。耳に密着してないのにパワー無いですからそういう音です。
とりあえずお試しで使うにはいいかもレベル。ストラップに標準添付しなくていいので値段下げてPimaxさん。


KDMAS
![HR8crXmqQ4CcCJijYS7TJA.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/97cb6771-f69b-06c0-9d4c-35b6fc92e505.jpeg)


VALVE Indexのようにオフイヤーで作ってみたけど、音がダメなのでイヤーカフ付けました的な外観。試しにイヤーカフ無しで付けてみましたが、高音がキンキン鳴るだけでダメダメでした。
イヤーカフを付けるとボリューム40%程度でVive Proと同等な感じになります。耳には触れますが無難なイヤフォンです。価格的にもこれを選ぶのが正解かも。ただ、SMASの解放感を知っているとDMASが欲しくなる罠。

DMAS
![DMAS装着.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/4e9d2c4b-abcc-077b-2376-e88a2a395f60.jpeg)

そして、Pimaxのイヤフォンでは最高峰とされているDMAS。SMASと違い耳に近い位置に大型のスピーカーを、KDMASと違いオフイヤーでを実現しています。海外のレビューでは低音が出ないと不評です。まぁ、Pimaxがリファレンスヘッドフォンに匹敵する音と宣伝してるせいかもですが。
実際の音はオフイヤーな小型スピーカーそのもので、海外の評価通り低音が弱いです。低音が無いわけではないですが、安物のPC用のスピーカを聞いているような感じです。耳に当たるものが無いので快適ですが音にこだわる方はKDMASの方が圧倒的に良いです。ボリューム80%くらいでKDMASのボリューム40%と同等の感じ（低音は出ないですが）になります。
お値段程の仕事はしてない感が強いです。Valve Indexはオフイヤーでちゃんと音出てますのでイコライザソフトで補正してみると若干よくなりますが、KDMASには及ばないです。

イコライザについては、こちらを参照ください。
https://community.openmr.ai/t/review-and-improving-the-audio-of-the-kdmas/37913
Peaceのデフォルトある「Bass Boost」を選ぶと概ね良い感じになります。
![Peace.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/38561e9e-98f7-d43c-5a30-cee6109a86be.png)

無料のオープンソースイコライザーAPO
https://forest.watch.impress.co.jp/library/software/equalizerapo/
EqualizerAPOのオープンソースGUIフロントエンドインターフェイスPeace
https://sourceforge.net/projects/peace-equalizer-apo-extension/
Red Hat Enterprise Linux 9をインストールしてみた

# はじめに
2022年5月18日にRed Hat Enterprise Linux 9がリリースされました。
まずはとにかく使ってみようと思い、Red Hat Enterprise Linux 9をインストールしてみましたので、今回はRed Hat Enterprise Linux 9のインストールについて記載していこうと思います。
[Red Hat Enterprise Linux 9](https://rheb.hatenablog.com/entry/2022/05/30/121300 "redhatenterpriselinux9")についてはこちらに記載されています。


# 目次
[1.前提条件](#1-前提条件)
[2.Red Hat Enterprise Linux 9のインストール](#2-red-hat-enterprise-linux-9のインストール)
[3.まとめ](#3-まとめ)
[4.参考文献](#4-参考文献)

# 1. 前提条件
Mac（Intel CPU）上のVirtual BoxにRHEL9をインストールします。
Mac OSのバージョン：macOS Big Sur 11.6.6
Virtual Boxのバージョン：6.1.28
RHEL9は[こちら](https://access.redhat.com/downloads/content/479/ver=/rhel---9/9.0/x86_64/product-software "rhel9")からダウンロードできます。今回は「Red Hat Enterprise Linux 9.0 Binary DVD」を使用しました。
![FireShot Capture 025 - Red Hat Enterprise Linux for x86_64 9 - Red Hat カスタマーポータル - access.redhat.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/40409bcf-5ce6-1cb9-2da5-158a539e4a04.png)


# 2. Red Hat Enterprise Linux 9のインストール
まずはじめに、VirtualBoxの仮想マシンをダウンロードしたRHEL9のisoでブートし、「Install Red Hat Enterprise Linux 9.0」を選択します。
![スクリーンショット 2022-05-31 17.40.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/4965bfec-0229-9ef8-7b00-2d21c2b1c485.png)

次に言語を選択します。
![スクリーンショット 2022-05-31 17.47.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/b9d34557-ef3e-8790-d779-b8db974b471d.png)

続いて、各種インストールに関する設定を行います。
サブスクリプションは「Red Hatに接続」のメニューからアタッチできます。
![スクリーンショット 2022-05-31 17.57.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/c790613c-044d-6602-74e1-fadaa1cbb54b.png)

「インストールの開始」をクリックするとインストールが始まります。
![スクリーンショット 2022-05-31 17.57.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/e0b6e65e-cd68-89c0-d36f-4b0a9939b88c.png)

インストールが完了したら、「システムの再起動」をクリックし、再起動します。
![スクリーンショット 2022-05-31 18.27.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/a891eeff-f0b1-45a4-aecc-f57107b11003.png)

RHEL9が起動します。
![スクリーンショット 2022-05-31 18.28.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/04f72e77-2028-ffce-2573-f9332c66e287.png)

# 3. まとめ
今回はRHEL9をVirtualBoxへインストールしました。
VirtualBox上でも問題なくRHEL9が起動しました。
インストール手順はこれまでと大きな違いはなく、RHELを触ったことのない方でも簡単にインストールできると感じました。
これからRHEL9をいろいろと触っていこうと思います。

# 4. 参考文献
* [Red Hat Enterprise Linux 9 公式ドキュメント](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9 "Red Hat Enterprise Linux 9 公式ドキュメント")
JavaScriptで雑にasync/awaitを使いたい

# 背景

こんにちは、最近Babylon.jsにハマっている[イワケン](https://twitter.com/iwaken71)です。
Babylon.jsはブラウザ上の3DCG表現を実装するためのJavaScriptのフレームワークなのですが、3Dモデルの読み込みなど非同期処理をしたいときがあります。

そんなときに、ベタに

```js
var scene = await createScene();
```

などと書くと「asyncで囲え！Top Levelに書くな！」的なことで怒られます (確か)

その時の対処法をメモしておきます。

# 解決策

```js
(async ()=>{

//書きたいこと書く
var scene = await createScene();
//書きたいこと書く

})()
```

なるほど、こうやってasyncで囲うことができるらしいです。

実際に使ったコードはこちら

https://github.com/iwaken71/babylonjs_webpack_template/blob/master/src/index.js

# 謝辞

こちらのアドバイスは[IwakenLab.](https://iwakenlab.jp/)のDiscordコミュニティにて、[にー兄さん](https://twitter.com/ninisan_drumath)にアドバイスもらいました。ありがとうございます！！！！
Redshiftのsuper型配列を反復処理する方法

# はじめに
Redshiftの[superデータ型](https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_SUPER_type.html)は、配列などを簡単に扱うことができ、とても便利である。
今回は、superデータ型の配列を反復処理する方法を簡潔にまとめてみた。

# 参考ドキュメント
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/query-super.html

# テスト用テーブル準備
今回の検証のために、以下のようなカラムを持つテンポラリテーブルを作成した。

```
create temporary table tmp_test_super(
username varchar(8),
hobby super
);
```

次に以下の値を持つ、jsonファイルを作成し、作成したテーブルにインポートした。

```
{"username":"Mac","hobby":["baseball","soccer","tennis"]}
{"username":"John","hobby":["baseball","cooking"]}
{"username":"Miki","hobby":["cooking","reading"]}
{"username":"Andy","hobby":["baseball","soccer"]}
```

インポートした結果は次の通りである。

```
=> select * from tmp_test_super;

 username |             hobby
----------+--------------------------------
 Mac      | ["baseball","soccer","tennis"]
 John     | ["baseball","cooking"]
 Miki     | ["cooking","reading"]
 Andy     | ["baseball","soccer"]
(4 rows)
```

このテーブルを用いて検証する。

# 検証

この項目では実際にクエリ例を紹介しながら、反復処理を行う。

## 単純に要素を1つずつ取り出す

```
=> select a.*, b from tmp_test_super a, a.hobby b;

 username |             hobby              |     b
----------+--------------------------------+------------
 Mac      | ["baseball","soccer","tennis"] | "baseball"
 Mac      | ["baseball","soccer","tennis"] | "soccer"
 Mac      | ["baseball","soccer","tennis"] | "tennis"
 John     | ["baseball","cooking"]         | "baseball"
 John     | ["baseball","cooking"]         | "cooking"
 Miki     | ["cooking","reading"]          | "cooking"
 Miki     | ["cooking","reading"]          | "reading"
 Andy     | ["baseball","soccer"]          | "baseball"
 Andy     | ["baseball","soccer"]          | "soccer"
(9 rows)
```

このように、**FROM句内に反復したい属性値を記述する**ことで、反復処理が可能となる。

次のように、asを記述しても良い。
```
=> select a.*, b from tmp_test_super as a, a.hobby as b;
```

## 配列の要素ごとにレコード数を数える

```
=> select b as a_hobby, count(1) from tmp_test_super a, a.hobby b group by a_hobby order by count desc;

  a_hobby   | count
------------+-------
 "baseball" |     3
 "cooking"  |     2
 "soccer"   |     2
 "reading"  |     1
 "tennis"   |     1
(5 rows)
```

## 配列の要素をWHERE句で条件指定する

```
=> select a.*, b as a_hobby from tmp_test_super a, a.hobby b where b = 'baseball';

 username |             hobby              |  a_hobby
----------+--------------------------------+------------
 Mac      | ["baseball","soccer","tennis"] | "baseball"
 John     | ["baseball","cooking"]         | "baseball"
 Andy     | ["baseball","soccer"]          | "baseball"
(3 rows)
```

条件指定する際は、`'"baseball"'`とするのではなく、`'baseball'`とすればよい

# まとめ
super型配列を反復処理するためには、FROM句に記述する必要があることがわかった。
JSONなどをそのままRedshiftで扱いたいときは、配列のまま簡単に扱うことができるsuper型は非常に便利である。
railsにおけるmodel間の関連

ruby on railsにてmodel間の関連(one2manyとか)を定義する方法を調べたときに少してこづったので、どうやったのかを記しておこうと思います。

## やりたかったこと
下記の2つようなテーブルを作成したいです
**Userテーブル**
| PK | FK | カラム名 | 項目名|
| -------- | -------- | -------- | -------- |
| ◯  |	  | id.    |ユーザ番号|
|    |	  | email  |	メールアドレス|
|    |	  |password_digest|	パスワード|
|    |	  |display_name|	表示名|

**Task テーブル**
| PK | FK | カラム名 | 項目名|
| -------- | -------- | -------- | -------- |
| ◯  |	  | id.    |タスク番号|
|    |	  | name  |	タスク名|
|    |	◯  |user_id|	作成ユーザー|
|    |	◯  |asignee_id|	担当者|

Taskテーブルのusr_idとasignee_idがUserテーブルのidとなるようにしたかったです。
UserとTaskがone2manyの関係ですね。

## 関連付けの方法を調べてみた
関連付けをする方法はすぐわかったのですが、カラム名を明確に指定するやり方が見つからなくて少し困りました。
### User model
```ruby
class User < ApplicationRecord
    has_many :tasks, foreign_key: "user_id", primary_key: "id"
    has_many :tasks, foreign_key: "assignee_id", primary_key: "id"
```
冗長なコードになっている気はしますが、
- 第一引数(:tasks)
    - 関係があるオブジェクトの指定
    - 複数形にする必要がある
- 第二引数(foreign_key: "user_id")
    - 参照**先**のテーブルのカラム名
    - ここではTaskテーブルのuser_idカラムと、assignee_idをそれぞれ指定しています
- 第三引数(primary_key: "id")
    - 参照元のテーブルのカラム名
    - ここではUserテーブルのidカラムを指定しています
### Task model
```ruby
class Task < ApplicationRecord
    belongs_to :user, foreign_key: "user_id"
    belongs_to :user, foreign_key: "assignee_id"
```
- 第一引数(:user)
    - 関係があるオブジェクトの指定
    - こっちは単数系
- 第二引数(foreign_key: "user_id")
    - 参照元のカラム名の指定

## rspecによるテスト
関連付けがきちんと行われているかをテストするのには[sholuda-matchers](https://github.com/thoughtbot/shoulda-matchers#activemodel-matchers)が便利でした。
Taskのspecでは下記のように記述をするだけでテストができます。
```ruby
it "belong to user id " do
    belong_to(:user_id).class_name(User)
end

it "belong to assignee id" do
    belong_to(:assignee_id).class_name(User)
end
```
`belong_to`では、どのカラムの関係をテストするかを指定して
`class_name`では、どのmodelを参照しているのかを指定してあります。

## まとめ
公式のドキュメントを読んだらすぐに分かったので、記事にするほどでもないかもしれませんが備忘録的に残しておきます。
ruby on railsはこっちが明示的に記述しなくても裏でよしなにやってくれていることが多すぎて何やってるかよく分かんないことが多い印象です。
ちゃんとドキュメント読みます...