OmniAICreator/Qiita-1.07M huggingface dataset:
TerraformでAWS RDS Aurora MySQL3(MySQL 8.0互換)クラスタを最低限構築する

# 環境
2022/03/01現在

```
$ terraform -v
Terraform v1.1.2
on linux_amd64
```

# tfファイル

## クラスタ設定

```terraform:rds_cluster.tf
resource "aws_rds_cluster" "mysql80" {
  cluster_identifier = "aurora-mysql80-cluster"

  engine         = "aurora-mysql"
  engine_version = "8.0.mysql_aurora.3.01.0"
  // engine_versionをこう指定しないとデフォルトのAurora MySQL2(MySQL5.7互換)で設定されてしまう
  // 8.0.mysql_aurora.までは共通で、後ろのバージョンはWebコンソールの"利用可能なバージョン"の値だと思われる
  // 今回は値取得のために新しくクラスタを作成し、terraform importして取得した

  master_username = "username"
  master_password = "password" // tfstateに残るので仮置し、webコンソールから書き換える
  port            = 3306
  database_name   = "database"

  db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.mysql80.name
  // カスタマイズしないなら"default.aurora-mysql8.0"でもよいが、
  // コンソールで一度クラスタとインスタンスをデフォルトで構築しないと作成されない。


  backup_retention_period = 15
  preferred_backup_window = "18:00-20:00" // 03:00-05:00(JST)

  availability_zones = ["ap-northeast-1a", "ap-northeast-1c","ap-northeast-1d"]
  // RDSクラスタはAZが最低3個になるまで勝手に自動で追加される
  // ap-northeastを使うなら最初からすべて入れるのが吉
  // 実際にインスタンスを置くAZの指定はaws_db_subnet_groupで行う

  db_subnet_group_name = aws_db_subnet_group.mysql80.name
  vpc_security_group_ids = [aws_default_security_group.default.id]

  lifecycle {
    ignore_changes = [
      master_password, // パスワードが変更されていても無視する
      availability_zones // 書き換えられていても問題ないので無視する
    ]
  }
}
```

```terraform:rds_cluster_parameter_group.tf
resource "aws_rds_cluster_parameter_group" "mysql80" {
  name   = "aurora-mysql80-cluster-parameter"
  family = "aurora-mysql8.0"

  parameter {
    name         = "time_zone"
    value        = "Asia/Tokyo"
    apply_method = "immediate"
  }
  // MySQL8.0からデフォルトの文字コードがutf8mb4になったのでいつもの呪文を書かなくてよくなった
}
```

```terraform:rds_cluster_subnet_group.tf
resource "aws_db_subnet_group" "mysql80" {
    name        = "aurora-mysql80-cluster-db-subnet"
    subnet_ids  = aws_subnet.private.*.id // 編注：サブネットは別途作っておくこと
}
```

## インスタンス設定

```terraform:rds_cluster_instance.tf
resource "aws_rds_cluster_instance" "mysql80" {
  count = 2

  cluster_identifier = aws_rds_cluster.mysql80.id
  identifier         = "aurora-mysql80-cluster-instance-${count.index}"

  engine                  = aws_rds_cluster.mysql80.engine
  engine_version          = aws_rds_cluster.mysql80.engine_version

  instance_class          = "db.t4g.medium"
  // Aurora MySQL3は最低インスタンスがt.mediumになった

  db_subnet_group_name = aws_rds_cluster.mysql80.db_subnet_group_name

  db_parameter_group_name = aws_db_parameter_group.mysql80.name
  // カスタマイズしないなら"default.aurora-mysql8.0"でもよいが、
  // コンソールで一度クラスタとインスタンスをデフォルトで構築しないと作成されない。

  monitoring_role_arn = aws_iam_role.aurora_monitoring.arn // 編注：Aurora MySQL2と変わらない
  monitoring_interval = 60

  publicly_accessible = false
}
```

```terraform:rds_cluster_instance_parameter_group.tf
resource "aws_db_parameter_group" "main_mysql80" {
  name   = "aurora-mysql80-cluster-instance-parameter"
  family = "aurora-mysql8.0"
}
```

# TIPS
- Aurora MySQL2から3への自動移行はできないので3のクラスタを別で立てて、DMSなりmysqldumpしてインポートするなりで移行する必要がある。
Mac OS初心者、コンソールでcurl出来なくて困った

最近初めてMac OSを触っていて、JenkinsのAPIを利用するためコンソールでcurlコマンドを叩いた際にこんな表示になった

```
curl --user ’hogehoge:qwsedrftgyhujiko' -s 'http://....../json' ｴﾝﾀｰﾎﾟﾁｯ
>  ｴﾝﾀｰﾎﾟﾁｯ
>  ｴﾝﾀｰﾎﾟﾁｯ
>  ｴﾝﾀｰﾎﾟﾁｯ
>
```

curlでjsonを取得したいのだが、実行したら大なりが表示されるだけで
URLが合っているのか間違えてエラーになっているのかすら分からず、
再度コマンドとにらめっこして判明

```
→→→ ’hogehoge:qwsedrftgyhujiko' -s 'http://....../json'
```

Macに備わっているメモにコマンドを書いてコピペ実行していたが、メモの表示に慣れずシングルクォーテーションの全角半角が違っていることに気付かなかった。
もしやと思い > に ' を入力してエンターを押したら無事にコマンドを終了出来た。

## 最後に
これが発生した時知識が何もなかったので「Linux　大なり　入力待ち」などで検索した結果、どこも標準出力について書いてあるだけで対処法が全然見つからず焦った経験をここに記載しました。(Control + C で対処自体は簡単に出来るけど)
初歩的な内容かとは思いますが、同じ現象でお困りの方の参考にしていただけましたら幸いです。
【RDKit】Draw.MolsToGridImageで作成したイメージの保存

# はじめに
最近、RDKitを使用し始めました。
その中で`Draw.MolsToGridImage`で作成したイメージの保存したいと思うことがありました。
イメージの保存は以下のようにできるとありました。

```python
img.save('sample.svg')
```

しかし、私の場合は以下のようなエラーが出てうまく保存できませんでした。

```
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-35-a3256ff69e93> in <module>
----> 1 img.save('sample.svg')

AttributeError: 'SVG' object has no attribute 'save'
```

イメージの保存の仕方がわかったので共有します。

# 本文
## 環境
Dockerで作成したJupyterLab上で実行しています。
* macOS Monterey 12.2.1
* Docker version 20.10.12
* Python 3.9.5
* rdkit-pypi 2021.9.4

## RDKitのimport

```python
from rdkit import Chem
from rdkit.Chem import Draw
```

## サンプルデータの作成

```python
smiles_dict = {
    'benezene': 'c1ccccc1',
    'pentacene': 'c1ccc2cc3cc4cc5ccccc5cc4cc3cc2c1',
    'BTBT': 'S1c2ccccc2C2=C1c1ccccc1S2',
    'TMTES-pentacene': 'CC[Si](CC)(CC)C#Cc1c2cc3c(C)ccc(C)c3cc2c(C#C[Si](CC)(CC)CC)c2cc3c(C)ccc(C)c3cc12',
}
```

## smilesをrdkit.Chem.rdchem.Molオブジェクトに変換

```python
moles_dict = {}
for name, smiles in smiles_dict.items():
    moles_dict[name] = Chem.MolFromSmiles(smiles)
```

## Imageの保存
今回の問題の解決方法は`with open()`を使うということです。
SVGとして保存する場合は、データは`str`である必要があります。
また、PNGとして保存する場合は、`bytes`である必要があるようです。
どちらの場合も`img.data`でその形式のデータを取得できます。

```python
type(img.data)

# SVGの場合の出力
str
# PNGの場合の出力
bytes
```

### SVGとして保存
SVGとして保存する場合は`Draw.MolsToGridImage()`の引数に`useSVG=True`を指定してください。

```python
img = Draw.MolsToGridImage(moles_dict.values(), molsPerRow=2, subImgSize=(400, 400), legends=moles_dict.keys(), useSVG=True)

with open('sample.svg', mode='w') as f:
    f.write(img.data)
```

### PNGとして保存

```python
img = Draw.MolsToGridImage(moles_dict.values(), molsPerRow=2, subImgSize=(400, 400), legends=moles_dict.keys())

with open('sample.png', mode='wb') as f:
    f.write(img.data)
```

## 実行結果(sample.png)
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043119/a843fafc-d303-a9fa-2231-7c530803af81.png)

# おわりに
今回は`Draw.MolsToGridImage()`で作成したイメージを保存する方法を紹介しました。
間違い等がありましたら、ご連絡いただけますと幸いです。

