OmniAICreator/Qiita-1.07M huggingface dataset:
Refererからバグが発生した話

# はじめに
リリースした際、Refererが原因でバグとなったので、Refererとは何かから備忘録として残したいと思います。
おかしな点はご指摘お願いします。

# Refererとは
>Refererは、HTTPヘッダの1つで、インターネット上の1つのウェブページまたはリソースから見て、それにリンクしているウェブページやリソースのアドレスを指す。
Refererを参照することで、どこからそのページに要求が来たのかを知ることができる。

要は今のURLの前どこにいたのかという情報のことです。

# Refererを取得してみる
試しにRefererを取得してみます。
googleのトップ画面にてQiitaと検索し、Qiitaのwebページへアクセスします。
[![Image from Gyazo](https://i.gyazo.com/71afe17866edf9e6e466c2f4e71f2c50.png)](https://gyazo.com/71afe17866edf9e6e466c2f4e71f2c50)
[![Image from Gyazo](https://i.gyazo.com/aa2c80f6a7e7acfcde2549eeebe63355.png)](https://gyazo.com/aa2c80f6a7e7acfcde2549eeebe63355)
[![Image from Gyazo](https://i.gyazo.com/df047565de9474e716bc97fc44bab63e.png)](https://gyazo.com/df047565de9474e716bc97fc44bab63e)
この流れではgoogleのページからQiitaのページへ遷移してきたのでReferer情報にはgoogleのURLが載ることになります。
確認してみましょう。
Refere情報は次のように確認することができます。
1. デベロッパーツールを開きます。
デベロッパーツールの開き方はWindowsであれば F12キー、MacOSであればCommand＋Option＋Iキー。
右クリックから「検証」をクリックしても開くことができます。

1. Networkを選択し、先頭のHTMLファイルを選択します。（何も表示がなければリロードしてください）
![71975c37484f36fdc6a3980ca4733209.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1431393/4562fdb7-2b0a-f897-6f79-70a12b8817f5.png)

1. Request Headersを確認する
HTMLファイルをクリックすると、このページの関するさまざまな情報を確認することができます。
RefererはHTTPヘッダに存在するのでHeadersを選択します。
![7c6971e940c02506ece8c3d944b6351b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1431393/149dea47-59bd-222f-8ee4-9e4abe625d3b.png)

Headersには大枠で次の３種類があります。
- General
    - リクエストしたURLやメソッド、HTTPステータス、IPアドレス、リファラのポリシーが記載されています。リクエストとレスポンス共通のものです。
- Responce Headers
    - レスポンスに関する追加情報、例えば場所や提供しているサーバーに関する情報を保持します。
- Request Headers
    - 読み込むリソースについての情報や、そのリソースをリクエストしているクライアントに関する詳細な情報を持ちます。

なお、RefererはRequest Headers内に記載されています。
![49b1b5ce6ef4cbf14088f17e9f3353de.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1431393/6df2a544-26fc-fa57-a832-67a6ec0a30bf.png)
今回はgoogleからアクセスしているのでRefererには遷移元であるgoogleのURLが載っていますね。

ただし、Referer情報が存在しない場合もあります。

# ノーリファラ (no referer)
>起動直後に最初に表示したページや、ブックマークやお気に入りから開いた場合など、そもそも参照元が存在しない状況で生じるほか、ブラウザに参照元を申告する機能がない場合、ブラウザの設定で参照元の申告を拒否するように指定した場合などに発生する。

ノーリファラの場合は、Refererが存在しません。

# バグ発生の状況
今回はホームページ（他社制作会社が作った）のバナーをクリックすると自社製品のURLに遷移する設計となっていました。
自社製品はAWSの環境下で動いています。
セキュリティ対策として、WAFにてRefererがホームページのURLのみを許可する設定としていました。
つまりホームページからバナーをクリックしなければ自社製品にはアクセスできない設計でした。
WAFによるReferer制限については次の記事がわかりやすかったのでお読みください。

https://qiita.com/oudon722/items/64de3880b8d65e799e59

# 本番環境で発生した不具合
バナーをクリックするのにも関わらず、画面が白いまま固まってしまっていました。

# 原因
調査の結果、原因はRefererにあることがわかりました。
バナーをクリックした際、自社製品アプリケーションのRefererがホームページのURLではなく自社製品のURLになっていました。
そのため初回遷移はできるものの、WAFではじかれDOMツリーでjavascriptが呼び込まれなかったのでした。

# 解決策
WAFのRefereに自社製品のURLを追加し、解決しました。

# おわりに
これまではフロント、バックエンド、インフラなどエンジニアの種類ごとに色々な知識を学習してました。
最近はその間のネットワークの部分を実務で触れる機会があり、とても楽しく、毎日が発見です。
これからも学習していきます！


# 参考
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers

https://e-words.jp/w/%E3%83%AA%E3%83%95%E3%82%A1%E3%83%A9.html

https://qiita.com/shizen-shin/items/77af3e961134977eaac7#1-general
[Rails・Heroku]HerokuでWheneverが機能しない場合の対処

### 前提
記事を書いている私は現役のエンジニアではなくエンジニアを目指して学習中の者です。
よって、気をつけてはいますが記述内容には誤った内容が含まれている危険性があります。
その為この記事は参考程度に読んで頂き詳しい内容は公式の記述を参考にすることをおすすめします。

### この記事で実装すること
個人開発のアプリで**gem:whenever**を使用して定期処理を実行しようとしたが動作しなくて困ったのでその時の対処をまとめました。
具体的にはHerokuでは**gem:whenever**はサポートされていないらしいのでHerokuのアドオンである**scheduler**を使用して定期処理を実行させるように変更しました。

### 使用技術
Ruby 3.1.2
Rails 6.1.6
Heroku


### 実装手順
##### 1, 定期実行させたい処理をrakeタスクとして作成する
gemのwheneverでもHerokuのschedulerでもまずは実行するrakeタスクを作成する必要があります。
rakeタスクは以下のコマンドを実行することで作成できます。
task名は任意ですが名前から処理が想像しやすいものにします。
```
$ rails g task scheduler_test
```

##### 2, 作成されたrakeタスクを編集する
コマンドによってlibディレクトリのtasksディレクトリの中にscheduler_test.rakeファイルが作成されていることが確認できます。
```ruby
namespace :scheduler_test do
end
```
このファイルに実行させたい処理を書いていきます。
ここではおはようメッセージを表示するタスクを定義してみます。
```ruby
namespace :scheduler_test do
  #descにはtaskの説明を書きます
  desc "毎日おはようメッセージを表示する"
　　　　#taskにはtask名を書きます
  task good_morning: :environment do
    puts "おはよう！！"
  end
end
```
これでrakeタスクの作成は完了です。
試しに以下のコマンドを実行してtaskの一覧に作成したタスク名があることを確認します。
```
$ rails s
$ rake -T
```
表示されたタスク一覧の中に先ほど作成されたタスク名と説明があることがわかります。
```
rake scheduler_test:good_morning                          # 毎日おはようメッセージを表示する
```
ちなみに、コマンドを打てばタスクが実行され"おはよう!!"が表示されます。
```
$ rake scheduler_test:good_morning
おはよう！！
```

##### 3, Herokuのschedulerを使用して定期実行させる
Herokuアプリにログインして対象のアプリの**Resourcesタブ**を開き**Add-ons**の検索バーで**Heroku scheduler**と打ち込みます。
[![Image from Gyazo](https://i.gyazo.com/5b0dd762760fc9d1ec03eb9196f73a8c.png)](https://gyazo.com/5b0dd762760fc9d1ec03eb9196f73a8c)
下の画面が表示されるので**Submit Order Form**を押します。
[![Image from Gyazo](https://i.gyazo.com/148e4d8c10bf074d783e0a6586253cd0.png)](https://gyazo.com/148e4d8c10bf074d783e0a6586253cd0)
これで追加が完了しました。

次に以下のコマンドを実行してスケジュール設定画面に移動します。
```
$ heroku addons:open scheduler
```
画面に移動したら**Create job**を選択します。
[![Image from Gyazo](https://i.gyazo.com/5f30f92362c34ad172fc36379e7ba034.png)](https://gyazo.com/5f30f92362c34ad172fc36379e7ba034)

最後に実行させたい時間帯と実行させたいタスクのコマンドを打ち込めば設定の完了です。
時刻がUTC基準になっていることに注意してください。
[![Image from Gyazo](https://i.gyazo.com/da32f1c6806ffc2dba04c94b1be39453.png)](https://gyazo.com/da32f1c6806ffc2dba04c94b1be39453)


以上でHeroku上で定期処理を実行するための説明を終わります。思っていたより簡単に実装ができました。
初学者なので何か間違い等を見つけましたらご指摘頂けると助かります！
Python,Ruby,PHP,Java,JavaScript,Perlの変数の比較 | プログラミング言語比較


<a href="https://qiita.com/yuki_kimoto/items/f9c2454e7f9130ddb003">Qiita > プログラミング言語の比較</a>

プログラミング言語Python,Ruby,PHP,Java,JavaScript,Perlの変数の比較

# Python

https://qiita.com/G-Rape/items/854a51ef188cd5933bcc

# Ruby

https://qiita.com/Hashimoto-Noriaki/items/d705a3fb92db14de4742

# PHP

https://qiita.com/tokutoku393/items/72d2f3f8986c97c36a27

# Java

https://qiita.com/takahirocook/items/52298e13281e26e576ab

# JavaScript

https://qiita.com/andota05/items/238ff472a0e711b65275

# Perl

https://perlzemi.com/blog/20161107147852.html
pfxファイル。ビルドエラーの解決。

## 前提
- PCを新調
- 前のPCは、Windows 10。Visual Studio 2019
- 新しいPCは、Windows 11。Visual Studio 2022

## 問題
ソリューションを新しいPCにコピーしてビルド。
エラーが発生。

>エラー		次のキー ファイルをインポートできません: HOGEHOGE.pfx。キー ファイルはパスワードで保護されている可能性があります。この状況を解決するには、証明書をもう一度インポートするか、次のキー コンテナー名で、証明書を厳密な名前の CSP に手動でインストールしてください: VS_KEY_FUGAGUGA


## 解決にあたって実行した方法

1. エクスプローラーで、pfxファイルを選択してから、**PFXのインストール**を実行。パスワードが必要になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/8a4eb5f9-45cf-6690-e1c4-3ba3090113e3.png)

2. **署名＞アセンブリに署名する**で、参照しなおす。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/a146d9aa-5fc5-959c-e17d-7995028615b4.png)


1が必要かどうかは分からないが、おそらく必要。
2は、必要。参照しなおさないと、うまくいかなかった。
SwiftUIアプリにFirebaseをSwift Package Managerを使って導入する

# 概要
Swift Package Manager (SPM) を使って SwiftUI に Firebase を導入します。
2022年8月時点で Firebase が公式でSPMに対応しているが、CocoaPodsを使用した導入方法が広く紹介されています。
今後の作業の参考になる情報を記録しておくことが目的です。
あくまでXcode側の作業の記録であり、Firebase の設定については触れません。



# 環境
macOS 12.4 
Xcode 13.4.1
Mac mini (2018)  Intel



# Swift Package Manager を使用した Firebase の導入
Xcode の File -> Add Packages... を選択し、右上の検索バーに　
```
https://github.com/firebase/firebase-ios-sdk.git　
```

を入力して検索。


firebase-ios-sdk を選択したら Dependency Rule の部分を Up to Next Major Version に変更して右下のAdd Packageをクリック。

導入するPackage を選択する画面が表示されるので必要なモジュールを選択して右下の Add Package を選択します。今回は公式のチュートリアルにもある、FirebaseAnalyticsを選択しました。

これでXcode Project にFirebaseを導入できました。




# SwiftUI に Firebase を導入する
Xcode Project内の App を宣言するファイルを開きます。

App 内で FirebaseApp.configure を初期化する必要がある。そのためにinitを使って初期化する。


```swift:ExampleSwiftUIApp.swift
import SwiftUI
//Firebase を import する
import FirebaseCore

@main
struct PasswordlessSwiftUIApp: App {
    //SwiftUIでFirebaseを使えるようにするためのコード
    init() {
        FirebaseApp.configure
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```
これでSwiftUI で Firebase を使えるようになりました。

# まとめ
SwiftUIアプリにFirebaseをSwift Package Managerを使って導入することが可能です。
クリックを数回して、コードを四行追加するだけで導入できるのですごく簡単に導入できます。

SwiftUIアプリにFirebaseを導入してみようと考えている方の参考になれば幸いです。
間違いや修正すべき点などがあれば是非お知らせください。

# 参考資料
https://firebase.google.com/docs/ios/setup?hl=ja

https://github.com/firebase/quickstart-ios/tree/master/swiftui/PasswordlessSwiftUI/PasswordlessSwiftUI
スロークエリの見つけ方


## MySQLのスロークエリを確認するまでの手順備忘録
アプリケーションを作るうえで、DBとのやり取りはほぼほぼ発生するかと思います。
その際に投げられるクエリたちについて、どれが時間がかかっているクエリ（スロークエリ）なのかを確認する方法となります。

### スロークエリのON/OFFを確認する
下記コマンドにてスロークエリのON/OFFおよびログの出力先を確認します。
```
mysql> show variables like 'slow_query%';
+---------------------+--------------------------------------+
| Variable_name       | Value                                |
+---------------------+--------------------------------------+
| slow_query_log      | OFF                                  |
| slow_query_log_file | /var/lib/mysql/f715b6ca7431-slow.log |
+---------------------+--------------------------------------+
2 rows in set (0.01 sec)
```

### 閾値を確認
下記コマンドにてクエリがスローと判断される（ログが出力される）閾値を確認します。
```
mysql> show variables like 'long%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)
```

### スロークエリの設定
設定ファイルまたはmysqlコマンドで設定を行います。

設定ファイル（my.cnf）の場合
```
[mysqld]
slow_query_log_file=’/tmp/slow.log’
slow_query_log=1
long_query_time=0.5
```

コマンドで設定の場合
```
mysql>set global slow_query_log_file='/tmp/slow.log';
mysql>set global slow_query_log=1;
mysql>set global long_query_time=0.5;
```
ちなみに`slow_query_log_file`に指定されたパスに対して mysqld の実行ユーザーが書き込み権限を持っていないとエラーになります
```
mysql> set global slow_query_log=1;
ERROR 29 (HY000): File '/var/log/mysql/slow.log' not found (OS errno 2 - No such file or directory)
```

### スリークエリの集計
スロークエリの設定が完了したら、実際にクエリを投げてみます。

```
# 3秒スリープさせるクエリ
mysql> select sleep(3);
```

クエリ実行後、`mysqldumpslow`コマンドを実行し集計結果を表示します。
`mysqldumpslow`はクエリではなくコマンドになります。mysql内で実行はできません。
コマンドのオプションは[こちら](https://dev.mysql.com/doc/refman/5.6/ja/mysqldumpslow.html)を参考にしてください。
```
$ mysqldumpslow -s t /tmp/slow.log

Reading mysql slow query log from /tmp/slow.log
Count: 1  Time=3.00s (3s)  Lock=0.00s (0s)  Rows=1.0 (1), root[root]@localhost
  select sleep(N)
```

| 集計結果 | 概要 |
|:-----------|:------------|
| Count       | 実行回数             | 
| Time     | 平均実行時間（累計）      |
| Lock       | テーブルをロックした平均時間（累計）        |
| Rows         | 操作したレコードの平均数（累計）          |

## まとめ
ここまででどのクエリが時間がかかっているかを確認できるようになりました。
次回はEXPLAINによるクエリ解析を行います。
 → [EXPLAINを使ってクエリ解析](https://qiita.com/eiji-noguchi/items/6513ef0f84615576c283)
【Docker】プロジェクト名の設定方法

## デフォルト
`docker compose build`などを実行する際に特に何も設定していない場合にはカレントディレクトリ名がプロジェクト名となります。
例えばカレントディレクトリが`sample-app`であった場合、プロジェクト名も`sample-app`となります。

## プロジェクト名の設定方法
プロジェクト名は以下の方法で設定できます。

### `-p`オプションを使用
`docker compose`コマンドを実行する際に`-p`または`--project-name`を使用することでプロジェクト名を指定できます。
```:ターミナル
$ docker compose -p プロジェクト名 build 

$ docker compose --project-name プロジェクト名 build
```

### 環境変数で設定する
環境変数`COMPOSE_PROJECT_NAME`にプロジェクト名を設定することでプロジェクト名を指定できます。
```:ターミナル
$ COMPOSE_PROJECT_NAME=プロジェクト名　docker compose build 
```
または
```.env
COMPOSE_PROJECT_NAME=プロジェクト名
```
```:ターミナル
$ docker compose build 
```

### トップレベルの`name`で設定
`compose.yml`に以下のように記述することでプロジェクト名を指定できます。
```compose.yml
name: プロジェクト名
services:
  db:
    image: mysql:8.0.30
    <以下略>
```

## 補間
`compose.yml`でプロジェクト名を補間するためには`${COMPOSE_PROJECT_NAME}`のように記述します。
```compose.yml
name: プロジェクト名
services:
 api:
    build:
      context: .
      dockerfile: ./docker/api/Dockerfile
    volumes:
      - .:/${COMPOSE_PROJECT_NAME}
```

## 優先順位
複数の方法でプロジェクト名を指定した場合、以下の順位で適用されます。

1. `-p`オプションを使用
2. `COMPOSE_PROJECT_NAME=プロジェクト名　docker compose build`を実行
3. `.env`ファイルに`COMPOSE_PROJECT_NAME=プロジェクト名`を記述
4. トップレベルの`name`プロパティ
seabornヒートマップの数値表示の四捨五入対処

# 概要
seabornでヒートマップを作る際に、セル内の数値表示が自動的に四捨五入されるらしい。
それによって、相関係数が1になるセルが大量に出てしまうことがあったので、対処した。

# 基本
以下のようなデータを用意する。
```python:seaborn.py
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame({'A': range(10),
                   'B': [x**2 for x in range(10)],
                   'C': [x**3 for x in range(10)],
                   'D': [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]})
#    A   B    C   D
# 0  0   0    0   0
# 1  1   1    1   2
# 2  2   4    8   3
# 3  3   9   27   4
# 4  4  16   64   5
# 5  5  25  125   6
# 6  6  36  216   7
# 7  7  49  343   8
# 8  8  64  512   9
# 9  9  81  729  10
```

相関係数は以下のようになる。
```python:seaborn.py
df_corr = df.corr()
print(df_corr)
#           A         B         C         D
# A  1.000000  0.962691  0.908434  0.996452
# B  0.962691  1.000000  0.985888  0.944573
# C  0.908434  0.985888  1.000000  0.886333
# D  0.996452  0.944573  0.886333  1.000000
```

結果は、
```python:seaborn.py
fig, ax = plt.subplots(figsize=(50, 30))
sns.heatmap(df_corr, vmax=1, vmin=-1, center=0, cmap='RdBu', annot=True, annot_kws={"size": 15})
```
![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784959/e7fe71c1-0680-5372-e228-442277f8f761.png)
小数点第三位で四捨五入されている。


# 1. 表示桁数を増やす
セル内の数値表示の桁数を増やすために、オプションにfmt='.3f'を追加。(デフォルト値: ‘.2g’)
```python:seaborn.py
sns.heatmap(df_corr, vmax=1, vmin=-1, center=0, cmap='RdBu', annot=True, annot_kws={"size": 15}, fmt='.3f')
```
結果は、
![Figure_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784959/eddcbf88-5173-80c3-a03b-2219a25944f1.png)
小数点第四位で四捨五入されている。

# 2. 任意の桁で切り捨て
小数点第三位以下を切り捨てたい場合、相関係数の数値を100倍して小数点以下を切り捨てた後、100で割る。
```python:seaborn.py
df_corr = (df.corr() * 100).apply(np.floor) / 100
fig, ax = plt.subplots(figsize=(50, 30))
sns.heatmap(df_corr, vmax=1, vmin=-1, center=0, cmap='RdBu', annot=True, annot_kws={"size": 15}, fmt='.2f')
```
結果は、
![Figure_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784959/3175c884-bbd4-703a-3db0-5b8e9bc46a95.png)
小数点第三位以下が切り捨てられている。
ユーザー退会時にユーザー関連データを削除するには（Swift SDK編）

iOSアプリではユーザー退会時にユーザーデータを削除する要件があります（2022年06月30日より）。プライバシーに配慮した要件ですが、アプリ開発者にとっては追加の対応が求められます。

ニフクラ mobile backend（以下NCMB）を使っている場合、ユーザーの退会処理（物理削除）は簡単に行えます。しかし、ユーザーに関連したデータはどう削除したら良いでしょうか。

今回はSwiftで、Swift SDKを使った関連データ削除方法を解説します。

## ユーザーデータの削除

ユーザーデータを削除するのは簡単です。必ずログインした状態で行う必要があります。

```swift
if let user = NCMBUser.currentUser {
	object.deleteInBackground(callback: { result in // ユーザー削除 = 退会
		switch result {
			case .success:
				print("削除に成功しました")
			case let .failure(error):
				print("削除に失敗しました: \(error)")
    }
	});
}
```

ただ、注意して欲しいのは `ユーザーデータの削除は関連データをすべて削除してから` にして欲しいということです。ユーザー関連データを削除できる権限がユーザー自身に紐付いている場合、データを削除すると削除権限がなくなる可能性があります。

## 関連データの検索

### ポインターの場合

大抵の場合、NCMBのポインター機能を使ってユーザーデータを紐付けているかと思います。そこで、データストアを検索して、そのユーザーに関連したデータだけを取得します。今回は例として、ユーザープロフィール `UserProfile` クラスにあるデータを検索する例を紹介します。

```swift
let query = NCMBQuery.getQuery(className: "UserProfile")
query.where(field: "user", equalTo: [
	"__type": "Pointer",
	"className": "user",
	"objectId": user.objectId
])
query.findInBackground(callback: { result in
    switch result {
			case let .success(array):
				array.forEach {
					$0.delete()
				}
			case let .failure(error):
				print("取得に失敗しました: \(error)")
    }
})
```

ポイントは、ポインターを使っているカラムの検索です。 `equalTo('user', user)` のようにしたくなりますが、これでは検索ができませんので注意してください。ポインターの形に合わせて検索を行うことで、該当ユーザーのデータだけを取得できます。後はすべて削除すれば良いでしょう。

### リレーションの場合

関連データをポインターではなく、リレーションで保存している場合もあるかと思います。その場合は次のようになります。なお、こちらのメソッドは執筆時点（2022年08月）はテスト中です。

```swift
let query = NCMBQuery.getQuery(className: "UserProfile")
// 関連データの検索
query.relatedTo('users', user.objectId, 'user')
query.findInBackground(callback: { result in
    switch result {
			case let .success(array):
				array.forEach {
					$0.delete()
				}
			case let .failure(error):
				print("取得に失敗しました: \(error)")
    }
})
```

### 注意点

UserProfileクラスに入っているデータの編集権限がユーザーにある場合のみ、削除可能です。権限がないと削除はできませんので注意してください。

## デバイストークンの削除

iOSアプリの場合、プッシュ通知を送信する際にデバイストークンを取得しているかも知れません。その場合、このデバイストークンも削除対象になります。

実装としては次のようになります。

```swift
if let installation = NCMBInstallation.currentInstallation {
	installation.delete();
}
```

## ログアウトを行う

ユーザーデータを削除した後には忘れずにログアウトを行ってください。

```swift
NCMBUser.logOut()
```

これでログアウト状態になり、ユーザーデータがすべてなくなった状態になります。

## まとめ

今回は物理削除の例を紹介しました。論理削除の場合は別なやり方になるかと思いますので注意してください。

[ドキュメント : 開発者向けドキュメント | ニフクラ mobile backend](https://mbaas.nifcloud.com/doc/current/index.html#/Swift)
Swift でバイト配列を扱う

Swift で Byte 型を扱いたいときは UInt８ 型を用います。
つまり、バイト配列は [UInt8] 型になります。
iPhone の NFC リーダーを使ってマイナンバーカードと APDU コマンドで対話をしたくてバイト配列を扱っていたのですが、その時に実装した Extension たちを紹介します。
Swift でバイト配列を扱う機会自体あまりないと思いますが、参考にしていただければ幸いです。

## Byte 型の定義

UInt8 型のままバイト配列を扱っても問題ないのですが、直感的に分かりやすくするために Byte 型という UInt8 の別名を定義しています。

```Byte+Extension.swift
public typealias Byte = UInt8
```

## Byte の Extension

```Byte+Extension.swift
extension Byte {
    
    // 16進数文字列に変換
    func toHexString() -> String {
        var hex = String(self, radix: 16).uppercased()
        if hex.count == 1 {
            hex = "0" + hex
        }
        return hex
    }
    
    // 2進数文字列に変換
    func toBinaryString() -> String {
        var binary = String(self, radix: 2)
        if binary.count < 8 {
            let i = 8 - binary.count
            for _ in 0 ..< i {
                binary = "0" + binary
            }
        }
        return binary
    }
    
}
```

## Data の Extension
```Data+Extension.swift
extension Data {
    
    // Data をバイト配列文字列に変換
    func toByteArrayString() -> String {
        let byteArray = [Byte](self)
        var byteArrayString = ""
        let size = byteArray.count
        var i = 0
        for byte in byteArray {
            i+=1
            var hex = byte.toHexString()
            hex = hex.uppercased()
            if size == i {
                byteArrayString += hex
            } else {
                byteArrayString += hex + " "
            }
        }
        return byteArrayString
    }

}
```

なお、Data と Byte 配列の相互変換は非常に簡単に行えます。
```swift
let data = Data(bytes: bytes) // Byte 配列 → Data
let bytes = [Byte](data) // Data → Byte 配列
```

## 使用例
```swift
// テストデータ
let bytes: [Byte] = [0x00, 0x01, 0xFE, 0xFF]
let data = Data(bytes: bytes)

print(bytes[2].toHexString())
print(bytes[2].toBinaryString())
print(data.toBytesString())
```
### 結果
```sh
FE
11111110
00 01 FE FF
```
【クエリビルダ：拡張表現】IsYes文を使ってみる

数ある拡張表現関数から、今回は**IsYes**文を使ってみます。
[Sharperlight](https://sharperlight.jp/)アプリケーションメニューから`クエリビルダ`を起動します。
下図のようなフィルター設定にし、カスタムでデータセットを準備します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/b4e7fec2-5c37-22a8-2c18-342ae98d80dd.png)
プレビューするとこのようなデータセットが返ってきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/d0810317-7ec5-0204-9cd9-7ab7c13f3604.png)
では、早速**IsYes**文を記してみましょう。
出力領域の右クリックから**拡張表現を追加**を選択します。
出力オプションダイアログが開いたら、関数一覧より`関数` -> `データ型` -> `IsYes`を選択します。
ダブルクリックすることでエディタ領域に転送できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/f2df9bc2-b396-1880-4a00-ea11e3658655.png)
出力される**Status**を使用して検証してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/c1305e02-5686-41c7-1e9f-19c7a8e8878e.png)
`拡張表現`の**説明**をこのように変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/a7e21c2e-46a3-197a-56ba-ef275f143506.png)
早速、プレビュー！！
Statusが"はい"の時、Trueが返ってますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/544f9cea-39e5-ed68-8a86-93ee9aaea58f.png)

では失礼します。
Ansibleにおける変数切り出し

## 概要

Ansibleの変数ファイルに変数を増やしていくにつれて、比較的頻繁に編集が必要な箇所を確認・修正するのに都合が悪くなったことはないでしょうか。

私自身Ansibleを業務上で利用していて編集箇所の確認・修正が手間になり、一部の変数のみを別ファイルに切り出そうということになりました。

本記事では、切り出し作業の際に数点引っかかった箇所について記載します。

## この記事で伝えたいこと
- Ansibleで変数ファイル(`all.yml`)から変数を切り出す際に、筆者が引っかかった点

## この記事で伝えないこと
- Ansibleの基本的な使い方

## 修正前の構成

本記事での説明は、以下の構成に手を加える形で進めます。

### ディレクトリ構成:
```
└── inventories
    └── prod
        ├── group_vars
        │   └── all.yml
        └── hosts
```

### all.yml
```yaml
  app1:
    image: "app1:2.0.2"
    .
    .
    .
  app2:
    image: "app2:2.0.3"
    .
    .
    .
  app3:
    image: "app3:2.0.3"
```

## 引っかかった点

### 1. 変数ファイル・フォルダの名前
`group_vars`フォルダ以下の変数ファイルの名前は、基本的に各環境に設定したグループ名と同じである必要があります。

※`all.yml`は例外的に、全てのグループに対する変数として認識されます。

私は変数を切り出す際に、以下のようにファイルを作成しましたが、`images.yml`は認識されず`all.yml`からのみ変数を探す状態になりました。
```
└── inventories
    └── prod
        ├── group_vars
        │   ├── all.yml
        │   └── images.yml
        └── hosts

```

この場合以下のようにグループ名と同じ名前のフォルダを作成することで、フォルダ以下のファイルがグループの変数ファイルとして認識されます。

```
└── inventories
    └── prod
        ├── group_vars
        │   └── all
        │       ├── all.yml
        │       └── images.yml
        └── hosts
```

### 2. 変数の重複

私は1.の構成で変数を別ファイルに切り出す際、最初は以下のように`all.yml`の変数名をそのままに`images.yml`に切り出しました。

### all.yml
```yaml
app1:
  image: "{{ app1.image }}"
    .
    .
    .
app2:
  image: "{{ app2.image }}"
    .
    .
    .
app3:
  image: "{{ app3.image }}"
```

### images.yml(修正前)
```yaml
app1:
  image: "app1:2.0.2"
app2: 
  image: "app2:2.0.3"
app3:
  image: "app3:2.0.3"
```

しかし、この形でプレイブックを実行した際、`image`以外の変数が存在しないとエラーが発生しました。

このエラーの原因は`images.yml`上の変数が、本来目的としている参照元の`all.yml`以外からも利用される変数名(切り出し元そのまま)を利用していることでした。

変数ファイルが複数ある場合、プレイブック実行時に合致する変数名をフォルダ内のファイルから辞書順で探索します。

そのため、`images.yml`→`all.yml`の順で変数を探索した際に、`images.yml`に探索中の変数を発見→`image`以外の変数も必要だが見つからないのでエラー発生 の流れになったのでしょう。

解決方法は簡単で、`all.yml`からのみ参照する用の変数を別途作成し、以下のような形に修正すればOKです。

### images.yml(修正後)
```yaml
app1_image: "app1:2.0.2"
app2_image: "app2:2.0.3"
app3_image: "app3:2.0.3"
```

要するに、以下のような形にするということですね
- `all.yml`:変数の定義として直接参照される
- それ以外の変数ファイル:`all.yml`からのみ参照される





## まとめ

以上が私が変数切り出し時に引っかかった点でした。
同じところで詰まった方の助けになれば幸いです。

最終的には、以下のような構成になりました。

### ディレクトリ構成:
```
└── inventories
    └── prod
        ├── group_vars
        │   └── all
        │       ├── all.yml
        │       └── images.yml
        └── hosts
```

### all.yml
```yaml
app1:
  image: "{{ app1_image }}"
    .
    .
    .
app2:
  image: "{{ app2_image }}"
    .
    .
    .
app3:
  image: "{{ app3_image }}"
```

### images.yml
```yaml
app1_image: "app1:2.0.2"
app2_image: "app2:2.0.3"
app3_image: "app3:2.0.3"
```

## 参考
- [インベントリーの構築方法 — Ansible Documentation](https://docs.ansible.com/ansible/2.9_ja/user_guide/intro_inventory.html#splitting-out-vars)
【SpringBoot】SpringSecurity + Ajax通信時の403 forbidden 対処法

SpringSecurityを用いたアプリケーション開発時、Ajax通信の際に403エラーが出たので、その対処法を備忘します。

### 原因
Spring Security で CSRF 対策を有効にしていたため、Ajax通信でcsrf情報をセットせずにPOSTしようとしたところ、閲覧禁止となってしまった。

### 解決方法
csrf情報をセットしたうえでAjax通信を行う

#### 1, メタタグにトークンを埋め込む
~~~ HTML
<meta th:name="_csrf" th:content="${_csrf.token}">
<meta th:name="_csrf_header" th:content="${_csrf.headerName}">
~~~

そうすると、下記のようにトークンが埋め込まれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711483/746f0373-60d6-875a-8b3c-c5666b57305e.png)

#### 2, Ajax通信時に、リクエストヘッダにトークンを埋め込む
~~~ javascript
$(function(){
    // メタタグに埋め込んだ情報を取得する
    let token = $("meta[name='_csrf']").attr("content"); 
    let header = $("meta[name='_csrf_header']").attr("content"); 
    
    // Ajax通信時に、リクエストヘッダにトークンを埋め込むよう記述
    $(document).ajaxSend(function(e, xhr, options){
        xhr.setRequestHeader(header, token);
    });
});

// Ajax通信を行う
$.ajax({
			url: XXXX,
			type: 'post',
			dataType: 'json',
			data: {
				XXXX: XXXX
			},
			async: true,
		}).done(function(data) {
			XXXX
		}).fail(function(XMLHttpRequest, textStatus, errorThrown) {
			console.log('XMLHttpRequwst:' + XMLHttpRequest);
			console.log('textStatus:' + textStatus);
			console.log('errorThrown:' + errorThrown);
		});
	});
});
~~~

こうすることで、403エラーを出さずに通信することができます。

### 参考文献
[Spring Security + ThymeleafでAjaxリクエストにCSRF対策トークンを適用](https://tosi-tech.net/2018/07/ajax-with-csrf-token-of-spring-security/)
[Spring + Thymeleaf ± Ajax通信時の403 forbidden](https://anveloper.com/2020/11/20/spring-thymeleaf-%C2%B1-ajax%E9%80%9A%E4%BF%A1%E6%99%82%E3%81%AE403-forbidden/)
[Spring Security 使い方メモ　CSRF](https://qiita.com/opengl-8080/items/3720ed415c2df26251a7#%E5%8F%82%E8%80%83)
enebularでalexaスキル その3

# 概要
enebularで、alexaスキルのwebhookを返してみた。
開発コンソールで、スキルを作ってみた。

# 手順

新しいスキルを作成


1.スキルに追加するモデルを選択

- カスタムを選択

2.スキルのバックエンドリソースをホスティングする方法を選択

- ユーザー定義のプロビジョニングを選択

スキルを作成をクリック

スキルに追加するテンプレートを選択

- スクラッチで作成を選択

選択をクリック

呼び出し名の登録

- ゲンキコール

スロットの追加

- GenkiSlot

スロットの値

- 元気、げんき

インテントの追加

- GenkiIntent

インテントのサンプル発話

- {GenkiSlot}
- {GenkiSlot} ですか
- {GenkiSlot} かな

サービスのエンドポイントの種類

- https https://***.herokuapp.com/



# テスト結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/7e0e063d-a460-df5d-5511-e565a0f8f111.png)


以上。
【クエリビルダ：拡張表現】IF文を使ってみる

拡張表現の基本中の基本**IF文**を今日は使ってみます。
[Sharperlight](https://sharperlight.jp/)アプリケーションメニューから**クエリビルダ**を起動します。
下図のようなフィルター設定にし、カスタムでデータセットを準備します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/296221bb-5644-2743-85a1-b1957c37aac5.png)
プレビューするとこのようなデータセットが返ってきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/650554e2-75d6-f549-5cfa-75bf4b9ed3fb.png)

では、早速**IF文**を記してみましょう。Sharperlightでは、正確には**IIF文**ですね。
出力領域の右クリックメニューから**拡張表現を追加**を選びます。
出力オプションダイアログが開いたら、関数一覧より`関数` -> `条件付き` -> `IIF(ConditionGoesHere, TrueValue, FalseValue)`を選択します。ダブルクリックすることでエディタ領域に転送できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/ed37d1d0-890c-b842-e646-d5a16f114684.png)
出力される**番号**を条件値にして、真の時は。。。偽の時は。。。といったような構文にしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/4d68fb72-2e78-de46-9238-268c04c4bef0.png)
追加した`拡張表現`の**説明**をこのように変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/68b2f91c-b26b-4a1d-8eba-2c5f84f7b394.png)
早速、プレビュー！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/9deeb0a1-a163-c98a-8bc4-9841c47c51ce.png)
ざっと**IIF文**の基本的な使い方をみてきました。**IIF文**は**ネスト**も可能なので、もうちょっと複雑な条件判断にも役立つと思います。

では失礼します。
RDF.rb 3.2における RDF::Graph#insert_statement が遅い問題

[RDF.rb](https://ruby-rdf.github.io/rdf/) は、Rubyで書かれたRDF解析ライブラリで、Ruby界隈でのセマンティックWebやLinked Data処理用途で広く使われている。

RDF.rbの2022年8月時点での最新版は 3.2.9 だが、このバージョンには、昨年2021年時点で使っていた3.1系列に比べて、かなり性能上の劣化があるようなので、念のためメモを残しておく。

例えば、以下のようなコードを実行した場合、数万トリプル規模のファイルの場合には数秒で終わるのが、数十万トリプルを超えた場合に、急速に遅くなる現象が発生する。

```ruby
require "rdf/n3"
graph = RDF::Graph.new
RDF::N3::Reader.open("test.n3") do |reader|
  count = 0
  reader.each_statement do |statement|
    graph.insert << statement
    count += 1
  end
end
```

上記のコードは単に、``test.n3``というRDF/N3形式のファイルを読み込みながら、``graph``変数にトリプルを格納しなおしているだけのコードである。

ベンチマークのために、[SP2Bench](http://dbis.informatik.uni-freiburg.de/index.php?project=SP2B)と呼ばれるRDFベンチマーク用のツールを使って自動生成した、1万トリプル、10万トリプル、20万トリプル、100万トリプルの各RDFデータファイルに対して実行した場合の性能比較を行ってみた結果が以下となる。

```
$ ./benchmark.rb "~> 3.1.0"
RDF::VERSION: 3.1.15
RDF::N3::VERSION: 3.1.2
                      user     system      total        real
test10k.n3        3.049624   0.069207   3.118831 (  3.119040)
test100k.n3      33.302798   0.159743  33.462541 ( 33.463206)
test200k.n3      84.753375   0.290011  85.043386 ( 85.045089)
test1000k.n3    805.143489   2.719901 807.863390 (807.891563)
```

```
$ ./benchmark.rb "~> 3.2.0"
RDF::VERSION: 3.2.9
RDF::N3::VERSION: 3.2.1
                      user     system      total        real
test10k.n3        3.084775   0.021109   3.105884 (  3.106361)
test100k.n3      40.841392   0.279945  41.121337 ( 41.124899)
test200k.n3     183.223961   0.829992 184.053953 (184.062652)
test1000k.n3  11218.755949  15.469557 11234.225506 (11234.622095)
```

まず、RDF.rb 3.1.15 での結果をみると、1万トリプルで3秒が、100万トリプルが800秒となる等、やや時間がかかっているとはいえ、おおむね線形の実行時間となっている。
一方、RDF.rb 3.2.9 では、1万トリプルでは3.1系と変わらないものの、10万トリプル・20万トリプルと少しずつ実行が3.1系より遅くなっている。さらに、100万トリプルのデータでは、3時間以上と相当に実行時間を要する結果となっている。

なお、上記の実行環境は Windows11 の WSL2 (Ubuntu) において構築した Ruby 3.1.2p20 を使って確認した。

実行に使ったスクリプトは以下にあるものです： https://gist.github.com/masao/398d9009cd8ba78d9da9283c8038c27d

また、使ったデータは以下にも置いておきます： https://www.dropbox.com/sh/kwndqqddj1jfz8l/AABcE0ssvYkl0EO5Vm5gtw-_a?dl=0
人事のおじさんプログラミングを学ぶ Day2「JavaScriptのファイルをHTMLファイルに読み込む」

書籍『確かな力が身につくJavaScript「超」入門 第2版』をKindleで購入。
JavaScriptのファイルをHTMLファイルに読み込んでみる。
うむ、わかりやすい。
![2022-08-18 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783084/669f9c35-cbba-25ac-5428-3e9aca65d12a.png)
ネットワークのセキュリティ対策

ネットワークの対策は外と中を区切る壁を設けて出入りを制限することから始める。

# ファイアウォール
LANの中と外を区切る壁として登場する役割。
そのものがあるわけではない。

ファイアウォールは```防火壁```の意味。
外からの不正なアクセスを```火事とみなして、それを食い止める```存在。

ファイアウォールの実現方法を紹介する。

# パケットフィルタリング
パケットを無条件で通過させるのではなくて、ある```条件をつけて通過させるように制御```している。

この機能では、```パケットのヘッダ情報```を見て、通過の判定をする。
パケットのヘッダ情報は```送信元IPアドレスや宛先IPアドレス、プロトコル種別、ポート番号```のこと。

アプリケーションが提供するサービスはプロトコルとポート番号で区別されます。
なので```どのサービスは通過させるかと決めた```ことになる。

# アプリケーションゲートウェイ
LANの中と外の間に位置する。
外部とのやりとりを代行して行う機能です。```プロキシサーバ(代理サーバ）```とも呼ばれる。
外のコンピュータからはプロキシサーバしか見えないのでLAN内のコンピュータが不正アクセスの表的になることを防ぐ。

アプリケーションゲートウェイ型のファイアウォールには```WAF(Web Application Firewall)```がある。
外部からのアクセスを監視するもので```通信データの中身```までチェックする。
なので悪意を持った攻撃を検知する。

# ペネトレーションテスト
セキュリティホールや設定ミスといった脆弱性の有無を確認するテスト
試験的にファイアウォールに攻撃を行う。

その時に調べる内容は
* もし侵入されたらどうなるか？
* どこまで突破されるか？
* 何をされてしまうのか？

日々脆弱性が発見、攻撃方法が進化しているのでこれを```定期的に行うことが望ましい```。

# 問題を解いた時の気づき
## パケットフィルタリングをもっと知る
https://www.gadgety.net/shin/tips/internet/packet.html
## DMZとは？
ネットワーク用語と軍事用語のDMZ、どちらにも共通しているのは「危険なエリア」と「安全なエリア」の```中間である「緩衝地帯」```として機能するということです。危険な地域のすぐそばに大切なものを置いておくのは危ないので、何かトラブルが起きても大丈夫なように緩衝地帯を設けて、そこには大切なものは置かないようにするのです。

　コンピュータ・ネットワークの世界における「危険なエリア」とは、```インターネットのような安全性が確認できない「外部ネットワーク」```などを指します。インターネット上には悪意ある攻撃者などが存在しており、ネット上に開放しているWebサーバやメールサーバはいつ攻撃されてもおかしくない状態です。外部に開かれているサーバを、機密情報等を含む```内部ネットワークと同じ場所に置いてしまうと、サーバが攻撃を受けた際に内部ネットワークにも侵入される```リスクがあります。

　そこで、DMZという隔離された領域を設けて、```外部ネットワークからアクセスを受ける領域を内部ネットワークから切り離します```。

　より身近な例でいえば、「家の玄関ドアから門扉までの庭などの空間」や「共用玄関のあるマンションのエントランスホール」の方が感覚的には近いかも知れません。そこは```自分たちの敷地内でありながら、外部の人間も内部の人間も入りやすい場所```です。しかも、大切なものがあまり置かれていないので泥棒が入っても被害が少なく、不審者がいれば警戒できる場所でもあります。

　DMZはこうした空間と同じ役割を持っています。緩衝地帯があることで、```大切なものを安全な場所に隔離```でき、外から来た人と気軽に交流もできるということです。

DMZでは、この```ファイアウォールが重要な役割```を担います。外部ネットワークとDMZ、DMZと内部ネットワーク、それぞれの間にファイアウォールが入るような構造を作り、通信を仕分けします。```仕分けのポリシーはファイアウォールごとに自由に設定```できるので、外部ネットワークとDMZの間にあるファイアウォールは緩く設定したとしても、```DMZと内部ネットワーク間のファイアウォールを厳しく設定していれば安全性は高まります```。

```DMZを作ってもWebサーバ自体の脆弱性自体は変わりません。```ただ、DMZから内部ネットワークに入る際にはもう一度ファイアウォールを通る必要があります。DMZから内部ネットワークへのアクセスを```遮断していれば、Webサーバが乗っ取られても内部ネットワークは守り切る```ことができるのです。ファイアウォールが「二重の防壁」として機能します。

　また、DMZではファイアウォールのほかにも不正なアクセスを通報する```「IDS（侵入検知システム）」やアクセスを遮断する「IPS（侵入防止システム）」を組み合わせて```DMZ内に多重のセキュリティを設けることが多いです。DMZは攻撃されることを前提に作られている空間なので、攻撃されたことに気付けるような仕組み作りも必要となります。

　その他、```DMZはルータなどを介して物理的に隔離されることが理想```ですが、難しい場合にはコンピュータ上```に構築した仮想空間に構築することも可能```です。仮想DMZそのものは内部ネットワーク内にありますが、外部からのアクセスを仮想DMZが受けることが可能です。```仮想DMZは、ビジネス用途というよりは個人や家庭向けに使われる```ことが多く、簡易のDMZと捉えると良いでしょう。
出典 https://www.sbbit.jp/article/cont1/37677
DBUnitを用いたテストコードサンプル

### application-test.yml
```yaml
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      main:
        driver-class-name: com.mysql.cj.jdbc.driver
        jdbc-url: jdbc:mysql://dev-test.co.jp:3306/dev_test?useSSL=false
        username: user
        password: password
        max-lifetime: 55000
  sql:
    init:
      mode: never
```

### Setup.xml
IntelliJのプラグイン `DbUnit Extractor`を使用するとDBのデータをコピーして生成できるので便利
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
  <user
    id="1"
    name="name1"
  />
</dataset>
```

### Excpected.xml
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
  <user
    id="1"
    name="name1"
  />
  <user
    id="2"
    name="name2"
  />
</dataset>
```

### テストクラス
```java
@SpringBootTest(classes = SampleApplication.class, = WebEnvironment.RANDOM_PORT)
@TestExecutionListeners(listeners = { DbUnitTestExecutionListener.class, TestExecutionListener.class },
        mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
@ActiveProfiles("test")
class HogeTest {

    @LocalServerPort
    private int serverPort;

    @Test
    @DatabaseSetup("Setup.xml")
    void get() {
        RestAssured.given()
                .when()
                .port(serverPort)
                .get("/v1/users/1")
                .then()
                .assertThat()
                .statusCode(200)
                .body(sameJSONAs("{\"id\": 1, \"name\": \"name1\"}", StandardCharsets.UTF_8))
    }

    @Test
    @DatabaseSetup("Setup.xml")
    @ExpectedDatabase(value = "Expected.xml", assertionMode = DatabaseAssertionMode.NON_STRICT)
    void post() {
        RestAssured.given()
                .when()
                .port(serverPort)
                .body("{\"name\": \"name2\"}")
                .post("/v1/users")
                .then()
                .statusCode(201);
    }
}

```
Windows10でDokcer Desktop for Windowsを使うときに毎回踏むところの記録

# 概要

自分が「説明書を読まないタイプ」の人間のため、Docker Desktop for Windowsインストール時に毎回踏んでいく箇所があります。

反省文代わりに記録です。

# 前提

winverを叩くとこんな感じ。
他バージョンでどうかまでは検証していません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138460/1756ed47-f910-2449-f670-1edd8149b0fe.png)

# いつも踏むところ

「WSL2インストールすればいいんだよね」という記憶だけを頼りに作業するので、

* WSL2はストアからインストール。（直近ではUbuntu 22.04.1 LTSを入れました。）
* 「Windowsの機能の有効化または無効化」で「Linux用Windowsサブシステム」「仮想マシンプラットフォーム」が有効になっていることを確認。

までは行うものの、Docker Desktop for Windows起動時に怒られます。

WSL 2 insallation is incomplete.
WSL2のインストールが不完全、リンクを参照してカーネルの更新をしなさいと・・・。（ここで毎度気がつく）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138460/cad9ed65-94d8-ab74-7bb0-37c969f0cdbb.png)

# （忘れる作業その１）WSL2のカーネル更新

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138460/b6625616-6925-1a2c-70eb-f0fa336fff38.png)

「Linuxカーネル更新プログラムパッケージ」をダウンロード、インストール。

https://docs.microsoft.com/ja-jp/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package

# （忘れる作業その２）WSL 2 を既定のバージョンとして設定する

```PowerShell
wsl --set-default-version 2
```

※この後、念のためWindows再起動。

# 無事Docker Desktop for Windows起動

めでたし。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138460/d5cc2830-9dcb-5495-8717-877e133ca030.png)

# 後書き

* 記憶に頼らずMS公式手順通りにやりましょう。＞自分

https://docs.microsoft.com/ja-jp/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package
ラズパイ(arm64)にGitBucketのDockerコンテナを生成する

## やりたいこと

家にあるラズベリーパイに、Gitリポジトリをhttp(s)で提供してくれるサービスを構築したい。
さらに構築はホストOSではなくて、コンテナ（ゲストOS）で行いたい。

* 試したマシンの情報
    * Raspberry Pi 4 Model B 4GB
    * OS : Ubuntu 22.04 LTS
    * CPUアーキテクチャ : aarch64
    * Dockerのバージョン : 20.10.17

## 課題

以下のgitlab-eeのDockerイメージを``docker run``したらサクッと作れるのだろうと思ったが上手く行かなかった。

https://docs.gitlab.com/ee/install/docker.html

どうやらCPUアーキテクチャがamd64のマシンにしか対応していないらしく、ラズパイがarm64(aarch64)のために上手くいかないようだ。

## 解決策

GitLabだと上手く行かずに諦め…、以下の「Docker-GitBucket-ARM64」からGitBucketのarm64対応版Dockerイメージを作ったらデプロイできた！

https://github.com/aziascreations/Docker-GitBucket-ARM64

## 手順

公開レジストリにコンテナイメージは見つからなったので、自分でソースを取ってきてビルドする必要あり。

* ソースをgit clone

```
$ git clone https://github.com/aziascreations/Docker-GitBucket-ARM64.git
```

* コンテナイメージをビルド
    * ``--force-rm=true``はビルドが失敗した時に作りかけのイメージを消すオプションなので、無くてもOK


```
$ cd Docker-GitBucket-ARM64
$ docker build --force-rm=true -t gitbucket-arm64 .
```

* コンテナをデプロイ
    * 8080 : httpサービスを提供
    * 29418 : ssh接続でpush/pullなど可能


```
$ docker run --name gitbucket -d \
  -p 8080:8080 -p 29418:29418 \
  gitbucket-arm64
```

## 接続確認

* Webブラウザで以下にアクセス
    * http://[ホストOSのホスト名等]:8080
* Sign In時のデフォルトのIDパスワード
    * ID : root
    * password : root

## 試行錯誤したメモ（おまけ）

ご参考に、上手く行かなかったケースも記載する。
筆者のやり方がよくなかっただけで、ちゃんとやれば以下でも出来るのかもしれない。

####  GitLabでの試行錯誤

* [arm64対応のDockerイメージ。``yrzr/gitlab-ce-arm64v8``](https://hub.docker.com/r/yrzr/gitlab-ce-arm64v8)
    * コンテナ起動はできるのだが、Gitのサービスにアクセスできなかった
* [omnibus-gitlabのソースのarm64-docker-imageブランチ](https://gitlab.com/gitlab-org/omnibus-gitlab/-/tree/arm64-docker-image)
    * こちらのdockerディレクトリに移動して``docker build``するも、必要なファイルがなくて失敗

####  GitBucketでの試行錯誤

* [Docker HubのGitBucketのイメージ](https://hub.docker.com/r/gitbucket/gitbucket/)
    * arm64非対応で失敗
直線の方程式「22年 東北学院大 工 A 1(3)」をsympyでやってみた。

オリジナル
直交する直線の方程式は...

https://kamelink.com/blog/2022/08/18/4-1-22-touhokugakuinndai-kou-a-1-3/

大学入試数学問題集成＞
(20220818)未掲載

# sympyで
```python
from sympy import *
y=Symbol('y',real=True)
P=Point(-2,-3)
Q=Point( 4, 3)
M=P+(Q-P)*1/3
L=Line(P,Q).perpendicular_line(M)
print("#",solve(L.equation(),y)[0])
# -x - 1
```

# 参考
perpendicular_line(p)＜

https://docs.sympy.org/latest/modules/geometry/lines.html#sympy.geometry.line.LinearEntity.perpendicular_line
Kullback-Leiblerダイバージェンスに基づく不確実性集合

Kullback-Leiblerダイバージェンスを直感的に理解するには下記の記事が参考になります。

https://qiita.com/ceptree/items/9a473b5163d5655420e8


Kullback-Leiblerダイバージェンスに基づく不確実性集合における分布的ロバスト最適化について手を動かして確認しました。誤りがあればご指摘頂ければ幸いです。


https://mathlog.info/articles/3430


ポートフォリオ選択問題とロジスティック回帰の分布的ロバスト最適化についてまとめています。式変形でわからないところについてご教示頂ければ幸いです。

https://mathlog.info/articles/3431
PowerShellフォルダ選択ダイアログ

[前回](https://qiita.com/drafts/9cf7a965fcc4c0dbaaac/edit)PowerShellファイル選択ダイアログの記事を書いたが、ファイル選択ダイアログができればフォルダ選択もしたいというのが人情。

```powershell:フォルダ選択ダイアログ.ps1
#名前空間指定
[void][System.Reflection.Assembly]::LoadWithPartialName("system.windows.forms")

#フォルダ参照ダイアログインスタンス生成
$dialog=New-Object System.Windows.Forms.FolderBrowserDialog

#ダイアログの説明表示
$dialog.Description="フォルダ選択"

#ダイアログ表示
$showdialog=$dialog.ShowDialog()

#選択したかどうか
if($showdialog -eq [System.Windows.Forms.DialogResult]::ok){
    
    #ここに動作内容記述
    #選択したパス表示
    Write-Host $dialog.SelectedPath

    #条件に当てはまるファイルに対して一括でファイル名を変更、Rename-Item -Path “名前を変更するファイルパス” -NewName “新しいファイル名”
    #ファイル名の拡張子変更
    #Get-ChildItem ($dialog.SelectedPath+"\*.jpg") | Rename-Item -NewName{$_.Name -Replace "\.jpg",".jpeg"}
    #ファイル名のファイル名変更
    Get-ChildItem ($dialog.SelectedPath+"\*.m4a") | Rename-Item -NewName{$_.Name -Replace "NG","OK"}

    <#
    #フォルダ内のファイル取得
    $filelist=Resolve-Path $dialog.SelectedPath

    #フォルダにループ
    foreach($foreachlist in $filelist){
    }
    #>
}
else{
    Write-Host "キャンセルしました。"
}
```
【参考文献】

https://atmarkit.itmedia.co.jp/fwin2k/win2ktips/986psdialog/psdialog.html

https://nyanblog2222.com/programming/2366/
Google Cloud Professional DevOps Engineer受験記

前回の[Google Cloud Professional Security Engineer受験記](https://qiita.com/ryoeguchi/items/c0cf97c14a494e9b7e47)に続き、次なる試験[Google Cloud Professional DevOps Engineer](https://cloud.google.com/certification/cloud-devops-engineer)を受けてきたのでそのご紹介です

# 試験について
![pdoe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345258/2933f42f-0e24-d2ab-b8ea-6b4078c64070.png)
※ロゴが2022/08になって一新されました

名前の通り、DevOpsに関する試験となります。
「DevOps」についての詳細な説明はここでは控えますが、
 - Development
 - Operations
ということで、システムの開発及び運用をGoogleCloud上で行う能力について問うものです。もちろん他のProfessional資格でもそれに準ずる出題はされますが、GoogleCloudのサービスに限らず広くDevOps自体についても出題されるというのが、この試験の特徴と言えます。

# 勉強の仕方
今回はあまり馴染みのない分野だったこともあり、GoogleCloudとしての勉強は少なめでした。

1 試験ガイドの確認
試験自体のイメージが充分につかめていなかったので、まずはガイドを確認しました。Googleサービスについてはともかくとして、SLI/SLO/SLAといった用語の正しい定義だったり、インシデント発生時の対応などといったところは理解が不十分だったため、このタイミングで一旦調べることにしました。

2 模擬試験
試験ガイドの内容確認を経て、「模擬試験で訊きたいことが全然分からない！なんてことは無いだろう」と思えるところまできて模擬試験を解きました。初回は60%程度だったような記憶があります。前回の試験と平行学習になることは承知の上で、だいたい模擬試験の1か月後に実試験日を設定しました。
やはりこちらの模擬試験は全3回程度、その後の学習フェーズを経た後に解き直しをしました。

3 動画コンテンツでの学習
前回同様、Udemyで提供されている、ハンズオンの多い教材があったのでそれを観ての学習がGoogleCloudとしてはメインでした。幸い、これまで使うことの多いサービスばかりだったので、こちらについてはあまり時間を割かなかったかなと記憶しています。
一方で「DevOps」自体についての勉強の方が、やや比重を置いて行いました。非常に役立ったのが、[GoogleCloudTech Youtube公式チャンネル](https://www.youtube.com/user/googlecloudplatform)
で公開されている [class DevOps implements SRE](https://www.youtube.com/playlist?list=PLIivdWyY5sqJrKl7D2u-gmis8h9K66qoj)シリーズが有用でした。
これまで知りませんでしたが、GoogleCloudのチャンネルで公開されている動画は、何かと勉強に使えそうです。

# 実試験
リモート監視試験と実地試験がありますが、今回も実地試験を選択しました。

## 時間配分
私の場合は、やや早めに1周解ききりってから見直しで2周、合計3周するというのがこれまでの試験でも基本的なスタンスとしています。
ただし、試験が英語でしかないため、日本語ネイティブの身としてはやはり少し時間がかかりました。
1周目で1時間程度、微妙な問題が5~6問残ったままで一旦終わったのち、2周目で問題全部を見たうえでの整合性を確認し、3周目で最終見直しといった具合です。幸いにも、実質同じ問題と言えてかつ回答には困らないものがあったので、今回は助かりました。同じ問題だけど自身が無い場合には、別の答えにしてせめて片方だけでも正解させにいくか、信じて同じ回答にするかは悩みどころですね。

# 所感
今回の出来のイメージも75%くらいだったでしょうか。前回のSecurity Engineerよりは若干自身がありました。
出題内容についてあまり言及はしませんが、模擬試験と内容にしろレベル感にしろ、あまり乖離していなかったような印象を受けました。

今回のDevOps Engineerの勉強のおかげで、単純なGoogleCloudに関する知識だけでなく、広く開発におけるDevOpsの考え方を学ぶことができたのは大きな収穫だったと感じています。

Professional資格がこれで5つ目となりました。既に次の試験も近々控えているので、そちらも受験記録を残すつもりです。
PowerShellファイル選択ダイアログについて。

[前回](https://qiita.com/AnimaLibera/items/4add9a9502202704d729)PowerShellにて16進数ダンプの記事を書いたが、ファイル選択が面倒なので、ファイル選択ダイアログを表示することとした。[フォルダ選択はこちら](https://qiita.com/AnimaLibera/items/23c6f11dd7714b716822)

```powershell:ファイル選択ダイアログ.ps1

#C#(.NETライブラリ)の名前空間を指定してアセンブリを有効にする
#※記述しなくても動いた。
[void][Reflection.Assembly]::LoadWithPartialName("Ststem.Windows.Forms")

#ファイル選択ダイアログのインスタンス生成
$OpenFileDialog=New-Object Windows.Forms.OpenFileDialog

#タイトル、指定しない場合「開く」になる
$OpenFileDialog.Title="ファイル選択"

#拡張子、指定しない場合「空白で全てのファイル」になる
$OpenFileDialog.Filter="テキスト(*.txt)|*.txt|全てのファイル(*.*)|*.*"

#デフォルトディレクトリ、指定しない場合「このスクリプトと同じ場所」になる
$InitialDirectory="C:\Users\〇〇\Desktop"
$OpenFileDialog.InitialDirectory=$InitialDirectory

#ダイアログ表示
$Rsult=$OpenFileDialog.ShowDialog()

#ファイルを選択した場合
IF($Rsult-eq[System.Windows.Forms.DialogResult]::OK){
    #ここに選択したファイルの操作を記述

    #Invoke-Item は、実行可能ファイルを実行するなど、関連付けられているアプリケーションでファイルを開く。
    Invoke-Item $OpenFileDialog.FileName

    #コンソールにファイル名表示
    Write-Host "選択したファイルは「"($OpenFileDialog.FileName)"」です。"
    
    #コンソールに内容表示 
    Write-Host "内容は「"(Get-Content -Path $OpenFileDialog.FileName)"」です。"

}else{
    #コンソールにメッセージ表示
    Write-Host "ファイルを選択しませんでした。"
}
```



[【参考文献】](https://acoustic-groove2.hatenablog.com/entry/2017/12/30/023749)

https://acoustic-groove2.hatenablog.com/entry/2017/12/30/023749
Postman使用し、APIテストを行う

##### 目録
- API経由、salesforce組織のデータをアクセス

---

##### API経由、salesforce組織のデータをアクセス
- postmanのAPPやWebページにsalesforceのAPIパッケージをインストール、手順は [Explore the Salesforce APIs with a Postman Collection](https://developer.salesforce.com/blogs/2020/03/explore-the-salesforce-apis-with-a-postman-collection) を参考
- インストール完了後、一つ「collections」を作成、中に接続したい組織の「variables」と「authorization」を設置、その後組織に接続できる
- 「REST API」の「limits」テンプレートを使って、GETメソッドでAPIを叩く。
  - 具体的にな書き方は [標準オブジェクトレコードから項目値を取得する](https://developer.salesforce.com/docs/atlas.ja-jp.204.0.api_rest.meta/api_rest/dome_get_field_values.htm) を参考
  - 例：「ContentVersion」オブジェクトの「0685D000000ydUAQAY」レコードを取得したい場合、以下のコード`{{_endpoint}}/services/data/v{{version}}/sobjects/ContentVersion/0685D000000ydUAQAY/VersionData` でbase　64のファイルを取得、decodingで本来の画像が貰える
discordのbot作成をする上でDeveloperPortalで必要な操作

# discordのbot作成をする上でDeveloperPortalで必要な操作
## はじめに
こちらは、下記の記事のDeveloperPortalで2022/08現在、必要な操作を記載しています。
もしコードなどの解説がご覧になられたい場合は、下のリンクからご覧ください。

https://qiita.com/darakeee/items/e5f3c7349b36f6eaffa1


## サーバーにBotをいれるまでの手順
1. DeveloperPortalにアクセス。 
https://discord.com/developers/applications

2. discordのアカウントを使い、ログイン。

3. 画像右の「New Application」をクリック。
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/7730c59a-9da5-106a-4924-2fd7331dfd47.png)

4. 任意の名前を入力した後に、「Create」をクリック。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/67ac7498-7204-5faa-dbcf-75bedb366017.png)

5. 作成し終わるとこのような画面に切り替わります。
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/585de8c3-52db-5e5c-57b3-8243c9f980dc.png)

6. 画像左側のメニューバーで「Bot」を選択。
その後、画像右側の「Add Bot」をクリック。
![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/9950e59f-fd19-b80d-3850-5122f0b9b48f.png)

7. クリックすると画像のようになります。
![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/b44b7692-0a50-ff79-114c-a385a406c034.png)

8. そのまま下にスクロールして下の画像のように設定。
![6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/098077f3-c899-f17a-461f-8972561cb176.png)
※ここは自分が使いたいものをオンにします。
　今回の場合は、この二つで大丈夫です。
※こちらの画像にはありませんがPublic Botという欄があります。
　そちらは、基本的にはオフにすることをオススメします。

9. 画像左側のメニューバーで「OAuth2 → URL Generator」を選択。
SCOPESで「bot」、
BOT PERMISSIONSでは「Administrator」にチェック。
その後下にスクロールしていくと、「GENERATED URL」という欄にBotを招待するためのURLが生成されていると思いますので、コピーしてください。
![7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/8d985278-1a10-a6db-1046-5d56c290accf.png)
※今回は管理者権限を付与していますが、この権限しか使わない
　という場合は、そちらを選択していただいても大丈夫です。

10. 先ほどコピーしたURLをブラウザに貼り付けて開いてください。
このような画面になりますので、入れたいサーバーを選択して
「はい」をクリック。
![8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/301a3b14-4496-aa2e-3535-4f3ab9fba44d.png)

11. 画像のようにBotに権限を付与していいか聞かれるので「認証」をクリック。
![9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/92a0377c-821d-c3ac-7b08-a2ee9a91cb7a.png)

後は、人間かどうかのチェックをすれば、選択したサーバーに自分のBotが入ってると思います。


## トークンの取得方法
**※トークンは誰にも教えないでください。Botが乗っ取られる可能性があります。**

1. 画像左側のメニューバーで「Bot」を選択。
画像右側の「Reset Token」をクリック。
![10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/a6f5e82c-6f17-e70f-f7a1-5a5ad05fcb30.png)

2. すると、このような画面になるので「Yes,do it!」をクリック。
![11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721575/24391fc2-49a0-da1c-9e0d-67135f805369.png)

後は、トークンが出てくると思うのでコピーしてお使いください。
以上で、本記事を終わろうと思います。

## さいごに
ここまで見てくださり、ありがとうございます。
今回はDeveloperPortalで必要な操作をまとめてみました。
近いうちに、discord.js v14での簡単なbotの作り方を記事にしようと思いますのでよければ見てください。

参考記事

https://qiita.com/1ntegrale9/items/cb285053f2fa5d0cccdf
各ProductFlavorsによって使用するAPIエンドポイントを変えたい

# 初めに
前回の記事で書くBuildTypeによって要素を変更する処理を紹介したので、今回はProductFlavorsによって変更する処理を書いていこうと思います。
### 本文
前回同様`build.gradle`に書いていきます

```gradle
    productFlavors {
        register("stg") {
            buildConfigField(
                "String",
                "API_ENDPOINT",
                "\"api_end_point/\""
            )
        }
        register("prd") {
            buildConfigField(
                "String",
                "API_ENDPOINT", 
                "\"api_end_point\""
            )
        }
    }
```
上記は`build.gradle`を`kotlin`化している場合の書き方です。
していない場合は下記のように書けば大丈夫です
```gradle
    productFlavors {
        stg {
            buildConfigField(
                "String",
                "API_ENDPOINT",
                "\"api_end_point/\""
            )
        }
        prd {
            buildConfigField(
                "String",
                "API_ENDPOINT", 
                "\"api_end_point\""
            )
        }
    }
```
### 最後に
`buildTypes`だけだと、課金要素のあるアプリなどを作る時にAPIの制御を気にしないといけなくなるので、今回は`productFlavors`の方も描いてみました。
誰かの役に立てたら光栄です
あるGit branchを別のGit repoに移動する

# 背景

本来同じレポで管理したかったものが2つのレポになってしまっていたので、一つのレポにしておきたいなと思って調べた。

今回は、repo_srcとrepo_dstがあって、repo_srcの `target_branch` ブランチをそのままrepo_dstの `target_branch` ブランチに移動する

# ステップ

## 1. 変数をセット

後で同じコマンドを使えるように、こんな感じでセットしておく

```
REPO_SRC=https://github.com/nakamasato/repo_src
REPO_DST=https://github.com/nakamasato/repo_dst
REPO_SRC_PATH=~/repos/repo_src
REPO_DST_PATH=~/repos/repo_dst
TARGET_BRANCH=target_branch
```

## 2. repo_srcとrepo_dstをローカルにClone

GitのRemoteにPushしてない場合はCloneは不要。単純にREPO_SRC_PATHとREPO_DST_PATHをセットすればOK

```
git clone $REPO_SRC $REPO_SRC_PATH
git clone $REPO_SRC_PATH $REPO_DST_PATH
```

## 3. repo_dst側でremote `repo_src_remote`をセットする

```
cd $REPO_DST_PATH
git remote add repo_src_remote $REPO_SRC_PATH
```

## 4. repo_dst側で`TARGET_BRANCH`を作成しておく

```
git branch -b $TARGET_BRANCH
```

## 5. repo_dst側で`TARGET_BRANCH`をrepo_srcの`TARGET_BRANCH`にresetする

```
git reset repo_src_remote/$TARGET_BRANCH --hard
```

これで`repo_dst`レポ側の`$TARGET_BRANCH`に`repo_src`の`$TARGET_BRANCH`のコミットがすべて移動できた。もちろんターゲットブランチがrepo_dstとrepo_srcで異なってもできる。

## 6. 不要になったremoteをrepo_dstから削除する

```
git remote rm repo_src_remote
```

# 参考

- [Move git branch from one repository to another with preserving history
](https://kasunsiyambalapitiya.medium.com/move-git-branch-from-one-repository-to-another-with-preserving-history-81ed64de3a02)