OmniAICreator/Qiita-1.07M huggingface dataset:
JSON log formatterを使用してログを出力したときに、日本語が文字化けする問題の対処法

ログをJSONで取得したいため、JSON log formatterを使用したが、なぜか日本語（2バイト文字）が文字化けしてしまった。

#環境
Windows10 Home 10.0.18362 ビルド 18362
Python 3.8.3
JSON-log-formatter  0.3.0

#失敗例

以下のプログラムを実行する。

```python:json_log_test.py
import logging
import json_log_formatter

formatter = json_log_formatter.JSONFormatter()

json_handler = logging.FileHandler(filename='my-log.json', encoding='utf-8')#UTF-8で出力する
json_handler.setFormatter(formatter)

logger = logging.getLogger('my_json')
logger.addHandler(json_handler)
logger.setLevel(logging.INFO)

logger.info('この文字列が文字化けする', extra={'extra': 'この文字列も文字化けする'})
```

出力されたログファイル「my-log.json」は次のようになる。（見やすいように整形）

```json:my-log.json
{
    "extra": "\u3053\u306e\u6587\u5b57\u5217\u3082\u6587\u5b57\u5316\u3051\u3059\u308b",
    "message": "\u3053\u306e\u6587\u5b57\u5217\u304c\u6587\u5b57\u5316\u3051\u3059\u308b",
    "time": "2020-10-21T02:29:53.275011"
}
```

extraとmessageが文字化けしている。

#解決策

「json_log_formatter」ディレクトリ内の「\_\_init__.py」の「to_json」メソッドを次のように書き換える。

```Python:__init__.py
    def to_json(self, record):
        """Converts record dict to a JSON string.

        It makes best effort to serialize a record (represents an object as a string)
        instead of raising TypeError if json library supports default argument.
        Note, ujson doesn't support it.

        Override this method to change the way dict is converted to JSON.

        """
        try:
            #return self.json_lib.dumps(record, default=_json_serializable)#書き換え前
            return self.json_lib.dumps(record, ensure_ascii=False, default=_json_serializable)#書き換え後
        # ujson doesn't support default argument and raises TypeError.
        except TypeError:
            #return self.json_lib.dumps(record)#書き換え前
            return self.json_lib.dumps(record, ensure_ascii=False)#書き換え後
```

辞書をJSON化するdumpsメソッドの引数に、ensure_ascii=Falseを付け加える。

再度「json_log_test.py」を実行し、出力ファイルを確認すると、今度は文字化けしていない。

```json:my-log.json
{
    "extra": "この文字列も文字化けする",
    "message": "この文字列が文字化けする",
    "time": "2020-10-21T02:31:16.704940"
}
```

#参考サイト
Python の json.dumps() で日本語が文字化けする場合のメモ - 牌語備忘録 -pygo
https://cortyuming.hateblo.jp/entry/20140920/p2
JSON-log-formatter · PyPI
https://pypi.org/project/JSON-log-formatter/
Xcode12でplaygroundを作成する

Xcode12は、Welcome to Xcode画面から「Get started with a playground」がなくなり、かわりに「Open a project or file」が追加になりました。

「Create a new Xcode project」を選択しても、playgroundの項目はありません。

既存のプロジェクトを開いた状態で下記画像の操作を行い、playgroundを作成することができました。

![スクリーンショット 2020-10-21 11.16.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683571/362fde0c-ce03-cf88-ff48-81ba48b23449.png)
Vue.js で dev server が https モードのときにホットリロードが動かないのをなんとかしたい

Vue.js の開発サーバーには、開発中のコードの更新に合わせて自動的にページが更新される、HMR (Hot Module Replacement) という機能がついてます。
（正確には webpack の機能）
いちいちブラウザをリロードしないでも変更が反映されていくので非常に便利なんですが、開発サーバーを https モードで動かしてる場合、つまり

```
yarn serve --https
```

で起動したり、vue.config.js で、

```javascript:vue.config.js
module.exports = {
  // ...
  devServer: {
    https: true
  }
}
```

みたいにしてた場合、なぜかこのHMRが機能しないことがあるようです。

## なんとかする方法

devServer の設定項目に、以下を追記します

```diff:vue.config.js
module.exports = {
  // ...
  devServer: {
    https: true,
+   host: 'localhost',
+   port: 8080
  }
}
```

これで HTTPS モードでもHMRが動作するようになりました:tada:
UIデザインの基礎について

今回は、UIデザインの基礎についてまとめていきたいと思います。

# UIの基礎
####コンテンツ > UI
コンテンツやサービスを伴い全体でデザインする。<br>
不要なパーツはどんどん削除する。

####TPO重視
オン（図）とオフ（文字）でメリハリをつける。<br>
同じアプリ内であってもTPOが異なるものは全く別のものとしてデザインしてよい。<br>
世界観の異なるものは一緒に並べず、必ず画面を分けること。

####屋外想定
######コントラストは高くする
室内で見るより画面が見づらくなるためコントラストを高くする。<br>
複雑なレイアウトや演出は避けてシンプルな構成にする。

######アクションは片手操作になることを想定する
荷物を持っていたり、つり革につかまっているなどを想定し、主要な操作が片手でできるか実機に入れて確認する。

####遷移
######無限ループ
友達リスト→その友達のプロフィール、友達の友達リスト→自分のプロフィール・・・という感じで無限ループを作ることができますが、遷移するたびにメモリを消費する。スマホのメモリは少ないのでループしないような整理と構成を心がける。

######キャンセル遷移
戻る方の遷移が考えられていない事が多い。<br>
ダイアログを表示させ、ダイアログから別画面を呼び出したときにキャンセルボタンを押すと、何が表示されるかなど、様々な状況想定のもとに設計をする必要がある。

# 最後に
UXは映画やドラマみたいなもの、UIはその1フレームのようなものだと考えます。全体の展開を練った上で構成を考えることで面白いUIが作れます。<br>
今回は以上になります。最後まで読んでいただき、ありがとうございました。
include?メソッドの使い方

この記事ではmacOS Catalina10.15.6にインストールしたRuby 2.6.5を使っています。
include?メソッドについて自分なりにまとめました。

# include？メソッド
- 引数で指定した要素が配列や文字列内に入っているか判定するメソッド

```ruby
array = ["dog", "cat"]
puts array.include?("dog") # => true
puts array.include?("hoge") # => false
```

# 実際のコードでは
- 出力例　登録したい名前を入力してください(例)YamadaTaro
- この場合は入力した名前を受け取って「.」や「空白」があればエラー文を出力したいということですね。 
 

```ruby
def check_name(name)
  if name.include?(".")
    puts "!エラー!記号は登録できません"
  elsif name.include?(" ")
    puts "!エラー!空白は登録できません"
  else
    puts "登録が完了しました"
  end
end

puts '登録したい名前を入力してください'
name = gets
check_name(name)
```

- 2行目、checkメソッドの引数nameにinclude？の引数”.”(ピリオド)があればtrueを返してエラー文が出力されます。
- ４行目、同様に、nameにinclude?の引数” ”(空白)があればtrueを返してエラー文が出力されます。
Ubuntuのログイン時に表示されるメッセージについて確認してみる

## はじめに

Ubuntuにログインした時、先頭にこのように、バージョンが表示されます。
このバージョンをコマンドでも確認してみよう。

```
Welcome to Ubuntu 16.04.7 LTS (GNU/Linux 4.4.0-186-generic x86_64)
```

参考記事
https://www.sejuku.net/blog/82556

## やったこと

OSのバージョンはコマンドからでも確認ができます。

```
$cat /etc/os-release
$cat /etc/issue
```

次に、**4.4.0-186-generic**についてですが、これは、Linuxカーネルのバージョンを表しています。カーネルのバージョンを確認するコマンドです。

```
$uname -r
4.4.0-186-generic
```

Ubuntuのバージョンとカーネルのバージョンは１対１になっているようで、次のように決まっています。

>
Ubuntu18.10: Linux Kernel 4.18
Ubuntu18.04: Linux Kernel 4.15
Ubuntu17.10: Linux Kernel 4.13
Ubuntu17.04: Linux Kernel 4.10
Ubuntu16.10: Linux Kernel 4.8
Ubuntu16.04: Linux Kernel 4.4

**x86_64**は64bit版という意味です。因みに、32bitはi686となります。
アーキテクチャを確認するコマンドです。

```
$arch
x86_64
```

OSのバージョン、カーネルのバージョン、アーキテクチャを個別で確認するのではなく、一括で表示する事もできます。

```
$uname -a
Linux swebsv 4.4.0-186-generic #216-Ubuntu SMP Wed Jul 1 05:34:05 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
```
reactでクラスを複数付与したい

```sample.js
className={`mt-3など ${classes.付与したいクラス名}`}
```

上記でちゃんと動いた。
以下のやり方もあるみたいだけど動かず…。
ライブラリ由来のクラス名と自分でつけたクラス名が混ざってるからかな？
別の場合で使えるかもしれないので一応記載しておく。

```sample.js
className={'クラス名' + ' ' + 'クラス名'}

className={classes.クラスA + " " + classes.クラスB}
```
スクラムイベント

