OmniAICreator/Qiita-1.07M huggingface dataset:
Python、MySQLのDATETIME（マイクロ秒付き）の扱い

[mysql]:https://dev.mysql.com/doc/refman/5.6/ja/fractional-seconds.html
[strftime]:https://docs.python.org/ja/3/library/datetime.html#strftime-strptime-behavior

# やりたいこと
`2022-01-20 12:34:56.123456`というマイクロ秒まで含んだ形式で時刻を表し、MySQLに格納したりPythonで扱ったりしたい。

## 本記事では説明しないこと
PythonでMySQLからデータを引っ張ってくる部分。
[pymysql](https://github.com/PyMySQL/PyMySQL)等のリファレンスをご参照ください。

# MySQL側
```sql:MySQLでDATETIME(6)を扱う
CREATE TABLE tbl (dt DATETIME(6));
INSERT INTO tbl VALUES('2022-01-20 00:16:07.123456');
```

# Python側
```python:pythonで表現するDATETIME(6)
from datetime import datetime
datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
#=> '2022-01-20 00:16:07.123456'
```

# 説明
MySQLでマイクロ秒までついた時刻を扱いたい時は`DATETIME(fsp)`という型が使えます。`fsp`は小数点の桁を表す、0から6の整数です。[（MySQL 5.6.4 以降）][mysql]
>
MySQL 5.6.4 以降では、マイクロ秒 (6 桁) までの精度を持つ TIME、DATETIME、およびTIMESTAMP 値に対して小数秒のサポートを拡張しています。

また、Python側ではdatetimeを[strftime()][strftime]で`%Y-%m-%d %H:%M:%S.%f`形式の文字列に変換しています。
>
%f 指定子は 1 桁から 6 桁の数字を受け付け、右側から0埋めされます。
000000, 000001, ..., 999999

## 参考
MySQLのマイクロ秒  https://dev.mysql.com/doc/refman/5.6/ja/fractional-seconds.html
strftime  https://docs.python.org/ja/3/library/datetime.html#strftime-strptime-behavior
Node.js が無理やり終了した時も処理したいときのメモ

Socketio を個人的に触っていて、
Node.js の終了時に処理を入れようと調べていて、
こちらの方の記事を参考にしていました。

https://qiita.com/Hiroki_Kawakami/items/f95b0cdbd201557b18cd

上記記事の情報に加え、
Terminalが強制終了されてしまったときなど、
雑に終了される時に処理をする方法をメモ。

## テストコード
各イベントが発火しているのかをテストするために、
発火したイベントとタイムスタンプを JSONにメモるような処理にした。
※console.logを出しても、Terminalが閉じてしまったら読めないため

```js:server.js

// サーバー構築
const http = require('http');
const fs = require('fs');
const server = http.createServer(requestListener);


/* ---------------------------------------------------
 終了時保存テスト
--------------------------------------------------- */

var saveData = {};

// httpサーバーの起動
server.listen((process.env.PORT || 5000), function() {
  console.log((process.env.PORT || 5000) + 'でサーバーが起動しました');
  clearJson();
});


// JSONの白紙化
function clearJson() {
  var json = JSON.stringify("", null, "  ");
  fs.writeFileSync("savedata.json", json);
}

// 発火イベントと時刻をJSONに書く
function saveJson(_eventName) {
  saveData["event"] = _eventName;
  saveData["date"] = new Date();
  var json = JSON.stringify(saveData, null, "  ");
  fs.writeFileSync("savedata.json", json);
  console.log("JSONを保存しました");
}

// exit時
process.on("exit", function() {
  console.log("exit しました");
});

// Ctrl + C での終了を検知
process.on("SIGINT", function () {
  console.log("SIGINT が発火");
  saveJson('SIGINT');
  process.exit(0); //プロセスを正常終了させる
});

// Terminal が閉じられるのを検知
process.on("SIGHUP", function () {
  console.log("SIGHUP が発火");
  saveJson('SIGHUP');
  process.exit(0); //プロセスを正常終了させる
});

```

## Node.js のプロセスの終了前のイベント各種
`process.on("イベント名", function());`

### Ctrl+C で終了した場合
`SIGINT`
![Ctrl+Cで終了.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48396/d953b959-db0e-d456-bf44-d7c820427aab.gif)
SIGINTイベントをリスナー登録することで ターミナルで Ctrl+C 押下もプロセスはまだ生きる。
JSONに SIGINTとタイムスタンプが書き出された
(※ ちなみに webstorm や VSCode の runパネルで実行しているときの ◼停止ボタン 押下時もこれが発火する)

### ターミナルが閉じられた場合
`SIGHUP`
![Terminalを閉じた.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48396/d32d9602-97ab-224d-04c5-2f734bfdfc90.gif)
SIGHUPイベントをリスナー登録することで、ターミナルのウインドウを閉じてもバックグラウンドでプロセスはまだ生きている。
JSONに SIGHUPとタイムスタンプが書き出された

### ターミナルが強制終了した場合
同じく `SIGHUP`
![Terminalを強制終了させた.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48396/5cd8d4dd-73d4-4fcd-5871-74d22f58637c.gif)
SIGHUPイベントをリスナー登録することで、Mac OS側の「アプリケーションの強制終了」でターミナルを強制終了してもバックグラウンドでプロセスはまだ生きている。
JSONに SIGHUPとタイムスタンプが書き出された

### プロセスの終了前
`beforeExit`

### プロセスの終了時
`exit`

### OS自体のクラッシュ
OS自体のクラッシュや、コンピュータの強制シャットダウン (電源ボタン長押しとか停電）などでは Node.jsの プロセスも物理的に即死するので、処理は不可能だと思う。

## その他
これらのイベント発火は
Linuxコマンドのシグナル (SIG) に準拠しているみたい。
以下記事を参考にした。

http://yohshiy.blog.fc2.com/blog-entry-315.html

.
Java初心者に向けた基本事項メモ

Javaには色々ルールがあるため、ここに備忘用として残していきたい。

・変数の命名規則
キャメルケースで記載するのが基本？（スネークケースは好まれない？）
例えば、赤い飴を変数として宣言するときは
`red_candy`
ではなく
`redCandy`
といったような記載をすると良い。

・変数の型が混同した際の仕様
double型とint型を混ぜるとdouble形に吸収される。
入力：
`double a = 12.5;`
`int b = 5;`
`System.out.println(a + b);`
出力：
`17.5`

String型とint型を混ぜるとString形に吸収される。
入力：
`String c = "テスト"`
`int b = 5;`
`System.out.println(c + v);`
出力：
`テスト5`

・for文の仕様
次の周に進む。
`continue;`
for文を打ち切る。
`break;`

・拡張for文
以下の記載にすることで、配列やリストといった複数の値を持つ箱？の中身を全て回してくれる。
`for(データ型 変数名: 配列やリスト名）{`
`}`
例（普通のfor文）：
`for(int i; names.length; i++){`
`}`
例（拡張for文）：
`for(String name: names){`
`}`
'useFindAndModify' が有効なオプションでない時のエラー (mongoose を使ってmongoDBに接続する)

##エラー
Node.jsにおいてmongooseでmongoDBに接続するコードで下記のように書くと

```
エラーコード

mongoose.set('useFindAndModify', false);

await mongoose.connect('connectionURL', {
  useNewUrlParser: true, 
  useUnifiedTopology: true 
});
```



```
Error: `useFindAndModify` is an invalid option
```

上記のようなエラーが起こる。

##原因
原因としては、不要なコードがあることが考えられます。

```
mongoose.set('useFindAndModify', false);
```

##解決法
なので、上記のコードを次のように書き換えます。



```

mongoose.set('useFindAndModify', false); //いらない

mongoose
  .connect('connectionURL', {
    useNewUrlParser: true,   //いらない
    useUnifiedTopology: true,  //いらない
  })
  .then(() => {
//接続に成功
    console.log('Success!! MongoDB connection ');
  })
  .catch((err) => {
//接続に失敗
    console.log('Failed MOngoDB connection');
    console.log(err);
  });
```

##参考
https://stackoverflow.com/questions/69030963/error-usefindandmodify-is-an-invalid-option
Microsoft Azure Virtual Training Day: Fundamentals

Azureを勉強する時に最初の教育課程と言うと「Microsoft Azure Virtual Training Day: Fundamentals」ですね。
そのクラスで、得た情報のリンク集です。

１．最初資格取得欲しい場合、az-900
https://docs.microsoft.com/ja-jp/learn/certifications/exams/az-900
２．**Azure無料教育**
https://docs.microsoft.com/ja-jp/learn/azure/
３．Azureアカウント作成方法
https://docs.microsoft.com/ja-jp/learn/modules/create-an-azure-account/3-exercise-create-an-azure-account
４．AzureからWEBサイトをホストして見る
https://docs.microsoft.com/ja-jp/learn/modules/welcome-to-azure/4-exercise-create-website
５．App Service構成方法
https://docs.microsoft.com/ja-jp/learn/modules/welcome-to-azure/5-exercise-configure-app-service
６．Azure Cloud Shell概要
https://docs.microsoft.com/ja-jp/azure/cloud-shell/overview
７．ペイン利用
https://docs.microsoft.com/ja-jp/learn/modules/tour-azure-portal/4-exercise-work-with-blades
８．Azure Portal利用
https://docs.microsoft.com/ja-jp/learn/modules/tour-azure-portal/5-exercise-navigate-the-portal
９．ダッシュボードの利用
https://docs.microsoft.com/ja-jp/learn/modules/tour-azure-portal/7-exercise-customize-the-dashboard
１０．Azure費用計算
https://docs.microsoft.com/ja-jp/learn/modules/predict-costs-and-optimize-spending/2-estimate-costs-with-the-azure-pricing-calculator
１１．Azureのコストを計画
https://docs.microsoft.com/ja-jp/learn/modules/predict-costs-and-optimize-spending/3-predict-and-optimize-with-cost-management-and-advisor
１２．Pluralsight役割基盤評価実施
https://www.pluralsight.com/partners/microsoft/azure
１３．**Azure基本コース**
https://docs.microsoft.com/ja-jp/learn/paths/azure-fundamentals
１４．AZ-900練習
https://github.com/MicrosoftLearning/AZ-900T0xKO-MicrosoftAzureFundamentals
１５．Azureアップデート状況
https://azure.microsoft.com/ja-jp/updates
１６．リリースされる予定のAzure
https://preview.portal.azure.com
InteliJ のデータベースツールから Amazon Aurora MySQL へ接続する


公式ドキュメントによると JDBC 接続文字列の形式は以下のようになるが、InteliJ での設定が分からなかった。

```
jdbc:mariadb:aurora://[clusterInstanceEndPoint[:port]]/[database]
```

結論としては、Amazon Aurora MySQL のドライバーに新しい URL テンプレートを追加すれば良い。

## 設定

設定パネルの青い文字をクリックするとオプションを切り替えられる。
ドライバーに `Amazon Aurora MySQL` を選ぶとよしなにドライバーのダウンロードも行ってくれる。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19223/d811f39b-f7fe-bf63-9115-7773045bb994.png)

ドライバータブを選択すると先ほどインストールされたドライバが存在する。
URL テンプレートには `jdbc:mariadb:aurora://` は存在しないので default 設定を利用して追加する。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19223/d054ca98-acba-0a9e-7a43-3436463a0f14.png)

