OmniAICreator/Qiita-1.07M huggingface dataset:
Unity　Recorderで　360度　動画を作る方法

今回はUnity　tipsということで　

360度　動画を作る方法を見ていきます。　

予め　360度動画や画像を用意しておいて　
ください。

※　Unityのvrは　２０１９．３を使用しています。


# ステップ１　Unity　Recorderを入れる

まずUnityを開いて　ウインドウから　

パッケージマネージャーを開きます。　　

開くとこんな画面になるので　↓
![bandicam 2020-05-21 20-25-41-157.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295760/6f56793a-12e9-15ce-b176-0feb94afa539.jpeg)




画面の右上にある　advancdをクリック　

そして　show　previewを選択します。　

そしたら　Unity　Recorderが出てくるので　

それをインストールします。　



# ステップ２　Recorderを開く　

ウインドウ→　一般　→　Recorder　→　RecorderWindowを開きます。　

開くとこんな画面になると思います。


![bandicam 2020-05-21 20-33-52-246.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295760/b2222772-139b-6b2d-d657-ec54e8bd2c87.jpeg)




ここで　設定をしていきます。　

最初に　Ａｄｄ　NEW　Recordersを押して　

movieを選択。

format　は　mp4にする。　

Captureを　３６０Ｖｉｅｗにする。

音も入れたい場合は、　audioにチェックを入れる　

そして　左上にある、　スタートを押します。

そうすると　ゲーム画面が録画されます。　

終了したいときは　ストップを押します。　



このときの注意ですが　カメラのタグが　

メインカメラになっていないとエラーになります。

出力した動画は　パスの所から確認できます。　



# ステップ３　　メタデータを入れてあげる

このままでは、　360度動画で　視点移動ができないので　

それをできるようにします。
メタを入れる場合は　こちらのツールを使います。

https://github.com/google/spatial-media/releases/tag/v2.0



Windows版　とｍａｃ版がそれぞれあるので　

使っている方を入れていきます。

ｅｘｅファイルを開くと　こんな画面になると思います。

![bandicam 2020-05-21 20-49-03-487.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295760/01ab548c-1a34-1545-5cea-2859576cedec.jpeg)




最初にコードの画面が出ると思いますが　

それはEnterを押せば大丈夫です。　　

次に　openを押して　

先程作った　360度動画を選択します。　

そして、　my　video　is　360にチェックを入れて　

Injectを　押して　ファイルを保存します。　　

これで360度動画の完成です。　



ＰＳ

[Unity講座](https://note.com/zazizuzezo22334/n/n90340339a00c?magazine_key=m3f4ee59f0352)
も　好評発売中です。　
セールはもうすぐ終了しますので
【salesofrce】Advanced Apex Specialist スーパバッジStep1　STANDARD_PRICEBOOK_ID は何を設定すべきか

記事の最後に書かれたサンプルコードはこちそち転がっているが、結局のところ、STANDARD_PRICEBOOK_ID に何を設定すべきか。
答えは、環境上にすでに存在した「標準価格表」のIdとなる。

手順1：Price booksタブを表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625521/a05be9e3-8c3d-38c7-036d-f7d1a9547069.png)


手順2：すべて表示のレコードの表示させビューを選択
※すべてのレコードを表示させるビューがなければ、作成してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625521/9e450489-3765-14aa-98e9-637b59126282.png)


手順3：Standard Price Book レコードのSFIDを取得し、設定すればＯＫ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625521/88fcf4f8-e577-85ea-14e7-5f240786b3dd.png)



――サンプルコード――――――――――――――――――
public class Constants {
	public static final Integer DEFAULT_ROWS = 5;
    public static final String SELECT_ONE = Label.Select_One;
    public static final String INVENTORY_LEVEL_LOW = Label.Inventory_Level_Low;
    public static final List<Schema.PicklistEntry> PRODUCT_FAMILY = Product2.Family.getDescribe().getPickListValues();
    public static final String DRAFT_ORDER_STATUS = 'Draft';
    public static final String ACTIVATED_ORDER_STATUS = 'Activated';
    public static final String INVENTORY_ANNOUNCEMENTS = 'Inventory Announcements';
    public static final String ERROR_MESSAGE = 'An error has occurred, please take a screenshot with the URL and send it to IT.';
    public static final String STANDARD_PRICEBOOK_ID = '01s2w000006rf14AAA';
    
}
Unityで作成したC#スクリプトがVisual Studio 2019で正しく読み込まれない問題

# 結論から言います
まずUnityを開き、以下の手順で環境設定まで行きます。
　[Edit]->[Preferences...]

External Script EditorをVisual Studio 2019(Community)に変更します。
　[External Tools]->[External Script Editor]->Visual Studio 2019(Community)

これで認識させることができました。

#参考ページ
SSchmidさん、感謝です。
https://stackoverflow.com/questions/26094908/unity-project-doesnt-have-solution-file

#背景
気が向いたら書きます。。。
Railsテスト

#前提
本日学んだことを書いていきます。

#本題

present?はRailsによって追加されたObjectクラスのインスタンスメソッド。
このメソッドはblank?メソッドの否定。
blank?メソッドの意味はクラスによって異なる。
文字列の場合は、❶長さが０である、または❷全ての文字列が空白文字（半角スペース、タブ、改行、復帰、改ページ）である場合にblank?メソッドがtureを返す。
配列の場合は、要素数が０の時にblank?メソッドがtrueを返す。
nil.blank?は常にtrueを返す。

#アセットパイプライン
初期状態のRailsアプリケーションでは、app/assetsディレクトリにimages、javascripts、stylesheetsと言う3つのサブディレクトが存在する。
それぞれ画像ファイル、JavaScriptファイル、CSSファイルを置くためのディレクトリ。
Railsではこれらのファイルをアセット（assets）と呼ぶ。
**アセットパイプライン機能の最大の売りは、ファイルの変換と統合。**

##メリット
ブラウザとRailsアプリケーションの間のHTTP通信の回数が減ること。
HTTP通信は接続開始処理のところで比較的大きな負荷をサーバーにかけるため、回数を減らすことが大事。


#Sacc/SCSSとは
Sassは、CSSを拡張したスタイルシート言語。
CSS3と互換性を保ちつつ、ネスティング、変数、ミックスインなどの特徴を備えている。
ブラウザはSassを理解できないため、サーバー側でSassをCSSに変換してブラウザに送る必要がある。
この処理をコンパイルと呼ぶ。
Sassにはインデントによって構造を表現するオリジナルの書式と、波括弧{}によって構造を表現するSCSSと呼ばれる書式がある。


#RSpecテストの導入

```Gemfile.
#省略

group :development, :test do
  gem 'rspec-rails', '~> 4.0.0.beta2'  # 追記
  #省略
end
```

```
$ bundle install
```
続いて、RSpecの各種設定ファイルやフォルダを作成するため次のコマンドを実行。

```
$ rails generate rspec:install
```
生成された.rspecファイルに、テストの出力結果をわかりやすく表示させるようにするための設定を追加。

```/.rspec
--require spec_helper
--format documentation # 追記
```
さらに、binstubをインストールしてテストの起動時間を早くする設定を行う。
bin/rspecを実行できるようにし、テストを早くする設定をしていく。


これを実現するには、Springというアプリケーションの起動時間を素早くするgemが必要になる。
Gemfileに下記を追記し、bundle installを実行。

```Gemfile.
#省略

group :development do
  gem 'spring-commands-rspec'  # 追記
  #省略
end
```

```
$ bundle install
```
新しいbinstubを作成し、bin/rspecが実行できるようにする。

```
$ bundle exec spring binstub rspec
```
bin/rspecが実行できるかどうか、試してみる。

```
$ bin/rspec
#省略

Running via Spring preloader in process 21348
No examples found.

Finished in 0.00045 seconds (files took 0.17522 seconds to load)
0 examples, 0 failures
```
まだテストは０個のため、これでひとまずOK。


#Rubocopの導入
デフォルトのRubocopを導入してもいいが、デフォルトに加えてたくさんルールを追加しなければならず手間となる。そこで、Airbnb社が公開しているカスタマイズ済みのrubocop-airbnbというgemを使用。

```Gemfile.
group :development, :test do
  #省略
  gem 'rubocop-airbnb'  # 追記
end
```

