OmniAICreator/Qiita-1.07M huggingface dataset:
リザーブドキャパシティ とは

## 勉強前イメージ

キャパシティを先に予約しておく感じ？
インスタンスではなく。

## 調査

### リザーブドキャパシティ とは

DynamoDBのスループットの容量に対して発生するコストで、
3年間の契約と引き換えに最大76%の節約ができます。

### 購入方法

- DynamoDBへ移動

DynamoDBのリザーブドキャパシティへ移動し、
キャパシティの購入を行います。

![1DynamoDB · AWS Console - Google Chrome 2021-08-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/4690b2f0-6614-fa35-615c-802d20686e66.png)


- キャパシティタイプ

予約するキャパシティタイプの選択を行います。
書き込みユニットと読み込みユニットの2つ選択できます。

![2DynamoDB · AWS Console - Google Chrome 2021-08-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/abed2aae-1538-3242-b751-cfd2fcc46331.png)


- 期間

期間に関しても1年と3年の選択を出来ます。
1年間では約53%、3年間では76%の削減が期待できます。

![3DynamoDB · AWS Console - Google Chrome 2021-08-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/4d9a2b18-19c5-ea1b-b638-ffe2d82629f1.png)


- キャッパシティーユニット

キャパシティの購入単価は100となっております。

![4DynamoDB · AWS Console - Google Chrome 2021-08-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/3be14df0-4ec3-f521-ec0c-745838d406ea.png)


## 勉強後イメージ

リザーブドインスタンスのDynamoのキャパシティ版って感じかな

## 参考