データソースタブに戻り、接続タイプに先ほど追加した設定を選ぶ。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19223/481b1a8f-881e-83c6-6483-956f049162c8.png)

後は SSH/SSL タブから SSH トンネルの設定を行うと、InteliJ から接続できるようになる。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19223/d2f5df51-7ec3-f7ed-86c0-fa37170b26bd.png)



## 参考

- [MySQL との互換性を持つ Amazon Aurora での MariaDB JDBC ドライバーの使用 \| Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/using-the-mariadb-jdbc-driver-with-amazon-aurora-with-mysql-compatibility/)
API実装時のステータスコードまとめ

# ステータスコードに迷ったときに見る逆引き一覧
色々情報漁った結果のまとめ。
適宜修正してく。

## 正常系
HTTPメソッド|アクション|ステータスコード
---|---|---
GET|show, index|200 OK
POST|create|201 Created
PUT|update|200 OK
DELETE|delete|204 No Content

## 異常系
失敗ケース|ステータスコード
---|---
認証エラー(ログイン失敗、認証トークン無効など)|401 Unauthorized
パラメータ不正(不足、値が望ましくないなど)|400 Bad Request
show, update, delete系APIで、その操作対象が存在しない(テーブルがない、レコードがない)|404 Not Found
その他うまいこと処理できなかった|500 Internal Server Error

**エラー系ステータスコードのイメージ**

- 4xx系: フロントエンド側の不備
- 5xx系: バックエンド側の不備
EXCEL 行番号

あるセルに内容が有る場合のみ、行番号を表示するセルの形式は標準にして、下記の内容を記載してくれれば、大丈夫です。

```vba:行番号
=IF(ISBLANK(B2),"",ROW()-1) 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516328/a40c1103-41b0-de76-ed20-8928bd9b545a.png)


B2が内容が記載されるセルの位置です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516328/08a2e72b-e09d-e006-ffdd-b6e5e18c0cc2.png)



ROW()-1の1は上から行番号を始める行の数を入れてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516328/f353d2a9-7f65-2b92-8901-978b10e8c849.png)
Firestore データが取得できない エラーも出ない【メモ】 

##結論
沼にハマりました。

Firestoreでデータ取得を行おうとしたら、デー取得できず、エラーも出ない状況が起きました。

```
日付の降順にデータをソートしてtaskの全件取得

const res = await db.collection('tasks').orderBy('dateTime', 'desc').get();
```
上記のコードでは問題なく機能しましたが、
orderByを使うときに、対応するドキュメントがあるか確認しないと、エラーも出ずにデータも取得できない状態に陥ってしまう可能性があります。



##参考
https://zenn.dev/code_diver/articles/0c335327ff8a08
部分関数従属の不利益の一例

COMPANY_ID,EMP_IDがprimarykeyの時roleより右にも色々カラムがあったとして、それらは完全関数従属{COMPANY_ID,EMP_ID}→{role,etc...}
になっていたとする。
この時、画像のようにcompany_idに対してcompany_nameは一意なはずなのにで混乱を招く入力ができてしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/e9af3cdf-09c9-ec34-9edd-ede7c92bde58.png)

```
drop TABLE if exists test;
CREATE TABLE test(
    COMPANY_ID CHAR(5),
    COMPANY_NAME CHAR(5),
    EMP_ID CHAR(5),
PRIMARY KEY(COMPANY_ID,EMP_ID));

insert into test
values
    ('A0001', 'C建設', '44444' )
  , ('A0001', 'C商事', '55555' )
  , ('A0001', 'C商事', '66666' )
;