# 参考
[RDKit](https://www.rdkit.org/docs/index.html)
[RDKit日本語ドキュメント](https://www.rdkit.org/docs_jp/index.html)
["How to save "IPython.core.display.SVG" as PNG file?"](https://stackoverflow.com/questions/67189346/how-to-save-ipython-core-display-svg-as-png-file) -- Stack Overflow
備忘録・任意の文字で区切られた数字の集まり

カンマ区切り・空白区切りの両方に対応したい、という需要から。
入力される文字列は、何らかの文字列によって区切られた数字の繰り返し。
負の値は考慮しない。

```js
const reg =/[\d]{1,}/g;
const list1 ="1 2 3".match(reg);   // [1,2,3]
const list2 = "5 66 ,7".match(reg); //[5,66,7]

```

最長一致を使う流れでした。
これで一致をとれても積極的に使うわけではないですが、この程度で試行錯誤するのもばかばかしいので。
より効率的な方法があるかもしれませんが、考慮しません。

# 追記
コメント欄で指摘があったので追記。

```js
const reg =/\d+/g;

```
上記の内容でも結果は同じ。
+は1回以上の繰り返しだから、{1,}と等価。
\dは単体でMatchする条件として機能するから…などなど。
中学理科の運動を大人向けに解説

# 中学理科の運動とは？
運動分野とは学術的には力学になる。力学とは未来を予想すること。
力学はエネルギーと力と位置の関係を示している。
この3つのものは別々のものを表し、約3000年前までは全く関係ないモノと捉えられていました。

# エネルギー
私なりの表現では、物体が他の物体の影響を受けずに力を発したり、位置を変えたりする能力になる。

```math
E=\int Fdx　・・・(1)
```
式ではこのように表される。Eはエネルギー、Fは力、xは位置を表す
# 力
私なりの表現では、物体の位置やエネルギーを変える現象。


# 位置
私なりの表現では、物体の位置


# 3つの関係
最初に話したエネルギーと力と位置の関係は(1)式で表されている。
エネルギーは力を位置のかけ算になる。単純なかけ算ではなく、難しい数式で表している理由は、力が位置で変化するためである。
(1)式からは次の3つがわかる
 1. 物体にかかる力を位置ごとにわかれば、エネルギーがわかる。
 1. 物体の位置ごとのエネルギーがわかれば、力がわかる。
 1. 物体のエネルギーごとの力がわかれば、位置がわかる。
3つ目がわかりやすいが、物体の力とエネルギーがわかれば、未来の物体の位置が予想できる。

# 結び
中学で学ぶ運動の分野は、エネルギーと力と位置の関係を表している。
物体の速度であったり、時間も教科書では取り扱っているが、ここではわかりやすくするために割愛している。
速度と時間は力の中の要素になっている。
離散後の伝達関数の実装方法 覚え書き(c2d -> 実装)

連続系伝達関数(s領域)の離散化はMATLABやPython.controlのc2dコマンドで簡単に出来るけれど、
でどうやって組み込みソフトの周期タスク内に落とし込む形にするのかという話のメモ書きです。
<br><br>
(手計算で離散化させれば実装まで持っていけるのに、c2dコマンドで出てきたものをどう扱ってよいか恥ずかしながら迷子に。)

## 離散化まで 

例として単純な積分器$(\frac{1}{s})$、対象のタスクは1秒周期(sample_time=1)とします。
離散化はc2dコマンド一発で

MATLABの場合は
```MATLAB
sample_time = 1;
s= tf('s');
integral_c = 1/s;
integral_d = c2d(integral_c, sample_time, "tustin")
```
Pythonの場合は
```python
import control
from control import tf, c2d

sample_time = 1
s= tf('s')
integral_c = 1/s
integral_d = c2d(integral_c, sample_time, method='tustin')
```

出力はどちらを使っても
```MATLAB
integral_d =
  0.5 z + 0.5
  -----------
     z - 1
Sample time: 1 seconds
Discrete-time transfer function.
```
こちらの出てきた式は出力$Y$,入力$U$とする離散系伝達関数で下記を指します。
$$ \frac{Y(z)}{U(z)} = \frac{0.5z + 0.5}{z - 1} $$
これをどう実装できる形にするのかが分からなくなるポイントで、自分は迷子になりました。

## 実装可能な式へ

ここから$z$の次数を下げてから差分方程式にします。
(分母より分子の次数が高い場合は非プロパーで実装不可なので下には進めません)

まず、右辺の分母分子両方を(分母の)$z$の最高次数で割ってzの最高次数を0とし実装可能な形にします。
この場合は$z$で割るので、
$$ \frac{Y(z)}{U(z)} = \frac{\frac{0.5z}{z} + \frac{0.5}{z}}{\frac{z}{z} - \frac{1}{z}} $$
よって
$$ \frac{Y(z)}{U(z)} = \frac{0.5 + \frac{0.5}{z}}{1 - \frac{1}{z}} $$
左辺を$Y(z)$とするように式変形していくと
$$ Y(z) \times (1 - \frac{1}{z}) = (0.5 + \frac{0.5}{z} ) \times U(z)$$

$$ Y(z) = Y(z) \times \frac{1}{z} + 0.5 \times U(z) + 0.5 \times \frac{1}{z} \times U(z) $$
ここまで変わらず出力は$Y$, 入力は$U$です。


次に、時間領域tへの書き換えを実施します。
これも単純で、$z$がかかった項は今回値の$t$となり、$z-1$がかかった項は前回値$t-1$になります。

具体的には
 - $Y(z)$ は　$Y(t)$  : 今回の出力
 - $Y(z)\times\frac{1}{z}$ 　は　 $Y(t-1)$ : 1回前の出力
 - $U(z)$ は $U(t)$ : 今回の入力
になります。
<br>
したがって、元の式
$$ Y(z) = Y(z) \times \frac{1}{z} + 0.5 \times U(z) + 0.5 \times \frac{1}{z} \times U(z) $$
を変換すると
$$ Y(t) = Y(t-1) + 0.5 \times U(t) + 0.5 \times U(t-1) $$
になりました。


日本語にすると
```python
今回出力 = 前回出力 + (0.5 * 今回入力) + (0.5 * 前回入力)
```
<br>
C言語ライクに書くと下記です。

```C
float Y = 0f;　    //出力値
float Y_z1 = 0f;  // 出力の前回値
float U = 0f;     //入力値
float U_z1 = 0f;  //入力の前回値

Task_1sec()　//離散化時のサンプル時間ごとに実行される関数
{
    //入力の取得
    U = funcGetU();
    printf("入力U=%f",U);
    
    //Yの算出
    Y = Y_z1 + (0.5f * U) + (0.5f * U_z1);

    //出力
    printf("出力Y=%f",Y);

    //前回値の更新
    U_z1 = U;
    Y_z1 = Y;
}
```
2022/3/3主にITとかセキュリティの記事(2/2)

「QRコード」悪用のサイバー攻撃　パーキングメーターを襲う(3/2)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/052100113/021800076/

Firefoxのハングアップ障害　悪いのはグーグル？(3/2)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/052100112/021800034/

PowerShellで手軽に取得　遠隔地でも情報収集
Part 1　標準ツール(3/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/021600129/021600001/

Wiresharkを使って異常なパケットを検出
Part 2　分析(3/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/021600129/021600002/

Pythonを活用してパケットを可視化する
Part 3　プログラミング(3/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/021600129/021600003/

NEWS pickup＆digest（2022/1/13～2/10）(3/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800011/021700052/

トヨタ取引先のサイバー被害で露呈した「供給網リスク」、狙われる保守用VPN装置(3/2)
https://xtech.nikkei.com/atcl/nxt/column/18/00989/030200077/

ハッカーに狙われたトヨタ車の部品、急所は他に「約200社」か(3/2)
https://xtech.nikkei.com/atcl/nxt/column/18/00001/06600/

DXのスピードを高める「モダンアプリ開発」、どんな要素で構成されるか(3/2)
https://xtech.nikkei.com/atcl/nxt/column/18/01968/030100001/

量子コンピューターによる暗号破りに備える、Infineonが新TPM(3/2)
https://xtech.nikkei.com/atcl/nxt/column/18/01537/00322/

ごみファイルの掃除やデータの整理、Windows 10にある長年の不満を解消しよう(3/2)
https://xtech.nikkei.com/atcl/nxt/column/18/01950/021400002/
【React】axiosによるHTTPリクエスト

## はじめに
　本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

## axiosによるHTTPリクエスト

``` Client.js
// axios-case-converterは、snake_case / camelCaseを変換するため利用
import applyCaseMiddleware from "axios-case-converter";
// axiosをインポート
import axios from "axios";

// ヘッダーはケバブケースのままにする
const options = {
  ignoreHeaders: true,
};

// URLの共通部分を設定
const client = applyCaseMiddleware(axios.create({
  baseURL: "http://localhost:3001/"
}), options)

export default client;

```

```Auth.js
import client from './Client'
import Cookies from 'js-cookie'

// サインアップ
export const signUp = (params) => {
  return client.post("auth", params)
}

// サインイン
export const signIn = (params)  => {
  return client.post("auth/sign_in", params)
}

// サインアウト
export const signOut = () => {
  return (client.delete(
    "auth/sign_out", {
      headers: {
        "access-token": Cookies.get("_access_token"),
        "client": Cookies.get("_client"),
        "uid": Cookies.get("_uid")
      }
    }
  ))
}

// 認証済みのユーザーを取得
export const getCurrentUser = () => {
  if (!Cookies.get("_access_token") || !Cookies.get("_client") || !Cookies.get("_uid"))
  return (client.get(
    "/auth/sessions",{headers: {
      "access-token": Cookies.get("_access_token"),
      "client": Cookies.get("_client"),
      "uid": Cookies.get("_uid")
    }}
  ))
}
```
Jaśkowski のスタイルによる自然演繹

# はじめに

演繹体系のひとつである「自然演繹」について、**何が自然なのか**については、明確に記述されている文書は少なく思います。

フレーゲ・ラッセル・ヒルベルトらの定式化がなかなか技巧的で、人間が行う非形式的な証明における推論方法とは大きく異なることから、それとの対比として提唱された定式化が**自然**演繹であると私は理解しています。

ここでは自然演繹の提唱者のひとりである Jaśkowski (ヤシュコフスキー、または、ヤスコフスキー) の方法について概説します。同じく自然演繹の提唱者として有名な Gentzen のものとはやや異なる形式です。ここでは命題論理の説明にとどめ、述語論理については省きます。
 
> なお、本記事では数理論理学の慣習にしたがって、「ならば」を $\supset$ で、「否定」を $\neg$ で表します。なお、「または」「かつ」はこの2つから導出できるので、命題はこの2つの演算子だけを使用していると仮定します。

# 参考文献

- Dag Prawitz. Natural Deduction. Dover Publications, Inc., 2006. (初版 1965)

# 仮定の導入からの推論

Jaśkowski は、人は「仮定の導入からの推論」を多用すると指摘しています。

例えば $A \supset B$ を証明するには、「$A$ を仮定して $B$ を証明」すればよいです。

また、背理法も「$A$ を仮定して矛盾を導くことにより $\neg A$ を証明する」方法なので同様であると言えます。

# 記法

Jaśkowski の1929年の論文では仮定の導入による文脈の区切りを**箱**で表しました。
次にあげるのは $(\neg A \supset \neg B) \supset (B \supset A)$ の自然演繹による証明です。※カッコ付き数字は説明のために付加しています。オリジナルの証明の書式には含まれません。

```math
\begin{gather}
\boxed{\begin{gather}
\neg A \supset \neg B \quad \cdots(1)\\
\boxed{\begin{gather}
  B \quad \cdots(2)\\
  \neg A \supset \neg B \quad \cdots(3)\\
  \boxed{\begin{gather}
    \neg A \quad \cdots(4)\\
    \neg A \supset \neg B \quad \cdots(5)\\
    \neg B \quad \cdots(6)\\
    B    \quad \cdots(7)
  \end{gather}} \\
  A \quad \cdots(8)
\end{gather}} \\
B \supset A \quad \cdots(9)
\end{gather}} \\
(\neg A \supset \neg B) \supset (B \supset A) \quad \cdots(10)
\end{gather}
```

基本的には箱内の上部に導入した仮定 $A$ を書き、そこから導ける命題を書き連ねていきます。それにより $B$ が証明できれば箱を閉じて、$A\supset B$ をその下に書きます。

- (10) を証明するためには $\neg A \supset \neg B\cdots(1)$ を仮定して $B \supset A\cdots(9)$ を示せばよい。箱内の1段目に (10) を書く。
- (9) を示したい。そのためには、さらに $B\cdots(2)$ を仮定して $A\cdots(8)$ を示せばよい。箱を新たに開始して (2) を書く。
- (1) で導入した仮定はネストした箱の中でも使えるので、(3) として置く。つまり、(2) と (3) から (8) を示せばよい。
- (8) を背理法で示すためにその否定、$\neg A\cdots(4)$ を仮定する。これも新しい箱を作ってそこの最上段に書く。(5) は (3) からコピーしてきた。
- (4) と (5) から、modus ponens (MP) により $\neg B\cdots(6)$ が得られる。
- (7) は (2) からコピーしてきた。
- (6) と (7) は矛盾するので、背理法によって (4) の否定である (8) が証明できた。
- (2) (と (3)) から (8) が証明できたので $B \supset A\cdots(9)$ が示せた。
- (1) から (9) が証明できたので (10) が証明できた。(証明終)

たぶん本人も箱を書くのが面倒くさくなったのでしょう、1934年の論文ではインデントのようなもの (正確には数字の列) を使った書式を提案しています。

##  (ざっくりした) 推論ルール

- $A$ と $A\supset B$ が証明できたなら $B$ を導いてよい。
- $A$ を仮定して $B$ が証明できたなら、$A\supset B$ を導いてよい。
- $\neg A$ を仮定して $B$ と $\neg B$ が証明できたなら、$A$ を導いてよい。

以上のように比較的シンプルな規則からなりますが、これで命題論理の完全な推論体系になっているはずです (参考文献には証明はなかったが)。

## まとめ

いかがでしたか? Jaśkowski のスタイルのメリットはその原理と規則がシンプルであることだと思います。一方で「ならば」「否定」にもとづく規則だけでは証明が長くなりがちだし、背理法を多用するのはあまり自然ではなさそうに見えます。

それを改善するために「かつ」「または」の演算子を導入し、それらに対する推論規則を設けて、仮定の導入・消去を証明木の形で表現すると Gentzen スタイルの自然演繹になるはずです。

以上

※誤りなどのご指摘歓迎です。
Laravel: with(eager load) Tips

# with
- リレーションのメソッドをwith()内に書くことでeager loadができる。

```User.php
$users = User::with('posts')->get();

// リレーションメソッド
public function posts() {
    return $this->hasMany(Post::class, 'user_id', 'id');
}
```

- リレーション先のobjectには動的プロパティとしてアクセスできる。

```php
foreach ($users as $user) {
    $user->posts;
}
```

- リレーションのネストや複数記入も可、その場合は一つずつクエリが発行されている。

```php
$users = User::with([
    'posts.tag',
    'address', 
])->get();
```

```sql
select * from `posts` where `posts`.`user_id` in (userのids) and `posts`.`deleted_at` is null
select * from `tags` where `tags`.`post_id` in (postのids) and `tags`.`deleted_at` is null
-- //
```

- 上記でのクエリからもわかるが「deleted_at is null」がデフォルトで指定。
便利だが、table名のaliasをつけた時に元の名前でdeleted_atを呼び出そうとしてエラーが出る。
->回避方法あるのか?

```php
// error
User::from('users as u')->get();
```

- 複数に分けても可
```php
$query = User::query();
$query->with('posts');
$query->with('address');
```

- カラムを選択できる
    - リレーション関係の外部キーは必須
    - 半角に注意
```php
$users = User::with('posts:user_id,title');

// 半角開けるとエラー
$users = User::with('posts:user_id, title');
```
100日でSQLの達人になる@LeetCode! Day30 <WHERE 変数 IN(SELECT文)>

## 570. Managers with at Least 5 Direct Reports （問題レベル: Medium）要課金
今日の問題はこれ。
５人以上の部下を管理している管理者をリストアップするという問題。

`GROUP BY, HAVING`と`WHERE 変数 IN(SELECT文)`を組み合わせればこれまでの知識で解けるシンプルな問題だった。
珍しく！？模範回答がある問題で、模範解答は`JOIN`を使った回答であった。
しかし、`Discuss`では、こちらの回答が最も`Vote`を得ており、理解しやすい回答であったためこちらを採用しました。

今日のポイントは`WHERE 変数 IN(SELECT文)`を使うだった。
`NOT IN(SELECT文)`はこれまで記事にしてきましたが、`IN`は一応はじめての記事でした。

```:SQL
SELECT name FROM employee
WHERE id IN(SELECT managerid FROM employee GROUP BY managerid HAVING COUNT(managerid) >=5)
```

* [LeetCode](https://leetcode.com/)の問題は、`MS SQL Server`で解いています。
MacでRStudioを使用するために「.Rprofile」を設定

# RStudioでパッケージを自動読み込み

M1チップ搭載Macに「RStudio」をインストールしました。
RStudio起動時に、以下を自動実行しパッケージを読み込むために「.Rprofile」を用意しました。

~~~
library(stats)
library(tidyverse)
library(ggplot2)
library(GGally)
library(patchwork)
library(lubridate)
library(dplyr)
~~~

RStudioの左上パネルで上記を記述します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/ed5ea450-af6e-fef7-6350-8ecda17f0ad9.png)

「.Rprofile」というファイル名で保存します。

# 「.Rprofile」が「.Rprofile.R」になる

ところが、以下のメッセージが出て、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/a3545c57-3db4-c49c-2c1c-57b2befe0eef.png)

「.Rprofile.R」という名称で保存されます（RStudioの右下パネル）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/f210c915-5eab-c2fa-f8b5-3987263e7b47.png)

このままでは設定が読み込まれません。

# ターミナルで「.Rprofile.R」を見えるように

ただし、通常「.Rprofile.R」はFinderで表示されません。
そこで、ターミナルで以下を実行し見えるようにします。

~~~
% defaults write com.apple.finder AppleShowAllFiles TRUE
% killAll Finder
~~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/80a5515c-073f-76ab-1360-68051fae689c.png)

ファイル名を「.Rprofile」に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/3e3426be-75a9-2aff-ce2e-669722687d5d.png)

Finderで各種ファイルを非表示に戻す場合は以下実行します（削除したくないファイルが見えてしまうので元に戻しました）。

~~~
% defaults write com.apple.finder AppleShowAllFiles FALSE
% killall Finder
~~~

# RStudioに自動取り込み

RStudioを起動すると、以下メッセージが表示され、設定が自動で読み込まれたことがわかります。
「tidyverse」パッケージと重なるパッケージがあったので、「Conflicts」メッセージが出ましたが、とりあえず動作には問題ないので、後で調整することにします。

~~~R
── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5     ✓ purrr   0.3.4
✓ tibble  3.1.6     ✓ dplyr   1.0.8
✓ tidyr   1.2.0     ✓ stringr 1.4.0
✓ readr   2.1.2     ✓ forcats 0.5.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
~~~

右下パネルをみると、「.Rprofile」となっていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/ce07c3db-b119-1c3e-1b2e-3ff5392d92e9.png)

**了**
PYNQ2.7でAXI BRAM Controllerがうまく利用できなくなった問題

# PYNQ 2.7(PYNQ-Z1向けimage)での動作確認
これまで作ってきた画像処理系の.bitファイルと.hwhファイルならびには実害なく動かせていたが、新しく作っているAXI BRAM Controllerを使った回路はうまくアドレスが取得できないでいる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2541794/cb55f658-3728-a5d8-fb07-5ec471958770.png)

具体的にはip_dictでmyipは先頭アドレスと範囲が取得できているようだが3つのAXI BRAM Controllerについてはip_dictでできていない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2541794/240f4a8f-5fa4-f5d3-c563-1bf4f1576560.png)

