OmniAICreator/Qiita-1.07M huggingface dataset:
GolangのValidationチェック(go-playground編)

#初めに
GolangでのValidationチェックを実施する記事です。

#サンプルコード
```go:main.go
package main

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

// User contains user information
type User struct {
	FirstName      string     `validate:"required"`
	LastName       string     `validate:"required"`
	Age            uint8      `validate:"gte=0,lte=130"`
	Email          string     `validate:"required,email"`
	FavouriteColor string     `validate:"iscolor"`                // alias for 'hexcolor|rgb|rgba|hsl|hsla'
	Addresses      []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
}

// Address houses a users address information
type Address struct {
	Street string `validate:"required"`
	City   string `validate:"required"`
	Planet string `validate:"required"`
	Phone  string `validate:"required"`
}

// use a single instance of Validate, it caches struct info
var validate *validator.Validate

func main() {

	validate = validator.New()

	validateStruct()
	validateVariable()
}

func validateStruct() {

	address := &Address{
		Street: "Eavesdown Docks",
		Planet: "Persphone",
		Phone:  "none",
	}

	user := &User{
		FirstName:      "Badger",
		LastName:       "Smith",
		Age:            135,
		Email:          "Badger.Smith@gmail.com",
		FavouriteColor: "#000-",
		Addresses:      []*Address{address},
	}

	err := validate.Struct(user)
	if err != nil {

		if _, ok := err.(*validator.InvalidValidationError); ok {
			fmt.Println(err)
			return
		}

		for _, err := range err.(validator.ValidationErrors) {
			fmt.Println("=====================【validateチェック】===========================")
			fmt.Println("1: " + err.Namespace())
			fmt.Println("2: " + err.Field())
			fmt.Println("3: " + err.StructNamespace())
			fmt.Println("4: " + err.StructField())
			fmt.Println("5: " + err.Tag())
			fmt.Println("6: " + err.ActualTag())
			fmt.Println(err.Kind())
			fmt.Println(err.Type())
			fmt.Println(err.Value())
			fmt.Println("10" + err.Param())
		}
		fmt.Println("====================================================================")

		// from here you can create your own error messages in whatever language you wish
		return
	}

	// save user to database
}

func validateVariable() {

	myEmail := "joeybloggs.gmail.com"

	errs := validate.Var(myEmail, "required,email")

	if errs != nil {
		fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag
		return
	}

	// email ok, move on
}
```

○実行結果
```go:main.go
=====================【validateチェック】===========================
1: User.Addresses[0].City
2: City
3: User.Addresses[0].City
4: City
5: required
6: required
string
string

10
====================================================================
Key: '' Error:Field validation for '' failed on the 'email' tag
```

うーん、なかなか分かりづらいですね。。。
下記、URLがわかりやすかったので、乗っけておきます。

○追記
 ozzo-validationチェックが使いやすかったので、こっちおすすめです。mattnさんの記事を乗っけておきます！！！
 https://zenn.dev/mattn/articles/893f28eff96129

→さっくさく作れるので楽しいですね！！！

○参考文献

https://chick-tack.blog/posts/2019/golang-validator-tag-custom-field/
【Unity：エディタ拡張】Unityのログを自動翻訳するエディタ拡張 (DeepL API)

https://github.com/R-Kobayashi-mnc/Unity-LogTranslation

Deepl API を利用し、ログの自動翻訳ができます。(DeepL API Free の登録が必要)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2283987/07298f02-1893-0684-2987-20a179d4fd74.png)
empty?, blank?, present?の違い

## empty?
``empty?``は空かどうかを確認するが、レシーバーが``nil``だと、``UndefinedMethod``になってしまう。

```rb
# 空配列にempty
[].empty?
# => true

# 空文字にempty
''.empty?
# => true

# nilにempty
nil.empty?
# NoMethodError: undefined method `empty?' for nil:NilClass

# nilにemptyメソッドがあるのか確認
nil.respond_to? :empty?
# => false
```

## blank?
``blank?``の場合は、``nil``に対しても使えて``nil``なら``true``を返す。

```rb
# 空配列にblank
[].blank?
# => true

# 空文字にblank
''.blank?
# => true

# nilにblank
nil.blank?
# => true

# nilにblankメソッドがあるのか確認
nil.respond_to? :blank?
# => true
```

## present?
``present?``は、``!blank?``と同じ結果になる。
[Golang] ユニットテストにおける正しい後処理の書き方：t.Cleanup()

ユニットテストの**後処理**を行う場合、

`defer`は**並列**で動いている**サブテストの終了を待たずに実行**されてしまう問題がある。

全てのサブテストが終了してから後処理を行たいなら `t.Cleanup()` を使おう。

## **`Defer`による後処理の例**

```go
package main

import (
	"log"
	"testing"
)

func TestDefer(t *testing.T) {
	tcs := map[string]string{
		"A": "1",
		"B": "2",
		"C": "3",
	}

	defer log.Printf("End")

	for tn, tc := range tcs {
		tc := tc
		t.Run(tn, func(t *testing.T) {
			t.Parallel()
			log.Println(tc)
		})
	}
}
```

そのログの抜粋：

```bash
2009/11/10 23:00:00 End
2009/11/10 23:00:00 1
2009/11/10 23:00:00 3
2009/11/10 23:00:00 2
```

[demo](https://play.golang.org/p/H8X0NLUtrwZ)

## **`t.Cleanup()` による後処理**

```go
package main

import (
	"log"
	"testing"
)

func TestCleanup(t *testing.T) {
	tcs := map[string]string{
		"A": "1",
		"B": "2",
		"C": "3",
	}

	t.Cleanup(func() {
		log.Printf("End")
	})

	for tn, tc := range tcs {
		tc := tc
		t.Run(tn, func(t *testing.T) {
			t.Parallel()
			log.Println(tc)
		})
	}
}
```

そのログの抜粋：

```bash
2009/11/10 23:00:00 1
2009/11/10 23:00:00 3
2009/11/10 23:00:00 2
2009/11/10 23:00:00 End
```

[demo](https://play.golang.org/p/izHFD_6afDv)

## 参考

[Go 言語でのテストの並列化 〜t.Parallel()メソッドを理解する](https://engineering.mercari.com/blog/entry/how_to_use_t_parallel/)

[t.Cleanup()で並列に動かすことのできるテーブルドリブンテストを書く](https://zenn.dev/flying_hato_bus/articles/ea7382be6650ded36ac4)

## 元記事

[[Golang] ユニットテストにおける正しい後処理の書き方：t.Cleanup()](https://aifan.jp/2022/03/05/golang-ユニットテストにおける正しい後処理の書き方：t-cleanup/)
Docker コンテナ内でbash: npm: command not foundが出た場合の解決方法

# 概要

DockerでLaravel環境を構築したのでスカフォールドをセットアップした。

`npm install`を実行すると「そんなもんねぇよ」と怒られたので対応方法をまとめる

https://readouble.com/laravel/9.x/ja/frontend.html?header=JavaScript%25E3%2581%25AE%25E5%2587%25BA%25E5%258A%259B

# 補足

記事では`nginx:1.19` をベースイメージとしたコンテナを構築しています。
コマンドについては開発環境に応じて読み替えてください

```yml
version: "3"

services:
  web:
    image: nginx:1.19
    ports:
      - 8010:80
    depends_on:
      - laravel
    volumes:
      - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./src/laravel/public:/var/www/html/laravel/public
      - ./docker/storage:/var/www/html/laravel/public/storage
```

# `Laravel ui`をインストール

```bash
composer require laravel/ui
```

# `apt`コマンドで`npm`・`node`をインストール

```bash
# パッケージ一覧を更新
apt update

