OmniAICreator/Qiita-1.07M huggingface dataset:
PerfectPixelを使ってカンプとの差を確認する

## chromeにPerfectPixelを追加する

[ChromeウェブストアのPerfectPixel](https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi) から追加します。

## デベロッパーツールの設定

カンプと同じ解像度で見られた方がいいのでデベロッパーツールを設定します。

1. デベロッパーツールを画面の下に表示する
&nbsp;
初期設定では画面の右に表示するようになっていますが、それだとPC版のコーディングをしていると狭すぎると思います。
デベロッパーツールを下に表示するようにすると横幅を確保できます。
&nbsp;
[![Fig1](https://i.gyazo.com/be80f347fd87ab81eb10598b17987030.png)](https://i.gyazo.com/be80f347fd87ab81eb10598b17987030.png)

2. デバイスのツールバーを表示する
[![Fig2](https://i.gyazo.com/518d931efd895c13cf073d75ef88303e.png)](https://i.gyazo.com/518d931efd895c13cf073d75ef88303e.png)

3. ①「デバイスのピクセル比」と②「デバイスの種類」を追加する
[![Fig3](https://i.gyazo.com/f20d3a9603043ee9f5344ab7620ecc85.png)](https://i.gyazo.com/f20d3a9603043ee9f5344ab7620ecc85.png)

4. デバイスの設定をする
①「サイズ」は「レスポンシブ」
② 横幅はカンプの横幅（ここでは「 `1366` 」）にする
③「DPR」は `1.0` にする
④ デバイスの種類は「Mobile」にする。これで縦のスクロールバーを消すことが出来ます。 
[![Fig4](https://i.gyazo.com/e6fed475de11f10e2eb26a33e7ab3cba.png)](https://i.gyazo.com/e6fed475de11f10e2eb26a33e7ab3cba.png)

5. 目的のサイトを表示する
テスト用のWebサーバやVSCodeのライブサーバを利用して表示します。

## PerfectPixelの設定

では実際にサイトとカンプを比べてみます。
ここではqiitaのトップページを使って説明します。

1. PerfectPixelのアイコンをクリックする
[![Fig5](https://i.gyazo.com/41d5b4fa7689f83482fedec12d55a3ba.png)](https://i.gyazo.com/41d5b4fa7689f83482fedec12d55a3ba.png)

2. カンプを画像化したものをPerfectPixelのダイアログにドラッグ＆ドロップする
[![Fig6](https://i.gyazo.com/2b6767fb76b6426bbdaafd975619e98f.png)](https://i.gyazo.com/2b6767fb76b6426bbdaafd975619e98f.png)

3. これでカンプと実際のサイトが比べられます。
ここではカンプの方を細工して、ちょっとだけずらしてあります。
下記のようにカンプとサイトがズレていることが確認できると思います。
PerfectPixelの `－` の部分をクリックするとダイアログが閉じます。
また🔒マークをクリックすると、重ねたカンプをロックできます。
[![Fig7](https://i.gyazo.com/ffa8f712540eaf6ab774b2a191cfde2c.png)](https://i.gyazo.com/ffa8f712540eaf6ab774b2a191cfde2c.png)

## 注意点

このデベロッパーツールの設定だと、要素が画面外にはみ出ていても横スクロールバーが出ません。
出来上がってきたら一度デベロッパーツールをOFFにして横スクロールバーが出ていないか確認しましょう。

SP版も同様にして幅を調整して確認するといいですね。
デバイスの種類を変えてしまうと「DPR」が変わってしまうので、想定したカンプの横幅と変わってしまうかもしれません。
ansible-vaultでパスワードが入ったファイルを暗号・復号化する

チーム内でパスワードを共有するのに便利。
特別なサーバなどは不要

```rb
$ brew install ansible

$ ansible-vault --version
ansible-vault [core 2.12.4]
...

# 秘密鍵を作る。これは git commit しない。 DM などでメンバーに共有する
$ echo 'PASSWORD' > .vault_pass    

# こういう内緒のファイルがあるとします
$ cat .env
DB_PASSWORD=abc12345
MY_SECRET=xzy99999


# 暗号化して、ファイル名を .env.encypted にする
$ ansible-vault encrypt --vault-password-file .vault_pass --output .env.encrypted  .env
Encryption successful

# 暗号化されました。これを git commit します。
$ cat .env.encrypted
$ANSIBLE_VAULT;1.1;AES256
66653666616531346330353435313635666233643333313164636265623031393135393964376164
3738653164376435653235636131343336396632623365360a326331643963333636316230653236
33333535376463303032663766356538626361376339643463656132386361646131333531353932
6633356337363833380a313530353561393936383666383135626164363736356135646136653464
61396235376661646235393665616234623834653634616331303265313737616563363732306636
6364613230353266303333613237393537313661666632636131


# 他のチームメンバーは、.env.eyncyprted を git clone したら 複合します
$ ansible-vault decrypt --vault-password-file .vault_pass --output .env .env.encrypted
Decryption successful

# 複合されました
$ cat .env
DB_PASSWORD=abc12345
MY_SECRET=xzy99999
```
CakePHP4 部分テンプレート

ちょっとだけ悩んだのでメモ。

## 環境

PHP 8.1.4RC1
CakePHP 4.3.6

## 部分テンプレート

```tempates/element```以下のファイルをレンダリングする。

```PHP:templates/content.php
  <?= $this->element('content/parts') ?>
```
不採用通知ショット開発日記

## 「不採用通知ショット」とは
シューティングゲームです。
上から降ってくる紙の中から不採用通知を射貫いて、内定通知書を獲得します。
たまに自身に合ったレア企業からも届きます。ポイントが倍です。

## なぜ作ったか
某会社のインターンシップのお題が「就活」or「虎」だった。
開発時間が3hとあり、簡単に作れるものを考えた。
(実際は他の作業を手早く終わらして開発していたため3hではない。)

## 開発環境
Unity2020.3.3f1
VisualStudio2019

## 参考にしたサイト

- https://tech.pjin.jp/blog/2018/10/03/unity_click_shot_bullet_direction/

## 日記本編

### 1日目(2022/04/07)

**進捗**

- 矢を発射させる
- 紙の挙動を作成
- 矢と紙が消えるようにした
- スコアを作成中

**メモ**

- 動的生成されるオブジェクトのスクリプトから、他のスクリプトの関数を呼び出すのにはサービスロケーターというものがいいらしい(https://blog.gigacreation.jp/entry/2021/01/24/223859)

### 2日目(2022/04/14)

**進捗**

- ポイントを獲得
- ハイスコア記録
- 紙の種類を追加
- ロゴ作成
- 紙の画像作成
- タイトル、リザルト画面作成
- Prefab生成でPositionとRotateがランダムで決定
- 最低限の完成

**メモ**

- OnTriggerEnter2D(Collider2D collision)でdestroy(collision)すると触れたオブジェクトのcolliderのみがremoveされる
- 触れたオブジェクトを破壊したい場合はdestroy(collision.gameObject)にする必要がある
PythonでPDFのページを結合する

筆者はMac使いなので、従来、PDFファイルの結合はAutomatorを使っていたのですが、macOS Monterey 12.3でPythonを標準搭載しなくなった煽りを受けて、Automatorの「PDFページを結合」アクションが動作しなくなりました。
仕方ないので、結合するスクリプトを書きます。

# PyPDF2のインストール
```
$pip install PyPDF2
```
（Python3がインストール済みの前提です。）

# ページの結合
今回は、`tojoin-01.pdf`〜`tojoin-09.pdf`という連番ファイル名、かつ、**各PDFには1ページしか入ってない**想定です。
（スキャン時にまちがって1枚1ファイルを生成しちゃった時の想定。）

```python:join.py
from PyPDF2 import PdfFileWriter, PdfFileReader

output = PdfFileWriter()

# tojoin-01.pdf〜tojoin-09.pdfから先頭ページを抜粋してoutputに入れる
for num in range(1,10):
	output.addPage(PdfFileReader(open("tojoin-0"+str(num)+".pdf", "rb")).getPage(0))

# PDFファイルをjoined.pdfというファイル名で書き出す。
with open("joined2.pdf", "wb") as outputStream:
	output.write(outputStream)
```
とりあえずこれで、inputファイル名固定でのアレができました。
もうちょっとしっかり作るならパスを標準入力から受け取ったり各PDFの最終ページまで足してから次のページに進めたりですかね。
Enjoy!
Redshiftで再帰処理(WITH RECURSIVE)

## はじめに

SQLで再帰処理ってなかなか難しいの & Redshiftの例がなかなか見つけられなかったのでここに残します。
再帰処理で作ったテーブルをどう実用につかうの?!みたいなのが大事なのですがそれはまたどこかで。

## 数値で再帰処理
### SQL
```
WITH RECURSIVE counter_table(cnt) AS (
    -- 初期値指定
    SELECT 1 AS cnt
    UNION ALL
    -- 再帰処理部分
    SELECT cnt + 1 AS cnt FROM counter_table
    -- 終了値指定
    WHERE cnt < 10
)
-- ここが実際のSELECT文
SELECT cnt FROM counter_table;
```

### 処理結果
| cnt |
|:-----------|
|1|
|2|
|3|
|4|
|5|
|6|
|7|
|8|
|9|

## 月次で再帰処理
```
WITH RECURSIVE calendar(calendar_date) AS (
    -- 初期値指定
    SELECT '2022-01-01'::DATE AS calendar_date
    UNION ALL
    -- 再帰処理部分
    SELECT dateadd(month,1,calendar_date)::DATE AS calendar_date FROM calendar
    -- 終了値指定
    WHERE calendar_date < '2023-12-01'::DATE

)
-- ここが実際のSELECT文
SELECT calendar_date FROM calendar;
```

| calendar_date |
|:-----------|
|2022-01-01	|
|2022-02-01	|
|2022-03-01	|
|2022-04-01	|
|2022-05-01	|
|2022-06-01	|
|2022-07-01	|
|2022-08-01	|
|2022-09-01	|
|2022-10-01	|
|2022-11-01	|
|2022-12-01	|
|2023-01-01	|
|2023-02-01	|
|2023-03-01	|
|2023-04-01	|
|2023-05-01	|
|2023-06-01	|
|2023-07-01	|
|2023-08-01	|
|2023-09-01	|
|2023-10-01	|
|2023-11-01	|
|2023-12-01	|

## 文献

大変参考になりました。

https://sqlite-date.com/calendar
最速でAWS CDK + Lambda Function URLs をやっていく

https://aws.amazon.com/blogs/aws/announcing-aws-lambda-function-urls-built-in-https-endpoints-for-single-function-microservices/

2022年4月23日現在 CDK(v2.21.0) の Lambda Function で Lambda Function URLs を設定することができるようになりました。

# tl; dr

```
const { HttpMethod } = require('aws-cdk-lib/aws-lambda');
const lambda   = require('aws-cdk-lib/aws-lambda')

      // function に対して addFunctionUrl をやる
      const furl = func.addFunctionUrl({
        authType: lambda.FunctionUrlAuthType.NONE,
        // cors はなんかちゃんと設定したい人がちゃんとしたのを入れてください
        cors:{
          allowedOrigins: ['*'],
          allowedMethods: [HttpMethod.ALL],
          allowedHeaders: ['*'],
        }
      }) 

      // addFunctionUrl の戻り値に対して url で見たところに URL が格納されているのでこれを使おう
      const theURLString = furl.url
```

- https://github.com/aws/aws-cdk/commit/4fd515a3a1de87977ad71329bb7cecb0527558f4

# 以下過去の内容

## でも Terraform のが早かった

発表されてから 2w 過ぎようとしてるのに何もできない一方で Terraform の方では

- https://registry.terraform.io/providers/hashicorp%20%20/aws/latest/docs/resources/lambda_function_url

ちゃんと latest で追加されているように見えるので、枯れてない機能を即使っていこうという姿勢としては AWS の CDK よりも Terraform の方が IaC に最適なのかも知れません。


## issue
https://github.com/aws/aws-cdk/issues/19798


## がんばれー
https://github.com/aws/aws-cdk/pull/19817

# (自力で)やってるひと

https://github.com/neilkuan/cdk-lambda-url-sample

# 感想

- https://aws.amazon.com/blogs/aws/announcing-aws-lambda-function-urls-built-in-https-endpoints-for-single-function-microservices/

> You can start configuring Lambda Function URLs directly in your IaC templates today using AWS CloudFormation, AWS SAM, and AWS Cloud Development Kit (AWS CDK).

あと数時間で実装ができれば today っぽいけど無理だった
MySQL Workbenchでスキーマが表示されない！？

# 現象

### キャプチャ
↓こんな感じになってる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668402/69f7e05c-6278-be2b-8b0b-572a8cfbf991.png)

### SQLは実行できる
作成されているはずのテーブル名を使ってQueryを書いて実行すると、データがちゃんと取れる。

んなあるはずやん？なんで表示されへんの？

# 解決
というか、隠れてしまっているだけのよう。
下の図の赤線のあたりにカーソルを合わせてドラッグすると見えてくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668402/7b1b813f-ad5b-87fb-fac9-d33684cc7f3d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668402/af942fb4-7b7f-da15-5583-25c3c2d046ab.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668402/f492ee22-91d6-ccd2-4330-1300166599b1.png)

こんな感じで表示できる。

いやいや、こんなとこさわったことないって！
そんなピンポイントな・・・
【Flask】openpyxl でExcelファイルに書き込みダウンロードさせるサンプル

# 環境
・Python3
・Flask 2.1.1
・openpyxl 3.0.9

# サンプル

Python

```
import datetime
from flask import Flask, render_template,request,send_file
from io import BytesIO
import openpyxl as excel

app = Flask(__name__)  # アプリの設定

# TOP画面
@app.route('/')
def top():
    return render_template('temp_download.html')

# ダウンロード機能
@app.route('/download')
def download():
    # 出力先ストリームの設定
    output = BytesIO()

    # テンプレートファイルを読み込み 今回は部署名と名前の入力枠を用意
    wb = excel.load_workbook('excel_template.xlsx')
    ws = wb.active
 
    # サンプルデータの書き込み 指定のセルに部署名と名前を書き込む
    ws['C2'].value = '営業部'
    ws['C3'].value = 'テスト太郎'
    
    #ワークブックをメモリ上へ出力
    wb.save(output)
    output.seek(0)
    wb.close()

    # 書き込みファイル名は時間を使用
    dt_now = datetime.datetime.now()
    name = 'test_{date}.xlsx'.format(date=dt_now.strftime('%Y%m%d%H%M%S'))

    # ブラウザへExcelファイルを設定
    return send_file(output, attachment_filename=name, as_attachment=True)

# メイン起動
if __name__ == "__main__":

    # IPの指定、ポートの指定
    app.run(host='localhost', port=8080)
```

HTML

```
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Excelダウンロードページ</title>
</head>
<body>
    <button type=“button” onclick="location.href='/download'">ダウンロード</button>
    
</body>
</html>
```

# 出力結果
![スクリーンショット 2022-04-06 17.28.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504099/4aabf894-4dcd-9bd3-59ab-f1b32754ff1f.png)
【AWS】SAP合格体験記 - 2021年10月2日 -

# AWS SAPについて
SAPはAWSの資格だと上位のレベルの資格になります。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512673/b92e754d-59fa-cea7-4e9f-099d5f64d2f2.png)

2021年10月2日に受験し、1回目で合格(756点)でした。

# 勉強方法①
Amazonにて下記テキストを購入、少し時間をあけつつ3周やりました。
特に模擬試験は有用なので、3回目は時間を計測しながら本番を見据えて勉強しました。
[AWS認定ソリューションアーキテクト－プロフェッショナル～試験特性から導き出した演習問題と詳細解説～](https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E3%82%BD%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%88%EF%BC%8D%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%EF%BD%9E%E8%A9%A6%E9%A8%93%E7%89%B9%E6%80%A7%E3%81%8B%E3%82%89%E5%B0%8E%E3%81%8D%E5%87%BA%E3%81%97%E3%81%9F%E6%BC%94%E7%BF%92%E5%95%8F%E9%A1%8C%E3%81%A8%E8%A9%B3%E7%B4%B0%E8%A7%A3%E8%AA%AC%EF%BD%9E-%E5%B9%B3%E5%B1%B1%E6%AF%85-ebook/dp/B08F9CQ6LT/ref=sr_1_1?crid=29BA1ZZ8ZFU0B&keywords=aws+sap&qid=1649320249&sprefix=AWS+SAP%2Caps%2C684&sr=8-1)

# 勉強方法②
下記の有料会員になり、SAP#の後半を2～3周ほど実施しつつ、解説を読み、
わからない箇所はQiitaや個人ブログを参照して勉強をしました。
[AWS WEB問題集で学習しよう](https://aws.koiwaclub.com/)

# 参考
Udemyの問題集は今回実施しませんでした。
購入された方の話を聞いたところ、本番試験より難しくて正答率が上がらず
本番に向けて自信がなくなると話しておりました(笑)
[AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集（全5回分375問）](https://www.udemy.com/course/aws-53225/)

# 総評
上記のテキスト、問題集を実施しても確実に受かるとは言い切れません。。
可能であれば上記と合わせて実機をさわりながら、どこでどのような設定ができるのか、
問題文を読みながら構成図を脳内で作ってくくらいのレベルが必要だと思います。

私は3か月ほど勉強をガッツリやりました(1日1時間～2時間＋土日は数時間)
試験は180分と長丁場ですが、問題が長文、解答欄も長文で75問を解くころには
残り15分……チェックを付けた問題を急いで見直し、終了ボタンを押しました。

3時間も長文問題を解き続けるための集中力や長文読むことへの苦手意識の排除、
当日の体調を整える等、色々と大変ですが、取得するための勉強をすることで、
AWSの基本を学べると思いますのでお勧めの資格です。
Ruby初心者さんたちが抱くややこしさ

初心者目線で書いています。
プロには違うと思うかも…

rubyのややこしさ①
いくつもほぼ同じことをするコードがある
```ruby:出力するprint系コード
print("hello world")
#これは良い

printf("hello world")
#まだ大丈夫

puts "hello world"
#うーん…ギリギリ良いかな…？

p "hello world"
#うん、いらない
```

rubyややこしさ②
繰り返しコードの多さ
```ruby:繰り返し
for i in 1..10 do
    print("hello")
end
#大丈夫、全然普通

while 1 < 5 do
    print("hello")
    i = i + 1
end
#forとwhileは全然問題ない

x = 3
until x <= 0 do
    print(x,"\n")
    x = x-1
end
#はぁ…まぁ良いけどさぁ

x = 1..10
x.each do
    print("hello!","\n")
end
#うーん…需要はあるか…

5.upto(10) do
    print("hello! ") # 6回繰り返された。
end
#使うのか？
10.downto(5) do
    print("hello! ") # 6回繰り返された
end
#いやdownもあるんかいΣ(゜o゜

10.times do
    print("hello! ")
end
#いやいらないかも

2.4.step(5.4,0.2) do
    print("hello!","\n")
end
#これはまぁまぁ需要あるかな？
```
もうお腹いっぱいです。
うーんややこしいｗ

これを覚えてることが不思議
rex0220 計算式プラグイン ファイル数をカウント

[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)で、添付ファイル項目のファイル数をカウントします。

# 概要

添付ファイル項目のファイル数をカウントするには、少し工夫がいります。
なお追加・編集画面で、ファイルを追加・削除してすぐにカウント数に反映することは、できません。
レコード保存時に、ファイル数をカウントしてレコードに反映しますので、詳細画面表示時に最新のファイル数を反映します。


![2022-04-07_17h13_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/1bf10501-e9d8-89bd-0ee8-950dabb0d5ed.png)

# kintone API の添付ファイル項目について

kintone で提供されているAPI は、イベントの種類によって、ファイル情報の有無があります。
show, submit.success では、ファイル情報を取得できますが
change, submit では、ファイル情報を取得できません。
※なおモバイル表示では、show イベントでファイル情報を取得できません。

# ファイル数をカウントする計算式

各イベント別に、ファイル数をカウントするか、ファイル数をそのまま保持するかを指定します。
※「LET(x,更新日時,」は、success イベントで計算処理を行わせるため、指定しています。
この項目ではなくとも、どれかの項目の計算式に「更新日時」を参照していれば、success イベントで計算処理が行われます。

- テーブル外の計算式：
LET(x,更新日時,
IF(OR(
AND(EV_INFO("mobile"),EV_INFO("mode")="success"),
AND(NOT(EV_INFO("mobile")),IN(EV_INFO("mode"),"","show","success"))),
ARRAY_COUNT(添付ファイル),数値)
)


- テーブル内の計算式：
LET(x,更新日時,
IF(OR(
AND(EV_INFO("mobile"),EV_INFO("mode")="success"),
AND(NOT(EV_INFO("mobile")),IN(EV_INFO("mode"),"","show","success"))),
ARRAY_COUNT(添付ファイルT),数値T)
)

![2022-04-07_17h23_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/716389e6-cf46-d1e1-a2d2-d60afe1a42f8.png)


# 簡易版ファイル数をカウントする計算式

対象アプリについて、連携サービスやAPIによるファイル項目更新等を行わないようであれば、計算式を少し簡単にできます。
一括計算と success イベントのみ最新のファイル数を取得し、それ以外は値を保持します。

- テーブル外の計算式：
LET(x,更新日時,
IF(IN(EV_INFO("mode"),"","success"),
ARRAY_COUNT(添付ファイル),数値)
)
DjangoのプロジェクトをGitHubにあげる前に必ず環境変数を設定しよう

Djangoを使用した場合の環境変数等の設定についての記事。
私は以前Javaの開発業務をしていました。Javaでは環境変数等はSystem.propertiesで管理するのが大半かと思います。
django-environを使用すればSystem.propertiesのように設定値を扱えそうなためまとめてみました。


:::note info
JavaのSystem.propertiesにはソースにハードコーティングしたくないような値や書き換えて設定を簡単に変えたい値を指定します。
例:外部ソースアクセス時に使用するシークレットキーなどの非公開にすべき値、ダウンロードファイルの格納先となるファイルパス、文字コード、拡張子等
:::

# 前提条件
Python 3.10
Django     4.0.2
pip        22.0.2
Windows環境

# 環境変数の設定
仮今回はDjango-environを使用して環境変数を設定します。想環境が起動していることを確認して次のpipコマンドを実行。

```:PowerShell
(venv) $ pip install django-environ
Collecting django-environ
  Downloading django_environ-0.8.1-py2.py3-none-any.whl (17 kB)
Installing collected packages: django-environ
Successfully installed django-environ-0.8.1
```
2行目以降は実行結果です。

実際に対象となる値を確認しましょう。Djangoでプロジェクト作成時デフォルトでsettings.pyにSECRET_KEYがハードコーティングされています。この値は外部に非公開にすべき値です。(※settings.pyには他にもハードコーティングすべきでない値はあります。)
また、今回はDEBUGの設定値も取り扱います。

```Python:settings.py
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'XXXXXX'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
```
Appフォルダ、manage.pyと同じ階層に.envファイルを作成する。.envファイルがJavaで言うSystem.propertiesのファイルに相当。
.envの中身は次のように設定する。
```:.env
SECRET_KEY='XXXXXX'
DEBUG=True
```

:::note warn
.envには余分な空白は入力しないこと。
:::

setting.pyを更新しましょう。
```diff_Python:setting.py
+import environ
+import os

 # .envでDEBUGを指定しない場合デフォルトでFalseが設定される。
+env = environ.Env(
+    DEBUG=(bool, False)
+)

BASE_DIR = Path(__file__).resolve().parent.parent
+environ.Env.read_env(os.path.join(BASE_DIR, '.env'))

-SECRET_KEY = 'XXXXXX'
+SECRET_KEY = env('SECRET_KEY')

-DEBUG = True
+DEBUG = env('DEBUG')
```
以上のように変更後manage.pyのrunserverコマンドで無事起動できれば完了となる。
push前に.gitignoreで.envファイルが追跡対象外となっていることを確認しましょう。

# 補足

```Python:setting.py
BASE_DIR = Path(__file__).resolve().parent.parent
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
```
Path(\_\_file__)は処理を実行しているファイルのパスを指す。.resolve()の処理でシンボリックリンク等が使用されていた場合解消後絶対パスに変換し返却される。.parent部分で一つ上の階層のディレクトリを参照する。
二行目でOS依存のパスの部分と.envの格納されたディレクトリのパスを連結し.envファイルを読み込んでいる。

# 参考
django-environ 

https://github.com/joke2k/django-environ

BASE_DIRについて

https://docs.python.org/ja/3/library/pathlib.html#module-pathlib
VSCodeで新しいターミナルを開くときのデフォルト設定を変更する

# はじめに
VSCodeで新しいターミナルを開くときの規定値をPoewrshellだったり、コマンドプロンプトだったり、あるいはanaconda用に設定されたPowershellだったりに設定したい。そんなときのTips。

# VSCodeでターミナルを開く
まずはターミナルを開きます。
GUIなら「ターミナル」→「新しいターミナル」
![open_term.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2381513/3955a2da-a412-ff71-32ef-a21a056d9aea.png)
ショートカットキーは、Ctl+Shift+@

# VSCodeで新しく開くターミナルのデフォルト設定を変える
「ファイル」→「ユーザ設定」→「設定」
```:設定の検索窓にいれる文字列
terminal.integrated.shell
```
![term_set.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2381513/3e4be8f9-0301-2a6a-a88f-7246e254f4ae.png)
はい、デフォルトで起動するターミナルのプロファイルを選択する項目があります。
Powershellやらコマンドプロンプトやらありますね。ここで選択すればOKです。

# (応用編) 選択できるプロファイルを追加する
例えば、anaconda用に設定されたPowershellを追加したい。
追加しましょう。setting.jsonに追加します。
setting.jsonの場所は先ほどの設定の上のほうにOSXの設定がありますが、そこにsetting.jsonで編集というリンクがあるのでクリック。
![json.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2381513/35277928-a946-41da-e26a-7b861dcaf894.png)



# (応用編) setting.jsonにプロファイルを追記する
今回はanaconda環境で作業したいので、anaconda用に設定されたPowerShellを設定プロファイルに追加したいと思います。
コピペもいいですが、簡単に内容を説明します。
"terminal.integrated.profiles.windows"属性が先ほどのプロファイルリストの中身になります。
その中に任意のプロファイルを追加します。
(ここでは"PS(miniconda)"という名前のプロファイルを追加)
"source"は立ち上げるターミナルの種類。
"args"はターミナルを立ち上げる時の引数のようです。
ここでは、anaconda関係のコマンドにパスを通すconda-hook.ps1を実行して、anacondaのbase環境をアクティベートするという内容になっています。
"-Command"以下で複数のコマンドを実行するときは2行に分けて書くようです。

```:setting.json
{
    "terminal.integrated.profiles.windows": {
        "PS(miniconda)": {
            "source": "PowerShell",
            "args": [
                "-ExecutionPolicy",
                "ByPass",
                "-NoExit",
                "-Command", 
                "C:\\Users\\hogeo\\miniconda3\\shell\\condabin\\conda-hook.ps1",
                "; conda activate 'C:\\Users\\hogeo\\miniconda3'"
            ],
            "icon": "terminal-powershell"
        }
    }
}
```


# 確認
今一度、設定画面に戻り、先ほどのプロファイルが追加されていることを確認します。
"PS(miniconda)"プロファイル追加されていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2381513/2cd8268f-4b0b-c08f-36a4-8f36a72356e4.png)

Ctl+Shift+@押して新しいターミナルを立ち上げて、
```
(base) PS C:\Users\hogeo\
```
てな感じでVSCodeのターミナルに表示されていればOKですね。
フォロワーを1人増やすには何人にいいねしないといけないか

TwitterなどのSNSを利用していると、色々な動機でフォロワーを増やしたくなりますよね！
フォロワーを増やす方法のひとつに、ツイートにたくさんいいねをしていく方法があります。
でも、一体何人にいいねをすればいいのか分からず、闇雲にいいねをしていくのは辛いですよね、、、

そんな時には統計学を使えば見通しを持つことができます！

# 二項分布の応用

まず、いいねをした人の数といいねをした人の中でフォロワーになった人数を数えます。
例えば、今日一日で100人にいいねをして三日後に何人フォロワーが増えたか集計するわけです。
次に、増えたフォロワーの数をいいねをした人の数で割り、いいねをした人がフォロワーになった確率を求めてください。100人にいいねをして3人フォロワーが増えたなら、確率は　3 / 100 = 0.03です。この確率を利用して何人にいいねをしないといけないか計算することができます！


いいねを押すとフォロワーが増える、増えないのどちらかであることから、この問題を二項分布によって表すことができ、Twitterでいいねをしてフォロワーが少なくとも一人増える確率を95％以上にするには何人にいいねしないといけないかを考えます。

フォロワーになった人の数をX、いいねをしてフォロワーになる確率を0.03、n人にいいねをしたとすると、X~B(n, 0.03)。
フォロワーが少なくとも一人増える確率を95％以上にするので、

```math 
\begin{align}
P(X\geqq1)\geqq0.95\\
1-P(X=0)\geqq0.95\\
1-(1-0.03)^n\geqq0.95\\
(0.97)^n\leqq0.05\\
n\log0.97\leqq\log0.05\\
n\geqq\frac{\log0.05}{\log0.97}\\
n\geqq98.352
\end{align}
```
ゆえに、99人以上で少なくとも一人フォロワーが増える。

# 上の式をPythonでプログラムすると、、、
```python
import cmath
import math

input_followed_probability = input('いいねをした人がフォロワーになった確率を小数で入力してください（例　８％→０.０８：')

#今回は少なくとも一人増える確率を95％以上にしたいので、1 - 0.95 = 0.05
a = math.log10(0.05)

#真数が負の場合、mathのlog10()ではなくcmathのlog10()を使う。
b = cmath.log10(1- float(input_followed_probability))

n = a / b

#nは98.35227246335738-0jで複素数になっている。
#実部だけ取り出すためにreal属性を使う。
real = n.real

#float()に複素数を入れるとTypeError: can't convert complex to floatとなるため実部だけを代入する。
c = float(real)

#小数点以下切り上げ
m = math.ceil(c)

print(f'{m}人')
```

これでいいねをした人がフォロワーになった確率を小数で入力するだけで、何人にいいねをすればフォロワーが増えるかが分かります！また、いいねではなくリツイートでも同様のことができると思います。

統計学を使って効率よく目標を達成しましょう！

### 追記
求めた人数の解釈は、特定の期間に特定の人数にいいねをしてフォロワーの増加分を観測する作業を、100回繰り返したら、95回以上は少なくともその人数で、フォロワーが少なくとも一人増える、ということでいいのでしょうか？
統計学初学者なので解釈に自信がありません。詳しい方がいらしたら教えて頂けると幸いです（プログラミングも初心者なのでアドバイス頂けると助かります）。
Laravel Breezeのインストールと日本語化

```bash
composer require laravel/breeze --dev
php artisan breeze:install
npm install && npm run dev
```
でインストール
データベースを使うので
```bash
php artisan migrate
```
日本語化には[GitHub](https://github.com/Laravel-Lang/lang)からファイルを落として解凍、できたフォルダのlocales/ja/ja.jsonを日本語化したいプロジェクトのresources/langにコピー
Laravelの日本語設定が済んでいればほとんどこれで日本語化されるのだが3〜4個トップページのbladeなどに英語が残ったままなので手っ取り早く直接修正
UE4のHDR対応その後

この記事は、2021年末の[UE4アドベントカレンダー](https://qiita.com/advent-calendar/2021/ue)の記事、
[UE4のHDR対応はどうなってるの？Win10編](https://qiita.com/dgtanaka/items/672d2e7b3152f4e5ed49)の後にわかったことなどをまとめた記事です。
記事を書いたときにはHDRの入り口で迷っていたレベルでしたが、自分もちょっと成長したのかな？
以下、UE4.27での状況です。

# UE4エディタでHDRはちゃんと描画されない
　はい、UE4エディタではHDRモードに切り替えることはできますが、正しく描画されません。これはPIE(Play in Editor)も同じです。なぜかというと、UE4エディタではゲーム画面を描画したあと、エディタUIに貼り付けてデスクトップ画面に表示されるのですが、エディタUIの描画そのものがHDR出力に正しく設定されていないので、そこにHDRのカラースペースの画像を貼り付けても正しい色で表示されません。この辺はUE5で改善されることを期待したいです。エディタ上で普通にHDR作業ができる時代はもうすぐです。きっと。
# WindowsでのHDR対応の条件
　WindowsでUE4でHDR描画をするためには次のような条件が必要です。
1. r.AllowHDR=1 が設定されている。
2. HDRディスプレイに接続されている
3. Windows10以降でHDRが有効になっている
4. DirectX12でビルドされている
5. エディタからスタンドアローンで実行するか、ゲームビルドで実行する

1は起動後の変更ができないので、GameEngine.iniなりに記述しておく必要があります。コマンドラインオプションで -hdr を指定することでも設定できます。
2,3は当然ですね。
4はDirectX11でも排他的フルスクリーンならHDRにできるかもしれないですが、試してないです。
5は前述の通り。

以上の条件を満たしたところで、コンソールコマンドから

```
r.HDR.EnableHDROutput 1
r.HDR.Display.OutputDevice 3
```

でHDR描画に切り替わります。
ということで、HDRにするのは難しくありません。問題はここから。


## HDRではUIが正しく描画されない
　現在のところ、HDRでのUI描画には色々問題があります。順番に説明します。
### UI CompositeMode
　HDRに切り替えると、r.HDR.UI.CompositeMode=1がデフォルトで設定されます。この状態ではUIの描画の仕組みが変わります。具体的にはUIを全て別バッファに描画して、最後にまとめてゲーム画面に合成します。ちょうどSeparate Translucencyと同じようなものですね。

　ところが、このモードにはいくつか問題があります。

#### カラー変換が正しくない
　別バッファに描画されたUIをHDR画面に合成するときのカラースペースの変換に間違いがあり、正しい色で描画されていません。この問題に関してはUDNにも報告されており、修正方法が提示されています。

#### BackgroundBlurを他のUIが上書きしてしまう
　BackgroundBlur自体は描画処理は行われているのですが、実際にUIが描画時に参照するのはBackgroundBlurが描画される前の画面なので、UIが上に描画されると無かったことにされてしまいます。この点もUDNでは修正方法が報告されています。
　ただし、この修正でもUIの上にBackgroundBlurが描画された場合には反映されません。UI全体の背景としてBackgroundBlurは使用できますが、UIそのものをぼかしたいといった用途には使用できません。

#### UIのBlendModeがTranslucentに限定される
　これは一旦別バッファに描かれたUIをアルファ値で一括合成するのが理由です。一括なのでアルファ値で合成することしかできません。Translucent以外のBlendModeで描画されたUIはすべてTranslucentとして描画されてしまいます。

#### UIの明るさは調整できる
　これはありがたい機能で、r.HDR.UI.LevelでUI全体の明るさが調整できます。HDRディスプレイによってはSDRが相対的に暗い場合がありますが、そういった場合に調整できるのはありがたいですね。

### UI CompsiteModeを切ると？
　CompsiteModeを使用しないと上記の問題は回避でき、BlurもTranslucent以外のBlendModeも描画されます。しかし、HDR空間にsRGB空間で描画するため、色が正しく出ません。妙に濃かったりドギツイ色で描画されてしまったりします。

## FilmicTonemapperが適用されない
　ゲーム画面をFilmicTonemapperで調整していた場合、その調整がHDRには反映されません。FilmicTonemapperで画面を明るくしたり暗くしてた場合、HDRでは全く違う明るさになってしまいます。
　同時にr.TonemaperGammaでの調整もできないので、HDR画面をユーザー環境にあわせて明るさ調整をしたいと思っても簡単にはできません。カラーグレーディングは機能するので、カラーグレーディング関連のパラメーターにHDR時にオフセットを加えるという手段はありそうです。

# まとめ
　ということでUE4のHDRにはまだまだ闇が広がっているみたいです。UE5もリリースされたことですし、UE5でのHDR対応が進んでいくのを期待したいところです。
Kubernetes + ArgoCD で HPA する時は ignore が必要

## TL;DR
 - ArgoCD で HPA を設定した場合、常に OutOfSync となり、pods の増加・減少が繰り返されてしまう
 - 特に　AverageValue　の場合、関係ない値 spec.metrics[].object.target.value が　HPA　によって差し込まれてしまう問題がある
 - 上記含め、HPA が変更する箇所は ignore してやる必要がある
 - [ドキュメント](https://argo-cd.readthedocs.io/en/stable/user-guide/diffing/)

## 個別設定
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  namespace: argocd
  name: hogehoge
spec:
 ignoreDifferences:
   - group: apps
     kind: Deployment
     jqPathExpressions:
       - .spec.replicas
   - group: autoscaling
     kind: HorizontalPodAutoscaler
     jqPathExpressions:
       - .spec.metrics[].object.target | select(.type == "AverageValue") | .value
...
```

## グローバル設定
 - グローバルに設定しておけば個別に設定しなくてよい。

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: argocd
  name: argocd-cm
  labels:
    app.kubernetes.io/name: argocd-cm
    app.kubernetes.io/part-of: argocd
data:
  resource.customizations.ignoreDifferences.apps_Deployment: |
    jqPathExpressions:
        - .spec.replicas
  resource.customizations.ignoreDifferences.autoscaling_HorizontalPodAutoscaler: |
    jqPathExpressions:
        - .spec.metrics[].object.target | select(.type == "AverageValue") | .value
```
【Angular】mswで簡単APIモック

# TL;DR

[msw](https://github.com/mswjs/msw)を使ったら、すごく簡単にAPIモックができました。

# バージョン

```sh
% msw --version                                                                                                                                                               
0.39.2
```

Angularのバージョンは`11.2.8`で確認しています。

# インストール

```sh
% yarn add -D msw
```

# セットアップ

初期化コマンドを実行して、`src`配下に`mockServiceWorker.js`を生成します。

```sh
% npx msw init src
```

次に、`angular.json`を修正します。

```angular.json
{
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": {
      "assets": [
        "src/favicon.ico",
        "src/assets",
        "src/mockServiceWorker.js" // 追加
      ],
    }
  }
}
```

あとは、モックする処理を`browser.ts`に書いて

```browser.ts
import { setupWorker, rest } from 'msw'

export const mocks = [
  rest.get('https://hoge.com/users/:user', (req, res, ctx) => {
    const { user } = req.params

    return res(
      ctx.status(200),
      ctx.json({
        name: `mocked-${user}`,
      }),
    )
  }),
]

const worker = setupWorker(...mocks)
worker.start()

export { worker, rest }
```

開発環境でのみモックさせるように、`environment.ts`で`import`します。

```environment.ts
import '../mocks/browser'

export const environment = {
  production: false,
}
```

# 動作確認

Angularを起動し、コンソールログに`[MSW] Mocking enabled (fallback mode).`と表示されていたら、workerが正常に起動しています。

あとは、APIがモックできていることを確認しましょう。

# トラブルシュート

### `Warning: captured a request without a matching request handler:`

デフォルトの設定だと、モックされていないAPIリクエストに対して、コンソールに警告が表示されます。
消したいときは`onUnhandledRequest`の設定値を`bypass`に変更します。

```browser.ts
worker.start({
  onUnhandledRequest: 'bypass',
})
```

# 所感

mswはService Workerでモックしているので、アプリケーションとして本番環境とほとんど変わらずに動作確認できるのが大きなメリットですね。あと、`json-server`を使うときのように、別プロセスを起動する必要もないので、管理しやすそうです。


# 参考

- [msw公式ドキュメント](https://mswjs.io/docs/)
- [Using MSW (Mock Service Worker) in an Angular project](https://timdeschryver.dev/blog/using-msw-in-an-angular-project)
- [Mock Service WorkerでAPIをモックして開発をスムーズに進められた話](https://tech.classi.jp/entry/2022/03/30/120000)
WindowsにRustをインストールする一番簡単な方法

コマンドを数回叩くだけで、RustをWindowsにインストールする方法を紹介します。

もちろん、[公式の手順](https://docs.microsoft.com/ja-jp/windows/dev-environment/rust/setup)でインストールするのがオススメです。しかし、ビルドツールのセットアップがかなり面倒でした。そこで、次回自分がインストールする時のために手軽な方法をメモしておきます。ここで紹介する手順は下記の通りです。

- [1] [Chocolateyをインストール](https://chocolatey.org/install)
- [2] Chocolateyでビルドツールをインストール 
- [3] ChocolateyでRustをインストール


# [1] Chocolateyをインストール

ChocolateyとはWindowsのパッケージマネージャーです。このパッケージマネージャーをインストールするために、まず、**管理者権限**で、PowerShellを起動します。**管理者権限**が大切です。

[こちらChocolateyのページ](https://chocolatey.org/install)にあるインストールスクリプトをコピーして、PowerShell上で実行します。Chocolateyがインストールできたら、準備完了です。

# [2] Chocolateyでビルドツールをインストール 

以下のコマンドを実行して、ビルドツールをインストールします。

```
choco install visualstudio2019buildtools
```


# [3] ChocolateyでRustをインストール

続いて、Rustをインストールします。

```
choco install rust
```

以上で完了です。

# インストールが成功しているか確認する

この時点で、Rustのビルドツール＆パッケージマネージャーのCargoが使えるようになっているはずです。以下のコマンドを実行してみましょう。

```
cargo
```

![スクリーンショット 2022-04-07 16.55.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/81b96f7c-63e5-8e05-8a18-6ab456443007.png)


# 参考まで

なお、Rustの本を書きました。良かったら見てみてください。

https://www.amazon.co.jp/dp/4802613512/ref=as_sl_pc_tf_til?tag=text2musiccom-22&linkCode=w00&linkId=97170724c87fa892e4a05732776c9586&creativeASIN=4802613512
Vuetifyのインストールから初期表示まで

### Vuetifyのインストール

VuetifyはVue.jsのUIライブラリーです。デザインの知識がなくても、GUI画面を簡単に作成することができます。

Vuetifyサイトへ行きます。
https://vuetifyjs.com/ja/

**はじめよう**をクリックします。
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381365/4f35c4d5-93cf-f88e-48ec-008bc70da1f2.png)



ここではVue CLIからインストールする手順をご紹介します。
Vue CLIのインストールについては、[VueCLI(Vue.js)の環境構築](https://qiita.com/s-tsutsumi/items/5c16b573c986c547117e)を参照ください。


Vueプロジェクトを作成します。
```
$ vue create myapp
$ cd myapp
```

Vuetifyをインストールしていきます。
```
# Vuetifyをインストール
$ vue add vuetify
```

yを選択
```
 WARN  There are uncommitted changes in the current repository, it's recommended to commit or stash them first.
? Still proceed? (y/N)
```

※下記エラーが出た場合、記事執筆時点で、VuetifyはVue3に対応していないため、プロジェクトをVue2で作成し直してから、再度、`vue add vuetify`を実行してみてください。
```
 ERROR  Error: You cannot call "get" on a collection with no paths. Instead, check the "length" property first to verify at least 1 path exists.
Error: You cannot call "get" on a collection with no paths. Instead, check the "length" property first to verify at least 1 path exists.
    at Collection.get (/usr/local/lib/node_modules/@vue/cli/node_modules/jscodeshift/src/Collection.js:213:13)
    at injectOptions (/usr/local/lib/node_modules/@vue/cli/lib/util/codemods/injectOptions.js:15:6)
    at runTransformation (/usr/local/lib/node_modules/@vue/cli/node_modules/vue-codemod/dist/src/runTransformation.js:60:17)
    at /usr/local/lib/node_modules/@vue/cli/lib/Generator.js:332:23
    at Array.forEach (<anonymous>)
    at Generator.resolveFiles (/usr/local/lib/node_modules/@vue/cli/lib/Generator.js:318:24)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Generator.generate (/usr/local/lib/node_modules/@vue/cli/lib/Generator.js:204:5)
    at async runGenerator (/usr/local/lib/node_modules/@vue/cli/lib/invoke.js:111:3)
    at async invoke (/usr/local/lib/node_modules/@vue/cli/lib/invoke.js:92:3)
```

Defaultを選択
```
📦  Installing vue-cli-plugin-vuetify...
added 9 packages in 6s
✔  Successfully installed plugin: vue-cli-plugin-vuetify

? Choose a preset: (Use arrow keys)
  Configure (advanced)
❯ Default (recommended)
  Vite Preview (Vuetify 3 + Vite)
  Prototype (rapid development)
  Vuetify 3 Preview (Vuetify 3)
```

下記が出たら成功です。
```
✔  Successfully invoked generator for plugin: vue-cli-plugin-vuetify
 vuetify  Discord community: https://community.vuetifyjs.com
 vuetify  Github: https://github.com/vuetifyjs/vuetify
 vuetify  Support Vuetify: https://github.com/sponsors/johnleider
```

### Vuetify実行

サーバを起動します。
```
npm run serve
```

指定されたURL　`http://localhost:8081/` にアクセスします。
```
DONE  Compiled successfully in 78013ms                                                                       4:49:28 PM


  App running at:
  - Local:   http://localhost:8081/
  - Network: http://x.x.x.x:8081/

  Note that the development build is not optimized.
  To create a production build, run npm run build.
```

下記画面が表示されたら成功です！

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381365/ac241611-fa2e-ed09-64c0-01de26e78fc1.png)
parcelでtypescriptをコンパイルしたときにprocess.envがインライン展開された件とその対応

# 事象

lambda functionをtypescriptで書き、parcelでビルドしていたのですが、
lambda上で `process.env.VAL` が何故か `undefined` になってしまっていました。

# 原因

parcelでコードをビルドしていましたが、
parcelは `package.json` に後述の設定がないと、process.envのプロパティにアクセスしているところを親切にもインライン展開してくれるようです。

# 対策
この挙動が嫌な場合は下記を入れましょう。

```json:package.json
{
  ...
  "engines": {
    "node": ">=14"
  },
  ...
}
```

nodeのversionはlambdaのランタイムで良いと思います。

# 参考
[package.json#engines](https://parceljs.org/features/targets/#package.json%23engines)
Oracle Cloud Infrastructure(OCI)関連の主な契約関連文書

Oracle Cloud Infrastructure (OCI) の主な契約関連文書についてまとめました。(2022/4時点）
正式かつ最新の情報は[オラクル社のホームページ](url "https://www.oracle.com/corporate/contracts/cloud-services/")をご確認ください。

| 文書名 | 日本語版の公開 | 説明 |
|:---|:-:|:---|
|Oracle Cloud Services Agreement (CSA)|[〇](URL "https://www.oracle.com/a/ocom/docs/corporate/cloud-csa-jp-jpn-v040119.pdf")  |注文書から参照されているCloud契約文書。リンクは日本向けのもの。機密保持条項や責任範囲などの記載あり。|
|[Data Processing Agreement for Oracle Services (DPA)<br>2019/6/26](URL"https://www.oracle.com/a/ocom/docs/corporate/data-processing-agreement-062619.pdf")|×   |クラウドにおけるデータ処理に関する文書。個人情報の取り扱いに関する記載あり。|
|[Oracle Cloud Hosting and Delivery Policies<br>2021/12](URL"https://www.oracle.com/assets/ocloud-hosting-delivery-policies-3089853.pdf")|[〇<br>2020/6](URL "https://www.oracle.com/assets/cloud-hosting-delivery-policies-jp-5023328.pdf")  |クラウドサービスに関する具体的なポリシーの記載あり。<UL><LI>Oracle Cloud Security Policy<LI>Oracle Cloud Service Continuity Policy<LI>Oracle Cloud Service Level Agreement<LI>Oracle Cloud Change Management Policy<LI>Oracle Cloud Support Policy<LI>Oracle Cloud Suspension and Termination Policy</OL>|
|[Oracle PaaS/IaaS Public Cloud Services Pillar Document<br>2022/3](URL"https://www.oracle.com/assets/ocloud-hosting-delivery-policies-3089853.pdf")|×|H&Dの補足文書。特にService Level Agreement Policyの詳細が記載してある。|
|[Oracle Privacy Polices](URL"https://www.oracle.com/legal/privacy/")|[〇](URL "https://www.oracle.com/jp/legal/privacy/")  |オラクル社のプライバシーに関するポリシー。|
|[Oracle Security Practices](URL"https://www.oracle.com/corporate/security-practices/")|△|オラクル社のセキュリティ規定。クラウドの運営がしっかりされているかを確認したい時に参照。一部英語のものもある。<UL><LI>Corporate Security Practices<LI>Oracle Software Security Assurance<LI>Oracle Cloud Security Practiceなど</OL>|
|[Oracle Cloud Services Program Documentation](URL"https://docs.oracle.com/")|△|H&Dに書いてある”Program Documentation”とは、マニュアルのこと。主なものは日本語化されているが一部英語のものもある。|
Laravel環境にPHP-CS-Fixerを導入する

# 概要

- Laravelの開発環境にPHP-CS-Fixerを導入する方法をまとめる。

# 方法

1. アプリ名ディレクトリに移動して下記コマンドを実行してtoolsディレクトリとその直下にphp-cs-fixerディレクトリを設置する。

    ```terminal
    cd アプリ名ディレクトリ
    mkdir -p tools/php-cs-fixer
    ```

1. アプリ名ディレクトリで下記コマンドを実行して、先に作成したディレクトリを指定してphp-cs-fixerのライブラリ本体をインストールする。（docker環境の場合、`$ docker-compose exec php composer require --working-dir=tools/php-cs-fixer friendsofphp/php-cs-fixer`を実行するか、PHPのコンテナに入り、アプリ名ディレクトリに移動して下記コマンドを実行する。）

    ```terminal
    composer require --working-dir=tools/php-cs-fixer friendsofphp/php-cs-fixer
    ```

1. アプリ名ディレクトリに`.php-cs-fixer.dist.php`ファイルを作成して下記の様に記載する。（laravelのコードをgit管理しているならこのファイルもgit管理することをおすすめする）

    ```アプリ名ディレクトリ/.php-cs-fixer.dist.php
    <?php 

    declare(strict_types=1);
    
    $finder = PhpCsFixer\Finder::create()
        // チェックするディレクトリの指定
        ->in([
            __DIR__ . '/app',
            __DIR__ . '/config',
            __DIR__ . '/database/seeders',
            __DIR__ . '/routes',
            __DIR__ . '/tests',
        ]);
    
    $config = new PhpCsFixer\Config();
    
    return $config
        ->setRiskyAllowed(true)
        ->setRules([
            '@PSR2' => true,
        ])
        ->setFinder($finder);
    ```

1. 下記コマンドを実行してエラーが出なければ導入完了（docker環境の場合、`$ docker-compose exec php ./tools/php-cs-fixer/vendor/bin/php-cs-fixer`を実行するか、PHPのコンテナに入り、アプリ名ディレクトリに移動して下記コマンドを実行する。）

    ```terminal
    ./tools/php-cs-fixer/vendor/bin/php-cs-fixer
    ```

# 2022/06/20追記

- tools直下のvendorディレクトリをgitの管理から外したい場合下記の内容の`.gitignore`ファイルをtools直下に設置すれば良い。

    ```.gitignore
    .php-cs-fixer.cache
    /tools/php-cs-fixer/vendor
    ```

- リポジトリで一個の`.gitignore`ファイルで終わらせたいならメインの`.gitignoreファイル`からの相対パスで当該tools直下の/vendorディレクトリを指定する。
- ただし/vendorをgit管理下から外した場合、セットアップ時などのcomposer install実行するときにアプリ名ディレクトリとtoolsディレクトリの二箇所で実行する必要があると思う。

# 2022/08/29追記

- クローンしたら通常のアプリ名ディレクトリでのcomposer installとは別に下記を実行してphp-cs-fixerをインストールする必要あり。

    ```shell
    composer install --working-dir=tools/php-cs-fixer
    ```

# 参考文献

https://github.com/FriendsOfPHP/PHP-CS-Fixer

https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/master/doc/usage.rst

https://qiita.com/miriwo/items/bdf37a27051a5635f502

https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/master/doc/rules/index.rst

https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/master/doc/ruleSets/index.rst
teratermのid_rsaが無い【備忘録】

サーバ技術者養成講座16日目。
teratermで公開鍵・秘密鍵を作成し、id_rsa(.pub)として保存。
しかし、保存時のパスC:¥Program Files(x86)¥teratermにはどうも見当たらない。

調べたところ、C直下ではなくユーザファイル下にあるもよう。
C:\Users\ユーザー名\AppData\Local\VirtualStore\Program Files (x86)\teraterm
確認したところ、無事発見。(ちなみにこのteratermフォルダ、themeフォルダとid_rsaしか置いていなかった)
実のところよくわかっていないが、teratermにC直下ファイルの書き込み権が無く、このようになるらしい。

参考(ほぼコピペ)URL: https://teratail.com/questions/64838
Slackで既存のユーザーを新しいチャンネルにすべてごっそり追加する

Slackを運営していて、メンバー全員を新しく作ったチャンネルに追加したいときってよくありますが、長年ググってもあまりピンとくる方法がありませんでした。

が、いつのまにかなのか最初からあったのか、簡単なやり方を見つけたので紹介しておきます。
手順はWindows版のアプリを前提にやってますが、権限があれば他プラットフォームのアプリやWeb版でもできるのではないかと思います。あと、スクショは英語環境になってるので、日本語UIを使ってる人は適当に読み替えてください。

# 手順
1. 招待したい人が入っているチャネルを開く
1. チャンネル名のところをクリックして詳細画面を開く
1. ***Settings*** タブの ***Copy member names*** をクリックする → ここでメンバー名がクリップボードにコピーされる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/1bd633d7-11f8-eff3-9282-d6d8de1ff0c3.png)
1. ダイアログを閉じる
1. コピー先のチャネルで ***Add people*** をクリックして ***Ctrl+V*** でペーストするとこのようにがさっとコピーされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/319692e1-32cf-87da-6c16-1f142ee6c4d1.png)
1. あとは、全員であればこのまま ***Add*** すればいいし、自分も入ってるので、そこは消してから ***Add*** してください。

# 前提条件
* 有料プランであること
* チャンネルへの参加者が1000人以下であること

# 実は
メールアドレスのコピペとかでも可能。なので、社内Slackとかでメールアドレスが分かってる場合は、そっちのほうが便利かもしれない。
いずれにしても、コピペで結構楽ちんにできるので目からウロコでした。だから誰も記事にしないのかな。。。

# 参考

https://slack.com/intl/ja-jp/help/articles/4409607962387-%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%8B%E3%82%89%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC%E5%90%8D%E3%81%A8%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%82%92%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B
PowerVC Tips: ストレージのボリューム保護機能によるイメージ・エクスポート、インポートの失敗

##### 事象

PowerVC のイメージ・エクスポート、イメージ・インポートでは、PowerVCサーバー(またはPowerVCバックアップ・ノード)に対して一時的ストレージのマッピングや一時的ボリューム作成、削除などが発生します。

・イメージのエクスポートおよびインポート
https://www.ibm.com/docs/ja/powervc/2.0.2?topic=images-exporting-importing


PowerVCで登録しているストレージ側の機能でボリューム保護機能を有効化していた場合は、イメージ・エクスポート、イメージ・インポート操作が阻害されていました。




---


##### 失敗した際にログに出力していた内容

イメージ・エクスポート失敗時の/var/log/cinder/backup.log の抜粋例

```
cinder.exception.VolumeBackendAPIException: ストレージボリュームバックエンド API からの不正な応答または想定しない応答: CLI 例外出力:
    コマンド: ['svctask', 'rmvdiskhostmap', '-host', '"POWERVCHOST"', '"volume-temp_vol_f3xxxxe-9xxx-4071-bxxx5-7520-cxxxx30-2e08"']
     stdout:
     stderr: CMMVC8478E The mapping cannot be removed because the volume being unmapped has received I/O within the defined volume protection period.

```

定義されたボリューム保護機能期間にI/Oが発生しているので、ボリュームのマッピングを解除できないというエラーが出ています。

このような場合では、ストレージ側でのボリューム保護機能をオフにすることでイメージ・エクスポート、インポートが成功することが確認できています。


(保護機能を有効化して運用したい場合は、インポート、エクスポート操作が終わった際には保護機能設定を元に戻します)


---
(ご参考) FS9000 : ボリューム保護
https://www.ibm.com/docs/ja/flashsystem-9x00/8.3.x?topic=volumes-volume-protection
_ボリューム保護は、システムが最新の入出力アクティビティーを検出した場合にアクティブ・ボリュームまたはホスト・マッピングが誤って削除されないようにします。このグローバル設定は、新しいシステム上でデフォルトで有効になります。システムで構成されているすべてのボリュームにこの値を適用するか、または特定のプールでシステム・レベルのボリューム保護を有効にするか無効にするかを制御できます。_


---

以上です。
LightGBM基礎

# LightGBMとは

・LightGBMは決定木の勾配ブースティングのフレームワーク


## 決定木
・決定木（DecisionTree）は教師あり学習の一つ
・チャート表示をすると推測結果を明確かつ簡単に説明できる

## アンサンブル学習
・Ensemble Learning
・勾配ブースティングはアンサンブル学習のブースティングの手法を使用する
・アンサンブル学習は複数のモデルを融合させて1つの学習モデルを生成する手法
・複数人で意見を出し合って知識を補い合いながら解く方が正答率が上がるのと考え方は同じ
・アンサンブル学習は「バギング」「ブースティング」「スタッキング」の3つの手法に分けることができる
・バギングはそれぞれのモデルを並列的に学習を行う。対してブースティングは前の学習器の結果を次の学習データに反映させる。
・バギングによるアンサンブル学習の手法を「ランダムフォレスト」と呼ぶ。対して、勾配ブースティングは決定木を弱学習器として「ブースティング」の手法を用いてアンサンブル学習を行う。

## 勾配ブースティング
・勾配ブースティングは複数の弱学習器（LightGBMの場合は決定木）を１つにまとめるアンサンブル学習の「ブースティング」を用いた手法
・前の学習結果を次の学習へ反映させる方法
　・まず決定木1号でモデル訓練を行い推測結果を評価する
　・決定木2号は1号の推測結果と実際の値の誤差を訓練データとして、2号の訓練を行う。N号の決定木はN-1号の決定木の誤差（Residuals）を学習する。
・勾配ブースティングはそれぞれの弱学習器の誤差を学習する


# 参考
https://www.codexa.net/lightgbm-beginner/
[TeX] 記号を重ねたときのボックスの上端下端位置

完全に作業ログなのですが記録を残しておきます。

# 前提

積分記号に別の記号を重ねて、特殊記号を自前で作っていました。

以下は説明のために用意したサンプルコードです。MathJaxでooalignなんて使えるわけはなかったので興味がある方は各自の手元で確認してください。
```tex
\mathop{\ooalign{%
  \hbox{$<$}\crcr%
  \hss$\displaystyle\int$\hss%
}}
```

# 発生した現象
表示上は先ほどのコードで問題なく積分記号に<が重なるのですが、上下に記号を配置(つまり通常の積分記号における積分範囲の上限・下限を書く位置)しようと思ったら、下側は想定通りの配置であった (このせいで気付くのが数か月遅れた) のに、上側はなぜか行の中央ちょっと上寄りに配置されるという不思議現象が発生しました。


どうやらooalignで記号を重ねた場合、ボックスの上端は先に配置した記号の上端、下端は最後に配置した記号の下端で計算されるようです。描画順を逆にしたら上下逆の現象が再現できました。

# 解決策
ここで[esint](https://ctan.org/pkg/esint)パッケージはどう解決しているのか確認すると、それ用のフォントを用意していました。確実だけど手元でぱぱっとやるにはコスト高すぎて不採用。

仕方がないので描画命令の最初と最後で2回積分記号を描かせる強引な解決方法を採用しました。うーん汚いけど仕方がない
複数のテーブルを同時にDELETEするには

## DB Fiddleで動かす

https://www.db-fiddle.com/f/dNjvZ3ce2kfQQ9abxgPG1r/1

## 概要

```sql
CREATE TABLE users (
  id INT NOT NULL PRIMARY KEY,
  name VARCHAR(100),
  date_of_birth DATE
);

CREATE TABLE clubs (
  user_id INT NOT NULL PRIMARY KEY,
  name VARCHAR(100)
);

-- ユーザ
INSERT INTO users VALUES
  (1, "Akita", "1985-01-01"),
  (2, "Inoue", "1986-01-01"),
  (3, "Ueda", "1987-01-01"),
  (4, "Endou", "1988-01-01"),
  (5, "Okada", "1989-01-01")
;

-- 所属クラブ
INSERT INTO clubs VALUES
  (1, "soccer"),
  (2, "baseball"),
  (5, "tennis")
;
```

上のようなテーブルとレコードがあって、「クラブに所属していて誕生日が1988/01/01よりも前のユーザとその所属クラブのレコード」を削除したいとき、どうすべきかを考える必要がありました。
（もちろん実際には全然違う話でしたが、２つのテーブルからそれぞれ削除条件を考えて削除しなければいけないケースがありました）

最初は以下のように

```sql
-- 所属クラブを削除
DELETE c
FROM clubs AS c
INNER JOIN users AS u ON c.user_id = u.id AND u.date_of_birth < "1988-01-01";

-- ユーザを削除
DELETE u
FROM users AS u
INNER JOIN clubs AS c ON u.id = c.user_id
WHERE u.date_of_birth < "1988-01-01";
```

それぞれ別にDELETEしようとしましたが、当然これでは意図した通りに削除されません。
先にDELETEをかけている`clubs`テーブルは意図した通りに削除されますが、`users`テーブルでは既に`clubs`テーブルが削除されてしまっているので**クラブに所属している**という条件で絞り込めなくなっています。

**users**

| id | name | date_of_birth |
|:--|:--|:--|
| 1 | Akita | 1985-01-01 |
| 2 | Inoue | 1986-01-01 |
| 3 | Ueda | 1987-01-01 |
| 4 | Endou | 1988-01-01 |
| 5 | Okada | 1989-01-01 |

**clubs**

| user_id | name |
|:--|:--|
| 5 | tennis |

---

逆に`users`テーブルから削除しようとすると、今度は`clubs`テーブルのレコードが削除されなくなってしまいます。

**users**

| id | name | date_of_birth |
|:--|:--|:--|
| 3 | Ueda | 1987-01-01 |
| 4 | Endou | 1988-01-01 |
| 5 | Okada | 1989-01-01 |

**clubs**

| user_id | name |
|:--|:--|
| 1 | soccer |
| 2 | baseball |
| 5 | tennis |

---

同時に２つのテーブルをDELETEするという発想がなかったので、自分はここで恐ろしく悩む羽目になりました。
実際にはただ以下のようにすればよかっただけでした。

```sql
DELETE u, c
FROM users AS u
INNER JOIN clubs AS c ON u.id = c.user_id
WHERE u.date_of_birth < "1988-01-01";
```

このクエリであれば意図した結果が得られます。

### users

| id | name | date_of_birth |
|:--|:--|:--|
| 3 | Ueda | 1987-01-01 |
| 4 | Endou | 1988-01-01 |
| 5 | Okada | 1989-01-01 |

### clubs

| user_id | name |
|:--|:--|
| 5 | tennis |

## そもそも...

MySQLであれば公式のドキュメントに記載があった。

https://dev.mysql.com/doc/refman/8.0/ja/delete.html

> 複数テーブルの削除

## 参考

[【MySQL】共通のIDのデータを複数テーブルからDELETEする  |  hamalabo](https://hamalabo.net/mysql-multi-delete)
Arch Linuxで複数NICの設定をする


有線LANと無線LANを両方同じサブネットに接続しようとしてハマったのでメモがてら。

## 構成
・Archがインストールされているマシンには無線LANと有線LANの2つのNICがある
・有線LANと無線LANの両方を同じネットワークに接続したい
・有線LANが優先的に使われてほしい
・それぞれ固定IPを振る(DHCPは使用しない)
・netctlのみで管理する

## やること
### 余計なサービスを無効化する
`sudo systemctl disable dhcpcd`
`sudo systemctl disable systemd-resolved`
`sudo systemctl disable NetworkManager`

### DNSの設定
`/etc/resolv.conf`にDNSサーバのIPを追記
`nameserver 8.8.8.8`
`nameserver 192.168.0.1`  # ルーター内蔵DNS

### netctlの設定
NICごとにプロファイルをつくる
#### 有線LAN
`sudo vim /etc/netctl/ethernet`(新規作成)
```
Interface=enp1s0
Connection=ethernet
IP=static
AutoWired=yes
Address=('192.168.0.122/24')
Routes=("default via 192.168.0.1 dev enp1s0 src 192.168.0.122")
# DNS=('192.168.0.1')
```

#### 無線LAN
`sudo vim /etc/netctl/wlan0`
```
Description='A simple WPA encrypted wireless connection'
Interface=wlan0
Connection=wireless

Security=wpa
IP=static
Address='192.168.0.121/24'
Routes=("default via 192.168.0.1 dev wlan0 src 192.168.0.121 metric 303")

ESSID='XXXxX'
Key='XXXX'

```
`Routes`で有線LANより高いmetricを指定すると、無線LANの優先度が下がる


### (必要であれば)IPv6無効化
`sudo vim /etc/sysctl.d/40-ipv6.conf` (新規作成)
```
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.enp1s0.disable_ipv6 = 1
```

### netctlの各プロファイル有効化
`sudo systemctl enable netctl@ethernet`
`sudo systemctl enable netctl@wlan0`
再起動

`/etc/netctl/example/`配下にコンフィグの例が置いてあるが、そのとおりだとNICが立ち上がらなかった。
netctlのプロファイルから`Gateway`および`DNS`を削除したらうまくいった。


### 確認
- ipアドレス
`ip a`
- ルート
`ip route`
- ping
`ping google.com`
`ping -I wlan0 google.com`
Dockerで色々リセットする方法

# コンテナ起動・停止
```
$ docker-compose up --detach
$ docker-compose down
```

# Dockerの初期化
```
$ docker stop $(docker ps -q) //①全コンテナ停止
$ docker ps -aq | xargs docker rm //②全コンテナ削除
$ docker volume rm $(docker volume ls -qf dangling=true) //③全ボリュームマウント全削除
$ docker images -aq | xargs docker rmi //④イメージ全削除
// ①～④一括
$ docker compose down --rmi all --volumes --remove-orphans
```

# ボリューム削除（特にDatabase）
```
$ docker volume ls
$ docker volume rm xxxxxx
```

```
$ docker system prune -a --volumes
```
シェルコマンドawk


# シェルコマンドawkの使用：

1.スクリプトを使用して、システムの現在のメモリ使用率のパーセンテージを出力します：
```bash
#!/bin/bash
[centos@centos shell]$ free -m
              total        used        free      shared  buff/cache   available
Mem:           1819         508         130          11        1180        1130
Swap:          2047         368        1679
[centos@centos shell]$ vim useCache.sh
echo "このスクリプトを使用して、現在のシステムメモリ使用率を確認できます"
use=$(free -m | grep Mem: | awk '{print $3}')
total=$(free -m | grep Mem: | awk '{print $2}')
useper=$(expr $use \* 100 / $total)
echo "システムの現在のメモリ使用率: "
echo ${useper}%
[centos@centos shell]$ chmod +x useCache.sh
[centos@centos shell]$ ./useCache.sh
このスクリプトを使用して、現在のシステムメモリ使用率を確認できます
システムの現在のメモリ使用率:
27%
[centos@centos shell]$
```

2.スペースで区切って、各行にフィールドがいくつあるかを示します

```bash
[centos@centos shell]$ vim file
aaaaaaaa bbbbb ccccc dddddd eeeee fffffff

bbbbbbbbbb aaaaa ccccccc ddddddddd eeeeeeeeee

ccccccc bbbbbbb eeeeee hhhhhhhhh

eeeeee ffffff

ffffff
[centos@centos shell]$ awk '{print NF}' file
6
0
5
0
4
0
3
0
2
0
1
```


3.スペースで区切って、ファイル内の4つ以上のフィールドを含む行を表示します

```bash
[centos@centos shell]$ awk 'NF>4 {print}' file
aaaaaaaa bbbbb ccccc dddddd eeeee fffffff
bbbbbbbbbb aaaaa ccccccc ddddddddd eeeeeeeeee
[centos@centos shell]$
```

4.各行の行番号を表示します

```bash
[centos@centos shell_study]$ awk '{print NR, $0}' file
1 aaaaaaaa bbbbb ccccc dddddd eeeee fffffff
2
3 bbbbbbbbbb aaaaa ccccccc ddddddddd eeeeeeeeee
4
5 ccccccc bbbbbbb eeeeee hhhhhhhhh
6
7 fffff hhhhhhh yyyyyyyy
8
9 eeeeee ffffff
10
11 ffffff
[centos@centos shell_study]$ awk 'NR==5 {print}' file
ccccccc bbbbbbb eeeeee hhhhhhhhh
```

5.最初の行を表示しない

```bash
[centos@centos shell_study]$ route -n | awk 'NR!=1{print}'
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.150.1   0.0.0.0         UG    100    0        0 ens33
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0
192.168.150.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33
[centos@centos shell_study]$ route -n | awk 'NR>1{print}'
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.150.1   0.0.0.0         UG    100    0        0 ens33
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0
192.168.150.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33
```


6.ファイル内の root を含む行をマッチ

```bash
[centos@centos shell_study]$ awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
```

7.ファイル内の root を含む行をマッチしない

```bash
[centos@centos shell_study]$ awk -F: '!/root/' /etc/passwd
```

8.ファイル内の空の行の行番号をマッチ

```bash
[centos@centos shell_study]$  awk '{if($0~/^$/)print NR}' file
2
4
6
8
10
```

```bash
[centos@centos shell_study]$ awk -F: '{if($3>100)print "LARGE";else print "SMALL"}' /etc/passwd
```
![シェルコマンドawk](https://img-blog.csdnimg.cn/190b582fdef64788a881d62805dfe47a.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YqA44Gu6b6N44Gu6IOM44Gr5LmX44Gj44GmX0lORw==,size_20,color_FFFFFF,t_70,g_se,x_16)

---
Koin3.1 + Ktor 1.6以降におけるNoSuchMethodError


# 事象
Koin 3.2より前のバージョンの場合、Ktor 1.6.0以降のKtor起動開始時、NoSuchMethodErrorの例外が発生し、起動できない。

## 動作環境
+ Kotlin 1.6.10
+ Ktor 1.6.7
+ Koin 3.1.5

## 対処方法
Koinのissue [#1188](https://github.com/InsertKoinIO/koin/issues/1188)に同事象の記載があり、
ワークアラウンドとして、ロガーのログレベルにERRORを設定すれば、回避可能。

```
install(Koin) {
        //ロガーのログレベルにERRORを設定。
        slf4jLogger(level = Level.ERROR)

        modules(
            省略
        )
}
```

なお、Koin 3.2はKtor 1.6に対応しているため動くようだが、当該バージョンはまだβ版のため、当面はワークアラウンドによる回避になると思われる。