.hwhなどの生成がしくじっているのかとVivadoのバージョンを2018.3と2020.2とMLと変更してみたがいずれもダメだった。


# PYNQのダウングレード
Vr2.7からVer2.6にダウングレードしたところ同じ.bitファイルと.hwhファイルで以前とうまく読み出せるようだった。とりあえずVer2.6で不便でもないため、そのままVer2.6で行こうと思う。
limitとoffsetについて

activerecordはrailsを使う際にはよく使われるとおもいますが、コマンドを打ったりコードを書いたりする際にlimitとoffsetをちゃんと知らんかったのでまとめようとおもいます。

## limit
これは名前から分かるかもしれませんね。
引数に数値を渡すことで、指定したレコード数を取得できます。
例えば、
```
User.limit(2)
# 最初のレコードから2件レコードを獲得される
```

## offset
これは、特定の位置からそれ以降のレコード数を取得できるメソッドです。
```
User.offset(3)
# 最初から3件目のレコードから最後までのレコードを獲得する
```

最後にこの2つを合わせた書き方があるんです。

## 途中から指定した件数を取得
以下のようなコードになります。
```
User.limit(3).offset(7)
# 最初から7番目のレコードから3件値を取得する
```
次回は、link_toのソースコードをアウトプットしようと思っていますので重めの内容になるかと思います
以上です。何か間違いがございましたら、ご教示いただけますと幸いです。