- [DynamoDBのリザーブドキャパシティを購入してみた](https://dev.classmethod.jp/articles/dynamodb-reservedcapacity/)
[iOS]UICollectionViewCompositionalLayoutを使うと横スクロールのUIScrollViewDelegateが取れない問題

間違ってたらすいません
UICollectionViewCompositionalLayoutってそもそも「縦スクロール内に横スクロール」は可能だけど、「横スクロール内に縦スクロール」みたいな構成はできないんですね。
できないんですよね？
たぶんできない。

それで、UICollectionViewCompositionalLayoutを適用したUICollectionViewのdelegateを設定してUIScrollViewDelegateを取ろうとすると、縦は取れるけど横が取れない。
まあ何となく取れない気がしますよね。

問題なのは横スクロールのUICollectionViewを作りたかった場合で、UICollectionViewCompositionalLayoutを使いたい場合。

そもそもそんなシーンどれだけある？と思いますが結構あります。
１つはpagingをしたい場合です。
UICollectionViewのpagingはマジで複雑だし微調整で数日掛かります。できればUICollectionViewCompositionalLayoutでpagingしてしまいたい。
しかしそうすると「いま何ページ目か」とか「スクロールが終わったら」を取れない。

それでどうすれば良いのか調べていたら

```swift
let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
layoutSection.visibleItemsInvalidationHandler = { (visibleItems, point, env) in
    print("-------------------------")
    visibleItems.forEach { item in
        print("item: ", item.indexPath.item, point)
    }
}
```
こうやるらしいです。
visibleItems, point, env、なんか知らないclassやらprotocolがたくさん出てきて嫌な感じですが、とりあえず上記のようにするとスクロールする毎に「現在表示されているcellのindexPath」とかそのポジションが取れるので、割といいんじゃないかと思いました。

またなんかあったら追記します。

もっとちゃんと分かりやすい記事
↓
https://qiita.com/hcrane/items/92c0e08f9bf7d017f53f


追記：
いや、スクロールの終了が取れないですね。
cellのイベントは取れますが、スクロールのイベントがさっぱり取れません。

というわけでゴリ押しで内部のscrollViewのdelegateを奪ったところ、レイアウトが壊れました。
どうやらscrollViewのdelegateは既に使用されているようでした。

詰みました。

似たような質問
https://stackoverflow.com/questions/58791121/uiscrollview-delegate-methods-not-called-when-uicollectionviewcompositionallayou


追記：
諦めました。非公開クラス使いたくないし。
エンジニア未経験入社三週間目

#現在学んでいること
* Reactの基礎知識
* Netlifyを使ってのWebアプリの公開
* ReactとAPIサーバーの連携
* Herokuを使ってのAIPサーバーを公開

#三週間経っての現在の状況
入社する前まではReactの勉強はほとんどやっておらず、学んでいたことはHTMLとCSS、それとバニラでのJavaScriptだけで、
Vueは少しだけ触ってみたことがありましたが、簡単なTodoリスト（かなり時間をかけて）ぐらいしかできませんでした。

まず最初に苦戦したのが、Reactを使う上での環境構築でした。
今まではJavaScriptという環境構築も簡単にできる言語での学習をしていたため、　Node.jsを使ったことも、さらにはコマンドをパチパチ叩いたこともほとんどありませんでした。
一からパッケージをインストールして、またそのインストールしたパッケージのバージョンが違くて動かないといったことが起き、入社前に学習している上で
教えてくれるエンジニアの方が何度もおっしゃっていたバージョンの重要性をここで知りました。（それに気付かず一時間ほど頭を抱えていました。。。）
他にもJavaScriptでは、場合によってはスルーされる　.　や　;　といったタイプミスや、「とりあえず書いておこう。。」などの余計なコードが
Reactではほとんどエラーになってしまうため、よくコードを見返す癖やできるだけ綺麗にコードを書こうといった良い癖が付いたと思います。

最後に、今書いているQiitaの投稿も職場の先輩エンジニアの方にやってきたことの復習やわからない事などのアドバイス等がもらえるから、
やっといた方がいいよーとのことで始めました。
こういった投稿はあまり経験がないのですが、文章力を鍛える為にもちょくちょく投稿できたらなと思います。

初めての投稿なのでこのぐらいで。。。
WioLTE: MQTT で Subscribe したデータを表示する

フォルダー構造

```text
$ tree mqtt_subscribe/
mqtt_subscribe/
├── mqtt_subscribe.ino
├── setupLTE.ino
└── setup_mqtt.ino
```

```text:mqtt_subscribe.ino
// ---------------------------------------------------------------
/*
	mqtt_subscribe.ino

					Aug/20/2021
*/
// ---------------------------------------------------------------
#include <WioLTEforArduino.h>
#include <WioLTEClient.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <stdio.h>

#define MQTT_SERVER_HOST  "example.com"
#define MQTT_SERVER_PORT  (1883)

#define ID                "WioLTE"
#define OUT_TOPIC         "sample/imageTopic"
#define IN_TOPIC          "sample/imageTopic"

WioLTE Wio;
WioLTEClient WioClient(&Wio);
PubSubClient MqttClient;

int icount = 0;
// ---------------------------------------------------------------
void callback(char* topic, byte* payload, unsigned int length)
{
	SerialUSB.println("*** callback ***");
	payload[length] = '\0';
	String msg = String((char*) payload);
	SerialUSB.println(msg);
}

// ---------------------------------------------------------------
void setup()
{
	setupLTE();

	setup_mqtt_proc();

	SerialUSB.println("*** Setup completed *** Aug/20/2021 PM 20:20 ***");
}

// ---------------------------------------------------------------
void loop()
{
	DynamicJsonDocument doc(512);
	char data_json[128];

	if ((icount % 1000) == 0)
		{
		doc["icount"] = icount;
		doc["uptime"] = millis() / 1000;
		serializeJson(doc, data_json);

		SerialUSB.println(data_json);
		}

	MqttClient.loop();

	icount++;
}

// ---------------------------------------------------------------
```

setupLTE.ino はこちら
[UDP で温度と湿度を Harvest に送る](https://qiita.com/ekzemplaro/items/690faa6f56003272299f)

setup_mqtt.ino はこちら
[ブラウザーから MQTT Publish でブザーを鳴らす](https://qiita.com/ekzemplaro/items/4fe55f7964f7c74ac1ce)


シリアルモニタの表示

```text
20:15:22.403 -> *** Connecting to "soracom.io" ***
20:15:23.529 -> *** SetupLTE completed ***
20:15:23.529 -> *** end *** seupLTE ***
20:15:23.529 -> ### Connecting to MQTT server "example.com"
20:15:23.761 -> *** subscribe ***
20:15:23.761 -> *** Setup completed *** Aug/20/2021 PM 20:20 ***
20:15:23.761 -> {"icount":0,"uptime":14}
20:15:24.192 -> *** callback ***
20:15:24.192 -> {"buzzer":"off"}
20:15:27.180 -> {"icount":1000,"uptime":17}
20:15:30.266 -> {"icount":2000,"uptime":20}
20:15:32.389 -> *** callback ***
20:15:32.389 -> {"buzzer":"on"}
20:15:33.649 -> {"icount":3000,"uptime":24}
20:15:36.767 -> {"icount":4000,"uptime":27}
20:15:37.496 -> *** callback ***
20:15:37.496 -> {"buzzer":"off"}
20:15:39.884 -> *** callback ***
20:15:39.884 -> {"buzzer":"on"}
20:15:40.482 -> {"icount":5000,"uptime":31}
20:15:43.599 -> {"icount":6000,"uptime":34}
20:15:46.684 -> {"icount":7000,"uptime":37}
20:15:49.769 -> {"icount":8000,"uptime":40}
20:15:52.887 -> {"icount":9000,"uptime":43}
20:15:56.072 -> {"icount":10000,"uptime":46}
```
【salesforce】カスタム項目やヘルプテキストまで⁉ユーザごとに翻訳できるトランスレーションワークベンチ


この記事では、Salesforceで環境をカスタマイズする際に役立った小ネタをご紹介したいと思います。

#前置き

実は以前、トランスレーションワークベンチの[記事](https://qiita.com/Supply-net/items/5362d2606879fc0c3a88)を書いたのですが、その記事は今回のようなケースより応用的な使い方をしていることに気づきました。そのため、基本的でより使用用途が高い使い方を今回の記事では紹介していこうと思います。
※関連する過去記事はページ下部に記載しています。

#ユーザごとに自動で翻訳したい

salesforce環境では通常、ユーザの言語設定を変更すれば表示される文字はその言語に合わせたものになります。

しかし、それはsalesforceが事前に用意している標準のオブジェクトや項目だけです。
自分たちで独自に作成したカスタムオブジェクトやカスタム項目などは、作成した言語から変わりません。

つまり、日本語で作成したカスタム項目であればユーザの言語設定を英語にした時、その部分だけが日本語で表示されてしまうのです。

この問題を解決するには、「トランスレーションワークベンチ」を使う必要があります。

#実施環境

作成環境は日本語で、よく使う以下の三点を翻訳していきます。
・カスタムオブジェクト：カスタム注文
・カスタム項目：キャンセル理由
・ヘルプテキスト：注文がキャンセルされた理由

現時点の状態
![スクリーンショット (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/e4a44a3d-bd25-b9ab-16ac-8fa64f667fbe.png)

この時点ではどれも日本語で表示されています。
では、ユーザの言語を英語にしてみます。
![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/5231f93d-d2da-fe39-f0b4-95a3c786a82f.png)

![スクリーンショット (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/0fcdfc89-95a9-cfd3-d21f-cab504588294.png)
他の標準オブジェクトと違い、カスタム注文だけ日本語で表示されています。
そのレコード内も、カスタム項目だけ日本語です。

#翻訳

ではここから、実際に翻訳設定していきます。
設定方法は基本同じのため、今回はカスタム項目の翻訳を例に見ていきます。

①「設定」のクイック検索から「翻訳」を検索します。
※なおトランスレーションワークベンチの有効化は過去記事と重なるため、わからなければ[そちら](https://qiita.com/Supply-net/items/5362d2606879fc0c3a88)を参照してください。

②画像のように設定します。
![スクリーンショット (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/2b9cbce0-ef11-0d97-7190-6aef244c9a9f.png)

③設定後、項目表示ラベルの翻訳列をダブルクリックして、英語での表示を入力します。
![スクリーンショット (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/d3e2cfef-6976-9338-d170-67dcea940eba.png)

設定は以上です。
カスタム項目の翻訳ができていることを確認します。
![スクリーンショット (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/3a17c849-7935-24b9-33c9-66ab83d42e9d.png)

同じ要領でヘルプテキストなども設定していきます。
最終的にこのような画面となります。
![スクリーンショット (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/ad8c1c96-c3d1-86b3-cc99-25cf2c35e032.png)

#関連記事
[【salesforce】グローバル化！見るユーザの言語設定によって、カスタマイズしたテキストを変える方法](https://qiita.com/Supply-net/items/5362d2606879fc0c3a88)
[【salesforce】レコードページでメッセージを表示させる方法](https://qiita.com/Supply-net/items/318b3fc1471c12719baf)
【SwiftUI】Spacerの最小サイズが0にならない問題

#課題
VStackやHStack内でSpacerがある時に、ビュー一杯一杯にオブジェクトを詰め込んだ時に、Spacerの大きさが0にならないで残ってしまう

```swift
VStack {
    ZStack{}.frame(height: 50)
    Spacer() // 微妙に細く残る
    ZStack{}.frame(height: 50)
}
.frame(height: 100)
```

#解決法
### 「minLength: 0」を設定する

```swift
VStack {
    ZStack{}.frame(height: 50)
    Spacer(minLength: 0)
    ZStack{}.frame(height: 50)
}
.frame(height: 100)
```
plunkerでcssフレームワーク その14

#概要

plunkerでcssフレームワークやってみた。
bulma使ってみた。

#サンプルコード

```
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css">

```

#成果物

https://embed.plnkr.co/plunk/Qe0MJYho27o40ODD


以上。
JSON.stringifyのreplacerはtoJSON()の後で呼ばれる


`JSON.stringify` の第２引数はたいてい `null` を指定するけど、値を置換できる `replacer` 関数を指定することができる。
オブジェクトに `toJSON()` メソッドが生えていれば、それでも置換できる。
`replacer` と `toJSON` の両方を使用していた場合は、`toJSON` が先に実行される。
だから、`toJSON` 実装済クラスのインスタンスを外から `replacer` で変換することは難しい。

----

検証用コード：

```js
class Foo {
  toJSON() {
    console.log("Foo#toJSON() called");
    return "FOO";
  }
}

const data = {foo: new Foo()};

JSON.stringify(data, (key, value) => {
  console.log(`replacer(${JSON.stringify(key)}) called`);
  return value;
});
```

実行結果は以下。

```
replacer("") called
Foo#toJSON() called
replacer("foo") called
```
1行目は親オブジェクトの `replacer`、2行目は `toJSON`、3行目は Foo の `replacer`。

---
ECMAScript の仕様書にも `toJSON` が先で `ReplacerFunction` が後と定義されてる。
https://262.ecma-international.org/#sec-serializejsonproperty
![ECMA2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12419/02f24f4c-51c8-074c-3f29-8648e5036a7c.png)
---
（参考）TypeScript の `replacer` の定義：
https://github.com/microsoft/TypeScript/blob/main/lib/lib.es5.d.ts#L1052

```ts
/**
 * Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
 * @param value A JavaScript value, usually an object or array, to be converted.
 * @param replacer A function that transforms the results.
 * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
 */
stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
```
Cloud registryで権限の編集をするとCannot get legacy ACL for an object when uniform bucket-level access is enabled...となる

# はじめに

「Google Cloud実践活用術」という本を勉強していて、書籍通りにやっていたのですが権限周りでうまくいかなかったのでまとめたいと思います。

ネットで調べれば自己解決できますが、初心者向けの本ということもあり丁寧に解決方法を載せてみました。

# 問題

書籍どおりに(Appendix-Aを参考に)Cloud Storageを作成し、音声ファイルをアップロードしました。
その後で、音声ファイルの権限を編集しようとしたところ、以下のようなエラーが発生しました。

```
Cannot get legacy ACL for an object when uniform bucket-level access is enabled. Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access
```

![1629447123.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/87138f9d-c7ed-742e-5e8c-07f847a12c50.png)

書籍通りにできなかったので、解決方法をまとめます。

# 解決方法

エラーを日本語に訳してみました。

```
均一バケットレベルアクセスが有効になっている場合、オブジェクトのレガシーACLを取得できません。 詳しくはhttps://cloud.google.com/storage/docs/uniform-bucket-level-accessをご覧ください
```

均一バケットレベルアクセスが有効になっているのが原因のようです。
ここを無効にするように設定します。

まず、バケット一覧に戻ります。

![1629447349.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/48365274-0fdd-d80c-185d-43b4abc14d42.png)

確かにアクセス権限をみると`均一`となっています(右端で見切れていますが)

今回使うストレージの右端にある:(点が縦に三つ)マークを押して、`バケットの権限を編集`をクリック

![1629447465.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/0fe34d29-aaed-5497-054a-00372e4dac8c.png)


Access controlの`きめ細かい管理に切り替える`をクリックします。

![1629447510.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/ac7232a8-ba72-1cab-239d-8068b935ce42.png)

きめ細かい設定にラジオボタンを変更して保存をします。

![1629447557.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/1c577614-88a2-3ce4-186b-41f93f70b3ab.png)

このあと、先ほどの音声ファイルの権限変種をするとエントリが追加できるようになります。

![1629447636.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/8329b5d2-8d0d-ff2c-f54c-f4965fc9adf3.png)

エントリを追加するを押して書籍通りに行えます。

# おわりに

初心者向けかつ、本特有の操作で想定通りでないことが起こるとあきらめようと思ってしまいます。
せっかく始めたのですから、この記事で先に進める人がいればうれしいです。
import [ライブラリ名]で[ライブラリ名:バージョン] (/usr/local/lib/python3.7/dist-packages), Requirement.parse('ライブラリ名>=バージョン'), {'libcst'} 

# はじめに

「Google Cloud実践活用術」という本をやっていて、ライブラリのインポートでエラーがでました。
そのライブラリが環境に合っていないのではないかと疑ったのですが、自分のミスでした。

```
ContextualVersionConflict: (PyYAML 3.13 (/usr/local/lib/python3.7/dist-packages), Requirement.parse('pyyaml>=5.2'), {'libcst'})
```

というエラーが私の環境ではでています。

ライブラリ名は違えど、同じ原因でエラーがでる方いるかと思いましたのでまとめます。

# 環境
- Google Colabratory

# 問題

以下のコードを実行した際にエラーが発生しました。

```
# セル1
from google.colab import drive
drive.mount('/content/drive')

# セル2
!pip install --upgrade google-cloud-speech

# セル3 (サービスアカウントキーと音声ファイルのフォルダに移動
cd drive/MyDrive/Colab\ Notebooks/cloudspeech

# セル4 (サービスアカウントキーを環境変数に設定)
import os
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './credentials.json'

# セル5 (エラー)
from google.cloud import speech
```

エラーは以下となります。

```
---------------------------------------------------------------------------
ContextualVersionConflict                 Traceback (most recent call last)
<ipython-input-5-589439c37498> in <module>()
----> 1 from google.cloud import speech

9 frames
/usr/local/lib/python3.7/dist-packages/pkg_resources/__init__.py in resolve(self, requirements, env, installer, replace_conflicting, extras)
    775                 # Oops, the "best" so far conflicts with a dependency
    776                 dependent_req = required_by[req]
--> 777                 raise VersionConflict(dist, req).with_context(dependent_req)
    778 
    779             # push the new requirements onto the stack

ContextualVersionConflict: (PyYAML 3.13 (/usr/local/lib/python3.7/dist-packages), Requirement.parse('pyyaml>=5.2'), {'libcst'})
```

PyYAMLを3.13や5.2をインストールしたり、アンインストールしたりしたが解決できず
ネットを調べても情報が見つかりませんでした。

# 解決方法

コードの実行順序が悪いことがわかりました。

`google-cloud-speech`をインストールしたあとに、認証のためにカレントディレクトリを移動したのが原因でした。

以下のコードで動くようになりました。

```
# セル1
from google.colab import drive
drive.mount('/content/drive')

# セル2 (サービスアカウントキーと音声ファイルのフォルダに移動
cd drive/MyDrive/Colab\ Notebooks/cloudspeech

# セル3
!pip install --upgrade google-cloud-speech

# セル4 (サービスアカウントキーを環境変数に設定)
import os
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './credentials.json'

# セル5 
from google.cloud import speech
```

ライブラリをインストールする前に、ディレクトリを移動すれば問題ありません。

# おわりに

いままでやったことのないミスだったのですが、初心者の方などはやってしまうのかなと思いましたので一応まとめてみました。ライブラリ名を入れてしまったので記事にたどり着く人は少ないかと思いますが、誰かの役に立てばと思います。
PHP 文字列を分解して配列にする

# 目的

- str_split()メソッドを使って文字列を配列に変換する方法をまとめる

# 方法

- 下記のように記載することで文字列を区切って配列にする事ができる。

    ```php
    str_split(文字列, 文字列から切り出す文字数)
    ```

# 例

- 「abcde」という文字列を一文字毎に切り出し配列に格納する

    ```php
    $array = str_split('abcde', 1);
    var_dump($array);
    ```

- 下記のように出力される。

    ```
    array(5) {
      [0]=>
      string(1) "a"
      [1]=>
      string(1) "b"
      [2]=>
      string(1) "c"
      [3]=>
      string(1) "d"
      [4]=>
      string(1) "e"
    }
    ```

# 参考文献

- [https://www.php.net/manual/ja/function.str-split](https://www.php.net/manual/ja/function.str-split)
【iOS15】通知許可ダイアログの「時刻指定要約で許可」の状態を取得する

#はじめに
iOS15からNotification Summaryという機能が追加される。
それに伴い、設定アプリの通知設定画面に「時刻指定要約」という項目が追加された。
「時刻指定要約」をONにした場合、↓のように通知許可ダイアログに「時刻指定要約で許可」という項目が表示されるようになる。

|時刻指定要約ON|時刻指定要約OFF|
|--|--|
|![IMG_0124.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237700/e6d83abd-20f9-9a87-2f6a-e1d020a3f3ec.png)|![IMG_0125.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237700/3ca87ed1-3ba0-a755-d693-358347675467.png)|

ユーザが「時刻指定要約で許可」をタップしたかどうかで処理を分岐する場合もあるため、その判定方法を記載する。

#判定方法
`UNNotificationSettings`にiOS15から追加された`scheduledDeliverySetting`を使用する。

```Swift
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
    if error != nil {
        // エラー
    }
    if granted {
        // 通知許可
    }
    notificationCenter.getNotificationSettings { settings in
        switch settings.scheduledDeliverySetting {
        case .enabled:
            print("許可")
        case .disabled:
            print("許可されてない")
        case .notSupported:
            print("サポートされてない")
        }
    }
}

```

#注意点
- 「時刻指定要約で許可」をタップしない限り`.enabled`にならず、通常の「許可」をタップした場合は`.disabled`になる。
- 「時刻指定要約で許可」をタップしても`UNNotificationSettings.authorizationStatus`は`.authorized`となっており、処理を分ける場合は注意が必要である。

#終わりに
ユーザが誤って「時刻指定要約で許可」を押した場合、通知によっては即時に届かなくなるため、通知許可ダイアログを表示する際に何かしら配慮をした方がいいかもしれない。
また、「時刻指定要約で許可」を選択した状態で`Interruption levels`が`Active`（defaultのlevel）の通知だと常に即時通知されないようになってしまう。そのため、必要に応じて`Interruption levels`を`Time Sensitive`以上にする対応も必要である。

##参考

https://developer.apple.com/documentation/usernotifications/unnotificationsettings/3747263-scheduleddeliverysetting

https://developer.apple.com/videos/play/wwdc2021/10091/

https://qiita.com/haseken_dev/items/36035b3d86fe0191e30b#411-passivenew
LINUX　ファイル操作コマンド

###初めに
LINUXファイル操作コマンド。
LPICレベル1基準

###IS
ディレクトリやファイルの情報を確認する。

`ls [オプション] [ファイル名 or ディレクトリ名]`

|オプション|説明|
|--|--|
|-a|「.」から始まるファイルも表示する|
|-A|「.」から始まるファイルも表示するが、カレントディレクトリと親ディレクトリは非表示|
|-d|ディレクトリ自身の情報を表示する|
|-F|ファイルの種類も表示する。ディレクトリは「/」、実行ファイルは「*」、シンボリックリンクは「@」|
|-i|iノード番号を表示する|
|-l|ファイルの詳細情報を表示する|
|-t|日付順に表示する|
|-h|単位付きで表示する|

###cp
ファイルやディレクトリをコピーする

`cp [オプション] コピー元　コピー先`

|オプション|説明|
|--|--|
|-f|コピー先に同名ファイルがある場合、上書きする|
|-i|コピー先に同名ファイルがある場合、上書きするか確認する|
|-p|コピー元ファイル属性を保持したままコピーする|
|-r, -R|ディレクトリ内を再帰的にコピーする|
|-d|シンボリックリンクをシンボリックリンクとしてコピーする|
|-a|できる限り元ファイルの構成と属性をコピー先でも保持する|

###mv
指定ファイルやディレクトリを移動する

`mv 移動元 移動先`

|オプション|説明|
|--|--|
|-f|移動先に同名フィルがあれば上書きする|
|-i|移動先に同名ファイルがある場合、上書きするか確認する|

###mkdir
ディレクトリを作成する

|オプション|説明|
|--|--|
|-m|指定したアクセス権で作成する|
|-p|親ディレクトリも同時に作成する|

###rm
ファイルやディレクトリを削除する

|オプション|説明|
|--|--|
|-f|確認無しに削除する|
|-i|削除前に確認する|
|-r,-R|サブディレクトリを含めて再帰的に削除する|

###rmdir
空のディレクトリを削除する。ディレクトリ内に何かあると削除できない

|オプション|説明|
|--|--|
|-p|複数階層のディレクトリを削除する|

###touch
ファイルのタイムスタンプを更新する。
ファイルの新規作成時にも便利
※引数で指定したファイルが無い場合は新規作成される。

・書式
`touch [オプション] ファイル名`

|オプション|説明|
|--|--|
|-t|タイムスタンプを指定時刻に更新|
|-a|アクセス時刻だけ更新|
|-m|修正時刻だけ更新|

※時刻フォーマット
CC:西暦上2桁
YY:西暦下2桁
MM:月
DD:日
hh:時
mm:分
ss:秒

###file
ファイル種別を表示する
どんなファイルかわからない場合に使用する

書式　`file ファイル名`

例
[root@localhost ~]# file /etc/hosts
/etc/hosts: ASCII text

###メタキャラクタの使用
パターンに一致するファイル等検索するときに

|メタキャラクタ|説明|
|--|--|
|*|0文字以上の文字と一致する|
|?|任意の1文字と一致する|
|{任意文字}|{}で指定された文字のいずれかに一致する。test{1,2}だと、test1、test2がヒットする|

###履歴
2021/8/20 作成
AWS構成図を作成し、サーバー周りについて初心者なりにまとめてみました・・・。

<h2>AWS構成図</h2>

今回AWS構成図というものを作ってみました。
ポートフォリオをデプロイしてみたものの、正直何をやってるのか・・・・
「私は今一体何を立ち上げているのか・・・」状態だったので、
基本を勉強しつつ、以下の表が何なのかわかるように、
まとめていきたいと思います。
サーバー周りはとても難しく感じます。:fearful:

![スクリーンショット 2021-08-20 17.05.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/0ef6c701-e78f-0dce-3d60-eb9aa5bd5adc.png)

<h2>まずは基礎知識の確認　</h2>

<h4>サーバーについて</h4>
:fist:サーバーって何？
→
サービスを提供するコンピュータのこと

:fist:WEBアプリケーションで必要になるサーバーは？
→
WEBサーバー、APサーバー、DBサーバー

:fist:WEBサーバーって何？
→
WEBクライアントのリクエストを受け取り、静的コンテンツを配信したり、
動的処理が必要なものであれば、APサーバーに処理を依頼し、
動的→静的になったものをWEBクライアントに渡す。

:fist:APサーバーって何？
→
アプリケーションサーバーのことで、WEBサーバーから送られてきたデータを
プログラムを実行したのちに、WEBサーバーに返す。

:fist:DBサーバーって何？
→
APサーバーが処理に必要なデータを持っている。
APサーバーのリクエストに対し、該当のデータを渡す。

:bangbang:上記の３つサーバーの連なりが、
「Websプリケーションの三層構造」と言われるやつです。

ここまでは、なんとか理解できました。

<h4>サーバーの中身というか成り立ち</h4>

下記のような４層構造になっています。

[アプリケーション]
[ミドルウェア]
[   OS 　　　 ]
[ハードウェア]

「OS」とは、オペレーティングシステムです！
OSというとよくわかりませんが、オペレーティングシステムというと理解しやすいです。
WindowsかLinuxのどちらかになりますが
Linuxの使用が多いのではないかと思います。

[ミドルウェア]OSとアプリケーションの中間に位置するプログラムを、
ミドルウェアと言います。
WEBサーバーやAPサーバー、DBMSなどがこれにあたります。
WEBサーバー達は以下のように位置するということですね・・・


![スクリーンショット 2021-08-20 18.40.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/3ade8dbc-e030-f2bf-b3c3-43a1d1522fbe.png)

今回選定したミドルウェアは、
WEBサーバーが、nginx（エンジンエックス）で、
APサーバーはPUMA
DBサーバーは、MYSQLです。

うーーん。難しい。

<h2>表にそって処理を見ていく...</h2>

いよいよ一番上の表です。

まずユーザーがやるのは「HTTPリクエスト」です。
このページ見せて！というリクエストです。

さて、これを受け取るのは誰かというと・・・
<h6>WEBサーバーです！</h6>
そして今回選定されてるWEBサーバーはNGINXなので、
NGINXに対してリクエストが送信されます。
しかしながら、NGINX静的処理しかできません・・・。

なので動的処理が来た場合に呼ぶのは、
<h6>APサーバーです！</h6>
NGINX「PUMAさん！動的処理できないのでヘルプお願いします！！！」
→このNGINXの働きをリバースプロキシというそうです。

そしてPUMAはrailsにリクエストの内容を伝え処理をしてもらいます。
（※PUMAとrailsの間には、Rackという通訳みたいな仕組みが存在しているそうです。）

適宜アクセスするのが、
<h6>データベースサーバーです！</h6>

処理が終わったらrailsはPUMAへ動的→静的にしたコンテンツを
返却します。

さらにPUMAは静的ファイルをNIGNXし、NGINXはレスポンスを返し、
表示されると。

<h2>終わりに</h2>
正直、理解がまだまだな部分です。
色々と閲覧し、自分が理解できる範囲でまとめてみました。

<h2>参考にしたところ</h2>

youtubeの動画が開きますのでご注意ください。

https://www.youtube.com/watch?v=cxX0r-ylLSE

https://qiita.com/mi-1109/items/a8e5cfa0637ba2925b59
１ファイルのHTML(+JavaScript)で、QRcodeを生成する #８つのマスクパタン対応



#１ファイルのHTML(+JavaScript)で、QRcodeを生成する
→　８つのマスクパタン対応

#実際のふるまい（動くものはこちら）

http://thomas.cranky.jp/js_QR/QRcode_javascript40x16_v2.html


注）本来、QRコード生成時、マスクパタンを手動で選ぶ、ということはないです。以下、参照。

JIS X0510 p.16
>7 要求事項　7.1 符号化手順概要
>手順6　マスク処理
>シンボルの符号化領域にマスク処理パターンを適用する。明及び暗の
>モジュールバランスを最適にし、また、望ましくないパターン
>の出現を最小限に抑えるパターンを評価し、選択する。

p.53
>表11－マスク処理結果の失点

#ソース

https://github.com/santarou6/QRcode_javascript/blob/main/QRcode_javascript40x16_v2.html



#マスクパタン選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107418/1fe47187-5865-f066-d37a-79580294ec90.png)


参考）
構造的連接で、複数のQRコードを読み込むとき、読み込めないQRコードがあることがある。
マスクパタンを変えて、QRコードを生成することで、読み込める場合がある。
（再生成した場合も、ｎ番目のＱＲコードの中身は変わらない。適用されたマスクパタンが違うだけ。）


#８つのマスクパタンのイメージ

QRコードの８種類のマスクを図示する
https://qiita.com/santarou6/items/f254f9fa5ea32d83ae27


#過去投稿

https://qiita.com/santarou6/items/baedd6ab5448aae5c1cf

https://qiita.com/santarou6/items/db17788158dba38f3a5c
DockerBuild実行時にsecret情報などをイメージに乗らせないようにする


## 参考
https://docs.docker.jp/develop/develop-images/build_enhancements.html

## 概要
- 一時的に扱うような資格情報とかを隠すことができる
    - というのは、DockerBuildが走る際にローカルマシンのファイルからSecret扱いでDockerfileに渡る
    - Biild時にはそのSecretが出力されるものの、/run/secret/の下にファイルが作成され、ビルドイメージには乗ってこない
    - Buildkitという機能らしい

## 準備

```mysecret.txt
WARMACHINEROX
```

```Dockerfile
# syntax=docker/dockerfile:1.2

FROM alpine

# shows secret from default secret location:
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret

# shows secret from custom secret location:
RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
```

## ビルド
```bash
DOCKER_BUILDKIT=1 docker build --no-cache --progress=plain --secret id=mysecret,src=mysecret.txt .
```

出力結果

```
#1 [internal] load build definition from Dockerfile
#1 sha256:8f00e80f65067d1c0d41665d67203cb5237148731db94e875148cd4cc66f5ec0
#1 transferring dockerfile: 38B done
#1 DONE 0.0s

#2 [internal] load .dockerignore
#2 sha256:a8882e94112cddc2da76edbd0f503b77bfa68c7d466b1ab0b3d9c3db28cc0827
#2 transferring context: 2B done
#2 DONE 0.0s

#3 resolve image config for docker.io/docker/dockerfile:1.2
#3 sha256:b239a20f31d7f1e5744984df3d652780f1a82c37554dd73e1ad47c8eb05b0d69
#3 DONE 1.4s

#4 docker-image://docker.io/docker/dockerfile:1.2@sha256:e2a8561e419ab1ba6b2fe6cbdf49fd92b95912df1cf7d313c3e2230a333fdbcc
#4 sha256:37e0c519b0431ef5446f4dd0a4588ba695f961e9b0e800cd8c7f5ba6165af727
#4 CACHED

#5 [internal] load metadata for docker.io/library/alpine:latest
#5 sha256:d4fb25f5b5c00defc20ce26f2efc4e288de8834ed5aa59dff877b495ba88fda6
#5 DONE 0.0s

#8 [1/3] FROM docker.io/library/alpine
#8 sha256:665ba8b2cdc0cb0200e2a42a6b3c0f8f684089f4cd1b81494fbb9805879120f7
#8 CACHED

#6 [2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
#6 sha256:75601a522ebe80ada66dedd9dd86772ca932d30d7e1b11bba94c04aa55c237de
#6 0.294 WARMACHINEROX
#6 DONE 0.3s

#7 [3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
#7 sha256:a1db940558822fcffbe7da0dc8b9f590a2870c01ea3a701051b7ce68412dc694
#7 0.346 WARMACHINEROX
#7 DONE 0.4s

#9 exporting to image
#9 sha256:e8c613e07b0b7ff33893b694f7759a10d42e180f2b4dc349fb57dc6b71dcab00
#9 exporting layers 0.0s done
#9 writing image sha256:d1523144da7a5f64952edcec97e950e70432b7bb7c2115eccd17d445ed0c2a92
#9 writing image sha256:d1523144da7a5f64952edcec97e950e70432b7bb7c2115eccd17d445ed0c2a92 done
#9 DONE 0.0s
```
AtCoder Beginners SelectionをPythonで実装してみた。

# 目的
本記事は、自身のAtCoderで実装能力を可視化するために備忘録として残していくためのものなのであしからず。初心者なので実装が拙いのはご容赦ください。

#模範解答

https://delta114514.hatenablog.jp/entry/2018/03/15/014555

https://qiita.com/drken/items/fd4e5e3630d0f5859067

# [Product](https://atcoder.jp/contests/abs/tasks/abc086_a)

```python
# -*- coding: utf-8 -*-
a,b = map(int,input().split())

if (a*b)%2 ==0:
  print("Even")
elif (a*b)%2 == 1:
  print("Odd")
```

#[Placing Marbles](https://atcoder.jp/contests/abs/tasks/abc081_a)

```python
s = input()
print(sum([int(i) for i in s]))
```
#[Shift only](https://atcoder.jp/contests/abs/tasks/abc081_b)

```python
N = int(input())
a = list(map(int,input().split()))

def counter(i):
    c_ = 0
    while i%2 == 0:
        i  = i//2
        c_ = c_ +1
    return c_

c = [counter(a[i]) for i in range(N)]
count = min(c)
print(count)
```

# [Coins](https://atcoder.jp/contests/abs/tasks/abc087_b)

```python
A = int(input())
B = int(input())
C = int(input())
X = int(input())

counter = 0
for ia in range(A+1):
    for ib in range(B+1):
        for ic in range(C+1):
            x = 500*ia + 100*ib + 50*ic
            if X == x:
                counter = counter + 1

print(counter)
```

# [Some Sums](https://atcoder.jp/contests/abs/tasks/abc083_b)

```python
N,A,B = map(int,input().split())

number = []

for i in range(N):
    n = i+1
    n_ = sum([int(i) for i in str(n)])
    if n_ >= A and B>=n_:
        number.append(n)

print(sum(number))
```

# [Card Game for Two](https://atcoder.jp/contests/abs/tasks/abc088_b)

```python
N = int(input())
a = list(map(int,input().split()))

alice_selct = []
bob_selct = []

def Alice_selector(a,alice_selct):
    i = max(a)
    a.remove(i)
    alice_selct.append(i)
    return a,alice_selct

def Bob_selector(a,bob_selct):
    i = max(a)
    a.remove(i)
    bob_selct.append(i)
    return a,bob_selct

for i in range(N):
    if len(a) != 0:
        a,alice_selct = Alice_selector(a,alice_selct)
    else:
        break
    if len(a) != 0:
        a,bob_selct = Bob_selector(a,bob_selct)
    else:
        break
    
print(sum(alice_selct)-sum(bob_selct))
```

# [Kagami Mochi](https://atcoder.jp/contests/abs/tasks/abc085_b)

```python
N = int(input())
d = []
for i in range(N):
    d.append(int(input()))
print(len(set(d)))
```

#[Otoshidama](https://atcoder.jp/contests/abs/tasks/abc085_c)

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

status = 0
for ix in range(N+1):
    for iy in range(N+1-ix):
        iz= N - ix - iy
        y = 10000*ix + 5000*iy + 1000*iz
        if y == Y:
            status = 1
            
        if status == 1:
            break
    if status == 1:
        break
        
if status == 0:
    print("-1 -1 -1")
else:
    print(ix,iy,iz)
```

# [白昼夢](https://atcoder.jp/contests/abs/tasks/arc065_a)

```python
S = input()


S=S.replace("eraser","")
S=S.replace("erase","")
S=S.replace("dreamer","")
S=S.replace("dream","")

if len(S) == 0:
    print("YES")
else:
    print("NO")
```
M1-MACでzsh: command not found

# はじめに
M1のMacbookAirにbrewでzshのパスが変わったためエラーが出たのでメモ

# 変更

```
% echo $SHELL
/usr/local/bin/zsh
```

M1Mac

```
% echo $SHELL
/opt/homebrew/bin/zsh
```

# 修正

## zshrcを変更

.zshrcにパスを追加

```
% vim ~/.zshrc
```

```
export PATH=/opt/homebrew/bin:$PATH
```

## シェルを変更

```
% cash -s /opt/homebrew/bin/zsh
```

# 終わりに
M1Macでdotfile系を反映するとエラーが結構出る。。
【BigSur】 アプリケーションを開くためのアクセス権限がありません。の対処法（その2）

# はじめに

BigSurになってからいつの日か、`アプリケーション"pcbnew.app"を開くためのアクセス権限がありません。` エラーが出るようになり**pcbnew**の単独起動ができなくなった。KiCadからのpcbnewは起動できるので、その時は対処せず放置していた。今回、pcbnewの単独起動が必要になりネットをググって対処法を見つけたので、ここにまとめておきます。

![スクショ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/4fb61217-75d5-c3f8-a319-10f777978564.png)

私のMacはインテルMacなので、シリコンMacでは発生しない可能性はある。
（BigSurはシリコンMacに最適化されたようで、私のインテルMacはBigSurにアップしてから様々な不具合が発生するようになった(泣)）

# 対処法を探す

ネットをググって最初に辿り着いたのは、下記のQiita記事であった。

https://qiita.com/tokiyan/items/6170afce9e02827a740f

コード署名したが現象は変わらず。一旦削除して再実行するも結果は同じ。

```shell
codesign --remove /Applications/KiCad/pcbnew.app
codesign --force --deep --sign - /Applications/KiCad/pcbnew.app
```

ターミナルからコマンド`open -a /Applications/KiCad/pcbnew.app`で起動してみると、下記のエラーであることが分かった。

> The application /Applications/KiCad/kicad.app/Contents/Applications/pcbnew.app cannot be opened for an unexpected reason, error=Error Domain=NSOSStatusErrorDomain Code=-10826 "**kLSNoLaunchPermissionErr**: User doesn't have permission to launch the app (managed networks)" UserInfo={_LSFunction=_LSLaunchWithRunningboard, _LSLine=2561, NSUnderlyingError=0x7fb88a41f620 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x7fb88a420260 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed with error: 111}}}}}

- [kLSNoLaunchPermissionErr](https://developer.apple.com/documentation/coreservices/3074489-anonymous/klsnolaunchpermissionerr)：The user doesn’t have permission to launch the app on a managed network.（Google翻訳：ユーザーには、管理対象ネットワークでアプリを起動する権限がありません。）

`kLSNoLaunchPermissionErr`をネットでググって辿り着いたのは、下記の記事である。

**Big Sur Problem?: "You do not have permission to open the application**

https://developer.apple.com/forums/thread/666611


```shell
xattr -rd com.apple.quarantine /Applications/KiCad/pcbnew.app
```
上記コマンドで無事に起動できるようになった。
**com.apple.quarantine**属性を削除したのだと思うが、これはネットからダウンロードしたファイルを開いたときに、確認ダイアログを出す属性ではなかったかな？

理屈はよく分かりませんが、目的を達成できたので良しとします。
同じ現象に悩んでおられる方の参考になれば幸いです。

以上
Laravelで非同期メール送信

#概要（仕事をTODOリスト(Queue)に入れて、下請け業者(Worker)に投げる）

メール処理は大変重く、同期処理(Sync)で捌くと、Viewの読み込みに多くの時間が必要になる。

__同期：アクション読み込み→メールJob→Viweの読み込み→画面の表示__
__非同：アクション読み込み→メールJobをqueueに保存→Viweの読み込み→画面の表示__
　　　　　　　　　　　　　　　　　　　　　　　　　__→WorkerがバックヤードでメールJobの処理__

・テストメールサーバーを用意する。
・メール送信機能を搭載する。
・非同期通信をオンにする。
・Queueを有効にする（データベースを作る）。
・workerをオンにして、Queue内のtaskを処理する。

#テストメール

mailtrapを使用する。

https://mailtrap.io/inboxes

Mybox内のingrationからLaravelを選択する。
![スクリーンショット 2021-08-20 18.26.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620852/cddac47b-6168-2493-7d63-2fddc31b1082.png)

以下の記述を丸ごとコピーして、プロジェクト内の.envへ

```.txt
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=***USERNAME***
MAIL_PASSWORD=***PASSWORD***
MAIL_ENCRYPTION=tls
```

#.env記述（メーラーも非同期もまとめて記述）

```..env
# 非同期処理　記述
QUEUE_CONNECTION=database

# メーラー機能　記述
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=***USERNAME***
MAIL_PASSWORD=***PASSWORD***
MAIL_ENCRYPTION=tls
#　送信元メールアドレス
MAIL_FROM_ADDRESS=sample@sender.com
```

 .envを触った後は、一応キャッシュをクリア

```.bash
php artisan config:cache
```

#メーラー設定

```.bash
php artisan make:mail SampleMail
```

メール発火機能を入れたい任意のコントローラ

```Controller.php
:
:
//クラスの宣言
use Illuminate\Support\Facades\Mail;
use App\Mail\SampleMail;
:
:


//メールを発火させたいアクション内に、以下を記述する。
public function index{
:
:
  SendSampleMail::dispatch();
:
:
}
```

#非同期設定（Queue設定）

```.bash
//仕掛りJobを保存するための、Queueテーブルを作成する。
php artisan queue:table
php artisan migrate

//仕掛りJobを保存するための機能を作成
php artisan make:job SendSampleMail
```

```Controller.php
:
:
//ジョブのクラスの宣言
use App\Jobs\SendSampleMail;
:
:
```

```SendSampleMail.php
:
:
//メーラーのクラスの宣言
use Illuminate\Support\Facades\Mail;
use App\Mail\SampleMail;
:
:

    public function handle()
    {
        // Mail::to('送信先メールアドレス')
        //以下のメール送信JobをQueueのテーブルに保存しますという処理
        Mail::to('sample@reciever.com')->send(new SampleMail());
    }
:
:
```

#Workerを有効化

以下のコマンドでWorkerを起動させれば、Queueテーブルから、仕掛りJobを実行してくれる。
この時、PHP MyAdminを見れば分かるが、保存されているJobが終わり次第テーブルから削除されているのが分かる。

```.bash
php artisan queue:work
```
PNG 画像のガンマ補正

# はじめに

PNG はディスプレイガンマを意識した画像ファイルフォーマットです。メタデータにガンマ補正の値を含める事ができます。
そのメタデータとしてのガンマ補正を解説します。

ガンマ補正自体の解説はこちらをどうぞ。

- ガンマ補正のうんちく 
  - https://qiita.com/yoya/items/122b93970c190068c752

<img width="50%" alt="gammma_transfer.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/ae978465-03fb-5267-932a-effcf54bc137.png"> <img width="25%" alt="gamma_graph.png" src="https://qiita-image-store.s3.amazonaws.com/0/1798/cf69d5c8-6105-85ee-926a-ea01a3cb146f.png">

# PNG のガンマ値

PNG ファイルは内包する RGB データのリニア輝度からのガンマ補正値を、メタデータとして持つ事ができます。
ファイル形式では gAMA チャンクが相当します。ImageMagick の identify で確認できます。

```shell
% identify -verbose sample.png | grep gamma
    png:gAMA: gamma=0.45455 (See Gamma, above)
```

## 歴史的な事情

今どきのプラットフォームでは画像のRGB値と物理的な色の対応を sRGB規格に合わせる事が多いです。
そのsRGBによる輝度変換はガンマ(γ, gamma)変換の係数"2.2"でおよそ近似できます。

- https://www.w3.org/Graphics/Color/sRGB.html

ところが環境によってこのガンマ値が異なる可能性があり、今となっては古い例ですが、Macintosh がガンマ1.8環境だった頃に、Windows で作った画像ファイルを Macintosh で表示すると色の明るさが微妙に変わってしまいました。

<img width="50%" alt="PNG-NoGamma.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/975300ff-2655-8942-074f-f2597b145fbb.png">

そこで、PNG ファイルのメタデータである gAMA チャンクに 1.0/2.2 を書き置く事で、他の OS (PNG 仕様策定当時のガンマ値が違う環境だと Macintosh, SGI IRIX、 NeXT 等) で表示する際に、その gAMA 値で補正すれば物理的に同じ明るさの色が表示できる。といった仕組みです。

<img width="50%" alt="PNG-gAMA.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/8c0c5bf5-7f09-e8f1-0ef9-f3b62c4d3675.png">

ただし、gAMA チャンクによる輝度補正だと雑になるので、正確に色を再現したい場合は sRGB チャンクや iCCP チャンクを使うよう PNG仕様に書かれています。
gAMAチャンクはもはや歴史的な遺物と言いたい所ですが、仕様として残っているので今でもエンコーダ、デコーダ共に対応する必要がありますし、今時のエンコーダでも gAMA チャンクが入る事が多いです。

## gAMA がない場合

gAMA, sRGB, iCCP チャンクのいずれもない PNG ファイルの RGB ガンマ値(正確には表示階調特性,EOTF)は実は環境依存です。なので、その場合は PNG ファイルがどの環境で作られかに合わせて、表示する際に補正する必要があるのですが、現実的でないので、通常は 1.0/2.2 決め打ちで処理する事が多いはずです。

# 備考

画像ビューア(ブラウザ含む)によっては gAMA を無視したり、カラー画像では使うけどグレースケールは無視とか、16bit は駄目、変換時に中途半端に使われる等といった不具合に散々悩まされてきました。
gAMA には1.0/2.2 しか入れないよう運用するのが無難でしょう。

# 参考

- http://www.libpng.org/pub/png/spec/pngspec-index.html
  - http://www.libpng.org/pub/png/spec/1.2/png-1.2.pdf
  - http://www.libpng.org/pub/png/spec/1.2/PNG-GammaAppendix.html
- libpng1.2.8   libpng.txt  訳
  - http://dencha.ojaru.jp/programs_07/pg_graphic_10_libpng_txt.html
Rails アソシエーション作成時のFK自動付与について

model作成を行い、アソシエーションで関連付けを行うと、自動的にFK(外部キー)が付与される。
この規則について考える

User モデルとPostモデルを作成しUserモデルとPostモデルは一対多の関係にあるとする

（userモデルに対するpostモデルのFKはuser_id)
（postモデルに対するuserモデルのFKはuserモデルのPK(主キー))

![Screenshot from 2021-08-20 18-44-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512448/22587b3e-5986-f7f2-de80-4c31683870cf.png)

画像汚くてすみません。

以下　コード例


```user.rb
has_many :posts
```


```post.rb
belongs_to :user
```

postモデルのbelongs_to :user　から考えると、belongs_to でpostの1レコードに対し必ずuserモデルの主キーは存在する。
そのため、post.rbに　belongs_to :userと記載することでbelongs_to :モデル名のモデル名を元にして、そのモデルのPKをFKと認識する。


一方,
userモデルのhas_many :posts　から見ると参照すべきカラムはPKではない。userモデルの1レコードに対し必ず対応すべきなのはpostモデルでFK用に作成したカラムのuser_idとなる。
そのため、user.rb にhas_many :postsと記載すると、自身のモデル名（今回だとuser）を元に参照先モデルのカラムを探しにいき、(自身のmodel名)_id　と一致するカラムをFKと認識する。


【まとめ】
has_manyでは（自身のモデルの名前）_idというカラムを参照先モデルの中から探し、FKとする。
belongs_toでは参照先モデルのPKをFKとする。

間違えていたらコメントください。
[Elixir] Phoenix 1.6.0-devのプロジェクトを作成できるようにする

__※2021年8月20日現在の情報です__

Phoenixの最新バージョンは1.5.10ですが、GitHubのリポジトリを見ると1.6.0-devが出ています。

https://github.com/phoenixframework/phoenix/blob/master/CHANGELOG.md#160-dev

- `mix phx.gen.auth` の追加
- webpack から esbuild への移行

などなど、魅力的なバージョンアップなので、ぜひ試してみたいですよね :sparkles: 
しかし、残念ながら [hex.pm](https://hex.pm/packages/phoenix) には1.6.0-devは出ていません :cry: 

そこで、Phoenixのソースでインストーラをビルドし、1.6.0-devのPhoenixプロジェクトを作成、起動してみます。環境の差異を考慮するのが面倒なので、Dockerを使います。

# `phx_new` をインストール

https://github.com/phoenixframework/phoenix/tree/master/installer

READMEにphx_newのインストール手順が書かれていますが、まっさらな環境の場合はuninstallは不要です。

途中、Yes/Noを何度か聞かれますが、すべてYesで問題ありません。

```sh
$ docker run --rm -it -p 4000:4000 elixir:1.12.2-alpine sh
# 以下、コンテナ内
$ apk add git
$ git clone https://github.com/phoenixframework/phoenix.git
$ cd phoenix/installer
$ MIX_ENV=prod mix do archive.build, archive.install
```

これで、 `mix phx.new` が実行できるようになりました :tada: 

```sh
$ mix phx.new -v
```

```:実行結果
Phoenix installer v1.6.0-dev
```


# Phoenixプロジェクトを作成する

`phx_new` をインストールできれば、あとは `mix phx.new` でPhoenixプロジェクトを作成するだけです。

```sh
$ mix phx.new /sample --live --no-ecto
```

`/sample` に1.6.0-devのPhoenixプロジェクトが作成されます。

# Phoenixプロジェクトを起動する

依存ライブラリはすでにインストールされているので、このまま起動したいところですが、 `MIX_ENV=dev` の環境ではデフォルトで `127.0.0.1` しか受け付けないようになっています。このままだと、Dockerを使っている場合、起動してもブラウザからアクセスできないため、 `config/dev.exs` を以下のように書き換えます。

```diff_elixir:config/dev.exs
config :sample, SampleWeb.Endpoint,
  # Binding to loopback ipv4 address prevents access from other machines.
  # Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
- http: [ip: {127, 0, 0, 1}, port: 4000],
+ http: [ip: {0, 0, 0, 0}, port: 4000],
```

それでは、起動してみましょう。

```sh
$ mix phx.server
```

http://localhost:4000/dashboard/home にアクセスすると、Phoenix LiveDashboardが表示されるはずです。
![Phoenix-LiveDashboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28249/d199a98d-abc8-3b4d-a470-5939183d3b91.png)
いいですね〜 :heart: 

# 最後に

ここまで注意深く見ていただいた方は分かるかと思いますが、Phoenixアプリを起動するまでにNode.jsをインストールしていません。webpackからesbuildに移行したことで、Node.jsが必須ではなくなりました。まあ、npmを使いたい場合は結局必要にはなりますが…

1.6.0の正式リリースが待ち遠しいですね！
Nuxt BuefyのグローバルCSS汚染を防ぐ

css統合用のmain.scssを作成。
nuxt-buefyの[options](https://github.com/buefy/nuxt-buefy#options)からcssの適用をfalseにします。


```javascript:nuxt.config.js
  css: ['~/assets/scss/main.scss'],

  modules: [
    [
      'nuxt-buefy',
      {
        /* buefy options */
        css: false,
      },
    ],
  ],
```
グローバルcssを何かしらのクラスでラップします。
（今回は.bulmaというクラスを使います。）
.bulma クラス配下にbulma,　buefyのcssが展開されるようにimportします。

```scss:~/assets/scss/main.scss
// bulma
.bulma {
  @import '~bulma/bulma.sass';
  @import '~buefy/src/scss/buefy.scss';
}
```
buefyを使用するコンポーネントのrootに.bulmaクラスをつけることで
コンポーネント内部にのみbulma・buefyのcssが適用されます。

```vuejs:temp.vue
<template lang="pug">
  div.bulma
    b-field.grouped
      ~~
```
【Draft.js】Editorコンポーネント・EditorState

# 基本要素
- Draft.jsは大きく以下の２つの要素に分けられる
  - Editorコンポーネント
  - EditorStateオブジェクト

## Editorコンポーネント
- ContentEditableなDOMを管理するコンポーネント
- `EditorState` オブジェクトをpropsとして持つ
- 下記の例では `onChange` によって `EditorState` が更新される

```.tsx
import { Editor, EditorState } from 'draft-js';
import * as React from 'react';

interface Props {
  editorState: EditorState;
  onChange: (editorState: EditorState) => void;
}

const RichTextEditor: React.FC<Props> = (props: Props) => (
  <Editor editorState={props.editorState} onChange={props.onChange} />
);

export default RichTextEditor;
```

## EditorState
- Editor全体の状態を表すトップレベルのオブジェクト  
  **（例）** 文章・カーソル状態
- 以下の情報を持つ
  - 現在の入力されているtext contentの情報（**ContentState**）
  - コンテンツのスタイリングのルール
  - 現在のカーソル位置・選択範囲の情報（**SelectionState**）
  - Undo/Redoのスタック
  - 最新のコンテンツに対して行った変更の種類
Python/pandas DataFrameにて、特定の文字列以降を抽出する方法


調べてみると、意外に適したものがなかったので、メモ。

pandasのdataFrameの特定カラム（URL）があったとして、ここから'?'以降を抽出する方法
'https://dummy.com/index2.html?abc=1' 

▼サンプルのデータ

```python
import pandas

my_dict =  {'A': [1, 2, 3, 4, 5], 'url': ['https://dummy.com/index.html', 'https://dummy.com/index2.html?abc=1', 'https://dummy.com/index2.html?def=2', '', 'https://dummy.com/index2.html?abc=1']}
df = pd.DataFrame.from_dict(my_dict)
```

最初思いついたのは、正規表現でのreplaceだった

```python
df['parms']=''
df['parms']=df['url'].replace('(.*?)\?','?',regex=True)
```

これで一発かな、と思ったのですが、すると、
パラメータ部分がないURLは、置換ができない。（当然ですね）

|  idx  |  A  | url | parms |
| ---- | ---- | ---- | ---- |
|0	|1	|https://dummy.com/index.html	|https://dummy.com/index.html
|1	|2	|https://dummy.com/index2.html?abc=1	|?abc=1
|2	|3	|https://dummy.com/index2.html?def=2	|?def=2
|3	|4	|	|
|4	|5	|https://dummy.com/index2.html?abc=1	|?abc=1

まぁ、これはそうだろう、という動きですが、次です。

```python
df['parms']=''
df['parms']=df['url'].str.replace('(?:.*?)\?(.*?)',r'?\1',regex=True)
```

こんな感じで、'?'の後ろの部分だけ取れるかな、と思ったら、同じ結果だったのです。

▼通った方法

```python
df['parms']=''
df.loc[df['url'].astype(str).str.contains('\?'), 'parms'] = df['url'].astype(str).str.replace(r'(.*?)\?','?',regex=True)
```

|  idx  |  A  | url | parms |
| ---- | ---- | ---- | ---- |
|0	|1	|https://dummy.com/index.html	||
|1	|2	|https://dummy.com/index2.html?abc=1	|?abc=1
|2	|3	|https://dummy.com/index2.html?def=2	|?def=2
|3	|4	|	|
|4	|5	|https://dummy.com/index2.html?abc=1	|?abc=1

=> OKですね。

(解説)
'?'を含むものを抽出して、'parms'に'?'以前を消した値をセット

他にも良い方法があるのかもしれませんが。
新インプットシステム関連メモ

# InputActionsのC#スクリプトを追加するとUnityEnginが見つからない旨のエラーが表示される
``The type or namespace name 'InputSystem' does not exist in the namespace 'UnityEngine' (are you missing an assembly reference?)``

アセンブリ参照が外れているので明示する。
同一ディレクトリにAssemblyDefinitionAssetを追加し、Use GUIDsにUnity.InputSystemのアセンブリ参照を追加すると直る。
https-portal でSSL証明書が取得できないエラー。原因はvolumeの設定し忘れ。

開発・運営しているWebサービス[満点学習帳](https://mantenroom.vercel.app/)が、アップデートした際にうごかなくなってしまいました。
アップデート前のコードに戻したものの直らず。

dockerコンテナの状態を確認すると、`https-portal`のコンテナがRestartを繰り返していました。
(ここに至るまでかなり時間がかかりました。次回からはまず`$ docker container ls`ですべてのコンテナの起動状態を確認したいと思います)

### https-portalとは
- https化するためのSSL証明書の取得と設定を全自動でやってくれるdockerコンテナ
- [満点学習帳](https://mantenroom.vercel.app/)ではAPIサーバーをhttps化するためにつかっています。

### SSL証明書が取得できないエラー
`$ docker logs コンテナID`で`https-portal`コンテナのログを見てみると、証明書の取得ができないとのことでした。


### SSL証明書の取得回数の制限を超えていた
ログをもうすこしよく読んでみると、`Let's Encrypt`からSSL証明書を取得する回数の制限を超えているとのこと
。

[Let's Encrypt](https://letsencrypt.org/docs/rate-limits/)を読んでみると



> 主なレート制限としては、登録ドメインごとの証明書数 (1週間に50個まで) があります。

> 証明書の発行に使用されたリソースはすでに消費されているため、証明書を取り消してもレート制限はリセットされません。

どうやら1週間サービスを再開できなさそう。さすがにそれはマズイので、ドメインを変更することにしました。(APIサーバーなので変更して問題無し)

### 原因: `https-portal`コンテナにvolumeを設定していなかった

ドメインを変更するまえに、なぜ制限を超えてしまったか調べてみると、`https-portal`コンテナにvolumeを設定していないことが原因でした。

volumeを設定しないと、コンテナのビルド時やRestart時に毎回SSL証明書を取得するため、あっという間に制限回数を超えてしまうとのことです。

下は[github: https-portal](https://github.com/SteveLTN/https-portal)より拝借

```yml:docker-compose.yml
version: '3'

https-portal:
  image: steveltn/https-portal:1
  ports:
    - '80:80'
    - '443:443'
  links:
    - wordpress
  restart: always
  environment:
    DOMAINS: 'wordpress.example.com -> http://wordpress:80'
    # STAGE: 'production' # Don't use production until staging works
    # FORCE_RENEW: 'true'
  volumes: # ここを書いていなかった
    - https-portal-data:/var/lib/https-portal # ここを書いていなかった

wordpress:
  image: wordpress
  links:
    - db:mysql

db:
  image: mariadb
  environment:
    MYSQL_ROOT_PASSWORD: '<a secure password>'

volumes:  # ここを書いていなかった
  https-portal-data:  # ここを書いていなかった
```

なぜ今までvolumeを設定せずにエラーが起こらなかったのか、なぜ今回エラーが起きてしまったのかは謎です。

とりあえずvolumeを設定し、ドメインを変更すると無事エラーは解決し、サービスを再開できました。
VBAのSendKeysの同期化

# SendKeys
セルに「a」を入力しようとしたが、
`Application.SendKeys "a{ENTER}", True`
`CreateObject("WScript.Shell").SendKeys "a{ENTER}", True`
のどちらも、Wait:=Trueでは同期できなかった。

SendKeysはキー入力を送るだけであり、
キーバッファからシステムが受け取れたかは確認されない。
Waitでも、ある程度は待つが同期は約束されない。

このため、セルへの入力が記述箇所で行われず、
マクロの最後にまとめて入力された。

SendKeysの直後で処理を止めてみる。

## Waitメソッド
`Application.Wait (Now + TimeValue("0:00:01"))`
結果：実感できず。
入力を受け取るセルも止まるのでは？

## WindowsAPIのSleep
(64bitの場合)
`Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)`
(32bitの場合)
`Private Declare Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)`
を先頭に書く。
`Sleep (1000)`
結果：少し同期される（体感2割）

## DoEvents関数
`DoEvents`
結果：まあまあ同期される（体感1割）

# 正攻法
DoEventsは、貯まっている非同期処理の完了の催促（らしい）
ここでは、キー入力と、それを受ける再描画に必要となる。
DoEvents単体では、0.数秒しか待ってくれないから、
入力の催促した後に、SleepかDoEventsで待つ必要がある。
再描画に対しても、DoEventsで再度催促すると安定する。

```vb:
DoEvents        '入力催促
Sleep (1000)    '実行
DoEvents        '描画催促
```

（体感6割）時間が無駄にかかる。

# 脳筋
`DoEvents` を連続で20行くらい書く（体感9割）
同じだけSleepで待つより、反応が良い。

貯まっている処理があれば催促され、0.数秒待ってくれる。
貯まってなければ時間はそんなにかからない。
よって、早い。

# ループの使用
Do系ループで回すと、待機するタイミングが記述した箇所とは限らないため、
For系ループで回すか、物理的にたくさん書くこと。

使える

- For - Next
- For Each - Next

使えない

- Do While - Loop
- Do Until - Loop
- Do - Loop While
- Do - Loop Until
- While - Wend

# モジュール
Do系For系を問わず、DoEventsをループさせるだけのSubを個別に作り、Callさせると上手くいく。

For系は内部で、別Subのようにスタックが積まれていくのかもしれない。
VBのアセンブリだと分かるかもしれない。

# まとめ
脳筋は正義。

# 参考
- [EXCELのVBAで使うSendKeys - 道草日記](https://blog.goo.ne.jp/40vq77a80/e/d3be7689d47c674e2e39c7cd4c5ec2f2)
- [Application.SendKeys](https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.sendkeys)
- [WshShell.SendKeys](<https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364423(v=msdn.10)>)
- [DoEvents](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/doevents-function)
LeetCode "49. Group Anagrams"にPythonで挑んだ話

自分には、setを使いたがるという悪い手癖が付いているようです。
setを使うやり方を思いついた時には、代案も考えるようにします。

#方針１

キーを整数、値を空の集合とした辞書を作ります。
各キーごとに、そこが空の集合なら、手元にある文字列を文字に分解してその集合に入れます。また、そのインデックスの答えにも格納します。
そこがすでに要素のある集合なら、その集合と、手元にある文字列を文字に分解した集合との、和集合を作ります。
その和集合がもともとの要素と長さが変わらないなら、同じ文字列で構成されていると考え、そのインデックスの答えに格納します。

```py

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        
        n = len(strs)
        
        if n <= 1:
            return [strs]
        
        sets = {i : set() for i in range(n)}
        ans = [[] for _ in range(len(strs))]
        
        for str_ in strs:
            for i in range(n):
                if len(ans[i]) == 0:
                    ans[i].append(str_)
                    sets[i] |=  set(str_)
                    break

                union = set(str_) | sets[i] 
                if len(union) == len(sets[i]):
                    ans[i].append(str_)
                    sets[i] |=  set(str_)
                    break
        
        return [inner_list for inner_list in ans if len(inner_list) >= 1]

```

結果：**Wrong Answer**
![acc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1851956/8f25895e-1322-b8ad-dbd2-de84892d1c10.png)

同じ文字を一部で使った異なる文字列の長さのものに対応していなかったので、誤りです。
また、おそらく同じ文字を複数回使った文字列にも対応していないです。

#方針2
辞書の内容が同じ文字列を持っているか否かの判定のために、setの特徴を使うのをやめます。
代わりに、キーを文字列、値をその文字列を整列させたものの辞書を作り、それを利用して比較します。

```py

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:

        n = len(strs)
        
        if n <= 1:
            return [strs]
        
        sorted_strs = [''.join(sorted(list(str_))) for str_ in strs]
        sorted_str_dict = {sorted_str_ : [] for sorted_str_ in sorted_strs}

        for str_ in strs:
            sorted_str_ = ''.join(sorted(list(str_)))
            sorted_str_dict[sorted_str_].append(str_)

        ans = [value for value in sorted_str_dict.values() if len(value) >= 1]        	

        return ans

```

結果：**Success**
![6812.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1851956/fcc085b6-5d11-28a9-4126-5cd48cc64197.png)


やったぜ！
Ubuntu20.04 LTSにBlueZ 5.60をインストールする

#はじめに

*以前書いた記事を参考にしつつ最新版をインストールする。
https://qiita.com/masahiros/items/e3867fba3064419046f5

*apt-get build-depでエラーが出たときの対処
https://qiita.com/masahiros/items/74efd1c55859d2afe84c

#ビルド
BlueZのサイトに行って最新版を確認する。
http://www.bluez.org/

現時点での最新版である5.60をインストールする。
http://www.kernel.org/pub/linux/bluetooth/bluez-5.60.tar.xz

BlueZを取得。

```
$ wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.60.tar.xz
$ tar xvJf bluez-5.60.tar.xz
```

READMEドキュメントを確認。

```
$ cd bluez-5.60
$ less README
```

READMEに従いビルド＆インストール。

```
$ sudo apt-get build-dep bluez
$ ./configure --prefix=/usr --mandir=/usr/share/man --sysconfdir=/etc --localstatedir=/var
<中略>
checking for rst2man... no
checking for rst2man.py... no
configure: error: rst2man is required
```

エラーを確認。
以下のサイトを参考にしpython-docutilsをインストール。
https://command-not-found.com/rst2man

```
$ sudo apt-get install python-docutils
$ ./configure --prefix=/usr --mandir=/usr/share/man --sysconfdir=/etc --localstatedir=/var
-> 今度は成功。
$ make
$ sudo make install
```
疑似要素（::before, ::after)のCSSをJavaScriptで制御する

JSで疑似要素（::before, ::after)の操作をしたかったので調べたところ、[こちらの記事](http://koda.d.dooo.jp/css/css3/addrule01.html)を見かけたので備忘録として記録する。

## 「スタイルルールの追加」の概念で制御する

厳密に言うと**疑似要素はJSで直接制御できない。**
疑似要素にはHTML属性が無いのでstyle属性によるインラインCSSの制御もできない。

ではどうするかと言うと、スタイルルールの追加の概念で疑似要素を操作する。

JSで `.class::before {width:100px}` みたいな記述をドキュメントに追加してしまうという考え方になる。


## スタイルルールの挿入

```javascript
//ドキュメントスタイルの取得
var sheets = document.styleSheets
var sheet = sheets[sheets.length - 1];

//スタイルルールの追加
sheet.insertRule(
  '.class::before { width: 100px }',
  sheet.cssRules.length
);

```

まずドキュメントが保持しているスタイル情報を取得する。
次にスタイルを挿入するという形。

その挿入するスタイルを擬似要素のスタイルにすることで、スタイルを編集することができる。