- セレモニー
- 4つのセレモニー


---
## デイリースクラム
- 毎日定時に開催
- 開発メンバーが主体
- その他は任意

---
## スプリントプランニング

- スプリントの計画
- スプリントで何を行うかを検討

---
## スプリントレビュー
- スプリントのインクリメントをチームで共有
- スプリント終了時に開催
- お披露目会

---
## スプリントレトロスペクティブ
- 振り返り、改善ミーティング
- チームとしてどうすればより良くなるか
- 通称レトロ


---

# 今後開催を増やしていくかもしれませんがよろしくお願いします。


---

- 昨日やったこと
- 今日やること
- 困っていること

---
なでしこの研究 その7

#概要

なでしこをplunkerでホスティングしてみた。
plugin、書いてみた。
ドレミ、です。

#サンプルコード


```
const PluginDoremi = {
	'初期化': {
		type: 'func',
		josi: [],
		fn: function(sys) {
			sys._sakura = {
				audioContext: new AudioContext(),
				oto: function(key) {
					var osciillatorNode = this.audioContext.createOscillator();
					var envelopeGen = this.audioContext.createGain();
					var freq = 440.0 * Math.pow(2.0, (key - 69.0) / 12.0);
					osciillatorNode.frequency.value = freq;
					osciillatorNode.connect(envelopeGen);
					envelopeGen.connect(this.audioContext.destination);
					var t1 = this.audioContext.currentTime;
					envelopeGen.gain.cancelScheduledValues(t1);
					envelopeGen.gain.setValueAtTime(1, t1);
					osciillatorNode.start();
					var release = 0.2;
					var keyUpTime = this.audioContext.currentTime;
					envelopeGen.gain.setValueAtTime(envelopeGen.gain.value, keyUpTime);
					envelopeGen.gain.linearRampToValueAtTime(0, keyUpTime + release);
					osciillatorNode.stop(keyUpTime + release);
				},
				sleep: function(milliseconds) {
					var start = new Date().getTime();
					for (var i = 0; i < 1e7; i++)
					{
						if ((new Date().getTime() - start) > 100 * milliseconds)
						{
							break;
						}
					}
				}
			}
		}
	},
	'ドレミ作成': {
		type: 'func',
		josi: [],
		fn: function(sys) {
			const id = 2
			return id
		}
	},
	'ドレミ斉唱': {
		type: 'func',
		josi: [],
		fn: function(sys) {
			var mml = sys.__getSysValue('ドレミ曲', 'MML')
			for (var i = 0; i < mml.length; i++)
			{
				mml = mml.replace('ァ', '');
			}
			for (var i = 0; i < mml.length; i++)
			{
				var a = mml[i];
				switch (a)
				{
				case 'a':
					sys._sakura.oto('69');
				break;
				case 'シ':
					sys._sakura.oto('71');
				break;
				case 'ド':
					sys._sakura.oto('72');
				break;
				case 'レ':
					sys._sakura.oto('74');
				break;
				case 'ミ':
					sys._sakura.oto('76');
				break;
				case 'フ':
					sys._sakura.oto('77');
				break;
				case 'ソ':
					sys._sakura.oto('79');
				break;
				case 'ラ':
					sys._sakura.oto('81');
				break;
				case 'B':
					sys._sakura.oto('83');
				break;
				default:
				break;
				}
				sys._sakura.sleep(4);
			}
			const id = 1
			return id
		}
	},
	'ドレミ曲': {
		type: 'var',
		value: 'MML'
	}
}
navigator.nako3.addPluginObject('PluginDoremi', PluginDoremi)

```

#成果物

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

以上。
MicrosoftのRPA - Power Automate Desktop 10月アップデートについて

皆さんこんにちは、マイクロソフトの川端です。
Microsoft Power Automateの有用な情報を発信していきます。

#1. はじめに
2020年9月のMicrosoft Igniteで発表のありましたPower Automate Desktop(プレビュー版)の10月アップデート情報が公表されました!
https://flow.microsoft.com/ja-jp/blog/power-automate-desktop-october-2020-update/

本内容はUIフローのインストールの際に確認できる下記バージョンでの動作内容となります。
https://docs.microsoft.com/ja-jp/power-automate/ui-flows/setup

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/86bdaa8b-f928-f60d-4c4e-fb9318c62268.png)

既にPower Automate Desktopを導入済みの場合には、一度Power Automate Desktopを端末からアンインストールし、最新版のインストーラーでお試しいただければと思います。

#2. Power Automate Desktop(プレビュー版)の10月アップデート情報

###コンソール内でのエラー通知が可能に


Power Automate Desktop内で管理されているフローを直接実行した場合に、実行エラー結果が返ってくるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/84381dee-9428-5df9-3f3f-311a9867d95e.png)