【参考資料】

https://railsdoc.com/page/limit

https://railsdoc.com/page/model_offset
Docker+AWS Lambdaのローカルテスト環境を作成する

## 概要

Lambdaのローカルテスト環境をDockerで作成しました。本記事ではPythonで書いています。
公式ドキュメントを読んでも上手くいかなかったので、記事にします。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images-create.html

## 用意するもの

- Dockerコマンドを実行できる環境

## 構築手順

### ディレトリ構成

```
（プロジェクトルートディレクトリ）/
├── Dockerfile
├── requirements.txt (不要なら作成しなくて良い)
└── app.py
```
### ファイル作成

```Dockerfile:Dockerfile
FROM public.ecr.aws/lambda/python:3.8

COPY app.py ${LAMBDA_TASK_ROOT}
COPY requirements.txt  .

RUN  pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"

CMD [ "app.handler" ]
```

```python:app.py
import sys
def handler(event, context): 
    return 'Hello, This is Lambda Test'
```

※本記事では`requirements.txt`は空で環境作成します。
何か必要なモジュールがあれば追記して次の動作確認をしてください。

### 環境構築・動作確認

#### 1. イメージ作成
テストで`hello-world`という名前のイメージにしていますが、お好きな名前で問題ございません。

```terminal
$ docker build -t hello-world .
```

#### 2. コンテナ作成
ローカルはポート9000で公開していますが、こちらもお好きなポートで大丈夫です。コンテナ内の8080ポートについては変更しないでください。
```bash
$ docker run -p 9000:8080 hello-world
~~
02 Mar 2022 15:57:27,797 [INFO] (rapid) exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)
```

#### 3. 動作確認

別ターミナルを起動し、`curl`で作成した関数を実行します。`/2015-03-31/functions/function/invocations`のパスについてはDockerfileで指定したイメージによるものなので特に考えずに設定してください。

`app.py`で設定したレスポンスが表示されます。

```bash
$ curl -d '{}' http://localhost:9000/2015-03-31/functions/function/invocations
"Hello, This is Lambda Test"
```

コンテナ作成を実行したターミナルのログには以下が表示されます。環境などによって表示が異なりますのでご承知おきください。

```terminal
02 Mar 2022 15:57:27,797 [INFO] (rapid) exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)
02 Mar 2022 16:00:22,977 [INFO] (rapid) extensionsDisabledByLayer(/opt/disable-extensions-jwigqn8j) -> stat /opt/disable-extensions-jwigqn8j: no such file or directory
02 Mar 2022 16:00:22,977 [WARNING] (rapid) Cannot list external agents error=open /opt/extensions: no such file or directory
START RequestId: f96f05b2-cf54-4ebf-94d7-d8399c37afcd Version: $LATEST
END RequestId: f96f05b2-cf54-4ebf-94d7-d8399c37afcd
REPORT RequestId: f96f05b2-cf54-4ebf-94d7-d8399c37afcd  Init Duration: 0.21 ms  Duration: 65.85 ms      Billed Duration: 66 ms    Memory Size: 3008 MB    Max Memory Used: 3008 MB
```

## まとめ

Docker+Lambdaのローカルテスト環境が簡単に作成できました。
テストを書く際はapp.pyを編集したり、requirements.txtに必要なモジュールを記載してからビルドしてください。
0-1ナップサック　アルゴリズム

# 何が書いてあるか。
0-1ナップサック問題[^1]のアルゴリズムのGo言語実装サンプル
[^1]: 重量を越えないような物の組み合わせのうち、価値が最大になるようにな組み合わせを求める問題。


```go
package main
import (
    "fmt"
    "math"
    )
type Kingyo struct {
    weight int
    kati int
}
func main(){    
    var N,x int
    fmt.Scanf("%d %d", &N,&x)
    
    kingyo:=make([]Kingyo,N)
    for i:=0;i<N;i++ {
        var w,k int
        fmt.Scanf("%d %d", &w,&k)
        kingyo[i]=Kingyo{w,k}
    }
    
    //fmt.Println(kingyo)
    
    choice:=make([][]int, N+1)
    for i:=0;i<N+1;i++ {
        choice[i]=make([]int, x+1)
    }
    
    for i:=1;i<=N;i++ {
        for j:=0;j<=x;j++ {
            choice[i][j]=choice[i-1][j]
            if j>kingyo[i-1].weight {
                choice[i][j]=int( math.Max( float64(choice[i][j]), float64(choice[i-1][j-kingyo[i-1].weight]+kingyo[i-1].kati)) )
            }
        }
    }
    
    //dump(choice)
    fmt.Println(choice[N][x])
}

func dump(choice [][]int) {
    for i:=0;i<len(choice);i++ {
        fmt.Println(choice[i])
    }
}
```
外部ネットワークに繋がっていないAIXでJProfilerを動かすまで

# 外部ネットワークに繋がっていないAIXでJProfilerを動かす

- 環境
サーバー AIX(7.2) **外部ネットワークに接続されていない**
クライアント Windows10+VNC Viewer

https://www.realvnc.com/en/connect/download/viewer/

# JProfilerはGUIが必要なのでVNC Serverをインストール

```rpm -Uvh tightvnc-server-1.3.10-2.aix6.1.ppc.rpm```で入れば話は早いが、それは勿論無理。

## 「AIX Toolbox」から片っ端からrpmを取得して転送

https://www.ibm.com/support/pages/aix-toolbox-open-source-software-downloads-alpha

クライアント側で取得しscpでAIXに転送。

rpmコマンドは最終的に以下のようになった。
rpmさんに怒られるままに泣きながらダウンロードして転送を繰り返した。

```
rpm -Uvh tightvnc-server-1.3.10-2.aix6.1.ppc.rpm \
libjpeg-9d-1.aix6.1.ppc.rpm \
zlib-1.2.11-2.aix6.1.ppc.rpm \
gcc8-8.3.0-6.aix7.2.ppc.rpm \
libgcc8-8.3.0-6.aix7.2.ppc.rpm \
gcc8-8.3.0-6.aix7.2.ppc.rpm \
info-6.7-1.aix6.1.ppc.rpm \
sed-4.8-1.aix6.1.ppc.rpm \
ncurses-6.2-3.aix6.1.ppc.rpm \
gettext-0.20.2-1.aix6.1.ppc.rpm \
libxml2-2.9.11-1.aix6.1.ppc.rpm \
libunistring-0.9.10-1.aix6.1.ppc.rpm \
xz-5.2.5-1.aix6.1.ppc.rpm \
xz-libs-5.2.5-1.aix6.1.ppc.rpm \
xz-lzma-compat-5.2.5-1.aix6.1.ppc.rpm \
glib2-2.56.1-3.aix6.1.ppc.rpm \
libffi-3.2.1-3.aix6.1.ppc.rpm \
libgcc-8-1.aix7.2.ppc.rpm \
libstdcplusplus8-8.3.0-6.aix7.2.ppc.rpm \
libtextstyle-0.20.2-1.aix6.1.ppc.rpm \
libgomp-8-1.aix7.2.ppc.rpm \
libgomp8-8.3.0-6.aix7.2.ppc.rpm \
gcc8-cpp-8.3.0-6.aix7.2.ppc.rpm \
mpfr-4.1.0-1.aix6.1.ppc.rpm \
gmp-6.2.1-1.aix6.1.ppc.rpm \
libmpc-1.2.1-1.aix6.1.ppc.rpm \
libstdcplusplus-8-1.aix7.2.ppc.rpm \
freetype2-2.10.4-1.aix6.1.ppc.rpm \
libpng-1.6.27-3.aix6.1.ppc.rpm \
bzip2-1.0.8-2.aix6.1.ppc.rpm
```

