OmniAICreator/Qiita-1.07M huggingface dataset:
ウェブカムにLUTを適用してみる

ウェブカムからの入力画像は、仮にミラーレスなどで高画質化しても、どうしても色見はのっぺりとした普通のビデオカメラっぽい色になる。
しかし、映画などの映像制作の分野では、カラーグレーディングなどと呼ばれるプロセスで、動画の色を修正し、味のある映像を作り出す。
これを、ウェブカムからのリアルタイム画像にも適用してみたい。

検索してみたところ、OBSを使うと、LUTを適用できるようだ。
だが、OBSは機能がたくさんありすぎ、ちょっとおおげさな気がしていて、それ以外の選択肢を調べてみた。
# CamTwistからLUTを使う
CamTwistはすでに更新が停止しているようだが、基本的な機能だけであれば、十分にまだ使える。
http://camtwiststudio.com/
と、思ったが、今満たらWebページが消えているようだ（汗）。

以下から、CamTwist 3.4.3をまだダウンロードできるようだ。今のうちにダウンロードしておいた方がいいかもしれない。
https://web.archive.org/web/20200828110537/http://camtwiststudio.com/
https://web.archive.org/web/20200616052747/http://camtwiststudio.com/download/
https://web.archive.org/web/20200616052747/http://camtwiststudio.com/beta/CamTwist_3.4.3.dmg

さて、CamTwistにもプラグイン機能がある。
このプラグインが、`.qtz`という拡張子で、つまりQuartz Composerのパッチのようである。
このQuartz Composerもディスコンなんですよね（汗）。もう消えゆく運命なんだな。

それはともかく、今はまだ動くので、これを使ってみよう。
以下の、CamTwist-LUTから、ダウンロードする。
https://github.com/Yak86/CamTwist-LUT

`LUT.qtz`だけあればプラグインとして動くのだが、サンプルのLUTファイルも重要なので、まずはgit cloneで全てを取得する。

    % cd ~/dev
    % git clone https://github.com/Yak86/CamTwist-LUT.git
次に、LUT.qtzをCamTwistのEffectsに追加する。

    % cd CamTwist-LUT
    % sudo cp LUT.qtz /Applications/CamTwist/Effects
- CamTwistを起動する。
- 「Step 1: Video Sources」から「Webcam」を選択してダブルクリック。Setting→Cameraで「FaceTime HDカメラ」を選択する。
- View→Previewよりプレビュー画面を出し、どのように見えるかを確認しつつ進める。
- 「Step 2: Select some effects」に「LUT」が出現しているはず。これを選択してダブルクリック。
- 「Settings」の「LUT_PNG_File」のところに、希望するLUTのPNGファイルをドラッグ&ドロップする。まずは、`~/dev/CamTwist-LUT/Sample LUT PNGs/BlueTrace.png`を試しに選んでみよう。このファイルをD&Dする。
- 次に、その画像の下の「Intensity」を右にドラッグして「1」にする。
- これで、カメラ画像にLUTが適用された状態になっている。`BlueTrace.png`を選んだ理由は、ほぼ白黒画像になるため、わかりやすいからだ。他のPNGファイルも試してみよう。

## はまった点
いくつか細々とはまった点がある。

- Webcamなどを選んでから、ダブルクリックする必要がある。シングルクリックではだめみたい。
- LUTを選択してから、Intensityを1にしないと、適用されない。なぜ最初から1にしておかないのだろうか。

# Gammmaを適用する
実際にいくつかのPNGを選んでみると、画面が暗すぎることが多いことに気がつくだろう。もともとカラーグレーディングは、明るすぎる画面を暗くすることが多いため、これは理解はできるのだが、あまりに暗すぎる。
そこで、画面にガンマカーブを適用して、元画像を明るくする。

- まず「Step 3: Adjust settings」の「LUT」の左の「×」を押して、消す。
- 「Step 2: Select some effects」から「Gamma Adjust」をダブルクリックする。
- 「Settings」から「Amonunt」を「0」にすると、かなり画面が明るくなる。
- そして、再度「Step 2: Select some effects」から「LUT」をダブルクリックして追加。
- 「Intensity」を「1」にする。
このようにすると、さきほどとは違ってベースが明るいため、適切なカラーグレーディングになっているようだ。
（おそらく、この明るさが適切なのだと思われる。元はあまりに暗すぎるため。）

課題としては、ここではPNGファイルによるLUTしか適用できない。
現在の業界標準の「`.CUBE`」ファイルなどは読み込むことができない。
これを読み込めるようにすることも検討したが、それをするなら、OBSを使えばいいのではないかと思うようになった。

とりあえず、LUTを使ってみることはできるようになった。

done!
expo startをしてもQRコードが出てこない、Starting Webpackしてしまう、UnhandledPromiseRejectionWarningとなってしまう場合

タイトルの通りなのですが、expo startをした際に、いつもであればQRコードがでてきてアプリがスタートしてくれるのですが、QRコードが出てこない。さらになんか自動的にWebpackサーバーがスタートしてしまう。エラー文章を見るとUnhandledPromiseRejectionWarningというエラーが出ている。