```
$ bundle install
```
Rubocop導入に必要なファイルを作成

```.rubocop_airbnb.yml
require:
  - rubocop-airbnb
```

```.rubocop.yml
inherit_from:
  - .rubocop_airbnb.yml

Rails:
  Enabled: true
```
Rails: Enabled: trueは、Rails用に最適化されたモードにする設定。基本trueにしておく。

Rubocopを実行

```
$ bundle exec rubocop
Inspecting 59 files
.....C...CC.....C...CCC...C...CC...CC.....C...CC....CC.C....

Offenses:

app/helpers/application_helper.rb:2:18: C: Airbnb/OptArgParameters: Do not use default positional arguments. Use keyword arguments or an options hash instead.
 def full_title(page_title = '')
                ^^^^^^^^^^^^^^^
#省略
59 files inspected, 32 offenses detected
```



```
#余分な改行がある
spec/requests/static_pages_spec.rb:27:1: C: Layout/EmptyLinesAroundBlockBody: Extra empty line detected at block body end.
```

```
#末尾に改行がない
spec/support/capybara.rb:11:4: C: Layout/TrailingBlankLines: Final newline missing.
```
JavaScriptのアロー関数が好きではない

JavaScriptのアロー関数が好きではない。

```js
const f = () => { a++; };

let a = 1;
f();
console.log(a); // 2 ←
```

こんな仕様当然みんなからフルボッコの[WTF案件](https://qiita.com/rana_kualu/items/793f0cbdde6a88f86394)だろうと思いきや、批判以前にそもそもこの仕様について言及している記事自体がほとんど見当たらない。
[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)にすらはっきりとは書かれていない。
[仕様書](https://tc39.es/ecma262/#sec-arrow-function-definitions)まで追えば当然載ってはいるんだけど、こんなところまでいちいち読んでられませんよね。

まあ[スコープチェーン](https://qiita.com/santaku3109/items/ad66f57ebb70b580ebaa#%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97%E3%83%81%E3%82%A7%E3%83%BC%E3%83%B3)というJavaScriptデフォルトの仕様のせいであるわけですが、しかしわざわざ最近追加された仕組みなのだからこんなクソ仕様は断ち切ってほしかったところですね。
アロー関数の仕様を決めるときに誰も何も言わなかったのか？
Vue(Vue-CLI)とTypeScriptのhighchartsグラフの数値に桁区切りを入れる

# はじめに
highchartsではデフォルトの区切りにスペースを使用しています。highchartsのグラフにカーソルを合わせたときに表示される数値に桁区切りを入れるところでハマったので、本記事を書きました。

# 通常の表示

```Graph.vue
<template>
	<div>
		<highcharts :options="graph"></highcharts>
	</div>
</template>

<script lang="ts">
	import { Component, Vue } from 'vue-property-decorator';
	import { Chart } from 'highcharts-vue';
	
	export type DataType = {
		graph: any;
	}

	@Component ({
		components: {
			highcharts: Chart 
		},
	})
	export default class Graph extends Vue {
		data (): DataType {
			return {
				graph: {
					title: {
						text: 'Xperiaの値段(au)'
					},
					xAxis: {
						categories: ['Xperia 1', 'Xperia 5'],
						crosshair: true
					},
					yAxis: {
						title: false,
						labels: {
							format: '{value} 円'
						},
						opposite: false,
					},
					credits: {
						enabled: false
					},
					tooltip: {
						pointFormat: '{series.name}：{point.y:,.0f} 円'
					},
					series: [{
						name: '一括価格',
						type: 'column',
						data: [92880, 81400],
						marker: {
							enabled: true
						},
					}],
				}
			}
		}
	}
</script>

<style>
	div {
		width: 80%;
		height: auto;
		margin: 20px auto auto auto;
	}
</style>
```

![スクリーンショット (32).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483911/3121d06b-7d91-3115-3277-fac38ae5bd65.png)

このように、桁区切りがスペースで表示されます。Xperia 1の値段を**92 880円**から、**92,880円**に表示したい場合は下記のようにします。

# 桁区切りで表示
import HighchartsとHighcharts.setOptionsを追加します。

```diff:Graph.vue
import { Chart } from 'highcharts-vue';
+ import Highcharts from 'highcharts';
+ Highcharts.setOptions({
+ 	lang: {
+ 		thousandsSep: ','
+ 	}
+ });
export type DataType = {
```

```Graph.vue
<template>
	<div>
		<highcharts :options="graph"></highcharts>
	</div>
</template>

<script lang="ts">
	import { Component, Vue } from 'vue-property-decorator';
	import { Chart } from 'highcharts-vue';
	import Highcharts from 'highcharts';
	Highcharts.setOptions({
		lang: {
			thousandsSep: ','
		}
	});
	
	export type DataType = {
		graph: any;
	}

	@Component ({
		components: {
			highcharts: Chart 
		},
	})
	export default class Graph extends Vue {
		data (): DataType {
			return {
				graph: {
					title: {
						text: 'Xperiaの値段(au)'
					},
					xAxis: {
						categories: ['Xperia 1', 'Xperia 5'],
						crosshair: true
					},
					yAxis: {
						title: false,
						labels: {
							format: '{value} 円'
						},
						opposite: false,
					},
					credits: {
						enabled: false
					},
					tooltip: {
						pointFormat: '{series.name}：{point.y:,.0f} 円'
					},
					series: [{
						name: '一括価格',
						type: 'column',
						data: [92880, 81400],
						marker: {
							enabled: true
						},
					}],
				}
			}
		}
	}
</script>

<style>
	div {
		width: 80%;
		height: auto;
		margin: 20px auto auto auto;
	}
</style>
```

![スクリーンショット (33).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483911/a4e32d6e-80ba-f166-69b9-9a48011f59bd.png)

3桁区切りで表示することができました。

# おわりに
合わせてこちらもご覧ください。
<a href="https://qiita.com/rockhopper-penguin/items/00898c1e8be54e8c1c15" target="_blank">Vue(Vue-CLI)とTypeScriptでhighchartsのグラフ表示</a>
GolangでScannerを使った時と使わなかった時

# 前書き 
始めまして、メガネです。
AtCoderをGolangでやった時にScannerを使った時と使わなかった時の差がどれくらいでるか検証してみました。
なおこの記事は本人の思い付きで書いているので、いろいろツッコミどころがあると思いますが、生暖かい目で見てもらえるとうれしいです。あと、本文中には提出したコードを載せないようにしました。

# 検証内容
GolangでScannerを使った場合と使わなかった場合の二つの実行時間の差を検証する。ただし、計算量がO(N)の問題を使用し、Nの値は制約の中で一番大きい数とする。なお、入力以外の部分のコードは同じものとする。

# 使用言語
Go (1.6)

# 検証に使用した問題
1. [AtCoder Beginner Contest 81 B - Shift only](https://atcoder.jp/contests/abc081/tasks/abc081_b)
- [AtCoder Beginner Contest 142 B - Roller Coaster](https://atcoder.jp/contests/abc142/tasks/abc142_b)

#Scanner部分のコード

```go:Scanner.go
package main
import(
  "fmt"
  "bufio"
  "os"
  "strconv"
)
var sc=bufio.NewScanner(os.Stdin)
func nextInt() int{
  sc.Scan()
  i, e :=strconv.Atoi(sc.Text())
  if e!=nil{
    panic(e)
  }
  return i
}
func main(){
  var i int
  sc.Split(bufio.ScanWords)
  n:=nextInt()
  a:=make([]int, n)
  for i=0;i<n;i++{
    a[i]=nextInt()
  }
}

```

#検証結果

#### AtCoder Beginner Contest 81 B - Shift onlyでの結果

$N=200$である。

Scannerを使用した場合
![2020-05-21 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326471/5a529657-9d93-9b3e-b23f-4a44c9f2db76.png)

結果　1 ms

Scannerを使用しなかった場合
![2020-05-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326471/0b7ab2fb-3338-6733-b8bd-a1cbc575fb0e.png)
結果　3 ms

#### AtCoder Beginner Contest 142 B - Roller Coasterでの結果

$N=10^5$である。

Scannerを使用した場合
![2020-05-21 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326471/8daa4e25-ab43-451e-2b42-6a5c94f8011c.png)
結果　16 ms

Scannerを使用しなかった場合
![2020-05-21 (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326471/624a2669-0561-b72e-2ea7-c2dbdda13c2e.png)
結果　314 ms

# 考察
$N=100$の時ではScannerを使うとおよそ3倍ほど早くなったが、$N=10^5$の時では20倍ほど早くなった。(正確には19.625倍) これを[GeoGebra](https://www.geogebra.org/)というサイトで雑にプロットしてみた。![2020-05-21 (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326471/44e7ee9d-4fee-6ca0-a774-7c45cdb504ea.png)
A=(1,3), B=(16,314)でとってみたら、ぱっと見$y=x^5$くらいの傾きになった。Nの値が大きければ大きいほど、Scannerは使うべきである。これだけでTLEを回避できそうなくらいである。やはりGo is God.

# 終わりに
思い付きで1時間弱で書いたのでわりとガバガバなところもありますし、検証に使った問題がたったの二問だけですので、このデータは十分正確ではないです。夏休みに気が乗ったら検証方法をよりよくして改訂版を書くかもしれないので、またその時にいい感じにします。何かあればTwitterのhima_megane_ までお願いします。
レポートとダッシュボードを使用したデータの分析

１．次の機能のうち、Lightning Experience でのみ使用できるのはどれですか?
２．Lightning Experience でレポートを参照中にできることはどれですか?
３．ダッシュボードコンポーネントについて質問をするのに最もよい方法はどれですか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/870658bf-6d50-5e86-afb3-3a2e24a57456.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/34185b56-3800-1fb3-6a81-98d61744a212.png)
opencv-rustでビルドに失敗したときの話

# 失敗したときの環境

| item | desc |
|:--|:--|
| OS | MacOS 10.14.6 |
| OpenCV 4 directory | /usr/local/Cellar/opencv/4.3.0 |
| opencv-rust features | buildtime-bindgen,contrib |
| How to install Opencv | brew install opencv |
| llvm directory | /usr/local/Cellar/llvm/7.0.1/ |

```toml
[package]
name = "***"
version = "0.1.0"
authors = ["***"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
opencv = { version = "0.36.0", features = ["buildtime-bindgen"]}
--- あと他にbindgenを利用するcrate ---
```

# 解決策 (追記 2020/05/26)

```toml
[package]
name = "***"
version = "0.1.0"
authors = ["***"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
opencv = { version = "0.37.0", features = ["buildtime-bindgen", "clang-runtime"]}
--- あと他にbindgenを利用するcrate ---
```

# 
現時点(2020/05/21)での解決策


```toml
[package]
name = "***"
version = "0.1.0"
authors = ["***"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
opencv = { git = "https://github.com/twistedfall/opencv-rust.git", features = ["buildtime-bindgen", "clang-runtime"]}
--- あと他にbindgenを利用するcrate ---
```


# 解決までの道筋

https://github.com/twistedfall/opencv-rust/issues/129

# 失敗した原因

opencv-rustを利用している、Cargo.toml内でbindgenを利用していた。そのbindgenが`clang-runtime`ベースで動いていた。
opencv-rustを始めとしてbind generationを並列でやるときにclang-runtimeベースだとうまく動かないらしい。

# 解決方法

featureとして`clang-runtime`というものを用意して `clang-runtime`がついてるときは(ビルド速度を犠牲にして)非並列でbind generationを行うことにした。
ESP-WROOM-32開発ボードを使うための準備

#ESP-WROOM-32開発ボードを使うための準備

## ArduinoIDEをインストール。
https://www.arduino.cc/

## ArduinoIDEの環境設定

Boards Managerが必要なので、Gitで最新の「Stable release link」を確認

https://github.com/espressif/arduino-esp32

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303278/21c6ed89-6e8c-7395-50b4-70bed170faf5.png)

「Instructions for Boards Manager」のリンクを押下。
　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303278/2d08b1c0-6f01-8b66-dd51-1828622aac21.png)

「Stable release link:」のURLをコピーして、ArduinoIDEの環境設定で

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303278/e94be9ad-efb1-7d54-ebf4-ef6aefc14807.png)

「追加のボードマネージャーのURL」へ貼り付け。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303278/439ef447-f8a1-ec4b-ed82-c545b123a1ad.png)

「ツール」から「ボードマネージャー」を開く

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303278/43d2db69-3536-f1c0-550a-a6610da3f16a.png)

「ESP」で検索して、インストールする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303278/409777db-1d37-fea1-88b2-1d4550ec44c2.png)