下の3パッケージが実は重要で、入れとかないと後にJProfilerのインストーラに怒られてしまう。

```Error: fontmanager (Not found in com.ibm.oti.vm.bootstrap.library.path)```

このエラーをググったらヒットして汝freetype2を入れ給えとのありがたいお言葉をみつけたという絡繰りである。

インストールができたら以下のコマンドでVCN Serverを起動させる。

```
vcnserver
```

# JProfilerはJava11以降が必要なのでこれも入れる
私の場合は/opt直下にインストールした。

```
chmod +x ibm-semeru-certified-jdk_ppc64_aix_11.0.14.1.bin
./ibm-semeru-certified-jdk_ppc64_aix_11.0.14.1.bin
```

（インストール場所を聞いてくれる）

# 環境変数の設定
インストーラに言われるがまま以下を設定する。

```
INSTALL4J_JAVA_HOME="/opt/jdk-11.0.14.1+1/";export INSTALL4J_JAVA_HOME
```

最後のスラッシュを忘れると動かないので注意。

# VNC Viewerで繋いでいよいよJProfilerをインストールする
```hostname:5901```でつなぐ。

```
./jprofiler_aix_13_0.sh
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117698/834d78f7-2c83-5518-2687-c0d24de42de1.png)

起動した！

# 試用ライセンスはインストーラの指示通りにする
ネットに繋がってるクライアント側でメールで貰って、頑張って手打ち。
（VNCのクリップボード共有をちゃんとやれば楽）

![2022-03-02-23-25-30.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117698/02c297c4-f007-2917-a9e5-7cfd7a30f9fb.gif)

やったぜ！

# 外部に繋がってないAIXってなんだよ
この記事誰得だよって思いましたか？

俺もちょっと思う。でもレアな環境ってあるじゃないですか、とか言ってみたりして。

# 以下参考にさせて頂きました

https://qiita.com/testnin2/items/f84f33eb42c445761f42
文字列をInt型に変換するPythonプログラムを作成しました

## 概要

データ分析・予測において、文字列をInt型に変換して、データ可視化判斷からの分類・予測等に使用できればと、、、、

### 実行環境

macOS Monterey 12.1 
python 3.8.12

### 実行プログラム

```python:StringToInteger.py
import argparse

# 文字列をint型に変換
def str_to_int(s):   
    strint = int((s.encode('utf-8')).hex(), 16)
    print("\t str_to_int : {0}".format(strint))
    # print(type(strint))


# メイン
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='引数の文字列を Hex型 と Int型 に変換する')
    parser.add_argument('-s', '--str', type=str, required=True, help='文字列（例:メールアドレス）')
    args = parser.parse_args()

    print("\n 変換対象文字列 : {0}".format(args.str))
    str_to_int(args.str)
    print("")
```

### プログラムのHELP表示
 
```
$ python StringToInteger.py -h                
usage: StringToInt.py [-h] -s STR

引数の文字列を Hex型 と Int型 に変換する

optional arguments:
  -h, --help         show this help message and exit
  -s STR, --str STR  文字列（例:メールアドレス）
```

### プログラムの実行

```
## 文字列にメールアドレスを定義
$ python StringToInteger.py -s hoge@hoge.local

 変換対象文字列 : hoge@hoge.local
	 str_to_int : 542258412590216803575412933219541356


## 文字列に日本語を定義
$ python StringToInteger.py -s 山田太郎

 変換対象文字列 : 山田太郎
	 str_to_int : 71086887249939475064926339982
```

### まとめ

変換することにより、機械学習等で利用できないかと、、、、、厳しいですかね、、、、
区間dp

[問題](https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1611&lang=jp#)

徐々に探索幅を広げていく

( 端を取り除きdpに格納 + より広い区間でdpが最大値となる組み合わせ ) の繰り返し


```c++
//ボトムアップ(for文)
int dp[310][310]; //それぞれの区間の最大個数
int w[310];


int main() {

    int n; //個数
    cin >> n;

    rep(i, 0, n)rep(j, 0, n) dp[i][j] = 0;

    rep(i, 0, n) cin >> w[i]; //重さ


    for (int W = 1;W < n;W++) // 探索幅
    {
        //left
        for (int l = 0;l < n;l++) // 区切る位置
        {
            int r = l + W;
            if (r >= n) continue;

            //端を除いたすべてが取り除ける(必須) && 端が取り除ける
            if (dp[l + 1][r - 1] == W - 1 && abs(w[l] - w[r]) <= 1)
            {
                dp[l][r] = W + 1;
            }
            //探索幅におけるすべてのパターン
            for (int mid = l;mid <= r;mid++) // 探索幅を二等分した区間の和の最大値
            {
                dp[l][r] = max(dp[l][r], dp[l][mid] + dp[mid + 1][r]);
            }
        }
    }
    cout << dp[0][n - 1] << endl;
}

```

```c++
//再帰
int dp[310][310]; //それぞれの区間の最大個数
int w[310];

//区間 l ～ r で取り除ける数
int rec(int l, int r) {

    //既に計算済みか？(区間で分けた片方で使用)
    if (dp[l][r] != -1) return dp[l][r]; //メモ化再帰

    //これ以上取り除けない？(1つしかない場合)
    if (abs(l - r) == 0) return 0;

    int res = 0; //取り除ける数

    //端が取り除ける && 端を除いたすべてが取り除ける(必須) 
    if (abs(w[l] - w[r]) <= 1 && rec(l + 1, r - 1) == r - l - 1)
    {
        res = r - l + 1;
    }

    //探索幅におけるすべてのパターン
    for (int mid = l; mid < r; mid++)
    {
        res = max(res, rec(l, mid) + rec(mid + 1, r));
    }
    
    return dp[l][r] = res;
};


int main() {

    int n; //個数
    cin >> n;

    rep(i, 0, n)rep(j, 0, n) dp[i][j] = -1;

    rep(i, 0, n) cin >> w[i]; //重さ

    cout << rec(0, n - 1) << endl;
    
}
```
Pythonプログラムに パラメータとして日付を渡してみました

## 概要

データ分析において、データ抽出に日付を指定したくなります、、、、そんな理由でサクッと作ってみました。

### 実行環境

macOS Monterey 12.1 
python 3.8.12

### 実行プログラム

```python:DateParameter.py
import argparse
from datetime import datetime, timedelta
import pytz

# 日付の表示
def DisplayDate(start_date, end_date):  
    print("\n\t ##### From : {}  To : {} ##### \n".format(start_date, end_date))


# パラメータの文字列を日付型に変換 StartDate
# 指定した日付の 00:00:00 〜
def valid_date_s(s):
    try:
       strp_dt = datetime.strptime(s, "%Y-%m-%d")
       return strp_dt.astimezone(pytz.timezone('Asia/Tokyo'))
    except ValueError:
        msg = "Not a valid date: '{0}'.".format(s)
    raise argparse.ArgumentTypeError(msg)


# パラメータの文字列を日付型に変換 EndDate
# 指定した日付の 〜 23:59:59
def valid_date_e(s):
    try:
       dt = datetime.strptime(s, "%Y-%m-%d")
       strp_dt = dt + timedelta(days=1) - timedelta(seconds=1)
       return strp_dt.astimezone(pytz.timezone('Asia/Tokyo'))
    except ValueError:
        msg = "Not a valid date: '{0}'.".format(s)
    raise argparse.ArgumentTypeError(msg)


# メイン
if __name__ == '__main__':
    
    parser = argparse.ArgumentParser(description='パラメータとして日付を渡す')
    parser.add_argument('-s', '--startdate', type=valid_date_s, help='From日付 yyyy-mm-dd', required=True)
    parser.add_argument('-e', '--enddate', type=valid_date_e, help='To日付 yyyy-mm-dd', required=True)
    args = parser.parse_args()
 
    if args.startdate < args.enddate :
        DisplayDate(args.startdate, args.enddate)
    else :
        print("\t 日付範囲の指定が間違っています \n")
```

### プログラムのHELP表示
 
```
$ python DateParameter.py -h                         
usage: DateParameter.py [-h] -s STARTDATE -e ENDDATE

パラメータとして日付を渡す

optional arguments:
  -h, --help            show this help message and exit
  -s STARTDATE, --startdate STARTDATE
                        From日付 yyyy-mm-dd
  -e ENDDATE, --enddate ENDDATE
                        To日付 yyyy-mm-dd