apt install nodejs npm
```

# `npm install`を実行すると動くようになる

```bash
npm install 
npm WARN npm npm does not support Node.js v10.24.0
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
```
【Unity】「ゴール！」とテキスト表示したn秒後にシーン遷移

やること：
ゴールしたら「ゴール」とテキスト表示して、その5秒後にシーン遷移する

### 1. Unityでテキストを作る
色やサイズ、文字を設定

### 2. スクリプトを書く
ゴール判定用のスクリプトを作るor既にある場合はそこに記載

![スクリーンショット 2022-03-05 20.34.45.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722227/989f95a7-e0c6-1d55-6840-2a917adbb62b.jpeg)

ぶつかったらゴールとなる場合
ぶつかったら→テキストがtrueになる（表示される）
新たにChangeSceneという関数を作り、その中にシーン遷移のコードを書く

Invoke関数を使って、5秒後にシーン遷移の関数を呼び出す

・SceneManagerを使うためのSceneManagementは宣言されているか？もチェック！
## 3.Unityでスクリプトをアタッチ
・このスクリプトをぶつかる対象物にアタッチ
・Inspectorウインドウを開き、Textの部分がnoneになっているので先ほど作成したテキストをアタッチ
![スクリーンショット 2022-03-05 20.58.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722227/8231237e-1049-3937-deb5-0c457c695b43.png)

・テキストオブジェクトのチェックを外す（初期状態をfalseにする）
![スクリーンショット 2022-03-05 20.59.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722227/64f8d08e-7ea6-7e87-8cec-a578f1f9fd04.png)

・BuildSettingsで、使うシーンが全て登録されているか？チェック
Vite（Vue3） + Laravel（XAMPP環境）でセッションが消える（Authが機能しない）

# イントロダクション

### フロントエンド（Vue.js）

Vite（Vue3）でサーバーを立ち上げる。 → http://localhost:3000

### バックエンド（Laravel）

XAMPPで立ち上げる。 → http://hogehoge.localhost

フロントエンドからバックエンドへは、axiosを使用。

```
axios.get(`http://hogehoge.localhost/api/auth/logout`)
        .then((response) => {
          console.log(response);
          if (response.data.status === 200) {
            router.push("login");
            return;
          } else {
            alert(apiErrorMessage.value);
            return;
          }
        })
        .catch((error) => {
          console.log(error);
        });
```

→ ログイン認証後、別のAPIを実行するとSESSION情報が消えている、、、。

# 結論

リクエストのドメインが、
http://hogehoge.localhost
ではなく、
http://localhost:3000
になっているので（クロスドメイン）、Cookieが取得できない→LaravelのAuthが機能しない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532969/0313a9bc-67d1-e434-5c10-56c0d39a43af.png)

なので、リクエストのドメインを、
http://hogehoge.localhost
に変装させる必要があります。

そのために使うのがvue.config.jsのproxy。

vue.config.jsに以下の内容を追記しましょう。（「^/api」の部分はもし異なるなら適宜、変更してくださいね。）
```
module.exports = {
    //
    devServer: {
        proxy: {
            '^/api': {
                target: 'http://hogehoge.localhost',
                changeOrigin: true
            },
        }
    }
}
```

そして、axiosの記述を書き換えます。（「`http://hogehoge.localhost`」を削除）

```
axios.get(`/api/auth/logout`)
        .then((response) => {
          console.log(response);
          if (response.data.status === 200) {
            router.push("login");
            return;
          } else {
            alert(apiErrorMessage.value);
            return;
          }
        })
        .catch((error) => {
          console.log(error);
        });
```

最後に、Viteを再起動！
→リクエストのドメインが「`http://hogehoge.localhost`」として処理されて、無事、セッションが引き継がれるようになりました。

この記事で100人ぐらい助かってくれるといいね。
Pythonでタイピングを自動化してみよう！

_`サンプルプログラムをダウンロードしてみよう`_
まずこのしたのMEGAのURLからダウンロードしてください

https://mega.nz/file/NopxGKaA#J7DK-Pp8gjXJyJEW66PsMr5vDbsY1YKGmH97pcZZoLs

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2571649/1ddbabc8-2b38-0f4e-c12a-c386d7ab27e5.png)
このようなダウンロード画面になります
ダウンロードを押してダウンロードしてください
この記事は作成している途中です
........
VSCodeのターミナルでlazygitが見づらいときの解決方法

# 結論

```json:setting.json
"workbench.colorCustomizations": {
  "terminal.ansiWhite": "#aaa",
  "terminal.ansiBrightWhite": "#fff"
}
```

# 概要
[lazygit](https://github.com/jesseduffield/lazygit)はgit操作が爆速でできるので愛用している。しかし、VSCodeのターミナルで使おうとすると、見づらい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297745/0ab8365e-7620-cc15-d5ea-9375db2732c8.png)
↑VSCodeのターミナルで開いたとき。実は、一行目が明るくなっているが分かりづらい。。。
ちなみに、iTerm2で開けば以下のようにコントラストがはっきりとする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297745/8bcb0b2a-7074-4caf-2e8d-740b39c66dce.png)
↑iTerm2でlazygitを開いたとき。一行目が選択されていることがわかりやすい。

VSCodeのターミナルでも見やすくなってくれると捗るんだけどな。。。
そんなときに出会ったのがこの記事。
https://dev.to/sfarias051/how-to-change-the-terminal-style-in-vscode-in-an-easy-way-5139
記事を参考に以下の設定を追加した。

```json:setting.json
"workbench.colorCustomizations": {
  "terminal.ansiWhite": "#aaa",
  "terminal.ansiBrightWhite": "#fff"
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297745/46e4fd6b-71d6-ab7e-9a08-e0eed02c2d34.png)
だいぶ見やすくなった :tada:
40 代おっさんLambdaのイベントソースとlambda関数を学ぶ

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## イベントソース

### イベントソースとは

lambda関数が呼び出されるきっかけとなるもの
lambda関数にはハンドラーなるものがあり、それでイベント受け取る

#### lambda関数を呼び出すタイプ

・同期
・非同期
・ストリーム
がある

イベントソースにより呼び出しのタイプが異なる。
それにより、aws側でリトライを実行されるのか、ユーザー側でリトライを実装するのかで変わる

## 最後に

またこの記事は AWS 初学者を導く体系的な動画学習サービス「AWS CloudTech」の課題カリキュラムで作成しました。
<https://kws-cloud-tech.com/>
【React】Next.jsで lang="ja" と title を設定する【TypeScript】

Next.js のプロジェクトは React のプロジェクトみたいに直接 html を編集することができないのでちょっと困りました。
ドキュメントを読んでてもちょっと分かりづらかったのでまとめ。

# やりたいこと

```html
<html lang="ja">           ← これと
  <head>
    <title>タイトル</title> ← これを設定したい
  </head>
</html>
```

# やったこと

2 つほどファイルを編集します。

まずは`_document.tsx`。
pages 内に無ければ作ってください。

```tsx:pages/_document.tsx
import { Html, Head, Main, NextScript } from "next/document";