インストールが完了すれば、ボードが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303278/840305cd-4b9b-36f4-9141-7a0a9ae90fa8.png)

#USBでつなげてもシリアルポート番号を認識しない場合
ドライバーが必要なので、ダウンロードしてインストール。

https://jp.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303278/df189602-e40e-09f4-d98e-7b952953d2c4.png)


以上
EC-CUBE4 で割引明細を追加するカスタマイズの例

EC-CUBE4 で割引明細を追加するカスタマイズの例

以下のPHPファイルを作成する。

app/Customize/Service/PurchaseFlow/Processor/TestDiscountProcessor.php

```php:app/Customize/Service/PurchaseFlow/Processor/TestDiscountProcessor.php
<?php


namespace Customize\Service\PurchaseFlow\Processor;


use Doctrine\ORM\EntityManagerInterface;
use Eccube\Annotation\OrderFlow;
use Eccube\Annotation\ShoppingFlow;
use Eccube\Entity\ItemHolderInterface;
use Eccube\Entity\Master\OrderItemType;
use Eccube\Entity\Master\TaxDisplayType;
use Eccube\Entity\Master\TaxType;
use Eccube\Entity\OrderItem;
use Eccube\Service\PurchaseFlow\PurchaseContext;
use Eccube\Service\PurchaseFlow\DiscountProcessor;

/**
 * 値引きを追加する.
 *
 * ここでフローを指定
 * @ShoppingFlow
 * @OrderFlow
 */
class TestDiscountProcessor implements DiscountProcessor
{
    /**
     * @var EntityManagerInterface
     */
    protected $entityManager;

    /**
     * TestDiscountProcessor constructor.
     *
     * @param EntityManagerInterface $entityManager
     */
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function removeDiscountItem(ItemHolderInterface $itemHolder, PurchaseContext $context)
    {
        foreach ($itemHolder->getItems() as $item) {
            if ($item->getProcessorName() == TestDiscountProcessor::class) {
                $itemHolder->removeOrderItem($item);
                $this->entityManager->remove($item);
            }
        }
    }

    public function addDiscountItem(ItemHolderInterface $itemHolder, PurchaseContext $context)
    {
        /* 必要であればここで適応条件の制御をする
         * if...
         */
        
        // 課税/不課税や税込/税抜はここで作成
        $DiscountType = $this->entityManager->find(OrderItemType::class, OrderItemType::DISCOUNT);
        $TaxInclude = $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::EXCLUDED);
        $Taxation = $this->entityManager->find(TaxType::class, TaxType::TAXATION);

        $OrderItem = new OrderItem();
        $OrderItem->setProductName($DiscountType->getName())
            ->setPrice(-100)
            ->setQuantity(1)
            ->setTax(-10)
            ->setTaxRate(10)
            ->setRoundingType(null)
            ->setOrderItemType($DiscountType)
            ->setTaxDisplayType($TaxInclude)
            ->setTaxType($Taxation)
            ->setOrder($itemHolder)
            ->setProcessorName(TestDiscountProcessor::class);
        $itemHolder->addItem($OrderItem);
    }
}
```
WordPressでカスタマイズAPIを作る