```

### プログラムの実行（正常）
 
```
## From日付とTo日付を同日定義
$ python DateParameter.py -s 2022-02-16 -e 2022-02-16

	 ##### From : 2022-02-16 00:00:00+09:00  To : 2022-02-16 23:59:59+09:00 ##### 


## From日付とTo日付に異なる日付を定義
$ python DateParameter.py -s 2022-02-01 -e 2022-02-28

	 ##### From : 2022-02-01 00:00:00+09:00  To : 2022-02-28 23:59:59+09:00 ##### 
```

### プログラムの実行（異常）

```
## From日付のみ（To日付のみ）指定
$ python DateParameter.py -s 2022-02-01              
usage: DateParameter.py [-h] -s STARTDATE -e ENDDATE
DateParameter.py: error: the following arguments are required: -e/--enddate


## 間違った日付フォーマットで定義
$ python DateParameter.py -s 2022-02-01 -e 2022/02/28
usage: DateParameter.py [-h] -s STARTDATE -e ENDDATE
DateParameter.py: error: argument -e/--enddate: Not a valid date: '2022/02/28'.


## 存在しない日付を定義
$ python DateParameter.py -s 2022-02-01 -e 2022-02-30
usage: DateParameter.py [-h] -s STARTDATE -e ENDDATE
DateParameter.py: error: argument -e/--enddate: Not a valid date: '2022-02-30'.


## From日付よりTo日付が過去として定義
$ python DateParameter.py -s 2022-02-01 -e 2022-01-20
	 日付範囲の指定が間違っています 
```

### まとめ

AzureのActivityログ等を日付範囲指定して引っこ抜けそうです、、、、、、
Go の API をフロントサイドから呼び出す

API 側に
```go
http.Handle("/", http.FileServer(http.Dir("static")))
```
"static" フォルダに html などを入れる。

## 詳しく
main.go に
```go
http.Handle("/", http.FileServer(http.Dir("static")))
log.Fatal(http.ListenAndServe(":8080", nil))
```
と書いた場合。(main.go があるフォルダ)/static に index.html を入れる。
```
go run main.go
```
などで実行すると、localhost:8080/ で index.html が表示される。
localhost:8080/test.html とかで static/test.html が表示される。

"static" フォルダは別フォルダにしても動く。"../test" とかでも問題ない。
"/" を "/top" にして localhost:8080/top にアクセスすると not found になったので、"/" は変えられなさそう。


## 題名と書いてること違うじゃないのか？
はい、そう思います。
ただ、自分は上記のことがしたかったものの、フロントサイドを別 port で立てて cors を設定し、、、などをやっていて、かなり詰まりました。そういう人の検索に引っかかりやすい題名にしたつもりです。
UE4 ネットワーク時のログとRoleについて


自分用に整理

* Repricatedがtrueになっている場合

https://docs.unrealengine.com/4.27/ja/InteractiveExperiences/Networking/Actors/Roles/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249684/2989d102-ca42-f5ae-fc0c-47e5b68fbb36.png)


```
LogBlueprintUserMessages: [BP_Item_2] Server: Role Local=ROLE Authority ,Remote=ROLE Simulated Proxy
LogBlueprintUserMessages: [BP_Item_2] Client 1: Role Local=ROLE Simulated Proxy ,Remote=ROLE Authority
LogBlueprintUserMessages: [BP_Item_2] Client 2: Role Local=ROLE Simulated Proxy ,Remote=ROLE Authority


LogBlueprintUserMessages: [FirstPersonCharacter_C_0] Server  : Role Local=ROLE Authority        ,Remote=ROLE Simulated Proxy
LogBlueprintUserMessages: [FirstPersonCharacter_C_0] Client 1: Role Local=ROLE Autonomous Proxy ,Remote=ROLE Authority
LogBlueprintUserMessages: [FirstPersonCharacter_C_1] Client 1: Role Local=ROLE Simulated Proxy  ,Remote=ROLE Authority


LogBlueprintUserMessages: [FirstPersonCharacter_C_1] Server  : Role Local=ROLE Authority        ,Remote=ROLE Simulated Proxy
LogBlueprintUserMessages: [FirstPersonCharacter_C_0] Client 2: Role Local=ROLE Autonomous Proxy ,Remote=ROLE Authority
LogBlueprintUserMessages: [FirstPersonCharacter_C_1] Client 2: Role Local=ROLE Simulated Proxy  ,Remote=ROLE Authority
```

# ログとRoleについて

[BP_Item_2] Server: Role Local=ROLE Authority ,Remote=ROLE Simulated Proxy

## ログの見方

* [BP_Item_2]
  * ログを出しているActorの名前
* Server
  * 実行しているプログラム

## Roleについて

 * Role Local
   * 実行しているプログラム自身のRole
 * Remote
   * 通信している相手のRole

# Itemなどのオブジェクト
```
LogBlueprintUserMessages: [BP_Item_2] Server: Role Local=ROLE Authority ,Remote=ROLE Simulated Proxy
LogBlueprintUserMessages: [BP_Item_2] Client 1: Role Local=ROLE Simulated Proxy ,Remote=ROLE Authority
LogBlueprintUserMessages: [BP_Item_2] Client 2: Role Local=ROLE Simulated Proxy ,Remote=ROLE Authority
```
* ServerがROLE Authority
* ClientはROLE Simulated Proxy


# プレイヤー
```
LogBlueprintUserMessages: [FirstPersonCharacter_C_0] Server  : Role Local=ROLE Authority        ,Remote=ROLE Simulated Proxy
LogBlueprintUserMessages: [FirstPersonCharacter_C_0] Client 1: Role Local=ROLE Autonomous Proxy ,Remote=ROLE Authority
LogBlueprintUserMessages: [FirstPersonCharacter_C_1] Client 1: Role Local=ROLE Simulated Proxy  ,Remote=ROLE Authority


LogBlueprintUserMessages: [FirstPersonCharacter_C_1] Server  : Role Local=ROLE Authority        ,Remote=ROLE Simulated Proxy
LogBlueprintUserMessages: [FirstPersonCharacter_C_0] Client 2: Role Local=ROLE Autonomous Proxy ,Remote=ROLE Authority
LogBlueprintUserMessages: [FirstPersonCharacter_C_1] Client 2: Role Local=ROLE Simulated Proxy  ,Remote=ROLE Authority
```
* ServerはROLE Authority
* 自分はROLE Autonomous Proxy
  * Client 1のFirstPersonCharacter_C_0　は　ROLE Autonomous Proxy
    * Client 1のFirstPersonCharacter_C_1 は ROLE Simulated Proxy (Client 2のFirstPersonCharacter_C_0)
  * Client 2のFirstPersonCharacter_C_0 は ROLE Autonomous Proxy
    *  Client 2のFirstPersonCharacter_C_1 は ROLE Simulated Proxy (Client 1のFirstPersonCharacter_C_0)
【Rails】references型

# references型って？
自動的にインデックスと外部キー参照付きのカラムが追加され既存のモデルと生成したモデルを関連付けする下準備をしてくれる。
つまり、既存のテーブルを参照して必要なカラムを自動的に追加して新しいテーブルを作成すること。
*すべてのデータベースで使えるわけではない。

#### 例）

Micropostモデルを作成

```
# userテーブルに紐付けて、Micropostテーブルを作成
$ rails generate model Micropost content:text user:references
```

自動生成されたMicropostモデル

```rb:micropost.rb
class Micropost < ApplicationRecord
   # belongs_toメソッドでuserモデルに紐付いている(自動的に記述してくれてある)
   belongs_to :user
end
```
Micropostのマイグレーション
```rb:[timestamp]_create_microposts.rb
class CreateMicroposts < ActiveRecord::Migration[6.0]
  def change
    create_table :microposts do |t|
      # contentというstringカラム
      t.text :content
      # user参照で外部キー有効
      t.references :user, foreign_key: true
      # imestampsカラム（created_at, update_at）
      t.timestamps
    end
    # user_idとcreated_atカラムにインデックス付与のため記述
    add_index :microposts, [:user_id, :created_at]
  end
end
```
user_idに関連付けられたすべてのマイクロポストを作成時刻の逆順で取り出しやすくなる。
下記のように配列を書くことによってActive Recordが、両方のキーを同時に扱う複合キーインデックスを作成する。


```
add_index :microposts, [:user_id, :created_at]
```
UserモデルにMicropostモデルを紐付ける

```rb:user.rb
class User < ApplicationRecord
  # has_manyメソッドでmicropostsモデルに紐付いている（自動で追加されないので手動で追加）
  has_many :microposts
  .
  .