SELECT *
from test;
```
EXCEL VBA シートから一覧作成マクロ

たまに、シートが多いファイルを利用する時とかシートで分けて作成して、目次を作る必要がある場合もあります。
その場合、量が多いと、手動でするのはつらいので、作成して見ました。

```vba:&#x20;SheetListMake
Sub SheetListMake()

    Dim list_sht As Worksheet
    Dim sht As Worksheet
    Dim i As Integer
    Dim t1 As Range
    Dim t2 As Range
    Dim condition As Range
    Dim d1 As Range
    Dim d2 As Range
    Dim d3 As Range

    'リストを書き出すシート名
    Set list_sht = Worksheets("list_sheet_name")
    i = 2
 
    For Each sht In Worksheets
        Set condition = sht.Range("A1")
        If condition = "targetText" Then
            Set t1 = sht.Range("C1")
            Set t2 = sht.Range("C2")
            Set d1 = list_sht.Range("B" & i)
            Set d2 = list_sht.Range("F" & i)
            Set d3 = list_sht.Range("J" & i)           

            d1.Value = "=Hyperlink(""#" & sht.Name & "!A1"", """ & t1.Text & """)"
            d2.Value = t2.Text
            Debug.Print sht.Name & " | " & t1.Interior.ColorIndex

            If t1.Interior.ColorIndex = 16 Then
                d3.Value = "N"
            Else
                d3.Value = "Y"
            End If

            i = i + 1
        End If
    Next sht

End Sub
```
VirtualBox Guest Additionsを導入してみた

# はじめに
今回は、以下の記事で作成したVirtualBox上のOracle Linux 8にVirtualBox Guest Additionsを導入する手順を紹介する。

https://qiita.com/tk_miya/items/8f99ad95a04c67b06d79

VirtualBox Guest Additionsを導入することで、

- シームレスなマウスカーソルの操作（右ctrlを押す必要がない）
- シームレスなウィンドウサイズの変更
- クリップボードの共有

などが可能となり、よりゲストOSが使いやすくなる。
# 導入手順
### 1. ゲストOSをアップデートする
ゲストOS内でターミナルを立ち上げて、rootユーザーで以下のコマンドを実行する。

```root:rootユーザー
yum update
```
### 2. 必要なパッケージをインストールする
VirtualBox Guest Additionsの導入に必要なパッケージをインストールする。
rootユーザーで以下のコマンドを実行する。

```root:rootユーザー
yum install kernel-uek-devel-$(uname -r)
yum install kernel-headers
yum install gcc
yum install make
yum install perl
```
### 3. VirtualBox Guest AdditionsをゲストOSにインストールする
VirtualBoxのVMのウィンドウのデバイスタブをクリックして、Guest Additions CD イメージの挿入をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/4abaa3ae-a3fa-25a0-25aa-52931e388389.png)
"Run"をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/83e1f553-c5b3-7546-ed85-9295c6ad6baa.png)
ユーザーのパスワードを入力して"Authenticate"をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/68b44375-b378-cbb0-26d6-8e499da5d2b7.png)
ターミナルが立ち上がりGuest Additionsがインストールされる。インストール完了後、ターミナルを閉じる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/073192a4-922d-c17e-6c2e-1d6b6de971f6.png)
インストール後、VMを再起動する。ウィンドウの右上のアイコンが並んだタブをクリックして、電源アイコンをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/978e093a-ea93-af62-4ba6-863991e4c225.png)
"Restart"をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/3c86d63b-af0a-3321-65ca-f6c548dccd05.png)
### 4. Guest Additionsによる機能を試してみる
- マウスカーソルがゲストOSとホストOSをまたいで自由に移動できるようになっている

- ウィンドウの画面の解像度を任意の値に変更できるようになっている
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/4e5254ad-a020-5b87-a807-cd51e9401dc2.png" width="500">

- "ウィンドウのサイズを調整"を使用することで最大化したときに画面いっぱいに使える。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/539f8f3d-91d7-c198-e3b3-c9f2227bd5d1.png" width="500">

Guest Additionsインストール前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/ffefb4d8-e927-826b-dbbe-294a8322ec77.png)
Guest Additionsインストール後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/0a882a7d-602d-4cba-6b4e-d8f8386ff116.png)

- クリップボードの共有を"双方向"に設定することでゲストOSとホストOSの間でコピー&ペーストが可能になる

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/01be54e0-acd9-8f42-65c6-221da113ec22.png" width="600">

# まとめ
今回は、VirtualBox上のOracle Linux 8にVirtualBox Guest Additionsを導入する手順とその機能を紹介した。マウス操作や画面の見やすさなど使いやすさが格段に上がり、作業効率も向上するため、導入することを強くおすすめする。
ラインとfacebookMessengerのメッセージ受送信について

実際開発に入っているわけではないので、軽くどんな内容があるかを調査した内容です。


1. ライン
1.1. ライン利用の概要
https://note.com/misuzu_neccos/n/n5b94a7099fb8#dxbfs
1.2. メッセージ（Webhook）を受信
https://developers.line.biz/ja/docs/messaging-api/receiving-messages/#verifying-signatures
1.3. メッセージを送信
https://developers.line.biz/ja/docs/messaging-api/sending-messages/

2. facebook
2.1. facebookMessengerの概要
https://developers.facebook.com/docs/messenger-platform/introduction
2.2. メッセージ（Webhook）を受信
https://developers.facebook.com/docs/messenger-platform/webhook
2.3. メッセージを送信
https://developers.facebook.com/docs/messenger-platform/send-messages
2.4. Facebook Chat (Messenger) for Python
https://fbchat.readthedocs.io/en/stable/install.html
Ubuntu 20.04.3 LTS+PostFix環境でさくっとDKIM対応

# Ubuntu 20.04.3 LTS+PostFix環境でさくっとDKIM対応

## 動機

- ぶっちゃけメール受信だけならSPFだけでいいけど、クラウドメール勢が多くなってきたからDMARCで協調しないといけなくなった。許すまじGAFAM。まずはDKIMか。

## 環境

- Ubuntu 20.04.3 LTS
- OpenDKIM: opendkim/focal,now 2.11.0~beta2-1 amd64
- Postfix: postfix/focal-updates,now 3.4.13-0ubuntu1.2 amd6 インストール設定済

## DKIMのインストール

```sh
apt install opendkim opendkim-tools
```

## DKIMキーの作成

```sh
mkdir -p /etc/postfix/dkim
cd /etc/postfix/dkim
opendkim-genkey -t -s yyyyMMdd -d example.com
ln -s yyyyMMdd.private dkim.key
chown -R opendkim:opendkim /etc/postfix/dkim
cat /etc/postfix/dkim/yyyyMMdd.txt #メモ
```

## DNSコンテンツサーバのTXTレコードにDKIM公開鍵を登録

- Bindの場合はメモしたものをそのままTXTレコードに設定可能。
- それ以外の場合はメモしたyyyyMMdd.txtの"v=～～"以降のデータ部分を"とスペースと改行を消して連結させる必要がある。
- テストが完了したならTXTレコードの値からt=y;属性は消してもよい。
- TXTレコードの例
    + yyyyMMdd._domainkey.example.com TXT 3600 "v=DKIM; h=sha256; k=rsa; p=（長い文字列）"

## opendkimの設定

```sh
vi /etc/opendkim/opendkim.conf
```

```
#ディレクティブをそれぞれ変更
Domain                  example.com
KeyFile                 /etc/postfix/dkim/dkim.key
Selector                yyyyMMdd
Socket                  inet:8892@localhost
#Socket                 local:/run/opendkim/opendkim
```

## postfixの設定

```sh
vi /etc/postfix/main.cf
```

```
# ディレクティブをそれぞれ追加
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:127.0.0.1:8892
non_smtpd_milters = $smtpd_milters
```

## 各種サーバの再起動

```sh
systemctl restart opendkim
systemctl restart postfix
```

## テスト

https://www.appmaildev.com/en/dkim

DKIMがpassになっていたらOK。

## 留意点

大した情報ではないけど、以下のファイルは
どこかサーバとは別の場所にセットで暗号化して保存しておこう。

- /etc/postfix/dkim/yyyyMMdd.private
- /etc/postfix/dkim/yyyyMMdd.txt

## DMARC

ガチでやるとしんどいけど、相手側にメール取り扱いを指示するだけなら
以下のページに従いTXTレコードを追加するだけ。

- https://support.google.com/a/answer/2466563?hl=ja
- TXTレコードの例
    + _dmarc.example.com TXT 3600 "v=DMARC1; p=quarantine; sp=quarantine; pct=100; adkim=s; aspf=s;"
[flexbox]media queryなしでレスポンシブ対応

# やったこと
今回はflexboxを使ってmedia queryを使わずにレスポンシブデザインを作りたいと思います。

幅999px以下で縦に積み上がって、1000px以上は要素が半分になるように作っていきます。

## コード
### html
htmlは簡単にしています。

```.html
      <div class="flexbox">
        <div class="flexbox__item">アイテム1</div>
        <div class="flexbox__content">アイテム2</div>
      </div>
```

### css
cssはこれだけです。

```.css
.flexbox {
  display: flex;
  flex-wrap: wrap;
  width: 100%;
  box-sizing: border-box;
}
.flexbox__item {
  background: #ddd;
  padding: 8px;
  flex-grow: 1;
  flex-basis: 450px;
  box-sizing: border-box;
}
.flexbox__content {
  width: 100%;
  background: #ff0000;
  flex-grow: 1;
  flex-basis: 450px;
  box-sizing: border-box;
}
```

### キャプチャ
3つの枠を作ってみました。
上から360px, 600px, 1000px(幅は適当に設定しました)
![スクリーンショット 2022-01-26 17.47.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163415/2e86153b-67ae-be04-7c52-b240d1c0e3e5.png)

### 解説
cssの解説になります。

まず親の要素(.flexbox)でdisplay: flex;を指定して、
flex-wrap: wrap;でflexboxからはみ出た要素を下に配置するように設定します。

その次に子要素にそれぞれ
`flex-grow, flex-basis`を設定します。

`flex-grow`はflexboxアイテムの幅の伸び率を設定します。
今回の件で言うと1000px以上は要素が半分なので、均等に1:1で作るため、両アイテムとも1を設定しています。

`flex-basis`はflexboxアイテムの初期の寸法を設定します。
300pxに設定すればそれを元に他のアイテムとの兼ね合いを見て、伸長したり縮小したりします。
今回は両アイテムとも500px以下になれば縦にしたかったので、500pxを設定することで
各アイテムが500px以下になるとflex-wrapがあるので積み上げる形になります。

## まとめ
flexの登場で最近のcssは面白い&やれる幅が増えているのでもっと勉強したいですね。
ロジスティック回帰をAI on Browserで動かしてみた！

今回はロジスティック回帰を紹介します。

# 目次
・[ロジスティック回帰とは](#ロジスティック回帰とは)
・[AI on Browserで動かしてみる](#AI on Browserで動かしてみる)
・[実装コードの確認](#実装コードの確認)
・[利用例](#利用例)

# ロジスティック回帰とは

予測結果を確率の形で求めることのできる分類モデルの一種です。

### 分類モデルとは

分類モデルとは、予測したい値がどのクラスに分類されるかを判別するモデルのことです。
この時、予測したい値を目的変数と呼び、判別材料として用いる変数を説明変数と呼びます。

例えば、
ガン患者と健常者についての、喫煙歴とアルコール摂取量のデータを所持しているとき
説明変数：喫煙歴、アルコール摂取量
目的変数：ガンになるかどうか（なるかならないかの二値）
として、喫煙歴とアルコール摂取量を用いて、「ある患者がガンになるかどうか」を予測することができます。

### ロジスティック回帰とは

ロジスティック回帰では、予測結果を確率として考えることができます。

通常の分類モデルでは「ガンになるかならないか」のどちらに属するかを予測するのに対して、ロジスティック回帰の場合は「ガンになる確率」を予測することにより分類を行います。

ロジスティック回帰の式は
$$y = \frac{1}{1+ \exp( - (\alpha + \beta x))}$$

と表すことができます。

$y$は目的変数（予測結果の確率値）、$x$は説明変数です。
$\beta$は回帰係数と言い、それぞれの説明変数への重みを表す数値です。

最終的には予測した確率に基づいて、分類を行います。

# AI on Browserで動かしてみる

[AI on Browser](https://ai-on-browser.github.io/?data=manual&task=CF&model=logistic&dimension=2)で実際にロジスティック回帰を動かしてみます。

![logisticregression_01 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318160/68d6b058-0a94-c3b0-3e24-3e3ca7e92f08.gif)


# 実装コードの確認
AI on BrowserのコードはGithub上に公開されており、ロジスティック回帰についてもコードの確認を行うことができます。

[Logistic Regressionの実装コード](https://github.com/ai-on-browser/ai-on-browser.github.io/blob/943fc4c56a08a8f71bcca133042d869cddd30424/lib/model/logistic.js) 

# 利用例
ロジスティック回帰は、前回とりあげた[Ridge回帰](https://qiita.com/d-matoba/items/7512f7a49c5048e1a45f)などのように「数値」を予測するわけではなく、「〇か×か」というような分類を行う手法となります。

予測結果が確率値に基づく分類として得られるという特徴があります。
例えば、マーケティングのシーンでは、商品購入者の属性やサイトの閲覧履歴から、「商品購入につながるか」の予測を行うこができ、より良いマーケティングの戦略を立てる指標として利用することができます。
また、顧客情報を用いて貸し倒れのリスクを予測することで、ローンの審査などにも利用されているようです[^1]。

[^1]: https://www.boj.or.jp/announcements/release_2019/data/rel190215d2.pdf
FirebaseのFacebook認証でローカル環境ではログインできない件でローカル環境ではログインできない件

##FirebaseのFacebook認証エラー

firebaseのauthenticationで、facebookアカウントを使ったログイン機能を実装してログインしようとするとエラーが出ました。

下記の画像のように、"URLを読み込めません"や"安全ではない"という警告をされてしまいます。



![スクリーンショット 2021-12-30 14.29.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/748980/08785b7c-ff9e-5211-1b1b-ba6fde26272e.png)


![スクリーンショット 2021-12-30 14.28.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/748980/313ff2de-bcf5-3d51-d578-c476c66cc8f4.png)

##結論
結論から言うと、ローカル環境でなく、デプロイ後であれば正常に動きました。

おそらくローカル環境では、http://...で通信が暗号化されていないためだと考えます。
一枚目の画像のにも**"URLを読み込めません"**と言われています。
なので、デプロイしてURLをhttps://...にすれば解決できるということになります。

##対処法
現在わかる対処法は2つ

* デプロイしてURLをhttps://...にする
* facebookから設定を変える

facebookの設定についてはまた、詳細がわかれば、追記していきます。
簡単なDAppを作ってみる 構想編

前回記事で[ブロックチェーンで何ができるのか](https://qiita.com/N_Shogo/items/97518b39088f2a286666)を理解したところで、実際に簡単なDAppを作って、更に理解を深めていきたいと思います。
この記事では、どのようなDAppを作るかを考えていきます。
なお、勉強中かつ構想段階なので作っていくうちに追記・修正するかもしれませんのでご了承ください。

# どの特徴を活かすか
復習になりますが、ブロックチェーンには以下の特徴がありました。

* データの透明性と追跡可能性
* データの耐改ざん性
* システムダウン耐性
* スマートコントラクト

これらの特徴を活かしたサービスを作れば良いことが分かりました。
今回は、**スマートコントラクト**を使って、**データの透明性と追跡可能性**を活かしたDAppを作ってみようと思います。

# システム図
以下のような投票DAppを作ってみようと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499481/4c02f37f-2c1c-5c40-ad41-e7dca19e1c4a.png)

各機能の簡単な流れを以下に記載します。
## 投票イベント発行
1. イベント発行者が名前や立候補者、期日など投票イベント情報を記入(今回は固定)
1. 投票イベントを発行

## 投票
1. 投票者が投票イベント一覧から参加したい投票イベントを選択
1. 投票権(投票トークン)を受領
1. 立候補者を選んで投票

## 投票状況確認
1. 傍観者が投稿イベント一覧から状況確認したい投票イベントを選択
1. 投票状況確認を選択
1. いつ誰が誰に投票したか確認

# 仕様
* 一人につき一票(1トークン)を配布
* 投票状況はいつ誰でも閲覧でき、いつ誰が誰に投票したか確認可能
* ブロックチェーンはEthereumチェーンを使用
* 投票イベント発行や投票トランザクションや投票状況読み取りはスマートコントラクトを使ってリクエスト
* 立候補者は固定。余裕があれば立候補者もトークンを使用して立候補できるようにするなど拡張したい
* 期日が過ぎたら、投票を締め切り、誰が当選したか発表。これも余裕があれば当選者は投票されたトークンを総取りとかにできるようにしたいです(実際に運用すると法律に違反しそう…するのかな？)

次回は開発環境構築を行います。
IE11で縦に配置したflexアイテムのmargin-top:autoが効かない問題の回避策

CSSのFlexボックスを使って「タイトル、テキスト、画像」を縦に配置したカード型のボックスを作り、それらのボックスを横に並べるとします。ここで互いに高さがバラバラな画像をボックス内で下揃えしたい（下図）。ところが、IE11だ表示が崩れてしまいハマりました。その回避策のメモです。

<p class="codepen" data-height="564" data-default-tab="result" data-slug-hash="GRORBbo" data-user="kaz_hashimoto" style="height: 564px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kaz_hashimoto/pen/GRORBbo">
  [CSS] Workaround for flexbugs about margin-top on IE11</a> by Kazuhiro Hashimoto (<a href="https://codepen.io/kaz_hashimoto">@kaz_hashimoto</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

Flexボックスで上記のような下揃えを実現するには、img要素を囲むflexアイテムのdivに```margin-top: auto```を指定してやればうまくいくハズです。

CSS仕様: [CSS Flexible Box Layout Module Level 1](https://drafts.csswg.org/css-flexbox/)
> [9.5. Main-Axis Alignment](https://drafts.csswg.org/css-flexbox/#main-alignment)
> 12. Distribute any remaining free space.

```html:html
<div class="card">
  <div class="title">タイトル</div>
  <p class="text">テキスト</p>
  <div class="image"><img src="foo.jpg" alt=""></div>
</div>
```

```css:css
.card {
  display: flex;
  flex-direction: column;
}
.image { /* flexアイテム */
  margin-top: auto; /* free spaceが分配されるハズ */
}
.image img {
  width: 100%;
  height: auto;
  vertical-align: top; /* div内で隙間を消す */
}
```

ところがIE11だとうまくいきません（下図）。img要素を囲むdiv（赤枠)のmarginではなく高さの方が伸びて、img要素がdivの上側に配置されるため下側に大きな余白ができてしまい下揃えになりません。

![flexbug-ie11-2_50p.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/0f25adf4-f5d9-138f-156f-6f2f61875288.png)

IE11の場合、img要素を囲むdivに```min-height```を0以外の確定値(px)で設定してやればこの問題を回避できるようです。

```css:css
.image {
	margin-top: auto;
	min-height: 1px;	/* IE11 */
}
```

IE11でも画像の下揃えを実現できました（下図）。

![flexbug-ie11-1_50p.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/572895e9-d384-4930-6014-f6c1e31a60f8.png)

追加した```min-height```の設定はIE11以外のブラウザには不要な設定ですが、残しておいても影響ありません。
Teamsにてメンション方法

メンションはチャネルの会話やチャットで特定のユーザーに向けて通知を送る機能です。
驚いたのは、チャット内の全員へメンション方法がまだないとのことでした。


チーム内のメンション
@team
@チーム
@〇〇〇（チーム名）

チャネル内のメンション
@general

該当チャネル内のメンション
@channel
@チャネル
@〇〇〇（チャネル名）


チャット内のメンション
@〇〇〇（名前）
[rails]いいねが削除できない💦　→ネスト時には引数が2つ必要

#はじめに
この記事はプログラミング学習の備忘録です。
今回はrailsでいいね機能の削除ができず、時間を使ってしまったのでまとめます。


今回分かったこととしては、**「ネストしている場合は引数を2つ指定する必要がある」**ということです。

#エラー内容
以下今回の記事の前提です。
・散歩習慣アプリを作っている
・投稿機能には、「walks」というモデルを使っている。
・いいね機能には、「likes」というモデルを使っている。

いいねを削除するために以下のように実装しました。

```index.html.erb
  <%= link_to "いいねを解除" ,walk_like_path(walk),method: :delete %> 
```


walk_like_path(walk)で投稿に紐づくいいねを指定、
method: :deleteも付けているので問題なさそうです。
しかし表示してみると、

[![Image from Gyazo](https://i.gyazo.com/eecd8e9a208e0ed922f9d335780693c8.png)](https://gyazo.com/eecd8e9a208e0ed922f9d335780693c8)

「No route matches」エラーが出てしまいました。

#原因
　もしかしたら「ネストしているとpathの指定方法が変わるのでは？」と思い、rails routesを実行すると以下のように出ました。

```
walk_like DELETE /walks/:walk_id/likes/:id(.:format)                                                      likes#destroy
```

「/walks/:walk_id/likes/:id」walk_idの他に、likesのidもパスに入っています。

その後様々調べてみると、
**ネストしている場合「引数は2つ指定する必要がある」**という事がわかりました。
（参考記事↓↓）
https://qiita.com/Jwataru/items/a8e0120dd32761d70bfa


#解決策
以下のように
walk_like_path(walk,walk.likes)というように、引数を2つ指定しました。

```
<%= link_to "いいねを解除" ,walk_like_path(walk,walk.likes),method: :delete %>  
```

実行してみると無事にいいねを削除する事ができました。

従ってエラーの原因は「ネストしているのに引数を1つしか指定しなかった」ということです。


#まとめ
　今回はいいね機能を削除する時のエラー解決をまとめました。

分かった事は**「ネストをしている場合は2つ引数を指定する必要がある」**
という事です。

ネストをした場合の削除の仕方は初見だったので、時間を使ってしまいましたが、解決できて良かったです。

今回の記事が少しでも誰かのお役に立てれば幸いです。

（参考記事↓↓）
https://qiita.com/Jwataru/items/a8e0120dd32761d70bfa
MacbookでFinderを終了させたい

## はじめに
Macbookを使っていてとても気になること、それはFinderアプリが常に起動していること。
Windowsでいうエクスプローラーの位置づけにあるFinderアプリはたしかによく使うのだが、常に起動状態にあることがモヤモヤしている人も多いのでは。
そんな問題を解決すべく方法を今回はシェアします。
一瞬です。

## Finderアプリの終了する設定

```
defaults write com.apple.Finder QuitMenuItem -bool true
```

ターミナルを開いて、上のコマンドを実行するだけです。

このコマンドを実行し、パソコンを再起動すると、Finderアプリのメニューに「Finderを終了」という項目が追加され、⌘＋QでFinderを終了できるようになります。

ちなみに以下のコマンドを実行すれば元の状態に戻ります。

```
defaults write com.apple.Finder QuitMenuItem -bool no
```

以上、Finderを終了させる方法でした。
iOS用アプリのストア掲載についての備忘録

IT業界でエンジニアの卵として働いている小生が、iOS用アプリのストア掲載について毎回手順を忘れるので備忘録として手順を記録します。今回のケースはコーディングを外注しており、それをgitで管理しそれをクローンするところから始まります。すでにAppleIDの登録やAppleDeveloperでのアプリの登録は済んでいるものとし省略します。

1. gitからリポジトリurlをクローンしXcodeで呼び出す
1. 証明書要求の作成（mac側での操作）
1. Certificate（証明書）の作成
1. プロビジョニングプロファイルの作成
1. Xcodeでのビルド
1. ストアアップロード

![iosビルド図.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1508384/117c7e14-a855-444e-7b3a-ba63b3cf4f1e.jpeg)


## 1. gitからリポジトリurlをクローンしXcodeで呼び出す
バージョン管理システムであるgitで共有された、、サーバーリポジトリをクローンし、Xcodeの「clone an existing project」から呼び出します。アプリのアップデートなどで既にローカルにサーバーリポジトリをクローンしている場合は、Xcode上部メニューから「SourceControl」→「Pull」を選択し、コミットをプルし最新の状態にする。

## 2. 証明書要求の作成
証明書要求とは、「ある成果物を小生のmacで作りましたよー」と証明してもらうために、Appleに要求するものです。この要求は、macに元々インストールされている「キーチェーンアクセス」を利用し、画面上部メニューから「キーチェーンアクセス」→「証明書アシスタント」→「認証局に証明書を要求」で行うことができます。そうするとダイアログが出るので、AppleDeveloperで使用しているメールアドレス、通称（任意の識別名）、CAのアドレス（必須となっているが未入力で大丈夫）、「ディスクに保存」を選択、「鍵ペア情報」を選択し、「Done」を選択。登録を行うと証明書要求が作成され、「CertificateSigningRequest.certSingningRequest」をダウンロードし保存。

## 3. Certicatesの作成
証明書要求が取得できたら、AppleDeveloperにて証明書を作成していきます。

- まずはAppleDeveloperにログインし、「Certificates」を選択し、「＋」をクリック。
- 「AppleDistribution」を選択し「Continue」をクリックし。
- 「Choose File....」をクリックし、2.で保存した「CertificateSigningRequest.certSingningRequest」を選択
-  「Download」をクリックし、「distribution.cer」をダウンロード
-  ダウンロードした「distribution.cer」をダブルクリックしてkeychainに保存

## 4. プロビジョニングファイルの作成
プロビジョニングファイルとは、「ある成果物を小生のmacで作りましたよー」という証明書とそれぞれのアプリに割り当てられたID（=AppID）を紐付けて生成したファイルのことです。これはXcodeでビルドを行った後にストアにアップロードする際に必要になります。作成の仕方はAppleDeveloperの「Profiles」から対象のアプリを選択し、「Edit」をクリック。「Certificates」のリストから先ほど3.で作成したCertificationsを選択。最後に「Save」をクリックし「Download」からプロビジョニングをダウンロードする。すでにXcodeがインストールされていれば、ダウンロードしたファイルをダブルクリックすると、Xcodeにプロビジョニングファイルが保存されます。この時は特にポップアップなどは出てきません。

## 5. Xcodeでのビルド
Xcode上で対象アプリを選択し、デバイスを選択する場所から「Any iOS Device」を選択。次に、中央ペインの「Signing&Capabilities」タブを開き、「automatically manage signing」のチェックを解除し、「Team」を状況に応じ選択し、「provisioning profile」に、4.で作成したものを選択。
その後、「General」タブで「build」「version」番号を入力。「version」はアプリのパージョンを表し、ストア上でユーザーに公開されるもの。「build」はストア上にアップロードされるファイルを管理するための一意の番号。
最後に上部メニューの「Product」→「Archive」からビルドを実行。ビルドが完了すると新しくウィンドウが表示されるので、その右ペインの「ValidateApp」をクリック。ダイアログは基本的にそのまま「Next」でいい気がします。完了したら続いて「DistributeApp」をクリック。こちらもそのまま「Next」でいいと思います。終了したら「AppStoreConnect」にアクセスし、アプリがアップロードできていることを確認します。

## 6.ストアアップロード
AppStoreConnectで該当のアプリ情報を開き「TestFlight」タブでアップロードされていることが確認できるかと思います。（ここはあまり詳しくないので小生とは違う状況の方もいるかもしれません。）ここでアップロードされたバージョンをクリックし「輸出コンプライアンス情報を提出」をクリックします。ここではアプリ内での通信が暗号化されているかを聞かれるので答えます。ちなみにhttps通信も暗号化に該当するようです。これ確認ができたら「AppStore」の左ペイン「iOS App」に「＋」ボタンが現れていると思うのでクリックし、ビルドの際に設定した「version」を入力します。そうすると、該当バージョンの情報を入力できるようになるので「スクリーンショット」などを入力し、右上のボタンから審査に提出をします。

これでiOSアプリのリリーズまでの流れは以上です。
下記参考にしたURLです。詳しく知りたい方は見てみてください。
[時偶ブログ](https://tokitama-blog.hatenablog.com/entry/2021/01/28/164604)
KMSまとめ

#AWS kmsについて
##kmsとは
暗号鍵の生成、管理、運用のためのサービス。
可用性、物理的セキュリティ、ハードウェアの管理はAWSが担当するマネージドサービス。
S3やEBS,RDSで使用可能。SDKを使用することでローカルのデータも暗号化できる。
鍵の使用履歴はCloudTrailに記録される。

##用語
1.CMK（Customer Master Key）
最上位の暗号鍵。最大４KBのデータを暗号化できる。

2.Envelope Encryption
マスターキーを直接暗号化に利用せず、マスターキーで暗号化した暗号キーで暗号化・複合化すること。

3.CDK(Customer Data Key)
実際にデータを暗号化する時に利用する暗号鍵。
KMSで生成されCMKで暗号化された状態で保管される。
利用時のみCMKで複合化し、アプリケーションやサービスで利用する。

4.Encryption Context
暗号化する際にKMSに渡せるKey/Valueペア。
設定した場合、複合化のために必要になる。

5.Client-Side Encryption
ユーザーアプリケーションでのデータ暗号化にSDKによってKMSを利用すること。

6.Server-Side Encryption
AWSサービスがデータを受信した時にサービス側でデータを暗号化すること。
AWSの各種サービスとインテグレーションされている。

##ベストプラクティス
1.認証と許可
IAMポリシーとキーポリシーのデザイン。鍵を利用するにはMFAを必須にするなど。

2.CloudTrail

3.パフォーマンスとサービスの制限
1秒あたりのAPIオペレーションのリクエスト数に制限あり。

4.インフラストラクチャのセキュリティ
本番環境ではCMKの利用を検討する。
データの重要性によってによって鍵を使い分ける。

5.インシデント対応の明確化と自動化
不正アクセスがあった際の鍵の無効化など。
CMKは削除すると復旧できないので、削除ではなく無効化する。
法人用のアカウントを作りました

#はじめに
この度、法人用のアカウントを作ったので
その時の気持ちを忘れないために記しておこうと思い、今記事を書いています。

#なぜ作ったか
- 社員の誰もが記事を書ける環境が欲しかった
- その場所としてqiitaが最適だろうと思った
- 会社の<b>売り上げ</b>UPに繋がるかも

というのが大きな理由になります。

#社員の誰もが記事を書ける環境が欲しかった
これは純粋に、会社に技術系の記事を書ける環境がないな〜と思っていたっていうのもありますし、社員の他の人との知見の共有がなかなか出来ていないなと思ったっていうのもあります。もちろん、Qiitaの記事を書くことをプロジェクトとしてやっている訳ではないので、なかなか記事を書き進めることはできないかもしれないですが、アカウント自体はないよりあった方がマシですし、何か共有したいなと思った時にスッと執筆できるような場所があるといいなと思って作りました。

別の角度から見てみると、新卒・転職者がQiitaを見た時にアピールになったり、会社の中の雰囲気が伝わったりすると思います。そこから興味を持ってくれる人が増えるかもしれないし、新たな戦力として採用という形にもなるかもしれません。そうすると会社の売り上げUPにも繋がると思っています。

#その場所としてqiitaが最適だろうと思った
Qiitaは、何と言っても無料ということもありますし、さらに影響力が高いといった点で最適だろと思いました。個人的な感想になりますが、記事を投稿しても数百Viewは最低でもあるなといった印象です。また、UI的にもモダンというほどのUIではないかもしれませんが、ある程度整っているという点から使い勝手は特に問題ないだろうと思っております。

#会社の売り上げUPに繋がるかも
Qiitaを見て採用に繋がったら会社の売上に繋がります。会社の売上に繋がれば会社も個人もお互いに幸せになれるwin-winになれます。これは、かなり大きな副次的なメリットになると思っています。

#これから
これからも自分のペースで記事を投稿していきたいと思っています。普段思い悩んでいることが他の人にとって解決策になることがありますし、そういった記事を投稿できたらと思っています。
elasticsearchへ出力する冪等なlogstash pipelineを構築して、重複ドキュメントを避ける

使うのはfingerprint filterと、(宛先インデックスでingest pipelineを使用する場合は)ruby filter。

# やりたいこと
ドキュメントの内容に応じたidを作成し、updateとしてelasticsearchに出力する。

# 実行環境
elasticsearch 7.16.3
logstash 7.16.3

# なぜ冪等な処理にしたいか
SQLをインプットにする場合は、公式ブログの「[LogstashおよびJDBCを使用してElasticsearchとリレーショナルデータベースの同期を維持する方法](https://www.elastic.co/jp/blog/how-to-keep-elasticsearch-synchronized-with-a-relational-database-using-logstash)」にもあるように、modification_timeというカラムを作成してその値でfilteringすることで*重複ないインデクシング*を実現できる。

一方でelasticsearchはRDBではなく、ACID特性を持たない。Ingest Nodeが複数あるような場合、インデクシングの順番が前後してしまうこともあり、modification_timeといったフィールドを用意していても漏れなくダブりなくのフィルタリングを実現するのは難しい。

## ingest pipelineを使っていない場合
```ruby
filter {
    fingerprint {
        source => ["fildA","fieldB"] #ドキュメントが一意に定まるフィールド群を指定
        concatenate_sources => true
        target => "[@metadata][_id]"
    }
}
output {
  elasticsearch {
    hosts => "host"
    user => "user"
    password => "pass"
    index => "index"
    action => "update"
    doc_as_upsert => true
    document_id => "%{[@metadata][_id]}"
  }
}
```
`doc_as_upsert`を`true`にするだけ。

## ingest pipelineを使っている場合
```ruby
filter {
    fingerprint {
        source => ["fildA","fieldB"] #ドキュメントが一意に定まるフィールド群を指定
        concatenate_sources => true
        target => "[@metadata][_id]"
    }
    ruby { # <-- ruby filterを追加
        code => "
        _doc = event.to_hash
        _doc.each{|k,v|
            event.set('[@metadata][_doc]['+k+']', v)
        }
        " # [#{k}]ではexpandされなかった。
    }
}
output {
  elasticsearch {
    hosts => "host"
    user => "user"
    password => "pass"
    index => "index"
    action => "update"
    upsert => "%{[@metadata][_doc]}"　# <-- 変更
    document_id => "%{[@metadata][_id]}"
  }
}
```

スクリプトを変えているのは、ingest pipelineを用いる場合に[doc_as_upsertを使うとupdateがうまく機能しないため](https://qiita.com/tmitani/items/b282c641e7797487504e)。

その記事に書いたように、upsertとしてdocumentと同じ内容を指定すれば良いのだが、logstashではフィールドへのアクセサが用意されているものの、ルートであるevent全体へのアクセサは見つけられなかった。このため、ruby filterで各フィールドをiterationし、全体を[@metadata][_doc]というフィールドに格納している。

公式の[Event API](https://www.elastic.co/guide/en/logstash/current/event-api.html)には載っていないのだが、"logstash event iteration"と検索してみると[こちらのトピック](https://discuss.elastic.co/t/how-to-iterate-over-all-fields-with-new-event-api/112514/2?u=tomo_m)がヒット。`event.to_hash`でハッシュに変換できることが分かり、そちらを利用している。

この方法ではドキュメント全体をコピーする分の負荷は生じる一方で、重複したoutputによりドキュメントのアップデートが生じてしまうとインデックス負荷が生じる。重複するドキュメントの割合によっては後者の方が負荷が軽いかもしれないが、versionが上がってしまうというのが何となく居心地が悪いのでlogstash側で制御する方法を検討した。

# 定期実行する場合の注意点
modification_timeのようなフィールドでフィルタリングすることになるが、登録されたドキュメントが検索可能になるまでわずかな(通常~1s)のタイムラグがあるので、その分余裕を持った期間にする必要がある。Indexing Latencyなどをモニタリングしておくと安全かもしれない。

# 他の選択肢は…？
inputする側のインデックスに、送信済みフラグを設ける方法もありそうだが、この場合も、次の実行時までに送信済みフラグが全て検索可能になるように十分に余裕をもった実行計画にする必要がある。
Webの勉強はじめてみた その26 〜Basic認証とCookie〜

N予備校「プログラミング入門Webアプリ」を受講しています。
今回は第3章18,19節です。

<h2>Basic認証</h2>
:::note
Authorization というヘッダの値に、エンコードされた ID とパスワードを含めて通信することで認証する方式
:::

暗号化されていない方式でエンコード(Base64)されているので、盗聴や改竄のリスクがある。
`atob`を使うと元の情報が見えてしまう。

<h3>http-auth</h3>
`http-auth` パッケージを利用する。
`yarn add http-auth@4.1.9`

```javascript
//Basic認証のモジュール
const auth = require('http-auth');
//basic関数
//realmプロパティに、Basic認証に保護する領域を規定する文字列 => 説明書き(認証が必要な範囲を書く)
//コールバックにユーザー名とパスワードのチェック => 認証するパターンを書く
const basic = auth.basic(
    { realm: 'Enquetes Area.'},
    (username, password, callback) =>{
      callback(username === 'guest' && password === 'xaXZJQmE');
    }
  )
 
http.createServer(basic.check((req, res) =>{}
```

`basic.check()`メソッドによって認証処理を行う。

<h3>ステータスコードとログアウト</h3>
100 番台は、処理中
200 番台は、成功
300 番台は、リダイレクト (場所が移転したため移動を促す)
400 番台は、クライアントのエラー
500 番台は、サーバーのエラー

200 - OK は、リクエストの成功
401 - Unauthorized は、アクセス権不正

```javascript
if(req.url === '/logout'){
  res.writeHead(401, {
    'Content-Type': 'text/plain; charset=utf-8'
  });
  res.end('ログアウトしました');
  return;
}
```

<h2>Cookie</h2>
:::note
Web ブラウザに情報を記録するための仕組み。有効期限を設定できる。
:::

内部的には HTTP のリクエストヘッダの Cookie という項目と、 レスポンスヘッダの Set-Cookie という項目を利用することで実現している。

<h3>Cookieの設定</h3>

```javascript
res.setHeader('Set-Cookie', `last_access=${now};expires=${limit_time}`);
```

`last_access`がキー、値が`now`
`expires`が有効期限。

<h3>Cookieの値取得</h3>

```javascript
const cookies = req.headers.cookie;
const last_access_time = cookies ? parseInt(cookies.split('last_access=')[1]) : now;
```

`last_access=`を区切り文字として`split`で配列にする。
 もし`cookies`がtrue なら `cookies`を表示、falseなら現在時刻を表示。

<h2>まとめ</h2>
PHPではCookieの他にSessionを利用したりしたけれど、Sessionはちょっとイメージしにくかった印象がある。

https://ssaits.jp/promapedia/technology/cookie-session-cache.html

Basic認証ってルーターの管理画面を覗いたりする時に使われてるくらい？今はあんまり使われてない感じかな。
【Python】乱数の生成方法

Pythonにおける乱数の生成方法をメモしておく。

#乱数の生成方法
まず、乱数を生成させるためにはPython標準ライブラリの```random```モジュールの関数を使用する。そのため、```random```モジュールをインポートする必要がある。

```python
import random
```
乱数を生成する関数のいくつかをメモしておく。

## random.random()
**0.0以上1.0未満**の浮動小数点数（float）の乱数を生成する。

```python
print(random.random())    # 0.06542510540207569
```

## random.uniform(a, b)
引数で与えられた任意の範囲で浮動小数点数（float）の乱数を生成する。

```python
print(random.uniform(10, 50))    # 11.769189644114281
```

## random.randint(a, b)
引数で与えられた任意の範囲で整数（int）の乱数を生成する。(a,bの値も含む)

```python
random.randint(10, 50)    # 39
```

##  random.seed(seed)
引数```seed```に任意の整数を指定することで、乱数生成器を初期化する関数。
同じ```seed```で初期化することで、同じ乱数値を取得できる。

```python
random.seed(1)
print(random.random())
print(random.random())

random.seed(1)
print(random.random())
print(random.random())
```
忘れがちなgitコマンド

たまに使うけど、普段はあまり使わないgitコマンドを備忘録として列挙します。
※徐々に増えると思います。

## ブランチの削除

そろそろ覚えたい。

### ローカルブランチの削除

```
git branch -D 削除対象ブランチ名
```

### リモートブランチの削除
```
$ git push --delete origin 削除対象ブランチ名
# または
$ git push origin :削除対象ブランチ名
```

## pushした内容の取り消しcommitを作成する

取り消した履歴が残るのでこちらのほうが好み

```
# 直前のコミットを打ち消すコミット
$ git revert

# 最新をふくめ、過去4つ分のコミットを打ち消す
$ git revert HEAD~3
```

参考：https://www-creators.com/archives/2020

## git pushしたことを無かったことにする

```
# 直前のcommitを取り消し
$ git reset --hard HEAD^

# 変更を無かったことにしたいbranch（ブランチ名）に強制的（ -f ）にPushする
$ git push -f origin ブランチ名

# リモートの ブランチ名 参照を強制に戻す
$ git push -f origin 8dj2dg:ブランチ名
```

指定したcommitハッシュにブランチを移動することもできるんですね。

参考：https://www-creators.com/archives/2020
参考：https://qiita.com/jun_kato/items/742503d40eb3afc26448

## リポジトリの引っ越し（移行）

```
# 今のリポジトリ先を確認する
$ git remote -r

# 新しいリポジトリに変更する
$ git remote set-url origin 新しいリポジトリURL

# 新しいリポジトリにpushする
$ git push -u origin master
```

この後、git branch -a をすると古いリポジトリのリモートブランチも出てきます。
これをクリアする方法がわかっていません。
リモートブランチ削除コマンドを投げても（当然ですが）そんなブランチは存在しない。というエラーが返ってくるだけ。。。
何をしたら消えてくれるかご存じの方がいたら教えていただきたいです。
わかったら追記します。

## ローカルリポジトリのリネーム

```
$ git branch -m <古いブランチ名> <新しいブランチ名>
```
今のブランチをリネームする場合はこちら
```
$ git branch -m <新しいブランチ名>
```
ローカル仮想マシン開発時のプロキシ設定

## はじめに
会社によってまちまちだと思いますが、
社内→社外の通信時に社内プロキシサーバーを経由してアクセスするように設定されていることがあります。主にWebフィルタリングや監査の関係です。

大学や家の環境ならうまくいくのに！っていう時にいろいろ躓いたところなので
これからエンジニアになる方の助けになればと。
今回はWindows + Docker + GitでLAMP環境を構築した体で書いています。

## プロキシとは何か
会社PCから外部に向けての通信を
プロキシと呼ばれる仕組みを通すことにより、危ない通信・怪しい通信をしていないかを確認します。

プロキシサーバーはWebフィルタリングや通信監査などの目的で導入されていることが多いです。例えば、会社PCを使ってフィッシングサイトやマルウェア感染の危険があるWebページへのアクセスを制限したり、アダルトなサイトにアクセスできなくしたり、Webゲームをしてサボったりなんかもできなくなっているわけです。

このプロキシサーバーですが、通常の業務レベルでは困ることは無いのですが、
ローカルPCに建てた仮想マシン環境からの通信についてもプロキシサーバーを経由するように設定しないと
通信がコケることがあるので、基本的な設定方法をまとめておきます。

## プロキシサーバー接続文字列
基本的には下記のような感じ

```bash
http://[プロキシのドメイン]:[ポート番号]
```
例) http://proxy.hoge.com:8080

認証ありプロキシの場合は下記

```bash
http://[ユーザー名]:[パスワード]@[プロキシのドメイン]:[ポート番号]
```

## 各環境毎の設定方法
### Linuxサーバー
環境変数で設定可能

```bash
export http_proxy="[プロキシサーバー接続文字列]"
export https_proxy="[プロキシサーバー接続文字列]"
```

### php
環境変数をphpのputenvからも設定可能

```php
putenv("HTTP_PROXY=[プロキシサーバー接続文字列]");
putenv("HTTPS_PROXY=[プロキシサーバー接続文字列]");
```

### git
gitbash等のコマンドラインから設定

```
git config --global http.proxy "プロキシサーバー接続文字列"
git config --global https.proxy "プロキシサーバー接続文字列"
```

### Docker Desktop (Windows)
設定メニューの「Resources > PROXIES」から設定可能

## 証明書関連のエラーが出る場合
プロキシサーバーで、https通信を複合化を行っている場合、
証明書関連のエラーが発生する場合があります。
この場合は、証明書エラーを無視する設定を入れるか、ネットワーク管理者に相談してください。
Windows10のbashを使ってLinuxサーバへssh

WindowsPCからLinuxサーバにsshで接続しました。
Macからであればこれまでログインしていましたが、今回初めてWindowsから試行しました。

コマンドプロンプトからbashを起動して、ログインはできるのですが、下記のメッセージが表示されます。

```
-bash: warning: setlocale: LC_CTYPE: cannot change locale (C.UTF-8): No such file or directory
```

同じサーバにMacからのssh接続は問題ありません。
ということで、原因は初めて使ったWindows上のLinux環境に問題があると考えました。

で、試したことはこれです。

下記コマンドで、コマンドの出力を日本語に変更。

```
hoge@DESKTOP-0OQ0IAC:~$ sudo apt install language-pack-ja
```

続いて「locale」を更新。

```
hoge@DESKTOP-0OQ0IAC:~$ sudo update-locale LANG=ja_JP.UTF-8
```
一度、bashをとコマンドプロンプトを閉じて起動します。
LANG変数を確認し、dateコマンドを実行して日本語表示するかを確認するとこうなります。

```
hoge@DESKTOP-0OQ0IAC:~$ echo $LANG
ja_JP.UTF-8
C:\Users\hoge>bash
hoge@DESKTOP-0OQ0IAC:/mnt/c/Users/hoge$ cd
hoge@DESKTOP-0OQ0IAC:~$ date
2022年  1月 26日 水曜日 15:40:47 JST
```

Macの時は秘密鍵のパスフレーズを覚えてくれたのですが、Linuxなので覚えてくれないようです。
（これまでは sshコマンドに-Aオプションを付けて鍵を渡していました）
覚えさせるには.bashrcの最後に下記を追加して、

```
# Setup ssh-agent
if [ -f ~/.ssh-agent ]; then
. ~/.ssh-agent
fi
if [ -z "$SSH_AGENT_PID" ] || ! kill -0 $SSH_AGENT_PID; then
ssh-agent > ~/.ssh-agent
. ~/.ssh-agent
fi
ssh-add -l >& /dev/null || ssh-add
```
再度bashを起動するとパスフレーズの入力を要求されて、そこへ入力するとsshコマンドでは秘密鍵のパスフレーズの入力は不要になりました。
メモ：Windows10をテザリング親機にする

LTE付Surfaceと、MacBookProを持っている際に、Surfaceを親機にしてネット接続をする、という想定。
（スマホはAhamoで、Surfaceは必要な場合だけPovo2の1日使い放題を利用している）

# 親機設定

## 事前準備
Windows設定のネットワークとインターネットの部分から「モバイルホットスポット」を選択することで接続名やパスワードを設定可能。
Wifiアイコンのホットスポットを右クリックでも設定は出せる。
（別のデバイスからのONは必要ない場合は切っておけばよい）

![2022-01-26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2081290/675f6491-d946-6992-cc75-d39ea7877222.png)

## 機能をON
Wifiアイコンから接続を開いて、「モバイルホットスポット」をONにする。

# 子機側
普通にWifiから選択してパスワードを入れる事で利用可能。

親機のネットワーク接続がWifiでも特に問題なくつながるので、
ルーターの性能が低くて接続可能台数が限られているとか、
両方でフリーWifi登録するのが面倒だという場合でも一応使える。
[py2rb] multiprocessing

# はじめに
移植やってます。
( from python 3.7 to ruby 2.7 )
# multiprocessing (Python)
```python
import multiprocessing as mp

try:
    _NPROC = mp.cpu_count()
except NotImplementedError:
    _NPROC = 4
```
https://docs.python.org/ja/3.7/library/multiprocessing.html

`並列処理`を移植するって、完全に力不足。
# どうする (Ruby)
```ruby
require 'etc'
p Etc.nprocessors #=> 4
```
いや、cpuのコア数を数えるくらいならできますけど。

https://docs.ruby-lang.org/ja/latest/method/Etc/m/nprocessors.html
# メモ
+ Python の multiprocessing を学習した
+ 百里を行く者は九十里を半ばとす
railsでmodelのscopeの実行結果をキャッシュしたかった話

問題
-
policies(規約)テーブル

|field  |type   |
|-------|-------|
|id     |int(11)|
|version|int(11)|



最新の規約バージョンがほしい、
つまりpoliciesテーブルのレコードの中のversionカラムの最大値を取得したい場合を想定します。

以下のようにscopeを定義し実行することで取得できます。

```policy.rb
class Policy < ApplicationRecord
  scope :latest_version -> { maximum(:version) }
end
```
:::note warn
2022/9 追記です。記事の本筋とは関係ないですが、こちらはscopeの使い方として正しくない事に気づいたので注意してください。scopeは`ActiveRecord::Relation`が戻り値になるようにするべきです。[参考](https://qiita.com/Seiga/items/e71e9497a395fe61102f#scope%E3%81%AE%E6%88%BB%E3%82%8A%E5%80%A4%E3%81%A8%E3%81%97%E3%81%A6%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%E3%81%AE%E3%81%AFactiverecordrelation%E3%81%A0%E3%81%91%E3%81%AB%E3%81%99%E3%81%B9%E3%81%8D)
:::

```ruby
Policy.latest_version #=> 10

# もちろんscopeを定義せずに直接実行してもよいです
Policy.maximum(:version) # => 10
```

ここで懸念が発生しました。
もし頻繁に`Policy.latest_version`を使用したい場合、いちいちDBへ検索をかけてしまうことになります。
(ひとつのメソッド内であれば実行結果を変数に格納しておけばよいですが、いろんな場所で使うケースですね）

皆さんならこのような時どうしますか？



結論
-
このままで良い

Railsには`SQLキャッシュ`という機能があり、以前と同じクエリが発生すると、データベースへクエリを実行する代わりに、キャッシュされたデータを利用します。
参考: [Railsガイド](https://railsguides.jp/caching_with_rails.html#sql%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5)

例えば`Policy.latest_version`を５回実行した場合の、ログは以下のようになります。

```
(5.3ms) SELECT MAX("policies"."version") FROM "policies"
CACHE (0.1ms) SELECT MAX("policies"."version") FROM "policies"
CACHE (0.1ms) SELECT MAX("policies"."version") FROM "policies"
CACHE (0.1ms) SELECT MAX("policies"."version") FROM "policies"
CACHE (0.1ms) SELECT MAX("policies"."version") FROM "policies"
```
１回目だけDBに実際に検索をかけていますが、それ以降はキャッシュを利用していることがわかります。
行頭にCACHEとついている場合は、SQLキャッシュ機能が使用されDBに検索をかけずにキャッシュからデータを取得します。
実際に処理時間が減っていることが確認できるかと思います。(5.3ms => 0.1ms)

念の為、誤解のないように補足します。
キャッシュが利用されるのは同じクエリであることが条件で、scopeを使用することが条件ではありません。当然ですが以下でも問題なくキャッシュからデータを取得します。

```ruby
Policy.maximum(:version)
# CACHE (0.1ms) SELECT MAX("policies"."version") FROM "policies"
```
ただし条件つき
-
SQLキャッシュが共有されるのは、あくまで１つのHTTPリクエストに対するアクションの範囲内です。
> アクションの開始時に作成され、アクションの終了時に破棄されるので、キャッシュはアクションの実行中しか保持されないという点です。
[Railsガイド](https://railsguides.jp/caching_with_rails.html#sql%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5)




その他の手段
-
クラスインスタンス変数にキャッシュするという手段もあります。

```policy.rb
class Policy < ApplicationRecord
  def self.latest_version
    @latest_version ||= maximum(:version)
  end
end
```
ただし本番サーバでは、クラスはサーバ起動時に作られてそれっきりです。
したがって、一度`@latest_version`変数にデータが格納されると、その後にDB側の規約最新バージョンが更新されても、クラスインスタンス変数は更新されません。
次にクラスインスタンス変数がリセットされるのは、サーバ再作成を伴うデプロイ処理時ということになるので注意が必要です。

お気づきの点がありましたら、ご気軽にご指摘ください。
【Unity2021】VRアプリ動作中にPCモニターから別カメラの映像を表示する方法

# はじめに
VRのプレイヤーと異なる視点でアプリケーションの画面をモニターから見たい場合や、
VRHMDの標準機能としてVRアプリケーション中の画面をモニターにキャストすると画角が狭くなるので、もう少し広角の映像を流したい。
上記のようなケースではシーン上にCenterEyeCamera(BothEyeカメラ)とは別途カメラの配置及び、設定が必要となります。

今回、Unity2020から設定方法が変わった（Cameraコンポーネントのプロパティ名が変わった）ので、備忘録として記録します。

# Unity2020以降の場合

Cameraをシーンに配置し、次の設定を行う。

1. PriorityをCenterEyeCameraの値より大きい値に設定する。
1. TargetDisplayをCenterEyeCameraと同じ値に設定する。
1. TargetEyeをNoneに設定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336886/2a2c79a9-1914-ed1d-8cae-27c43d9db6c1.png)
 

# Unity2019以前の場合

1. DepthをCenterEyeCameraの値より大きい値に設定する。
1. TargetDisplayをCenterEyeCameraと同じ値に設定する。
1. TargetEyeをNoneに設定する。
C# の Invoke, delegate の話の抽象化

どうしても C# の Invoke, delegate の解説記事がうまく理解できないので、ゆっくり咀嚼しつつ自分なりの抽象化を試します。
ちゃんと C# を勉強しないまま使わざるを得ないので、試行錯誤の過程でこういうことになるのです...

## delegate とは
関数ポインタ型 のようなもの
なので実体を作らないと使えない。
実体を作るときのコンストラクタには、実行したい関数のポインタを指定する。（つまり関数名を書く）

delegate の宣言の形は
`delegate 実行したい関数の戻り値型 デリゲートの名前( 実行したい関数と同じ引数 )`
という感じ。ただ戻り値がどこに戻るのかよくわからない。つまり受け取り方がよくわからない。むむむ。後で勉強しよう。

## Invoke とは
関数ポインタを別スレッドに投げること。
コントロールのメソッドである Invoke は、そのコントロールの属するスレッドで投げられた関数を実行する。

引数には
1. デリゲートの実体
1. 実行したい関数への引数

を渡す。実行したい関数への引数がややこしいが、複数個の引数を羅列した object 配列を塊として渡す。
塊の作り方は

```cs
new object[]{ param1, param2, ...}
```

## 雛形

``` cs
delegate void DELEGATENAME( T1 param1, T2 param2 );
void FUNCTIONNAME( T1 param1, T2 param2 )
{
}


// 別のスレッドで実行されている関数
void OTHER_THREAD_FUNCTION()
{

  DELEGATENAME dINSTANCE = new DELEGATENAME( FUNCTIONNAME );
  oneObject.Invoke( dINSTANCE, new object[]{ param1, param2 } );

}
```

こんなところでしょうか。
[Android] 古いバージョンのRoomを使用した時に出るビルドエラーを解消する（M1 Mac）

## はじめに

M1 MacでAndroid開発をする際、ライブラリのバージョンが古かったりすると問題が起こるケースがあります。

ここでは、その内のひとつの内容・解決方法をご紹介します。

私が問題に遭遇した時は日本語での情報が少なく、解決に苦労したということもあり、ここに残しておこうと思います。

## 開発環境

PC : M1 MacBook Air(2020) 16GB OS:Big Sur
AndroidStudio : ArcticFox arm64 (2020.3.1 patch3)

Room 2.2.5

## なにが起きたか

Androidアプリ開発で使用される、ライブラリ`Room`のビルドが出来ない

#### ビルド時のエラーメッセージ

```
Execution failed for task ':app:kaptDevelopmentDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
   > java.lang.reflect.InvocationTargetException (no error message)
```

stacktraceにて、詳細を確認

```
Caused by: java.lang.Exception: No native library is found for os.name=Mac and os.arch=aarch64. path=/org/sqlite/native/Mac/aarch64
	at org.sqlite.SQLiteJDBCLoader.loadSQLiteNativeLibrary(SQLiteJDBCLoader.java:333)
	at org.sqlite.SQLiteJDBCLoader.initialize(SQLiteJDBCLoader.java:64)
	at androidx.room.verifier.DatabaseVerifier.<clinit>(DatabaseVerifier.kt:68)
```

## エラー解消方法①(推奨)

Roomのバージョンを`2.4.0-alpha03`以上にする
これで解消します。

が、おいそれと変更できない状況であれば、以下②で。

## エラー解消方法②

build.gradleの、Roomの設定に１行追記する

```App.build.gradle
dependencies {
// 省略
    def room_version = "2.2.5"
    kapt "org.xerial:sqlite-jdbc:3.34.0" // この１行を追記
    implementation "androidx.room:room-runtime:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
}
```

上記で解消しない場合は以下で対応

```Project.build.gradle
allprojects {
    configurations.all {
        resolutionStrategy {
            force 'org.xerial:sqlite-jdbc:3.34.0'
        }
    }
}
```


## 原因はなんなのか

エラー文から分かるように、SQLiteJDBCLoaderで問題があるようです。


 **jbdcのgithubに上がっているissue**
[java.lang.StringIndexOutOfBoundsException exception for Android Studio Arctic Fox (stable build) with Apple M1 ARM](https://github.com/xerial/sqlite-jdbc/issues/638)

どうやらRoomで使用されているsqlite-jdbcが、arm版ではバグを吐いてしまうようです。
sqlite-jdbcとは、JavaでSQLiteを使用する際に必要なドライバ(ライブラリ)です。だいぶざっくりですが...


解決にはここを参考にさせて頂きました。
**IssueTracker(google)**
[Build failed on Apple M1 with JDK8-arm64
](https://issuetracker.google.com/issues/174695268?hl=ja)

`Roomのバージョンを2.4.0-alpha03以上にする` 、 `sqlite-jdbcのバージョン3.34.0を使用する`　といった方法で問題を回避できると言っています。
公式で本バク対応をしてくれており、2.4.0-alpha03で解消されています。

当時はsqlite-jdbc:3.36.0.1が最新だったので、バージョンを落として使いましょうということですね。


## 公式アプデきた

2021/12/15
https://developer.android.com/jetpack/androidx/releases/room?hl=ja#2.4.0

安定版リリースやったね！ばんざい！
PyDriveでGoogle Driveにアクセスしていーく（Windows 10、Python3.6）

# はじめに
PyDriveを使ってGoogle Driveにアクセスしていくー

# 開発環境
- Windows 10 PC
- Python 3.6

# 実装
1．ライブラリをインストール

~~~
conda activate py36
pip install PyDrive
~~~

2．Google Drive APIの有効化
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/041b6615-df31-b023-5ce9-748389bfd94f.png)

3．認証情報からOAuth 2.0 クライアント IDを作成。
client_secret_xxxx-yyyy.apps.googleusercontent.com.jsonをダウンロード。

4．settings.yamlを作成

~~~settings.yaml
client_config_file: client_secret_xxxx.json
save_credentials: True
save_credentials_backend: file
save_credentials_file: saved_credentials.json
get_refresh_token: True
~~~

5．下記プログラムを実行

~~~test.py
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

gauth = GoogleAuth()
drive = GoogleDrive(gauth)

file = drive.CreateFile({'title' : 'test.txt',
            'parents' : [{'id' : 'xxxx'}]})
file.SetContentString("Hello World !\n")
file.Upload()
~~~

※parentsのidにはgoogle driveのfoldersのidを入れる
https://drive.google.com/drive/u/0/folders/xxxx

6．初回のみGoogleの認証が出るので許可する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/729a4a78-aa5c-8ab8-1b74-d310624be8e3.png)

7．指定したフォルダにファイルが作成されていたら成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/9ca2e1ff-fb8d-9306-a0a3-0d5aba48c58c.png)

お疲れ様でした。