WordPressの記事コンテンツをAPIとして書き出すには公式同等の[WP REST API](https://ja.wp-api.org/)が存在します。
しかし、セキュリティ面での懸念もあり、いろいろいらない情報が書き出されてしまったり、APIの構造が複雑になったり、いろいろデメリットがあります。
固定ページの機能を活用し、スラッグAPIの固定ページを作成し、テンプレートファイルにpage-api.phpファイルを作ってしまえば、カスタマイズしたAPIを簡単に作れちゃいます。
そのコードをご紹介します。

```page-api.php
<?php
// ベーシック認証
switch (true) {
    case !isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']):
    //ベーシック認証のID・PWを設定
    case $_SERVER['PHP_AUTH_USER'] !== 'user_name':
    case $_SERVER['PHP_AUTH_PW']   !== 'pass_word':
        header('WWW-Authenticate: Basic realm="Enter username and password."', true, 401);
        header('Content-Type: text/plain; charset=utf-8');
        die('認証が必要です');
}
header('content-type: application/json; charset=utf-8');
header("Access-Control-Allow-Origin: *");

if($_SERVER["REQUEST_METHOD"] == "GET"){
  $api_data = '[';
  if(isset($_GET['cat_api'])) {//カテゴリ指定がある場合
    $cat_id = $_GET['cat_api'];
    $posts = wp_get_recent_posts(array( 'numberposts' => 10, 'post_status' => 'publish', 'category' => $cat_id ) );//公開済みの記事を対象に
  }else{//カテゴリ指定がない場合、全記事を対象に
    $posts = wp_get_recent_posts(array( 'numberposts' => 10, 'post_status' => 'publish,private' ) );
  }
  foreach($posts as $post){
    $post_id = $post["ID"];
    $category = get_the_category($post_id);
    $cat_name = $category[0]->cat_name;
    $thumbnail = get_the_post_thumbnail_url($post_id);
    $update = get_the_modified_date("Y-m-d H:i:s", $post_id);
    $status = get_post_status($post_id);
    $post_url = '{"url":' .  site_url() . $post["post_name"] . '/",';
    $post_image = '"image":' . '"' . $thumbnail .'",';
    $post_date = '"date":' . '"' . $post["post_date"] . '",';
    $post_update = '"update":' . '"' . $update . '",';
    $post_status = '"status":' . '"' . $status . '",';
    $post_category = '"category":' . '"' . $cat_name . '",';
    $post_title = '"title":' . '"' . $post["post_title"] . '",';
    $post_excerpt = '"expert":' . '"' . $post["post_excerpt"] . '",';
    $post_content = $post["post_content"];
    $post_content = wpautop($post_content); //余計な改行等々
    // 関連記事のデータ生成
    $relateds = wp_get_recent_posts(array( 'numberposts' => 3, 'post_status' => 'publish', 'category' => $category_id ) );
    $post_related = '<h2>関連記事</h2><ul>';
    foreach($relateds as $related){
        $related_id = $related["ID"];
        $post_related .= '<li><a href="' . site_url() . $related["post_name"] . '/">' . $related["post_title"] . '</li>';
    }
    $post_related .= '</ul>';
    $post_content .= $post_related;
    $post_content = str_replace('"', '\"', $post_content);
    $post_content = '"content":' . '"' . $post_content . '"},';
    $api_data = $api_data . $post_url . $post_image . $post_date . $post_update . $post_status . $post_category . $post_title . $post_excerpt . $post_content;
  }
  $api_data = $api_data . ']';
  $api_data = preg_replace('/(?:\n|\r|\r\n)/', '', $api_data ); //余計なものを一括置換
  $api_data = str_replace('},]', '}]', $api_data);
  $api_data = str_replace('	', '', $api_data);
  print $api_data;
}else{
  header("HTTP/1.0 404 Not Found");
  return;
}


```
サクッとaタグでPOST送信（自分メモ）

### はじめに
今回、aタグでpost送信したい時(ログアウトのリンクをクリック)がありましたので、その記述をメモとして残します。簡易的な自分用のメモですので、その点はご了承くださいませ。


### 記述方法
```html
<form
  method="POST"
  name="logout_form"
  action="/logout">
  <!--CSRF-->
  <a href="javascript:logout_form.submit()">ログアウト</a>
</form>
```

aタグのhref属性にjavascript:(実行するJavaScriptコード) の形式で記述します。
上記で行っていることは、formのname属性を指定してあげて、submit()でフォームの内容を送信しています。
はい、以上になります。

### おわりに
簡易なメモではありますが、もし間違い等ありましたらご指摘をお願いいたします。


### 参考資料
[aタグをPOSTにする](https://qiita.com/horikeso/items/cceb42be04e2b6d1d5a6)
[HTMLのAタグでPOSTする方法](https://qiita.com/next1ka2u/items/9736ce2f9c7f3aa69d61)
WordPressのAMP対応をLazyLoadと両立

WordPressの記事コンテンツをAMP対応するために、いろいろプラグインがありますが、
無料のものだと、なかなかうまくいかず、予期せぬバグが発生したり、デザイン面のカスタマイズができなかったり、
いろいろと厳しい部分があります。
プラグインを使わずに、テンプレートファイルをカスタマイズすれば、意外にも簡単に対応できます。
こちらの記事で詳しく紹介されて、参考させていただきました。
[WordPressをプラグインなしでAMP対応させる試み【その1:格闘編】](https://qiita.com/Fujix/items/95119d00c34a0f19d448)

しかし、Lazyloadを使う場合、画像の一括置換でバッティングしてしまい、うまく動作しません。
そのために、functions.phpの該当箇所を両立できるように対応してみました。
ご参考まで！

```functions.php
function add_image_placeholders( $content ) {
	if(isset($_GET['amp']) && is_single()){//ampの場合はampタグに置換
    	$content = preg_replace(
        '#<img([^>]+?)src=[\'"]?([^\'"\s>]+)[\'"]?([^>]*)>#',
		sprintf( '<amp-img layout="responsive" src="${2}"${3}></amp-img>' ), $content );
		return $content;
	}elseif( is_feed() || is_preview() || ( function_exists( 'is_mobile' ) && is_mobile() ) ){//プレビューやフィードモバイルなどで遅延させない
        return $content;
	}elseif ( false !== strpos( $content, 'data-original' ) ){//既に適用させているところは処理しない
        return $content;
	}else{$content = preg_replace(//Lazyload画像正規表現で置換
        '#<img([^>]+?)src=[\'"]?([^\'"\s>]+)[\'"]?([^>]*)>#',//IMGタグの正規表現
        sprintf( '<img${1}src="%s" data-lazy="true" data-original="${2}"${3}><noscript><img${1}src="${2}"${3}></noscript>', get_template_directory_uri().'/images/lazy_image.gif' ),//置換するIMGタグ（JavaScriptがオフのとき用のnoscriptタグも追加）
        $content);//投稿本文（置換する文章）
		return $content;
	}
}
add_filter( 'the_content', 'add_image_placeholders', 99 );
add_filter( 'post_thumbnail_html', 'add_image_placeholders', 11 );

```
ゼロから始めるLeetCode Day32「437. Path Sum III」

#概要
海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

その対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイト。

せっかくだし人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

[Leetcode](https://leetcode.com/)

[ゼロから始めるLeetCode 目次](https://qiita.com/KueharX/items/6ee2502c3b620c795b70)

前回
[ゼロから始めるLeetCode Day31「581. Shortest Unsorted Continuous Subarray」](https://qiita.com/KueharX/items/4d1f1623503f20f70d0b)

基本的にeasyのacceptanceが高い順から解いていこうかと思います。

[Twitter](https://twitter.com/kueharx)やってます。

そういえば一ヶ月分続きました。めでたい。


# 問題
[437. Path Sum III](https://leetcode.com/problems/path-sum-iii/)
難易度はeasy。
Top 100 Liked Questionsのeasyがこれを入れて残り三問となりました。

各ノードに整数値が含まれている二分木が与えられます。

ノードの値を合計して特定の値`sum`になるパスの数を求めます。

経路は親または葉で開始または終了する必要はありませんが、下方向に移動する必要があります（親ノードから子ノードへの移動のみ）。

なお、ツリーのノード数は1,000以下で、値の範囲は-1,000,000〜1,000,000です。

>root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

```

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

```

>Return 3. The paths that sum to 8 are:

>1.  5 -> 3
2.  5 -> 2 -> 1
3. -3 -> 11

# 解法

再帰を使ったdfsで解きました。

```Python
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    ans = 0
    def pathSum(self, root: TreeNode, sum: int) -> int:
        def dfs(root,sums,start):
            if not root:
                return 0
            sums -= root.val
            if sums == 0:
                self.ans += 1
            dfs(root.left,sums,False)
            dfs(root.right,sums,False)
            if start:
                dfs(root.left,sum,True)
                dfs(root.right,sum,True)
        dfs(root,sum,True)
        return self.ans
# Runtime: 940 ms, faster than 24.67% of Python3 online submissions for Path Sum III.
# Memory Usage: 15.1 MB, less than 6.82% of Python3 online submissions for Path Sum III.
```

最初は`root`と`sums`だけでかけるかと思って書いていたのですが、どうもそれだけでは書けなかった（書けるかもしれないが今の私の頭では思いつかなかった）ので、discussを覗いたら[ほとんど一緒の解答](https://leetcode.com/problems/path-sum-iii/discuss/581442/Python-DFS-Recursive-Solution)があり、そこでは現在のnodeを始点として扱うためにbooleanを用いており、非常にすっきりとした実装ができたのでそのままこちらを載せておきます。

それにしてもアルゴリズム強い人すごい・・・

もっと精進しなければならないですね。

良さげな解答があれば追記します。
Three.jsのdirctionalLightの影を最適化する

影の入れ方の最適化を確認します。

基礎～応用まで

**影いれんの最初めんどくさい**

Three.jsで影を作る場合、

###プロパティを設定

```js:qiita.js
obj.castShadow = true;
```
を物体に設定

```js:qiita.js
obj.receiveShadow= true;
```

を床に設定します。

で、出るかなと思ったら、出ない:rage:

###ライトに設定
ライトにも影を出す設定をする必要があるらしい。
いれてないリファレンスはふぁっく:angel_tone1:


```js:qiita.js
directionalLight.castShadow = true;
```

で出ない:rage:

###レンダラーに設定
レンダラーにも影を出す設定をする必要があるらしい。
いれてないリファレンスはふぁっく:angel_tone1:


```js:qiita.js
renderer.shadowMap.enabled = true;
```

で、人によって出る:kiss_mm:
もしくは出ない:rage:
出ても影がおかしい:rage:

###影が出る範囲を設定する

出る範囲がデフォルトで小さい場合があるので、大きくしよう

```js:qiita.js
directionalLight.shadow.camera.right = 12;
directionalLight.shadow.camera.left = -12;
directionalLight.shadow.camera.top = -12;
directionalLight.shadow.camera.bottom = 12;
```
で、(0,0,0)を中心に24*24の矩形の範囲の影ができる:heart_eyes:。

###影の解像度を調整
mapサイズを設定すると影がくっきり出たりするらしい。

```js:qiita.js
directionalLight.shadow.mapSize.width = 512;
directionalLight.shadow.mapSize.height = 512;
```

大きくするとくっきりした影になる。8192くらいにすると綺麗なんだけど、重くなる。2048が限度くらいの認識512に抑えれると嬉しい:heart_eyes:

##本題：影の最適化をする

・影が出る範囲を大きくすればするほど、解像度は小さくなる。
・影が出る範囲を小さくすればするほど、解像度は大きくさくなる。
つまり影が出るエリアをカメラが映してる方向に限定したい。

###確認する為にはHelperを出す。

```js:qiita.js
var directionalLightShadowHelper = new THREE.CameraHelper(Data.directionalLight.shadow.camera);
scene.add( directionalLightShadowHelper);
var directionalLightHelper = new THREE.DirectionalLightHelper( Data.directionalLight);
scene.add( directionalLightHelper);
```

と黄色と赤い枠みたいので照明が当たってるエリアが分かる。

影が出る範囲を

```js:qiita.js
directionalLight.shadow.camera.right = 12+100;
directionalLight.shadow.camera.left = -12+100;
```
みたいにすると移動しそうだ。やる。
移動しない:rage:
left rightの意味はほぼない。普通に0を中心に動くだけ:rage:

ヘルパーを見てると中心地に向けて照明はあたり中心地に影ができ続けてる。

###照明のターゲットが存在する
照明にターゲットのパラメーターが存在している。

```js:qiita.js
directionalLight.position.set( 300, 300, 300 );
directionalLight.target.position.set( 300, 0, 300 );
```
※x:300 z:300から真下(Y)に向けてdhirectionLightを当てるような設定のはず
これで照明を当てるエリアを設定できそうだ。設定。
移動しない:rage:

公式のリファレンスを見る。

>Note: For the target's position to be changed to anything other than the default, it must be added to the scene using

google 翻訳

>注：ターゲットの位置をデフォルト以外の位置に変更するには、次のコマンドを使用してシーンに追加する必要があります

```js:qiita.js
scene.add( directionalLight.target );
```

ついに好きな位置に影のターゲットを移動できた:heart_eyes:
これでカメラが向いた方向のみに高画質な影が存在する設定ができる:heart_eyes:

ライトに設定されてるtargetを更に追加しないと変化しないとかが意味不明な感じでしたが、
なんとか実装をする事ができました。
Docker ToolboxでのWindows10共有フォルダマウント方法 備忘録

Dockerを使用する際、ホスト⇔コンテナ間でファイルを共有したい時の方法になります。
sshよりローカルでいじりたい！という人向け。

# 使用ツール
Docker Toolbox v19.03.1
ホストOS：Windows 10 Home
コンテナOS：CentOS

## 本記事で使用するフォルダ名
ホストOS：`folder_host`
Dockerマシン：`folder_machine`
コンテナOS：`folder_container`

## 1.VirtualBoxの共有フォルダを設定する
VirtualBox->対象のDockerマシンの設定->共有フォルダー->追加
ホストOS側の共有させたいフォルダ絶対パスと、Dockerマシンに配置されることになる共有フォルダ名を設定する。

ここでは例として、ホストOS側のフォルダ名を`folder_host`、Dockerマシンに配置される共有フォルダ名を`folder_machine`とする
(Dockerマシンに`/folder_machine`が作られることになる)
## 2.Dockerマシンを再起動する(大事)
投稿時は記載し忘たが、Dockerマシンに共有フォルダを認識させるために必要。

```text:再起動
docker-machine restart default
```

## 3.マウントを指定してdocker runする
`-v Dockerマシンに配置される共有フォルダパス:コンテナで使用したいフォルダパス`
例として、コンテナで使用したいフォルダ名を`folder_container`とする。

```text:run例
docker run -d -v /folder_machine:/folder_container centos /sbin/init
```

あとはrunしたコンテナにexecでアタッチする。
例：`docker exec -it <コンテナIDとか名前> /bin/bash`

## 4.ホストOSとコンテナOSでファイルが共有できていることを確認する
ホストOS側のフォルダ`folder_host`と、コンテナOS側のフォルダ：`folder_container`が共有される。
テストは`echo "test" > /folder_container/test.txt`等

### 雑記
本記事は備忘録になります。
検索すると色々なページが見つかりますが自分の環境でうまくいかず余計なことをしている気がして、
中でどういう動作をしているかわからないので少しでも動きを理解するために書きました。
Docker for Windowsに適したWindows 10がアップデートされるまでしょうがなくDocker Toolboxを使ってる人はどうぞ。
いまさら聞けない「コネクションプール」とは？？

メモとして残します。
あくまで私の解釈ベースのため、悪しからず。。。

エンジニアとして恥ずかしいのですが、**コネクションプール**について問われて、「？？。わかりません！」となってしまいました。
調べてみたら概念は知っていたのですが、用語との紐づけができなかったため、改めて勉強してまとめてみます。

#【TL;DR】
###・「コネクションプーリング」、「DBコネクションプール」などと呼称される。
###・DBへの接続情報を保持して、**次回以降の接続コストを軽減**する。
###・コネクションプールとは厳密には**DBへの問い合わせをするコネクション（権利）を保管**している場所。
###・コネクションプールで保持できるコネクションの数はRDBの設定によって変わってくる。（積極型、我慢型、厳格型）
####積極型
動的にコネクション数の上限を調整。
####我慢型
上限数は静的であり、リクエスト＞コネクションとなった場合は順番待ちとなる。
####厳格型
上限数は静的であり、リクエスト＞コネクションとなった場合はコネクションを取得しようとしたセッション（リクエスト）に対してエラーを返す。

#さいごに
ボトルネックとなりうるファクターであるということは今回振り返ってみると、よくわかりました。
WEBはDBへの接続が大半なため、必須な用語ですね。。。
いやはや、概念知ってるけど、用語は知らないってことが、ままあるので、今年その紐づけをするように専念しないと、
エンジニアと円滑に会話ができないな(;^_^A
次回は、MYSQLでコネクションプールの恩恵について実際にクエリを発行して確認してみます。
【Rails】Carrierwaveを導入する

タイトルと本文のみの投稿ができるブログアプリに
写真の投稿機能を追加した時の、Carrierwaveを導入する
手順に付いてまとめました。

#  1.  Gemfileファイルを編集する

```:Gemfile
gem 'carrierwave'
gem 'mini_magick'
```
```:ターミナル
% bundle install
```



# 2.  アップローダーを作成する

```:ターミナル
rails g uploader image
```
実行後、app/uploaders 下に image_uploader.rbが作成されます。

# 3.  アップローダーをマウントする

```ruby:app/models/message.rb
class Message < ApplicationRecord
  belongs_to :group
  belongs_to :user
  belongs_to :heven

  validates :content, presence: true, unless: :image?

  mount_uploader :image, ImageUploader  ⬅️ この１行
end
```

# 4.   画像のリサイズを可能にする
**include CarrierWave::MiniMagick** のコメントアウトを外し、
任意の行に**process resize_to_fit: [800, 800]**と追記。
これにより、縦横比を維持したまま、縦横を800px以内にリサイズ可能になります。

```ruby:app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick  ⬅️ 有効化

# 〜省略〜

  process resize_to_fit: [600, 600]  ⬅️ 追記

# 〜省略〜
end
```
__________________________
以上で画像のアップロードの準備ができました。


ご覧いただきありがとうございました。
OBS (macOS) Virtual Camera で遊ぶ

# OBS (macOS) Virtual Camera で遊ぶ

References に挙げた記事を見て、遊んでみました。

## [OBS (Open Broadcaster Software) Studio](https://obsproject.com/) をインストール

自分の場合、以下のコマンドで最新版が入りましたが、一応最新版かどうか確認しておいてください。

```sh
brew cask install obs
```

## [OBS (macOS) Virtual Camera](https://github.com/johnboiles/obs-mac-virtualcam) をインストール

最近 `.pkg` 形式で、正式版がリリースされたということらしいですが、誰かが早速 brew cask 化してくれているので、これもそれで入れます。

```sh
brew cask install obs-virtualcam
```

## [Zoom.us](https://zoom.us/) をインストール

こちらもインストール後、最新版でなければ、最新版に上げておきます。

```sh
brew cask install zoomus
```

なお v4.6.9 で、おそらくセキュリティの関係上 (リリースノートには一時的にとは書いてありますが) virtual camera が選択できなくなったのですが、以下のコマンドを実行することで最新版でも選択できるようになるそうです。
macOS 10.15 (Catalina) での Device Abstraction Layer (DAL) plugins をアプリが許可しているかどうかというのと関係しているそうですが、セキュリティ的に保証できないので、あくまで私的な実験にお使いください。

```sh
sudo codesign -f -s - /Applications/zoom.us.app
```

もちろん zoom をインストールしなおせば、元に戻ります。

** 追記 (2020-05-31) **

Zoom.us v5.0.4 にて再度 virtual camera が選択可能になりました。これで Zoom でも堂々と OBS 経由の配信ができますね。

- [New updates for May 24, 2020 – Zoom Help Center](https://support.zoom.us/hc/en-us/articles/360043996131-New-updates-for-May-24-2020)

## [Snap Camera](https://snapcamera.snapchat.com/) をインストール

こちらは残念ながら brew cask や App Store に登録されていないっぽいので、手動で [公式ページ](https://snapcamera.snapchat.com/download/) からダウンロードしてインストールします。

## 操作手順

Snap Camera -> OBS Studio (-> OBS Virtual Camera) -> Zoom.us (or Google Meet on Chrome) の経路で映像が流れるようにします。

つまり Snap Camera と OBS Virtual Camera の仮想カメラ2段構えです。

以下の手順で操作します。

1. Snap Camera を起動, Emoji Head を選ぶ!

   ![obs_virtial_camera_trial_01.png](https://files.tearoom6.biz/9593cbe9-73b1-41e8-9ac8-212fc5d0bfe1.png)

2. OBS Studio を起動, Source に Device として "Snap Camera" を選択した "Video Capture" を追加

   ![obs_virtial_camera_trial_02.png](https://files.tearoom6.biz/f7988904-ad9b-4d42-9363-f300fa36d497.png)

   ![obs_virtial_camera_trial_03.png](https://files.tearoom6.biz/2f2cce48-9843-4c8d-868d-59739113b6b8.png)

3. OBS Studio のメニューで [Tools] > [Start Virtual Camera] を選択

   ![obs_virtial_camera_trial_04.png](https://files.tearoom6.biz/d079f07b-c3c4-46c6-b4ce-ca050fd4c377.png)

4. Zoom.us を起動, [Settings] > [Video] > [Camera] に "OBS Virtial Camera Device" を選択 (文字とか入れてる場合は "Mirror my video" を外さないと逆さ文字になりますよ)

   ![obs_virtial_camera_trial_05.png](https://files.tearoom6.biz/c8d00880-76ad-48ed-8db1-e2dd65979a0b.png)

以上です。

> References

- [johnboiles/obs-mac-virtualcam](https://github.com/johnboiles/obs-mac-virtualcam)
- [ライブ配信アプリOBS Studioに仮想カメラを作り出し、ZoomやGoogle Meetなどに映像を直接配信できるOBSプラグイン「OBS (macOS) Virtual Camera」がリリース。 | AAPL Ch.](https://applech2.com/archives/20200520-obs-studio-for-mac-virtual-camera-plugin.html)
- [New updates for macOS – Zoom Help Center](https://support.zoom.us/hc/en-us/articles/201361963-New-updates-for-macOS)
- [Compatibility · johnboiles/obs-mac-virtualcam Wiki](https://github.com/johnboiles/obs-mac-virtualcam/wiki/Compatibility)
Tableau Desktop から Amazon Athena への接続

### Tableau Desktop データソース接続 > Amazon Athena


>サーバ： **athena.【目的のDBがあるリージョン】.amazonaws.com**
> ポート： **443**
> S3ステージングディレクトリ： **【下記アクセスキーの権限で書込み可能なS3バケットおよびディレクトリ】**
> Access Key ID： **【目的のDBへ接続可能なIAMユーザのアクセスキーID】**
> Secret Access Key： **【上記アクセスキーIDに対応するシークレットアクセスキー】**

![Athenaコネクタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582725/a3e0c2c5-365c-d8d3-a70d-00d9ef181d9f.png)

【参考】
https://dev.classmethod.jp/articles/tableau103-new-features-connect-to-athena/
Google ScriptでGoogle formから得たデータを各所に保存、自動返信など

#Goole Formで得たデータをいろんなところで自動で使いたい！
Formで得たデータはスプレッドシートへ簡単に連携できますが、Gmailで自動で返信したり、そのデータを自動でいろんなところに保存したい。仕事したくない。と思って昔作ったスクリプトですが、忘備録と誰かの役にちょっとでも立てれば良いと思うので、公開します。
流れとしては、Google Form -> Spreadsheet　連携。それからトリガを使ってスクリプトを実行し、自動返信や連絡帳に保存、Google Groupのメーリングリストに登録、というところまで。
##Spreadsheetからデータを取得する。

```javascript
 
    //現在のシートを取得
	var sheet = SpreadsheetApp.getActiveSheet();
    //最後の行数を取得、この最新行について処理する。
	var row = sheet.getLastRow();
    //最後の列数を取得
	var column = sheet.getLastColumn();
    //getDataRangeで取得する範囲を決定（これで取得する範囲を限定すると動作が早いかもしれません！）
	var range = sheet.getDataRange();
    //各種変数、今回はメールとお名前
    var mail = "";
    var firstname = "";
    var lastname  = "";

    //各列を巡回
	for (var i = 1; i <= column; i++ ) {
		//ヘッダを取得
		var header = range.getCell(1, i).getValue(); 
		//最新行の値をリストとして取得
		var value = range.getCell(row, i).getValue();
 
		//ヘッダ情報が一致したとき、情報を取得
		if ( header === '苗字　(Lastname)' ) {
            lastname = value;
   		}
		if ( header === '名前　(Firstname)' ) {
            firstname = value;
   		}
   		if ( header === 'メールアドレス' ) {
     		mail = value;
   		}
 	}

}
```

##Gmail APIで連絡帳に追加
Gmail APIを使うと、簡単にスクリプトからメール送信ができます。テストは自分のメールアドレス宛にしましょう笑

```javascript
	var title = "自動返信メールのタイトル"; 
	var contents
	= "自動返信メールの内容";
    //メールの内容、これだと改行がないですが、変数を使ってある程度自由に作れると思います。
    contents = contents + lastname + "様、ご登録ありがとうございました。";
    
	//Gmail APIでメールを送る
	GmailApp.sendEmail(mail,title,contents);
```


##People APIで連絡帳に追加
People APIは詳しくはGoogleさんのドキュメントをご覧いただきたんですが、createContactメソッドでこんなふうに連絡帳に追加が可能です。

```javascript

    //Create Contact through API
    var connections = People.People.createContact(
      body={"names": [{"givenName": firstname, "familyName": lastname}],
      "emailAddresses": [{"value":mail}],
      });

```

##Members APIで今回のメールアドレスをGoogle Groupに追加
メンバースAPIのinsertというメソッドでNewMemberのディクショナリを追加してあげます。

```javascript
    //Add email to Google Group
    var groupEmail = 'Google Groupのメールアドレス';  

    var NewMember = 
        {
         email: mail,
         role: 'MEMBER'
        };

    AdminDirectory.Members.insert(NewMember, groupEmail);

```

こう見ると結構簡単そうですが、最初は何が何だか分からなくて二、三日くらい時間を食い潰しました。誰かの役に立ちますように！
Ruby 技術者認定試験 Silver に合格しました

# はじめに
2020-05-21 に Ruby技術者認定試験 Silver に合格しました。
<img width="550" alt="20200521B.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/2af64247-9a91-2340-3ad0-87a5bc637569.png">
この記事が受験を考えている方の参考になれば幸いです。
# 勉強方法
勉強は次の３つを行いました。

+ 試験対策本
+ 模擬試験
+ AtCoder

# 試験対策本
試験対策本は次の本を使用しました。
*[Ruby技術者認定試験合格教本 Silver/Gold対応　Ruby公式資格教科書](https://www.amazon.co.jp/gp/product/4774175676/)*
購入：4月中旬

改訂2版も出ていますが、こちらも`v2.1`に対応していますので問題ないと思います。~~中古価格が安い~~
気になる方は正誤表のダウンロードをお勧めします。
*[サポートページ](https://gihyo.jp/book/2015/978-4-7741-7567-6/support)*
私自身は、分からないところや気になったところを辞書的に引いたくらいなので、正誤表をダウンロードしましたが見比べなどはしなかったと思います。

使用頻度：中
# 模擬試験
模擬試験問題は次のページを使用しました。
+ *[REx - Ruby Examination](https://rex.libertyfish.co.jp/)*
+ *[DIVE INTO EXAM](https://exam.diveintocode.jp/exam)*
+ *[模擬問題(Silver試験用)](https://gist.github.com/sean2121/945035ef2341f0c39bf40762cd8531e0)*

上の2つは繰返し解くことができますので、学習効果が高いと思います。
<img width="550" alt="20200521C.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/5a024514-2af5-3b94-0065-9b3507dd2cc2.png">
最初は、試験対策本を見ながら若しくはVScode等で実際にコードを実行しながらで構わないと思います。
*[Ruby AtCoder向けVSCode設定](https://qiita.com/superrino130/items/b9a7bedd9737932ddfc9)*

問題を覚えすぎない程度の回数でいいと思います。

使用頻度：高
# AtCoder
私自身は、繰返し実行して覚えるタイプの人間ですので、AtCoder さんの問題を解くことでかなり勉強させていただきました。
<img width="750" alt="20200521D.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/51a582cf-6203-6fe1-2ee1-2a6f401a6eb8.png">
9月末に ***Java*** でスタートし、2020年頃から ***Perl*** に切り替え、更に4月頃に *[もっとプログラマ脳を鍛える数学パズル](https://qiita.com/superrino130/items/ec340b4830b2c312e0cf)* を読んでから ***Ruby*** に切り替えと Ruby 歴は浅いです。
しかし、灰色diff問題を解くことで文法を覚え、茶色diff問題を解くことで String/Array/Hashクラス等のメソッドを覚えました。
*[AtCoder 茶diff 一覧](https://qiita.com/superrino130/items/60912978519b87b09e6f)*

使用頻度：特高
# まとめ
試験勉強に一番のお薦めは、**[AtCoder](https://atcoder.jp/?lang=ja)** さんです。
*[AtCoder Problems](https://kenkoooo.com/atcoder/#/)* さんを併用して活用することにより学習の進捗を確認しながら勉強を進めることができます。

但し、使用するクラス・メソッドの幅が狭くなる（例えば、`key?`を使用する人は`include?` `has_key?` `member?`を覚えない、ヒアドキュメントって何？美味しいの）と思われますので、模擬試験サイトや試験対策本で補う必要はあると思います。

また、**Qiita** に投稿されている先輩諸氏の記事も参考になりましたので、一読をお勧めします。

最後に、投稿した記事にコメントをいただいた皆様に感謝を申し上げます。

```ruby.rb
begin
  print "Happy Programming\n".chomp
end
```
Python3でQRコードを生成する。

ざーっとメモ書き程度になります。
QRコードって日本で作られたものなんですね。
調べれば１０行程度でQRコード生成のスクリプトがつくれるとのこと。


QRコードをPython3で作ってみました。
https://github.com/ajitama/qrcode-generate
画像も埋め込めます。
QRコードの構成情報は４つの■みたいですね。

qrcodeモジュールがあって、それを利用する形です。
QRコードは単純に文字を図形化したものとのことです。
https://www.cman.jp/QRcode/operation/url/read/


発行したQRコードに時間制限はかけられないので、URLを埋めるか、QRコードを読み取るシステム側から、サーバになんらかのリクエストをしないとだめそうです。
https://www.cman.jp/QRcode/faq/qa2_due_date/


これを利用して、乱数を埋め込んで
Base64とかでWEBサーバとかで表示すれば一々画像を保存しなくていいのかな？
時間があったらやってみよう…。

今後の構築のための素材として、残しておきます。
簡易的なKrunkerのチートシート(?)を作りました

#サイト
https://katudon.000webhostapp.com/Home.php
途中まで攻略サイトみたいにしようと思ったんですが、そんなサイトは既に山ほど存在してるので、ダメージとかを計算できるデータベース的なサイトにしました。なので、銃一覧以外は機能しません。
いつかherokuに移すかも。
#使用方法
見たい銃を銃一覧から選択するとその銃の性能を見ることができます。
<img width="578" alt="スクリーンショット 2020-05-21 19.02.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278362/58f6673d-af80-6ad1-fbb1-ed825c4a5e8b.png">

- ドロップダウンメニュー(画像の"スナイパーライフル"って書いてるやつ)を選ぶことでその場で他の銃と比較が出来ます。左上の+を押すことで複数の銃と比較も可能。-を押すと一番右端のやつが消えます。

- 威力のドロップダウンメニューから頭、胴、足それぞれのダメージを見ることが出来ます。

- 総合DPSは勝手に自分が勝手に編み出したDPSで、下に小さく書いてある通り、人間の反応速度やエイム速度等を反映したDPSを計算します。

- 総火力の所に数値を入れると(単位はms)、その間に与えることが出来るダメージの総数を計算します。

以上です。
FirebaseのセキュリティルールをWHEREのように使えると思っていた

Nuxt.js+Firebaseの勉強を始めたばかりです。
みなさんの記事を見よう見まねで、WebページでFirestoreのデータベースにデータを登録できるところまで作成しました。

前回： [Nuxt.js＋Firebaseでログイン情報を保持したい](https://qiita.com/_takahito/items/56c086aa6e90aa61ca5e)

# やりたいこと
Firestoreのデータを誰でも閲覧できてしまっては困るので、ログインユーザーごとにデータを出し分けたいと思います。

# 環境
- Firebase 7.3.0
- Vue CLI 4.0.5
- Nuxt.js 2.10.2

# セキュリティルールを変更したが...
Firestoreの構成は次の通りです。

コレクション|ドキュメント|フィールド
:----------|:----------|:----
notes      |(uid)      |・content

ログインユーザーのuidとドキュメントのuidとが一致するデータを画面に表示したかったので、Firestoreのセキュリティルールを次のようにしました。

```:firestore.rules
service cloud.firestore {
  match /databases/{database}/documents {
    match /notes/{userId} {
      function isOwner() {   
        return request.auth.uid == userId;
      }
      
      allow update, delete: if isOwner();
      allow create: if request.auth.uid != null;
      allow read: if isOwner();
    }
  }
}
```

Webページを開いてみたら取得結果が0件になっていました。ログインユーザーが登録したデータも表示されません。

# セキュリティルールはフィルターではない
FirestoreのセキュリティルールをWHEREのように使えると思っていました。
取得結果が0件になったのは、Firestoreの検索結果に **ログインユーザーのuidとドキュメントのuidとが一致しないデータ** が含まれていたからです。

```:修正前のpages/index.vue
  mounted () {
    this.$store.dispatch('setNotesRef', db.collection('notes'));
  },
```

```:修正後のpages/index.vue
  mounted () {
    let userID = this.$store.getters['auth/getUid'];
    this.$store.dispatch('setNotesRef', db.collection('notes').doc(userID));
  },
```

`db.collection('notes').doc(userID)` には **ログインユーザーのuidとドキュメントのuidとが一致しないデータ** は含まれていない、つまりルールに一致するデータのみなので、Firestoreからログインユーザーのデータだけを取り出すことができました。

参考までに~/store下はこんな感じです。

```store/auth.js
import Vue from 'vue';
import { auth } from '~/plugins/firebase';

export const state = () => ({
        user: {},
        status: ""
    });

export const mutations = {
        setUser(state, user) {
            state.status = "loggedIn";
            state.user = user;
        },
        logout(state) {
            state.status = "loggedOut";
            state.user = {};
        }
    };

export const getters = {
        isLoggedIn: (state) => {
          return state.status === "loggedIn";
        },
        getUsername: (state) => state.user.displayName,
        getUid: (state) => state.user.uid
    };

export const actions = {
        gotUser({ commit }, user) {
            commit("setUser", user);
        },
        logout({ commit }) {
            auth.signOut().then(() => {
                commit("logout");
            })
        },
    };
```

```store/index.js
import { vuexfireMutations, firestoreAction } from 'vuexfire';
import createPersistedState from "vuex-persistedstate";

export const state = () => ({
      notes: [],
    });

export const mutations = {
      ...vuexfireMutations
    };

export const getters = {
      getNotes: (state) => {
        return state.notes;
      },
    };

export const actions = {
      nuxtClientInit ({ commit, state, dispatch }, { req }) {
        createPersistedState()(this);
      },
      setNotesRef: firestoreAction(({ bindFirestoreRef }, ref) => {
        bindFirestoreRef('notes', ref);
      }),
    };
```

# まとめ

今回学んだことのまとめです。

- Firestoreのセキュリティルールはフィルターではない
- Firestoreのセキュリティルール ＋ 検索条件のコーディングをする
TeXにソースコードを等幅フォントで"ちゃんと"載せる

# はじめに

以下のクイックソートの疑似コードを**アラインメント込みで**TeXにちゃんと載せたい。

```tex
\begin{lstlisting}
quicksort(data) {
  if (data.length <= 1) {
    return data;
  } else {
    p         = select_pivot(data);
    {lo, hi}  = partition(p, data);
    lo_sorted = quicksort(lo);
    hi_sorted = quicksort(hi);
    return (lo_sorted ++ p ++ hi_sorted);
  }
}
\end{lstlisting}
```

"ちゃんと"やれば以下のような出力が得られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215516/3df5384e-c38e-267a-312c-ddec7db7845b.png)

巷に溢れかえっているlistingの設定ではこうはならない。
アラインメントが崩れたソースコードが表示されがちである。

## 結論から...

よくあるlistingの設定の

```tex
\lstset{
  ...
  columns=[l]{fullflexible},
}
```
を

```tex
\lstset{
  ...
  columns=fixed,
  basewidth=0.5em,
}
```
に書き換えよう、ということになる。

これは

```tex
\lstset{
  ...
  basicstyle=\ttfamily,
}
```
などとして等幅フォントをlisting内で使用している場合に限る。
そもそも等幅フォントを使うならばfullflexibleにする必要がなく、fixedにしておいた方がアラインメントが崩れない。

# 上手くいかない例

## `columns=[l]{fullflexible}`

まずはよくある設定。

```tex
\lstset{
  ...
  columns=[l]{fullflexible},
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215516/4a2a4e06-b763-1a92-0650-13d73a49ed1c.png)

スペースがガン無視されてアラインメントが消失する。

## `columns=fixed`

```tex
\lstset{
  ...
  columns=fixed,
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215516/dbaa63ce-9f4d-efff-d1b9-127fb453f4bb.png)

文字間の間隔が空いてしまって見た目が良くない。
おそらくこれがfullflexibleの設定が浸透してしまった原因のような気がする。

# 上手くいく例

```tex
\lstset{
  ...
  columns=fixed,
  basewidth=0.5em,
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215516/3df5384e-c38e-267a-312c-ddec7db7845b.png)

basewidthのデフォルトは0.6emだが、これを0.5emに縮めてやるといい感じの見た目になる。

# おわりに

これらは
[vimのカラースキームでLaTeXのコードを彩る、carbonpaper.vim](https://qiita.com/s417-lama/items/7d74d1593a9344d880b3)
このプラグインを作る際に調べたものでした。こちらもよろしくお願いします。

以下、PDF生成に使用した全ソース。

```tex
\documentclass[uplatex]{jsarticle}
\usepackage{xcolor}
\usepackage{listings}
\usepackage{inconsolata}

% Color
\definecolor{Green}{HTML}{009e73}

% Listings
\lstset{
  language=C++,
  basicstyle=\ttfamily\Large,
  keywordstyle=\bfseries\color{Green},
  showstringspaces=false,
  frame={tb},
  numbers=left,
  xrightmargin=0zw,
  xleftmargin=2zw,
  % columns=[l]{fullflexible},
  columns=fixed,
  basewidth=0.5em,
}

\begin{document}

\begin{lstlisting}
quicksort(data) {
  if (data.length <= 1) {
    return data;
  } else {
    p         = select_pivot(data);
    {lo, hi}  = partition(p, data);
    lo_sorted = quicksort(lo);
    hi_sorted = quicksort(hi);
    return (lo_sorted ++ p ++ hi_sorted);
  }
}
\end{lstlisting}

\end{document}
```
seleniumからfortigate(6.0)管理画面にログイン〜ログアウトしてみる

# やりたいこと
・webdriverで、ネットワーク機器の管理画面を操作してみたい。
・fortigateはRESTFULなインタフェースを持っているが、今回は考えない。

# 何が嬉しいの？
・fortigate管理画面にログインできなくなるような特異故障を監視できるかも。

# 用意するもの
・Forigate（今回はFortigate60D 6.0.x)
・ubuntu 20.04
・selenium＋firefoxが動く環境（https://qiita.com/gaichi/items/1ece50111b50f8de6453）

# 下調べ（elementの調査方法）
・Firefoxにselenium IDE pluginを導入し、recordで記録した結果を見る。
・HTMLのソースから探し出す。
recordの記録ですが、操作をうまく拾えず、同じ操作でも異なる結果が出ることがあります。HTMLはなんとなく理解していますが、cssは全然理解していないので結構適当に探しました。

#ソース

```
#!/bin/python3

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
import time

USERNAME='admin'
PASSWORD='password'
LOGINURL='https://192.168.1.99/login'

# ブラウザ起動
options = Options()
options.binary_location = '/usr/bin/firefox'
#options.add_argument('-headless')
driver = webdriver.Firefox(options=options)

# Fortigateログイン画面の取得
driver.get(LOGINURL)

# ID,Passwordの入力
time.sleep(1)
driver.find_element_by_id('username').send_keys(USERNAME)
time.sleep(1)

driver.find_element_by_id('secretkey').send_keys(PASSWORD)
time.sleep(1)

driver.find_element_by_name('login_button').click()
time.sleep(5)
# ↑管理画面の表示は時間がかかるので、長めに待つ。

# Adminメニューをクリック
driver.find_element_by_class_name('admin-avatar').click();
time.sleep(2)

# ログアウトをクリック
driver.find_element_by_class_name('fa-sign-out').click();
time.sleep(10)

# ブラウザーを終了
driver.quit()
```