1日中悩んでいたのですが、以下の記事のとある部分に重要なことが書かれていました。
[expoによるReact Nativeのおさらい（最低限）](https://qiita.com/zaburo/items/b47bfe27d0b8910a1488)

>なぜか再度npm installしないと使えません。。。

どうやら、expoではパッケージをnpm install でいれた場合、もう一度

```
npm install
```

をしないといけないようです。理由は調べてみましたが、イマイチわかりませんでした。。
→もしわかる方いたらコメントしていただけると幸いです。

これによってアプリの動作が非常におかしくなってしまったので、同じようなエラーで悩んでいる方の助けになれば幸いです。

また、ミスや僕の勘違いがありましたらご指摘いただけると大変ありがたいです！
LaravelでVue.jsを使う

# 目次
Laravelの記事一覧は下記
[PHPフレームワークLaravelの使い方](https://qiita.com/toontoon/items/c4d0371e504c37f6576e)

# Laravelバージョン
動作確認はLaravel Framework 7.19.1で行っています

# 前提条件
[eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)](https://qiita.com/toontoon/items/76fa7f8845b20776077c)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています

[LaravelでJavaScript、CSSを使う](https://qiita.com/toontoon/items/6d7c88bc96bfa8fcb53a)
本記事は上記が完了している前提で書かれています

#Vue.jsを使う準備
[Laravelの認証(web画面)](https://qiita.com/toontoon/items/34c871da8660e7d7c075)
を実行した人はもう準備が済んでいます
上記記事で行った
`composer require laravel/ui`
`php artisan ui vue --auth`
でVue.jsを使うのに必要なものがインストールされていました
やってない人は
`composer require laravel/ui`
`php artisan ui vue`
`npm install`
をしましょう
package.jsonを見てみるとvueが追加されているはずです

# コンポーネント作成
 /sample/resources/js/components/Sample.vue作成

```Sample.vue
<template>
  <div>
    <div>{{ message }}</div>
  </div>
</template>


<script>
export default {
  props: {
	  message: {title: String, default: 'hello world'}
  }
}
</script>
```

# コンポーネント登録
 /sample/resources/js/app.jsに
`Vue.component('sample', require('./components/Sample.vue').default);`
を追記

```app.js
‥‥
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('sample', require('./components/Sample.vue').default);
‥‥

```
app.jsを見ると`Vue.component('example-component', require('./components/ExampleComponent.vue').default);`が既に書かれていたと思います。また、resources/js/components/ExampleComponent.vueが既に存在していたはずです
Laravelでは事前にapp.jsにVue.jsを使う準備ができており、開発者はそこにVue.jsのグローバルコンポーネントを登録すれば使えるようになっています

# Controllerにメソッド追加
(1) /sample/app/Http/Controllers/SampleController.phpにvueメソッドを追記

```
    public function vue()
    {
        return view('sample.vue');
    }
```

(2) /sample/routes/web.phpに下記を追記
`Route::get('sample/vue', 'SampleController@vue');`

# viewの作成
/sample/resources/views/sample/vue.blade.phpファイル作成

```vue.blade.php
<html>
    <head>
        <title>sample</title>
        <script src="{{ asset('js/app.js') }}" defer></script>
    </head>
    <body>
        <div id="app">
            <sample />
        </div>
    </body>
</html>
```
#JavaScriptビルド実行
コマンドラインで
`cd sample`
`npm run dev`

# 動作確認
`http://localhost/laravelSample/sample/vue`

実行結果

```
hello world
```
PGP暗号化メールを一括で復号する

## 背景

とある事情でEnigMail(ThunderBird)のユーザーだった。
が、先日、PGP暗号化メールのdecrypted copyを一括で作ることになった。
単一復号化は、メールを右クリックして「Decrypt to folder」で行えるが、一括復号化は、メールフィルタの「If OpenPGP encrypted, create decrypted copy」で行わねばならない。しかし、私の環境ではなぜかフィルタがうごかなかった。
ところで、右クリックでの復号に微細な不具合が見受けられたので、修正を試みた。それが https://gitlab.com/enigmail/enigmail/-/merge_requests/47 である。その過程で https://gitlab.com/enigmail/enigmail/blob/enigmail-2.1-branch/package/persistentCrypto.jsm を調査していたのだが、実は復号処理は簡単なのではないかと思ったので実装を試みた。

## 方法

### 言語

最近最も触っている言語であり、またメールパーサーが標準ライブラリに存在することもあり、Pythonを選択[^1]。

### IMAP

EnigMailはThunderBirdの機能拡張だが、本ツールはスタンドアローンで動作する都合上、IMAPアクセスが必須となる。これは https://docs.python.org/ja/3/library/imaplib.html#imap4-example をほぼ丸写しで良い。

### メール

#### 復号エンジン

デファクトスタンダードとして、GnuPGとした。GnuPGは外部プログラムなので、subprocessモジュールを必要とする。ところが、subprocess.Popenにはコンテキストマネージャがない。そこで、(コード)ブロック中に例外発生時にはプロセスを停止させるようなPopenラッパーを作成した。

#### 通常の暗号化

本文を`gpg --decrypt --skip-verify`に流せば良い(検証結果に関わらず復号はされてほしいので--skip-verifyは必須である)。マルチパートの場合は1パートごとに。ただし、Content-Transfer-Encodingが指定されている場合は事前に処理する必要がある。base64.b64decodeやquopri.decodestringを用いる。
(中身が始めからエンコードされている場合あるいは)中身にマルチバイト文字が含まれる場合はエンコードする必要がある。このエンコードはEnigMailにならいBase64を72文字ごとに改行する実装としたが、末端のみ72文字未満でも改行する必要がある(A)。
添付ファイルのファイル名取り出しだが、PGPには、ファイル名を暗号化ファイルに埋め込む機能があるらしい(?)。GnuPGは`--enable-special-filenames`なるオプションで、`-&N`なるファイル名が埋め込まれることがあるので、この形式のファイル名が来た場合は無視する必要がある(B)。ただし今回作成したツールでは埋め込みファイル名ではなく常にContent-Disposition filenameを使うのでこの影響はない。
なお、この(A)および(B)がEnigMailの「微細な不具合」の内容である。

#### PGP/MIME

MIME partの1番目がバージョン情報(常に1)、2番目が実体メール(ただしヘッダは含まない)となっている。よって、「実体メール」にヘッダをコピーして返すようにすれば良い。

#### 件名暗号化

PGP/MIMEは実体メールにヘッダは含まないと書いたが、EnigMailの件名暗号化は実体メールにsubjectヘッダを入力することで実装されている。よって、実体メールにヘッダをコピーする際、すでに存在しているヘッダは単にコピーしないようにすれば良い。

## 結果

https://github.com/cielavenir/imap_mass_decrypter/blob/master/imap_decrypter.py により、無事に一括復号化することができた(pypiは利用していない)。しかもメールフィルタはフィルタを掛けるフォルダを1つずつ指定する必要があるが、こちらであれば全フォルダを一度に対象にできる。

[^1]: Rubyだとmail gemとかを使うことになると思いますが、標準ライブラリではない
さようならFirefox Send。あなたは私のT4gインスタンスの中で永遠に生き続けます!!

とても便利な`Firefox Send`ですが、残念ながらサービスの停止が発表されました。

[Mozilla、「Firefox Send」の再開を断念 ～無償のファイル送信サービス - 窓の杜](https://forest.watch.impress.co.jp/docs/news/1277879.html)
[Update on Firefox Send and Firefox Notes - The Mozilla Blog](https://blog.mozilla.org/blog/2020/09/17/update-on-firefox-send-and-firefox-notes/)

停止の発表とともにすでにサービス停止済みで https://send.firefox.com/ にアクセスしてもmozillaのトップページに転送されます。

Firefox SendのソースコードはGitHubでオープンソースで公開されていますので、そちらを起動してみましょう。

Docker Composeを使いますが、

> We don't recommend using docker-compose for production.

だそうですのでお気をつけください。

---

よろしければ、ご自由にどうぞ。
https://send.moritalous.tk/

---

独自ドメイン化とSSLについて以下で続きを書きました。
[意外と簡単！EC2上のWebアプリを独自ドメイン化＆SSL化](https://qiita.com/moritalous/items/2baf4a47f53c740d38e4)

# 環境

丁度いいタイミングでAWSからt4g.microインスタンスの年内無料トライアルが発表されたため、こちらを使用してみます。

[新しい EC2 T4g インスタンス – AWS Graviton2 によるバースト可能なパフォーマンス – 無料で利用可能 | Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/new-t4g-instances-burstable-performance-powered-by-aws-graviton2/)

# 構築

## Docker

```bash
sudo amazon-linux-extras install -y docker
```

sudoなしでdockerコマンドが使えるようになるおまじない

```bash
sudo groupadd docker
sudo usermod -aG docker $USER
```

Dockerサービス起動

```bash
sudo systemctl enable docker
sudo systemctl start docker
```


## Docker Compose

ちょっと面倒ですが

```bash
sudo yum install -y python3 python3-devel libffi-devel openssl-devel gcc make
sudo pip3 install docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/
```

## Git

```bash
sudo yum install -y git
```

環境構築は以上です。

# アプリケーションデプロイ

## ソースの取得

```bash
git clone https://github.com/mozilla/send.git
```

ちなみに2020/09/20時点で、リポジトリはすでに`Archived`状態になっています。

## docker-compose.ymlの修正

2点、変更します。

* selenium-firefoxの削除

```diff:docker-compose.yml
-  selenium-firefox:
-    image: b4handjr/selenium-firefox
-    ports:
-      - "${VNC_PORT:-5900}:5900"
-    shm_size: 2g
-    volumes:
-      - .:/code
```

* Firefox Account不要化

このままdocker-composeすると起動はするのですが、ファイルのアップロードが失敗します。結構ハマったのですが、[Issue](https://github.com/mozilla/send/issues/1513)を参考に、Firefox Accountを不要化することで解消します。

```diff:docker-compose.yml
     environment:
       - REDIS_HOST=redis
+      - FXA_REQUIRED=false
```

修正後はこんな感じ

```yaml:docker-compose.yml
version: "3"
services:
  web:
    build: .
    links:
      - redis
    ports:
      - "1443:1443"
    environment:
      - REDIS_HOST=redis
      - FXA_REQUIRED=false
  redis:
    image: redis:alpine
```

## docker-compose up

Docker Imageのビルドが始まり、しばらくすると起動します。

```bash
docker-compose up -d
```

`http://[EC2のパブリックIP]:1443`でFirefox Sendが無事起動します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/59e23763-361f-bbcd-95b8-8cf10f121956.png)

ファイルを登録して

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/2fd47880-262f-38e3-7054-74fe42652a75.png)

アップロード！！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/bf308b3b-dcdb-87e6-d52d-85f1eeeb3953.png)

発行されたリンクをクリックしてダウンロードできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/be2f5b9b-8b34-7776-82c7-93cf38c08cf1.png)

自分用にはこれでなんとかなりそうです。

いいサービスだったのに、残念ですねぇ。。
Google Spreadsheet で式を文字列化しそれに正規表現をかけて部分を取り出す方法

## 式

```
=VLOOKUP(1,IMPORTRANGE("SPREADSHEET_ID","A:B"),2,FALSE)
```

## 文字列化

```
=FORMULATEXT(A1)
```

## 正規表現で SPREADSHEET_ID を抜き出す

re2 なので double quote の escape は ```""``` ですね。

```
=REGEXEXTRACT(A2,"""(.*?)""")
```
PHPで変数を使う

PHPで変数を用いる方法を解説

1<?php $sum = 100+1050+200; ?>

(1の説明)$sumに計算したいものを入れます(PHPでは変数にドル記号を用いる)


2合計金額は:<?php print($sum); ?>円です

(2の説明)合計金額は1の時に$に入れた計算式をprint($sum)で呼び出す


3税込価格は:<?php print($sum*1.10); ?>円です

(3の説明)税込金額ではprint($sumに1.1０をかけるアスタリスク*を用いる)


上記の結果はブラウザで以下のようになる

合計金額は:1350円です
税込価格は:1485円です
【javascript】TABLEセル内のテキストデータを二次元配列で全取得（colspan/rowspan対応）

何かあればご指摘いただけると助かります。

#概要

|head1|head2|haed3|head4|head5|
|:--:|:--:|:--:|:--:|:--:|
|1-1|1-2|1-3|1-4|1-5|
|2-1|2-2|2-3|2-4|2-5|
|3-1|3-2|3-3|3-4|3-5|

こんな感じのテーブルを

```javascript
[
	['head1','head2', 'haed3', 'head4', 'head5'],
	['1-1', '1-2', '1-3', '1-4', '1-5'],
	['2-1', '2-2', '2-3', '2-4', '2-5'],
	['3-1', '3-2', '3-3', '3-4', '3-5']
]
```

二次元配列として取得します。
結合されたセルに対しては、結合元と同じテキストで埋めます。

#コード

```javascript:
const getTableTexts = table => {
	const tableTexts = [];
	
	const tableRows = table.rows;
	//行数
	const numOfRows = tableRows.length;
	//列数（1行目参照）
	const numOfCols = [...tableRows[0].cells].reduce( (n, cell) => n + (cell.colSpan-0), 0);
	
	//rowspan管理用
	const rowspans = Array(numOfCols).fill(0);
	
	const getLineTexts = lineIdx => {
		const lineTexts = [];
		
		//colspan分の穴埋め　＋　行を配列で取得[rowspan, text-data]
		const dataOfLine = [...tableRows[lineIdx].cells].flatMap( cell => 
			Array(cell.colSpan-0).fill([cell.rowSpan-1, cell.textContent]) );
		
		let dataIdx = 0;	//dataOfLine用のindex
		for (let i=0; i<numOfCols; i++) {	//列ループ
			if (rowspans[i]) {	//数値が1以上：rowspan範囲内なので一行上のデータで穴埋め
				rowspans[i]--;
				lineTexts.push(tableTexts[lineIdx-1][i]);
			} else {	//0の時：rowspan範囲外なのでdataOfLineのデータを挿入
				const [num, text] = dataOfLine[dataIdx];
				if (num) rowspans[i] += num;
				lineTexts.push(text);
				dataIdx++;
			}
		}
		tableTexts.push(lineTexts);
	};
	//行ループ
	for (let i=0; i<numOfRows; i++) getLineTexts(i);
	
	return tableTexts;
};

const tableTexts = getTableTexts(document.getElementsByTagName('table')[0]);
console.table(tableTexts);

```
AssetGraphで生成したバンドルファイルの位置がようやく理解できたのでメモ

# はじめに

AssetGraphを使って AssetBundle を作成した際、出力ディレクトリに関して混乱していたのでまとめます。

AssetGraphの使い方は、公式のドキュメントに記載されています。

[AssetBundleドキュメント](https://docs.google.com/document/d/e/2PACX-1vQBhFqcklSHMYCEvcMCFeQ_OoeV3QTzZ4fNFeQBx_tOVY3tBRcba6fgMy2vvR7WXjgUFsaDyaXTPNuM/pub?fbclid=IwAR0GbgrAeSrLp7ln0YSy7HfDu-6SAldyCxJ_2mETl2xY4QXtCSuZD-IynIo)

# AssetBundleの出力ディレクトリ

出力するAssetBundleのディレクトリは、「Build Asset Bundle」ノード(赤色のノード)で設定されています。「Output Option」で形式を指定できます。
最初の1つ目が既定で、残り3つがディレクトリ指定型です。

## Build In Cache Directory

規定のディレクトリです。ディレクトリ名は以下となります。

```
/Assets/AssetGraph/AssetBundles/Cache/AssetBundles/(id)/(platform)
```

`platform`には `Windows` などが入ります。

## Error If No Output Directory Found

ディレクトリを指定できますが、存在しないディレクトリを指定するとエラーになります。

## Automatically Create If No Output Directory Found

ディレクトリを指定し、存在しないときは自動的に生成します。

## Delete And Recreate Output Directory

ディレクトリが存在すれば一旦削除し、再生成します。

# ディレクトリの指定のコツ

Webを使わない場合、 Output Directroy を `/Assets/StreamingAssets` に指定しておけば、手間を掛けずに AssetBundle ファイルを設置できます。

また、Output Directory に `(Platform)` を指定すれば、プラットフォーム単位で出力するファイルのディレクトリを変えることができます。

例： `/Assets/StreamingAssets/(Platform)`

# まとめのまとめ

このように設定方法を理解することで、AssetBundleの管理にかける手間が省けるので、AssetGraphを活用するきっかけになればと思います。
IBM Cloud CIS トラブル時に取得する情報

##目的
IBMCloud InternetServicesを利用している際のトラブル時に取得する情報を記載します。

##取得情報
大きくわけて６つになります。

###1~3ポータルトップから取得する
1.Domain Name
2.Domain ID
3.CRN
![貼り付けた画像_2020_09_17_17_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/81d9a710-5e2c-7969-3edf-459e9d679b39.png)

###4.トラブル時の時間

タイムゾーンを含めた発生時刻
例:Thu, 17 Sep 2020 08:30:54 GMT

###5.トラブルが発生したURL

例:https://glb.m365.work/

###6.HTTアーカイブ(HAR)の生成

リクエストヘッダー、レスポンスヘッダー、本文コンテンツ、ページの読み込み時間を含め、全てのWebブラウザ要求を記録した情報
取得方法はブラウザ毎に異なるので、下記サイトを参考に実施する。
参考:[トラブルシューティングサイトへの情報収集](https://support.cloudflare.com/hc/ja/articles/203118044-%E3%83%88%E3%83%A9%E3%83%96%E3%83%AB%E3%82%B7%E3%83%A5%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B5%E3%82%A4%E3%83%88%E3%81%B8%E3%81%AE%E6%83%85%E5%A0%B1%E5%8F%8E%E9%9B%86#h_8c9c815c-0933-49c0-ac00-b700700efce7)

Chromeブラウザで実施した例
MacOSXの場合は、ブラウザの画面で**⌥ + ⌘ + I**を押し、Chromeデベロッパー・ツールを起動する。

Chromeデベロッパー・ツールが起動したら、<font color="Red">●</font>および右下に**Recording network activity**となっている事を確認
Recording担っていない場合は、●になっているはずなのでクリックする。
![https___glb_m365_work.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/a28ec70c-6536-682e-93a0-603f3a0b0835.png)

Recording状態で、一度URLにアクセスするとアクセス記録が下に記載される。
![https___glb_m365_work.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/1bf4b0f0-4059-7969-ff48-113eaed395c8.png)

↓矢印マークを選択すると、ファイルをダウンロードできる。
![Slack_と_https___glb_m365_work.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/244c8ba2-3c3b-4441-19c2-6808d13b47f2.png)

###HARファイルの中身の確認
下記サイトへアクセスする。
[Google HAR Analyzer](https://toolbox.googleapps.com/apps/har_analyzer/)

先ほどダウンロードしたHARファイルを選択する。
![HAR_Analyzer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/e4ae0a1f-de56-267a-82d2-5ba2d1790f85.png)

アクセス時のリクエストヘッダなどが参照できるため、この情報をもとにサポートで解析する。
![HAR_Analyzer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/82b30042-6e97-a71b-4ed9-a8cd94d63c9b.png)
SSL証明書のルート認証局・中間認証局 とは？

## そもそもSSL証明書とは？

`デジタル証明書`とも呼ばれる。
webサイトとそのサイトを閲覧しているユーザのデータのやり取りを暗号化するために使用される証明書。
サーバやネットワーク機器に電子ファイルをおいて使用する。
`https`での通信のやり取りでURLの横に鍵のマークが付いていて、`この接続は保護されています。`と出るのがSSL通信ができているものになります。

![無題 - ペイント 2020-09-11 22.15.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/148b751a-5b2e-67f9-47cc-5c8e71058239.png)

## SSL通信とは？

サーバとwebサイト閲覧者のブラウザ間での暗号化通信を行う。

1. ブラウザ : サーバにSSL通信のリクエストを送る
2. サーバ : ブラウザにSSL証明書を送る
3. ブラウザ : 受け取ったSSL証明書の公開鍵を使って共通鍵を暗号化、サーバに送る
4. サーバ : 受け取った共通鍵をSSL証明書の秘密鍵を使って復号。ここで鍵が一致。
5. ブラウザ/サーバ : これ以降の通信は共通鍵を使って暗号化・復号化を行う

## SSL証明書はどうやって設置するの？

SSL証明書は`サーバ管理者`がサーバに設置を行います。
設置方法はざっくりいうと以下。

1. サーバ管理者が秘密鍵を生成する
2. サーバ管理者が秘密鍵を用いて[CSR](https://qiita.com/samichi_valley/items/e038e2ca7d8b6443657d)を生成する
3. サーバ管理者が中間認証局に[CSR](https://qiita.com/samichi_valley/items/e038e2ca7d8b6443657d)をつけて証明書の申請を行う
4. 中間認証局がサーバ証明書・中間証明書をサーバ管理者に送る
5. サーバ管理者がサーバ証明書・中間証明書・秘密鍵をサーバに設置する

`中間認証局`が、サーバ証明書を発行している！ ということになる。

## 中間認証局とは？

`サーバ証明書`を発行しているところ。
有名なところだと以下。

- [digicert](https://www.ssl-secure.jp/digicert/)
- [Symantec](https://www.ssl-secure.jp/symantec/)
- [GlobalSign](https://www.ssl-secure.jp/globalsign/)

中間認証局は、
`中間証明書`というのを持っており、`中間証明書の秘密鍵`を用いてサーバ証明書に署名することで
サーバ証明書の信頼性を担保している。
中間証明書も階層構造になっており、ルート証明書の秘密鍵を用いてルート認証局に署名されることで
中間証明書の信頼性を担保している。

## ルート認証局とは？

中間認証局より上位の最上位認証局。
ルート認証局より上位の認証局はないため、ルート証明書は自分自身ルート認証局が署名を行って作成している。
ルート認証局は、中間認証局から発行を依頼された中間証明書に対して
上記で記載したように、ルート証明書の秘密鍵を用いて中間証明書に署名を行っている。
ルート証明書は各ブラウザに標準で組み込まれている。

![プレゼンテーション1.pptx - PowerPoint 2020-09-11 22.06.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/ad19e3d5-b871-c41b-e7d9-206889f44acb.png)

## 参考

- [【図解】よく分かるデジタル証明書(SSL証明書)の仕組み 〜https通信フロー,発行手順,CSR,自己署名(オレオレ)証明書,ルート証明書,中間証明書の必要性や扱いについて〜](https://milestone-of-se.nesuke.com/sv-advanced/digicert/digital-certification-summary/)
- [SSLって何？意味や仕組みをわかりやすく解説！](https://ssl.sakura.ad.jp/column/ssl/)
- [認証局とは？](https://jp.globalsign.com/ssl-pki-info/pki/ca.html)
vimのカラースキームを変更する方法

Linuxなどのコンソールでファイルをvimで開いたときに色が見にくい時があります。  
そんな時に色を変更する方法をメモがてら共有します。

### vimを開いてから変更する方法
①コロン(:)をうちコマンドモードにし「colorscheme」と入力します。colorと入力してtabキーを入力すれば保管されます。
②tabキーを押して使用したいカラースキームを選択します。
例えば「elflord」というカラースキームを変更する際には以下のようになります。

```
:colorscheme elflord
```
### 恒常的にカラースキームを設定する方法
vimを開くたびにカラースキーム設定をするのは面倒です。  
そこでデフォルトのカラースキームを設定します。
設定を書き込むのは「vimrc」というファイルです。

vimrcは各ユーザーのホームディレクトリ配下に隠しファイルとして用意されています。  
なので以下のように開けます。

```
vim ~/.vimrc
```

そして以下のように書き込み保存します。（カラースキームとしてelfordを使用した場合）

```
colorscheme elflord
```

vimrcはvimを開いたときに設定として読み込まれますのであとはvimを開けばカラースキームは自動で置き換わってくれます。
UPS(無停電電源装置)とは？

#UPSとは
- **U**ninterruptible **P**ower **S**upplyの略で、一言でいうと`サーバーを支える「巨大なバッテリー」`のこと。日本語では「無停電電源装置」と呼ばれる。


- UPSは平常時でも停電時でも、接続されたサーバーに対して電源を供給してくれる。

- UPSは電源供給だけではなく、`「安全なシャットダウンを実現する」`という役割も担っている。
Electronアプリをビルド・発行する時のプラットフォームにおける制約とネイティブモジュールとの関係

Electronを用いるとクロスプラットフォームな開発ができることは皆さんご存じの通りです。

しかし、ビルド→発行としていくなかで、**それらの作業がすべて一つのプラットフォーム上で完結するというわけではありません**。

また、**ネイティブモジュールを利用する場合は、話が異なります**。

そこらへんについて説明していこうと思います。

# 一つのプラットフォームですべてのプラットフォームにたいしてビルド・発行できるか

例えば「WindowsですべてのOS向けのアプリをビルドできるか？」という問題ですが、**ネイティブモジュールの利用有無次第**となります。

## ネイティブモジュールを利用していない場合

**ビルドはできます**。

ただし、**Mac向けの発行はCode Signingが必要になるため、Mac上でしかできません**。

よって、Mac上で動かせば、ビルドから発行まですべてMac上で完結します。

### Docker イメージ

electron-builderを動かせる環境として、Dockerイメージが用意されています。

しかし、これはLinux上で動かすのと同じなので、WindowsとLinux向けのアプリのビルド・発行しかできません。

また、Windows用のネイティブモジュールを利用する場合は、ビルドもできません。

ネイティブモジュールについては、次の節で説明します。

## ネイティブモジュールを利用している場合

ネイティブモジュールは各OS向けにそれぞれビルドする必要があります。

よって、基本的にはターゲットとなるプラットフォームの数だけビルド環境を用意する必要があります。

Macのネイティブモジュールをビルドするなら、Mac。

WindowsならWindowsのビルド環境が必要です。

昨今は、Mac用のVMも用意されていることを考えると、用意することは難しいことではないかもしれませんが、開発に当たっては実機が必要になることに間違いはないでしょう。

ネイティブモジュールを使わずとも、多くの機能が実装できることは確かですが、いつかはぶち当たる問題になります。

必要になったらで良いとは思いますが、ネイティブモジュールとそれに伴うビルド・発行環境の用意を検討する必要があるでしょう。
VuetifyのSpacingヘルパーでMargin, Paddingをかんたん調整（～v-containerを詰めて表示したい～編）

Vuetifyの必須・便利コンポーネントである`v-container`ですが、普通に表示すると他要素との間にいい感じの余白が入ります。

```vue:sample
    <v-app-bar color="blue lighten-3">app-bar</v-app-bar>
    <v-container>
      <v-row>
        <v-col cols="3">
          <v-card height="100" color="amber lighten-4"> v-card </v-card>
        </v-col>
      </v-row>
    </v-container>
```
↓

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352532/fe863189-42b2-002a-50ba-75cc3d3bd0ba.png" width=70%>

見やすい余白が勝手に入ってくれるのでありがたいのですが、以下のように密着して表示させたいこともあります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352532/53596e50-6fc7-2c59-ec1a-d08bffb6e6bf.png" width=70%>

MarginやらPaddingやらをいじることで密着させるのですが、VuetifyにはこのMarginとPaddingを簡単に設定できるヘルパークラスが存在します。

##Spacingヘルパー
[Spacingヘルパー](https://vuetifyjs.com/ja/styles/spacing/)を使うことで、簡単に各要素の余白を調整できます。


記法はシンプルで、`{Margin/Paddingのどちらか}{どの方向か}-{どれだけの幅か}`の順に書くだけです。例えば上方向のMarginとPaddingを0にしたいのであれば`mt-0 pt-0`となりますし、上方向のMarginを2(8px)、左方向のMarginを1(4px)、下方向のPaddingを3(12px)にしたいなら`mt-2 ml-1 pb-3`という具合です。

##上記のv-containerでやってみる
v-containerはデフォルトでMarginとPaddingが効いているので、0にします。

```vue
    <v-app-bar color="blue lighten-3">app-bar</v-app-bar>
    <v-container mt-0 pt-0>
      <v-row>
        <v-col cols="3">
          <v-card height="100" color="amber lighten-4"> v-card </v-card>
        </v-col>
      </v-row>
    </v-container>
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352532/593a42c2-30e1-c953-1c8c-3f21d13af2f3.png" width=70%>

あれ、Margin, Paddingともにゼロにしたのになぜか微妙に隙間が空いていますね。

おそらくですが、`v-app-bar`, `v-container`ともに、視覚効果のための影のキワまで1つのコンポーネントとなっているため、パッと見では隙間が空いているように見えるのかと思います。

試しにこのコンポーネントの境界部分を限界まで2値化したところ、隙間があるように見えていた部分も、実は影で埋まっていることがわかりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352532/b92aca81-ad3f-d917-090e-36600c3a4517.png)


「**隙間みたいに見えますけど実は影で埋まってるんで**」と言われてもどうしようもないので、これを埋めるために**ネガティブマージン**を使います。
ネガティブの名の通りMarginに負の数を与えるイメージで、要は他要素に重ねるように表示することができます。

```vue
    <v-app-bar color="blue lighten-3">app-bar</v-app-bar>
    <v-container mt-n2 pt-0>
      <v-row>
        <v-col cols="3">
          <v-card height="100" color="amber lighten-4"> v-card </v-card>
        </v-col>
      </v-row>
    </v-container>
```

`v-container`を`v-app-bar`の影に重ねるように、`v-container`の上方向にネガティブの2(8px)を設定しました。

これで無事に密着して（いるように）表示させることができました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352532/53596e50-6fc7-2c59-ec1a-d08bffb6e6bf.png" width=70%>


##参考
[CSS Spacing helpers — Vuetify.js](https://vuetifyjs.com/ja/styles/spacing/)
【GAS x kintone連携】kintoneで発生したエラー処理は、ステータスコードで判別する

* 「GASのUrlFetchAppを使ってkintoneに何か処理をした際のエラー処理についてのメモ」改題。

Google Apps Script(GAS)からkintoneにレコード登録するなどの処理をした際、kintone側でエラーが発生した場合の、エラー処理のメモです。

# kintone API エラー判別

kintone APIのエラー判別はレスポンスのステータスコードで判別する。

kintone REST API レスポンス
https://developer.cybozu.io/hc/ja/articles/201941754#step10

>HTTPステータスコードが「200」であれば正常終了、それ以外はエラー終了です。


# エラー処理

例えば、kintoneのレコード登録後にスプレッドシートを更新する場合のエラー処理は、下記の用にgetResponseCodeで判別する。

```javascript
  // fetchRecordsはkintoneに何か処理をする関数
  fetchRecords(URL, option)
  .then(result => {
    if (result.getResponseCode() !== 200) { // ステータスコードが200以外の時
      throw new Error(result.getContentText()); // エラーをスローする
    }
    return result;
  })
  .then(result => {
    // スプレッドシートを更新する処理など
    console.log(result.getContentText());
  })
  .catch(error => {
    // エラー処理する
    console.error(error);
  });
}
```

# 参考

https://developers.google.com/apps-script/reference/url-fetch/http-response
【Golang】Go言語の配列の基礎

最近Go言語の勉強を初めました！

今回は配列の基礎について復習したので備忘録として簡単にまとめさせていただきます。

##書き方

```
1. var 変数名 [長さ]データ型
2. var 変数名 [長さ]データ型 = [長さ]データ型{初期値A, 初期値B}
3. 変数名 := [...]データ型{初期値A, 初期値B}
```

例

```go

package main

import "fmt"

func main() {
	var a [3]int
	a[0] = 100
	a[1] = 200
	a[2] = 300
	fmt.Println(a) //=> [100 200 300]

	var b [3]int = [3]int{100, 200, 300}
	b = append(b, 400) //=> ERROR
	fmt.Println(b)     //=> [100 200 300]

	c := [...]int{100, 200, 300}
	fmt.Println(c) //=> [100 200 300]
}
```

配列は長さが決められており、appendなどを用いて要素を追加しようとするとエラーになります。
実際は次に説明するスライスを使いことが多いようです。スライスは配列の長さを変更することができます。

##スライスの書き方

```
1.var 変数名 []型
2.var 変数名 []型 = []型{初期値1, ..., 初期値n} 
3.変数名 := 配列[start:end]
```

```golang

package main

import "fmt"

func main() {

	n := []int{1, 2, 3, 4, 5, 6}
	fmt.Println(n)      //=> [1 2 3 4 5 6]
	fmt.Println(n[2])   //=> 3
	fmt.Println(n[2:4]) //=> [3 4]
	fmt.Println(n[:2])  //=> [1 2]
	fmt.Println(n[2:])  //=> [3 4 5 6]
	fmt.Println(n[:])   //=> [1 2 3 4 5 6]

	n[2] = 100
	fmt.Println(n) //=> [1 2 100 4 5 6]

	var board = [][]int{
		[]int{0, 1, 2},
		[]int{3, 4, 5},
		[]int{6, 7, 8},
	}
	//入れ子
	fmt.Println(board) //=> [[0 1 2] [3 4 5] [6 7 8]]

	n = append(n, 100)
	fmt.Println(n) //=> [1 2 100 4 5 6 100]

}
```

↑のようにスライスの要素を変更すると、その元となる入れるの要素も変更されている。
iOSアプリのリバースエンジニアリング-[ツール編]


#はじめに
この記事は随時追記していきます。時々思い出した頃に見に来てください。ストックかLGTMで多分更新時に通知がいくようにするのでみたい人はお願いします

#ツールたち
##LLDB
LLVM（Xcodeでも使われているコンパイラ）のプロジェクトの一部として開発された高性能な動的デバッガ。
以下のサイトはgdb to lldbのチートシートであるが、普通にlldbのコマンドを調べるためにも役に立つ。
http://lldb.llvm.org/use/map.html
こちらは純粋なlldbのチートシート
https://www.nesono.com/sites/default/files/lldb%20cheat%20sheet.pdf

breakpointはもちろん、bt(バックトレース)やimage lookup --address、thread returnなどをよく使ってる。
XcodeからでなくコマンドラインでLLDBを使うようになってから、普通のiOSアプリの開発においてもコマンドから使ったりするようになった。

あんまり実用性はないけどGUIも用意されてたりする。
![スクリーンショット 2020-09-19 22.07.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377767/f765544d-389b-612f-92c1-327e97c2d302.png)

##otool
いくつかの用法がある。
###ライブラリの依存関係を調べる
lddみたいな使い方

```
otool -L　ファイル名
```

##nm
シンボルを抽出して表示する。使用されているクラス名などを調べることができる。

```
nm ファイル名
```

##strings
ファイルから文字列の部分を抽出する。例えば、pirntf("aaaa");としていれば、aaaaが見つかる。
このコマンドから見つからないようにする方法も今度記事にしようと思っています。

```
strings ファイル名
```

##dsdump

##Hopper Disassembler V4
![スクリーンショット 2020-10-27 21.33.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377767/2fac0670-284b-efca-ed75-1223ea71de40.png)

##Ghidra

##frida
【Unity&Hololens2】Azure Speech Servicesを日本語音声に対応させる

####Azure Speech ServicesをUnityで日本語で使いたい！
Unity&Hololens2 **超初心者**の自分用のメモ書きです。
[公式チュートリアル](https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrlearning-speechsdk-ch1)でAzure Speech Servicesを導入することはできたのだが
日本語でしゃべってもローマ字になってしまう...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666865/d6ab2e09-ad73-1b63-1218-dd69f8f08d8c.png)

これは当たり前で初期設定では英語に設定されているから。
ということでどこから変えるかというと、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666865/84772505-0fd1-cd4b-06d6-c11273a06bbe.png)
Lunarcomの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666865/2115310b-bc12-ca7e-fb8f-cddbe9fdff88.png)
LunarcomSpeechRecognizerというコンポーネントから変更できます。
開いてみると

```
using UnityEngine;
using Microsoft.CognitiveServices.Speech;

public class LunarcomSpeechRecognizer : MonoBehaviour
{
    private string recognizedString = "Select a mode to begin.";
    private object threadLocker = new object();

    private SpeechRecognizer recognizer;

    private bool micPermissionGranted = false;
    ///private bool scanning = false;

    private string fromLanguage = "en-US";

    private LunarcomController lunarcomController;
~~~~~~~~~~~~~~(以下略

```

fromLanguageとかいうあからさまに言語を変換できそうな変数があるのでここを日本語に変更してあげるだけで完了します。
[利用できる言語一覧](https://docs.microsoft.com/ja-jp/azure/cognitive-services/speech-service/language-support)
日本語は<font color="HotPink">ja-JP</font>なのでそのまま入れてあげれば日本語に対応してくれます。

```
private string fromLanguage = "ja-JP";
```

変更してからしゃべると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666865/beda664d-9eb7-b25d-e6bd-9dfe2be7651e.png)
日本語になってくれました!
iOSDC2020の HomeKit のセッションが面白かった

iOSDC2020 の HomeKit に関するセッションが面白かったので、セッションで聞いた内容含め簡単にまとめておこうかと思います。暇があったら何か作ってみたい🙃


### HomeKit とは?

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292456/b1ee73b0-a6c0-5c55-5767-10ee57656874.png)


iOS、iPadOS、macOS、watchOS などの Apple製品からデバイスを管理・コントロールできるようにするための IoT アプリケーションの枠組みです。また、そのような HomeKit 対応のアプリケーションを対応する機器をコントロールするアプリとして Apple から `Home` というアプリが標準で提供されていますが、`HomeKitFramework` という Framework を使うことで独自にアプリを作ることも可能です。

### HomeKit Accessory Protocol(HAP) とは？

HomeKit Accessory Protocol(HAP) は、サードパーティー製アクセサリ(証明やドアロックなど)と Apple製品とが相互に通信するためのプロトコルで、商用目的ではない場合は自由にアクセサリに HAP を実装できますが、商用目的の場合は、[MFi](https://developer.apple.com/programs/mfi/) プログラムに基づく HomeKit 認定を完了する必要があるみたいです。


### Homebridge とは？

Homebridge は、iOS HomeKit API の挙動を HomeKit に対応していないアクセサリを動かすために使用される、ホームネットワークで実行できる軽量のサーバーです。また、それら HomeKit デバイスを制御する Homebridge プラグインが2000以上あるそうです。詳しくは[こちら](https://homebridge.io/) を参照してください。

セッションでは、Homebridge の代表例として、Philips hue の Bridge が消化されていました。この Bridge により他の Philips Hue で提供されているアクセサリーが実質 Home App で使用できるようになっているようです。



https://www.philips-hue.com/ja-jp/p/hue-bridge/8718696562260




### HomeKit ADK とは？

HomeKit Accessory DevelopmentKit の略でアクセサリーメーカーが HomeKit に対応したデバイスを作成するための Apple から提供されている開発コードのようです。つまり、前述の Bridge とは違い Home App で直接的にアクセサリを操作できるようにするための DevelopmentKit のようですね。



https://github.com/apple/HomeKitADK




### 参考

- https://speakerdeck.com/tokorom/homekit-2020
- https://www.tokoro.me/posts/homekitadk/
- https://homebridge.io/
- https://developer.apple.com/homekit/
- https://developer.apple.com/jp/support/homekit-accessory-protocol/
CSSのみで作るドロップダウンメニュー

####1.目的
作成中

####2.参考サイト
https://theorthodoxworks.com/web-design/drop-down-menu-multi-css/

####3.必要なもの
作成中

####4.ぶつかった問題
作成中

####5.解決策
作成中
[Xcode]ViewControllerの画面サイズを変更する

## ViewControllerの画面サイズを変更する


StoryBoard上で画面サイズ以上のViewを配置したい時。


1.ViewControllerを選択
2.Size inspector → Simulated Sizeを[Fixed]から[Freeform]に変更
3.WidthとHeightを好きなサイズに変更

以上！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692883/e55c0fe8-2a37-d065-4acb-ff2011a88780.png)
Android 入力後キーボードを閉じる方法

[参考](https://qiita.com/bassaer/items/0e412d9f36b2113ee8d0)

```kotlin
    private fun hideKeyboard(view:View?) {
        if(view != null) {
            val manager = this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            manager.hideSoftInputFromWindow(view.windowToken, 0)
        }
    }
```
ベクトルを2次元に可視化する

##準備 - Preparation

```
vecs #numpyの2重配列
Name #ラベル
```


##主成分分析 - Principal Component Analysis

```
from sklearn.decomposition import PCA #主成分分析器

pca = PCA(n_components=2)
pca.fit(vecs)
x = pca.transform(vecs)

X = []
Y = []
for j in range(len(x)):
  X.append(x[j][0])
  Y.append(x[j][1])
```


##可視化 - Visualization

```
fig, ax = pyplot.subplots(figsize=(15,15))
ax.scatter(X, Y)
for i, txt in enumerate(Name):
  ax.annotate(txt, (X[i], Y[i]))
pyplot.savefig("img.png") # 保存
```



##例 - Example
Wikipedia2Vecの事前学習モデルから国名に対応するベクトルを抽出し，可視化した結果
Visualization of country vectors, which was extracted Wikipedia2Vec model.
![img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431266/07f124a5-ebe1-4777-ebdd-7bd0c5858dea.png)
Nuxt.js + TypeScript + Composition API の.vueファイルテンプレート

## 結論

VSCodeで、nuxttsと打ち込むだけで以下のテンプレートが出力されるようにします。

``` Hoge.vue
<template>
  <div></div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
} from '@nuxtjs/composition-api'

export default defineComponent({
  setup() {
    const state = reactive({

    })
    return {
      state,
    }
  }
})
</script>

<style>

</style>
```


## 手順
[ctrl] + [shift] + [p] を押し、User Snippets と入力してエンターを押します。

vue と入力し、`vue.json` を作成します。
以下の内容を入力します。コメントアウト部分はデフォルトの記載です。不要であれば消してください。

```
{
	// Place your snippets for vue here. Each snippet is defined under a snippet name and has a prefix, body and 
	// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
	// same ids are connected.
	// Example:
	// "Print to console": {
	// 	"prefix": "log",
	// 	"body": [
	// 		"console.log('$1');",
	// 		"$2"
	// 	],
	// 	"description": "Log output to console"
	// }
	"nuxtTs": {
		"prefix": "nuxtts",
		"body": [
			"<template>",
  			"\t<div></div>",
			"</template>",
			"",
			"<script lang=\"ts\">",
			"import {",
  			"\tdefineComponent,",
  			"\treactive,",
			"} from '@nuxtjs/composition-api'",
			"",
			"export default defineComponent({",
  			"\tsetup() {",
    		"\t\tconst state = reactive({",
			"",
    		"\t\t})",
    		"\t\treturn {",
      		"\t\t\tstate,",
    		"\t\t}",
  			"\t}",
			"})",
			"</script>",
			"",
			"<style>",
			"",
			"</style>"
		]
	}
}
```

保存してテキトーに.vueファイルを作って、`nuxtts`と打ちます。

![nuxtts.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199887/aa77617c-c2b6-2496-9d8b-5e438a6fab5b.gif)

やりました。

## 補足
素の@vue/composition-apiではなく[@nuxtjs/composition-api](https://www.npmjs.com/package/@nuxtjs/composition-api)を使っています。`asyncData`が使えない等の面倒な問題をある程度解決してくれています。
ただバージョンが浅いのでいきなり仕様が変わったりするかもしれません。(そこはご愛敬)

末尾のカンマとかstyleの言語とかは各々カスタマイズしていただければと思います。


## 感想
Vue3リリースおめでとうございます。Nuxt.jsのVue3対応が待ち遠しいですね！

コードスニペット作ってみて思ったんですが、何が面倒って""とか,とか\t(タブ)とかいちいち打ち込むところですね。
ある程度は一括入力で何とかなるんですが、タブ揃えのための\t打ち込みがしんどい。。。

Vue, Composition API, TypeScriptでの開発はまだコーディングのお作法のデファクトみたいなのが決まっていないと思うので、こういうテンプレも良いよーというのがあれば是非教えてください！

(追記)「vscode スニペット 作成」でググったらめっちゃ普通に[スニペット作成ツール](https://migi.me/vsc_snippet/)がありました(激怒)
ポチポチ記号を打ち込む前に調べなかった自分への激怒であり、スニペット作成ツールは神です。これから積極的に使います。

(追記2)投稿してから思ったんですが、Vue3何も関係ないのでタイトルから削除しました()
ElixirでOSの環境変数を利用する

# はじめに
- @yuta_vamdemic さんの[GoでOSの環境変数を利用する](https://qiita.com/yuta_vamdemic/items/89b22cc1b32ad1bd3e5f)を拝見しまして、私はぜひ[Elixir](https://elixir-lang.org/)での話をまとめておこうとおもいます
- [Elixir](https://elixir-lang.org/)は`Elixir 1.10.4 (compiled with Erlang/OTP 23)`を使いました

# System.get_env を使います

## [System.get_env/0](https://hexdocs.pm/elixir/System.html#get_env/0)

- `/`のうしろの数字は引数の数です
- 引数無しで呼び出すとすべての環境変数がマップで得られます

```elixir
iex> System.get_env
%{
  "HELLO_NERVES_QIITA_READ_WRITE_TOKEN" => "secret",
  ...
}
```

## [System.get_env/1](https://hexdocs.pm/elixir/System.html#get_env/2)

- 環境変数がセットされていない場合には`nil`が返ります

```elixir
iex> System.get_env("NHK_API_KEY")
"secret"

iex> System.get_env("NOT_SET")
nil
```

## [System.get_env/2](https://hexdocs.pm/elixir/System.html#get_env/2)

- 環境変数がセットされていない場合のデフォルト値を第二引数で指定します

```elixir
iex> System.get_env("NOT_SET")
nil

iex> System.get_env("NOT_SET", "4001")
"4001"

iex> System.get_env("NHK_API_KEY", "nhk")
"secret"
```

# Wrapping Up
- [Elixir](https://elixir-lang.org/)では`System.get_env`を使います
- Enjoy [Elixir](https://elixir-lang.org/)!
Shopifyのカスタムアプリでwebhookを設定する

#はじめに
この記事ではShopifyのストア内で起こる特定の[event](https://shopify.dev/docs/admin-api/rest/reference/events/event)をrailsで作成したカスタムアプリと連動させるために使用したwebhookの設定についてお話しします。
webhookの通知を受けるためには管理画面上で設定→通知からマニュアルで設定する方法もありますが、アプリを作ったストア全ての管理画面に入れるわけではないこと、公開アプリとして運用したい人たちのために、今回は管理画面からの設定はしないこととします。

#環境
Ruby 2.6.6
Rails 6.0.2

## 1. 必要となるアクセススコープをconfigureする
shopify_app.rb

```Ruby
ShopifyApp.configure do |config|
  ...
  config.scope = "read_products, read_orders" 
  ]
  ...
end
```
※ここで注意しなければいけないのが、この時点ですでにストアにアプリがインストールされている場合は、スコープを増やした後にアプリのアンインストール→再インストールをした方が良いという点です。

##2.通知を受けたいwebhookとリクエスト先のURLを指定
[gem 'shopify_app'](https://github.com/Shopify/shopify_app)をインストールしていることが前提でコマンドラインで下記を指定

```shell
rails g shopify_app:add_webhook -t orders/create -a https://example.com/webhooks/orders_create
```

この後shopify_app.rbには下記が追加される

```Ruby
ShopifyApp.configure do |config|
  ...
  config.webhooks = [
    {topic: 'orders/create', address: 'https://example.com/webhooks/orders_create'},
  ]
  ...
end
```

##3.Jobの設定
それぞれのwebhookでjobを作成します
app/jobs/orders_create_job.rb

```Ruby
class OrdersCreateJob < ActiveJob::Base
  def perform(shop_domain:, webhook:)
    shop = Shop.find_by(shopify_domain: shop_domain)

    shop.with_shopify_session do
      # ここでimplementしたい機能を追加
    end
  end
end
```
sidekiq等の非同期処理を行うライブラリを使用されいる場合は、上記のjobがbackgroundで処理されます。

##4.webhook用のカスタムcontrollerを作成
この部分はなくても問題ないのですが、webhookを通じてjobで行う以上の機能が必要となる場合などに必要となるので記載します。
routes.rb

```Ruby
...
post 'webhooks/orders_create', :to => 'custom_webhooks#orders_create'
...
```

app/controllers/custom_webhooks_controller.rb

```Ruby
class CustomWebhooksController < ApplicationController
  
  def orders_create
  end
  ...

  private

  def webhook_params
    params.except(:controller, :action, :type)
  end

end
```

- Webhook verification
全てのwebhookはアプリがインストールされたストアからのリクエストであることを証明する必要があります。
Shopify側では、これをhttpリクエストのheaderにHMACを入れることでこれを証明するようにしています。
railsアプリの場合、幸いにも下記を入れるだけでこのHMACを識別して正しいリクエストかどうかを判断してくれます。

```Ruby
class CustomWebhooksController < ApplicationController
  include ShopifyApp::WebhookVerification
  ...
end
```

- 必要となるmethodを作成


```Ruby
def orders_create
  params.permit!
  OrdersCreateJob.perform_later(shop_domain: shop_domain, webhook: webhook_params.to_h)
  head :no_content
end
```

webhookを通じてPOSTコールがされたあと、Shopify側に200 series statusを返す必要があります。([公式ドキュメント](https://shopify.dev/tutorials/manage-webhooks)によると200 OK以外のレスポンスを返した場合には、48時間以内に19回のコールをしてくれるようです)
head :no_content にすることで、レスポンスは "204 no content"＝どのデータもレスポンスしていない＝webhookのデータは受領されたと判断されます

##注意点
最初に管理画面にてwebhookの通知を設定をしている場合でも、config上で必要となるscopeのアクセスを許可されていなければhttpリクエストすらされないようでした。
ご自身のアプリがすでにストアにインストールされてしまっている場合には、このscope追加でアプリが再インストールされる際に下記のような画面でスコープ許可がされることを確認してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656820/0b91b139-75b2-d886-9b33-6f87bedb3489.png)

webhookがストアに設定されているかを確認する場合は、

```
header
Content-Type: application/json
X-Shopify-Access-Token:  該当のshop.shopify_token
GET https://ストア名.myshopify.com/admin/api/2020-07/webhooks.json
```
で確認することもできます。
フォームオブジェクトを使ったdate型カラムの保存方法

フォームオブジェクトを使って、date型のカラムを保存しようとしたところ、
フォームオブジェクトのクラスでインスタンスを生成してしまうとdate型のカラムが認識されないので、

unknown attribute 'expire_date(1i)' for ItemsTag.

のようにエラーが出てしまう。。

なので、コントローラーのcreateメソッドのなかで、インスタンス生成した際に、date型にあらかじめ変形させておいた値をmergeさせてフォームオブジェクトに渡してあげる、ということをしていきます。

[やること]
songsテーブルに追加した、date型　「 t.date :sales_date,          null: false」
を保存させたい。

[方法]

[フォームのビュー]

```ruby:new.html.erb
   <div class="weight-bold-text"> 
        リリース日
       <span class="indispensable">(必須)</span>
      </div>
    <div class='input-sales-wrap'>
      <%= raw sprintf(
                  f.date_select(
                    :sales_date,
                    class:'select-birth',
                    use_month_numbers: true,
                    prompt:'--',
                    start_year: (Time.now.year),
                    end_year: 1930,
                    date_separator: '%s'),
                  "<p> 年 </p>", "<p> 月 </p>") + "<p> 日 </p>" %>
    </div>

```

[コントローラー]

```ruby:songs_controller.rb

 def create
    @song = SongsArtist.new(song_params)
    date = params.require(:songs_artist).permit(:sales_date)
    sales_date = Date.parse( date["sales_date(1i)"] + "-" + date["sales_date(2i)"] + "-" + date["sales_date(3i)"] )
    @song = SongsArtist.new(song_params.merge(sales_date: sales_date))
end

 def song_params
    params.require(:songs_artist).permit(:name, :text, :image, :translate, :youtube_url, :genre_id, :art_name,:featuring_name,:producer_name).merge(user_id: current_user.id)
  end
```
sales_date以外は、song_paramsメソッド内でpermitのなかに入れてフォームオブジェクトに渡すが、
sales_dateは、
 date = params.require(:songs_artist).permit(:sales_date)
    sales_date = Date.parse( date["sales_date(1i)"] + "-" +  date["sales_date(2i)"] + "-" + date["sales_date(3i)"] )
この２行の記述でdate型に変更し、
  @song = SongsArtist.new(song_params.merge(sales_date: sales_date))
フォームオブジェクトに渡す値であるsong_paramsに、date型に変更したsales_dateをmergeさせて
一緒に渡す。

```ruby:song_artist.rb

class SongsArtist
  include ActiveModel::Model
  attr_accessor :name, :text, :image, :genre_id, :translate, :youtube_url, :sales_date,:art_name,:producer_name,:featuring_name, :user_id,:song_id
  validates :name, :text,:image,:genre_id, presence: true
  validates  :genre_id, numericality: { other_than: 1 }
  def save
    artist = Artist.where(art_name: art_name).first_or_initialize
    artist.save
    featuring = Featuring.where(featuring_name: featuring_name).first_or_initialize
    featuring.save
    producer = Producer.where(producer_name: producer_name).first_or_initialize
    producer.save
    song = Song.create(name: name, text: text, image: image, genre_id: genre_id, translate: translate, youtube_url: youtube_url, sales_date: sales_date,user_id: user_id,producer_id: producer.id,featuring_id: featuring.id)
    SongArtistRelation.create(song_id: song.id, artist_id: artist.id)
  end
end
```

フォームオブジェクトの記述は、普段と変わらず、 attr_accessorでコントローラーから渡ってきたカラムを許可し、createアクションの引数に保存するカラムを記述する。

以上です。
sedでHTML内の特定の拡張子のファイルだけパスを置換するのに苦戦した

## やりたかったこと
こんな感じのファイルのjsのパスだけフォルダ名をsedコマンドで一括置換したい。
ファイル内のjsのパスは全て変えたいが、他の拡張子のパスは変えたくない。

```html:target.html
<!-- "./js/hoge.js"みたいな感じにしたい -->
<script src="./アセット/hoge.js" /><link rel="./アセット/hoge.css" /><script src="./アセット/hoge.min.js" />
<link rel="./アセット/hoge.css" />
<img src="./アセット/hoge.png" />
<img src="./アセット/hoge.svg" />
<img src="./アセット/hoge.jpeg" />
<img src="./アセット/hoge.jpg" />
```

## 結論
下記の正規表現でできました。めでたしめでたし。

```bash
sed -i "" "s/アセット\(\/[^\"]*\.js\"\)/js\1/g" target.html
```

実行結果はこうなる。jsファイルへのパスだけフォルダ名がjsになっている。

```html:target.html
<script src="./js/hoge.js" /><link rel="./アセット/hoge.css" /><script src="./js/hoge.min.js" />
<link rel="./アセット/hoge.css" />
<img src="./アセット/hoge.png" />
<img src="./アセット/hoge.svg" />
<img src="./アセット/hoge.jpeg" />
<img src="./アセット/hoge.jpg" />
```

## 苦戦したところ
結論を書いてしまうと非常にあっさりなのだが実はかなり苦戦した。
１行目のような１行に複数回jsのパスが書いてあるケースを考えると複雑さが増す。

## 最長一致ではダメ
最初にパッと思いついた正規表現は以下のようになった。

```bash
sed -i "" "s/アセット\(.*\.js\)/js/g" target.html
```

実行結果はこうなる。１行目にある２つ目のjsファイルhoge.min.jsのフォルダ名が置換できていない。

```html:index.html
<script src="./js/hoge.js" /><link rel="./アセット/hoge.css" /><script src="./アセット/hoge.min.js" />
<link rel="./アセット/hoge.css" />
<img src="./アセット/hoge.png" />
<img src="./アセット/hoge.svg" />
<img src="./アセット/hoge.jpeg" />
<img src="./アセット/hoge.jpg" />
```
これはhoge.min.jsが正規表現にヒットしなかったわけではなく、**最初のhoge.jsが最長一致によって過剰にヒットしたため**にこうなっている。
上記の正規表現の**括弧の内側は「任意の文字の連続 + .js」を検索している**ため、１行目は下記の範囲でヒットしている。

```
hoge.js" /><link rel="./アセット/hoge.css" /><script src="./アセット/hoge.min.js
```
２つ目のjsファイルまでヒットしてしまったため、１つ目のファイルのフォルダ名だけが置換されてしまっている。

## 最短一致ならどうか？
最長一致で長すぎるのであれば最短一致ならどうだろうか？

```
/アセット\/.*?\.js/g
```
これならば最初に.jsが出てきた時点で一致が止まる。１行目の２つ目のjsが含まれてしまう心配はない。
この正規表現の一致は以下のようになる。

```
アセット/hoge.js
アセット/hoge.css" /><script src="./アセット/hoge.min.js
```
確かに１つ目のjsファイルは期待通りの結果になったが、**２つ目の一致が大きすぎる**。
js以外のファイルが挟まっているとそのフォルダ名がマッチしてしまい、そこから.jsまでが一致してしまう。
さらに言うと**sedコマンドは最短一致（?記号)をサポートしていないので、そもそもこの正規表現がコマンドで実行できない。**

ちなみに、仮にsedで実行できたとしたらHTMLはこうなっていただろう。やはり間違いである。

```html:target.html
<!-- cssのディレクトリがjsになってしまう -->
<script src="./js/hoge.js" /><link rel="./js/hoge.css" /><script src="./アセット/hoge.min.js" />
<link rel="./アセット/hoge.css" />
<img src="./アセット/hoge.png" />
<img src="./アセット/hoge.svg" />
<img src="./アセット/hoge.jpeg" />
<img src="./アセット/hoge.jpg" />
```

## "が出現した時に一致を止める
やりたいことを言い換えれば下記の単位で置換すべきかを確認したいのだ。

```
"./アセット/hoge.js"
"./アセット/hoge.css"
"./アセット/hoge.min.js"
```

**ダブルクォーテーションの閉じが出現した時に一致を止められれば過剰な長さの一致を防げる**。
しかし、正規表現に「一致を止める」などという表現は私の知る限りでは存在しない。

なので、言い方を変える。**"の内側から始まり「"以外の文字の連続」**を検索する正規表現を書けばいい。
「x以外の文字」は文字クラスの先頭に^を書けばいい。[]で囲って先頭に^を書く。

```
/アセット\/[^\"]*\.js/g
```
これで**「"以外の文字列の連続が.jsで終わる」**を表現できた。
あとはこれをsedコマンドに組み込んで、ファイル名を後方参照しつつフォルダ名の部分だけ置換するように書き換えればいい。

```bash
sed -i "" "s/アセット\(\/[^\"]*\.js\"\)/js\1/g" target.html
```

また一歩、正規表現脳を強化できたと思った。
AtCoder Beginner Contest 179 参戦記

# AtCoder Beginner Contest 179 参戦記

## [ABC179A - Plural Form](https://atcoder.jp/contests/abc179/tasks/abc179_a)

1分半で突破. 書くだけ.

```python
S = input()

if S[-1] != 's':
    print(S + 's')
else:
    print(S + 'es')
```

## [ABC179B - Go to Jail](https://atcoder.jp/contests/abc179/tasks/abc179_b)

1分半で突破. 書くだけ. 問題名はなんで「牢屋に行く」なんすかね.

```python
N = int(input())

t = 0
max_run_length = 0
for _ in range(N):
    D1, D2 = map(int, input().split())
    if D1 == D2:
        t += 1
    else:
        t = 0
    max_run_length = max(max_run_length, t)

if max_run_length >= 3:
    print('Yes')
else:
    print('No')
```

## [ABC179C - A x B + C](https://atcoder.jp/contests/abc179/tasks/abc179_c)

4分で突破. 書くだけ. 数秒くらい計算量大丈夫かなって考えはしたけど、まあC問題だし大丈夫だろうと腐った考えで PyPy で提出して AC.

```python
N = int(input())

result = 0
for A in range(1, N + 1):
    for B in range(1, (N // A) + 1):
        C = N - A * B
        if C == 0:
            continue
        result += 1
print(result)
```

A×B+1≦N なら良いので、式変形して B≦(N-1)÷A となり、B の値域が一発で求まる.

```python
N = int(input())

result = 0
for A in range(1, N + 1):
    result += (N - 1) // A
print(result)
```

## [ABC179D - Leaping Tak](https://atcoder.jp/contests/abc179/tasks/abc179_d)

突破できず. 50分くらい考えて閃いたけど、5分では実装できません.

## [ABC179E - Sequence Sum](https://atcoder.jp/contests/abc179/tasks/abc179_e)

36分半で突破. ループ検出題は何題か解いているので、そこまで難しいとは思わなかった. 入出力例3がなかなか合わなくてこれだけ時間がかかっていると説得力がないけど(笑).

```python
N, X, M = map(int, input().split())

existence = [False] * M
a = []
A = X
for i in range(N):
    if existence[A]:
        break
    existence[A] = True
    a.append(A)
    A = A * A % M

try:
    loop_start = a.index(A)
except:
    loop_start = len(a)

result = sum(a[:loop_start])
N -= loop_start
if N != 0:
    a = a[loop_start:]
    loops = N // len(a)
    remainder = N % len(a)
    result += sum(a) * loops + sum(a[:remainder])
print(result)
```
OPL系チップに4MHzのクロックを与えた時のF-Numberテーブル

[OPLのNOTESELの話題](https://qiita.com/okaxaki/items/4dc3b57649b3de0f9d0d)からの派生です。

OPL系チップの入力クロックは 3.58MHz を与えることが前提になっていますが、4MHzを与えても動きます。
しかし、4MHzを与えると、音階を表すF-Numberテーブルが3.58MHzのときとは変わってしまいます。

これに NOTESEL の設定も絡めて考えると、どのような F-Number テーブルを作って NOTESEL をどう設定すれば良いでしょうか？

Excel で計算すれば答えはすぐ出るのですが、備忘録として結果だけ貼っておきます。トA3=440.0Hz前提です。

# 普通のF-Numberテーブルを使う場合
NOTESEL=0 を選択し、D#3 基準のF-Numberテーブルを使います。

|周波数(Hz)|音階|F-Number|D<sub>9</sub>|D<sub>8</sub>|D<sub>7</sub>|D<sub>6</sub>|D<sub>5</sub>|D<sub>4</sub>|D<sub>3</sub>|D<sub>2</sub>|D<sub>1</sub>|D<sub>0</sub>|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|311.13|D#3|367|0|1|0|1|1|0|1|1|1|1|
|329.63|E3|389|0|1|1|0|0|0|0|1|0|1|
|349.23|F3|412|0|1|1|0|0|1|1|1|0|0|
|369.99|F#3|436|0|1|1|0|1|1|0|1|0|0|
|392.00|G3|462|0|1|1|1|0|0|1|1|1|0|
|415.3|G#3|490|0|1|1|1|1|0|1|0|1|0|
|440.00|A3|519|1|0|0|0|0|0|0|1|1|1|
|466.16|A#3|550|1|0|0|0|1|0|0|1|1|0|
|493.88|B3|583|1|0|0|1|0|0|0|1|1|1|
|523.25|C3|617|1|0|0|1|1|0|1|0|0|1|
|554.37|C#3|654|1|0|1|0|0|0|1|1|1|0|
|587.33|D3|693|1|0|1|0|1|1|0|1|0|1|

# 高精度のF-Numberテーブルを使う場合
NOTESEL=1 を選択し、A3基準のF-Numberテーブルを使います。キースケールの変化点がオクターブの中心になりませんが、NOTESELの仕様なので、諦めます。

|周波数(Hz)|音階|F-Number|D<sub>9</sub>|D<sub>8</sub>|D<sub>7</sub>|D<sub>6</sub>|D<sub>5</sub>|D<sub>4</sub>|D<sub>3</sub>|D<sub>2</sub>|D<sub>1</sub>|D<sub>0</sub>|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|440.00|A3|519|1|0|0|0|0|0|0|1|1|1|
|466.16|A#3|550|1|0|0|0|1|0|0|1|1|0|
|493.88|B3|583|1|0|0|1|0|0|0|1|1|1|
|523.25|C3|617|1|0|0|1|1|0|1|0|0|1|
|554.37|C#3|654|1|0|1|0|0|0|1|1|1|0|
|587.33|D3|693|1|0|1|0|1|1|0|1|0|1|
|622.25|D#3|734|1|0|1|1|0|1|1|1|1|0|
|659.26|E3|778|1|1|0|0|0|0|1|0|1|0|
|698.46|F3|824|1|1|0|0|1|1|1|0|0|0|
|739.99|F#3|873|1|1|0|1|1|0|1|0|0|1|
|783.99|G3|925|1|1|1|0|0|1|1|1|0|1|
|830.61|G#3|980|1|1|1|1|0|1|0|1|0|0|
Androidでアプリ内のLocaleを変更せずに他言語リソースを取得する


# はじめに

Androidで言語を切り替える場合、下記のようにActivityのattachBaseContextでlocaleを設定するのが一般的です。（API 25でupdateConfigurationはdeprecatedとなり、[createConfigurationContext](https://null-i.net/index.html?AndroidJava/%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%81%A8%E8%8B%B1%E8%AA%9E%E3%81%AA%E3%81%A9%E3%81%A7%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E3%82%8B)の利用が推奨されています。）

ですが、一つの画面に複数の言語リソースを表示したい場合や言語切替時にActivityをrecreateしたくない場合、この方法は使えません。今回は一時的に変更できるようにする方法をメモしときます。

```kotlin:MainActivity.kt
override fun attachBaseContext(base: Context) {
    val locale = Locale.ENGLISH
    val res = resources
    val config = Configuration(res.configuration)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        config.setLocales(LocaleList(locale))
    } else {
        config.setLocale(locale)
    }
    super.attachBaseContext(base.createConfigurationContext(config))
}
```

# やり方

やり方はとても簡単です。attachBaseContextでlocaleを変更したcontextを返さなければいいだけです。
まずは、言語を切替やすくするためにcreateLocalizedContextという拡張関数を作ります。

```kotlin:ContextExtention.kt
fun Context.createLocalizedContext(locale: Locale): Context {
    val res = resources
    val config = Configuration(res.configuration)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        config.setLocales(LocaleList(locale))
    } else {
        config.setLocale(locale)
    }
    return createConfigurationContext(config)
}
```

リソースファイルは日本語（default）と英語を用意。

```values/strings.xml
<string name="hello_world">こんにちは 世界</string>
```

```values-en/strings.xml
<string name="hello_world">hello world</string>
```

利用方法は下記の通り。簡単に切り替えられました。

```kotlin:MainActivity.kt
    var localizedContext = applicationContext.createLocalizedContext(Locale.ENGLISH)
    print(localizedContext.getString(R.string.hello_world))
    // hello world

    localizedContext = applicationContext.createLocalizedContext(Locale.JAPANESE)
    print(localizedContext.getString(R.string.hello_world))
    // こんにちは 世界
```