const Document = () => {
  return (
    <Html lang="ja">
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
};

export default Document;
```

内容は下記リンクを参考に。
とくに内容をイジる必要はないので脳筋テンプレファイルだと思って作ればいいと思います。

https://nextjs.org/docs/advanced-features/custom-document

次は`_app.tsx`。
以下のようにして`Head`と`title`追加してあげるだけです。

```tsx:pages/_app.tsx
import type { NextPage } from "next";
import type { AppProps } from "next/app";
import Head from "next/head";

const MyApp: NextPage<AppProps> = ({ Component, pageProps }) => {
  return (
    <div className="app">
      <Head>
        <title>タイトル</title>
      </Head>
      <Component value="何かしらのコンポーネント" />
    </div>
  );
};

export default MyApp;
```

https://nextjs.org/docs/api-reference/next/head

# ハマったポイント

書こうと思えば以下のように`_document.tsx`の中に`title`を書くこともできます。

```tsx:pages/_document.tsx
import { Html, Head, Main, NextScript } from "next/document";

const Document = () => {
  return (
    <Html lang="ja">
      <Head>
        <title>タイトル</title> ← ここに書くこともできる
      </Head>
    </Html>
  );
};
```

できますが、警告が出ます。

```
Warning: <title> should not be used in _document.js's <Head>.
```

> 訳）pages/_document.jsに&lt;title&gt;を追加すると、_document.jsは最初のプリレンダリング時にのみレンダリングされるため、next/headで予期せぬ結果を招くことになります。

ということみたいです。

https://nextjs.org/docs/messages/no-document-title

ちなみに以下のような書き方は普通にエラーがでます。

```tsx:pages/_document.tsx
import { Html, Main, NextScript } from "next/document";
import Head from "next/head"; // next/head の Head が読み込まれてる

const Document = () => {
  return (
    <Html lang="ja">
      <Head>
        <title>タイトル</title> ← ここに書くこともできる
      </Head>
    </Html>
  );
};
```

```
Error: next/head should not be imported in pages/_document.tsx. Import Head from next/document instead.
```

> 訳）エラー: pages/_document.tsx で next/head がインポートされていません。代わりにnext/documentからHeadをインポートしてください。

https://nextjs.org/docs/messages/no-head-import-in-document
Kotlin KoansでKotlin入門　第１回：Simple Functions

# はじめに
公式の問題集[「Kotlin Koans」](https://play.kotlinlang.org/koans/overview)を解きながらKotlinを学習します。

# 問題
[Simple Functions](https://play.kotlinlang.org/koans/Introduction/Hello,%20world!/Task.kt)

文字列「OK」を返すようにコードを変更してください。
```kotlin
fun start(): String = TODO()
```

# 解答例
TODO()を"OK"に書き換えてRUNボタンを押すとコードが実行されます。
```kotlin
fun start(): String = "OK"
```

# ポイント
関数の定義に戻り値を式で指定できるようです。

戻り値の型も省略できました。
```kotlin
fun start() = "OK"
```


普通に書くとこんな感じだと思います。
```kotlin
fun start(): String {
    return "OK"
}
```
Kotlin KoansでKotlin入門　第０回

# はじめに
普段はJavaを書いていますが、Kotlinを使うことになりました。
学習教材としてKotlin Koansが良いらしいのでやってみます。

## Kotlin Koans とは
[Kotlin Koans](https://play.kotlinlang.org/koans/overview) 
> Kotlin Koansは、Kotlinの文法といくつかのイディオムに慣れるための一連の演習です。

Kotlin公式ページで提供している１問１答形式の問題集です。４３問くらいありました。
ある程度他のプログラム言語の経験がある人向けのようです。
環境構築は不要で、[こちらのページ](https://play.kotlinlang.org/koans/overview) で、テストが通るようにプログラムを修正します。

## Koansは公案のことみたいです
> 公案とは、禅の問答、または問題をいう。禅宗で修行僧が参究する課題である。
[ウィキペディア](https://ja.wikipedia.org/wiki/公案)
AWS Route53 位置情報ルーティングポリシー 複数レコードで同じ「場所」は選べない（Udemy SysOps問題集④ ラボ試験問題1 質問70）

Udemy SysOps問題集④ ラボ試験問題1 質問70にて、位置情報ルーティングポリシーの設定があるのですが、ここで**２つ（以上）登録するレコードに対してどちらも同じ「場所」（解答では「デフォルト」だが、場所はどこにしても同じになると）を設定すると登録ができなかった**のでここにメモしておきます。

※私のハンズオンがミスってる可能性が大いにあるのでご了承ください。といっても位置情報なので、同じものが２つ存在すればどっちにいけばいいのってなるから、話としては理にかなってるのかなぁとは思います。

## 設定（エラー）画面
![スクリーンショット 2022-03-05 18.41.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/d6af63af-c957-b8f5-7e97-6ff3e1ece37b.jpeg)

## 実際に発生させる
① ドメインを取得する（.click が一番安かったです。3$！）
② ①のドメインを使ってホストゾーンを作成する
**③ （本事象）ホストゾーンに①の各インスタンスIPでAレコードを位置情報ルーティングで登録する**

## エラー文
(InvalidChangeBatch 400: RRSet with DNS name xxx.xxx., type A, SetIdentifier dadaewdaewda, and routing to [country = (*, Default)} cannot be created because a GEO RRSet with the same name, type and routing to ***[country = (*, Default)} already exists.)***

デフォルトはもうあるよ！って出てますね。

以上です。この問題でRoute53まわりは良い復習になりました:grinning:
Outsystems Reactive紹介

リアクティブWebアプリとは

OutSystemsでは、リアクティブWebアプリはブラウザで実行されるレスポンシブなインターフェイス
を備えたアプリです。多くのタイプのデバイスや画面サイズで優れたユーザーエクスペリエンスを提供
します。OutSystemsのビジュアル言語を使用して開発し、HTML5とJavaScriptを使用してアプリのロ
ジックを拡張することで、デバイスのハードウェアとやりとりすることができます。
リアクティブWebアプリは、開発エクスペリエンスの統合に役立ちます。開発を単一の言語で行うこと
ができ、複数のアプリで動作するコンポーネントを作成して発展させることができます。
リアクティブWebアプリを開発すると、以下を行うことができます。
• Web開発とモバイル開発のパラダイムの統一
• クライアント側のランタイムを利用するアプリの開発と、レスポンシブなUXの作成
• 最新のスタック上でのアプリの実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/ee47e676-8cef-9f78-b796-1ae4a880b7ad.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/b873a183-a1e5-aa89-ace6-6868778fe58a.png)

OutsystemsStudioでリアクティブWebアプリ作りします
OutSystemsでは、複数のタイプのアプリを作成できます。［New Application］ウィンドウで新しい
アプリを選択する際に役立つ概要を以下に示します。
ユーザーがデスクトップブラウザで実行することが多いアプリを作成する場合は、［Reactive
Web App］を選択します。
• ユーザーがダウンロードできるモバイルアプリとしてアプリを作成し、Apple App StoreやGoogle
Playに提出する場合は、［Phone App］または［Tablet App］を選択します。
• 軽量なアプリを作成してプログレッシブWebアプリ（PWA）としてWebサイトで共有し、ユーザ
ーがモバイルのホーム画面にアプリのアイコンを配置できるようにする場合は、［Phone App］
または［Tablet App］を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/dcafffa1-4d58-f947-de61-c55eb0e97bcc.png)
AWS KMS でアプリケーション内の暗号化をしようとしてハマった話

## 背景
今回はあるWebアプリケーションを作っている際にテキストを暗号化する
APIを作った時の備忘録です。

KMSを使うのが初めてで、おそらく初心者っぽいミスをしてしまったかなと
思ったのでメモを残しておきます。


## APIの構成
アプリケーション全体の構成は少し複雑ですが、API自体は
とてもシンプルな構成です。
APIGatewayを経由して対象のLambdaを呼び出し、結果を返します。
（実際はAuthorizerを経由しているが、この説明からは割愛）
![api.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371958/d6b3ff9b-0a3c-8c47-d6a0-3cc222e0939c.jpeg)

## 実装の内容
今回は初めてということもあり、効率的な実装ができていたかはわかりません。
とりあえず、下記のような手順で進めてみました。

1.AWSコンソールでカスタムキーを作ってみる。
2.boto3を使ってencryptとdecryptをするクラスを作ってみる。
3.APIのリクエストを処理するメイン処理を実装してみる。
4.IAMロールを作成してAPIの動作確認をしてみる。



## 1.AWSコンソールでカスタムキーを作ってみる。
最初に鍵を作ってみました。
正直鍵をコンソールで作ることは簡単すぎてあまり手順を覚えていないですw

まずキーを選びます。
- 対称キー
- 非対称キー

その後はエイリアスを決め、キーの管理者、キーの利用権限を
設定し、終了。
5つくらいのステップでした。

## 2.boto3を使ってencryptとdecryptをするクラスを作ってみる。
AWSのサイトにもサンプルコードが公開されています。
https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/python-kms-key_encryption.py.html

しかし、自分は下記の方を最初に参考にしました。
任意のテキストを暗号化したいだけの用途としてAPIを作成していたので、
一番似たような用途かなと思ったため。
https://gist.github.com/hajimeni/2d5eb87a1cfd55f0ebb2077d8621772f

最終的にはAWSのサイトにあるようなものを使ってブラッシュアップしていきました。

## 3.APIのリクエストを処理するメイン処理を実装してみる。
これは上で作ったクラスを呼んで、実際に来たリクエストを暗号化して返してあげるという処理をしています。
上のAPI構成図では割愛した部分ですが、Authorizerのチェックが通った場合にこの処理にリクエストが
流れてくるという仕様です。

## 4.IAMロールを作成してAPIの動作確認をしてみる。
今回ハマってしまったのはこの部分なのですが、
APIの処理を担うLambdaに必要なIAMロールを付けて
実際にAPIを叩いてみます。

テストの段階ではうまく行き、なんとか実装できていたと安心していました。



## ハマったところ
上にも記載がありますが、IAMロールの権限付与の部分で少しハマってしまいました。

結論から言うと、KMSのカスタムキーを使ってアプリケーション内の暗号化をする場合は
<strong>キーポリシー、キーユーザーの登録</strong>を行わないといけないということです！

手順のところでも書きましたが、キーを作成した時に何をしたのかという記憶が薄くなっており、
最後に行ったIAMロールのアタッチのところでトンチンカンなことをしていたというわけです。

何をしていたかというと下記のようなことをしておりました。

まず、仮実装・テストの段階では仮に作ったIAMロールをアタッチしておりました。
キーを作成した際にこのテスト用のIAMロールをキーポリシー、キーユーザーに登録していました。

テストが終わり、本番用のIAMロールを作成しようとして勘違いな行動をしました。

必要なロール、今回はKMSを使うのでKMSのサービスにアクセスするためのポリシーを
アタッチしたロールを作り、IAMロールをアタッチし直して、APIにリクエストを投げてみました。
すると案の定動きません。
色々なポリシーをアタッチし直し、試しますが一向に動きません。
キーポリシー、キーユーザーにロールを登録していないからです！

最終的にはテスト用のIAMロールと同じ設定にして確認するまでしましたが、
当たり前ですが、動きませんでした。
そもそも、テスト用のIAMロールにKMS関連のポリシーがアタッチされていないのに
動いていたことに気づいておらず、そこに気づくまでにだいぶ遠回りをしてしまいました…。


## まとめ
・KMSのカスタムキーをアプリケーション内の暗号化/復号で使える。
・Lambdaで使用する際はIAMロールをKMSで作ったキーのキーポリシー、キーユーザーに登録する。
・カスタムキーを使ってencypt/dectyptのAPIを呼び出すなどのポリシーはキーポリシーに記載する。
・KMS関連のAWS管理ポリシーはキーの利用権限などとは関係ない。

今回のことで自身が学んだこととしてはこんなことかなと思います。
初心者だとおもいもよらぬところで躓いてしまいますが、メモとして残しておきます！
Laravel: Redisにjobを任せるときのTips

サーバーで重い処理を連続して行う際、Redisのqueueに突っ込んでバッチ処理させる時がたまにあります。
毎回queueとかredis-cliとか忘れるのでここにまとめます。

随時更新します。

# queue:workerの起動
artisanコマンドでqueueに溜まったjobを実行できる。
--queue=で動かしたいqueueを指定しないと動かない。
--daemonはワーカーを常に起動しておくことで再起動によるCPU利用率を下げることができる。パフォーマンスが良い。
--timeoutは実行時間
```bash
$ php artisan queue:work --daemon --queue=mail,alert,default --tries=3 --timeout=0
```

ただ、jobのコードを変更した時などは変更の反映のために、<b>ワーカーを再起動</b>する必要がある。
ここらの処理はsupervisorを入れると自動で制御してくれる。

# redis-cli
コマンドラインからRedisにアクセスできる。
```bash
$ redis-cli
```

### jobの取得
Redisはkey-value型のNoSQLであるのでkeyを指定することで値を取得できる。
```bash
# keyを全て表示する
$ keys *
# 1) "hoge_id"
# 2) "Job\Hoge"

# keyの型を知ることができる
$ type hoge_id    # string
$ type "Job\Hoge" # hash

# 値を取得。型によって取得コマンドが違う。
$ get hoge_id        # 1
$ hgetall "Job\Hoge"
# 1) "throughput"
# 2) "52"
# 3) "runtime"
# 4) "100.0101"
```

### jobの削除
特定のqueueやjobのデータを消したい時
```bash
$ del <消したいqueueの名前>
```

全てのデータを削除したい時。
*ログイン情報など重要なキャッシュも消してしまうので使う際には注意が必要。
```bash
$ flushdb
```

# jobの作成方法
Laravel側でdispatch()してあげれば良い。HogeJobのhandler()が呼び出されます。
```php
dispatch((new Job\HogeJob())->onQueue('Hoge'));
```


# コマンド参考
https://blog.eiel.info/blog/2014/08/26/remember-redis/
静的サイトジェネレーター「Astro」を軽く調べて立ち上げてみた

## Astroとは？
https://twitter.com/FredKSchott/status/1402351702708080640?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1402351702708080640%7Ctwgr%5E%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fengineer.ashita-team.com%2Fentry%2Ftest-astro

---
直訳
>🚀 Astro紹介：新しいタイプの静的サイトビルダー
⚡️ React、Preact、Svelte、Vueで動作する
⚡️ Astroはすべてを静的なHTMLにレンダリングする
⚡️ 結果：デフォルトでJSは0バイト
⚡️ インタラクティブなコンポーネントをオンデマンドで読み込む
---

特に気になるのは
>⚡️ Astroはすべてを静的なHTMLにレンダリングする
⚡️ 結果：デフォルトでJSは0バイト
⚡️ インタラクティブなコンポーネントをオンデマンドで読み込む

ですかね。
今回は実際にローカルで立ち上げてみるまでの手順公開のため、この恩恵を明示できないのですが... :sweat_drops: 

---

https://astro.build/

Astroは2022/03/05現在で公開されている最新のバージョンは0.10.14とBeta版のようです。

---


## 前提
```
$ node -v
v16.14.0
$ npm -v
8.3.1
$ yarn -v
1.22.17
```

---
## 叩くコマンド（以下yarnで実行）
1. npm init astro
1. yarn install
1. yarn start

以上

---
## 実行手順
1. npm init astro

テンプレート選択
色々あるみたいですが、とりあえず起動してみたいだけですので「Starter Kit (Generic)」を選択します。

```
$ npm init astro

Welcome to Astro! (create-astro v0.7.1)
If you encounter a problem, visit https://github.com/withastro/astro/issues to search or file a new issue.

> Prepare for liftoff.
> Gathering mission details...
? Which app template would you like to use? › - Use arrow-keys. Return to submit.
❯   Starter Kit (Generic)
    Blog
    Documentation
    Portfolio
    Portfolio Svelte
    Minimal
```

---

フレームワーク選択
（今回こだわりはないので）一番上の「PReact」を選択します。 
```
? Which frameworks would you like to use? ›
Instructions:
    ↑/↓: Highlight option
    ←/→/[space]: Toggle selection
    a: Toggle all
    enter/return: Complete answer
◯   Preact
◯   React
◯   Solid
◯   Svelte
◯   Vue
```
---

Next stepsに`git init`も入っていますが、今回はスルーで。
```
> Copying project files...
✔ Done!

Next steps:
  1: npm install (or pnpm install, yarn, etc)
  2: git init && git add -A && git commit -m "Initial commit" (optional step)
  3: npm run dev (or pnpm, yarn, etc)

To close the dev server, hit Ctrl-C

Stuck? Visit us at https://astro.build/chat
```

---
&#50;. yarn install
warningが出ているけど、へーきへーき！()

```
$ yarn install
yarn install v1.22.17
info No lockfile found.
[1/4] 🔍  Resolving packages...
warning astro > @astropub/webapi@0.10.14: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
warning astro > @astrojs/language-server > vscode-emmet-helper@2.1.2: This package has been renamed to @vscode/emmet-helper, please update to the new name
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
✨  Done in 24.31s.
```

---
&#51;. yarn start
準備ができたので提示された`http://127.0.0.1:3000/`にアクセスしてみます。

```
$ yarn start
yarn run v1.22.17
$ astro dev
18:07 [astro] Server started                               113ms
18:07 [astro] Local: http://127.0.0.1:3000/

```

---
無事立ち上がりました！
![スクリーンショット 2022-03-05 18.09.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1830441/ce2d1a12-d4ca-886a-be2c-1112483d7c46.png)


---
## おわりに
このような静的サイトジェネレーター（ビルダー）は他にも色々あり、結局どれがいいの？どれが自分・プロジェクトに合っているの？と迷うかもしれません :cry: 

---
ですがご安心を... :smile:
なんと各種静的サイトジェネレーターとの比較まで公式ドキュメントにまとまっているではありませんか！
百聞は一見にしかず...。
と言うことで行ってらっしゃい！（投げやり）

https://docs.astro.build/ja/comparing-astro-vs-other-tools/
ボトルの残量を推定する

| 満タン | 半分 | 空 |
|:-:|:-:|:-:|
| ![PXL_20220305_080759247.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/8e50b4b0-2d88-5d5c-9b09-8437c9907376.jpeg) | ![PXL_20220305_081005143.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/8cf6759f-5ab1-4b39-0d58-7bc397cf009a.jpeg) | ![PXL_20220305_081249946.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/97b7ce82-e880-c964-0b81-419523b19a2d.jpeg)  |

<p class="codepen" data-height="813" data-default-tab="result" data-slug-hash="VwrRYoM" data-user="04" style="height: 813px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/04/pen/VwrRYoM">
  Bottle Water Remaining</a> by John Doe (<a href="https://codepen.io/04">@04</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

TeachableMachineで液体の残量を推定してみました！降水量やハムスターの水の残量などに使えるかも

# 作り方

### 画像プロジェクトを選択

![Screenshot from 2022-03-05 17-21-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/24471500-2010-c66a-ce0e-8f53d9080a7a.png)


### 標準を選択

高速処理する場合は、埋め込み型

![Screenshot from 2022-03-05 17-21-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/112643b8-565e-9f9d-b39e-5f4afb03cde6.png)

### 画像をアップロードして `トレーニングする` をクリック

![Screenshot from 2022-03-05 17-22-47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/542b32cf-7591-e1d3-2294-8e8df76ab9df.png)

### 精度を確認
100%正解です！

![Screenshot from 2022-03-05 17-24-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/bc5d46d0-db2c-2e8a-850f-9735c688aa05.png)

![Screenshot from 2022-03-05 17-24-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/b4ccd9da-eac9-501b-2903-ceb0a1b48e03.png)

### ネットから画像を拾ってテスト

#### Sample1

![ba39a66c4b0001cf02725bf2b4531bc5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/57a73046-cf2a-f64a-251a-8a4b51a7d3e9.jpeg)


![Screenshot from 2022-03-05 17-26-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/afa15bce-0fa6-9085-f57d-4863b0d51e2c.png)

#### Sample2

![emptyBottle.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/83874bda-d578-97ae-a9d8-55a0615126ee.jpeg)


![Screenshot from 2022-03-05 17-29-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/17baaa40-f010-5a4c-a1be-862979dd66be.png)

#### Sample3

![20200227_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/39f63841-181e-f803-8384-a6452ecbb2a8.jpeg)


![Screenshot from 2022-03-05 17-25-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/b16afecd-b4b3-0457-99cf-46499bd8a4a6.png)



### デプロイ

モデルをアップロードしてHTMLをCodepenなどに貼り付けましょう

![Screenshot from 2022-03-05 17-30-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/97ab563b-c399-9a8e-dfda-3d962b2c52cc.png)

### データセット
https://drive.google.com/file/d/1IKZUOWAPF33n0vkA7CjgDntyFfeaR47C/view?usp=sharing
もう迷わないFIFO/LILO/FILO/LIFO

## はじめに
キューとスタックは格納したデータの取り出し方に特徴をもつデータ構造である。
詳しくは割愛。以下はキューとスタックに詳しい記事。

https://qiita.com/drken/items/6a95b57d2e374a3d3292

その取り出し方からキューについて`FIFO`(First-In, First-Out)または`LILO`(Last-In, Last-Out)、スタックについて`FILO`(First-In, Last-Out)または`LIFO`(Last-In, First-Out)と呼ぶことがあるが、

**「キューってFIFO, LILOどっちだっけ？」**
または
**「スタックってFILO, LIFOどっちだっけ？」**

と混乱してしまうことがしばしばある。
同じことで何度も迷いたくないので、FIFO/LILO, FILO/LIFOのそれぞれ、どちらを使うべきかについて本記事で結論を出したい。

## アプローチ
下記2つの方法で調査し、その結果を総合して判断する。
1. 辞書の記載を調査する
1. 技術記事で使われる頻度を調査する

## 1. 辞書の記載を調査する
各ワードが辞書にどう記載されているかを確認するため、IT用語辞典で検索した。
結果、以下のページがヒットした。

> FIFOとは、複数の対象を取り扱う順序を表した用語で、最初に入れたものを最初に取り出す（先に入れたものを先に出す）方式のこと。

https://e-words.jp/w/FIFO.html

> LIFOとは、複数の対象を取り扱う順序を表した用語で、最初に入れたものを最後に取り出す（先に入れたものを後に出す）方式のこと。会計の分野では「後入先出法」と呼ぶ。

https://e-words.jp/w/LIFO.html

ページが存在するのはFIFO, LIFOで、LILO, FILOはそれぞれの別名として記載されている。つまり、例えばキューはFIFOと呼んでもLILOと呼んでも問題ないということのようだ。
しかし、FIFO, LIFOだけが立項されているということは、何か優先度の違いがあるのかもしれない。

## 2. 技術記事で使われる頻度を調査する
技術記事で使われる頻度が多い方が、技術者に受け入れられているワードであると推測できる。各ワードについてQiitaで検索し、ヒットした記事数を記録した。

|ワード|検索ヒット数|
|--|--|
|FIFO|957|
|LIFO|243|
|FILO|39|
|LILO|33|

(2022/3/5時点の検索結果)

どのワードも使われている記事は存在するが、その頻度には差がある。
結果を解釈するために2種類の観点でマトリクスを作成する。

### Inの表し方に注目したマトリクス
|データ構造 \ Inの表し方|First-In|Last-In|
|--|--|--|
|キュー|957|33|
|スタック|39|243|

キューでよく使われるのは**First-In**、スタックでよく使われるのは**Last-In**である。

### Outの表し方に注目したマトリクス
|データ構造 \ Outの表し方|First-Out|Last-Out|
|--|--|--|
|キュー|957|33|
|スタック|243|39|

キュー、スタックに共通して**First-Out**がよく使われ、**Last-Out**はあまり使われない。
「In」よりも「Out」の違いの方が、使用頻度に強く影響しているといえる。

## 考察
1で辞書の記載を確認した結果では、キューはFIFO, スタックはLIFOが立項されていた。
2でQiitaの記事数の調査では、**First-Out**がよく使われる傾向にあることが分かった。
両者の結果は一致したが、この結果について**データ構造のどんな特徴に興味があるのか**で考えれば説明できるのではないだろうか。

各ワードの興味とは、
First-Inなら「最初に入れたデータがいつ取り出されるのか」
Last-Inなら「最後に入れたデータがいつ取り出されるのか」
First-Outなら「次に取り出されるのはいつ入れたデータか」
Last-Outなら「最後に取り出されるのはいつ入れたデータか」
というところにある。どの見方で考えてもキューやスタックの特徴を表すことはできるが、実際にキューやスタックを使う場面を考えると、「次に取り出されるのはいつ入れたデータか」で考えるのが最も自然だと思われるため、First-Outがよく使われるのではないだろうか。

## まとめ
FIFO/LILO, FILO/LIFOはどちらを使ってもよいが、First-Out(次に取り出されるのはいつ入れたデータか)に注目するのが自然と考えて

**キューはFIFO　スタックはLIFO**

を使えば、大勢の感覚に合っているといえよう。
Dockerってなんで使うの？メリットは？

# Dockerってなんで使うの？
プログラミングを始めたばかりの人や、実務経験がない方は同じ疑問を持っていると思います。
僕も同じく、実務を始めるまでは、Dockerを使う理由やメリットが分かりませんでした。
**「ただめんどくさいだけじゃない？」**
こんな感じでした。
しかし、いざ実務でDockerを使うと、最初はコマンドや仕組みを覚えることが面倒ですが、どんどんDockerの凄さを実感します。
そこで、以下では僕が感じたメリットについて書きます。
**Dockerのコンテナやイメージというような言葉は使いません。**
**そのため、知っている人は「これはコンテナのことだな」のように考えて読んでみてください。**

# Dockerを使うメリット

## データやプログラムを分けられる
これはDockerの性質でもあり、メリットとも言えます。
これを読んでも、初心者や未経験の場合は
**「分けられるからどうしたの？」**
となりますよね。
では、想像してください。
就職・転職に成功して、A社で働くことになり、あなはそのA社で2つのプロジェクトに関わることが決まっています。
しかし、各プロジェクトで開発環境が異なります。
さて、あなたはどうしますか？
初心者や未経験の8割以上は、パニックですよね。
そこで、Dockerを使うことで、開発環境を分けられます。
このように、個人開発では気にする必要がなかったことでも、どこかの組織に入ると気にする必要が出てくるものがあります。
**Qiitaの個人開発の記事を見ると、Dockerを使っている人を見かけることがありますが、ほとんどの初心者は使っていません**

## 他人と同じ開発環境にできる
これも個人開発ではあまりに気にする必要がないことです。
まず前提として、チームで開発する場合は、開発環境を同じにする必要があります。
それはそうですよね、**AさんはRubyのバーションが3.1.1だけど、Bさんは2.6.9を使っています**だと、一緒に開発できないですよね。
**では、どのようにその開発環境を同じにしますか？**
わざわざ集まって、「これのバージョンはこれで...」のように話し合うのは面倒ですよね。
そこで、Dockerの機能を使うと、全員同じ環境に設定できます。
上記でデータやプログラムを分けられると書きましたが、その分けたものを他の開発者に配ることができます。
それによって、チーム全員が同じ開発環境に設定でき、また、関わるプロジェクトによって、開発環境を変えることで、スムーズに開発できます。

## 環境を汚さない
開発マシンにミドルウェアを入れていくと、把握していない依存ライブラリがインストールされます。
そのときはOKかもしれませんが、後々、依存ライブラリが原因で、新しいものをインストールできなくなる可能性があります。
そこでDockerを使うと、ローカル環境を汚さずに、インストールできます。
なぜの部分に関して知りたい場合は、Dockerの仕組みについて調べてみてください。
ここでその話を書くと、本の1章分ぐらい必要ですので。

# まとめ
Dockerを使うメリットは、以下の通りです。
- データやプログラムを分けられる
- 他人と同じ開発環境にできる
- 環境を汚さない

もし「こんなメリットもある！」「逆にこんなデメリットも存在するよ」「ここ間違ってるよ」などがあれば、コメントで教えてください。
Red Hat Enterprise Linux 8 でタイムゾーンをCSTからJSTに変更する

検索して、Red Hat Enterprise Linux7 の情報だったが、以下のURLに記載している流れで変更できた
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/chap-configuring_the_date_and_time

[root@db01 ~]# date
Sat Mar  5 02:16:42 CST 2022
[root@db01 ~]# timedatectl list-timezones | grep Tokyo
Asia/Tokyo
[root@db01 ~]# timedatectl set-timezone Asia/Tokyo
[root@db01 ~]# date
Sat Mar  5 17:21:17 JST 2022
[root@db01 ~]#
Firebase CLIでorganization repositoryに対してのgithub actionが設定できない


Firebase CLI(firebase-tools)を使ってレポジトリのセットアップをするときに、下記のセクションでハマったので備忘録です。

```bash
For which GitHub repository would you like to set up a GitHub workflow? 
```

## 現象

Firebase hostingの設定を行いたいときには、下記のようなコマンドを実行します。

```bash
$ firebase init hosting:github # firebase initをしてにもhostingの設定を選択した場合と等価
```

このセクションで何度入力してもエラーも発生せずに、先にも進めないということが発生し、ハマりました。

```bash
For which GitHub repository would you like to set up a GitHub workflow? 
```

### (ちなみに)debug方法

下記のようにFirebase CLIのコマンドに `--debug` をつけることで詳細なログが得られるのは豆知識です。

```
$ firebase init hosting:github --debug
? For which GitHub repository would you like to set up a GitHub workflow? (format: user/repository) (xxxxxxxxx/xxxxxxxxxx)
[2021-xx-xxTxx:xx:xx.xxxZ] >>> [apiv2][query] GET https://api.github.com/repos/****/****/actions/secrets/public-key type=owner
[2021-xx-xxTxx:xx:xx.xxxZ] <<< [apiv2][status] GET https://api.github.com/repos/phorward-org/phorward.org/actions/secrets/public-key 403
[2021-xx-xxTxx:xx:xx.xxxZ] <<< [apiv2][body] GET https://api.github.com/repos/phorward-org/phorward.org/actions/secrets/public-key {"message":"Must have admin rights to Repository.","documentation_url":"https://docs.github.com/rest/reference/actions#get-a-repository-public-key"}
? For which GitHub repository would you like to set up a GitHub workflow? (format: user/repository) (xxxxxxxxx/xxxxxxxxxx)
```

## 原因&解決策

下記のIssueチケットで同様の問題に遭遇している方がいて、原因と解決策がわかりました。

Cannot Initialize Github Actions on Organization Account · Issue #3143 · firebase/firebase-tools https://github.com/firebase/firebase-tools/issues/3143

![Cannot_Initialize_Github_Actions_on_Organization_Account_·_Issue__3143_·_firebase_firebase-tools.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127651/c30a848f-b2d9-d007-4bc7-d7c475d6dd57.png)

Organizationの下のRepositoryに対して、setupを行う際には「自分のアカウントから組織のアカウントへの権限付与」が必要です。このIssueチケットのコメントにあるように設定を行います。

`profile settings -> Applications -> "Authorized OAuth Apps" tab -> Click on Firebase CLI -> Organization access` 

Settingsページ([https://github.com/settings/profile](https://github.com/settings/profile))にアクセスして、Applications
を選び、さらにタブでAuthorized OAuth Appsを選びます。Firebase CLIがあるはずなのでそれをクリックします。

![Authorized_OAuth_Apps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127651/20ce43d5-b42e-dff1-fa4b-35f7b45a5210.png)

今自分が設定しようとしているOrganizationが表示され ❎ が付いていると思います。「Grant」ボタンを押して権限を付与しましょう。

![Connection_with_Firebase_CLI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127651/bb367b01-0b80-764a-ac7c-be915288b352.png)

これで自分は動きました。以上です。
WEBクローラー・Octoparseについての備忘録

# 対象読者
- WEBサイトから多数の情報を取得したいけどコード書いてスクレイピングするの面倒という人
- Octoparseの使い方が全く分からないという人

何度か地道にコードを書いてスクレイピングを行って「WEBサイト毎にコードを書くのがさすがに面倒！」と思った際に出会ったWEBクローラー・octoparseに関しての備忘録です．

# スクレイピング？クローラー？
### スクレイピングとは
- 主にAPIが用意されていないサイトの情報を取得する際に使用
- HTML等の人間が直接読むのに適さないデータ群から必要な情報だけを抽出する際に用いられる技術

### octoparseとは
- スクレイピングがものすごく簡単にできるWebクローラーの一つ
- 人間の操作をシュミレートすることで複雑な操作も自動化
- 静的，動的どちらのWebサイトにも対応
- 無料版でも十分な機能が搭載

# スクレイピングを行う前に
- クローリングが禁止されていないサイトか確認
    - サイトのルートディレクトリに用意されている「robots.txt」ファイルを確認し，以下のように書かれている場合は「サイト全体でクローリングしないで」という意思表示なのでクローリング，スクレイピングを行わない．
    ```
    User-agent: *
    Disallow: /
    ```
    - HTML内に以下のような「robots metaタグ」が書かれている場合も「このページ内のリンクをたどらないで」という意思表示なのでクローリング，スクレイピングを行わない
    ```
    <meta name="robots" contest="nofollow">
    ```
- 著作権違反していないか確認
当たり前ですがスクレイピングが大丈夫だからと言ってフリーではないので使い方に注意

# 基本的な使い方
## スクレイピングしたいWebサイトを指定する 
1. ホーム画面からカスタマイズモードの+タスクを選択
2. Webサイトの欄に，データを抽出したいWebサイトのページのURLを張り付け，保存
## データを抽出する
1. 張り付けたURLのページが表示されるため，欲しい部分をクリック(まとめて選択することも可能)
    - 同じ系統の情報は，2つ以上クリックすると勝手に全部選択してくれる．
2. 「リンクのテキストを抽出」をクリックするとループアイテムが作成される
### 複数のリンクの中身が欲しい場合
1. データが欲しいページのリンクの一覧があるページで全てのリンクを選択
2. 「各URLをループクリックする」を選択するとループアイテムが作成され，ページが切り替わる
3. 抽出したいデータをクリックし，「データを抽出する」をクリックすると，ループアイテム内に「データを抽出する」が現れる

## 複数ページにまたがってスクレイピング
### ページネーションに矢印がある場合
1. サイトの下の方に行き，ページをめくるリンク(ページネーション)があることを確認する
2. ページネーションに次のページに行く矢印や「次へ」等がある場合，それをクリックして「選択したリンクをループクリックする」をクリックするとページネーションアイテムが作成される
3. ページネーションアイテム内にデータ抽出を行うアイテムを入れることで複数ページに渡ってデータを抽出することが可能
### ページネーションに矢印がない場合
1. 上記の矢印がある場合と同じ手順でページネーションアイテムを作成する
2. アイテム内の単一要素のXpathを以下のように変更する
    1. データを抽出したいページのソースを開いて，ページ番号を表しているコードを探す 
    ```
    <div class="paginator section">
        <span class="count">110,230</span>
        <span class="unit">件</span>
        <span class="current">1</span><span><a href="/novel/index?sort=total&amp;limit=120&amp;page=2&amp;direction=desc">2</a></span><span><a href="/novel/index?sort=total&amp;limit=120&amp;page=3&amp;direction=desc">3</a></span>
    ```
    2. 上記の場合，classを目印にして以下のようにXpathを記述することで複数ページのスクレイピングが行える
    ```
    //span[@class='current']/following-sibling::span/a
    ```


## 抽出したくないデータをはじく
1. アイテム「データを抽出する」をクリックすると右側にトリガーという欄が現れるので，そこをクリック
2. 「新しいトリガーを作成する」をクリックして，トリガー名を設定
3. 「もし」の下のボタンを選択すると抽出するフィールドが全て表示されるので，条件を追加したいフィールドを選択
4. 鉛筆マークの横のボタンで条件を指定
5. 複雑な条件を付けたい場合も「[AND]条件を追加」もしくは「[OR]条件を追加」ボタンで条件を追加
6. 最後に画面下部の「このデータを破棄する」ボタンから条件に合った場合どうするかを選択する 
7. 抽出データを成形して判定を行いたい場合は，以下の手順で行うことができる
    * 抽出データから数字のみを抜き取りたい場合
7.1. トリガーを編集する画面で鉛筆マークをクリック
7.2. フィールド編集画面でステップを追加するをクリックし，正規表現で置き換えるをクリック
7.3 正規表現の欄に数字以外を表す[^0-9]を入力し，計算するをクリックし，数字だけ出力できていれば成功

# 引用
https://www.octoparse.jp/
AWS上でADを構築する個人メモ

AWS上でADを構築してみる

はじめに
--
ADの構築は簡単と聞きますが、本当にそうなのでしょうか？
また、家で試しにADを１台立てみるのはどうすればいいのでしょうか？
その疑問を解決するべく、探検隊（私）はAmazonの奥地へ向かった。

AWSのアカウント作成
--
下記リンクを参照に頂きながらアカウントを作成します。
参照しなくとも、そこまで難しい内容ではないのでノリで作成もできます。

https://aws.amazon.com/jp/register-flow/

AWS上でサーバの作成
--
①AWSのコンパネを開くとインスタンスの起動画面が出てきますのので、
「インスタンスを起動」を選択します。

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/7ef2444b-4243-6535-ee3a-6faff4a1e347.png">

②「無料利用枠のみ」にチェックを入れて、「Microsoft Windows Server 2019 Base 」を選択。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/9b398584-54c7-0c31-7d51-4c300cf5bfe7.png">

③「t2.micro」を選択します
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/68efa004-23dc-8ab0-dfe0-85aa25659b87.png">

:::note warn
警告
1vCPU/1memなので、Windows の関係で動作がもさもさしてイライラするかもしれないです。
必要に応じて、2vCPU/4memぐらいの品目を選択してください
:::

まだ作成しないで、次のステップを選択します。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/4fac1008-28a2-015c-aafd-3e0e1bd63c79.png">

③ネットワーク周りを設定します。
　ADはプライベートIPを固定で振っておいたほうがいいので、今回は192.168.1.0/24を振ります。
・ADのI/Fのアドレスは、192.168.1.10
・自動割り当てパブリック IP　”有効”　【**あとから設定できないので注意**】
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/ff5b9d8c-ab03-be23-e2c0-bc92ae2bcd80.png">

④セキュリティグループ周りの設定
　SGは責任取れないので、よし何に設定してください。
　RDPを自分の家のGIPアドレスからのみ許可するのをお勧めします。

⑤インスタンスの作成

⑥WindowsSVにログイン
インスタンスを開き、対象仮想サーバの「接続する」から仮想マシンのパスワードが取得できます。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/33a5cb47-c599-1174-92f9-a0414988d335.png">

パブリック IPv4 アドレスを自分のPCからアクセスします。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/5243619b-e599-f1d7-7c4f-a6767365952e.png">

作成完了！
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/dfe68ea2-08ad-6924-ff8b-4331da2464fd.png">

:::note info
TIPS
ドメイン参加させる用のWindowsSVを同じ手順でもう1台作成してください。
また、作成したADと同じサブネットに追加してください。
:::

AD構築前に準備
--
①日本語化します
NICの帯域の問題と思いますが、謎に時間かかりました。

https://zenn.dev/supersatton/articles/807635bdb0a85b

②念のため設定を確認します
```cmd:PowerShell
$ipconfig
$hostname
```

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340199/f1001f41-c60b-fffd-2139-90270a1eb986.png">

ADの構築
--
ブログにあるまじき丸投げですが、作ったことなかったので下記記事を参考にしました。

https://www.aibsc.jp/joho/otasuke_m/clientserver/03/01.html

逆引きDNSの設定は、上記リンクの内容だとうまくいかなかったので、下記リンクを参照しました。

https://tamnology.com/win004/

ADの昇格とDNSの設定が完了したら、OUとユーザを作成します。

https://www.aibsc.jp/joho/otasuke_m/clientserver/04/01.html

クライアントのドメイン参加
--
ドメインに参加させるクライアント（今回は、AD以外に１台WindowsSVを作成してます）
からの参照先DNSをAD(今回は192.168.1.10に向けます)

その後、下記リンクの通り実施すれば参加可能です。

https://www.aibsc.jp/joho/otasuke_m/clientserver/05/02.html

ドメイン参加出来れば完了です。
ただ、私の環境だとインターネット経由でADがRDPできなくなりました。
現在格闘中です。
[Flutter] FlutterFire Package ChangeLog まとめ - 220305 

よく変わっているFlutterのFirebaseパッケージの履歴をまとめてみたいです。

# 1. Analytics
## firebase_analytics 
- https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_analytics/firebase_analytics

## 9.1.2

 - **FIX**: update all Dart SDK version constraints to Dart >= 2.16.0 (#8184). ([df4a5bab](https://github.com/FirebaseExtended/flutterfire/commit/df4a5bab3c029399b4f257a5dd658d302efe3908))

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137182/b343ad4f-16a0-3725-17c8-3c4593d71929.png)

# 2. Authentication

## firebase_auth 
- https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_auth/firebase_auth

## 3.3.9

 - **FIX**: update all Dart SDK version constraints to Dart >= 2.16.0 (#8184). ([df4a5bab](https://github.com/FirebaseExtended/flutterfire/commit/df4a5bab3c029399b4f257a5dd658d302efe3908))

# 3. Cloud Firestore

## cloud_firestore 
- https://github.com/FirebaseExtended/flutterfire/tree/master/packages/cloud_firestore/cloud_firestore

## 3.1.10

 - **FIX**: update all Dart SDK version constraints to Dart >= 2.16.0 (#8184). ([df4a5bab](https://github.com/FirebaseExtended/flutterfire/commit/df4a5bab3c029399b4f257a5dd658d302efe3908))

## 3.1.9

 - Update a dependency to the latest release.


# 3. Cloud Storage

## cloud_firestore 
- https://github.com/FirebaseExtended/flutterfire/tree/master/packages/cloud_firestore/cloud_firestore

## 3.1.10

 - **FIX**: update all Dart SDK version constraints to Dart >= 2.16.0 (#8184). ([df4a5bab](https://github.com/FirebaseExtended/flutterfire/commit/df4a5bab3c029399b4f257a5dd658d302efe3908))

## 3.1.9

 - Update a dependency to the latest release.


# 4. Core

## firebase_core  
- https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_core/firebase_core

## 1.13.1

 - **FIX**: update all Dart SDK version constraints to Dart >= 2.16.0 (#8184). ([df4a5bab](https://github.com/FirebaseExtended/flutterfire/commit/df4a5bab3c029399b4f257a5dd658d302efe3908))

## 1.13.0

 - **FEAT**: refactor error handling to preserve stack traces on platform exceptions (#8156). ([6ac77d99](https://github.com/FirebaseExtended/flutterfire/commit/6ac77d99042de2a1950f89b35972e3ee1116dc9f))

# 5. Crashlytics

## firebase_crashlytics 
- https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_crashlytics/firebase_crashlytics

## 2.5.3

 - **FIX**: update all Dart SDK version constraints to Dart >= 2.16.0 (#8184). ([df4a5bab](https://github.com/FirebaseExtended/flutterfire/commit/df4a5bab3c029399b4f257a5dd658d302efe3908))

## 2.5.2

 - Update a dependency to the latest release.

# 6. Realtime Database

## firebase_database 
- https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_database/firebase_database

## 9.0.8

 - **FIX**: update all Dart SDK version constraints to Dart >= 2.16.0 (#8184). ([df4a5bab](https://github.com/FirebaseExtended/flutterfire/commit/df4a5bab3c029399b4f257a5dd658d302efe3908))

## 9.0.7

 - Update a dependency to the latest release.
【パブリッシャー】レポートを公開してみる

この記事では、**[Sharperlight](https://sharperlight.jp/)パブリッシャー**を使用して、ブラウザでの閲覧可能なレポートを作成し、Sharperlightサービスを利用して公開してみましょう。
通常は、社内ネットワーク内のアプリケーションサーバ―やクラウド上のサーバーにSharperlightがインストールされていて、WEBレポートは社内ネットワーク内に配信されたり、広域ネットワーク上に高度なセキュリティ下で配信されたりします。
ここでは、ローカルPCでサービスを起動し、ローカルPCのブラウザでレポートを閲覧するといった手法で説明します。
## 公開用レポートの作成
Sharperlightアップリケーションメニューから **パブリッシャー**を起動します。
![2022-03-05 Figure 01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/0cac252d-458d-54b5-6aa8-17dedce6b1fc.png)
![2022-03-05 Figure 02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/3d771fad-2ff8-677d-32d0-892eda18b3d3.png)
[新規]ボタンを押して、「レポート公開」ダイアログを表示します。
![2022-03-05 Figure 03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/1a3c1a97-ceec-88bf-090d-56f85a7a6cb6.png)
次のプロパティに値を入力します。
- **コード**: 一意のコードです。このレポートの識別コードとなるので、後で変更の必要のないようにしましょう。
- **グループ**: レポートのグループ化を行うための名前です。レポートの数が多くなる場合に便利です。
- **分類**: グループと同じ働きをします。サブグループといった具合でしょうか。
- **タイトル**: レポートの **パブリッシャー**上でのタイトルです。簡潔なタイトルを入力します。
- **レポートのタイトル**: ブラウザ上に表示されるレポートのタイトルです。

では、[クエリーを編集]ボタンを押して、クエリを作成しましょう。
:bulb:公開するレポートはクエリが定義されていることが必要最低条件です。
![2022-03-05 Figure 04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/65253cf0-4d3d-84cb-ddb7-a52b58bccc8c.png)
このようなクエリを作成しました。
[選択]階層領域から売上日フィールドを[フィルター]領域にドラッグ&ドロップしました。そして[出力]領域には4つのフィールドを設定。
[プレビュー]ボタンを押して動作確認をします。クエリが正常にデータを返すことを確認できれば[OK]ボタンを押して保存します。
![2022-03-05 Figure 05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/dc77d58d-7f1d-98c5-9ac5-cd3157ddca1d.png)
「レポート公開」ダイアログに戻ったら、[オプション]タブに移動し、既定の出力形式が **Table**となっていることを確認します。標準的な表としてブラウザに表示しますよという意味です。[OK]ボタンを押して保存します。
![2022-03-05 Figure 06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/8644a194-9aeb-231b-2ed3-9b04f73a919a.png)
## サービスの起動
Sharperlightサービスには、二通りの起動方法があります。ひとつはSharperlightアプリケーションとして起動する方法、もうひとつはWindowsサービスとして起動する方法です。
![2022-03-05 Figure 07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/2df6f53b-01bf-1e26-270b-e810f2cf4868.png)
![2022-03-05 Figure 08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/3a1bd9d3-71b9-e2be-f593-e51ba791346a.png)
## レポートの閲覧
もう一度、Sharperlight **パブリッシャー**を起動して、先ほど作成したレポートを開きます。
[リンク]タブに移動して、レポートのリンクをコピーします。
![2022-03-05 Figure 09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/3ddf86a2-2e4b-2042-c73f-607c5b02733d.png)
コピーしたリンクをブラウザのアドレスバーに貼り付けてページを更新すると、レポートを閲覧できます。
![2022-03-05 Figure 10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/da73eddb-9558-7b5c-a420-e58d24312a66.png)
プロンプト領域の売上日フィルターに以下のように値を入力し、[送信]ボタンを押します。
![2022-03-05 Figure 11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/69e8dd90-aa90-ed7f-92ba-d7c21634b8cf.png)
作成したレポートがこのように表示されます。
![2022-03-05 Figure 12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/4c9e54a3-b4b6-f84a-d7e1-db7e53f3c91a.png)
:postbox:[お問い合わせ](https://sharperlight.jp/about-us/contact-us/)
ISO-2022-JP（7bit JIS）のeml形式データをApps Scriptで解読する

Google Driveにバックアップしておいたeml形式のメールデータをApps Scriptで読み込んでみました。文字コードがISO-2022-JP（7bit JIS）だったのですが、Apps Scriptの`Utilities`のおかげでいい感じに読めました。

# ISO-2022-JPのeml形式データを読み込むには

生データに`ISO-2022-JP`と書いてあったので、文字コードを`JIS`に指定して読み込みます。

```javascript
const driveUrl = 'https://drive.google.com/drive/folders/...';
const folderId = driveUrl.split('/')[5];
const childFolderName = 'backups'; // driveUrlの下にあるフォルダー名
const fileName = 'a.eml'; // フォルダーの下にあるファイル名 
const file = DriveApp.getFolderById(folderId).getFoldersByName(childFolderName).next().getFilesByName(fileName).next();
const eml = file.getBlob().getDataAsString('JIS');
```

これでメール本文は解読できたのですが、ヘッダーのSubject、From、Toなどにある日本語が読めません。

# ISO-2022-JPのヘッダーを読み込むには

どれも`=?ISO-2022-JP?B?`と書いてあります。`B`はbase64によるエンコードなので、

```javascript
function decodeJis(encoded) {
  return encoded.replace(/=\?ISO-2022-JP\?B\?(.*?)\?=/ig, (a, b) => Utilities.newBlob(Utilities.base64Decode(b)).getDataAsString('JIS'));
}
```

という関数を作って解読しました。こんな風に使います。

```javascript
function test() {
  const encoded = '=?ISO-2022-JP?B?GyRCJDMkcyRLJEEkTxsoQg==?==?ISO-2022-JP?B?GyRCJDMkcyRLJEEkTxsoQg==?=';
  const decoded = decodeJis(encoded);
  console.log(decoded);
  //こんにちはこんにちは
}
```

# ヘッダーを解析するには

かなり力技ですが、ヘッダーを読み込んでオブジェクト形式に変換する関数も作ってみました。車輪の再発明は楽しいですね！

sepはセパレーターです。`\n`の場合と、`\r\n`の場合があります。

```javascript
function parseHeaders(headers, sep='\n') {
  const set = (obj, line) => {
    const sep = ': ';
    const [key, ...values] = line.split(sep);
    const k = key.toLowerCase().replace(/-/g, '_');
    const value = values.join(sep);
    if (obj[k] && Array.isArray(obj[k])) {
      obj[k].push(value);
    } else if (obj[k]) {
      obj[k] = [obj[k], value];
    } else {
      obj[k] = value;
    }
  };
  let line = '';
  const ojb = headers.split(sep).reduce(prev, curr) => {
    if (curr.includes(': ')) {
      if (line) set(prev, line);
      line = decodeJis(curr);
      return prev;
    }
    line += decodeJis(curr);
    return prev;
  }, {});
  if (line) set(obj, line);
  return obj;
}
```

先ほどDriveから取得した`eml`からヘッダーを解析してみます。

```javascript
const eml = ... // 上記
const sep = data.includes('\r\n') ? '\r\n' : '\n';
const [headersPart, ...body] = data.split(sep + sep); // 空行2つがヘッダーとボディーの切れ目
const headers = parseHeaders(headersPart, sep);
console.log(headers);
// { "subject": "...", "from": "...", "to": "...", ... }
```