OmniAICreator/Qiita-1.07M huggingface dataset:
Kotlin KoansでKotlin入門　第４回：Triple-quoted strings

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

過去記事はこちら
- [第０回：Kotlin Koansについて](https://qiita.com/kosuke1/items/41d192af63485bfc8cb8)
- [第１回：Simple Functions](https://qiita.com/kosuke1/items/5862a3ece96082a62e67)
- [第２回：Named arguments](https://qiita.com/kosuke1/items/2af11262852ee41b5da7)
- [第３回：Default arguments](https://qiita.com/kosuke1/items/16cb8ac780df58dc8054)

# 問題
下記コードのテストが通るように修正します。

```Kotlin
const val question = "life, the universe, and everything"
const val answer = 42

val tripleQuotedString = """
    #question = "$question"
    #answer = $answer""".trimIndent()

fun main() {
    println(tripleQuotedString)
}
```
上記を実行するとテストが失敗しました。
```
Fail: testSolution: The margin prefix shouldn't be present in the resulting string 
expected:<[question = "life, the universe, and everything" ]answer = 42> 
but was: <[#question = "life, the universe, and everything" #]answer = 42>
```
結果の文字列に"#"が含まれないように修正します。

# 問題のポイント
便利なライブラリ関数 [trimIndent](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim-indent.html) と [trimMargin](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim-margin.html) を使って、複数行のトリプルクォート文字列をフォーマットすることができます。

- トリプルクォート文字列を使うと改行などのエスケープが必要なくなります。
- [trimIndent](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim-indent.html)はすべての入力行に共通する最小のインデントを検出し、すべての行からそれを削除し、また、最初と最後の行が空白であればそれを削除します。
- [trimMargin](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim-margin.html)はソース文字列の各行から、marginPrefix に続く先頭の空白文字を削除し、最初と最後の行が空白の場合は削除します。marginPrefixのデフォルト値は"|"です。

# 解答例
trimIndent の呼び出しを、# をプレフィックスの値とする trimMargin の呼び出しに置き換えて、結果の文字列に"#"が含まれないようにします。

```Kotlin
const val question = "life, the universe, and everything"
const val answer = 42

val tripleQuotedString = """
    #question = "$question"
    #answer = $answer""".trimMargin("#")

fun main() {
    println(tripleQuotedString)
}
```
Laravel RefreshDatabase 高速化

laravelのRefreshDatabaseが時間がかかるため、高速化したはなし

# 環境
```
laravel: v5.5.50
phpunit/phpunit: 5.7.27
```

# 原因
```:vender/laravel/framework/src/Illuminate/Foundation/Testing/RefreshDatabase.php
//...

    /**
     * Refresh a conventional test database.
     *
     * @return void
     */
    protected function refreshTestDatabase()
    {
        if (! RefreshDatabaseState::$migrated) {
            $this->artisan('migrate:fresh');

            $this->app[Kernel::class]->setArtisan(null);

            RefreshDatabaseState::$migrated = true;
        }

        $this->beginDatabaseTransaction();
    }

//...
```

`$this->artisan('migrate:fresh');` に時間がかかる

データはcleanにしたいけど、migrationを1から実行したくない

# 対応
```:tests/Traits/RefreshDatabaseLite.php
<?php

namespace Tests\Traits;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
use Illuminate\Support\Facades\DB;

trait RefreshDatabaseLite
{
    use RefreshDatabase;

    /**
     * @return void
     */
    protected function refreshTestDatabase()
    {
        if (! RefreshDatabaseState::$migrated) {
            $this->artisan('migrate');

            DB::statement('set foreign_key_checks = 0');

            $tables = DB::connection()->getDoctrineSchemaManager()->listTableNames();

            foreach ($tables as $table) {
                if (in_array($table, [
                    'failed_jobs',
                    'jobs',
                    'migrations'
                ])) {
                    continue;
                }

                DB::table($table)->truncate();
            }

            DB::statement('set foreign_key_checks = 1');

            RefreshDatabaseState::$migrated = true;
        }

        $this->beginDatabaseTransaction();
    }
}

```

`DB::connection()->getDoctrineSchemaManager()->listTableNames();`でテーブル名を全て取得

`laravel`の固有のテーブル`failed_jobs`・`jobs`・`migrations`以外は、
`DB::table($table)->truncate();` でtruncate処理

`DB::statement('set foreign_key_checks = 0');` を実施しないと、
foreign keyの依存関係でtruncateがエラーになります

# 速度比較
* RefreshDatabaseの場合
```
Time: 1.17 minutes, Memory: 36.00MB
```

* RefreshDatabaseLiteの場合
```
Time: 15.1 seconds, Memory: 28.00MB
```

# さいごに
`use RefreshDatabase`しているため、
テストごとにロールバックされてcleanな状態でテストが実施可能です
※ auto incrementの採番は進んでしまうので、id指定でテストしている場合には注意が必要です
【Django/async/await】JavaScriptでfetchなどの非同期処理を含んだループを順番に実行したい

（編集履歴）
|日付  |内容  |
|---|---|
|2022/3/9  |@standard-software さんからのご指摘を受け、状況説明をより詳細にし、これに合わせてタイトルに文言を追加しました。  |
---

djangoを使った開発をしていて、「クライアント側からサーバー側にfetchなどでリクエストを送って、時間のかかる処理が終わるのを待ち、処理完了したら１サイクル終了」といった操作を、指定回数だけ順番に繰り返したい…こんな状況に出くわし、理解の浅い非同期処理を実装するのに右往左往してしまったので備忘録。
fetchを使う理由は、サーバーからのリクエストを受け取るときに、画面を再ロードしなくて済むようにしたいので、非同期処理としています。


簡便ですが開発環境は以下。
django: 3.1.4
OS: windows 10

# 最初にやらかした間違いコード
しょっぱな、「asyncを宣言時につけた関数はPromiseを返してくれる」という文言を見かけて、「じゃあasyncをつけた関数をawaitで待っていれば返り値が来るまで待ってくれるのか…？」と考え、こんなコードを書きました。（大枠だけ示しています）

```javascript:間違いコード
let count = 3;  // 繰り返し回数

func(); // 実行

async function func() {
    // 非同期処理を含んだループ
    for (let i = 0; i < count; i++) {
        await myFunc();            // 処理の完了を待つ
        console.log(`${i+1}回目`); // コメント
    }
}

async function myFunc() {
    fetch('サーバーにリクエストするurl')
    .then((response, reject) => {
        // 時間のかかる処理を実行
        // 処理完了時に目印として「非同期処理終わり」を出力する
    });
}
```
やりたいことと気合は十分伝わってくるコードではあります（たぶん）。
出てきてほしい結果は、
```:期待する結果
非同期処理おわり
1回目
非同期処理おわり
2回目
非同期処理おわり
3回目
```
なわけですが、実際に実行してみると、
```:現実
1回目
2回目
3回目
非同期処理おわり
非同期処理おわり
非同期処理おわり
```
のように、ループ内の`await myFunc()`はほぼ無視してループはどんどん進んでしまいました。


# 非同期処理をループさせる方法
というわけであれこれ調べた結果、最終的には以下のようにして非同期処理全体を`new Promise`として返すことで、思い通りの動作を得ることができました。
```javascript
// ※　myFuncの中身だけ変わっています。

let count = 3;  // 繰り返し回数

func(); // 実行

async function func() {
    // 非同期処理を含んだループ
    for (let i = 0; i < count; i++) {
        await myFunc();            // 処理の完了を待つ
        console.log(`${i+1}回目`); // コメント
    }
}

// 以下変更点
async function myFunc() {
    return new Promise((resolve) => {
        fetch('サーバーにリクエストするurl')
        .then((response, reject) => {
            // 時間のかかる処理を実行
            // 処理完了時に目印として「非同期処理終わり」を出力する
            resolve('返したいものがあれば返す');
        });
    });
}
```


# 参考
以下記事にお世話になりました。
[async await の使い方](https://qiita.com/niusounds/items/37c1f9b021b62194e077)
Blitz.js 迷った時のディレクトリ構成

Blitz.jsを使って開発をしている時に、「このファイルはどこに配置しよーかなー」と悩んだことはないでしょうか？
私は多々あります。主に`utils`か？それとも`services`か？とか。
感覚値で配置場所を決めてたこともあったので、この機会にシンプルにまとめたいと思います。

## 本記事の対象者
- Blitz.jsユーザーでファイルの設置場所に悩むことがたまにある人

## 本記事で解決できること
- ファイルの設置場所で悩む事による時間の無駄遣い


## そして結論
基本的に以下の順序で一考すれば間違いない（と信じてる）

**1. まずは基本に忠実にファイル構成を考える（以下は公式から参照）**

```
├── app/
│   ├── core/
│   │   ├── components/
│   │   │   ├── Form.tsx
│   │   │   └── LabeledTextField.tsx
│   │   ├── hooks/
│   │   │   └── useCurrentUser.ts
│   │   └── layouts/
│   │       └── Layout.tsx
│   ├── pages/
│   │   ├── 404.tsx
│   │   ├── _app.tsx
│   │   ├── _document.tsx
│   │   ├── index.test.tsx
│   │   ├── index.tsx
│   │   └── projects/
│   │       ├── [id]/
│   │       │   └── edit.js
│   │       ├── [id].js
│   │       ├── index.js
│   │       └── new.js
│   ├── api/
│   │   └── stripe-webhook.js
│   ├── auth/
│   │   ├── components/
│   │   │   ├── LoginForm.tsx
│   │   │   └── SignupForm.tsx
│   │   ├── mutations/
│   │   │   ├── login.ts
│   │   │   ├── logout.ts
│   │   │   └── signup.ts
│   │   ├── pages/
│   │   │   ├── login.tsx
│   │   │   └── signup.tsx
│   │   ├── auth-utils.ts
│   │   └── validations.ts
│   ├── users/
│   │   └── queries/
│   │       └── getCurrentUser.ts
│   └── projects/
│       ├── components/
│       │   ├── Project.js
│       │   ├── ProjectForm.js
│       │   └── Projects.js
│       ├── mutations/
│       │   ├── createProject.js
│       │   ├── createProject.test.js
│       │   ├── deleteProject.js
│       │   ├── deleteProject.test.js
│       │   ├── updateProject.js
│       │   └── updateProject.test.js
│       └── queries/
│           ├── getProject.js
│           └── getProjects.js
├── db/
│   ├── index.ts
│   ├── schema.prisma
│   └── seeds.ts
├── integrations/
│   └── sentry.ts
├── public/
│   ├── favicon.ico*
│   └── logo.png
├── test/
│   ├── setup.ts
│   └── utils.tsx
├── README.md
├── babel.config.js
├── blitz.config.js
├── jest.config.js
├── package.json
├── tsconfig.json
├── types.ts
└── yarn.lock
```

**2.  便利かつどちらかと言えば複雑度低めな関数（処理 ex.文字列の加工など）なら**`/utils`**フォルダへ、どちらかと言えば複雑度高めなら**`/services`**フォルダへ**

**3. 深くネストしないような構成で考える（相対パスを使ったインポートが面倒 + ファイルが移動したときにそれらを更新するのも大変）**

**4. それでもしっくり来ないなら、よく一緒に変更するファイルを近くに置いておく！**

公式からのサンプルに追記すると、以下のような構成にすれば個人的にはネストも深くせずにシンプルになるのではないでしょうか。

```
│   ├── users/
│   │   └── queries/
│   │       └── getCurrentUser.ts
│   │   └── services/   <----
│   │       └── serviceExample.ts
│   │   └── utils/   <----
│   │       └── utilsExample.ts
```

Blitz.jsの公式ページには以下記載があることからも、迷った場合はよく一緒に変更するファイルに記述すれば確実かもしれないですね。

> Guiding Principles
> 
> - Files that change together should live together.（一緒に変更されるファイルは一緒に配置しましょう）
> - Minimal requirements, maximum flexibility.（最小の用件を、最大の柔軟性で）

## 余談
「一緒に変更されるファイルは一緒に配置しましょう」という考え方・原則は「コロケーション」と呼ばれます。コロケーションスタイルは、「Done is better than perfect.（完璧であることより、まず終わらせることが重要だ）」で有名なザッカーバーグ氏の思想を反映させたようにも感じますよね。
【SwiftUI】オブジェクトがキーボードに隠れないように簡単実装

# 地味に面倒臭いキーボードに隠れないようにする処理
UIKit、SwiftUIに限らず開いたキーボードにUIが隠れないようにする。当たり前だけど、地味にめんどくさい実装ですよね。
キーボードの開閉タイミングを通知したり、ScrollViewを任意の場所にスクロールさせたり、いろんなやり方が状況によってあると思いますが、今回はSwiftUIで　**Spacer()と可変frame**　を利用して、通知やイベント処理を使用せずにキーボードにUIが隠れないように実装する方法を紹介します。

# Spacer()と可変frameを使用して実装
実装方法は簡単でVStackで表示したいオブジェクトとSpacer()を囲み、オブジェクトに対して可変frameを設定するだけでできます。
ここで言う可変frameとはオブジェクトの最低値、理想値、最大値のCGRectを設定できるもののことを指します（今回は理想値は利用していません）。ここに任意の値を設定することで、画面の状態によってオブジェクトが最低値まで小さくなったり、最大値まで大きくなったりします。
次にSpacer()ですが、これはSpacer()が含まれているスタックレイアウトに沿って可能な限り広がるオブジェクトです。つまりこれをVStackで利用したりすると、縦軸に沿って他に設定されているオブジェクトの隙間を埋めるまで広がります。そのためオブジェクトの下に設置した場合には、オブジェクトを上に押しつける形になります。
この２つの特性を生かして下記のように実装することで、キーボード出現時にSpacer()により押されて、TextEditorがキーボードの高さ分低くなり、キーボードに隠れないように表示することができます。

```swift
import SwiftUI

struct TextEditorView: View {
    @State var text: String

    var body: some View {
        GeometryReader { geometry in
            VStack(alignment: .center) {
                TextEditor(text: $text)
                    .frame(minWidth: 0, maxWidth: geometry.size.width, minHeight: 0, maxHeight: geometry.size.height, alignment: .center)
                    .onTapGesture {
                        UIApplication.shared.closeKeyboard()
                    }
                Spacer()
            }
        }
    }
}

```
AWS EC2 nvmを用いてNode.jsをインストールしてnpmコマンドを実行できるようにする

## 概要

- EC2のAmazonLinux2インスタンスにnvmを入れてNode.jsをインストールしnpmコマンドを実行できるようにする方法をまとめる。

## 方法

1. EC2にssh接続を行い下記コマンドを実行してnvmをインストールする。

    ```terminal
    $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
    ```

1. 下記コマンドを実行してnvmを有効化する。

    ```temrinal
    $ . ~/.nvm/nvm.sh
    ```

1. 下記コマンドを実行してNode.jsのインストール可能バージョン一覧を出力する。

    ```terminal
    $ nvm ls-remote
    ```

1. 今回はv16.14.0をインストールするので下記コマンドを実行してNode.jsをインストールする。

    ```terminal
    $ nvm install v16.14.0
    ```

1. 下記コマンドを実行してNodeの使用バージョンを宣言する。

    ```terminal
    $ nvm use 16.14.0
    ```

1. 下記コマンドを実行してnpmコマンドが実行できる事を確認する。

    ```terminal
    $ npm
    ```

## 参考文献

- [チュートリアル: Amazon EC2 インスタンスでの Node.js のセットアップ](https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html)
PHP traitの継承的な書き方

traitの継承的なやり方について、適切な記事がなかったので自分なりのまとめ

# php version
```:bash
# php -v
PHP 7.1.33 (cli) (built: Oct 31 2019 17:37:57) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans
```

# traitの継承的な書き方

```test1.php
<?php

namespace Traits;

trait test1
{
    /**
     * @return string
     */
    public function execute(): string {
        return 'a';
    }
}
```

```test2.php
<?php

namespace Traits;

trait test2
{
    use \Traits\test1:

    /**
     * @return string
     */
    public function execute(): string {
        return 'b';
    }
}
```

継承したいtrait内で
対象のtraitをuseして関数を上書きしてあげる
未経験からインフラエンジニアを目指して⑤

## フリースペース(好きに書かせて貰いますのコーナー)
学習を始めてから早くも1週間経過、いやはや、時が過ぎるのはあっという間です。
まだまだ全然知識は足りないですが、先週より成長出来ていると僅かばかり実感しています。
小さくともこの一歩ずつ進めるのが大事。

でも早く活躍したいなぁ、もっと頑張らねば！！

**＜お知らせ＞**
当面の目標については目的意識がブレないように、毎回記載しています。
無事達成して次の目標を定める時には随時更新していきます。
## 取り組み内容(当面の目標)
- ネットワークについての知識を会得し、理解を深める
- 頭で覚えただけでなく、きちんと専門用語を用いて説明出来るようになる
- 資格取得(CCNA)する

**<font color="Red">資格取得はスタートライン！実際の作業で滞りなく行えるようになる！！</font>**
## 今回行った学習
**1. CCNAの問題集への取り組み**
昨日は項目毎にコメントを残しましたが、本日はいっぺんに纏めます。
と言うのも、実は問題集を最後までやってみましたんですが(650ページくらいありましたが)
散々な結果で、項目毎に書くと私のテンション急降下になってしまうので、ご容赦下さい。

そんな訳で、本日はカテゴリを分けて取り組みました。

- **学習したのに覚えていない事**
- **まだ学習していない部分だからわからない事**

本日は｢学習したのに覚えていない事｣を改めて学習しました、つまり復習ですね。
学習していない所からやろうとも考えたのですが、既に学習した所を先に確実にした方が
落ち着いて新たな事を覚えられると考えました。
現状の｢あっちもこっちもやらなきゃ！｣状態だと、きっと効率が悪くなる、私の頭脳。

学習済み内容の問題でも、知らない用語が含まれていたので、併せて学習しました。

今回、回答した中で不正解だった問題を、今度は本やWebから情報を収集しながら
再度問題を解いてみるという形で、知識の定着を図りました。
ある程度進めた所で再度何も見ずに回答して、改善出来たか確かめると言う事を
明日以降に行っていく予定です。

まだまだ先が長い！
頑張れ自分！！負けるな自分！！！

**明日も学習した事を書いていきたいと思います。**
ポモドーロテクニック入門まとめ

# はじめに
本を読んだ中でネットには載っていないポモドーロの本質を掴むために重要な箇所を自分のためにまとめました

# 大事なこと
1ポモドーロに数える条件

- 25分ジャストで作業を止める
- 休憩をしっかりとる
- 別のアクティビティを行っていない

午前・午後の区切りはポモドーロセット(4ポモドーロ)で区切る
午後も4ポモドーロ区切りで終了させる (リズムを守るため)


# ステージ
-	プランニング
アクティビティ在庫シートからバックログを取り出し、ToDoシートに書く
-	トラッキング
タイマーを25分にセットして取り掛かる。割り込みされた回数を数える
-	レコーディング (3分)
1日の終わりに1日の観察した結果をレコーディングシートに記録、割り込み数のカウントも保存
-	プロセッシング
記録したデータを情報に変換する。25分単位で見たときの平均的な割り込み数を計算
-	ビジュアライズ
情報を整理して、プロセスの中に改善できる点がないかを見ていく

# ポモドーロの流れ
朝に重要なアクティビティを選んでToDOシートに書き込む
ポモドーロ時間以内に終わった場合は強化学習にあてる。25分をこえて作業はしない
リズムを大事にする
レコーディングは完了したポモドーロ数を1行で記録する
1つのアクティビティに対する平均的なポモドーロ数を計算する
実際にアクティビティ在庫にどれだけ滞在していたかの平均時間を記録する

# 割り込み

割り込みが続いたときには長めの休憩をとる

## 内部割込み
ToDoシートの下半分に「計画&緊急」という枠を用意して書き留める
今日のToDoシートの現在行っているアクティビティの右側に小さくドットを書く
今日中でないことがわかっている場合はアクティビティ在庫に書き込み小文字uと締め切りを書いておく
ポモドーロを守れなかった場合はポモドーロを破棄する必要がある

## 外部割込み
ToDoシートに割り込みのタイトルを書きこむ
今日中でなければアクティビティ在庫に締め切りとuを書き添える
現在進行中のアクティビティにダッシュを記入する

アクティビティ在庫シート状のuマークと計画外&緊急の数で計画能力を評価

# 計画
7ポモドーロ以上は分割する。複数をまとめて1ポモドーロにしてよい
ボックスがなくなった場合は円、三画を加える
レコーディングでは余ったボックス数を記録する
再記録見積もりの数を記入する。円と三角の数を記録する
在庫アクティビティが多い場合90以上は余計なものを消す
【PHP】Google SheetsAPI で Fatal error: Uncaught TypeError: count():

# API接続がローカル環境のPC上では動いていたのに、windows server 2012上ではエラー。

## エラー内容
```:エラー内容
Fatal error:  Uncaught TypeError: count(): Argument #1($value) must be of type Countable| array, null given in C: \xampp\htdocs\example\vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php: 67 Stack trace:
```
## 解決
以下ページでCurlFactory.php のcount()が正しくない状態との解説。
https://github.com/googleapis/google-api-php-client/issues/1392
/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php の
67行目のif文の書き出しを以下に変更することで解消。

```php:CurlFactory.php
// ~67行目
if(count((array)$this-> handles)> = $this-> maxHandles){
// ~~
```
保存しようとするとvscodeが警告を出したが問題なく動く。
勉強になった。
GoのCLIでテキスト入力をVimとかでやりたかった件

# はじめに
CLIのTwitterクライアントとか作りたいなー って思った
なので、複数行のTweetをコマンドラインで入力するんだったら、Vimとか使いたいなーって思った

## ググった
[GoでVimを開いて編集内容をパースする方法](https://qiita.com/lighttiger2505/items/d3b9ee9884c75a7819d8)
最高やん！

## 結果
[kotaoue/go-eeditor](https://github.com/kotaoue/go-eeditor)を用意した

```Go
import (
	"fmt"

	"github.com/kotaoue/go-eeditor"
)

func main() {
	editor := eeditor.NewEditor()
	b, _ := editor.Open()
	fmt.Println(string(b))
}
```
みたいなコードで、Vimでテキスト編集した結果をbyteで受け取れる

起動時のパラメータ変更すれば、Emacsも使える
```
editor := eeditor.NewEditor(eeditor.Command("emacs"))
```
EC2 Laravel9系 MySQL8系の組み合わせで初回マイグレーションできない問題の解決

# 概要

- EC2にPHP/Laravelの環境を構築し同じEC2内にMySQLをたてていざマイグレーションしようと思ったらできなかったので問題を解決してみる。

# ご注意

- 今回の作業は主に検証のために環境構築を行いました。本来Laravelでマイグレーションの行うことのできるMySQLユーザーはrootユーザーとは別に準備すべきです。（せめて当該DBのみselect updateが行える権限に絞るべき）

# 問題までの経緯

1. EC2 AmazonLinux2インスタンス起動
1. PHPインストール完了
1. composerインストール完了
1. Laravelインストーラーインストール完了
1. MySQLインストール完了
1. MySQLの起動とrootユーザーでのログインとDBの作成完了
1. Apacheインストール完了
1. Apacheのドキュメントルートに`$ laravel new test`を実行してlaravelのtestブロジェクトの作成完了
1. `http://EC2インスタンスのパブリックIP`でLaravelのwelcome画面が表示される事を確認
1. .envにMySQL系の情報を記載完了
1. マイグレートコマンドを実行してマイグレーションを実行

# 問題

- 下記のエラーが発生してマイグレーションが実行できない。

```
$ php artisan migrate

   Illuminate\Database\QueryException 

  SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: NO) (SQL: select * from information_schema.tables where table_schema = test and table_name = migrations and table_type = 'BASE TABLE')

  at vendor/laravel/framework/src/Illuminate/Database/Connection.php:716
    712▕         // If an exception occurs when attempting to run a query, we'll format the error
    713▕         // message to include the bindings with SQL, which will make this exception a
    714▕         // lot more helpful to the developer instead of just the database's errors.
    715▕         catch (Exception $e) {
  ➜ 716▕             throw new QueryException(
    717▕                 $query, $this->prepareBindings($bindings), $e
    718▕             );
    719▕         }
    720▕     }

      +33 vendor frames 
  34  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
```

# 問題解決までの経緯

1. .envに記載したMySQL系の情報（特にrootユーザーのユーザー名、パスワード）に誤りが無いか確認
    1. .envの情報をコピペーして`$ mysql`コマンドでターミナルからログインすることはできたので問題なさそう。
1. MySQL8系からデフォルトの認証方式が変更になった記憶があったので確認してみた。
    1. 下記のリンクに認証方式変更になった旨記載されていた。
        - [https://dev.mysql.com/doc/refman/8.0/ja/caching-sha2-pluggable-authentication.html](https://dev.mysql.com/doc/refman/8.0/ja/caching-sha2-pluggable-authentication.html)

        ![MySQL____MySQL_8_0_リファレンスマニュアル____6_4_1_2_SHA-2_プラガブル認証のキャッシュ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/4ea1172d-d539-c10f-d542-6c28e2a5fa31.png)

1. 下記の方法でrootユーザーの認証プラグインを「mysql_native_password」に変更した。
    - [MySQL8系 すでに作成されたMySQLユーザーの認証プラグインをmysql_native_passwordに変更する](https://qiita.com/miriwo/items/fcb63f8e1075927891d1)
1. しかしこのままだと新しくMySQLのユーザーを追加した時に新しいの方の認証プラグイン「caching_sha2_password」で認証情報が登録されてしまう。
1. 下記の方法で当該サーバーのMySQLのデフォルトの認証プラグインを「mysql_native_password」に変更しておく。
    1. [MySQL8系 新規作成されるMySQLユーザーの認証プラグインをmysql_native_passwordに変更する](https://qiita.com/miriwo/items/a15819ee2e11e3b36d3d)
1. 再びマイグレーションを実行したが、同様のエラーが出てマイグレーションをする事ができない。
1. ダメ元でLaravelの設定のキャッシュをクリアして見る。

    ```
    $ php artisan config:cache
    ```

1. 設定が反映されたのかマイグレーションできるようになった。
1. おそらく、キャッシュのクリアだけではだめでMySQLの設定変更 → キャッシュクリア → マイグレーションの流れで解決できたものと思われる。
WSL上に既に構築した仮想環境がVS Codeで一覧に出てこない

# 状況
VS Codeを使っている時にWSL上に既に構築した仮想環境を，
Pythonの実行またはJupyerの実行に使いたいが，なぜか一覧に出てこない．

# 解決策（自分の場合）
ターミナルではWSLを開いているが，VS Code自体はWSLの環境ではなくローカルの環境だった．
開きたいファイルがWSLのディレクトリ外だったためだと思われる．

なので，
左下の緑のところ → Reopen Folder in WSL
としたらWSLの環境でVS Codeを開きなおしてくれる．
[PHP] 改行コード指定のPHP_EOL 注意点

PHPで、外部API呼出しの処理を書いた時にハマったのでメモです。

PHP_EOLとは。。。
```OSで異なる改行コードを環境に合わせて自動変換してくれる関数です。```

##### OSごとの改行コード
この関数を利用する時には、必ずこれを意識してください。
そうしないと、ハマります。
| OS | 改行コード |
|:--:|:-------:|
|Windows| CR+LF(\r\n) |
|Mac| CR(\r) |
|Linux| LF(\n)|


これを利用すると、下記の通り変換が入るということです。
```shell
// Linuxだと、\nで改行
 echo "this is the new-line" . PHP_EOL

// Macだと、\rで改行
 echo "this is the new-line" . PHP_EOL 

// Windowsだと、\r\nで改行
 echo "this is the new-line" . PHP_EOL  
```

#### 注意点
実行するOSで改行コードが異なるということは、外部サービスなどを使う時は使わない方が無難です。
なぜなら、外部サービスは改行コードが指定されていることが多いからです。
[Laravel] 空文字をDB登録時にnullにしたい

# 解決したい事
nullableなdate型のカラムがありますと。
空文字の状態で送られてDBに入れようとするとエラー吐いちゃう。

<a id="#対処法"></a>
# 対処法
空だったらnull入れるパターン、毎回書くのは大変面倒くさい
```php:
$hoge->fuga = empty($fuga) ? null : $fuga;
```
<br/>
ミューテターなるものを書こう。

モデルへ属性の値を設定しようとすると自動的に呼び出してくれるらしい、なんと便利な。
<a href="https://readouble.com/laravel/8.x/ja/eloquent-mutators.html">Laravel 8.x Eloquent：ミューテタ／キャスト
</a>

```php:
class Hoge extends Model
{
    public function setFugaAttribute($value)
    {
        $this->attributes['fuga'] = empty($value) ? null : $value;
    }
}
```

これで空文字のままぶち込もうとしてもミューテタ君が働いてせっせとnullを入れてくれる訳だ。
```php:
$hoge->fuga = $fuga;
```


# 余談
livewireで宣言するpublicプロパティ
初期値がnullなので初期値の状態でそのプロパティを使ってDBに登録しようとしてもnullのまま入ってくれるが、何か入力してから入力した内容を消すと空文字になるのでnullにすんの面倒だなぁと思いましたが、ミューテタ君に助けてもらう事にします。

参考:<a href="https://qiita.com/hitochan/items/9cd9f2cbbbdd35916a96">【Laravel】アクセサ、ミューテタの基本のキ</a>
MySQL8系 新規作成されるMySQLユーザーの認証プラグインをmysql_native_passwordに変更する

# 概要

- MySQL8系にて、新規作成されるMySQLユーザーで使用する認証プラグインを「mysql_native_password」に変更する方法をまとめる。

# 方法

1. 下記コマンドを実行してMySQLの設定ファイルを作成する。すでに存在している場合も実行して設定ファイルを開く。（設定ファイルの場所は後述する記事を参考にさせていただきました。[my.cnfの場所を調べる](https://qiita.com/is0me/items/12629e3602ebb27c26a4)）

    ```terminal
    $ sudo vi /etc/my.cnf
    ```

1. 開いたファイルの`[mysqld]`より下の読み込まれる行に下記の内容を追記する。

    ```/etc/my.cnf
    default_authentication_plugin=mysql_native_password
    ```

1. 当該ファイルを保存して閉じ、下記コマンドを実行してMySQLを再起動する。

    ```terminal
    $ sudo systemctl restart mysqld
    ```

1. 下記コマンドを実行してmusqldの状態を確認する。

    ```terminal
    $ systemctl status mysqld.service
    ```

1. MySQLにログインして下記SQLを実行して認証プラグインのデフォルト設定が「mysql_native_password」に変更になった事を確認する。

    ```sql
    show variables like 'default_authentication_plugin';
    +-------------------------------+-----------------------+
    | Variable_name                 | Value                 |
    +-------------------------------+-----------------------+
    | default_authentication_plugin | mysql_native_password |
    +-------------------------------+-----------------------+
    ```
MySQL8系 すでに作成されたMySQLユーザーの認証プラグインをmysql_native_passwordに変更する

## 概要

- MySQL8系にてすでに作成されているMySQLユーザーの認証プラグインを「mysql_native_password」に変更する方法をまとめる。

## 方法

1. 初期状態のMySQLのrootユーザーがどの認証プラグインを用いているか確認してみる。

    ```sql
    mysql> select user, plugin from mysql.user;
    +------------------+-----------------------+
    | user             | plugin                |
    +------------------+-----------------------+
    | root             | caching_sha2_password |
    +------------------+-----------------------+
    ```

1. ↑やはり当該のrootユーザーはMySQLの新しい認証プラグインである「caching_sha2_password」が採用されているようだ。
1. 下記SQL句（`alter user`）を実行してrootユーザーの認証プラグインを「caching_sha2_password」から従来の「mysql_native_password」に変更する。（パスワードポリシーは「大文字・小文字・特殊文字を含む」だった気がする。）

    ```sql
    alter user 'root'@'localhost' identified with mysql_native_password by '認証プラグイン変更後にrootユーザーに設定するパスワード';
    ```

1. マイグレーションに用いる予定のMySQLのrootユーザーの認証プラグインがmysql_nateve_passwordに変更になっているか確認してみる。

    ```sql
    mysql> select user, plugin from mysql.user;
    +------------------+-----------------------+
    | user             | plugin                |
    +------------------+-----------------------+
    | root             | mysql_native_password |
    +------------------+-----------------------+
    ```

1. ↑無事に切り替わっているようだ。これで問題なさそう。

## 参考文献

- [https://dev.mysql.com/doc/refman/8.0/ja/caching-sha2-pluggable-authentication.html](https://dev.mysql.com/doc/refman/8.0/ja/caching-sha2-pluggable-authentication.html)
- [https://dev.mysql.com/doc/refman/8.0/ja/native-pluggable-authentication.html](https://dev.mysql.com/doc/refman/8.0/ja/native-pluggable-authentication.html)
- [https://dev.mysql.com/doc/refman/8.0/ja/alter-user.html](https://dev.mysql.com/doc/refman/8.0/ja/alter-user.html)
Watson Studioサービス(無料プラン)の作成

# 前提条件

Watson Studioの利用には、IBM Cloudのアカウントが必要です。
未取得の方は[こちら](https://ibm.biz/BdfSTr)から取得してください。

# Watson Studioサービスの作成

1. IBM Cloudにログインし、 **カタログ** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/8d6db7d3-8854-52cd-10f7-9e6cccd6cd8b.png)

2. 検索バーに `Watson Studio`と入力し、検索結果に表示されている **Watson Studio** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/c8000b09-ef47-ec54-694c-e263b3d62ca5.png)

3. ロケーションの選択で **東京(jp-tok)** を選択
   料金プランの選択で **ライト** を選択 <font color="red">注意：ライト以外のプランを選択した場合、料金列に記載の利用料金が発生しますのでご注意ください。</font>
   **ご使用条件の同意** にチェック
   **作成** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/13a1f3f2-011c-c9a5-afec-25031e42d85e.png)

4. サービスの詳細ページに遷移したら、**Launch in IBM Cloud Pak for Data** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/93f431ad-232c-089f-c031-de15f06db3ba.png)

5. **ご自身の情報** を入力し、**続行** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/57f537e2-5d8e-daab-9fd4-8bbf14d3159f.png)

6. プロビジョニングが開始されるので、終了したら **IBM Watson Studio への移動** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/7e07de0a-17c0-d785-b2ee-036d95ed9670.png)

以下の様に、「Cloud Pak for Data へようこそ。」が表示されたらWatson Studioサービスが利用可能な状態になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/e597c1ff-3b2d-8cc7-7972-5230ea8c7869.png)
Terraformのfor_eachをお手軽に試したい

## はじめに
Terraformのfor_eachって便利ですね。

一部が異なるresourceを複数作る場合には欠かせないです。
個人的にはとてもIaCを感じるところです。

しかし若干直感に反した、クセがある使い方が必要になることがあります。
例えば、mapのlistをfor_eachしたい時など。

そんな時にこんなことをよく思います。

**for_eachをいろいろ試しながら動きを確認したい！！**

と。

でもfor_eachってresourceの中でしか使えないので、
試すにもまずはresourceを用意する必要があるんですよね。

そうは言ってもわざわざAWSなどのresourceを使うのはちょっと面倒くさい。

ということで今回は、

- for_eachの動きをちゃんとしたresourceを用意せずに確認する。

そんな時にどうしたらいいのか調べてみたので、その結果をシェアします

## 結論：Null Providerを使おう！

これだけです。

ドキュメントはこちら。
https://registry.terraform.io/providers/hashicorp/null/latest/docs

有識者の皆様ならこれだけでもう終わりでいいかもしれませんが、
せっかくなので実際にnullを使ってfor_eachの動きを確認するところまで確認してみます。

## 使い方
上記ドキュメントを読むと、
```hcl
resource "null_resource" "cluster" {
  # Changes to any instance of the cluster requires re-provisioning
  triggers = {
    cluster_instance_ids = join(",", aws_instance.cluster.*.id)
  }
```
こんな感じでnull_resourceというリソースを使い、
triggersにmapをぶち込めば良さそうです。

早速やってみましょう。

## 軽く試してみる
### nullのインストールとterraform init
```hcl:main.tf
terraform {
  required_version = ">= 0.12"
  required_providers {
    null = {
      source = "hashicorp/null"
      version = "3.1.0"
    }
  }
}
provider "null" {}
```

で``terraform init``。

### mapのlistをfor_eachしてみる
```hcl:for_each.tf
locals {
  members   = [
      {"id" = 1, "name" = "Takashi"},
      {"id" = 2, "name" = "Satoshi"},
    ]
}

resource null_resource for_each {
    for_each = {for k in local.members : k.id => k}
    triggers = {
        "${each.value.id}" = each.value.name
    }
}
```

そして``terraform plan``してみると、、
```hcl
Terraform will perform the following actions:

  # null_resource.for_each["1"] will be created
  + resource "null_resource" "for_each" {
      + id       = (known after apply)
      + triggers = {
          + "1" = "Takashi"
        }
    }

  # null_resource.for_each["2"] will be created
  + resource "null_resource" "for_each" {
      + id       = (known after apply)
      + triggers = {
          + "2" = "Satoshi"
        }
    }

Plan: 2 to add, 0 to change, 0 to destroy.
```

はい！
こんな感じでtriggersの中に良い感じにmapが出力されてますね。

これでfor_eachの動きをお手軽に確認できるようになりました。
本当にありがとうございました。

## あとがき
ProviderはもっぱらAWSぐらいしか使っていませんでいたが、
こういうのもあると知ったら俄然調べたくなりますね。

また便利なものがあったら試して記事にしたいと思います。


## 参考情報
[hashicorp/null | Terraform Registry](https://registry.terraform.io/providers/hashicorp/null/latest/docs
)
[Types and Values - Configuration Language | Terraform by HashiCorp](https://www.terraform.io/language/expressions/types)
[Type Constraints - Configuration Language | Terraform by HashiCorp](https://www.terraform.io/language/expressions/type-constraints)
[For Expressions - Configuration Language | Terraform by HashiCorp](https://www.terraform.io/language/expressions/for)
[The for_each Meta-Argument - Configuration Language | Terraform by HashiCorp](https://www.terraform.io/language/meta-arguments/for_each)
【Serializer】カラムの命名は他言語開発者にも配慮しよう

# きっかけ

最近でいちばんなるほどと思ったこと、検索してもあまり出てこない情報だなと感じたのでまとめる。


# 出来事

ActiveModelSerializerでJSONを出力する際、**Rubyの命名規則で**カラム名を書こうとした。
たとえば、ユーザーが自身のアイコン画像があるかのフラグを真偽値で返したいときの命名。

```ruby
class UserSerializer < ActiveModel::Serializer
  attributes :id,
             :name,
             :registered_avatar

  def registered_avatar
    ...
  end
end
```

最初は```avatar_registered?```と命名しようとしたが、
他のserializerのコードを見ても語尾に```?```をつけた命名をしていなかったので、
何でだろうと思いながらも一応空気を読んで```registered_avatar```と命名してPRを出した。

すると
> ```avatar_exist```の方がいいかも。
Serializer内での命名はJSONに反映され、特に他の言語の開発者の目に触れるので
Rubyの命名規則ではない方が他言語の開発者にとってわかりやすい。
JSやSwiftなど有名どころの言語の命名習慣を見ておくといいよ！

とレビューをもらった。

# まとめ

「なるほど、たしかに語尾に```?```付ける命名するのはRubyだけだしな」とかなり腑に落ちた！
API作るときなど、ネイティブ側へのこういう細かい配慮まで考えて開発できるエンジニアになりたいと強く思いました。

↓最終的なコード

```ruby
class UserSerializer < ActiveModel::Serializer
  attributes :id,
             :name,
             :avatar_exist

  def avatar_exist
    ...
  end
end
```
Apache CXFで、TLSClientParametersをプログラム内で設定する

# What's？

Apache CXFで、`TLSClientParameters`をプログラム内で動的に設定する方法をメモしておこうかなと。

ドキュメントとしては、このあたりに関わる話です。

https://cxf.apache.org/docs/tls-configuration.html

なお、この記事ではApache CXFの3.5.1時点の情報で書いています。

# 問題

Apache CXFで、クライアントのSSL／TLSに関する設定は、以下のドキュメントを参照するように記述されています。

[TLS Configuration / Client TLS Parameters](https://cxf.apache.org/docs/tls-configuration.html#TLSConfiguration-ClientTLSParameters)

ドキュメントはSpring FrameworkのBean定義ファイルでの設定として書かれており、設定項目の一覧もあるのですが。

よくよくXML Schemaを見てみると、Bean定義では指定できない項目も含まれています。

https://github.com/apache/cxf/blob/cxf-3.5.1/core/src/main/resources/schemas/configuration/security.xsd#L440-L559

`sslSocketFactory`や`hostnameVerifier`あたりですね。

これらは、`TLSClientParameters`クラスのインスタンスを直接扱わないと設定することができません。

では、`TLSClientParameters`クラスのインスタンスを設定するにはどうしたらいいのか、という話です。

# 環境

今回確認に使った環境は、こちらです。

```shell
$ java --version
openjdk 11.0.14 2022-01-18
OpenJDK Runtime Environment (build 11.0.14+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.14+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: /home/user/.sdkman/candidates/maven/current
Java version: 11.0.14, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-100-generic", arch: "amd64", family: "unix"
```

# TLSClientParametersの設定方法

Apache CXFに含まれるサンプルコードを例に書きます。  
※コード例に使っているだけで、このサンプル自体はSSL／TLSは使っていません

https://github.com/apache/cxf/blob/cxf-3.5.1/distribution/src/main/release/samples/jaxws_handlers/src/main/java/demo/handlers/client/Client.java

以下のように、Portを扱っている処理がありますが

```java
        AddNumbersService service = new AddNumbersService(wsdl.toURI().toURL(), serviceName);
        AddNumbers port = (AddNumbers)service.getPort(portName, AddNumbers.class);

        //Add client side handlers programmatically
        SmallNumberHandler sh = new SmallNumberHandler();
        List<Handler> newHandlerChain = new ArrayList<>();
        newHandlerChain.add(sh);
        ((BindingProvider)port).getBinding().setHandlerChain(newHandlerChain);
```

ここで、`BindingProvider`にキャストして`getRequestContext`を呼び出し、`TLSClientParameters`のクラス名でインスタンスを設定します。

```java
        TLSClientParameters clientParameters = new TLSClientParameters();

        // TLSClientParametersのインスタンスに、適宜設定
        clientParameters.setXxx...;

        ((BindingProvider) port).getRequestContext().put(TLSClientParameters.class.getName(), clientParameters);
```

`RequestContext`に設定した情報は、最終的には以下の箇所で`TLSClientParameters`のクラス名をキーに値が設定されていればそちらを使うようになります。

https://github.com/apache/cxf/blob/cxf-3.5.1/rt/transports/http/src/main/java/org/apache/cxf/transport/http/URLConnectionHTTPConduit.java#L117-L120

このアプローチを使う場合には、Apache CXFの設定で`http-conf:tlsClientParameters`は指定しなくてよいでしょう。
[react-konva] canvasでドラッグをするときにスナップを効かせる。

今まで触る機会がなかったのですが、初めてcanvasを使ってみたので記事にしてみます。

canvasは色々できるイメージありますよね。余り使わないかもですが、お絵描きのようなこともできますし、FigmaとかMiroのような便利なサービスで使われています。

FigmaやCADのようなGUIサービスだと、オブジェクトの位置を調整するためにスナップを利かせたいというときがあると思います。

今回はreact-konvaというライブリを使ってやってみています。

[https://konvajs.org/docs/react/Intro.html](https://konvajs.org/docs/react/Intro.html)

## onDragEndが発火するタイミングで、端数を四捨五入する。

onDragEndの引数のeventは、event.targetはx()やy()のような関数を持っています。
この関数は引数を値を入れた場合と入れない場合で異なる挙動をします。

例えばドラッグの終了位置が、{x: 333, y: 222}という座標に落ちた場合とします。
event.target.x(100)のように数値を入れるとオブジェクトの座標が{x: 100, y: 222}と設定されます。

一方、event.target.x()のように空の場合だと、返り値として333が返ってきて、座標は更新されません。
この性質を使って、スナップを効かせることができます。

```tsx
const positionUnitValue = 100

onDragEnd={e => {
    const newX = Math.round(e.target.x() / positionUnitValue) * positionUnitValue
    const newY = Math.round(e.target.y() / positionUnitValue) * positionUnitValue
    e.target.x(newX)
    e.target.y(newY)
  });
}}
```

見ての通りで特に難しいことをやっているわけではありません。
基準となる数を設定して、割り算して余りを除いてあげているだけです。

ちなみに、onDragMoveでも同様に書くことで、常時スナップを効かせることができます。ただ、その場合、ドラッグして移動中に毎回処理が走るので、その点パフォーマンスを考慮しておく必要ありそうですね。

---

canvasを触ってみた感想は、コードが難しいというよりも、どうやったら理想に近づくのかというのを組み立てる点だと感じました。デザイナーがいる場合は、Figmaでモックを作っていただくということもあるかもしれません。ただ、ある程度使えるようになると、やれることと実装の想像ができるようになるので、自分で作ってどんどん作っていった方が手っ取り早いかもしれません。
AWS EC2 AmazonLinux2にApacheを入れる

# 概要

- EC2のAmazonLinux2インスタンスにApacheを入れてApacheのテストページを表示する方法をまとめる。

# 方法

1. EC2インスタンスにssh接続して下記コマンドを実行し、yumを最新の状態にする。

    ```terminal
    $ sudo yum update
    ```

1. 下記コマンドを実行してApacheをインストールする。

    ```terminal
    $ sudo yum install httpd
    ```

1. 下記コマンドを実行してApacheを起動する。

    ```terminal
    $ sudo systemctl start httpd
    ```

1. 下記コマンドを実行してApacheが正常に起動している事を確認する。

    ```terminal
    $ systemctl status httpd.service
    Redirecting to /bin/systemctl status httpd.service
    ● httpd.service - The Apache HTTP Server
       Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
      Drop-In: /usr/lib/systemd/system/httpd.service.d
               └─php-fpm.conf
       Active: active (running) since 火 2022-03-08 08:18:05 UTC; 4s ago
         Docs: man:httpd.service(8)
     Main PID: 11711 (httpd)
       Status: "Processing requests..."
       CGroup: /system.slice/httpd.service
               ├─11711 /usr/sbin/httpd -DFOREGROUND
               ├─11712 /usr/sbin/httpd -DFOREGROUND
               ├─11713 /usr/sbin/httpd -DFOREGROUND
               ├─11714 /usr/sbin/httpd -DFOREGROUND
               ├─11715 /usr/sbin/httpd -DFOREGROUND
               └─11716 /usr/sbin/httpd -DFOREGROUND
    
     3月 08 08:18:05 ip-10-0-10-20.ap-northeast-1.compute.internal systemd[1]: Starting The Apache HTTP Server...
     3月 08 08:18:05 ip-10-0-10-20.ap-northeast-1.compute.internal systemd[1]: Started The Apache HTTP Server.
    ```

1. 下記コマンドを実行して当該のEC2インスタンスが起動した時にApacheも起動する様に設定する。

    ```terminal
    $ sudo systemctl enable httpd
    ```

1. http://EC2インスタンスのパブリックIPアドレス にアクセスして下記のApacheのテストページが表示される事を確認する。

    ![Test_Page_for_the_Apache_HTTP_Server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/77368d5b-c5f7-475f-f201-b8a5e5234a28.png)
Node.js + Express - ルーターモジュール内でパラメータに変数の値を入れてリダイレクトする

専門学校の授業で1年間情報技術の基礎やプログラミング言語の文法等を勉強してきたけど、フレームワークを使って実践的なプログラミングにチャレンジしたい。

そう思い立ち、実際にNode.jsのExpressで掲示板サイトを作成しながら勉強している中で、パラメータを含めたリダイレクトが上手く動作せず数時間費やしたので記録。
（手探り状態で進めているので圧倒的知識不足を痛感・・・）

## 掲示板の構造
掲示板のトップにはthreadから取得したスレッドの一覧を表示。
一覧の中のタイトルをクリックするとコメント一覧表示（/comments/:threadId）のページに移動する仕組み。

スレッド一覧からタイトルをクリックすると、スレッドのID（thread.id）をルートパラメータに指定して対応するコメントを取り出して表示する。
```
[thread]
+--------+-------------+------+-----+---------+----------------+
| Field  | Type        | Null | Key | Default | Extra          |
+--------+-------------+------+-----+---------+----------------+
| id     | int(11)     | NO   | PRI | NULL    | auto_increment |
| userId | int(11)     | NO   | MUL | NULL    |                |
| title  | varchar(54) | YES  |     | NULL    |                |
+--------+-------------+------+-----+---------+----------------+
[comments]
+----------+--------------+------+-----+-------------------+----------------+
| Field    | Type         | Null | Key | Default           | Extra          |
+----------+--------------+------+-----+-------------------+----------------+
| id       | int(11)      | NO   | PRI | NULL              | auto_increment |
| threadId | int(11)      | YES  | MUL | NULL              |                |
| userId   | int(11)      | NO   | MUL | NULL              |                |
| body     | varchar(700) | YES  |     | NULL              |                |
| time     | timestamp    | NO   |     | CURRENT_TIMESTAMP |                |
+----------+--------------+------+-----+-------------------+----------------+

```

## リダイレクトの引数に変数を含めたい
コメント一覧のページの下部に、コメント投稿機能を設置。
コメントを投稿してデータベースに追加した後、コメント一覧（/comments/:threadId）へリダイレクトして、新しいコメントを含めたコメント一覧を表示。

## 引数のルートパラメータに変数は入れられない
バリバリプログラミングやってる人からしたら当たり前すぎて驚くかもしれないけどドが付く初心者の私はここでつまづく。

変数をそのままredirectのルートパラメータにぶち込んでも、{}で囲ってもダメ。
リダイレクトとしてリクエストされた/commentsでパラメータを受け取れずエラーが起きてしまう。


```app.js

app.post('/comments/:threadId', (req, res) => {
   const threadId = req.params.threadId;
......
   res.redirect('/comments/threadId');
});

```

## パス+変数で解決
単純なことだけど、これがわかるまでかなりてこずった。
引数に「'/comments/'+ thread」を渡してやるか、これを変数に入れて引数に変数を渡してやればよかったらしい。

もしかしたらもっと別の方法があるのかもしれないけど、自分なりに出した解決法がこれ。

```app.js

app.post('/comments/:threadId', (req, res) => {
   const threadId = req.params.threadId;
......
   const re_comments = '/comments/' + threadId;
   res.redirect(re_comments);
});

```

てこずった割に理解したら満足して似たような問題に直面したときに「前はどうやったかな・・・」と思い出せないことが多いので、アウトプットと記録として初投稿。

同じように手探りド初心者の方のお役に立てれば尚良し。

- 2022.3.10 追記｜　　\　commentsなのにthreadsじゃないんだ・・・　/
Rails7で複数画像file_filedを使っていると空画像が入る対策

## 背景

Rails6.1からRails7に上げたとき、画像フィールドの動作がおかしくなったのを修正した備忘録。

RailsアプリはHerokuで動かしており、画像のアップロードにCarrierWaveとCloudinaryを使っている。
development環境では実際にCloudinaryには上げず、手元のローカルファイルとして動作させている。
画像のためにRailsのActiveStorageは使っていない。
また、画像のアップロードは複数画像を使うために`file_filed multiple: true`を使っていた。

## 起こったこと

複数画像を許可している`file_filed`を使って画像をアップロードすると、想定していない空画像が一緒にアップロードされてしまう。

![スクリーンショット 2022-03-08 170300.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42721/025970ce-bd32-bfc9-e356-678334e88785.png)

consoleからparamsを確認すると、先頭に謎の空文字があるのが確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42721/378b703a-4dd8-3bd4-059d-a5926f802b0e.png)

## 原因

Rails7からActiveStorageの便利さのために、`multiple: true`で呼び出した`file_filed`が空の入力フィールドを一緒につくるようになった。
ActiveStorageによるファイル添付操作が上書きのため、update時にすでに添付されていたファイルを置くためのフィールドらしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42721/de778355-c33f-065c-30bd-3dbcc16cb03b.png)

自分のアプリではActiveStorageを使っていなかったため、上記のような不具合となった。

## 解決方法その1

既存ファイル`config/application.rb`や新規ファイル`config/initializers/multi_file_field.rb`に設定を追加する。

```ruby:config/application.rb
config.active_storage.multiple_file_field_include_hidden = false
```

## 解決方法その2

`file_field`を`multiple: true`付きで呼び出すときに、`include_hidden: false`をつける

```erb:app/views/sakes/_form.html.erb
<%= form.file_field(:photos,
                    multiple: true,
                    include_hidden: false,
                    class: "form-control col-12",
                    accept: "image/*;capture=camera") %>
```

## 参考

- Configuring Rails Applications
  - https://guides.rubyonrails.org/configuring.html#config-active-storage-multiple-file-field-include-hidden
- Ruby on Rails API
  - https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-file_field
障害対応について

# 背景

初めて障害を起こしたので、今後のためにメモする。

# 前提

- 障害対応は関わっている人で自分のタスクの手を止め協力する
- 誰が悪いとか責任追求ではなく、再発防止策を考える
- 障害対応時、これが足りないなどで追加でリリースは絶対NG
    - 焦っているときの追加オペレーションは、追加事故を起こす可能性が高い
    - エラーが出ていなかった状態に、最速で切り戻す
    - カスタマーに不便をかけている事象の解消を最優先する

# 障害対応の流れ

- 障害を検知
- 関係者に周知
- エラーが出ていなかった状態に切り戻す
- 障害報告書を作成・周知
- SRE チームと情報齟齬解消
    - 解消できない場合、週次で議題に挙げ、問題解決を図る

# 障害発生時の対応

- 障害は、主に２つの役割で複数人でやる
    - 障害記録や報告をまとめる人
    - 復旧オペレーションをやる人
- コード書いた当事者
    - 復旧オペレーションには、できるだけ関わらない
        - 焦って追加でリリースして、２次災害出る可能性ある
        - 第3者目線で、上長が復旧オペレーションする方がいい
    - 発生時刻、規模、復旧方法など経緯をまとめる
        - 状況まとめてくれた方が、助ける時に助けやすい
kubectlのconfigmapを更新するコマンド

kubectlでのconfigmapは更新コマンドなくて、  
いちいちDeleteUpdateしてたら面倒くさいし、
削除したら差分とれないし
なんとか上手い具合にならないかと思って色々調べてたら
`--save-config --dry-run=client -o yaml` オプションをつけてyamlを生成し  
kubectl apply に渡せば良い感じに更新できました。

以下はConfigmap作成の例です。
```
kubectl create configmap nginx-server-config --from-file=./conf.d \
  --save-config --dry-run=client -o yaml | kubectl apply -f -
```
docker engine and docker compose

# overview
docker desktopを利用しないでdockerを利用する設定

# installation
## docker engine
https://docs.docker.com/engine/install/binaries/#install-client-binaries-on-macos

## docker compose v2
https://docs.docker.com/compose/cli-command/#install-on-linux

```
 $ DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
 $ mkdir -p $DOCKER_CONFIG/cli-plugins
 $ curl -SL ${URL_OF_DARWIN} $DOCKER_CONFIG/cli-plugins/docker-compose
 $ chmod 755 $DOCKER_CONFIG/cli-plugins/docker-compose
```

## env
zsh
```
export DOCKER_HOST=unix:///${SOCK_DIR}/docker.sock
export DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
```
[対処] PG::ConnectionBad: could not connect to server on socket

## 環境
- MacOS

## 現象
`rails db:migrate` を実行しようとしたら以下のエラーに遭遇。

```
PG::ConnectionBad: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory
Is the server running locally and accepting connections on that socket
```

`PG::ConnectionBad: connection to server on socket` で調べるとpostgresql関連の問題らしい。
以下のコマンドを実行してpostgresqlの状態を確認。

```
$ brew services list                         
Name       Status  User Plist    
postgresql error   user  /path/to/postgresql/homebrew.mxcl.postgresql.plist
```

ひとまず再起動を試す。

```
brew services restart postgresql
Stopping `postgresql`... (might take a while)
==> Successfully stopped `postgresql` (label: homebrew.mxcl.postgresql)
==> Successfully started `postgresql` (label: homebrew.mxcl.postgresql)
```

成功したっぽいが、 `brew services list`　を再実行すると相変わらずpostgresqlはerrorのまま。
調べながら以下のコマンドを試す。

```
$ postgres -D /usr/local/var/postgres
The data directory was initialized by PostgreSQL version 13, which is not compatible with this version 14.2.
```

## 対処
バージョン違いっぽい。ので、再度エラーメッセージで検索して出てきた以下の記事を参考に `PostgreSQL version 13` をインストール。
https://zenn.dev/koniman/articles/a1acab134a43aa

```
 $ brew install postgresql@13
 $ brew services stop postgresql
 $ brew services start postgresql@13
```

確認。

```
$ brew services list                         
Name          Status  User Plist    
postgresql    none
postgresql@13 started user /path/to/homebrew.mxcl.postgresql@13.plist
```

この後無事に　`rails db:migrate` を実行できた。

## 備考
先週 `brew update` を実行するつもりが誤って `brew upgrade`　を実行してしまったので多分postgresqlも最新になったっぽい。
【Docker】タイムゾーンの設定でbuildが止まった時の対処法

Dockerでbuildを実行した際に、タイムゾーンの設定でbuildが止まってしまったので対処法をメモしておく。

# 問題
Dockerでbuildした際に、以下のようなタイムゾーンの選択を求められて、buildが止まってしまった。
この画面で、タームゾーンを選択しても止まったままの状態になってしまう。

```:コンソール
Please select the geographic area in which you live. Subsequent configuration
questions will narrow this down by presenting a list of cities, representing
the time zones in which they are located.

1. Africa 6. Asia 11. System V timezones
2. America 7. Atlantic Ocean 12. US
3. Antarctica 8. Europe 13. None of the above
4. Australia 9. Indian Ocean
5. Arctic Ocean 10. Pacific Ocean
Geographic area:
```

# 解決策
解決策としては、Dockerfileに以下の記述を追加した。

```dockerfile:Dockerfile
ENV DEBIAN_FRONTEND=noninteractive
# timezoneを設定
ENV TZ=Asia/Tokyo
```

追加するとタームゾーンの選択でbuildが止まることはなくなった。
ちなみに、タイムゾーンの設定が正常に行われているかチャックしてみると、正しく``JST``(日本)になっていた。

```:コンソール
$ docker run -it <イメージID>
root@<コンテナID>:<WORKDIR># date
Tue Mar  8 15:33:51 JST 2022
```
【Ruby/Rails】定数の定義と管理方法



# config gemを使う

```config/settings/development.yml```などファイルを作成して環境ごとに管理する。

下記のように呼び出して使える。

```ruby
Settings.SERVICE_NAME
#=> "hoge_app"

Settings[:SERVICE_NAME]
#=> "hoge_app"
```

# クラス内で定義

文脈としてあるクラスの中だけで使われるような定数はそのクラスに定義する。
```freeze```を忘れずに！

```model/post.rb
class Post < ApplicationRecord
...
  MAX_COMMENT_COUNT = 100.freeze
...
end
```



# 参考

https://github.com/rubyconfig/config


https://qiita.com/clbcl226/items/c068f617aa34d552a50a
Pythonで月初日と月末日のリスト作成

SageMakerからRedshiftやSnowflakeに接続してクエリを投げたり、月単位のデータマートに対して集計を行ったりということが最近多いので備忘録です。
状況としては
データマートのテーブル名やcsvファイルのファイル名
に対して複数の期間をfor文で集計を回すことを想定しています。
集計コードの例としては、以下のようなトランザクションのテーブルが

| purchase_id | user_id | purchase_price |
|:---------|:----------|----------:|
| P0001    | USER001   | 1000      |
| P0002    | USER002   | 1500      |
| P0003    | USER003   | 2000      |
| P0004    | USER004   | 1000      |
| P0005    | USER001   | 3000      |
| P0006    | USER003   | 5000      |

`transaction_20210401`
`transaction_20210501`
`transaction_20210601`
`...`
のように月単位で存在する状況で
```py
output = pd.DataFrame()
for TARGET_DATE in TARGET_DATE_LIST:
    TARGET_DATE = TARGET_DATE.strftime('%Y%m%d')
    sql = f"""
        select
            count(purchase_id) as 購入回数合計
            , count(distinct user_id) as 購入人数合計
            , sum(purchase_price) as 購入金額合計
        from
            transaction_{TARGET_DATE}
        """
    df = pd.read_sql(sql, con)
    df = df.T
    df.rename(columns={0:f'{TARGET_DATE}'}, inplace=True)
    output = pd.concat([output, df], axis=1)
```

上記のような集計を行うときにfor文で回す日付のリストを簡単に作成する関数を月初日パターンと月末日パターンで作成しました。
```py
# ライブラリのインポート
from datetime import date
from dateutil.relativedelta import relativedelta
```
指定した期間の**月初日**のリストを作成する関数は以下で作成できます。

```py
def get_first_day_list(start_date: date, end_date: date):
    """指定した期間の月初日のリストを作成する関数"""
    first_day_list = []
    while start_date <= end_date:
        first_day_list.append(start_date)
        start_date = start_date + relativedelta(months=1)
    return first_day_list
```

```py
# 実行
start_date = date(2021, 4, 1)
end_date = date(2022, 3, 1)
TARGET_DATE_LIST = get_first_day_list(start_date, end_date)
TARGET_DATE_LIST
```

```py
# 実行結果
[datetime.date(2021, 4, 1),
 datetime.date(2021, 5, 1),
 datetime.date(2021, 6, 1),
 datetime.date(2021, 7, 1),
 datetime.date(2021, 8, 1),
 datetime.date(2021, 9, 1),
 datetime.date(2021, 10, 1),
 datetime.date(2021, 11, 1),
 datetime.date(2021, 12, 1),
 datetime.date(2022, 1, 1),
 datetime.date(2022, 2, 1),
 datetime.date(2022, 3, 1)]
```

指定した期間の**月末日**のリストを作成する関数は以下で作成できます。
```py
def get_last_day_list(start_date: date, end_date: date):
    """指定した期間の月末日のリストを作成する関数"""
    last_day_list = []
    while start_date <= end_date:
        last_day_list.append(start_date)
        start_date = start_date + relativedelta(days=1) + relativedelta(months=1) - relativedelta(days=1)
    return last_day_list
```

```py
# 実行
start_date = date(2021, 4, 30)
end_date = date(2022, 3, 31)
TARGET_DATE_LIST = get_last_day_list(start_date, end_date)
TARGET_DATE_LIST
```

```py
# 実行結果
[datetime.date(2021, 4, 30),
 datetime.date(2021, 5, 31),
 datetime.date(2021, 6, 30),
 datetime.date(2021, 7, 31),
 datetime.date(2021, 8, 31),
 datetime.date(2021, 9, 30),
 datetime.date(2021, 10, 31),
 datetime.date(2021, 11, 30),
 datetime.date(2021, 12, 31),
 datetime.date(2022, 1, 31),
 datetime.date(2022, 2, 28),
 datetime.date(2022, 3, 31)]
```