end
```
Windows11 のコンテキストメニューを Windows10 以前のものに戻す

Windows11 になってから, 右クリックをしたときに表示されるコンテキストメニューが簡素になり, Windows10 以前で利用していた詳細なメニューは「その他のオプションを表示」にまとめられてしまった.

![2022-03-02_23-28-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122814/e4057c56-3205-502a-9617-0eb379fd09d9.png)

そこで, レジストリを変更して Windows10 以前の使い慣れたコンテキストメニューに戻す手順をメモ.

なお, レジストリエディタを操作して変更する方法と, reg コマンドを入力して変更をする2通りがあるので, どちらか好みの方法でよい.

**レジストリの変更は自己責任**

## 方法1: レジストリエディタで変更

1. `regedit` を起動.
1. `HKEY_CURRENT_USER\Software\Classes\CLSID` に移動する.
1. `CLSID` を右クリック -> 新規 -> キー から, `{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}` というキーを作成（波括弧も含む）.
1. さらに、その作成したキーを右クリック -> 新規 -> キー から, `InprocServer32` というキーを作成.
1. `InprocServer32` 内の「(既定)」をダブルクリックして, 「値のデータ」には**何も入力せず** OK.
（元々データに「(値の設定なし)」と書かれていたのが, 空白になるはず.）

変更後はこのような階層・データになっていれば正しい.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122814/c78fdd6a-afb7-4511-2ded-a3ee0f49f904.png)

レジストリエディタを終了し, コンピュータを再起動, またはタスクマネージャからエクスプローラを再起動することで, 変更が適用される.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122814/ae206e8e-8867-fd51-5225-512c2bd4d325.png)

## 方法2: reg コマンドで変更

1. **管理者権限で** コマンドプロンプトを起動.
1. 以下のコマンドを実行
`reg.exe add “HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32” /f`

一応このコマンドの意味を解説しておくと, `add` はレジストリの追加なので, `HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32` のレジストリを追加する.
`/f` は force の意味で, 確認を求めずに実行する. **`/f` オプションはなくてもよい** が, すでに同じ名前のレジストリが存在する場合に, 上書きするかどうか尋ねられる.

参考: https://docs.microsoft.com/ja-jp/windows-server/administration/windows-commands/reg-add

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122814/08e23b0c-a9b6-7aee-cc2f-38d4aba6b9aa.png)

「**この操作を正しく終了しました。**」と表示されれば成功.

コンピュータを再起動, またはタスクマネージャからエクスプローラを再起動することで, 変更が適用される.

## 変更を元に戻す方法

何かしらの事情で Windows11 標準のコンテキストメニューに戻したい場合は, 以上の手順で作成したレジストリを削除することで戻すことができる.

または, 以下のコマンドを実行することでも, 該当のレジストリを削除することができる.
`reg.exe delete “HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}” /f`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122814/db58822d-f22a-8584-38c7-abb0999bbf2b.png)

以上.
すぐ使えるjsメモ


業務で必要となることが割とあるけど、コードを組むまでもない計算や変換のjsのメモとなります。
ブラウザのデベロッパーツールを起動してjsを実行するだけで結果がわかるので重宝してます。
## 現在時刻のUNIXタイム（ミリ秒）出力
```js
Date.now(); // 1646227190720
```
```js
new Date().getTime(); // 1646227352970
```

## UNIXタイム（ミリ秒）から現在時刻へ
```js
new Date(1646227190720).toLocaleString('ja-JP'); // '2022/3/2 22:19:50'
```

## 文字列をURLエンコード
```js
encodeURI('カステラ'); // '%E3%82%AB%E3%82%B9%E3%83%86%E3%83%A9'
```

## URLエンコード文字列のデコード
```js
decodeURI('%E3%82%AB%E3%82%B9%E3%83%86%E3%83%A9'); // 'カステラ'
```

## JSON整形
```js
var input = {"name":"カステラ","size":123,"item":[{"name":"梅","type":"small","price":100},{"name":"竹","type":"medium","price":500},{"name":"梅","type":"large","price":1000}]};
console.log(JSON.stringify(input, null, 4)); // 第三引数はインデント長
console.log(JSON.stringify(input, null, '\t')); // tabインデント
```

## Base64エンコード
```js
btoa(encodeURIComponent('taro:password01')); // 'dGFybyUzQXBhc3N3b3JkMDE='
```

## Base64エンコード文字列のデコード
```js
decodeURIComponent(atob('dGFybyUzQXBhc3N3b3JkMDE=')); // 'taro:password01'
```

## 数値3桁カンマ区切り
```js
(12345556789).toLocaleString(); // '12,345,556,789'
```

## 先頭0埋め
```js
'123'.padStart(10, '0'); // 0000000123
```
```js
('0000000000' + 123).slice(-10); // 0000000123
```
Poderosaで複数プロファイルを用意し、見分けやすくする


Poderosa使う際に、複数ターミナルを開いて、それぞれプロファイル（背景色など）を変えたい　というケースがあります。
※例えば、「ローカル環境と思って操作していたら本番サーバで、あぼした」とかの対策として。

### やり方

1.Poderosaプロファイル情報を用意

デフォルトのをコピーするなりして、作る

- デフォルト:  `%AppData%\poderosa`
- 別環境用:  `%AppData%\poderosa\production`

2.別環境用ショートカットを用意

従来のPoderosaショートカットではデフォルトが起動するので、別環境用ショートカットをこんな感じで新たに作成する：

```shell
C:\path_to_poderosa\poderosa.exe --profile %AppData%Poderosa\production
```

新たに作ったプロファイルの設定は、↑で起動したPoderosaの画面からやると、やりやすいです。

ドキュメントでなく、GitHub上のコードから確認できました。

https://github.com/poderosaproject/poderosa/blob/master/Plugin/PoderosaStartup.cs

### 参考

https://qiita.com/hanamiche/items/c1fc39442d8ab823482b

:::note
 記事の内容はあくまで個人の考えに基づくものであり、組織を代表するものではありません。
:::
ハッシュ値を圧縮すればもっと短くできる？→長くなった

# 時間がない方に向けて結論
ハッシュ文字列をzip圧縮すると、長くなります。
SHA256の場合：元256bit＝64文字＝32byte　→　137byte（428%増）
SHA3_512の場合：元512bit＝128文字＝64byte　→　169byte（264%増）

当たり前だろという声も聞こえる気がします。
恥を忍んでソースはこちら
https://github.com/yo16/compress_str


# はじめに思ったこと
ハッシュ化して256bitなり512bitなりになった後の16進数の文字列を見ると、異常に長く感じますよね？長いですわ。例えばSHA256でも```661b976821ad4a7545054a2e45367e3af53522477d39b28fdca26b36fed95f8b1a2005e3188b682a74f9e772aa3cb7201fcb6d01ce6cb2cdf720690fd26d5bb1e```になって64文字。512だと倍。これをDBへ格納して、なんなら表示したりとか気が知れない。

だけどそもそも16進数、つまり読み直せば2進数、バイナリですよね。上のも、```011110000101001010111000010101011....(さすがに略.16進数の4倍```みたいに0/1の値。こうやって表現すると、これってコンピューターの中のバイナリファイルだなーと思いました。

そしたらそのバイナリファイルを圧縮すれば小さくなるんだから、圧縮結果をもう一度2進数にして、16進数にすれば、短い文字列ができるんじゃないか・・・？

# 実験
## 1. 文字列をハッシュ化する関数
記事の本筋ではないので超絶割愛。知りたければ[GitHubのソース](https://github.com/yo16/compress_str)を見てください。
```python: hashing.py
# キモのところ
import hashlib
h = hashlib.sha256(s).hexdigest()
```

## 2. zip圧縮
ハッシュ化した文字列をバイナリ化して、zip化して、文字列化(16進数)する。
難しいことはないのだけれど、普段、バイナリの操作はあまりやらないので試行錯誤。
```python:compress_str.py
def do_compress(str_hex:str)->str:
    """文字列の16進数をバイナリ値にそのまま変換し、zip圧縮して返す

    Args:
        str_hex (str): 16進数の文字列(先頭にbはない)

    Returns:
        str: zip圧縮したバイナリ値を16進数にした文字列
    """
    # 16進数文字列をそのままバイナリ化
    b = bytes.fromhex(str_hex)
    
    # バイナリをzip化
    zip_stream = io.BytesIO()
    with zipfile.ZipFile(zip_stream, 'w', compression=zipfile.ZIP_DEFLATED) as new_zip:
        new_zip.writestr('_', b)
    
    # zipしたバイナリ値をそのまま取得
    h = zip_stream.getvalue()

    # 16進数にして返す
    return h.hex()
```

## 3. 評価
実行するところとその結果。
```python: compress_str.pyのメイン
test_str = 'test123'
#ret = do_hashing(test_str, ret_type='Hex', hash_method='SHA256')
ret = do_hashing(test_str, ret_type='Hex', hash_method='SHA3_512')
print(ret)
print(f'{len(ret)/2} bytes')        # 16進数1文字=4bit=0.5byte
# >>> 64.0 bytes

ret2 = do_compress(ret)
print(ret2)
print(f'{len(ret2)/2} bytes')
# >>> 169.0 bytes
```
最初に書いた通り、
- SHA256の場合
  - 元256bit ＝ 64文字 ＝ 32byte
  - → Zip →　137byte（428%増）
- SHA3_512の場合
  - 元512bit ＝ 128文字 ＝ 64byte
  - → Zip →　169byte（264%増）

ZIP圧縮方法変更してもっと圧縮するとかは、もうそういうレベルではないのでやってません。

# あとがき
残念でしたが、思いついたことがダメだとすぐ判明してスッキリしました。コーディングできる人でよかった。（間違ってなければ）
【R】正規表現を使って文字列を取り出す

```R
library(tidyverse)
library(magrittr)
df1 <- data.frame(x1=c("a(12),b(30),c(0)", "b(6),c(9)"))
```


x1カラムからbの直後の()内の数字を取り出してみます。

```R
df1 %<>% mutate(y1=str_extract(x1, "(?<=b\\()\\d+"))
```

`"(?<=b\\()\\d+"`は正規表現で、`(?<=b\\()`が肯定後読みで`b(`を探してその直後にアンカーを置きます。カッコは正規表現でグループ化を意味しますので、文字とて認識させるのにはバックスラッシュの後に書きます。(Rの正規表現では`\\`と2つ重ねる必要があります)
その後の`\\d+`は1文字以上連続している数字を取り出すことを意味します。
もう少し複雑な場合で、カッコの中に数字以外の文字を含む場合です。

```R
df2 <- data.frame(x2=c("a(12),b(30A),c(0)", "b(6B),c(9)"))
df2 %<>% mutate(y2=str_extract(x2, "(?<=b\\().+?(?=\\))"))
```

少し複雑ですが、`(?=\\()`が肯定先読みです。
`.+?`は1文字以上の文字列で、肯定先読みで表される次の`)`の前までを読みます。
カッコの中は英数文字に限られる場合には、`"(?<=b\\()\\w+)"`とすることもできます。

```R
df3 <- data.frame(x3=c("a(12),b1(30A),c(0)", "b12(6B),c(9)"))
df3 %<>% mutate(y3=str_extract(x3, "(?<=b.{0,2}?\\().+?(?=\\))"))
```

今度はbのあとにいくつかの文字が入っている場合です。
`(?<=b.{0,2}?\\()`でbの後の左カッコまでの0から2文字を読み飛ばしています。
Rで正規表現で後読みの中では、`{}`の中で文字数の範囲を指定する必要があります。
繰り返しを表す`{0,2}`や`+`などの後の　`?`は最小量指定子です。

正規表現については、他の言語で分かりやすいサイトが多くありますので、そちらを参考にしてください。ただし、バックスラッシュを2つ連続して入れる必要があることと、後読みの中では繰り返し記号`+`や`*`を使うことができないので、`{0,2}`のように範囲してください。
【論文読み】要約者の意図を組み込みやすい文書要約

## はじめに

こんにちは。論文を読んだ結果の紹介記事です。  
今回紹介するのは、「MMRによる文選択とTF-IDFによる文圧縮を用いたニュース記事要約」という論文です。  

- タイトル：MMRによる文選択とTF-IDFによる文圧縮を用いたニュース記事要約
- 出典：石原祥太郎, et al.; 人工知能学会, 2021  
- URL：https://www.jstage.jst.go.jp/article/pjsai/JSAI2021/0/JSAI2021_1D2OS3a03/_pdf/-char/ja  


## 概要
70記事を3行にまとめ、210文中56分文が同一が、編集者の要約と内容が一致した。
MMRによる文選択とTF-IDFによる文圧縮を用いた手法による編集者の負担低減、文圧縮の際に重みづけすることによる編集者の意図の組み込み、について検討した。

## 技術的特徴
- 文抽出の際にMMRを利用。文と記事全体の類似度 - 文同士の類似度。コサイン類似度を採用。
- 文の圧縮には、文の係り受け解析を行い、部分木を列挙。望ましい文字数範囲の文を列挙。
- 圧縮文の選択はTF-IDFで重要度を算出。各文に登場する単語のTF-IDFの値を足し合わせ、文の重要度とした。


## 想定される適用例
- 文章を要約するタスク全般
AWS SAAを1ヶ月半で2回不合格となり、3回目で合格したお話 (2022年2月)

## はじめに
AWS SAAを先日取得しましたので、勉強方法などをこの記事にまとめておきます。
これから受験する方などのお役に立てましたら幸いです。

### 前提
- 普段はWebアプリケーションの開発やマネジメントをしている。
- インフラ構築の経験はなし。
- エンジニアになってから1年半くらい。
- CLFは持っていない。基本情報とかも持っていない。
- ネットワークやセキュリティーなどに関してもそこまで詳しいわけではない。
- 体育会系、たぶん

## 勉強時間
ちなみに合格するまでに2回ほど不合格となりました。
不合格となると2週間後でなければ試験予約ができないため、不合格となった時点ですぐに2週間後の試験に予約してました。
多分、これは結構重要です。不合格となったらすぐに次の受験を申し込みましょう。
不合格となったからといって「もう少しじっくり勉強しよう」と次の受験を申し込まずにいると色々もったいないです。

|1回目  |2回目  |3回目  |
|---|---|---|
| 709 | 689  | 760  |

このような点数の推移でした。

## そもそもAWS SAAとは
AWSのサービスを使った可用性が高く、高パフォーマンスで、コスト効率が高いアーキテクチャの設計が主な試験の内容となっています。
ユースケースに応じて、どのAWSサービスを使用すればいいか最適な設計方法が問われます。
また、セキュリティが高いアプリケーションの設計方法も出題されます。
多くのAWSのサービスがあるので、出題範囲はかなり広く感じましたが、まぁしっりと対策をすれば誰でも合格することができると思います。

https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/

## 1回目の受験対策
### 使用した教材
https://www.udemy.com/share/101rfM3@VnRe9xITREEIt7eG4Uva4BY7-bkZ1KhILVyUGvvOozzbVCL2cJ5w4zEmWeThalvQkg==/

この教材を使用しました。
**AWS SAA対策**こんな感じでググってみると「Udemyの模擬試験問題で90%以上取れていれば合格できる！」みたいな記事がたくさんありました。
この言葉を信じて6回ある全ての模擬試験を90%以上取得したうえで試験に挑みましたが、結果は**709点**でした。

正直なところ、**Udemy模擬試験**だけでは厳しいと思います。

すでに業務でAWSを触っている、もしくはオンプレなどでインフラに触れる機会がある方はこれで問題ないかもしれないですが、
僕と同じように業務でインフラに触る機会のない方、エンジニアとしての経験もそこまで長くない方は正直この問題集を繰り返し解くみたいな勉強法では合格するのはギャンブルみたいなものになってしまうと思いました。

Udemyで解いていた問題は1つも出題されなかったと思います。


## 2回目の受験対策
### 使用した教材
2回目の受験では、**Udemyだけでは無理だ**判断したので、他の教材を購入してみることにしました。
そこで購入したのが、、、

[Cloud Tech](https://kws-cloud-tech.com/ "CloudTech")


こちらでした。購入というか入会ですね。
AWSで有名なくろかわさんのオンラインスクールに入会しました。

ここに有料会員として入会し、AWS SAA試験対策問題を解きまくりました。
10問ずつのクイズ形式をなっており、当時存在していた問題は全て3回以上正解できるように勉強を進めていきました。
そして、最後に模擬試験を受験し、合格となり本番にのぞみましたが、結果は**689点**でした。

1回目より点数が下がっている、、、、。

## 3回目の受験対策
### 使用した教材
[Amazon Web Services WEB問題集で学習しよう ](https://aws.koiwaclub.com/ "koiwa")
このkoiwa問題集と呼ばれているもので学習をしました。
この問題集が一番**本番の試験に近い形式での出題**がされていました。


そして、合格することができました。
![スクリーンショット_2022-03-08_14_49_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628093/cec9fd02-6cd0-48f7-bf48-8736f66ba031.png)




## 1回目、２回目の受験までの勉強で何がいけなかったのか
### 1 教材の選択
Udemy,CloudTechとどちらもかなり優良なコンテンツだと思います。たくさんの方に愛されているのも事実だと思います。
ただ、僕が実際使用してみた感想として3回目の受験前に取り組んだ

[Amazon Web Services WEB問題集で学習しよう ](https://aws.koiwaclub.com/ "koiwa")

 この問題集が一番価値があったと思います。

実際に、このkoiwa問題集で解いた問題が本試験でもいくつか出題されました。

### 2 パターンプラクティスという言葉を信じすぎた
よく「AWS SAAは問題のパターンを掴めれば誰でも受かる」なんてことが言われています。これは結構リスキーだと思いました。あと、運もあると思います。
確実にAWS SAAの試験で合格を掴みたければやはり理解学習をしていくことが必要だと思います。


## 試験後
3回目の受験で760点が取れ、なんとか合格することができました。
受験会場のPCで**合格**の文字を見た時は、重い何かを降ろした感覚でした。笑

それに2回不合格だったので、16500円×2で = 33000円無駄にしているわけですから。。。笑

受験料高すぎです。

### 勉強してよかったこと / 合格してよかったこと
- 毎月の給料に上乗せして資格手当がもらえる。
- AWSの基本的なサービス概要などを知れたため、ある程度AWSの話題が出ても理解できる。
- セキュリティーやネットワークの知識が少しだけついた。
- AWS SAAの認定バッチがもらえて、少しだけ自信がついたかもしれない。
- クラウドにさらに興味、関心が出た。

こんなところかなと思います。

![スクリーンショット 2022-03-10 9.25.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628093/e31b6243-20f4-5e9c-5fea-46252ee718e6.png)


## 今後
AWS SAAを取得して、なんとなくAWS・クラウドというものがどういうものか知ることができたので、
引き続き勉強を継続していきたいと思っています。

AWS認定11冠なんて人もいるとよく聞くので、11冠まではいかなくとも、

**AWSのことならだいたい知ってるんじゃん俺**

みたいなところまでは勉強をしていきたいと思いました。

思っていたより苦戦しましたが、取得してよかったです。