###フロー名で扱える文字列が増えました
下記のような文字列「\<>/*"」の扱いができるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/59276f84-07a7-d8b1-7803-23f617b3bf61.png)

###保存したフローのキャッシュを利用できることで読み込みが高速化
SaaSのPower Automateクラウドサービス（通常のワークフロー、ビジネスプロセスフローを管理している環境）からの読み込みが高速化されました。過去に読み込まれて変更がないPower Automate Desktopフローに関しては、ローカルにフローデータを保持しているので、高速に起動することが可能となりました。

###Power Automateの実行履歴でサブフローの情報が参照できるように
Power Automateクラウドサービスにおける、[マイフロー]>[実行履歴]で実行ログを確認できるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/948f59d2-9912-fa8b-6b06-100da4c6cdc8.png)

###アクションパラメーターがグループ化され、より効率的に
パラメーターで画面上散在していたものをひとまとまりにし、分かりやすく変更されました。下記のような様々なアクションの設定がより直感的でわかりやすく構成されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/5620e6c6-d762-3ae2-cee9-292d468e2bb2.png)

###デスクトップレコーダーで「キーの送信」アクションが記録できるように
画面操作を操作しながらフローを作成できるデスクトップレコーダーが更に高度化され、キーボード操作がデスクトップレコーダー上で記録できるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/764e4934-0514-1ab8-1119-a959ea65afca.png)


###SAPのレコーディングが可能に
SAPアプリケーションに対するレコーディングが可能になりました。

###フローの実行中にサブフローの情報が参照でき操作できるように
フローの実行中にサブフローの操作が可能となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/5a7c26d7-7667-614e-5c40-c45ee0d08225.png)

###Power Automate Desktopで新しいアイコンに
より直感的な親しみやすいアクション内のアイコンとなりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/6543232c-6d77-7ea9-2b3b-52b8f66985c4.png)

###メールメッセージの変数プロパティのFromとToが取得できるように
「メールを取得」アクションのなかで、RetrievedEmailsの変数からFromとToが取り出せるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/808554/7b1546b9-ff0a-bd4e-24be-0274fa91eb08.png)

###UI Automation、Active Directory、OCR(光学文字認識)、ターミナルのエミュレーションモジュールの機能追加
TeamsやWindows標準のアプリケーションの画面コンポーネントの取得手段であるUI Automationが機能追加され、またOCRやターミナルのエミュレーションモジュールの機能が機能追加されました。
なでしこの研究 その6

#概要

なでしこをplunkerでホスティングしてみた。
plugin、書いてみた。
mml、です。

#サンプルコード

```
const PluginSakura = {
	'初期化': {
		type: 'func',
		josi: [],
		fn: function(sys) {
			sys._sakura = {
				audioContext: new AudioContext(),
				oto: function(key) {
					var osciillatorNode = this.audioContext.createOscillator();
					var envelopeGen = this.audioContext.createGain();
					var freq = 440.0 * Math.pow(2.0, (key - 69.0) / 12.0);
					osciillatorNode.frequency.value = freq;
					osciillatorNode.connect(envelopeGen);
					envelopeGen.connect(this.audioContext.destination);
					var t1 = this.audioContext.currentTime;
					envelopeGen.gain.cancelScheduledValues(t1);
					envelopeGen.gain.setValueAtTime(1, t1);
					osciillatorNode.start();
					var release = 0.2;
					var keyUpTime = this.audioContext.currentTime;
					envelopeGen.gain.setValueAtTime(envelopeGen.gain.value, keyUpTime);
					envelopeGen.gain.linearRampToValueAtTime(0, keyUpTime + release);
					osciillatorNode.stop(keyUpTime + release);
				},
				sleep: function(milliseconds) {
					var start = new Date().getTime();
					for (var i = 0; i < 1e7; i++)
					{
						if ((new Date().getTime() - start) > 100 * milliseconds)
						{
							break;
						}
					}
				}
			}
		}
	},
	'さくら作成': {
		type: 'func',
		josi: [],
		fn: function(sys) {
			const id = 2
			return id
		}
	},
	'さくらPLAY': {
		type: 'func',
		josi: [],
		fn: function(sys) {
			const mml = sys.__getSysValue('さくらMML', 'MML')
			for (var i = 0; i < mml.length; i++)
			{
				var a = mml[i];
				switch (a)
				{
				case 'a':
					sys._sakura.oto('69');
				break;
				case 'b':
					sys._sakura.oto('71');
				break;
				case 'c':
					sys._sakura.oto('72');
				break;
				case 'd':
					sys._sakura.oto('74');
				break;
				case 'e':
					sys._sakura.oto('76');
				break;
				case 'f':
					sys._sakura.oto('77');
				break;
				case 'g':
					sys._sakura.oto('79');
				break;
				case 'A':
					sys._sakura.oto('81');
				break;
				case 'B':
					sys._sakura.oto('83');
				break;
				default:
				break;
				}
				sys._sakura.sleep(4);
			}
			const id = 1
			return id
		}
	},
	'さくらMML': {
		type: 'var',
		value: 'MML'
	}
}
navigator.nako3.addPluginObject('PluginSakura', PluginSakura)


```

#成果物

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

以上。
なでしこの研究 その5

#概要

なでしこをplunkerでホスティングしてみた。
plugin、書いてみた。
speechSynthesis、です。

#サンプルコード


```
const PluginKent = {
	'初期化': {
		type: 'func',
		josi: [],
		fn: function(sys) {
 		}
	},
	'ケント作成': {
		type: 'func',
		josi: [],
		fn: function(sys) {
			return 2
		}
	},
	'ケントplay': {
		type: 'func',
		josi: [],
		fn: function(sys) {
			const text = sys.__getSysValue('ケントtext', 'text')
			speechSynthesis.speak(new SpeechSynthesisUtterance(text));
			return 1
		}
	},
	'ケントtext': {
		type: 'var',
		value: 'text'
	}
}
navigator.nako3.addPluginObject('PluginKent', PluginKent)

```

#成果物

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

以上。
ltspiceでラジオ その4

#概要

ltspiceでAMラジオやってみた。
AM波の作り方、書いた。

#写真

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/90688aca-c225-458f-2765-e7d8899819d0.jpeg)


#AM波の作り方

- specialfunctionsからmodulateを貼り付ける
 
- valueに、mark=1Meg space=1Megを入れる。
- FMは、グランド
- AMに、sin波、入れる


以上。
【 1jpeg1knowledge 】xcodeproj と xcworkspace は違うのよぉ。🇬🇭

![#1j1k XCWorkSpace vs XCodeProject.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792464/9f43d165-8c70-a5ef-90c6-9540bded0efd.jpeg)

【1peg1knowledge】  というのは、インスタの流行りのせいで、もはや文字情報の伝達がダルくなった平成世代を中心に画像で知識を共有する試みです。
ちなみに自分はインスタで女の人のパンケーキとかタピオカとか加工まみれの顔みたいな甘ったるい画像を見まくったあとにYouTubeで長渕剛のライブを見るのがマイブームです。
サウナのあとの水風呂効果です。
イラストレーターのグラフ作成方法

#グラフ作成
###スプレットシートで作成
![スクリーンショット 2020-10-21 0.47.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633943/cece5e29-0462-59b0-d5d1-368c9d0451bf.png)

###Keynoteで作成
![市場規模グラフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633943/011aad3b-b0cb-f8b8-2d70-86565dd7c863.png)

###Illustratorで作成
Illustratorは「棒グラフツール」を使って作りました。
![市場規模_市場規模.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633943/8c8f1c7a-5e06-578b-a8a8-274e853cedf5.jpeg)
【AWS】EC2でssh接続する際のユーザー名の備忘録

#ssh接続できない...
EC2でのssh接続をしようとした所、以下のメッセージが出てログインができなかった。

```
$ ssh -i  ~/hoge/hoge.pem ec2-user@xx.xxx.xxx.xxx
The authenticity of host 'xx.xxx.xxx.xxx (xx.xxx.xxx.xxx)' can't be established.
ECDSA key fingerprint is hoge
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'xx.xxx.xxx.xxx' (ECDSA) to the list of known hosts.
ec2-user@xx.xxx.xxx.xxx: Permission denied (publickey).
```
鍵はあっているし、いつもと違うAMIを使用しているからユーザー名が違うのかと思い調べると、ユーザー名はAMI毎に違うようだ。本稿では備忘録としてAMI毎のユーザー名を簡単にまとめたいと思う。

#ユーザー名一覧
|AMI  |ユーザー名  |
|---|---|
|Amazon Linux2 または Amazon Linux AMI | ec2-user  |
|CentOS AMI   | centos   |
|Debian AMI   | admin  |
|Fedora AMI    | ec2-user または fedora   |
|RHEL AMI   | ec2-user または root    |
|SUSE AMI   | ec2-user または root   |
|Ubuntu AMI    | ubuntu    |

いつもはAmazon Linuxを使用していたのでユーザー名を`ec2-user`だったが、今回はUbuntu AMIだったので`ubuntu`に変更したら無事ssh接続できた。


https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/managing-users.html
Vue.js で Video.js を使って動画を再生する



## install

```
$ npm install --save-dev video.js
```

## Component 作成
```vuejs:videoPlayer.vue
<template>
    <video ref="videoPlayer" class="video-js"></video>
</template>

<script>
import videojs from 'video.js';

export default {
    name: "VideoPlayer",
    props: {
        options: {
            type: Object,
            default() {
                return {};
            }
        }
    },
    data() {
        return {
            player: null
        }
    },
    mounted() {
        this.player = videojs(this.$refs.videoPlayer, this.options, function onPlayerReady() {
            console.log('onPlayerReady', this);
        })
    },
    beforeDestroy() {
        if (this.player) {
            this.player.dispose()
        }
    }
}
</script>
```

## Component 使用

オプション情報については[オプションガイド](https://docs.videojs.com/tutorial-options.html)を参照してください

```vuejs

<template>
    <div>
		<video-player :options="videoOptions"/>
	</div>
</template>

<script>
import VideoPlayer from "@/components/VideoPlayer.vue";
import 'video.js/dist/video-js.css';

export default {
	name: "VideoExample",
	components: {
		VideoPlayer
	},
	data() {
		return {
			videoOptions: {
				autoplay: true,
				controls: true,
				sources: [
					{
						src: "/path/to/video.mp4",
						type: "video/mp4"
					}
				]
			}
		};
	}
};
```
video.js/dist/video-js.css をインポートし video.js の css を含める。
検索条件に合うファイルの一覧をテキストファイルに出力


#検索条件に合うファイルをテキストファイルに出力
grepやfindで結果を出力し、それをteeでファイルに書き出す、というだけ。
##検索条件に合うファイルを出力
 [参照【find・grep】特定の文字列を含むファイルのリストを取得する方法](https://qiita.com/pokari_dz/items/0f14a21e3ca3df025d21 "参照【find・grep】特定の文字列を含むファイルのリストを取得する方法")
###ファイル名に特定文字列が含まれているファイルのリストを取得
・指定フォルダ直下のみ

```
$ ls [検索対象フォルダのパス] | grep "[検索したい文字列]"
```
・指定フォルダ配下を再帰検索

```
$ find [検索対象フォルダのパス] -type f -name "*[検索したい文字列]*"
```

###ファイルを開いた中身に、特定文字列が含まれているファイルのリストを取得
・指定フォルダ配下を再帰検索

```
$ grep [検索したい文字列] -rl [検索対象フォルダのパス]
```

##結果の出力フォーマットを指定する
 [参照【 find 】コマンド（応用編その2）――検索したファイルを指定したフォーマットで表示する](https://www.atmarkit.co.jp/ait/articles/1607/20/news024.html "参照【 find 】コマンド（応用編その2）――検索したファイルを指定したフォーマットで表示する")
###ファイルの名前だけを出力
（例として拡張子が.jsのものを出力する）

```
$ find [対象ディレクトリ] -type f -name "*.js" -printf "%f\n"
```

###ファイルの名前とサイズを出力

```
$ find [対象ディレクトリ] -type f -name "*.js" -printf "%f %s\n"
```

\nは改行。これをつけないと、改行無しで羅列されて見にくい。

##テキストを出力
###teeコマンドでファイル出力
teeコマンドには様々なオプションがあるが、今回は単純にファイル名を引数に持たせるだけ。

```
$ tee [ファイル名]
```

##組み合わせ
出力結果とteeコマンドを「|」(パイプ)で連結する。

```
$ find [対象ディレクトリ] -type f -name "*.js" -printf "%f %s\n"|tee [ファイル名]
```
これで[対象ディレクトリ]内から再帰的に拡張子「.js」のファイルを検索し、ファイル名とサイズを[ファイル名]に書き出すことができる。

以上。
Codeforces Round #677 (Div. 3) C Dominant Piranha

https://codeforces.com/contest/1433/problem/C

# 題意
- n匹のピラニアがおり、大きさはaiである。このリストaが与えられる。
- ピラニアは左右に自分よりも小さい(同じはダメ)ピラニアがいれば、それを食べて(消し)自分のサイズが1上がる
最後にただ1匹のピラニアがいる状態を作れるか述べよ。
- もし作れるなら、そのピラニアの最初のindexを述べよ。そうでない場合、-1を出力しろ。

# 例
- [1,2,3]という場合、[1,4]と[5]となる
- [1,1,1]という場合、すべてのピラニアは同じ大きさなので題意を満たさない。
- [2,1,1,1,3]という場合、大きさ2のピラニアが右に食べるか、大きさ3のピラニアが左に食べればよい。

# こう考えた
max(a)のピラニアの左右にmax(a)より小さいピラニアがいればそのピラニアが解の１つである。

- max(a)のピラニアの１つが隣のピラニアを食べられるなら、そのピラニアはすべての魚を必ず食べられる。
- max(a)のピラニアが他のピラニアを食べられないというのは、max(a)のピラニアの隣は必ずmax(a)のピラニアの時だけである。
- ポイントは、max(a)でないピラニアも最強になれるかもしれないが、その時、max(a)のピラニアは確実に解の候補である

このため、各ピラニアについて左右にmax(a)があるかを確認すればよい。

# 実装
```Python
def do():
    n = int(input())
    dat = list(map(int, input().split()))
    ma = max(dat)
    res = -1
    for i in range(n):
        if dat[i] != ma:
            continue
        if i != 0:
            if ma > dat[i-1]:
                res = i+1
                break
        if i != (n-1):
            if ma > dat[i + 1]:
                res = i+1
                break
    print(res)

q = int(input())
for _ in range(q):
    do()
```

https://codeforces.com/contest/1433/submission/96101079
SSHの転送先を制限する方法(authorized_keys版)

# authorized_keys を編集

* 以下のように行の先頭にオプションを記載

```
command="/bin/false",no-agent-forwarding,no-pty,no-user-rc,no-X11-forwarding,permitopen="example.com:22" ssh-rsa AAA-.......
```

* よく利用するオプション
  * permitopen="host:port"  
    転送を許可されたホスト:ポート  
    複数の転送先を記述するときは以下のように並べる  
  ```
  permitopen="hostA:port",permitopen="hostB:port",... 
  ```
  * from="pattern-list"  
    ssh接続を許可するホストリスト
  * no-agent-forwarding  
    認証エージェント転送禁止
  * no-port-forwarding  
    ポートフォワーディング禁止
  * no-pty  
    仮想端末の割り当て禁止
  * command="command"  
    実行可能なコマンド
  * environment="NAME=value"  
    環境変数
  * no-user-rc  
    ~/.ssh/rcの実行禁止  
  * no-X11-forwarding  
    X11転送禁止
[メモ] openMVGのmacOSでのビルド


[OpenMVG](https://github.com/openMVG/openMVG)はStructure from Motion (SfM)のライブラリである。画像セットから３Dモデルを作るのに利用される。
基本的なビルド方法は[OpenMVGのサイト](https://github.com/openMVG/openMVG/blob/develop/BUILD.md#macos)にあるのだが、macOS Catalina(ver.10.15.7)でビルドする時に、ちょっとひっかっかったのでメモ。

monoを入れていると、[ここ](https://github.com/openMVG/openMVG/issues/1349)と同じ問題にぶつかるので、monoをアンインストールする。
[Uninstalling Mono on macOS](https://www.mono-project.com/docs/about-mono/supported-platforms/macos/)を参考に、

```bash
sudo rm -rf /Library/Frameworks/Mono.framework
sudo pkgutil --forget com.xamarin.mono-MDK.pkg
sudo rm /etc/paths.d/mono-commands
```

clangだと"fatal error: 'omp.h' file not found"と言われて、[ここ](https://github.com/openMVG/openMVG/issues/1727)と同じ問題にぶつかるので、結局、以下の様にしてビルド。

```
$ git clone --recursive https://github.com/openMVG/openMVG.git
$ mkdir openMVG_Build
$ cd openMVG_Build
$ cmake -DCMAKE_BUILD_TYPE=RELEASE -DOpenMVG_USE_OPENMP=OFF -G "Xcode" . ../openMVG/src/
$ xcodebuild -configuration Release
```

openMVGもopenMVSも[VCPKG](https://github.com/Microsoft/vcpkg)に対応しているので、VCPKGをセットアップしてあれば、その方が簡単かもしれない。
LightsailでWordPressのWebサイトを開設する

Apache+mod_mdを使って、Let’s EncryptでのSSL化をしていたが、LightSailのBitnami上の環境だと、Bitnamiがもっと簡単なセットアップを用意してくれている。

SSHで接続した後、

sudo /opt/bitnami/bncert-tool

を実行。これだけ。聞かれるままに設定して終わり。やばい。はやい。

Domain list []:
はドメインのリストを聞いているので、一つであれば、
Domain list []:sample.com
でリターン。

あとは、自分に合わせた設定でOK.　ちなみに私は
HTTP to HTTPS redirection [Y/n]:n
non-www to www redirection [Y/n]:n
www to non-www redirection [y/N]:n

Do you agree to these changes? [Y/n]: Y
Do you agree to the Let’s Encrypt Subscriber Agreement? [Y/n]: Y

Successが出れば無事に終了。
ブラウザーでhttps://sample.comを開いて、証明書を確認。
【VSCode】Vue.js で Unbound breakpoint

# 困りごと

VSCodeでのVue.js（TypeScript）の開発時にブレークポイントを設定しようしたら、以下のようになってブレークポイントが貼れない、止まらない。

![private.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93814/ecf00c2c-e362-bd75-9f4d-328305472c79.png)
￼

```json:launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "vuejs: chrome",
      "url": "http://localhost:8080",
      "webRoot": "${workspaceFolder}/src",
      "breakOnLoad": true,
      "sourceMapPathOverrides": {
        "webpack:///./src/*": "${webRoot}/*"
      }
    },
    {
      "type": "firefox",
      "request": "launch",
      "name": "vuejs: firefox",
      "url": "http://localhost:8080",
      "webRoot": "${workspaceFolder}/src",
      "pathMappings": [{ "url": "webpack:///src/", "path": "${webRoot}/" }]
    }
  ]
}
```

# 解決
VSCodeの設定で以下の設定をfalseにしたらブレークポイントが設定できました。

![Debug › Java Script Use Preview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93814/0f74b276-72b8-795e-2218-19fc20062853.png)
￼
# 参考
https://github.com/microsoft/vscode/issues/102493
ShellScriptで変数に格納した出力結果が改行されずに表示されてしまうのをそのまま出す方法

忘れっぽいのでメモ的な記事です。

# 結論
```ShellScript
echo ${CSVLOG}
↓
echo "$CSVLOG"
```

# 引用元
- https://stackoverflow.com/questions/613572/capturing-multiple-line-output-into-a-bash-variable
tensorboardでWindows fatal exception: access violationが出た時

大体のtensorboardがなぜか動かん！というときの解決策は、tensorflow、tensorboardをインストールし直すことみたいですがそれでも治らなかったので備忘録です。



[公式のissue](https://github.com/tensorflow/tensorboard/issues/2399)より抜粋。

##実行環境
Windows10
tensorflow-gpu==1.15
tensorboard==1.15


##実行コマンド
同じディレクトリ内にlogsファイルが有る時
```tensorboard --logdir=./logs --host=127.0.0.1```
を実行
ちなみに自分の環境だとhostを指定しないと動きませんでした。（hostの指定は[このサイト](http://wshinya.hatenablog.com/entry/2018/10/04/112909)を参照)

##解決策
同じディレクトリ内のcheckpointファイルの名前を変更、削除

##余談
これをすると直りました。おそらく参照関係でぶつかったのでしょうか。
動画から静止画を切り出してみました

＜経緯＞
機械学習の教師データを作成するためにアノテーションを行う必要ができました。
そのために静止画が大量に必要になり、動画から静止画を切り出すことにしました。

はじめは動画から静止画を抽出するツールを使用して手作業で行っていましたが、
その作業が面倒であったので、自動化することにしました。

＜手順＞
opeCVのインストール
動画の読み込み
単位フレーム毎に静止画を切り出す
静止画サイズを再調整する

opeCVのインストール
今回はwindows+anacondaで行いましたので、anacondaプロンプトで
```C:Users\user\conda install -c conda-forge opencv```
コマンドでインストールできました。
基本的には全自動でできますが、時間は２時間程度かかりました。

実際に動かすために少しだけPythonでの記述が必要です。


＜コード＞
ラプラシアンフィルタとは二次微分を利用して画像輪郭を抽出する空間フィルタのことです。
laplacian.varはラプラス分布の分散（ばらつき）を見ています。

if ret and laplacian.var() >= laplacian_thr:
laplacian_thrはボケ画像と判断するためのスレッショルド
この値は自分が見てボケていると認識した画像のパラメータ取得して利用することにして、
今回はlaplaciaan.var()の値が800以下のものをボケ画像として判定することにしました。


```python
"""
@author: S.Nakamura     2020/10/18
動画を読み込んで画像（ｊｐｇ）に分割するプログラム
input_movie：読み込む動画ファイル名
cpf：何フレームごとに保存するか
image_dir：画像の出力先ディレクトリ（無ければ作成する）

・動画の読み込み
・何フレーム毎に読み込むか
・画像の出力先のディレクトリの指定
・ピンぼけ画像を外す
・サイズの変更
・名前を決めて出力する
""" 
import cv2
import numpy as np
import os

i=0
count = 0
cpf = 10                        #何フレーム毎に切り出すか

#画像のサイズ
image_width = リサイズする画像の幅
image_heigh = リサイズする画像の高さ
#ボケ画像判定のためのlaplacian.var
laplacian_thr = 800             #ボケ画像判定をするときのスレッショルド

#動画の読み込み
cap = cv2.VideoCapture('読み込む動画ファイルを指定')

while(cap.isOpened()):
    ret, frame = cap.read()                   #動画を読み込む
    #assert frame, "オープンに失敗"            #デバッグ用

    if ret == False:
        print('Finished')                    #動画の切り出しが終了した時
        break

    if count%cpf == 0:                      #何フレームに１回切り出すか

        #サイズを小さくする
        resize_frame = cv2.resize(frame,(image_width,image_heigh))

         #画像がぶれていないか確認する
        laplacian = cv2.Laplacian(resize_frame, cv2.CV_64F)
        if ret and laplacian.var() >= laplacian_thr: # ピンぼけ判定がしきい値以上のもののみ出力
            
            #第１引数画像のファイル名、第２引数保存したい画像
            write = cv2.imwrite('保存する画像の名前と拡張子')  # 切り出した画像を表示する
            assert write, "保存に失敗"
            print('Save', 保存する画像の名前と拡張子)          #確認用表示
            i += 1
        
    count = count + 1

cap.release()
```
細かい検証はしていませんが、画像を切り出してリサイズするという目的は達成できました。
これだけ簡単な記述で動画から静止画を切り出すことができて感動です。

＜参考情報＞
Blur detection with OpenCV　https://www.pyimagesearch.com/2015/09/07/blur-detection-with-opencv/
note.nkmk.me　　https://note.nkmk.me/python-opencv-video-to-still-image/
動画（mp4）から画像（jpg）を切り出すプログラム　　https://www.souichi.club/deep-learning/spliter/
へっぽこが1週間でwebサービスを開発する #2 ドメインサーチ

![スクリーンショット 2020-10-04 22.31.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634341/8d20d39c-6cb0-27a3-9373-276d6aab5edc.png)

#ドメインサーチ
ドメインサーチは以下の機能を提供するサービスです。
[ドメインサーチ](https://searching.monster/)

* tld検索:対象のtldの提供有無と価格を検索できます。
* キーワード検索：対象ドメインが任意のキーワードでのランキングを検索できます。
* WHOIS検索：対象ドメインのWHOISドメインを検索できます。
* DNSレコード検索：対象ドメインのDNSレコードを検索できます。
* ドメイン年齢：対象ドメインの運用期間を検索できます。


#僕のスペック
・へっぽこエンジニア
・開発歴：３年
・個人開発歴:10ヶ月目(2020.01に今年は個人開発をやる！と決めた。)
・開発言語：python
・今回の開発でようやくvueを使ってみました！！
・ノーコーディングに割と興味がでてきたり。

#開発経緯
今回も前回同様、だらさんのweb1weekにて開発しました。

始まる直前にUdemyでVue講座のお勉強をしていたので早速Vueに挑戦するぞ！って事でVue CLIで開発しました。

なんか、NuxtJsが今のVue開発の主流的な記事(Nuxtで始めろ的な記事)をどっかで目にしていたのですが、今回は初めてなので、大人しくVue CLIで開発！

vue自体もそうですが何よりVue CLIすご！って思いました。

#使用技術
* 言語：Vue
* フレームワーク:Vue CLI
* デザイン：Vutify (これまたすご！って思いました。)
* デプロイ環境：netlify　(これもまた　すご！すご！って思いました。)
* バックエンド：lambda (AWS)

今回は特にすご！便利！って思いながら開発できたので楽しかったです！！

あと、今回はバックエンドで各サイトのドメイン価格等を取得するためにpythonでスクレイピングしてます。

そのバックエンド処理をlambdaに置いています。
AWSのlambdaは今回初めて使いましたがこれも、すご！って思いました！

#本番環境
![環境.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634341/7fcb0146-768d-8be0-87c6-e1a3bfd6b912.png)
今回はNetlifyを初めて利用しました。
カスタムドメインまで無料で設定できるのでありがたいサービスです。

#Lambda
Lambdaも今回初めて利用しました。
サーバレス構成のアプリケーションにはとても相性の良いサービスでした。

似たようなサービスでGoogleのCloudFunctionsを当初、利用しようとしていましたが、後述するchromedriverの参照がどうしてもうまくいかず諦めました。

Lambdaはpythonを利用していましたが、Lambdaでpythonのモジュールを参照するためにはレイヤーと呼ばれる箇所に対象のモジュールファイルをアップロードする必要があります。

##レイヤーへのモジュールアップロード
今回はseleniumのモジュールをレイヤーにアップロードする方法を記載します。

```
 mkdir python #まずはルートフォルダpythonを作成します。
 cd python
 pip install selenium -t #カレントディレクトリにseleniumモジュールをダウンロード
 cd ../
 zip -r selenium.zip ./* #最後にpythonフォルダごとzip化
```
上記で作成したzipファイルをレイヤーにアップロードすることでseleniumをLambdaから参照できるようになり、importで読み込むことができるようになります。

モジュールファイルだけでなく、ドライバ等のpythonファイル以外でも同様の方法で参照することができますが、lambdaを利用するのであれば、他のファイルはS3に置いて参照する方がスマートかとおもいます。

私自身も、今回スクレイピングで必要になったchromedriverはS３に置いてそれを参照させています。

#その他

##動的にタイトルやdescriptionを変更する
今回、VueCLIを使っており、意図せず、SPA(シングルページアプリケーション)になりました。。
VueRouterを利用して、擬似的に複数ページになるような構成にしたものの、どうやって、タイトル等を変更するんだろう。。ってところに躓きました。

以下のサイトを参考にすることで見事、動的にタイトル等を変更することができるようになりました！！
[参考ページ](https://qiita.com/yuta-38/items/1fc2d1f5b4add2c0ed2c)




[ドメインサーチ](https://searching.monster/)
汎用的な機能を実装するときは使う側が簡単に使えるか？を意識しよう

プログラムを書いているとき、汎用的な機能をクラスやメソッドに切り出して実装することがあると思います。

例えば指定した複数のユーザーを特定のイベントに参加させる処理を考えます。

まずはすべての処理が1メソッドにある場合の実装を確認します。
（Rubyで書いていますが他のプログラム言語をやったことがある方であれば雰囲気はつかめると思います）

```ruby
def main(user_ids, event_id)
  users = User.where(id: user_ids)
  event = Event.find(event_id)

  # 参加しているユーザーは除く
  target_users = users.reject {|user| user.events.ids.include?(event.id) }

  # イベント参加
  target_users.each do |user|
    # イベント参加 => EventUserにレコードを追加
    EventUser.create!(user: user, event: event)
  end
end
```

上記からイベント参加の処理をメソッドとして切り出してみます。
今回はEventモデルにメソッド追加してみました。

```ruby
def main(user_ids, event_id)
  users = User.where(id: user_ids)
  event = Event.find(event_id)

  # 参加しているユーザーは除く
  target_users = users.reject {|user| user.events.ids.include?(event.id) }

  # イベント参加
  event.join(target_users)
end
```

```ruby:app/models/event.rb
def join(users)
  users.each do |user|
    # イベント参加 => EventUserにレコードを追加
    EventUser.create!(user: user, event: event)
  end
end
```

これで他のところからイベントに参加する処理を実行したくなった場合も`event.join(users)`で呼び出すことができるようになりますね。

ただ、この実装方法は微妙な点があります。
それは呼び出し元が**参加済みのユーザーを除いて参加可能なユーザーのみを渡さないといけない**点です。

今回の例の場合は下記のようにしたほうが呼び出し元が楽になります。

```ruby
def main(user_ids, event_id)
  users = User.where(id: user_ids)
  event = Event.find(event_id)

  # イベント参加
  # 呼び出し元はusersが参加済みか気にしなくて良い。対象となりうるユーザーを渡せばOK
  event.join(users)
end
```

```ruby:app/models/event.rb
def join(users)
  # 参加しているユーザーは除く
  target_users = users.reject {|user| user.events.ids.include?(event.id) }

  target_users.each do |user|
    # イベント参加 => EventUserにレコードを追加
    EventUser.create!(user: user, event: event)
  end
end
```

このように実装すれば呼び出し元は参加済みか気にせずに対象となりうるユーザーを渡せば良くなります。

今回のように順序立って説明すると3つ目の実装をするのが当たり前のように感じるかもしれませんが、実際には2つ目の状態で実装されているものもよく見かけます。

なぜならメソッド単体で見て「ユーザーをイベント参加させるメソッドです」と言われても違和感がないからです。
もう一度2つ目の汎用化した部分を下記に再掲します。このメソッド単体で見るとどうでしょうか？

```ruby:app/models/event.rb
def join(users)
  users.each do |user|
    # イベント参加 => EventUserにレコードを追加
    EventUser.create!(user: user, event: event)
  end
end
```

また、最初に汎用メソッドを作ったときは呼び出し元がほとんどない（もしくは1つしかない）かもしれません。
そうなると呼び出し元でチェックしても呼び出し先でチェックしても手間はあまり変わらないので、呼び出し元ですべてでチェックしなければいけないという煩わしさにも感じづらいです。

そして一度このように実装されてしまうと、同じようにイベント参加をする処理を実装するときも既存の箇所をコピペしてしまいます。
そうなると『既存がこうだから〜』の力学が働いてしまい、煩わしさを感じるどころか当たり前と感じるようになってきます。

# まとめ
汎用的な機能を実装するときは、使う側が簡単に使えるか？を意識するようにしましょう。
使う側が様々な制約を考慮しなければいけなかったり、必ず実行しなければいけない処理（今回の例でいうと参加者を除く処理）がある場合、それらの処理を汎用的な機能の内部に取り込めないか検討するようにしましょう。

そうすることで使う側が楽になるだけでなく、実装漏れなどのバグも防ぐことに繋がります。

また、せっかく汎用的に作るのであれば、使われてなんぼです。
使い方が難しいと実装した人以外は使えない可能性が高いです（実装した人も数カ月後には使えなくなっているかもしれません）
利用者が使いやすくて楽ができる実装を心がけましょう！！
俺的RxSwiftまとめ②

#RxSwiftの特徴をさらに詳しく
この記事は、[俺的RxSwiftまとめ①](https://qiita.com/_Masa_asaM_/items/5b15094e047633070b92)の続きです。

##RxSwiftの特徴

非同期処理には、気を付けるポイントが2点ある。

- コードの実行順序
- 共有された[mutable](https://qiita.com/makotoo2/items/fc3a617882916f9775f5)なデータをどのように取り扱うか

である。

RxSwiftは、これらの問題に対して、以下の2つの概念を取り入れて、対処している。

- [宣言的プログラミング](https://qiita.com/ababup1192/items/7c2cc6c48c06eb4ab4b2) → 例:`a = b + c`と定義すれば、`a`の値は`b`と`c`の値が変化するごとに更新する。
- [関数型プログラミング](https://qiita.com/tail-island/items/1782e4c1e7b620a4f9c0#%E9%96%A2%E6%95%B0%E5%9E%8B%E3%82%82%E3%81%84%E3%81%84%E3%81%91%E3%81%A9%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%82%82%E3%81%AD) → 関数の入出力の連なりで処理を記述する方式

そして、以下の5つの特徴を手に入れている。(＝[Reactive System](https://thinkit.co.jp/article/9185#:~:text=%E3%83%AA%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E3%80%81%E3%81%B2%E3%81%A8%E3%81%93%E3%81%A8%E3%81%A7%E8%A8%80%E3%81%86%E3%81%A8%E3%80%8C%E5%8D%B3%E5%BF%9C,%E3%80%8D%E3%81%A7%E3%81%99%EF%BC%88%E5%9B%B31%EF%BC%89%E3%80%82))

- Resposive→UIにアプリの最新状態を常に反映すること
- Resilient→各処理が分離されていて、エラーリカバリが容易であること
- Elastic→[変動ワークロード](https://www.otsuka-shokai.co.jp/words/workload.html)に対して、[遅延読み込み](https://ja.wikipedia.org/wiki/%E9%81%85%E5%BB%B6%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)や[スロットリング](https://future-architect.github.io/articles/20200121/)、リソースシェアなどの機能で対処する
- Message-driven→コンポーネント間のやりとりをメッセージベースの通信を使用して非同期に行い、疎結合にして再利用性を高め、クラスのライフサイクルと別に実装すること

#RxSwiftの構成要素
RxSwiftは`Observable/operator/scheduler`の3つの構成要素を持っている。

##Observable
`Observable<type>`で定義する、観察対象のこと。
時間の経過とともに生成される一連のデータの不変な[snapshot](https://wa3.i-3-i.info/word14388.html)(その瞬間のデータのコピー)を流す一連のイベントを、非同期に生成することができる。

複数の`observer`(観察者)がリアルタイムにイベントに反応して、UIを更新したり、データを利用できる。
`ObservableType protocol`は以下の3つのイベントを生成することができる。

- `next` → 次のデータを`observer`に持ってくるイベント。`completed`が起こるまで、値を`observer`に持ってき続ける。
- `completed` → 一連のイベントを`success`で終了させ、observerに通知する。
- `error` → `observable`が`error`で終了したことを通知する。

##Operators
`Observable<type>`には、非同期、イベントに基づいた処理を行うメソッド(`Operators`)が多数含まれている。これらはSide effect(ユーザー側にUIで反映すること)なしに出力のみを生成するので、`Operator`を組み合わせて入力を任意の値に変換することができる。
代表的な`Operator`を挙げると、

- `filiter` → 条件に合う値のみを抽出する
- `map` → `Observable`で流れてきた全ての値に対して処理を行う
- `skip` → 特定の値をスキップする

などがあります。(後ほど別記事でまとめたいと思います。)

##Scehduler
`Scheduler`は`Dispatch queue`と同じようなもので、処理をメインスレッドとサブスレッドで分けることができる。RxSwiftは定義済みの`Scheduler`がたくさんあるので、便利!
*UIの更新はメインスレッドで行う

#RxCocoa
`RxSwift`は、`Swift`に限らないRxの共通使用に関するものだ。`Swift`特有の`UIKit`などは、`RxCocoa`を用いて扱っていく。
`RxCocoa`は多くの`UIパーツ`にリアクティブな機能を追加しているライブラリである。
Windows × Vagrant ： Failed to open/create the internal network

新規に Vagrant と VirtualBox をインストールして vagrant up を実行すると、ホストオンリーアダプターの作成でエラーが発生した。

# 環境

- Windows 10 Pro
- Vagrant 2.2.10
- Virtual Box 6.1.14
  - 1個もVMがなく、手動で何も設定していない状態

# エラー内容

```
> vagrant up
Stderr: VBoxManage.exe: error: Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter' (VERR_INTNET_FLT_IF_NOT_FOUND).
VBoxManage.exe: error: Failed to attach the network LUN (VERR_INTNET_FLT_IF_NOT_FOUND)
VBoxManage.exe: error: Details: code E_FAIL (0x80004005), component ConsoleWrap, interface IConsole
```

# 解決方法

Windows の「ネットワークの接続」に表示されている「VirtualBox Host-Only Ethernet Adapter #N」（N：数値）に設定されたIPアドレス帯のアドレスを、Vagrantfile の private_network に指定する。

自分の環境には「VirtualBox Host-Only Ethernet Adapter #3」が「ネットワークの接続」に表示されていた。
これと同じIPアドレス帯の任意のIPアドレスを Vagrantfile に指定して、エラーを解消した。

# エラー原因（推測）

Vagrantfile に最初に指定したIPアドレス帯で NIC を作成するのに失敗している模様。

エラー発生後のネットワーク関連設定は、以下の状態だった。

- VirtualBox に作成された VM のネットワーク設定
  - ホストオンリーアダプターに「VirtualBox Host-Only Network」が指定されていた
  - 「名前」の選択肢には、「VirtualBox Host-Only Network #3」も存在した

- Windows の「ネットワークの接続」
  - 「VirtualBox Host-Only Network」は存在しない
  - 「VirtualBox Host-Only Network #3」は存在する

# 備考

Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter'
で検索すると、他の解決方法を紹介した記事がいくつか出てきます。
Netatmo　Weather Station: 利用編


昨年の台風19号の時に、記録できる気圧計が状況を把握する上でとても役に立った。しかし、データとして落とせないなどの問題があったことから、電池が切れた機会に気になっていたNetatmo Weather Stationを購入した。

- [Netatmo Weather Stationセットアップあれこれ](https://qiita.com/plus_sum/items/e702a009cc1da4452415)

使ってみると、色々と面白いデータが採れる。

# データあれこれ

## 二酸化炭素濃度と騒音
意外と面白かったのが、二酸化炭素濃度と騒音のデータ。Wearther Stationを設置した部屋の生活状況が分かってしまう。ある意味怖いのだけれど、生活をしているっていうのは、こういうことだと認識させてくれる。
ちなみに、大気中の二酸化炭素濃度は400ppm程度　(ppm: parts per million, 1/100万）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529969/848bc933-9625-92a5-2a6f-0a7bcf22b833.png)


To be continued

# 関連
[Netatmo Weather Stationセットアップあれこれ](https://qiita.com/plus_sum/items/e702a009cc1da4452415)
[おうちLANあれこれ（WiFi, Vistumber, nmap）](https://qiita.com/plus_sum/items/3e4e060930cccd5c9663)
mindの研究 その27

#概要

mindが謎なので調べてみた。
vistaに入れた。
atcoder、やってみた。

#座標(0,0)を出発地点とした場合、時刻ti時点で(xi,yi)にいることができるかどうかを判定する。

```

メインとは
　文字列１は　文字列
　合否は　変数
　数１は　変数
　Tは　変数
　Xは　変数
　Yは　変数
　DTは　変数
　DXは　変数
　DYは　変数
　PTは　変数
　PXは　変数
　PYは　変数
　Lは　変数
　Mは　変数
　Nは　変数
　Nに　０を　入れ
　PTに　０を　入れ
　PXに　０を　入れ
　PYに　０を　入れ
　文字列入力し　文字列１に　入れ
　文字列１を　数値変換し　数１と　合否に　入れ
　数１を　回数指定し
　　文字列入力し　文字列１に　入れ
　　文字列１を　数値変換し　Tと　合否に　入れ
　　文字列入力し　文字列１に　入れ
　　文字列１を　数値変換し　Xと　合否に　入れ
　　文字列入力し　文字列１に　入れ
　　文字列１を　数値変換し　Yと　合否に　入れ
　　Tから　PTを　引き　DTに　入れ
　　Xから　PXを　引き　DXに　入れ
　　Yから　PYを　引き　DYに　入れ
　　DXに　DYを　加え　Lに　入れ
　　DTから　DXを　引き　DYを　引き　Mに　入れ
　　Mを　２で　割った余りを　Mに　入れ
　　もし　Lが　DTより　大きい　または　Mが　１に　等しい　ならば
　　　Nに　１を　入れ
　　つぎに
　　Tを　PTに　入れ
　　Xを　PXに　入れ
　　Yを　PYに　入れ
　繰り返し
　もし　Nが　１に　等しい　ならば
　　「No」を　表示する
　さもなければ
　　「Yes」を　表示する
　つぎに

```

#ここまでの、まとめ

##mindは、配列が弱い。
ソートが無い。サンプルコードも探せない。

##mindは、splitが無い。

以上。
mindの研究 その26

#概要

mindが謎なので調べてみた。
vistaに入れた。
atcoder、やってみた。

#文字列Sが、'dream','dreamer','erase','eraser'の組み合わせで作れるかどうかを判定する。

```

メインとは
　文字列１は　文字列
　Iは　変数
　Jは　変数
　Iに　０を　入れ
　文字列入力し　文字列１に　入れ
　文字列１から　"dreamer"を　検索する　Iに　入れ
　もし　Iが　０より　大きい　ならば
　　Jに　１を　入れ
　つぎに
　文字列１から　"dream"を　検索する　Iに　入れ
　もし　Iが　０より　大きい　ならば
　　Jに　１を　入れ
　つぎに
　文字列１から　"eraseer"を　検索する　Iに　入れ
　もし　Iが　０より　大きい　ならば
　　Jに　１を　入れ
　つぎに
　文字列１から　"erase"を　検索する　Iに　入れ
　もし　Iが　０より　大きい　ならば
　　Jに　１を　入れ
　つぎに
　もし　Jが　１に　等しい　ならば
　　「Yes」を　表示する
　さもなければ
　　「No」を　表示する
　つぎに

```

以上。
mindの研究 その25

#概要

mindが謎なので調べてみた。
vistaに入れた。
atcoder、やってみた。

#10000円札、5000円札、1000円札がある前提で、合計がN枚、Y円になる組み合わせを求める。

```
メインとは
　文字列１は　文字列
　合否は　変数
　数１は　変数
　数２は　変数
　Iは　変数
　Jは　変数
　Kは　変数
　Lは　変数
　Mは　変数
　Xは　変数
　Yは　変数
　Zは　変数
　文字列入力し　文字列１に　入れ
　文字列１を　数値変換し　数１と　合否に　入れ
　文字列入力し　文字列１に　入れ
　文字列１を　数値変換し　数２と　合否に　入れ
　数１を　回数指定し
　　Iに　回数を　入れ
　　数１を　回数指定し
　　　Jに　回数を　入れ
　　　数１を　回数指定し
　　　　Kに　回数を　入れ
　　　　Iに　１００００を　掛けて　Lに　入れ
　　　　Jに　５０００を　掛けて　Lを　加えて　Lに　入れ
　　　　Kに　１０００を　掛けて　Lを　加えて　Lに　入れ
　　　　Iに　Jを　加えて　Kを　加えて　Mに　入れ
　　　　もし　Lが　数２に　等しい　かつ　Mが　７に　等しい　ならば
　　　　　Xに　Iを　入れ
　　　　　Yに　Jを　入れ
　　　　　Zに　Kを　入れ
　　　　つぎに
　　　繰り返す
　　繰り返す
　繰り返す
　Xを　数値表示し　改行し
　Yを　数値表示し　改行し
　Zを　数値表示する。

```

以上。
「[基本情報技術者試験]うるう年の判定のアルゴリズムをPythonで書いてみた。」を参考にして、WolframAlphaとgoogleでやってみた。

(オリジナルポスト)[基本情報技術者試験]うるう年の判定のアルゴリズムをPythonで書いてみた。	
https://qiita.com/kuro_take/items/525c5e31268f22c08fcf	
	
##WolframAlphaの実行結果	
	
```	
2014年はうるう年か 	
https://ja.wolframalpha.com/input/?i=2014%E5%B9%B4%E3%81%AF%E3%81%86%E3%82%8B%E3%81%86%E5%B9%B4%E3%81%8B+	
入力解釈:	
2014年はうるう年でしたか?	
結果:	
いいえ．2014年 はうるう年ではありませんでした	
```	
	
```	
(以下結果のみ)	
いいえ．2015年 はうるう年ではありませんでした	
いいえ．2200年 はうるう年ではありません	
はい．2400年 はうるう年です	
```	
	
##googleの実行結果	
2014年はうるう年か 	
https://www.google.com/search?hl=ja&sxsrf=ALeKk01FtAR4-4wQoWvn1p1XWwVHS_xtYQ%3A1603150213052&source=hp&ei=hSGOX5ifAc7XhwOe7JGgDw&q=2014%E5%B9%B4%E3%81%AF%E3%81%86%E3%82%8B%E3%81%86%E5%B9%B4%E3%81%8B+&oq=2014%E5%B9%B4%E3%81%AF%E3%81%86%E3%82%8B%E3%81%86%E5%B9%B4%E3%81%8B+&gs_lcp=CgZwc3ktYWIQAzoHCCMQ6gIQJ1CUD1iUD2CjFWgBcAB4AIABbogBbpIBAzAuMZgBAKABAqABAaoBB2d3cy13aXqwAQo&sclient=psy-ab&ved=0ahUKEwjY9d_358HsAhXO62EKHR52BPQQ4dUDCAk&uact=5	
2014=2008.497	
	
	
(参考)	
コンピュータシステムと閏年<閏年（wikipedia）	
https://ja.m.wikipedia.org/wiki/%E9%96%8F%E5%B9%B4#コンピュータシステムと閏年	
うるう年	
https://ja.wolframalpha.com/input/?i=%E3%81%86%E3%82%8B%E3%81%86%E5%B9%B4	
leap year	
https://ja.wolframalpha.com/input/?i=leap+year	
leap 飛躍(google翻訳より)	
intercalary 閏(google翻訳より)
ポメラDM200のDebianから印刷する

ポメラDM200上のDebianからWi-Fiでネットワークに繫いだ状態から、ネットワーク内のプリンタで印刷する方法のメモ。

以下のような記事を参考にポメラDM200でDebianが起動する状態にしてあることを前提とする。

- [KING JIM ポメラDM200でEmacs、Vim、Ruby、Pythonが動くなんて素敵すぎる！](http://hitoriblog.com/?p=51448)
- [pomera DM200 の Linux 化のメモ - Qiita](https://qiita.com/alt-core/items/d62c6447c607fbf6e8bf)

## 方法概要
- プリンタへのデータの送信はCUPS(Common Unix Printing System)を用いる
    - [Common Unix Printing System - Wikipedia](https://ja.wikipedia.org/wiki/Common_Unix_Printing_System)
- テキストを印刷する際は、`paps`を用いてPostScript化する
    - [paps download | SourceForge.net](https://sourceforge.net/projects/paps/)

## 手順
### CUPSとpapsをインストール
```sh
$ sudo apt install cups paps
```

### CUPSのテスト
Xを立ち上げ、ブラウザを開き、`http://localhost:631`に繋ぐとCUPSの設定画面が出る。

ここからプリンタの追加やテストページの印刷を行う。

- 設定の方法は [なんぶ電子: Debian(Linux)にプリンタをインストールする](https://seedoftalk.blogspot.com/2019/12/debian-printer.html) を参照。
    - 私はデフォルトで両面印刷する設定にした。
    - デフォルトプリンタの設定も行ったが、これはなぜか私の環境では効いていない。
- インターネット上には、プリンタのドライバをインストールしないといけないと印刷できないという情報もあるが、少なくとも私の使っている Brother DCP-J978N の場合はドライバなしで印刷できた（最低限のPostScriptプリンタとしての機能はドライバなしでも使えるということ？）。
- w3mでは設定できなかった。
- GUIを使うのが嫌ならば、コンフィグファイルを編集すればいけるらしい。
- 以下、機種依存性が大きいと思われる。

### CUPSを用いた英語テキストの印刷
CUPS経由で印刷する場合は `lp` コマンドを用いる。英語のテキストファイルであればそのままこのコマンドで送れば印刷できる。

> ただし、sample.txtに半角英数字以外の文字が含まれていると、印刷できないことがある。プリンタがその文字コードを理解できない場合があるからだ（このあたりはプリンタに依存する）。

とのこと（出典：[lprコマンドでバイナリ・モードで印刷する － ＠IT](https://www.atmarkit.co.jp/fwin2k/win2ktips/810binprn/binprn.html)）

まず、

```
$ lpstat -p
```

でプリンタを検索する。

その後、

```sh
$ lp -d プリンタ名 sample.txt
```

で印刷できる（`プリンタ名`には検索したときに出てきた名前を入れる）。

プレーンテキスト以外にも、PDFやPostscriptのファイルがあれば、同様にして印刷できる。

### 日本語テキストを印刷する

日本語テキスト（UTF-8）を印刷したい場合は、テキストをPostScriptまたはPDFに変換した後に印刷することになる。

気合の入った文書の場合はLaTeXで組版してPDFにしても良いが、この場合数GBのLaTeXのインストールが必要になり大変。
ここでは、`paps`というソフトで簡易にプレーンテキストをPostScriptに変換して印刷する方法を紹介する。

使い方は

```sh
$ paps --header --font="TakaoMincho 9" input.txt > output.ps
```

のようにするだけ（オプションは「ヘッダ付き」「TakaoMinchoの9ポイントを指定」の意）。これで生成されたpsファイルを、

```
$ lp -d プリンタ名 output.ps
```

としてプリンタに送ってやると印刷される。


- LaTeXを使う方法で行く場合は [メモ: Pandoc+LaTeXで気軽に日本語PDFを出力する - Qiita](https://qiita.com/sky_y/items/15bf7737f4b37da50372) あたりを参考にするのがよさそう。
- text->ps変換を行うツールは`paps`以外にもいくつかあり、[なにかやったら書くブログ: UTF-8で書かれた日本語テキスト, テキストファイルをPostScriptに変換する方法(2019/11)](https://taraijpn.blogspot.com/2018/04/utf-8postscript.html)で紹介されている。なお、GitLab版のgnome-u2psは、そのままではビルドできなかったが、Makefileの中のgccのところに`-lm`オプションを足せばビルドできた。
- ps2pdfでPDFに変換してから印刷しても、特になにも変わらないように見えた。

## 以上

ポメラで入力した文章を、パソコンを経由せずに直接印刷できるのは結構便利だと思う。

これはもはやワープロな気がするが……。
[Azure] WebAppでAzure AD認証を有効にした際に「rts.powerapps.comへのアクセスエラー」が出る場合の対応手順

Azure WebAppにはappservice認証機能があり、AzureAD、Google、Facebook、Twitterでの認証を簡単に設定することが可能です。

本記事は、そのうちAzureAD認証を設定した場合に発生したエラーの対応手順となります。

# エラー内容

appservice認証機能はポータルで簡単に設定することが可能です。メニューの「認証/承認」からappservice認証をオンにし、Azure Active Directoryを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/0e5764b1-98ab-c37d-a297-34fd0efff35f.png)

Azure Active Directoryの設定は簡易メニューだと名前を入力するだけで設定可能です。本エラーは、ここで「Common Data Servicesに対するアクセス許可を付与する」をオンにした場合に発生します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/f6783c73-d40b-fb2b-b2f8-69ae27e203f2.png)

設定したWebAppにアクセスしてみると、サブスクリプションとテナントの状況によっては、401エラーになる場合があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/b5e6d08b-ec48-a6d0-e92c-cd8f2e24df60.png)

`{"code":401,"message":"An error of type 'access_denied' occurred during the login process: AADSTS650052: The app needs access to a service ('http://rts.powerapps.com') that your organization '53cf3xxx-xxxxxxxx-xxxxxxxx' has not subscribed to or enabled. Contact your IT Admin to review the configuration of your service subscriptions. Trace ID: 57d090xxxxxx-xxxxxxxxxx-xxxxxxxxx Correlation ID: 0935axxxx-xxxxxxxxx-xxxxxxxxxxxxx Timestamp: 2020-10-20 08:47:00Z"}`

# エラーの意味と対応手順

ぱっと見エラーメッセージが分かりづらいですが、Common Data Serviceへのアクセス権限が無くエラーになっているようです。Common Data Serviceは[「PowerAppsアプリケーションで使用されるデータストア」](https://docs.microsoft.com/ja-jp/powerapps/maker/common-data-service/data-platform-intro)とのことですが(実際にはPowerAppsに限らずデータストアとして利用可能なよう)、[ライセンスの概要](https://docs.microsoft.com/ja-jp/power-platform/admin/pricing-billing-skus)を見ると別途購入が必要なようで、これを行っていないテナントに紐づくサブスクリプションではエラーが発生します。

## 対応手順

appservice認証の設定時にCommon Data Servicesに対するアクセス許可を付与しようとしたのが(ライセンスを持たないサブスクリプションでは)不要な処理でした。この設定を外します。

AzureポータルのActive Active Directoryで設定可能です。「アプリの登録」から、作成されたアプリケーションを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/8fd235a1-344a-e150-a2b6-ffc23f50f56d.png)

APIのアクセス許可メニューを選択すると、「PowerApps Runtime Service」へのアクセス許可(依頼)が設定されています。これを右の「・・・」メニューから削除します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/f8d2848f-b371-6a93-56cb-8e497d4188b3.png)

確認ダイアログで「はい、削除します」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/651ab6ff-72f9-79b4-d35e-c8f5297bf7a8.png)

削除後にWebAppにアクセスすると、今度はアクセス許可要求のダイアログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/cdb2ce45-c87f-bce6-3558-a25d736efe11.png)

承諾すると、WebAppにアクセスできるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/09a0eb81-4ed3-541d-9e2f-68a8c8145b47.png)

# 参考資料

- [Azure AD ログインを使用するように App Service または Azure Functions アプリを構成する](https://docs.microsoft.com/ja-jp/azure/app-service/configure-authentication-provider-aad)
- [Common Data Service とは何か？](https://docs.microsoft.com/ja-jp/powerapps/maker/common-data-service/data-platform-intro)
- [Power Platform のライセンスの概要](https://docs.microsoft.com/ja-jp/power-platform/admin/pricing-billing-skus)
【Swift】複数行のUILabelの余白を設定する：上下左右

# はじめに

環境は
・Xcode 11.6
・Swift 5
になります。

ラベルの余白（パディング）を設定したいとき、ありますよね？

例えばtextViewの場合は`textContainerInset`、UIButtonの場合は`contentEdgeInsets`なんかを使って、比較的楽に設定できるかと思います。

しかしUILabelの場合は少し面倒で、複数行のテキストだと尚更。

# まず試すこと

特に横方向の余白については、`attributedText`できれいに解決するかも。
以下は一例。

```swift
let style = NSMutableParagraphStyle()
// horizontal setting
style.headIndent = 0
style.tailIndent = 0
// vertical setting
style.lineSpacing = 0
style.maximumLineHeight = 16
style.minimumLineHeight = 16
style.paragraphSpacingBefore = 10
style.paragraphSpacing = 30

let attr: [NSAttributedString.Key : Any] = [
    .font: ...,
    .paragraphStyle : style,
]
let attributedText = NSAttributedString(string: "hoge", attributes: attr)

let label = UILabel()
label.attributedText = attributedText
```

縦方向については、行間隔と行の高さを指定できるものの、直接余白を設定できないのが悔しい。
ただしテキストが１行の場合は、行の高さとフォントサイズをうまく設定して、実質的に上下の余白をコントロールするやり方も。

# 大抵はこれでオッケー

検索すればよく出てくるやり方だが、以下のようにUILabelを継承したカスタムLabelを作ってやれば、大抵は解決する。

きちんと上下左右の余白を設定できる。

```swift

class PaddingLabel: UILabel {

    var padding: UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

    override func drawText(in rect: CGRect) {
        let newRect = rect.inset(by: padding)
        super.drawText(in: newRect)
    }

    override var intrinsicContentSize: CGSize {
        var contentSize = super.intrinsicContentSize
        contentSize.height += padding.top + padding.bottom
        contentSize.width += padding.left + padding.right
        return contentSize
    }
    
    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var contentSize = super.sizeThatFits(size)
        contentSize.width += padding.left + padding.right
        contentSize.height += padding.top + padding.bottom
        return contentSize
    }
}
```

ここで`sizeThatFits(_ size: CGSize)`は無くても良いが、これがあると`sizeToFit()`したときに余白を含んだ大きさで自動調整してくれるので、ありがたい。
もちろん、`sizeToFit()`で余白を含めたくなければ、オーバーライドしないでおく。

# 最終手段

以上で解決しない問題があったら、おそらく最終手段は

UILabel( ) in UIView( )

として、ラベルは通常の`sizeToFit()`で余白なしの状態にしてから親ビュー内の任意の位置に配置することによって、親ビューを余白つきのラベル（もしくはボタン）として扱える。

この場合は親ビューのサイズをこちらで指定しないといけないが、`sizeToFit()`+`AutoLayout`で半自動化はできるはず。

# 最後に

他に良い方法があったら教えてください！