OmniAICreator/Qiita-1.07M huggingface dataset:
Java 初心者でもわかる関数型インタフェイス(Predicate編）

#はじめに
関数型インターフェースの１つPredicatetインターフェースをご存知でしょうか。
predicateインターフェースとラムダ式を組み合わせれば、複雑な条件をシンプルに実装できてしまいます。そんなPredicateインターフェースとおまけにBiPredicateインターフェースを解説していきます。
##Predicatetとは？
Predicateを日本語に訳すと「断定する」という意味になります。言葉の通り、引数を通して何らかの判断をする処理を定義するためのものです。例えば、戻り値がboolean型の処理をラムダ式で変数に代入して簡単に呼び出せるようにできます。Predicateはtestメソッドを持っています。そのメソッドは引数を１つ受け取り、その引数を使って、その結果をboolean型で戻します。サンプルコードを通して使い方を説明していきます。

##どうやって使うの？
サンプルコードでは理想の男性を絞るためにMainクラスでif文を使って絞り込んでいきます。

```Man.java
public class Man {
	private int hight;
	private int income;
	private String looks;
	private int age;

	public Man(int hight, int income, String looks, int age) {
		this.hight = hight;
		this.income = income;
		this.looks = looks;
		this.age = age;
	}
	public int getHight() {
		return hight;
	}
	public int getIncome() {
		return income;
	}
	public String getLooks() {
		return looks;
	}
	public int getAge() {
		return age;
	}
}
```
普通にif文を使用すると複雑な文になってしまいます。

```Main.java
Man man = new Man(170,900,"hot",20);
if(getHight > 170 && getIncome > 800||
   getLooks == hot && age <30){
}
```
それを解消するためにPredicateインターフェースを利用します。
下記のコードはPredicateオブジェクトを組み合わせた論理演算を実行しています。

```Main.java
import java.util.function.Predicate;

public class Main {
  public static void main (String[] args) {

	 Predicate<Man> isHight = m -> m.getHight() > 170;
	 Predicate<Man> isIncome = m -> m.getIncome()<1000;
	 Predicate<Man> isLooks = m -> m.getLooks()=="hot" ;
	 Predicate<Man> isAge = m ->m.getAge()<35;
	 Predicate<Man> type = isHight.and(isIncome).or(isLooks.and(isAge));
	 Man man = new Man(170,900,"hot",20);
	if(type.test(man)) {
		System.out.println("OK");
	}else {
		System.out.println("NG");
	}
  }
}
```
##BiPredicateとは？
Predicateは引数を１つ受け取るのに対してBiPredicateは２つの引数を受け取って何らかの判断をする処理を記述します。Predicateメソッドを同じくtestメソッドを持ちます。

##どのように使うの？
サンプルコードを通して説明していきます。
下記のコードはBiPredicateは２つのString型を受け取り、変数strがsuffixで終わっているかをendsWithを利用して判定しています。

```Sample.java
import java.util.function.BiPredicate;

public class Sample {
	public static void main(String[] args) {
		BiPredicate<String, String> b=
				(str, suffix) -> str.endsWith(suffix);
		System.out.println(b.test("sample.class", ".class"));
	}
}
```

##まとめ
Predicateは1つの引数を通して何らかの判断をする処理を定義するためのものです
BiPredicateは２つの引数を受け取って何らかの判断をする処理を記述します
SQL ServerでCountが遅い時の代替方法（Indexの件数を取得する方法）

- レコード件数が多すぎて、Countが遅いときに、Index件数で代替して速度向上

```sql:indexCount.sql
  SELECT
    i.name,
    i.rows
  FROM
    sysindexes as i
  INNER JOIN
    sysobjects o
    ON i.id = o.id
  WHERE
    o.xtype = 'U'
    AND i.name = N'PK名称'
```
Docker .envファイルを用いてポート情報を外出しする

# 概要

- .envファイルを用いてdocker-compose.ymlのポート番号等の情報を外出しする方法をまとめる。

# 完成したもの

- [https://github.com/miriwo0104/laravel9_test_docker/tree/env](https://github.com/miriwo0104/laravel9_test_docker/tree/env)

# 前提

- 今回、ポート番号を外出しするdocker-compose.ymlファイルは下記で作成した環境のものを使用する。
    - [Nginx PHP（laravel） MySQLのDocker環境を作る途中の話](https://qiita.com/miriwo/items/3cd5be10457b2abf0440)

# 方法

1. 下記コマンドを実行してdocker-compose.ymlファイルと同じ階層に.envファイルを作成して開く。

    ```terminal
    $ vi .env
    ```

1. 下記のように.envファイルを記載する。

    ```laravel9_test/docker/.env
    # local側 Nginxのポート
    NGINX_PORT=8000
    
    # local側 MySQLのポート
    MYSQL_PORT=4306
    ```

1. 下記のようにdocker-compose.ymlを編集して.envで定義した値を取得する

    ```laravel9_test/docker/docker-compose.yml
    version: '3'
    services:
      php:
        build: ./php
        volumes:
          - ../project:/var/www/html
    
      nginx:
        image: nginx:1.15.6
        ports:
          - ${NGINX_PORT}:80
        volumes:
          - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
          - ../project:/var/www/html
        depends_on:
          - php
    
      mysql:
        image: mysql:8.0
        ports:
          - ${MYSQL_PORT}:3306
        volumes:
          - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
          - ./mysql/initdb.d:/docker-entrypoint-initdb.d
          - ./mysql/db:/var/lib/mysql
        environment:
          MYSQL_ROOT_PASSWORD: root
          TZ: "Asia/Tokyo"
    ```

1. 当該のコンテナが起動している場合は停止する。
1. 当該のコンテナを削除する。
1. 下記コマンドを実行して設定を反映する。

    ```terminal
    $ docker-compose up -d --build
	$ docker-compose exec php composer install
	$ docker-compose exec php cp .env.example .env
	$ docker-compose exec php php artisan key:generate
	$ docker-compose exec php php artisan migrate
    ```

1. [http://localhost:8000/](http://localhost:8000/)にアクセスして下記の様な画面が表示されれば作業は完了となる。

    ![Laravel_🔊.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/95de6562-81e1-f0d0-47d2-b461be3cc675.png)

# 参考文献

- [https://matsuand.github.io/docs.docker.jp.onthefly/compose/environment-variables/](https://matsuand.github.io/docs.docker.jp.onthefly/compose/environment-variables/)
【Dart】json文字列とMapの変換

Dartでjson文字列とMapの相互変換処理です。

備忘録として残しておきます。

* Dart: 2.15

``` dart
import 'dart:convert' as convert;

void main() {
  final map1 = {
    "name": "hoge",
    "age": 20
  };
  
  // Map => json文字列
  final json = convert.json.encode(map1);
  print(json); // {"name":"hoge","age":20}

  // json文字列 => Map
  final map2 = convert.json.decode(json) as Map<String, dynamic>;
  print(map2); // {name: hoge, age: 20}
}

```
2022年に注目すべきオフショア開発動向

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512901/a44e6527-0c72-dbce-d1d7-62bc423f0bdf.png)

クラウドコンピューティングやAIは、2022年のトレンドの技術として、引き続き注目されるでしょう。あるの報告によると、クラウドコンピューティング市場規模は、2022年から2030年にかけて年平均成長率（CAGR）15.7％である一方で、世界のAIの市場規模は2021年から2026年にかけて年間成長率（CAGR）は39.7％です。

また、リモートワークを適用する企業がますます増加し、2022年までに世界の労働力の31％がリモートで働くことが予想されています。

上記は、2022年に起こるオフショア開発トレンドのうちの3つに過ぎません。

詳細については[読み続いてください](https://lotus-ts.com/jp/blogs/it-outsourcing-trends/?utm_source=Qiita&utm_medium=Share+Blog&utm_campaign=LTS)。

[第1 オフショア開発動向：新しいテクノロジー使用の増加](https://lotus-ts.com/jp/blogs/it-outsourcing-trends/?utm_source=Qiita&utm_medium=Share+Blog&utm_campaign=LTS)
[第2 オフショア開発動向：職場で何が起こっているのか](https://lotus-ts.com/jp/blogs/it-outsourcing-trends/?utm_source=Qiita&utm_medium=Share+Blog&utm_campaign=LTS)
[第3 オフショア開発動向：ソフトウェア開発手法のトレンド](https://lotus-ts.com/jp/blogs/it-outsourcing-trends/?utm_source=Qiita&utm_medium=Share+Blog&utm_campaign=LTS)
[第4 オフショア開発動向： IT採用におけるトレンド](https://lotus-ts.com/jp/blogs/it-outsourcing-trends/?utm_source=Qiita&utm_medium=Share+Blog&utm_campaign=LTS)

 

---------------------------

Lotus TSは、ソフトウェアテスト、ソフトウェア開発やAIデータ処理のITサービスを、高品質で確実なセキュリティシステムと熟練したスタッフとともに提供します。弊社のサービスに関する詳細についてはお気軽に[ご連絡ください](https://lotus-ts.com/jp/contact/)！

・Website: https://lotus-ts.com/jp
・Tel: (+84) 24-6660-7474
・Linkedin: https://www.linkedin.com/company/lotus-ts/
[JavaScript] 分割代入でリファクタリング

## 挨拶
Web系エンジニアへの就職に向け学習をしております、ひろやすと申します。
今回の記事は、JavaScriptの復習をしていて分割代入について知ったので、学習のアウトプットとして投稿しようと思いました。

## 分割代入とは...
**分割代入**とは、配列やオブジェクトのプロパティを別々に変数へ代入すること。

```javascript
//　配列
const array = [1, 2, 3];

const [num1, num2, num3] = array;

console.log(num1); // 1
console.log(num2); // 2
console.log(num3); // 3
```

```javascript
// オブジェクト
const object = { name: "たろう", email: "taro@gmail.com", age: 20 };

const { name, email, age } = object;

console.log(name); // たろう
console.log(email); // taro@gmail.com
console.log(age); // 20
```

## 分割代入を使ってリファクタリング

```javascript
// リファクタリング前
const array = { name: "たろう", email: "taro@gmail.com", age: 20 };

const ageMethod = () => {
  if (array.age >= 20) {
    console.log(`${array.name}は成人しています`);
  } else {
    console.log(`${array.name}はまだ成人していません`);
  }
};
```

```javascript
// リファクタリング後
const array = { name: "たろう", email: "taro@gmail.com", age: 20 };

const ageMethod = () => {
  const { name, age } = array; // 分割代入

  if (age >= 20) {
    console.log(`${name}は成人しています`);
  } else {
    console.log(`${name}はまだ成人していません`);
  }
};
```

参考になった方がいれば幸いです。
また、改善出来る部分などがあれば教えて頂きたいです。
最後までお読み頂きまして、ありがとうございました。
バッチファイルでプロンプト表示&ログ出力

- 思い出すのに苦労するのでメモ
- 標準出力&エラー出力をコマンドプロンプト&ログ出力する方法

## サンプル

```bat:hoge.bat
@ECHO OFF

REM カレントディレクトリへ移動
cd /d %~dp

REM コマンド実行
FOR /F "usebackq" %%i IN (`dir /b 2^>^&1`) DO (
    REM 遅延環境変数を避けるためにサブルーチンへ移動
    call :result %%i !ERRORLEVEL!
)

REM 終了
pause
exit /b o

REM プロンプト出力 & ファイル出力
:result
    echo 
    echo %~1 >> C:\hoge.txt
    
```
Netlify にデプロイする時、node.js のバージョンを指定する

Nuxt で作っていたWebサイトを久々に改修していて、yarn install 等をやり直して Netlify にデプロイした際、失敗した。
Netlify のログを見てみると、

```
error chalk@4.1.2: The engine "node" is incompatible with this module. Expected version ">=10".
error Found incompatible module
```

chalk@4.1.2というモジュールについて、node.js と互換性がないと言われていた。（[chalk](https://www.npmjs.com/package/chalk)は、ターミナルのスタイリングをしてくれるモジュールらしい。）

というわけで、node.js のバージョンを指定する。

プロジェクトのルートディレクトリに、以下のコマンドで、.nvmrcファイルを作成する。
.nvmrcファイルは、node.jsのバージョンのみが記載されており、このファイルを置いておくと Netlify が認識してくれる。

```shell
$ node -v > .nvmrc
```

再度デプロイし直し、無事に完了した。
M1 Macを買ったので設定備忘録


# まずはbrew
https://brew.sh/index_ja

```
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```


# brew管理のGitをinstall
```
$ brew install git
$ brew info git | grep stable
```

```~/.zshrc
PATH=/usr/local/bin/git:$PATH
export PATH
```

```
$ source ~/.zshrc
$ which git
 => /opt/homebrew/bin/git
```

# GitHubの設定
```
$ ssh-keygen -t rsa
$ pbcopy < ~/.ssh/id_rsa.pub
$ ssh -T git@github.com
```

# nodeのインストール
```
$ brew install nodenv
$ echo 'eval "$(nodenv init -)"' >> ~/.zshrc
```
```
$ curl -fsSL https://github.com/nodenv/nodenv-installer/raw/master/bin/nodenv-doctor | bash
Checking for `nodenv' in PATH: /opt/homebrew/bin/nodenv
Checking for nodenv shims in PATH: OK
Checking `nodenv install' support: /opt/homebrew/bin/nodenv-install (node-build 4.9.69)
Counting installed Node versions: none
  There aren't any Node versions installed under `/Users/tk/.nodenv/versions'.
  You can install Node versions like so: nodenv install 2.2.4
Auditing installed plugins: OK
```
```
$ nodenv install -l
$ nodenv install 16.14.0
$ nodenv global 16.14.0
$ node -v
```

# Goのインストール
```
$ brew install go
```

# Docker エラー発生したので以下のたいおう
```
$ docker --version
Docker version 20.10.12, build e91ed57
/usr/sbin/softwareupdate --install-rosetta --agree-to-license
```

# vim
```
$ vim .vimrc
```

# Ruby
TBD: Dockerで開発しているのでそのうち
日付・フッター・ページ番号を追加してMarpをさらに発表会資料っぽくしてみた

## Marp（Markdown Presentation）とは

Markdown記法でプレゼン資料をつくれる便利なツール。
特にVSCodeで用意されているExtensionを使えば、リアルタイムにプレビューを確認しながら作業可能。
お気に入りは、Latex（厳密にはKatex）文法で数式をさくっと載せられる◎

Marpの基礎的なところはこの記事がとても参考になりました。
https://qiita.com/tomo_makes/items/aafae4021986553ae1d8

## ちょっと困った
宗教上の理由で、プレゼンをつくるときは次の形式にしなければならない。

- ページの左下：『日付』
- ページの中央下：『発表会名』
- ページの右下：『ページ番号』（「現ページ番号/全ページ数」）

### 理想はこう
この後紹介するCSSで次のようになります。
![sample2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529987/dbe1435a-8cdd-362d-fbfe-b6fdd6eb7784.jpeg)

### デフォルトではこんな感じ
![sample.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529987/b72c9cd0-eb17-0dec-984d-96a4f853ce89.jpeg)
headerに日付、フッダーに発表名を入れてみました。

```md:sample.md
---
marp: true
theme: footer_temp
header: "サンプル発表会"
footer: "2022/02/16"
paginate: true
---

# サンプル
```

## CSSで頑張る

どうやら用意されている機能では実現できそうにないので、CSSで無理やり実現します。
長々と説明するほどのことでもないので、テーマCSSのfooter_temp.cssを先に紹介します。

```css:footer_temp.css
/* @theme footer_temp */
@import 'default';

section {
	position: relative;
}

/* ページ番号 */
section::after {
    content: attr(data-marpit-pagination)" / "attr(data-marpit-pagination-total);
    font-size: 80%;
}

/* 発表会名 */
header {
    width: 100%;
	position: absolute;
    top: unset;
    bottom: 21px;
    left: 0;
    text-align: center;
    font-size: 80%;
}

/* 日付 */
footer {
	text-align: center;
    font-size: 80%;
}
```

- 発表会名（header）はpositionで左下に移動
- フッターはtext-alignで中央寄せ
- ページ番号は、HTMLを解析してみるとsection要素に「data-marpit-pagination-total」というメタ属性が入っていたのでそれを拾って追加
良い開発組織では「予定より早く終わりそうです」を聞く。

エンジニアに見積もりを依頼した時。”バッファ”を適切に見込んでいる開発組織では、しばしば「予定より早く終わりそうです」という報告を開発チームから受けます。

★[第2回](https://qiita.com/satou_ot/items/c3ac2fdfc6c8c40423db)を投稿いたしました！

「”バッファ”とはなにか？」この質問は、ほとんどの開発組織でマネージャーや発注者から発せられています。
開発者は「”バッファ”とは”バッファ”です」と答えています（笑）
次に。「”バッファ”が必要な理由を説明しろ」とマネージャーや発注者は詰めます。
こうして”バッファ”は減らされていきます。
そして、見積を見直して大きく減らすことが出来たマネージャーや発注者は満足して引き上げます。

そして、3ヶ月後。マネージャーや発注者は「何故、プロジェクトが遅れているのか？」という議題に悩むことになります。
それは、**貴方自身が削った”バッファ”が原因**です。

「バッファがない見積」とは「全コースをミスもトラブルもなく。ベストラップで走り抜けられたら、このタイムでゴールします。」という、言わば理論上の世界レコードのようなものです。
バッファをゼロにしたプロジェクト計画とは貴方のプロジェクトメンバーが全員「ミハエル・シューマッハ」であることが前提なのです（苦笑）
勿論これは、わかりやすく極論化したものです。
ですが「ノーブレーキでアクセル踏みっぱなしなら1時間で着きます」という計画が無謀だということは誰にでもわかります。
”バッファ”をなくしたプロジェクト計画とは「理論上の最善値」で計画が組まれていることになります。

もし、貴社のITプロジェクトがいつも遅れ。いつも品質が課題になっているなら。
エンジニアや開発チームが盛り込んだ”バッファ”を信用してみるのはいかがですか？
きっと「予定より早く終わりそうです」という。いままでマネージャーや発注者が聞いたこともない。素晴らしいコメントを手に入れることができます。

**計画より早く終わることは間違いですか？**
いつも残業や休出で”巻き返し”を図るプロジェクトマネジメントは正しいと思っていますか？
ITプロジェクトが遅れるのは常識ですか？その結果、品質が課題になるのは開発チームの生産性問題ですか？

もし、貴方がマネージャーや発注者、組織管理者で「マネジメント」をする立場だとしたら。
思い出してみてください最期に「予定より早く終わりそうです」を聞いたのはいつだったか。

「システム開発のための見積りのすべてがわかる本」でも記述していますが。
”積み上げ方”で見積もる時、タスクごとにバッファを積むと、工数が1.5倍など”膨らむ”傾向があるのは事実です。
ですが、”バッファ”自体はテスト期間のように必要なコストです。

では”バッファ”とは結局なんでしょう？
・・・次回にさせていただきます＾＾

[第2回](https://qiita.com/satou_ot/items/c3ac2fdfc6c8c40423db)を投稿いたしました！
Google Maps APIで徒歩経路を取得についての備忘録


徒歩経路を取得するパラメータ。

`mode`を指定すれば徒歩経路が取得出来ました。


```js
const axios = require('axios');

const queryParams = {
  mode: 'walking',
  key: YOUR_API_KEY,
  origin: 出発地,
  destination: 到着地
};

const config = {
  method: 'get',
  url: `https://maps.googleapis.com/maps/api/directions/json?${queryParams}`,
};

axios(config)
.then(function (response) {
  console.log(JSON.stringify(response.data));
})
.catch(function (error) {
  console.log(error);
});
```
PostgreSQLで数値をlike検索する方法



「数値型のカラムから9で終わる値を検索したい」というときの方法です。
ちょっとしたことですが、覚えておくと便利です。

# 失敗事例
```sql
-- sint_colは「smallint」のカラムです。
select * from table_name where sint_col like '%9';
```

数値はlikeで検索できないので、上記のSQLを実行すると`operator does not exist: smallint ~~ unknown`のようなエラーになります。

# 数値をlike検索する方法
数値を文字列にキャストしてしまえば、likeで検索できます。

## 型キャストを使う
数値のカラムは`cast(数値のカラム as text)`のように書くと文字列にキャストできます。
`数値のカラム::text`という書き方もできます(意味は同じです)。

詳細 : [4.2. 評価式 - postgresql](https://www.postgresql.jp/document/13/html/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS)

```sql
select * from table_name where cast(sint_col as text) like '%9';
```

## 暗黙キャストを定義する
こちらの方法は、やっていませんが場合によっては有効かもしれません。
`CREATE CAST`で新しくキャストを定義できます。

詳細 : [CREATE CAST - postgresql](https://www.postgresql.jp/document/13/html/sql-createcast.html)

しかし、「多用しない方が賢明です。」と記載されていることから一時的に使いたいのであれば「型キャスト」のほうが良いかもしれません。

> 暗黙キャストは、多用しない方が賢明です。 暗黙的キャストを使用し過ぎると、PostgreSQLがコマンドを思わぬ意味に解釈してしまう原因になります。
> [CREATE CAST - postgresql](https://www.postgresql.jp/document/13/html/sql-createcast.html)
PHPのPDOをDockerコンテナ内で使おうとしたところ、"No such file or directory" エラーが発生した話

# はじめに

docker-composeでPHP用とDB用の2つのコンテナを立てて、PHPのPDOの挙動を確認したところ、 `SQLSTATE[HY000] [2002] No such file or directory` というエラーが発生してしまったので、その時の解消方法を備忘のために残しておこうと思います。

# リポジトリ
https://github.com/b-coffin/pdo-tutorial

# 結論
結論としては、新規PDOを作成する際のhost名を、**docker-compose.ymlで指定したservice名**にすればよかっただけでした。

```diff:src/index.php(一部)
-$pdo = new PDO('mysql:host=localhost;dbname=homestead;', 'root', 'secret');
+$pdo = new PDO('mysql:host=db;dbname=homestead;', 'root', 'secret');
```

# 解説
composeを起動すると、デフォルトで単一のネットワークが生成され、**各コンテナはdocker-compose.ymlで指定したservice名でそのネットワークに参加します**。
そのため、各コンテナから別のコンテナにアクセスする際は、ホスト名として**service名**を使用することができるようになります。

参考: [Compose のネットワーク機能 - Docker-docs-ja](https://docs.docker.jp/compose/networking.html)

# 参考
- [docker-composeでPHPとMySQLを連携させてみる - Qiita](https://qiita.com/ayuzaka/items/b56122e2ecd94022a7b6)
「ネストされた」リクエストに対するバリデーションlaravel8

# はじめに
laravelドキュメントのバリデーションについて読んでいて
>受信HTTPリクエストに「ネストされた」フィールドデータが含まれている場合、
>「ドット」構文を利用してバリデーションを指定できます。

とあり。
ネストされたHTTPリクエストがなんぞやとなったのでその記録。

# ネストしたリクエストを送信する
```html:index.html
<form>
  <input type="text" name="sample[][name]">
  <input type="text" name="sample[][email]">
  <input type="text" name="sample[][age]">
</form>
```
## リクエストの中身
```js:request
$sample = [
    ['name' => 'tarou', 'email' => 'tarou@test.com', 'age' => 22],
]
```

こんな感じでネスト（配列）にして飛ばすことができる。

# バリデーション
```php:SampleController.php

$request->validate([
  'sample.name' => ['required', 'max:20'],
  'sample.email' => ['required','unique:users'],
]);
```

# 環境
larave8

# 終わりに
「へー」という感じでした。
特に記事にする必要なかったですね、、
CloudFrontのBasic認証をTerraformで手っ取り早く設定したい

## 参考記事
関数の実装は以下を参考にさせていただきました。ありがとうございます。
https://dev.classmethod.jp/articles/apply-basic-authentication-password-with-cloudfront-functions/

## IDとPASSの生成

```
$ echo -n "id:pass" | base64
```

`aWQ6cGFzcw==`が生成されます。

## Terraform定義

CloudFront FunctionをTerraformで定義します。
関数の実装は、上述の記事を参考にさせていただきました。

```terraform
resource "aws_cloudfront_function" "basic_auth" {
  name    = "basic_auth"
  runtime = "cloudfront-js-1.0"
  comment = "Basic Auth"
  publish = true
  code    =  <<EOT
function handler(event) {
    var request = event.request;
    var headers = request.headers;
    var authString = "Basic aWQ6cGFzcw==";

    if (
        typeof headers.authorization === "undefined" ||
        headers.authorization.value !== authString
    ) {
        return {
            statusCode: 401,
            statusDescription: "Unauthorized",
            headers: { "www-authenticate": { value: "Basic" } }
        };
    }

    return request;
}
EOT
}
```

既存のCloudFrontの定義に追加します。

```terraform
resource "aws_cloudfront_distribution" "cloudfront" {
  enabled = true
  is_ipv6_enabled = true
  price_class = "PriceClass_All"
  http_version = "http2"

  default_root_object = "index.html"

  origin {
    domain_name = "${aws_s3_bucket.s3.bucket}.s3-website-ap-northeast-1.amazonaws.com"
    origin_id = "xxxxxxxxxx"

    custom_origin_config {
      http_port = 80
      https_port = 443
      origin_protocol_policy = "http-only"
      origin_ssl_protocols = [
        "TLSv1", "TLSv1.1", "TLSv1.2"
      ]
    }
  }

  default_cache_behavior {
    allowed_methods = ["GET", "HEAD", "OPTIONS"]
    cached_methods = ["GET", "HEAD"]
    target_origin_id = "xxxxxxxxxx"
    viewer_protocol_policy = "redirect-to-https"

    default_ttl = 0
    min_ttl = 0
    max_ttl = 0

    forwarded_values {
      query_string = true

      cookies {
        forward = "all"
      }

      headers = []
    }

    function_association {
      event_type = "viewer-request"
      function_arn = aws_cloudfront_function.basic_auth.arn
    }
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = false
    acm_certificate_arn = var.acm_edge_arn
    minimum_protocol_version = "TLSv1.1_2016"
    ssl_support_method = "sni-only"
  }
}
```

以下の部分に注目してください。

```terraform
function_association {
  event_type = "viewer-request"
  function_arn = aws_cloudfront_function.basic_auth.arn
}
```

以上
Redshiftに格納されている文字列データから特定の文字に囲まれた文字列を抜き出す方法

# はじめに
こんにちは、株式会社ジールの[@Suguru-Terouchi](https://qiita.com/Suguru-Terouchi)です。
今回はRedshiftに格納されている文字列データから特定の文字に囲まれた文字列を抜き出す方法について記載したいと思います。

# やりたきこと
「xxx-12345678-xxx」というようなデータがあった場合に「12345678」だけを抜き出したい。

Redshiftでは [POSITION関数](https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_POSITION.html) を使うことで文字列中にある任意の文字を検索して、その位置を取得することが出来ますが、
今回のデータの場合、１つ目の「-」の位置を検索してから [SUBSTRING関数](https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_SUBSTRING.html) を使って、
「xxx-12345678-xxx」から１つ目の「-」以降の文字列「12345678-xxx」を抜き出し、また「-」の位置を探して、、と煩雑になってしまい、
可読性、保守性にも残念なSQLを書くはめになってしまいます。

残念なSQLの例：

    select substring(substring('xxx-12345678-xxxx', position('-' in 'xxx-12345678-xxxx') + 1), 1, position('-' in substring('xxx-12345678-xxxx', position('-' in 'xxx-12345678-xxxx') + 1)) - 1)
はい、もう見る気なくしますね。。。
これを作るのに小一時間を無駄にしたくないアナタ（過去の自分）に良い方法を伝授したいと思います。

# 特定の文字に囲まれた文字列を抜き出す方法
前置きが長くなりましたが、早速、本題の方法について記載していきたいと思います。
今回はRedshiftで使用可能な文字列関数から [REGEXP_SUBSTR関数](https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/REGEXP_SUBSTR.html) で正規表現を使ってズバッと狙った文字列を抜き出してみせたいと思います。

    select regexp_substr('xxx-12345678-xxxx', '\-(.*)\-')
**実行結果**
-12345678-

うーん、、ちょっと違いますね、この辺で既に正規表現を使えない人間だとバレてしまっているかも知れませんが、
気を取り直して、再トライしてみます。

    select regexp_substr('xxx-12345678-xxxx', '\-(.*)\-', 1, 1, 'e')
**実行結果**
12345678

狙い通りの文字列を抜き出すことに成功しました。
正規表現パターンを表す文字列リテラルに（）がありますが、そこが上手く認識されていなかったようです。
今回のケースでは「e」というパラメータを引き渡してあげることで想定していた結果を得られました。

めでたしめでたしと行きたいところですが、
ヒゲを生やした~~意地悪な~~ 素晴らしい上司が「その方法で全てのデータパターン対応できているの？」と言ってきました。
「大丈夫ですよ！」と言いつつも不安を覚え、こっそりテストをしてみると案の定、対応しきれていないパターンがありました。

それは「xxx-12345678-0000-xxx」というようなデータがあった場合に上記のSQLでは「12345678-0000」という結果が返ってきてしまいました。
なにか対応策がないか試行錯誤しているうちに以下のSQLに辿り着きました。

    select regexp_substr('xxx-12345678-0000-xxxx', '\-(.*?)\-', 1, 1, 'ep')

正規表現の世界では「*」のあとに「?」を入れることで非貪欲なマッチングにすることが出来ることはすぐに分かったのですが、
１つ前のSQLに「?」を追加するとSQLでエラーが発生してしまい、失意のどん底に突き落とされてしまいました。

諦めずにもう一度、関数のマニュアルを眺めていると、パラメータの最後に「p」の説明を見つけ、
藁にも縋る思いでパラメータに追加したところ、無事に想定した結果を得ることが出来ました。

# 参考URL
https://atmarkit.itmedia.co.jp/ait/articles/2103/16/news025.html
http://taustation.com/python3-regex-greedy-and-non-greedy/
https://qiita.com/ren0826jam/items/896bd8b49d154808d61f

# まとめ
いかがでしたでしょうか。
最後のパラメータ「p」について説明をするスキルがなく、詳しい方コメントなど頂けると嬉しいです。

これまでも仕事で正規表現を使う機会は何度かありましたが、
毎回忘れてハマってしまうのでこの機会にTipsとして残せればと思い執筆に至りました。
（ただ正規表現とは今後も仲良くなれる自信はありません。。。）

ご参考になれば幸いです。

# データ活用をサクッと始めるなら！
株式会社ジールでは、「ITリテラシーがない」「初期費用がかけられない」「親切・丁寧な支援がほしい」「ノーコード・ローコードがよい」「運用・保守の手間をかけられない」などのお客様の声を受けて、オールインワン型データ活用プラットフォーム「ZEUSCloud」を月額利用料にてご提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
 
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_zeuscloud_content-area
composer updateで"package information was loaded from the local cache and may be out of date"

##状況

composer updateを実行した際に以下のエラーが発生

```
https://repo.packagist.org could not be fully loaded (curl error 7 while downloading https://repo.packagist.org/packages.json: Failed to connect to repo.packagist.org port 443: Connection refused), package information was loaded from the local cache and may be out of date
```
##解決方法
composer updateを実行する前に以下のコマンドを実行する

```
composer config -g repo.packagist composer https://packagist.org
```

##参考

[Composer: "Content-length mismatch" & "http://packagist.org could not be fully loaded..."](https://stackoverflow.com/questions/40309620/composer-content-length-mismatch-http-packagist-org-could-not-be-fully-l)
RHEL8でパスワード変更をフックする

RHEL8に限らずLinux一般で使えると思うが、RHEL8で出来るかを試したのでそのメモ。

Linuxにpam_scriptモジュールを導入して、OSユーザーのパスワード変更をHookしてみる。
パスワード変更がHook出来ると、独自のパスワードルールを作りこんだり、変更したパスワードを他システムと連携してパスワード管理を一元化できる。パスワード管理の一元化は、オンプレなら普通はLDAPでやると思うが、まあ、少し活用しそうな用途があったため。

# pam_scriptを導入する

RHELのバージョンは8.3。VMWare Workstationにminimalでインストールしたものを使用。RHELの導入手順は割愛。

EPELの以下のURLからpam_scriptを入手する。依存関係があまり複雑じゃないのでrpm単体をダウンロードして導入も苦ではない。

https://download-ib01.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/p/pam_script-1.1.9-7.el8.x86_64.rpm

rpmファイルをRHELに転送し、rpmコマンドでインストール。

```
# rpm -i pam_script-1.1.9-7.el8.x86_64.rpm
```


# PAMを設定する

pam_scriptの利用方法はGitHubの以下を参照。
https://github.com/jeroennijhof/pam_script

passwdコマンドのパスワード変更にpam_scriptが噛むよう、pamの設定ファイルを修正する。

```/etc/pam.d/passwd
#%PAM-1.0
# This tool only uses the password stack.
（↓↓↓ここに行を追加）
password   required     pam_script.so onerr=fail dir=/root/pam_script
（↑↑↑ここに行を追加）
password   substack     system-auth
-password   optional    pam_gnome_keyring.so use_authtok
password   substack     postlogin
```


# フック用のスクリプトを作る

まあ、用途の良し悪しは置いておいて、パスワード変更時に渡されたパスワードをファイルに記録するスクリプトで動作検証。
スクリプトのファイル名はpam_scriptで決められており、pam_script_passwd。

```bash:/root/pam_script/pam_script_passwd
#! /bin/bash
date >> /root/pam_script/passwd-hook.log
env >>  /root/pam_script/passwd-hook.log
```

ファイルの実行権を付ける。

```
# chmod a+x /root/pam_script/pam_script_passwd
```

まあ、selinuxが有効な場合は動作しないので、Permissiveに。

```
# setenforce 0
```


# 動作確認

テスト用のユーザーを作る。

```
# adduser test
```

テスト用ユーザーのパスワードを変更する。

```
# passwd test
```

パスワードを変更すると/root/pam_script/passwd-hook.logに変更したパスワードが記録される。envコマンドの出力結果をすべて出力しているが、必要な部分を抜粋すると以下のような感じ。
PAM_AUTHOKに変更したパスワードが、PAM_USERに変更したユーザー名が値として設定されている。

```/root/pam_script/passwd-hook.log
Wed Feb 16 15:08:07 JST 2022
...
PAM_TYPE=password
PAM_AUTHTOK=PasswordForTest
...
USER=root
PAM_USER=test
...
```


# ついでに

テスト用のユーザーtestに、設定したパスワード(PasswordForTest)でログインできるようになっているが、testユーザーは自分自身のパスワー変更時にエラーが出力されるようになる。

```
[test@r8 ~]$ passwd
Changing password for user test.
Current password:
New password:
New password (again):
/bin/bash: /root/pam_script/pam_script_passwd: Permission denied
Retype new password:
passwd: Authentication token manipulation error
[test@r8 ~]$
```

これは、testユーザーにpam_script_passwordのファイルアクセス権を追加するとか、今回の例でいえばpasswd-hook.logファイルにtestユーザーからの書き込み権を設定して、とかを調整すればパスワード変更できるようになるのだが、ちょっと今回はそこまで踏み込まない。

あとはまあ、パスワード変更のhookにpam_scriptを使うのは若干悪い点があり、今回は例としてパスワードをプレーンテキストでログファイルに記録しているというのはまあ置いておいて、pam_scriptではスクリプトおよびスクリプト内でコマンド実行する際にメモリに記録されたパスワード文字列をクリアする手段がない。OSのメモリダンプを取られたり、Meltdownのようなサイドチャネル攻撃に対して脆弱である。通常は心配しすぎの領域だと思うが、その場合はcでpamモジュールをメモリのクリアとかちゃんと意識して書くしか。pam_script自体の実装がそれなりに参考になると思うが。
Laravelのログイン機能でRegister（情報登録）ができない時の対処法

### 発生したエラー

``` php
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'mmictltd.admins' doesn't exist 
```
ブラウザ上で、上記エラーが発生してしまいました。
これは簡単にいうとテーブルがないよ。ということ。

### エラーまでの流れ
Laravelのログイン機能をインストールして、ログイン機能を表示するところまで
できたのですが、会員登録をしようとするとエラーが起きました。

認証機能をインストールすると、
>ユーザ登録のためのテーブルマイグレーションファイルは database/migrations/2014_10_12_000000_create_users_table.php と database/migrations/2014_10_12_100000_create_password_resets_table.php として標準で準備されている．

https://rinsaka.com/laravel/u03-auth.html

らしいのですが、自分は”2014_10_12_100000_create_password_resets_table.php”こちらしかインストールされていなかったです。

### どう対処したか
■結論
**テーブルを強引に作成した**

■なぜなら

https://teratail.com/questions/103158

>・DBにuserテーブルが存在しているか。
・appフォルダに「User.php」は存在するか。
・envファイルに正しくDBの情報を書き込んでいるか。

これらが原因らしく、そもそもuserテーブルが存在していなかったので、どうしても
テーブル問題を解決する必要があった。
migrationのミスなのかな、とも思ったが
migrate:rollbackしてから再度migrateしても結果は変わらなかったため強引に作ることにした。

### テーブルの作り方

https://readouble.com/laravel/8.x/ja/migrations.html

>php artisan make:migration create_flights_table

これをflightsを好きな名前にするだけ。今回はusersにする必要があったためそうした。

ちなみに、テーブル名は複数形で、モデルは単数じゃないとエラーが起きるぽいので注意してください！

Userテーブルが作れたら、本来記載されているはずのコードをコピペする。

https://rinsaka.com/laravel/u03-auth.html


``` php
<?php
 
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
 
class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
 
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}
```

### こうなりました
![スクリーンショット 2022-02-16 16.49.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2525372/d12af4ed-ab0f-69f5-d6c3-1c8c681b6208.png)
![スクリーンショット 2022-02-16 16.49.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2525372/38bb8d07-d28e-8803-7199-e9d5cc90cdc1.png)


エラー解決はやはり嬉しい！嬉しすぎて、温泉のセブンティーンアイスを買ってしまった。。
GitHub Actions で Unity ビルドを行う時に事前に設定した認証情報を利用する

# はじめに
Unity の UPM を利用する際にプロジェクトで GitHub Actions の自動化でプライベートリポジトリにあるパッケージを取得する方法です。

https://qiita.com/akiojin/items/fe34db784a79582cd4a1

で書いた内容を GitHub Actions のタスクに置き換えたものですので、認証情報を抑制する方法だけであれば上記を参照していただければ完結すると思います。

## GitHub Actions の設定
GitHub Actions 側では以下のように credeitial-manager-core を使用します。

事前に GitHub Actions のシークレットに設定しておきます。

- USERNAME: GitHub にアクセス権を持つユーザー名
- PASSWORD: 上記のユーザーのパスワードもしくはリポジトリにアクセスできる権限があるパーソナルアクセストークン

```yml
- name: Git credential
  run: |
    git credential-manager-core store << EOS
    protocol=https
    host=github.com
    username=$USERNAME
    password=$PASSWORD
    EOS
```

上記を Unity のインポート前に設定しておくことで Unity のパッケージマネージャーがリポジトリアクセス時に認証情報を git-credential-manager の情報を参照するようになります。

ただ、このままだと認証情報が残ったままですので最後に認証情報を削除する処理も入れておきます。

```yml
- name: Clean up Git credential
  if: ${{ always() }}
  run: |
    git credential-manager-core erase << EOS
    protocol=https
    host=github.com
    EOS
```

## エラー発生時
上記の `git credential-manager-core` で以下のようなエラーが出る場合は

```
fatal: Interaction with the Security Server is not allowed. [0xffff9d24]
```

こちらを参考にアクセス許可を付与してください。

https://stackoverflow.com/a/22637896/1730828

https://github.com/sparkle-project/Sparkle/issues/1323

もしくはキーチェインの設定が間違っている場合があります。
`git-credential-manger-core` は『[デフォルトのログインキーチェイン](https://github.com/GitCredentialManager/git-credential-manager/blob/main/docs/credstores.md#macos-keychain)』を使用します。

**そのため独自にキーチェインを使用する場合はデフォルトのキーチェインの変更が必要になります。**

```sh
security default-keychain <キーチェインパス>
```

https://github.com/GitCredentialManager/git-credential-manager/blob/main/docs/credstores.md#macos-keychain

## GitHub Actions 用のアクション

この辺りを設定するのが面倒だったりキーチェインの部分が色々と知識がないと出来なかったりするので設定用のアクションを作成しました。

https://github.com/marketplace/actions/store-github-credential

こんな感じで設定してもらうとこのアクション実行で `git-credential-manager-core` の設定を行い、最後にその設置を破棄する部分まで行います。

```yml
- uses: akiojin/store-git-credential-github-action@v1.1
  with:
    username: ${{ secrets.GIT_CREDENTIAL_USERNAME }}
    password: ${{ secrets.GIT_CREDENTIAL_REPOSITORY_PASSWORD }}
```

# さいごに
UPM を GitHub プライベートリポジトリで運用されている環境は意外と少ないかもしれませんが、社内ライブラリを GitHub　で運用されている方は結構この辺りでつまづくことがあるんじゃないかと思いますので、一度試していただければと思います。
Latitudeタッチパネル無効化

[タッチパネル無効化](https://www.dell.com/support/kbdoc/ja-jp/000124374/dell-%E3%83%8E%E3%83%BC%E3%83%88%E3%83%91%E3%82%BD%E3%82%B3%E3%83%B3-%E3%81%A7%E3%81%AE-%E3%82%BF%E3%83%83%E3%83%81%E3%83%91%E3%83%83%E3%83%89-%E3%81%AE-%E7%84%A1%E5%8A%B9%E5%8C%96-%E3%81%BE%E3%81%9F%E3%81%AF-%E6%9C%89%E5%8A%B9%E5%8C%96)
記載のように
「Windows（Windowsキー）キーを押したままqキーを押します。
検索ボックスに「Touchpad」と入力します。
［タッチパッド設定］（システム設定）をタッチまたはクリックします。
「Touchpad On/Off（タッチパッドオン/オフ）」トグルを探します。
［Touchpad On/Off］トグル オプションがある場合：
［Touchpad On/Off］トグルをタッチまたはクリックして、タッチパッドのオンとオフを切り替えます。

ってやりましたっ(*^^*)
【JavaScript】map()の使い方


#map()の使い方
``map()``は、配列すべての要素に対して、コールバック関数を実行してその返り値で新しい配列が生成される。``map()``の基本的な書き方は以下となる。

```javascript
// arrayは配列
array.map((value, index, array) => {
    //　処理内容
});
```
上記のようにコールバック関数は以下の3つの引数を取る。ただし、```index```と```array```については省略可能。
■ **value** : 配列の要素
■ **index** : 配列のインデックス
■ **array** : 処理対象の配列

``map()``を使って配列の要素を2乗するだけの簡単なサンプルが以下となる。

```javascript
const array = [1, 7, 12, 15];
const result = array.map((value) => {
	return value * value;
});

console.log(result);    // [ 1, 49, 144, 225 ]
```

# forEach()とmap()の違い
``forEach()``と``map()``の違いは、実行結果を新しい配列として返すかどうか。
``map()``は、コールバック関数の返り値で新しい配列が生成される一方で、``forEach()``は単純に処理を実行するだけで返り値がないため、``return``を記述しても``forEach()``の結果は``undefined``が返される。
MDN Web Docsには、``map()``を使用すべきではない場合として2点挙げられていた。(参考: [MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map))
● 返された配列を使用しない場合
● コールバックから値を返さない場合
【Laravel】 俺が書く検索機能のif文パラダイスはなんだったのか


検索機能を作る時によくこう書いていた。

```php:
$query = User::select();
if(!empty($request->input('name'))){
  $query->where('name',$request->input('name'));
}
$users = $query->get();
```
条件が増えるたびにif文が増えていきif文パラダイスが起きる。
そして最近知る事になるWhen、彼はif文パラダイスを解決してくれました。

<a href="https://readouble.com/laravel/8.x/ja/queries.html">公式ドキュメント</a>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282328/af1393ba-5197-a7a9-5e18-55471dc06266.png)

```php:
$users = User::when($request->input('name'), function ($query) use ($request) {
  return $query->where('name',$request->input('name'));
})->get();

```
if文を書かずに一本で書けます。
因みに第三引数にクロージャを書く事でelseの場合の処理も書けます

```php:
$users = User::when($request->input('name'), function ($query) use ($request) {
  return $query->where('name',$request->input('name'));
}, function ($query) {
  return $query->orderBy('created_at','desc');
})->get();

```

バージョンが5ぐらいの時からあるらしいんですが知りませんでした。


### 追記
php7.4以降はクロージャ省略して書いた方が見やすいです。

```php
User::when($request->input('name'), 
    fn($query) => $query->where('name',$request->input('name'),
    fn($query) => $query->orderBy('created_at','desc'))
```

### 追記2

コメントで指摘して頂きました。
if文の段階で代入した方が見やすいです。

```php
if($name = $request->input('name')){
  $query->where('name', $name);
}
```
【Unity】ラジオボタンの一つを常にオン表示 (ToggleGroup)

2022/02/24追記：
Toggleコンポーネントがアタッチされたオブジェクトの子に、トグルがオンの状態と同じ見た目・大きさの画像オブジェクトを追加して、そのオブジェクトをToggleコンポーネントのグラフィックスに設定すればいいことに気が付きました。コードを減らしたいならそっちの方が良さそう。

注意：Unity 2019.2.21 です。

**トグルグループ(ToggleGroup)で実装したトグルの、最後に押したトグルをずっとオンにしていたい。**
めちゃめちゃ悩んだのに、とても簡単に直せたので記事に残します。
Unity初心者なので公式の機能やもっといい方法があったら教えてください。

Unityでラジオボタン（一つだけオンになるボタン）を実装したいときは以下の記事に従えば実装できます。

https://qiita.com/daria_sieben/items/79481afdc0733bd3aeda

ただし、このままの実装では、トグル以外を押したときに全てのトグルがオフ状態になってしまいます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">成功例 <a href="https://t.co/YRtxIoQPru">pic.twitter.com/YRtxIoQPru</a></p>&mdash; のこ (@nokonoko312) <a href="https://twitter.com/nokonoko312/status/1493848682520727556?ref_src=twsrc%5Etfw">February 16, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ー
やることとしては、オンのときトグルを無効、オフのときトグルを有効にするだけです。
interactableをオフにしておけばトグルの色が無効の色に固定されます。
無効の色を押された色にしておけば、トグルが押されっぱなしのように見えます。

以降詳しい解説：
まず、トグルコンポーネントの「ナビゲーション」について。

![キャプチャ_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1946685/8d4c70a8-891a-0d9d-1be8-9ca99c097d3d.jpeg)

デフォルトは自動になっています。
これは注目しているトグルをキーボード等で切り替えるための機能なので、マウスやタッチで操作するゲームには不要です。たぶん。
騙されやすいのでオフにするのがオススメです。

次に、トグルの「無効時の色」を「押下時の色」と同じにします。
デフォルトは透明度が50%なので注意。

トグルをON/OFFしたとき呼び出す関数を以下のように変更します。

```c#:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ToggleController : MonoBehaviour
{
    private Toggle toggle;
    
    void Start()
    {
        toggle = this.GetComponent<Toggle>();
    }
    
    public void OnToggleChanged()
    {
        if(toggle.isOn == true){
            //なんらかの処理（OFF→ON）

            //interactableをオフ (押されたまま表示になる)
            toggle.interactable = false;
        }else{
            //なんらかの処理（ON→OFF）

            //interactableをオン
            toggle.interactable = true;
        }
    }
```

これで押されたままのように見えるトグルを実装できます。
スプライトスワップでも同じように実装できると思います。
おわり。
IBMCloud VRA BIOSファームウェアのアップデート方法

# この記事の目的

IBMCloudのVRAはベアメタルサーバ上にAT&T社のVRAソフトウェアをインストールして利用しているため、通常のベアメタルサーバ同様に、BIOSのファームウェア管理がIBMCloudポータル上から実行できます。

実施するにあたっての考慮事項や、どの程度のサーバ停止を伴うのかの作業影響を確認しましたので、参考情報として記載します。

## VRA(ベアメタルサーバ)の BIOS/IPMI/RAIDController/HardDrive のFirmware適用状況を確認する

* IBMCloud Portal -> ClassicInfrastructure -> Device List -> 対象デバイスを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703075/9d4502ac-7911-d9ab-8e10-b15c6ff31648.png)

* 左側にある "Firmware" を選択し、"Updates available"の項目を確認する。
(もし、BIOSやRAIDControllerやIPMIのFirmwareに新しいバージョンが提供されている場合、下図の例のようにBIOSがUpdatesAvailavleの項目に表示され、現在利用/アップデート先のバージョンが表示されます。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703075/4f03935d-d30e-127d-7058-0851d39b11b0.png)

* BIOSのFirmwareに現在より新しいバージョンがあることが分かりました。



## Firmware Updateの実施

* 続いて、BIOSのFirmwareのアップデートを行っていきます。
    * VRAのFirmware Updateを行うため、HA 2台構成であればVRRPをStandby状態に変更したり、Configバックアップなどを取った上で作業を行うことをオススメします。

1. 稼働中であれば、まずVRAの電源OFFを実施します。
2. "Actions" -> "Update firmware"を選択します。
  (電源がONだとActionボタン配下のUpdateFirmwareボタンがグレーアウトしており、実行できないので注意ください。)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703075/15d15d5a-f096-f814-99cd-a867a42cf417.png)

3. 以下表示された画面で必要な項目を選択して"OK"をクリックする。（図の４行目に、最低でも完了まで1時間はかかる旨の注意書きが書かれています）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703075/d10974c2-5b59-79fb-1a37-09400a79188c.png)


4. 定期的にポータルページのブラウザの更新ボタンを使って、更新状況を確認できます。
(一時間以上かかるため、ご注意ください。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703075/e9c95fe8-94bc-af86-5825-c391212aff23.png)

* 完了するとポータル画面が以下のようになります。 "Up to date firmware"にBIOSの項目が移動しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703075/3e217f9e-7631-071a-4bb3-c8a902485bd8.png)

## バージョンアップまでの時間目安について

利用しているHardware製品のベンダが違う可能性もあるので、あくまで１つの参考情報となりますが、手元の機器では 1時間7分 でFirmwareアップデートが完了し自動でVRAが起動してきました。

[作業時間]
 14:27 ポータルで"Update firmware"のOKボタンを実行。
 15:34 ポータルで"Up to date firmware"にBIOSが表示され、VRAのStatusがRunningに変更された。

## その他

* ポータルでRunnningとなっていることを確認した後にSSHログインし、起動時間を確認することで具体的にいつ復旧したのか確認できます。(分かりずらいですが、本機はCST[米国中部標準時]で設定しているため、00:41の7min前にUp = 日本時間では15:34にUpしたことがわかります）

```
Welcome to AT&T vRouter
Version:      1912m
Description:  AT&T vRouter 5600 1912m
Linux xxxx-gateway02 4.19.0-trunk-vyatta-amd64 #1 SMP PREEMPT Debian 4.19.176-0vyatta1+1.2 (2021-02-22) x86_64
vbash-sandbox: sudo: command not found
vyatta@xxxx-gateway02:~$
vyatta@xxxx-gateway02:~$ uptime
 00:41:09 up 7 min,  0 users,  load average: 1.85, 1.57, 0.79
vyatta@xxxx-gateway02:~$
```
PHP独学ノート　その6

<font color="green">浮動小数点リテラル</font>

浮動小数点リテラルは整数リテラルに比べると少し複雑。

一般的な「1.41421356」のような小数点数だけでなく、指数表現が存在するから。

<font color="red"><仮数部>e<符号><指数部></font>
の形式で表されるリテラルのこと。

<font color="red"><仮数部>×10の<符号><指数部></font>
で本来の小数値に変換できる。

一般的には非常に大きな（小さな）数値を表す為に利用する。

<font color="blue">1.4142e10</font>→<font color="blue">1.4142×10の10乗</font>→
<font color="red">1412000000.0</font>

<font color="blue">1.173205e-7</font>→<font color="blue">1.173205×10の-7乗</font>→<font color="red">0.0000001173205</font>

指数を表す「e」は大文字小文字を区別しないので「E」でも良い。

指数表現では、
1732を
「173.2e1」（173.2×10）、
「17.32e2」（17.32×10の2乗）、
「1.732e3」（1.732×10の3乗）のように複数のパターンで表現できてしまう。

そこで一般的には仮数部が「0.」+「0以外の数値」で始まるように表すことで表記を統一する。

この例であれば「0.1732e4」とする。

先頭のゼロは省略できるので、「.1732e4」としても同じ意味。

<font color="green">数値セパレーター（7.4）</font>

PHP7.4以降では桁数の大きな数値の可読性を改善する為、数値リテラルの中に桁区切り文字（_）を記述できるようになった。

（数値セパレーター）以下はいずれも正しい数値リテラル。

```
$value = 1_234_567;
$pi = 3.141_592_653_59;
$num = 0.123_456e10;
```

日常的に利用する区切り文字の「,」でない理由は、PHPにおいてカンマはすでに別の意味を持っている為。

数値セパレーターはあくまで人間の可読性を助ける為の記号なので、自由に差し込む事ができる。

12_34_56    →   2桁ごとに区切り
12_345_6789 →   異なる桁での区切り

以下のように2、16進数でも利用できる。

0b01_01_01  →   10進数で21
0xf4_240    →   10進数で1000000
023_420     →   10進数で10000

ただし数値セパレーターを挿入できるのは数値の間のみ。
よって以下は不可。

_123_456_789、123_456_  →  数値の先頭/末尾
1._234     →     小数点の隣
0_x99      →     数値プレフィックスの途中

<font color="green">文字列リテラル</font>

値そのものだけで表現する数値リテラルに対して、文字列リテラルを表すには文字列全体をシングルクォート（’）、またはダブルクォート（”）でくくる。

クォート文字で文字列の開始と終了を表す。

```
‘今HTMLとPHPでサイトを作る勉強中’
“なかなかうまくいかなくて泣きそう”
```

よって文字列リテラルには「’」「”」そのものを含めることはできない。以下は不可。

```
print “私の好きな食べ物は”カレー”です！”;
```

これだと「”私の好きな食べ物は”」と「”です！”」の間に不明な識別子カレーがあるとみなされてしまう。

その場合は、

<font color="red">文字列に含まれない方のクォートでくくる</font>

```
print ‘私の好きな食べ物は“カレー”です！’;
```

今度は文字列の開始/終了を表すのはシングルクォートなので文字列にダブルクォートが含まれていても単なる「”」とみなされる。

逆も一緒。

```
print “あとは‘豚キムチ’も好きです！”;
```

<font color="red">クォート文字をエスケープ処理する</font>

先ほどの方法では文字列にシングルクォート/ダブルクォート双方が含まれる場合に対処できない。

以下はエラーとなる。

```
print ‘単純’に”肉”は全般好きです！’;
```

このようなケースでは文字列に含まれるクォート文字を<font color="blue">エスケープ処理</font>する。

エスケープ処理とは<font color="red">「ある文脈の中で意味を持つ文字を、あるルールに基づいて無効化する（無意味にする）」</font>ことをいう。

今回の例で「意味を持つ文字」とは、文字列リテラルの開始と終了を表すクォート文字である。

この例であれば、以下のように表すことでクォート文字をエスケープできる。

```
print ‘単純\’に”肉”は全般好きです！’;
```

「\’」は（文字列の開始と終了でない）ただの「’」とみなされるので意図した通り表示される。

同じく「\”」は文字列の開始と終了を意味しないただの「\”」になる。

よって以下のように書き換えても同じ意味。

```
print “単純‘に\”肉\”は全般好きです！”;
```

<font color="green">シングルクォート文字列とダブルクォート文字列の違い</font>

PHPでは文字列リテラルをシングルクォートまたはダブルクォートのいずれでくくるかということには大きな違いがある。

具体例↓

```
<?php
$title = ‘死霊館シリーズ’;

$data1 = “怖かったホラー映画は「{$title}」です。<br>“;

$data2 = ‘怖かったホラー映画は「{$title}」です。<br>’;

print $data1;
//結果: 怖かったホラー映画は「死霊館シリーズ」です。

print $data2;
//結果: 怖かったホラー映画は「{$title}」です。

```

シングルクォートかダブルクォートのいずれでくくるかによって、文字列を解釈する方法が変化する。

<font color="green">その7でもう少し詳しく</font>
Error : npm does not support Node.js v10.19.0

>Error : npm does not support Node.js v10.19.0

上記エラーが出る場合、Nodejsのバージョンを上げることによって解決する。

```
$ curl -fsSL https://deb.nodesource.com/setup_12.x | sudo -E bash -
$ sudo apt install -y nodejs
```
Concrete CMS でログイン状態で負荷テストをする方法


Concrete CMS でログイン状態の負荷テストを行たい場合があります。
手軽に、Apache Bench を使ってテストをする方法です。

この元アイデアは Hissy によるものです。


# 事前準備

1. 開発環境で行う (本番環境で行わない)
2. Concrete CMS の自動ログアウトのセッションセキュリティのポリシーを緩めます
	1. admin (管理者権限のあるユーザー)でログイン
	2. [管理画面] - [システムと設定] - [ログインとユーザー登録] - [自動ログアウト] ページに訪問
		- URL は [C5 サイトURL]/index.php/dashboard/system/registration/automated_logout
	3. `ユーザーの IP が変わるとログアウトする` と `ユーザーのブラウザエージェントが変わるとログアウトさせる` をオフにして保存する
	4. テストが終わったら設定を元に戻すのを忘れずに
2. テストをしたいページを準備
	- コンテンツ
	- キャッシュ設定
	- 必要に応じてユーザー作成・権限を設定
3. ユーザーとして Concrete CMS ログイン
4. Chrome の Developer Tools などを開き、ログイン後に取得される `CONCRETE`のクッキーの値をメモ
	- ただし V8未満は `CONCRETE5`です
	- config の設定でセッション & クッキー名はカスタマイズ可能なのでその場合は違います
5. Curl で動作テスト
	- 非ログイン状態で実行する
		- `curl -o /dev/null -s -w %{size_download} "https://example.com/"`
		- ページのバイト数が表示される
    - ログイン状態 (クッキーで取得した情報を入力) で実行する
	    - `curl -o /dev/null -s -w %{size_download} --cookie "CONCRETE_LOGIN=1;CONCRETE=XXXXXXX" "https://example.com"`
	    - 非ログイン状態よりも大きいページサイズが表示される
    - Concrete CMS が生成する HTML ソースのバイト数が変化したらログイン成功です。
    - Cookie の値をあえて間違えて送信し、非ログイン状態と同じバイト数になっていることを確認。



これで準備完了です。

# Apache Bench で実行

Apache Bench では、以下のように実行します。

- -n や -c の値を調整して、負荷テストをしてください。
- Apache Bench の結果の中にある `Document Length:` の数字が、さきほどの curl テストの時と同じ数であることをチェックしてください。
- 繰り返しますが各Cookieの名前は Concrete CMS V8 以前と、V9以降とデフォルトが変わっています。またセッション名をカスタマイズしている場合は違う名前になっています。
- 時間が経つとユーザーのセッションは切れてしまいます。Apache Bench を実行する直前にログインをしてください。
- ab の実行後、前述の [自動ログアウト] 管理画面の設定を元に戻すのを忘れないでください。


## 非ログイン状態での実施

```
ab -n 10 -c 10 https://example.com/
```

最後にスラッシュを忘れずに。Invalid URL と怒られる場合があります。


## ログイン状態での実施

さきほどの curl テストで設定した `--cookie` パラメータを ab では `-C` オプションで設定してください。

```
ab -n 10 -c 10 -C "CONCRETE_LOGIN=1;CONCRETE=XXXXXXX" https://example.com/
```


# テスト実行後の設定

ab の実行後、前述の [自動ログアウト] 管理画面の設定を元に戻すのを忘れないでください。

1. admin (管理者権限のあるユーザー)でログイン
2. [管理画面] - [システムと設定] - [ログインとユーザー登録] - [自動ログアウト] ページに訪問
	- URL は [C5 サイトURL]/index.php/dashboard/system/registration/automated_logout
3. `ユーザーの IP が変わるとログアウトする` と `ユーザーのブラウザエージェントが変わるとログアウトさせる` をオンに戻して保存する



以上
【Unity】GitHubでLogsフォルダを共有しない方法

UnityのプロジェクトをつくるとLogsフォルダにLogがでて、GitHubでの共有で競合しちゃったりするとおもいます。
その時の対処法

現状これで問題ないだけで正しいかどうかはわかりません
正しい対処法を知ってる方いればコメントいただけると嬉しいです

#動画で解説
https://youtu.be/ib0eT-gHcJY


#やること
・Logsフォルダを削除
・gitignore Logs/* を追加してPush


#その他
https://qiita.com/simanezumi1989/items/05bc1437374c05d2de98
【Arduino Library 第4弾】大体(?) 6STEPで書く tinyESPNow

## 0.ライブラリ
https://github.com/chrmlinux/tinyESPNow

## 1.はじめに

自社基板のFWに __ESPNow__ の実装をするたびに
「これ長いなぁ」と毎回感じており
特に100個のクローンを製作する場合にIPアドレスの設定等ちょっと面倒な事になります
そこで 自前で __MYID__ を設定し基本ブロードキャスト送信
受信するときに __MYID__ で振り分けが出来るような
仕組みを実装し __Arduino Library__ として登録しました

## 2.仕組み

_slave.peer_addr[i] = (uint8_t)0xff;
上記の設定により ブロードキャスト送信

```　
tinyESPNow::begin 

uint16_t tinyESPNow::begin(uint8_t myId, uint32_t arySize) {
  __arySize = arySize;
  __transAry = new uint8_t[__arySize];

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  if (esp_now_init() == ESP_OK) {
    Serial.print("ESPNow Init Success\n");
  } else {
    Serial.print("ESPNow Init Failed\n");
    ESP.restart();
  }
  memset(&_slave, 0x0, sizeof(_slave));
  for (int i = 0; i < sizeof(_slave.peer_addr); ++i) {
    _slave.peer_addr[i] = (uint8_t)0xff;
  }
  esp_err_t addStatus = esp_now_add_peer(&_slave);
  esp_now_register_send_cb(&OnDataSent);
  esp_now_register_recv_cb(&OnDataRecv);

  __myId = myId;
  return 0;
}

```

受信したときに呼ばれるコールバック関数
if (recv[0] == __myId) {
}

```
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *recv, int recvCnt) {
  if (recv[0] == __myId) {
    memcpy(__transAry, recv, recvCnt);
    __recved = true;
  }
}
```
## 3.使い方

tEN.get で バッファのポインタを持ってきて
tEN.put で バッファ更新して
tEN.sendで バッファを送信します
ESPNow はサーバ/クライアントの概念がありまてんので
これを2個の ESP32系基板に入れ
最初に立ち上げた方が受信 後に立ち上げた方が送信となり
未来永劫送受信できます

```
#include "tinyESPNow.h"
static tinyESPNow tEN;

#define BUFSIZE (64)            // The size of the buffer
#define MYID    (0xFF)

void dataUpdate() {
  uint8_t *buf = tEN.get();     // Get a pointer to the buffer
  buf[0] = 0xFF;
  Serial.printf("%02X=>", buf[1]);
  buf[1] = (buf[1] + 1) % 256;  // Add One to the received data
  Serial.printf("%02X\n", buf[1]);
  tEN.put(buf, 2);              // Update the buffer
  tEN.send();                   // Send the buffer
}

void setup() {
  Serial.begin( 115200 ); while (!Serial);
  tEN.begin(MYID, BUFSIZE);
  dataUpdate();
}

void loop() {
  if (tEN.isRecv()) {           // Did the data arrive?
    dataUpdate();
  }
  tEN.update();                 // Update class
  delay(20);
}
```
## 4. 6STEP とは?

* バッファのポインタを持ってくる
* 更新する
* 書き込む
* 送る
* 受信があれば何かする

この6STEPになります

## 5. 最後に
コードがすっきりちました

@chrmlinux03
Microsoft Teams で メンションができないとき

なぜメンションがうまく機能しなくなるのかはわかりませんが、メンションできなかったときに以下の方法を試してみてください。私はこの方法でメンションできるようになりました。

# メンションの方法
@ を入力した直後に”半角スペース”を入力することで、名前が表示できるようになります。
ちなみに@も半角で入力してください。@が全角になっていると、そもそもメンションできません。
VS CodeのRemote Containerへスペースの含まれたユーザー名でログインしたい

WindowsでDockerを使っているいるときのあるあるではないでしょうか。

```
"docker.host":"ssh://yamada tarou@192.168.0.2"
```

上記のように接続したいときは

```
"docker.host":"ssh://%22yamada%20tarou%22@192.168.0.2"
```

.ssh/configでもいいんですけど.......
よく使うCurlのオプション

Curlで頑張る自分です。


|オプション  |効果  |メモ  |
|---|---|---|
|　-H　|ヘッダを追加する  |書き方次第で色々つけられる  |
|　-H "Content-Type: application/json"  |Content-Typeをapplication/jsonにする  |APIリクエストなどでよく使う。  |
|　-H "Origin: http://example.com"  |オリジンを書き換える  |CORS対策の調査とかで使える。  |
|　-H "Access-Control-Request-Method: GET"  |アクセスコントロールのリクエストをGETにする  |CORS対策の調査とかで使える。OPTIONS向け。  |
|　-X　|メソッドを固定する  |POST,GET,PUT,DELETEなど  |
|　-L　|リダイレクトを受け入れて、リダイレクト先も取得する  | Xでメソッド固定してると、リダイレクト先でも固定されるので注意。 |
|　-d　|データをボディに付ける  |メソッド指定しなくとも、POSTになる  |
|　-v　|通信の詳細を見る  |★重要★  |
|　-c my.cookie　|my.cookieファイルを作成し  |  |
|　-b my.cookie　|リクエストにmy.cookieの値を使う  |  |


`curl -L https://www.yahoo.co.jp/ -v -b my.cookie -c my.cookie`
こんな感じで使うと、カレントディレクトリに`my.cookie`が作成される

```my.cookie
$ cat my.cookie
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

.yahoo.co.jp	TRUE	/	TRUE	1708152710	XB	e7sm9r5h0p7o6&b=3&s=6t
.yahoo.co.jp	TRUE	/	FALSE	1708152710	B	e7sm9r5h0p7o6&b=3&s=6t
```


最近良く使うのを一通り書き出しました。
もっと丁寧に書いてくれてる記事などもありますが、自分用ということで…

職場ではPOSTMANというツールを使ってる人が多い。
GUIで見やすくて便利なんだけど、EC2インスタンスの中へは持ち込めないですよね。
運用中のサーバにインストールとかできるわけがないので。
AWS SAA-C02に合格した勉強法（22/02/13 受験）

#はじめに
##私のAWSの事前知識
無料利用枠のEC2インスタンスを立ち上げたことがあるだけ

##試験結果
![awsq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528939/84852d92-7e04-34f4-5948-a2b52fab8064.png)
一度目の受験で合格することができました。
あまり余裕のある点数ではありませんでしたが。。。


#勉強方法
##Udemy（有料）
[Udemy](https://www.udemy.com/)の下記の動画で勉強しました。
メインの教材はこれだけです。

[【2022年版】これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座](https://www.udemy.com/course/aws-associate/)

SAA試験はC02にバージョンアップしているため、書籍よりも上記の動画での勉強のほうが最新の試験に対応していると思います。
（書籍は購入していないので比較はできませんが）
AWSは更新が頻繁に行われますが、この動画は購入後も更新が続いてAWSの最新の内容が反映されているのがよかったです。

この教材は他のSAA試験の合格体験記事でもよく紹介されていますが、合格された方の中ではハンズオンをやる派とやらない派に分かれているようです。
既にAWSをめちゃくちゃ使いこなしていて、肩書が欲しいだけという人以外はハンズオンも実施することをお勧めします。
模擬試験を繰り返すだけでも試験に合格することはできますが、それだけでAWSのさまざまなサービスを組み合わせて可用性やセキュリティ、コスト最適などを意識したWell-Architected-Frameworkに則ったシステムを実際に設計・構築するのは難しいのではないかと思います。

ハンズオンを実施することで、AWSの主要なサービスの使い方がわかるようになります。
また、実際にサービスを使用することで、どこまでが無料でどこからが有料なのか、有料サービスの中でも月数百円程度のサービスと月数万～数十万円かかるサービスの違いも身につきます。

私はこの動画をハンズオンも含めて最初から最後まで通しで実施し、知識が曖昧なところは動画を見直しつつ、最終的にはすべての小テストと模擬試験を9割以上解けるまでやりました。

##AWS BlackBelt（無料）
Udemyの模擬試験を実施してみて理解不足なサービスが出てきたら、AWSの[サービス別資料](https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/)というところにある資料が参考になります。
AWSのサービス別に細かく解説されている資料があります。

BlackBeltを見ると、EC2、VPC、IAMなど主要なサービスは先ほど紹介したUdemyの動画の資料と内容や構成が似ていることがわかると思います。
BlackBeltをベースにして、初心者でもわかりやすいようにかみ砕いて表現したのがUdemyの動画の資料になっているのかもしれません。

そのため、Udemyの動画で詳しく説明されているサービスをBlackBeltで確認するよりは、動画でさらっと流しているサービスだけど模擬試験でよく出てくるようなサービスの知識をBlackBeltで補強するような使い方がいいと思います。

##AWS 無料WEB問題集&徹底解説（無料）
[AWS 無料WEB問題集&徹底解説](https://aws-exam.net/saa/)
SAA試験対策の問題が掲載されていて、会員登録をすれば成績表機能が利用できます。
問題の難易度は若干易しいように感じました。
私は基礎知識の確認の意味合いで使っていました。
ただ、解答が間違っていたり、内容が古いままの問題があるので注意が必要です。

##公式サンプル問題（無料）
[AWSのSAAのページ](https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/)にサンプル問題（全10問）があります。
試験の難易度の確認というよりは、AWSの認定試験は日本語が怪しいとよく聞くので、実際にどんなものなのかの感覚を掴むために解きました。
私はSAAが初めてのAWS認定試験になるので日本語の問題文が理解できるか少し不安でしたが、実際の試験の問題はこのサンプル問題やUdemyの模擬試験と同じような問題文でした。
クラウドプラクティショナーに合格している方はさらっと見るだけでもいいかもしれません。

##公式練習問題（無料）
これも[AWSのSAAのページ](https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/)から行けます。
試験を受けるまでの手順がややこしいので、参考のリンクを貼っておきます。

[AWS認定10資格について模擬試験が無料/解説付きで公式からリリースされたので受けてみた](https://dev.classmethod.jp/articles/aws-exam-free-practice/)

全部で20問あります。
私は本番直前の腕試し的な感じで解きました。
正答率は8割くらいでした。

#おわりに
お金はできるだけかけたくないという思いがあり、メインの教材はUdemyの動画だけにしました。
動画のレビューで試験範囲が網羅されているというコメントがそれなりにあったので、そのレビューを信じて動画の内容に集中しました。
結果的には合格したので良かったです。
かかった費用はUdemyの動画と受験料のみでした。

〇週間で合格とか〇時間で合格といった記事もありますが、私は割と時間をかけて勉強したほうだと思います。
勉強時間はだいたい100時間くらいはしたかと思います。
Udemyのハンズオンを実施することでAWSの主要なサービスの使い方がわかったので、なにもわからなかった時よりもAWSを利用することへの抵抗がなくなった気がします。
これが今回の勉強での一番の成果だと感じています。

私がSAA試験の受験を決めたときに勉強方法についていろいろ調べましたが、Udemyのハンズオンで勉強している人以外にも、書籍で勉強している人、Udemyにある模擬試験の教材で勉強している人もいたりして、私の選択は正しいのかと少し不安になりました。
こういう勉強方法もあるということで、この記事がこれからSAA試験を受験しようとしている方の参考となれば幸いです。