OmniAICreator/Qiita-1.07M huggingface dataset:
Cloud Text-to-Speech APIをNode.jsで試した時の備忘録

Googleの音声認識ライブラリ**Cloud Text-to-Speech API**を試した時のメモ。

## プロジェクトの登録
[Google Cloud Platform](https://console.cloud.google.com/)にアクセスして、プロジェクトを作成する。

## APIの有効化
ホームのメニューにある**APIとサービス**から**ライブラリ**を選択し、以下のAPIを検索して有効化しておく

* Cloud Text-to-Speech API
* Cloud Speech API

Cloud Text-to-Speech APIは課金制なので、クレジットカードの登録が必要。12 か月間トライアル無料‎を使って登録する。ここでクレジットカードを登録して無料枠分を超えてしまうときでも、**黙って請求されることはない**そうなので安心して使えます。Googleからメールにて通知されるそうです。

#### 料金
音声認識のCloud Text-to-Speechは毎月60分（リクエスト）まで無料で使えます。それ以降は$0.006 米ドル/15 秒で課金される。
> 各リクエストは 15 秒単位で切り上げられます。たとえば、それぞれに 7 秒の音声が含まれる 3 つのリクエストは、45 秒（3 × 15 秒）の音声として $0.018 が請求されます。また、15 秒単位での切り上げは、小数点以下の秒数も対象になります。つまり、15.14 秒は 30 秒として請求されます

## install sox 
node.jsで音声を扱うために[**`sox`**](http://macappstore.org/sox/)というライブラリを使う。

```rb
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null
```

```
brew install sox
```

## node.js用のプロジェクトフォルダを用意
適当なフォルダを作成して、index.jsファイルを作成する。
ソースコードの中身はgoogleの[サンプルコード](https://cloud.google.com/video-intelligence/docs/common/auth?hl=ja)をダウンロードしてきて、以下の箇所をコメントアウトして修正する。

```js:uncommentする
const encoding = 'LINEAR16';
const sampleRateHertz = 16000;
const languageCode = 'ja-JP';
```

#### Support Language
* https://cloud.google.com/speech-to-text/docs/languages?hl=ja

## サービスアカウントを作成する
GCP Console で [API Manager] → [認証情報] の順に移動し、[認証情報を作成] → [サービス アカウント キー] の順に選択します([参考](https://cloud.google.com/video-intelligence/docs/common/auth?hl=en))。
作成されたjsonファイルをディレクトリに入れる。

## 環境変数を登録
GOOGLE_APPLICATION_CREDENTIALSにパスを通す。

```bash:先ほどのjsonファイルのパス
export GOOGLE_APPLICATION_CREDENTIALS=<path_to_service_account_file>
```

## 実行
```
node index.js
```

そのまま実行したら反応しなくてあれ？となったが、数秒後に音声認識された文字列がコンソールに表示された。ただ、リアルタイムで変換されていないので、どこかに設定があるのだろうと探していたらありました。

```js:リアルタイムの設定
interimResults: true
```

この`interimResults`を`true`に設定すると、途中経過まで表示されます。

* [テスト音源](https://so-zou.jp/web-app/news/nettv-news/)
 - 斬新さで人気！！　剣道×フィットネス 配信:2019年2月5日(火)11時 [49分前]
![画面収録 2019-02-05 11.55.28.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/117549/c2658328-2db5-fc8c-29aa-513176b4642b.gif)



## 備考
このCloud Text-to-Speech APIは[こちら](https://cloud.google.com/speech-to-text/?hl=en)でデモができます。mobile safariからアクセスして試してみましたが、あまり遅延なく動作しました。無料で使える`Web Speech API` の `SpeechRecognition`はmobile safariはまだサポートされていないようなので、音声認識でmobile safariにも対応する場合は、この`Cloud Text-to-Speech API`を使う必要があるようです。
よく使う Homebrew のコマンド

# 概要
  
Homebrew 2.0 がリリースされました。Linux や Windows Subsystem for Linux でも使えるようになったということなので、ユーザーはもっと増えていくんじゃないでしょうか。  
  
また、後述しますが、brew cleanup についても変更点があったようですね。  
  
それはさておき、Homebrew にはよくお世話になっているにも関わらず、コマンドをすぐに忘れてしまいます。備忘録として、よく使うコマンドを記しておきます。

# ホスト

## Mac

* [MacBook Pro ( 13-inch, Early 2011 )](https://support.apple.com/kb/SP619?locale=ja_JP&viewlocale=ja_JP) 魔改造済み


* メモリ: 16 GB

* ストレージ: SSD 512 GB

* OS: macOS Sierra 10.12.6
  
# brew -v
  
まずは、バージョンを確認するコマンド。  
  
```
% brew -v
```
  
以下のように Homebrew と Cask のバージョンが表示されます。  
  
```
Homebrew 2.0.0
Homebrew/homebrew-core (git revision 385c9; last commit 2019-02-04)
Homebrew/homebrew-cask (git revision 8ab02; last commit 2019-02-03)
```

# brew outdated
  
更新のある formula を見る、つまり、ご自分のマシンに Homebrew でインストールされていて、最新ではないパッケージを一覧表示するコマンドです。  
  
```
% brew outdated
```
  
実行結果の例です。以下のような感じで表示されます。左側が、マシンにインストールされているバージョン、右側が最新版です。  
  
```
cmake (3.13.3) < 3.13.4
digdag (0.9.27) < 0.9.32
embulk (0.9.7) < 0.9.14
go (1.11.4) < 1.11.5
mas (1.4.1) < 1.6.2
maven (3.5.4) < 3.6.0
node (11.7.0) < 11.9.0
pipenv (2018.11.26) < 2018.11.26_1
```
  
# brew cask outdated
  
brew outdated の Cask 版です。  
  
```
% brew cask outdated
```
  
brew outdated の実行結果と同様に、左側が、マシンにインストールされているバージョン、右側が最新版です。  
  
```
airdisplay (3.0.3) != 3.2
kindle (50131) != 52065
libreoffice (6.1.0) != 6.1.4
mi (3.0.0) != 3.0.1
vagrant (2.1.2) != 2.2.3
virtualbox (5.2.18,124319) != 6.0.4,128413
```
  
# brew update と brew upgrade
   
update と upgrade は紛らわしくて、どう違うのか調べても、よくわからなかったのですが、以下のサイトを見て納得しました。  
  

https://codenote.net/mac/homebrew/972.html
  
上記サイトから、以下を引用させていただきます ｍ（＿ ＿）ｍ
  
```
“アップグレードとアップデートの違いは、
アップデートが『ソフトの小規模な更新を指し、不具合の修正・わずかな機能向上などが提供される』のに対して、
アップグレードは『ソフトに大幅な改良がされ、新バージョンとして公開されること』。” 
らしいです。
```
  
私は、Homebrew 自体や、Homebrew でインストールしているパッケージを新しくしたいときは、brew update と brew upgrade のどちらも使って、一気にやってしまいます。  
  
```
% brew update
% brew upgrade
```

# brew cleanup
  
update と upgrade が終わったら、古いファイルを削除するために、これまでは brew cleanup を使っていましたが、これからは無理にコマンドを打ち込まなくてもよさそうです。  
  
[Homebrew 2.0 リリースのアナウンスメント](https://brew.sh/2019/02/02/homebrew-2.0.0/)によれば、Homebrew 2.0 からは、30日ごとに自動で brew cleanup が実行される、また、install コマンドなどを実行することによっても、brew cleanup が実行されるようです。

```
brew cleanup is run periodically (every 30 days) 
and triggers for individual formula cleanup on reinstall, install or upgrade.
```
  
# brew doctor
  
何か不具合がないか、定期的に brew doctor を実行しておきましょう  
  
以上です。
libfreenectを使ったKinect v1の開発①

ようやくUbuntuでKinect v1の深度画像を表示することができたのでメモ.
とりあえず動いたことが確認できたので, 特別な処理を施したりはしていない.

# 使ったもの
 
[libfreenect](https://github.com/OpenKinect/libfreenect)
OpenCV-3.4.4

#libfreenectについて
Kinectの開発というと, OpenNIが主流な気がするが. こちらはOpenNIに比べてシンプルで値の取得が速いらしい. ただし, カラー画像, 深度画像, チルトモーターなどのセンサーデータをそのまま使うことしかできない.
深度画像, カラー画像など生のデータだけほしいのであればこれで十分.

# ソースコード
[これ](https://gist.github.com/jayrambhia/5677608)を参考にして, コードを書いた.
はじめは簡単. 初期化するだけ.

```cpp:
	freenect_context *ctx;
	freenect_device *dev;
	
	//コンテキストの情報を初期化. 成功すると0を返す.
	if (freenect_init(&ctx, NULL) < 0)
	{
        	std::cout << "初期化に失敗しました." << std::endl; 
        	return 1;
	}
 
	//デバイスに接続. 成功すると0を返す.
	if (freenect_open_device(ctx, &dev, 0) < 0)
	{
	        std::cout << "Kinectに接続できません." << std::endl;
	        return 1;
	}
```

次に, コールバック関数を呼び出す.

```cpp:
	//depth_cb内の処理は自分で書く
	freenect_set_depth_callback(dev, depth_cb);
```

今回, depth_cbはこのようにした.

```cpp:
void depth_cb(freenect_device *dev, void *depth, uint32_t timestamp) 
{
	cv::Mat d8;
	//深度画像データを入れる
	cv::Mat temp = cv::Mat(480, 640, CV_16UC1, depth);

	//8bitグレースケール画像に変換, 4000は測定可能な最大距離
    	temp.convertTo(d8, CV_8UC1, -255.0f/4000, 255.0f);
	//データをコピー
    	memcpy(img.data, d8.data, 640*480);
}
```

はじめはvoid型のdepthへのポインタがなんだかわからなかったので, 標準出力してみた.
するとメモリアドレスが表示された. depthへのポインタは深度画像データが入ったメモリのアドレスを指しているのだろう. OpenCV以外のライブラリを使いたい場合はこのdepthをうまく使えばいい.
depth_cbでは, まずtempに深度画像データを入れる. 次に, temp画像を8bitグレースケール画像に変換, それをd8に入れる. 最後に, d8に入ったデータをimgのデータにコピーする.

次に,　depthデータをKinectから受け取る.

```cpp:
	//データを流す
	freenect_start_depth(dev);
```

これで, Mat型の変数にdepthデータが入る. これを表示や加工すればOK.


コード全体

```cpp:
#include<iostream>
#include<libfreenect.h>
#include<opencv2/opencv.hpp>

cv::Mat img;

void depth_cb(freenect_device *dev, void *depth, uint32_t timestamp) 
{
	cv::Mat d8;
	//深度画像データを入れる
	cv::Mat temp = cv::Mat(480, 640, CV_16UC1, depth);

	//8bitグレースケール画像に変換, 4000は測定可能な最大距離
    	temp.convertTo(d8, CV_8UC1, -255.0f/4000, 255.0f);
	//データをコピー
    	memcpy(img.data, d8.data, 640*480);
}

int main()
{
	img = cv::Mat(480, 640, CV_8UC1);
	freenect_context *ctx;
	freenect_device *dev;
	
	//コンテキストの情報を初期化. 成功すると0を返す.
	if (freenect_init(&ctx, NULL) < 0)
	{
        	std::cout << "初期化に失敗しました." << std::endl; 
        	return 1;
	}
 
	//デバイスに接続. 成功すると0を返す.
	if (freenect_open_device(ctx, &dev, 0) < 0)
	{
	        std::cout << "Kinectに接続できません." << std::endl;
	        return 1;
	}
 	
	//depth_cb内の処理は自分で書く
	freenect_set_depth_callback(dev, depth_cb);
 
	//データを流す
	freenect_start_depth(dev);
	while(freenect_process_events(ctx) >= 0 ){
		cv::imshow("Depth", img);
		if(cv::waitKey(1) == 'q'){
			break;	
		}
	}
}
```

#実行結果
![depth.png](https://qiita-image-store.s3.amazonaws.com/0/316006/1c429805-2e81-2a9d-dcc1-c8ab86a2a14d.png)

実行結果を見ると, 奥行きが少しわかりにくいので加工処理をもう少し改善できないかこれから検討する.
Amazon Product Advertising APIの始め方^H^H^H始められなかった

Amazon Product Advertising APIの始め方です。

1. Amazonアソシエイトにサインアップする
2. Product Advertising APIにサインアップする
3. 規約を読む
4. [オプション] お試しする

# Amazonアソシエイトにサインアップする

使いたい地域（日本、US、イタリア等）によりサインアップ先が異なります。
[Sign up as an Amazon Associate](https://docs.aws.amazon.com/AWSECommerceService/latest/DG/becomingAssociate.html)から、使いたい地域を選んでください。

日本の場合は https://affiliate.amazon.co.jp/ です。

# Product Advertising APIにサインアップする

サインインしたら、上部メニューからProduct Advertising APIを選びます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/59475/8d20e0f8-a1b9-0ab3-390f-d780b7cfca7a.png)

利用を始めるをクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/59475/1908ee0a-4cc0-243f-f04f-90739046dd47.png)

アクセスキーとシークレットキーが表示されますので、コピーして保存しておきます。
あるいは認証情報をダウンローをクリックして、ファイルを保存しておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/59475/e32854d2-4183-451d-88c0-f1d5308632d1.png)


# 規約を読む

[Amazonアソシエイト・プログラム運営規約](https://affiliate.amazon.co.jp/help/operating/agreement)を読みます。

禁則事項がたくさんあるので気をつけないと。。。

# [オプション] お試しする

[ScratchPad](https://webservices.amazon.co.jp/scratchpad/index.html)にアクセスします。

サイドバーから例えばItemSearchを選びます。

Marketplaceを選びます。
Access Key IDとSecret Access Keyを入力します。
Run Requestをクリックします。

結果が表示されるはずが、HTTP 503 You are submitting requsts too quickly. Please retry your requests at a slower rate. となりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/59475/f474ef6c-99c6-719f-d7ae-c3ac831c3d70.png)

## 一晩待ってみる

ダメ :cry: 

## 二晩待っても

ダメ :sob:

何を間違えたのだろう。。。
Qiita 記事でリンクを作るときの遷移の仕方をテストしてみる

マークダウンにはリンクを生成する記法が用意されてると思うんですが、別タブで開くのかページ遷移で開くのか興味を持ちました。

[これは Qiita の記事です。フルパスです。](https://qiita.com/FumiyaShibusawa/items/c7a3ff4d0793ca2d281f) → これはページ内遷移で開きました。
[これは Qiita の記事です。フルパスです。でも http です。](http://qiita.com/FumiyaShibusawa/items/c7a3ff4d0793ca2d281f) → これは https にページ内遷移でリダイレクトして開きました。
[これは Qiita の記事です。試しに相対パスで書いてみます。](/FumiyaShibusawa/items/c7a3ff4d0793ca2d281f) → どうやら Qiita 記事なら相対パスで書いても大丈夫なようです。
[これは外部リンクです。](https://google.com) →　ドメインが qiita.com でない場合、デフォルトで別タブで開くようになっているようです。

## Qiita のエンジニアさん賢い。
たしか、このあたりの面倒はマークダウンの仕様ではカバーしていないので、パースするときに独自で書き換えないと行けなかったりするはず。なので、 Qiita の中にいるエンジニアさんがいろいろとカスタマイズされているのかなと思ったり思わなかったり。

```
**ほげ**
*ふが*
```
Automator 複数ページ起動&自動ログイン

# 作成の背景
以前作ったLPWAのデモ機は[The Things Network](https://www.thethingsnetwork.org/)と[my Devices](https://mydevices.com/)のCayenneというWebサイトでステータスの表示、確認を行っていましたが、毎回デモをするたびに各サイトへのログインが手間だったので、動作簡略化の一環で作成しました。
なおステータス表示用端末がMacだったためAutomatorで実装しました。

*なお現状はID,Passを平文で保存することになるため自己責任でお願いします。

# やった事
 1. Automatorでのワークフロー作成
 2. ログイン用Apple script記述
 3. 動作検証

実際のやり方、検証結果は
[Automator 複数ページ起動&自動ログイン：詳細版](https://instanttry.com/2019/05/17/post-327/)で紹介しています。
# 概要編
##  1. Automatorでのワークフロー作成
<img width="997" alt="スクリーンショット 2019-02-05 9.57.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/354941/25bfaeeb-0930-ff4a-07a3-85d9691efa11.png">


<img width="999" alt="スクリーンショット 2019-02-05 9.59.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/354941/4c660edd-a517-2058-2248-9e537589e99a.png">

<img width="1458" alt="スクリーンショット 2019-02-05 10.04.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/354941/4e1ab988-0b51-cffc-ed99-b52956f71262.png">
タブでTTNとmyDevice Cayenneのログインページが表示されたら成功です。

##  2. ログイン用Apple script記述
<img width="995" alt="スクリーンショット 2019-02-05 10.16.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/354941/b8557063-b586-6440-c72e-daf78cdb7ff2.png">

```applescript:TTNCayenelogin.app
tell application "Safari"
	activate
	tell application "System Events"
		delay 7 --7s delay
		key code 102 --英数キー
		keystroke "email@address" --ログインID
		keystroke tab --タブキー
		keystroke "password" --パスワード
		key code 76 --エンターキー
		delay 3 --3s delay
		keystroke tab using {control down, shift down} --Safari内タブ遷移
		delay 1 --1s delay
		keystroke "email@address" --ログインID
		keystroke tab --タブキー
		keystroke "password" --パスワード
		key code 76 --エンターキー
	end tell
end tell
```
##  3. 動作検証
Automator右上から実行し、両サイトへのログインが成功すれば完了です。
TWA試してみた

先日GooglePlayでPWAを配信できるようになったという記事を見て、試してみた記事になります。
詳細は[元の記事](https://medium.com/@firt/google-play-store-now-open-for-progressive-web-apps-ec6f3c6ff3cc)を読むといいと思います。


# ざっくり要約
仕組みとしてはTrusted Web Activity(TWA)というものを使ってネイティブアプリ内でWebコンテンツを起動するようです。
メリットとしてはアプリとPWAでキャッシュを共有できたり、ネイティブAPIの一部（今はプッシュ通知くらい？）が使えるっぽいです。

# サンプルを試す
まずは公開されている[サンプル](https://github.com/GoogleChromeLabs/svgomg-twa/)をそのまま試す手順です。
とは言えリンク先GitHubのREADMEに手順が書いてあるのでほぼそれをやるだけです。
この確認はエミュレータで行いました。

1. 上記ページからcloneしてくる。
2. chromeアプリを起動して`chrome://flags`を開き、`Enable commmand line on non-rooted devices`を有効にする。
3. エミュレータを起動した状態でcloneしたプロジェクト内のenable-debug.shを実行する。その際、引数に `https://svgomg.firebaseapp.com`を指定する。
4. cloneしたプロジェクトを実行する。

注意点としてはエミュレータでchromeを使うためには最新のNexus5Xを使う必要があったくらいです。
当初、古いバージョンを使っていて`Enable commmand line on non-rooted devices`の設定がありませんでした…

# 自分で用意したPWAに繋ぎ変えてみる
上記が動いたので今度は自分で用意したPWAを表示してみます。

1.build.gradle(Module:app)を開き、manifestPlaceholdersを修正する。例として`https://hogehoge.com`を表示するものとします。

```build.gradle
manifestPlaceholders = [
    // The hostname is used when building the intent-filter, so the TWA is able to
    // handle Intents to open https://svgomg.firebaseapp.com.
    hostName: "hogehoge.com",
    defaultUrl: "https://hogehoge.com",
    launcherName: "SVGOMG TWA",
    // This variable below expresses the relationship between the app and the site,
    // as documented in the TWA documentation at
    // https://developers.google.com/web/updates/2017/10/using-twa#set_up_digital_asset_links_in_an_android_app
    // and is injected into the AndroidManifest.xml
    assetStatements: '[{ "relation": ["delegate_permission/common.handle_all_urls"], ' +
        '"target": {"namespace": "web", "site": "https://hogehoge.com"}}]'
]
```

2.enable-debug.shを`https://hogehoge.com`を引数にして実行する。
3.ビルドして実行する。

と、やればできると思ったんですが、私の環境だとエミュレータでは動きませんでした。
Chromeを入れろ的なToastが出て、ページが開きませんでした。もちろん先のサンプルが動いたものなのでchromeのバージョンなどには問題ないはず。
そこで試しに実機をつないでやってみましたらさらっと動きました…なぜだ…

# まとめ
本来は[Digital Asset Links](https://developers.google.com/digital-asset-links/)というのを使ってPWAのサイト側で認証させる必要があるらしいのですが、今回はそれをシェルで行っている処理ですっ飛ばすようにしてるし本当にお試しというレベルです。
まだまだほとんど情報がなかったので参考になれば幸いです。
jsで数値にカンマをつける

## 正規表現を使う

```js
const NumberWithDelimiter = (number) => {
  return String(number).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
}
```

## number.toLocaleString()を使う

```js

var num = 100000;
num.toLocaleString();
// -> "100,000"
var num = "100000";
num.toLocaleString();
// -> "100000"
var num = Number("100000")
num.toLocaleString();
// -> "100,000"
```

ブラウザ実装状況
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString#Browser_compatibility

そこそこ実装されているので
number.toLocaleStringで問題なさそう
AWS APIの1つの値しか許可されない配列

# はじめに
CloudFormationでALBを作成していたら、テンプレートの構文で気になるところがあった。

# ListenerRuleのConditonsのValues

AWS::ElasticLoadBalancingV2::ListenerRuleのPropertyのConditionsのValuesが、配列になってるんですよね。
[公式ドキュメント](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticloadbalancingv2-listenerrule-conditions.html)を見ても、Valuesはしっかり`Type: List of String values`って書いてます。

```yaml
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
  Actions:
    - Actions
  Conditions:
    - Field: String
      Values:
        - String # 配列になっている
  ListenerArn: String
  Priority: Integer
```

通常は下記のように1つの値を入れるのだけど(実際いままではそうやってしか使っていなかった)、
配列になってるから2つ以上の値もいけるのか？と思って試してみた。

```yaml
listenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn:
            Ref: targetGroup
          Type: forward
      Conditions:
        - Field: path-pattern
          Values:
            - hogehuga # パスパターンを記述
      ListenerArn:
        Ref: listener
      Priority: 1
```


パスパターンを2つ記述したテンプレート

```yaml
listenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn:
            Ref: targetGroup
          Type: forward
      Conditions:
        - Field: path-pattern
          Values:
            - hogehuga
            - foobaa # 配列なのでパスパターンを追加してみる
      ListenerArn:
        Ref: listener
      Priority: 1
```

が、ダメ・・・！

`A condition can only have '1' values (Service: AmazonElasticLoadBalancingV2; Status Code: 400; Error Code: ValidationError; Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)`

Fieldがホストヘッダの場合でもやってみたが、結果は同じ。

```
listenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn:
            Ref: targetGroup
          Type: forward
      Conditions:
        - Field: host-header
          Values:
            - hoge.example.com # ホストヘッダの場合でもやってみた
            - huga.example.com
      ListenerArn:
        Ref: listener
      Priority: 1
```

公式ドキュメントに"you can specify a single host name", "you can specify a single path pattern"と書いてあるのでダメなんだろうなとは思ってた。

[APIのドキュメントのほう](https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_RuleCondition.html)も、文字列の配列になっている。

```
Values.member.N
The condition value.

~略~

Type: Array of strings

Required: No
```

# AWSサポートに問い合わせてみた

なんで配列なのかなと思って、AWSサポートに問い合わせてみた。

以下回答の抜粋

```
> 私が理解できていないだけで、2つ以上の値を設定する場面があったり、その方法があったりするのでしょうか？

現時点では 2 つ以上の値を設定する場面はございません。

配列となっている理由といたしましては、将来的に API の拡張が行われた際に、2 つ以上の値を指定できるように変更される可能性などが考えられます。
```

なるほどなぁと思った(こなみ)
nitrogenでデュアルディスプレイの壁紙をぶち抜きでランダム更新

私の場合，壁紙ディレクトリの下にサブディレクトリを掘ってジャンル毎に壁紙を入れているため，`ls`コマンドではうまくファイルパスを抜けない．
しかしそこは，`find`をうまく使えば絶対パスで抜ける．

```sh:set-background.sh
#!/bin/sh

PICDIR=~/Pictures/wallpapers
TARGETFILE=$HOME/.config/nitrogen/bg.jpg

interval=900
while true
do
    if [ ! -e ~/.config/nitrogen/bg-saved.cfg ]; then
        echo First of all you have to setup ~/.config/nitrogen/bg-saved.cfg
        echo Next, change 'file' value into \$TARGETFILE.
    else
        JPGLIST=$(find ${PICDIR} -type f)
        NUM_JPG=$(echo "$JPGLIST" | wc -l)
        RAND=$(expr $(date +%s) % ${NUM_JPG} + 1)
        SRC=$(echo "$JPGLIST" | head -${RAND} | tail -1)

        cp -f ${SRC} ${TARGETFILE}
        nitrogen --restore

        sleep $interval
    fi
done
```

私の環境では左側ディスプレイが1，右側ディスプレイが0なので，xin_-1に設定する．xin_-0だと画像が右・左にぶった切れてしまう．

```config:.config/nitrogen/bg-saved.cfg
[xin_-1]
file=/home/username/.config/nitrogen/bg.jpg
mode=0
bgcolor=#000000
```

これは普通．以前はfehを使っていたが，4Kディスプレイを2分割して縦長に使うようになったので壁紙はぶちぬきにしたくなったのであった．

```haskell:.xmonad/xmonad.hs
myStartupHook = do
    --spawn "feh --bg-fill -z ~/Pictures/wallpapers/*"
    spawn "/home/username/bin/set-background.sh"
```


----

追記

参考文献を書き忘れてた．
基本はそのまんま~~パク~~もとい参考にさせていただいたが，サブディレクトリ対応をしたのと，変数`RAND`の設定時に+1をしないと境界条件でエラーを吐いたのが，この記事のnewなところ．

[Xmonad \+ nitrogenで壁紙を設定する \- tototoshi の日記](http://tototoshi.hatenablog.com/entry/20101229/1293591819)
PopupWindow $BadTokenException: Unable to add window — token null is not valid について

PopUpWindowはちょっとのダイアログや吹き出しなどを実装したいときに作りやすい。

KotlinでPopUpWindow書いている記事があまりないなと思い、勉強も兼ねて実装していたのだが、
ある画面が出て条件を満たす場合に出したい場合、そのままViewの上に描画しようとするとタイトル通りのエラー

原因としてはポップアップさせるタイミングが早すぎるので少しずらしてあげないといけない
そのため、
[1] ストーリーは違うが、ボタンが押された後にPopUpするとか、
[2] RxやAsync, Handler等で非同期処理
する必要がある

[1] については単純にButtonが押された場合にPopUpWindowを呼び出してあげればいい
[2] についてはこのように時間をずらして表示

```
private fun showPopUpUsingRx(popUp: PopUp) {
        Completable.complete()
                .delay(5, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnComplete { popUp.show(contact_button) }
                .subscribe()
    }
``` 

参考コードはこのような感じ
 
```MainActivity.kt
class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        showPopUpUsingRx(PopUp(this))

        popup_container.setOnClickListener {
            showPopUpUsingButton(PopUp(this))
        }
    }

    private fun showPopUpUsingButton(popUp: PopUp) {
        if (popUp.isShowing) {
            popUp.dismiss()
            popUp.show(contact_button)
        } else {
            popUp.show(contact_button)
        }
    }

    private fun showPopUpUsingRx(popUp: PopUp) {
        Completable.complete()
                .delay(5, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnComplete { popUp.show(contact_button) }
                .subscribe()
    }
}
```

```PopUp.kt
@SuppressLint("InflateParams")
class PopUp(private val context: Context) : PopupWindow() {

    private val layoutInflater = LayoutInflater.from(context)

    init {
        contentView = layoutInflater.inflate(R.layout.popup_layout, null)
        contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
        width = WindowManager.LayoutParams.WRAP_CONTENT
        height = WindowManager.LayoutParams.WRAP_CONTENT
        isOutsideTouchable = true
        isFocusable = true

        contentView.popup.setOnClickListener {
            dismiss()
        }

        setOnDismissListener {
            Toast.makeText(context, "Popup closed", Toast.LENGTH_SHORT).show()
        }
    }

    fun show(anchorView: View) {
        showAsDropDown(anchorView, anchorView.measuredWidth / 4,
                -anchorView.measuredHeight - calcNavHeight(), Gravity.NO_GRAVITY)
    }

    private fun calcNavHeight(): Int {
        val resource = context.resources
        val resourceId = resource.getIdentifier("navigation_bar_height", "dimen", "android")
        return if (resourceId > 0) {
            resource.getDimensionPixelOffset(resourceId)
        } else {
            0
        }
    }
}
```

結果はこんな感じ
<img src="https://qiita-image-store.s3.amazonaws.com/0/260353/655184a0-8736-3674-3282-3657c158a3a4.png" width="250px">

[Repository is here](https://github.com/sudo5in5k/popUpWindow)
【SpringBoot】アップロードするMultipartFileの最大サイズを変更する

# 問題
2MB程度のファイルをアップロードしようとしたところ、`org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field uploadFile exceeds its maximum permitted size of 1048576 bytes.`というエラーが出ました。

# 解決方法
`application.properties`を設定する方法と、`MultipartConfig`を`Java`から設定する方法の2つを試しました。
`@MultipartConfig`を用いる方法は上手く出来なかったのでここでは扱いません。
調査はSpringBoot2.0.5で行いました。

## application.propertiesを設定する
[ドキュメント](https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/html/common-application-properties.html)より、以下を設定すればできます。

```properties
spring.servlet.multipart.max-file-size=1MB # Max file size. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively.
spring.servlet.multipart.max-request-size=10MB # Max request size. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively.
```

### 補足
`multipart`プロパティは、以前は別のプロパティ配下だったようですが、2.0.0から`servlet`配下に移り、[2.1.0でも](https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/html/common-application-properties.html)`servlet`配下にあるようです。

## MultipartConfigをJavaから設定する
[@tera78 様の記事](https://qiita.com/tera78/items/432d365c527342dcf9f4)より、`MultiPartConfigure.java`がそのまま利用できました。

> ```java:MultiPartConfigure.java(引用)
import javax.servlet.MultipartConfigElement;
import org.springframework.boot.context.embedded.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MultiPartConfigure {
    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize("100MB");
        factory.setMaxRequestSize("100MB");
        return factory.createMultipartConfig();
    }
}
> ```

# 効率的な調べ方
紹介したドキュメントのページはバージョンを変えればそのバージョンのドキュメントが見られるので、それを辿ると効率的に調べられるかなと思います。

# 参考にさせていただいた記事
- [Spring Boot で大きいサイズのファイルをアップロードする \- Qiita](https://qiita.com/tera78/items/432d365c527342dcf9f4)
NCL > gsn_add_polymarker()を複数実行した時に一つのマーカーしか追加できない > 対処: 戻り値を配列に代入する

```txt:動作環境
Xeon E5-2620 v4 (8コア) x 2
32GB RAM
GeForce GT 730 1GB GDDR5
CentOS 6.9 (64bit)
NCAR Command Language Version 6.3.0
for WRF3.7.1, WPS3.7.1
  openmpi-1.8.x86_64 とその-devel
  mpich.x86_64 3.1-5.el6とその-devel
  gcc version 4.4.7 (とgfortran)
for WRF3.9, WPS3.9
  Open MPI v2.1.1
  gcc version 4.9.2 (とgfortran; devtoolset-3使用)
　NetCDF v4.4.1.1, NetCDF (Fortran API) v4.4.4
Python 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) 
Python 3.6.0 on virtualenv
GNU bash, version 4.1.2(2)-release (x86_64-redhat-linux-gnu)
date (GNU coreutils) 8.4 
tmux 1.6-3.el6
```

NCL(NCAR Command Language)関連。
WRF(Weather Research and Forecasting Model)関連。


### 参考

地図画像にマーカーを追加する関数。

- https://www.ncl.ucar.edu/Document/Graphics/Interfaces/gsn_add_polymarker.shtml

### はまったこと

```txt:NCL 
         x1 = (/135.0/)
         y1 = (/35.0/)
         plot1 = gsn_add_polymarker(wks,plot,x1,y1,pmres_main)  ; circle
         x2 = (/130.0/)
         y2 = (/35.0/)
         plot1 = gsn_add_polymarker(wks,plot,x1,y1,pmres_sub)  ; star
```

（記載していないが）pmres_mainは白丸、pmres_subは星形、として定義している。

上記の処理の後で描画を行うと、星形しか表示されない。

### 対処

plot1を配列にして、別の要素の配列値に代入する。

```txt:NCL
         plot1 = new(2, graphic)
         x1 = (/135.0/)
         y1 = (/35.0/)
         plot1(0) = gsn_add_polymarker(wks,plot,x1,y1,pmres_main)  ; circle
         x2 = (/130.0/)
         y2 = (/35.0/)
         plot1(1) = gsn_add_polymarker(wks,plot,x1,y1,pmres_sub)  ; star
```

代入方法によって処理が失敗する言語、処理系は今回初めて経験した。
React Nativeは Node.jsで実行されていなかった

React Nativeで本格的に開発して2ヶ月くらい経ちますが今日React NativeがNode.jsの実行環境で動作していないことを知りました。

ことの発端はNode.jsの標準モジュールである`url`を使おうと`import * as url from 'url'`と書いたことです。
するとビルド時に以下のエラーが出力されるようになりました。

```
Error: Unable to resolve module `url` from `/Users/user544/dev/mimizuku_client/react_project/App.tsx`: Module `url` does not exist in the Haste module map
```

でまぁ、React Nativeのbundlerあたりの問題かと思って、よくあるキャッシュ削除の手順とか実行したんですが、一向に解決できないわけです。
いろいろググっていると https://stackoverflow.com/questions/39046429/react-native-unable-to-resolve-module-fs を発見。

同じく標準モジュールのfsを使おうとしてエラーになっているひと。
回答を見ると`React Native アプリはNode.js環境で実行されないよ。コンパイルとかパッケージャーとして使ってるだけ。` とのこと :rolling_eyes: 

```
React Native applications do not run in the Node.js environment (it is only used by the packager to actually serve and compile your application bundle).
```

いやーハマったハマった。
これで心置きなく `npm install url --save` できる。
Vue.jsで外部APIから取得したデータが反映されないときの対処法メモ

# やりたかった処理
現在自分で使う用に簡単な家計簿webアプリのようなものを作っているのですが、その中でフロントエンド（Vue.js）からAWS上のREST APIを叩いて、取得した内容を即座に画面に反映させる処理を作成していました。

以下の図のような処理です。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/283226/9a800d83-a247-bbd9-db1b-05091a4e49da.png)

Vue.jsの親コンポーネントがサーバサイドよりデータを取得し、取得データを子コンポーネントに渡し子コンポーネントがチャートを描画する処理です。

参考までに、こんな感じのチャートです（支出の種別のランキングを表すドーナツチャートです）。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/283226/9cda8569-f6f7-a202-9f15-c3cdd9683223.png)


ところが、ログを見るとAPIからのデータ取得は成功しているにもかかわらず、画面にはデータが反映されない現象が起こりました。

この問題を解決するためインターネットでサーチをするも、あまり参考になる記事が少なかったため、ここに解決方法を記しておきます。

# うまくいかなかったコード
うまくいかなかった処理は以下のようになっています。

まず、親コンポーネントで以下のようにAPIサーバからデータを取得し、`dataset`という変数に取得結果を格納します。

家計簿アプリなので、取得するデータは特定の期間中の支出及び収入の一覧となっています。

```javascript:親コンポーネント
axios.get(getUrl, config).then((response) => {
    this.dataset = response.data.body;
})
```

そして、`dataset`を`chart-component`という子コンポーネントに引き渡します。

```html:親コンポーネント
<chart-component :dataset="dataset"></detail-component>
```

子コンポーネントでは、引き受けた値をドーナツチャートにして表示します

```javascript:子コンポーネント
Vue.component('chart-component', {
    template: `
    <div class="summary-content">
        <canvas id="pieChart"></canvas>
    </div>
    `,
    data: function () {
        return {
            //チャートの描画するデータを保持
            "dataList": [],
            //チャートの描画するラベルを保持
            "labelList": [],
            //チャートの描画色を保持
            "colorList": []
        }
    },
    props: [
        "dataset"
    ],
    methods: {
        /*
        * 変数の初期化
        */
        init() {
            this.dataList = [];
            this.labelList = [];
            this.colorList = [];
        },

        /*
        * ドーナツチャート表示用のデータを作成
        */
        editPieChartData() {
            //チャート用のデータを整える処理ですが、詳細は記事と関係ないので省略
        },

        /*
        * ドーナツチャートの描画
        */
        createPieChart() {
            //チャートを描画する処理ですが、詳細は記事と関係ないので省略
        }
    },
    created() {
        console.log(this.dataset) // <= ここでログ出力
        this.init();
        this.editPieChartData();
        this.createPieChart();
    },
})

```
`props`でAPIより取得した収入支出データを受け取ったら、`created`でいくつかの関数を呼び出してチャートを描画しようとしています。

ところが、チャートは描画されないにも関わらず、引き受けた`dataset`の値を`created()`直後にログに出してみてみると(ソースコード内のコメント参照)、きちんと値が入っていました。
# 解決方法
悩んだ末、`watch`を使うと解決することが分かりました。

`props`で受け取った値は`created`の時点では空であることがあるため、中身が空でなくなった時点で処理をするように変更します。

以下のように、子コンポーネント内で親から渡される`dataset`の値をwatchして変更時にチャート作成関数を呼び出すようにすることで、きちんとデータが画面表示に反映されるようになりました。

```javascript:子コンポーネント
watch: {
    dataset: function () {
        // チャート作成関数を呼び出し
        this.init();
        this.editPieChartData();
        this.createPieChart();
    },
},
```

# インターネットでサーチしてみると...

Vue.jsではデータの変更に合わせて画面が切り替わらない現象がよくおこるらしく、その解決方法として、`$forceUpdate`を使えばいいというもの、配列の追加削除には`$set`を使うようにすればいいというもの...などが出てきましたが、この記事のように親子間でデータを引き渡す場合についてはそれらの方法では解決せず、`watch`を使うのが正解のようです。

参考までに、以下がVue.jsでデータ変更が画面表示に反映されないときに参考になりそうな記事です。

- [Vue.js で後から追加したデータを反映させる方法](https://qiita.com/popona/items/cb659d6514b86a43cf2f)
- [よくある初心者の落とし穴](https://jp.vuejs.org/2016/02/06/common-gotchas/)
- [Vue.jsでビューの変更がされないときに疑うこと+主な解決策方法](https://qiita.com/bobu_web/items/ec5a98d03758d12ad721)
Macにて4Kディスプレイで適切な解像度に設定できない場合の対処法

# はじめに

nVIDIA社製GPUを搭載したグラフィックカードと4Kディスプレイを導入したのに、高解像度の設定ができないという現象があったので、対応をまとめてみます。

# 通常の解像度選択

システム環境設定からディスプレイを選択し、解像度が「ディスプレイのデフォルト」になっているので「変更」をクリックする。

<img width="780" alt="スクリーンショット 2019-02-05 11.15.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/114240/b326d248-60de-dd48-d513-419908b4766c.png">

表示される解像度の選択肢には（低解像度）という文字があり、これを選択するとメニューの文字列が小さすぎてとても読めたものではない...(-_-;)

# 高解像度の選択

解像度の変更をクリックするときに、optionキーを押しながらクリックすると、選択できる解像度が増えます。

<img width="780" alt="スクリーンショット 2019-02-05 11.15.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/114240/9eccedaf-affb-058f-49da-b002fb38c3fe.png">

適切な解像度を選択すると、メニューなどの文字がくっきりと表示され、画像なども高解像度で表示されるようになりました。

...やった！
S3からNeptuneにバルクロードする


NeptuneにVertex(頂点)、Edge(辺)のデータをいれる手段の一つとしてS3を経由したバルクロードの方法があります。

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/bulk-load.html)にもある通り、csvを用意してIAMを設定すればほぼほぼ完了です。


IAMの用意
---

マネジメントコンソールから「クラスターのアクション」から「IAMロールの管理」を選択すると下記の画面が現れます。

![スクリーンショット 2019-02-05 10.39.53.png](https://qiita-image-store.s3.amazonaws.com/0/18331/c921fec5-691a-71f2-5245-2555595a91ab.png "スクリーンショット 2019-02-05 10.39.53.png")

ここに、設定したIAMロールを紐付ければオッケーです。反映まで少し時間がかかります。

設定方法ですが[ここ](https://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/bulk-load-tutorial-IAM.html)にある通り、

* AmazonS3ReadOnlyAccessを使う
* 信頼関係の編集を行う

以上の２点を行えばオッケーです。最終的に以下のようになると思います。

![スクリーンショット 2019-02-05 10.45.53.png](https://qiita-image-store.s3.amazonaws.com/0/18331/6215023f-f55d-f861-02b8-f01ccecadbfe.png "スクリーンショット 2019-02-05 10.45.53.png")

![スクリーンショット 2019-02-05 10.46.03.png](https://qiita-image-store.s3.amazonaws.com/0/18331/247c695c-76f9-c02a-6ee3-3d8ebf18a20a.png "スクリーンショット 2019-02-05 10.46.03.png")

![スクリーンショット 2019-02-05 10.46.09.png](https://qiita-image-store.s3.amazonaws.com/0/18331/14b44024-ceed-3b68-c9e0-b101c572eaba.png "スクリーンショット 2019-02-05 10.46.09.png")


データの用意
---

[ここ](https://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/bulk-load-tutorial-format-gremlin.html)を参考にためしてみます。

ヘッダーとして、下記が最低限定義できれていれば、ほぼほぼオッケーでしょう。

![スクリーンショット 2019-02-05 10.48.37.png](https://qiita-image-store.s3.amazonaws.com/0/18331/2be02ff3-0ee8-2fd4-af9d-70fc8182a50d.png "スクリーンショット 2019-02-05 10.48.37.png")

ちょうど、私は駅すぱあとを提供する会社に勤めていますので、駅データを抽出してCSV化してみました。
作成したcsvファイルをS3に配置します。


バルクロード
---

個人的都合でNeptuneをPrivate Subnet内に配置しているため、アクセスが許可されたEC2からバルクロードしたみたいと思います。

以下の２点がちゃんとできていれば、ほぼほぼオッケーです。

* curlコマンドが使える
* セキュリティグループが適切に設定されている
* 
![スクリーンショット 2019-02-05 11.04.00.png](https://qiita-image-store.s3.amazonaws.com/0/18331/f65036d9-447d-111b-b21d-3c5b58c23032.png "スクリーンショット 2019-02-05 11.04.00.png")

EC2上で下記のコマンドを実行します。

```
curl -X POST \
    -H 'Content-Type: application/json' \
    https://あなたのクラスターエンドポイント:8182/loader -d '
    {
      "source" : "s3://csvを配置したバケット/作成した.csv",
      "format" : "csv",
      "iamRoleArn" : "さっきつくったIAMロール",
      "region" : "ap-northeast-1",
      "failOnError" : "FALSE"
    }'
```

そうすると下記のレスポンスが帰ってきます。

```
{
    "status" : "200 OK",
    "payload" : {
        "loadId" : "50b6ccc6-de0b-4830-ba15-*********"
    }
}
```

これは、挿入・更新が成功したというものではなく、どうやら処理を受け付けたというレスポンスっぽいです。

また、挿入後すぐに別のを挿入しようとするとエラーが帰ってきます。
（基本的に１タスクしか受け付けない？）

ロードとCPU使用率の関係
---

Neptuneのr4.largeインスタンスを使ってたので、ロード件数に対してどれくらいCPUを使うのかチェックしてみます。

結果としては、下記のようになりました。

![スクリーンショット 2019-02-01 15.10.46.png](https://qiita-image-store.s3.amazonaws.com/0/18331/7443d74b-4aa8-e3a8-1ded-70b6bbe8a515.png "スクリーンショット 2019-02-01 15.10.46.png")

ただ、これを試す前に２０万件を一気にバルクロードしたらCPUが100%に張り付いたまま帰ってこない事象が発生しました。（バグか？）

[ベスト・プラクティス](https://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/best-practices.html)にあるように、ロード時には一旦強いインスタンスにスケールアップするのがベターですね。
AWS Certified Solutions Architect Associateを再認定しました

2年経過して期限が切れたので再認定試験を受けました。
最近AWSにがっつり触れてなく自信がなかったので、ProfessionalへのレベルアップではなくてAssociateの再認定に逃げました。

# 私のこと

インフラエンジニアです。
Azure寄りですが、AWSもちょいちょい触ってるのと最新情報はウォッチしてます。

* AWS
    * Solutions Architect Associate（期限切れ）
* Azure
    * MCSE: Cloud Platform and Infrastructure
* GCP
    * Professional Cloud Architect

# 再認定ポリシーが変わります

いきなりですが、再認定ポリシーが変わるようです。
AWSから期限切れのメールが届き、こんなことが書かれていました。

```
2019年2月末までに、現在および将来のAWS認定はすべて、2年間ではなく3年間有効となります。
つまり、AWS認定アカウントにおいて、「有効期限」と「再認定のための最終日」が同じになります。 
また、2月末までに、個別の再認定試験の実施を廃止します。
認定を更新するために、50%割引で完全な試験を受験するか、または同じく50%割引でソリューションアーキテクト - プロフェッショナル試験にアップグレードすることができます。
ソリューションアーキテクト - アソシエイトまたはプロフェッショナルベータ試験（利用可能な場合）への参加結果が合格の場合も、再認定要件が満たされます。 
```

なるほど。再認定試験そのものがなくなると。

# 黒本最強説

[徹底攻略 AWS認定 ソリューションアーキテクト - アソシエイト教科書](https://www.amazon.co.jp/dp/4295005495/ref=asc_df_42950054952580417/?tag=jpgo-22&creative=9303&creativeASIN=4295005495&linkCode=df0&hvadid=295658337340&hvpos=1o1&hvnetw=g&hvrand=17867220016027771876&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1028853&hvtargid=pla-595366187700&th=1&psc=1)

どうやって勉強しようかなと思ってたところ、ちょうどタイミングよく2019/1/18に発売されたばかりだったので購入しました。
めちゃくちゃ分かりやすかったです。おすすめです。
今回この本しかやってないです。

章末の演習問題が若干難易度低かったので大丈夫かなと思ってたんですが、購入特典で付いてくる模擬問題が秀逸で、難易度的にもアソシエイト試験と同等か若干低いくらいかなと思いました。
模擬問題がすらすら分かるくらいであれば、本番も問題ないと思います。

# 結果

合格
891点 / 1000点

# まとめ

S3やEBSのタイプが増えていたり、改めて勉強すると知らないこともたくさんあって受験してよかったです。
プロフェッショナルへのアップグレードが50%割引になるので、プロフェッショナルまで目指そうかなと思います。
Oracle Cloud Infrastructure上のWindows VM x2台でSANsymphonyを使ってWSFC（フェイルオーバークラスター）を組んでみる

出来そうなのでやってみた。
**結論：できました。**

まずはWindowsを2つ作ります。今回はAvailability Domainは同一にして、Fault Domainはわけました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/115778/8eaf822b-64e2-8ddd-7c8a-8f479974e851.png)

それぞれに一つ以上のBlock Volumesを追加します。paravirtulizedでもiSCSIでもOK。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/115778/ef29b241-2366-6487-451d-21f71f0339c5.png)

それぞれに一つVNICを追加します。追加したVNICはストレージI/Oの同期に使います。サービスやRDPと共有すると遅延の原因になってしまいます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/115778/39bf3934-541e-22fa-ddf1-e824e429e0b9.png)

Default Security Listに穴を開けてRDPとVM間通信が出来るようにしましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/115778/a4e38d63-a6db-7ab9-6e8f-be0b71dcdd09.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/115778/40f6d303-8376-b8a6-c2c7-cc87641fd563.png)
↑今回は検証なので全開放。ちゃんと開けるならTCP3389（RDP）、TCP3793（データコアのサービス）、TCP3260（iSCSI）だけにしましょう。


（いつものようにインストールとか初期設定をして・・・）
↑興味ある人はコメントください。ちゃんと書きます。



はい、できました。
<img width="676" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/115778/29342b89-7017-0356-1640-3565475e42a4.png">

手抜きなのでドメインに参加せずワークグループのままですが、無事にフェイルオーバークラスターを組むことが出来ました。

軽く性能を見てみましょう。またも手抜きでCrystalDiskMarkを初期設定のまま実行してみました。
[ここによると](https://cloud.oracle.com/storage/block-volume/faq#capacity)Oracle Cloudもご多分に漏れず容量に比例して性能が伸びていきます。今回のディスクサイズは最小の50GBです。

左がParavirtulizedでそのままマウントした時
右がSANsymphonyの同期ミラーで仮想化してCSVとしてマウントした時
<img width="201" alt="無題.png" src="https://qiita-image-store.s3.amazonaws.com/0/115778/198a147f-4075-329c-cd99-8e19232804c8.png">  <img width="201" alt="無題.png" src="https://qiita-image-store.s3.amazonaws.com/0/115778/5a2f8bb2-fa65-7ccf-d1b6-185b79f60058.png">

ネットワークを往復するので書き込みは性能が低下すると思っていましたがライトキャッシュの効果がそれを上回りました。

**果たして需要はあるのか！？**
MACでEDFbrowserを使う

# EDF-D形式の悩み
mne-pythonを使う人とか、pyedflibを使う人は、
EDF形式を読み込んで脳波解析を出来ます。
しかし、残念ながらEDFには複数種類があり、EDF-Dは読めません。
そこで、EDFbrowserというソフトでEDF-Cに変換することになります。
(他にもやり方はあるかもですね)

# MACでのさらなる悩み
windowsならバイナリの配布がされていますし、
linuxではコンパイルの方法を書いてあります。
でも、mac版のバイナリは配布されてないし、コンパイルの方法も書いてないです。

だから、コンパイルすることにします。

# 前提
下記のソフトはインストールしておきましょう。
- xcode : AppStoreにあります。超重いですが仕方ないですね…。
- homebrew : パッケージ管理ソフト。→　https://brew.sh/index_ja
- qtとgit : homebrewの存在下で下記をやると入る。

```sh
brew install qt
brew install git
```

# コンパイル
すぐ出来ます。

```sh
git clone https://gitlab.com/Teuniz/EDFbrowser/
cd EDFbrowser; qmake; make; open .
```

これでfinderが開くから、この中にあるedfbrowser.appを
アプリケーションのフォルダにコピーすればいいです。

# 問題点
これ、他のmacにコピっても動かなかったんですよね。
僕のスキルの問題と思いますが…まぁ、コンパイルの術を分かっていれば、
いつも最新版を使えるのでこれはこれでいいでしょう！
windows 機で mac みたいな web 開発環境を用意する wsl + linuxbrew + vscode 

# はじめに

家に League of Legends 用の windows機（TSUKUMOさんありがとう。）があり、開発したいな〜とか思って幾星霜。
`power shell` とか　なんか嫌だな〜とか思ってて、 `bash on ubuntu on windows` の時に試したけどなんか上手くいかず、環境構築を諦めていた人向け。

ちなみに　開発環境というのは `npm` の利用などを前提としています。

# wsl

何だこれは、、、と思って コマンドプロンプトで `wsl` と叩く。起動。すごい(小並感)。

# linuxbrew

Mac で開発している人ならほぼお世話になっているだろう `brew`。
これが遂に `wsl` で対応したというので入れる。

以下は `wsl` 上で行う

##### 1. wslでの最低限の環境を整える (初めての方向け)
```
sudo apt-get install build-essential curl file git
```

##### 2. linuxbrew 入れる
```
sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
```

結構時間かかるが、我慢

##### 3. path を通す

```
echo "eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" >>~/.profile
```

ここで注意なのが、 `.profile` というのが wsl の設定ファイル。ただ、 `.bash_profile` があるとそちらを読みにいってしまうので、ファイルを消すか、その中で `source .profile` なりをして対応しましょう。 (通算１敗)

##### 4. 設定ファイルを読み込む

```
source ~/.profile
```

これは初回のみ

ここまでくれば、後は Mac と同じ要領でいける。 `nodebrew` でも `nodenv` でもいいので、入れよう。

#　VSCode

`wsl` では `node` もとい `npm` の準備が整った前提で、

[Windows10でWSLとVSCodeを使ってC++プログラミング環境を整える](https://qiita.com/yo_kanyukari/items/37421f497b7ffaa75502#%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E3%81%AE%E8%A8%AD%E5%AE%9A
)

ここに書いてあるように default のターミナルを `wsl` にする。
ただ私は上の記事のような設定画面でなく、　もうちっと簡単に設定できる　UI が合った気がするが、、、まぁいいでしょう(よくないだろ！)

# 日常でのムーブ

- コマンドプロンプトで 作業フォルダに `cd`
- そこで `code .`
- 作業ディレクトリと一緒に `VSCode` が起動
- 新規ターミナル開く
- `wsl` で開かれる
- ハッピー　

みたいな感じでいけそう。
これだったら windows でも苦しくなく開発できそう。

もっといい方法ある人は教えてちょんまげ。
pandas.DataFrameのループ記法についての備忘録


```python:ループ処理
#リストループ(numpy.arrayも同様
for index, item in enumerate(list1):
    print(str(index))

#辞書
for key, value in dict.items():
    print (key, value)

for key in dict:
    print (key)

for value in dict.values():
    print (value)

#Seriesループ
for index, item in srs.iteritems():
    print (index, item)

#DF行ループ
for index, row in df.iterrows():
    df.at[index, 'square'] = df['value'] ** 2

#DF列ループ
for column_name, item in df.iteritems():
     print(type(column_name))

#プログレスパー表示版
#tqdmはアラビア語でprogress
#特にdfのaxis=1は重く、表示してあげると使用感が良くなります
from tqdm import tqdm
for i in tqdm(range(100)):
    sleep(0.1)
```

子要素へループ処理をする場合、
C#などのforeachの感覚で行うと注意。

pythonではオブジェクトごとに
ループ処理の書き方が違います。
最初enumerateをDataFrameに使ってハマりました。

また、辞書はkey, valueのみに対して、
DataFrameは行、列それぞれに対してループが可能。

参考
---
[python の for 文の回し方。リスト、辞書、pandas、ほか](http://ailaby.com/for/#id3)
誰でもアプリが作れちゃう！EXPOでreact-native入門

アプリを作りたくなったので、EXPOというやつでreact-native入門してみる記事。

# EXPOとは

なんかいい感じにreact-nativeを書けるようにしてくれるやつ。rubyで言うところのRuby on Railsみたいなポジションらしい。

https://expo.io/

# 環境構築

まぁyarnとかnpmとかは入ってるものとして...

brewでwatchmanってやつを入れる

```
$brew install watchman
```

expo動かすやついれる

```
$yarn global add expo-cli
```

# expo動かしてみる

```
$expo init tommy-app
```

テンプレートを選んでね。
→せっかくなのでblank

<img width="469" alt="スクリーンショット 2019-02-05 10.40.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/77198/8fc650b2-5e9b-db4c-c113-056d45c37058.png">

ワークフローを選んでね
→工事マーク付いてるのでとりまmanaged

<img width="533" alt="スクリーンショット 2019-02-05 10.44.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/77198/90ef765f-6143-084a-e20f-0a2fbcbe5171.png">

名前つけてね
→まぁtommy-app

<img width="506" alt="スクリーンショット 2019-02-05 10.41.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/77198/9a021c6e-7fe6-6b83-5406-63aa572fe20d.png">

yarn見つけたけど使う？
→ Y

<img width="444" alt="スクリーンショット 2019-02-05 10.41.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/77198/d2e0e6bd-aff6-a04d-60ba-6e8873d3b4d7.png">

早速起動。

```
$cd tommy-app
$yarn start
```

なんかでる。Run　on　iOS simulatorを押してみる。

![スクリーンショット 2019-02-05 10.47.05.png](https://qiita-image-store.s3.amazonaws.com/0/77198/5db513ed-526c-49cd-e019-a34e4acc33fc.png)

シミュレーター動いた。xcode入れてない人はいれとこうね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/77198/3398e33d-cc9e-9911-d8e2-42c51d054381.png)

実機デバックのために、ログインしておく

```
$expo login
```

expoのアプリを入れると、同じwi-fiにつないどけば、実機デバックもできちゃって便利😭

<img width="375" alt="Image from iOS.png" src="https://qiita-image-store.s3.amazonaws.com/0/77198/100e9269-ed7e-01b5-edd4-82b203c42913.png">
View Customize pluginを特定のプロジェクトのみに適用する

View Customize pluginではまったのでメモします。
プロジェクト"test"のみにJavaScriptを適用したいときの書き方例です。


パスのパターン：/issues
挿入位置　　　：全てのページのヘッダ
種別　　　　　：JavaScript
コード

``` 
$(function() {
　if ($('body').hasClass('project-test')) {
　　# 任意の処理
　}
})
``` 

if文をfunction内に入れるのがキモみたいでした。

参考：[View customize pluginを使いこなす](https://www.slideshare.net/onozaty/view-customizeplugin-62005780)
Controller に書いた helper メソッドを view spec で stub する

```ruby 
# ApplicationController

def user_logged_in?
 'hoge'
end

helper_method :user_logged_in?
```

```ruby
# header.html.slim_spec.rb

RSpec.describe 'application/_header', type: :view do
  let(:user) { create(:user) }

  subject do
    render partial: 'application/header'
  end
  before { stub_helper_method }

  def stub_helper_method
    controller.singleton_class.class_exec do
      helper_method :user_logged_in?
      define_method :user_logged_in? do
        'stub'
      end
    end
  end

  context 'not signed in' do
    before do
      allow(view).to receive(:user_logged_in?).and_return(false)
    end

    it do
      is_expected.to have_link 'ログイン', href: new_user_session_path
    end
  end
```


純粋に以下のみで試みると
`allow(view).to receive(:user_logged_in?).and_return(false)`

```
=> does not implement: user_logged_in?
```

と返されるため。
PythonスクリプトをPyInstallerでWindowsの実行体にする際にハマったことをまとめる 

# TL;DR

 ubuntu側で開発したPythonスクリプトをWindowsの実行体に変換する必要があった  
 実際の作業で何点かハマったので、まとめておく  
 ちょっと前の作業をまとめているので、バージョン情報等あいまい  

※ 本記事は、2019/02/05に[弊社スタッフブログ](https://www.northtorch.co.jp/archives/469)に投稿した記事をQiitaに転載しています。

# 発端

ubuntuで開発したPythonスクリプトをWindows上で実行する必要があった。  
将来的に配布を簡単にしたい、という要望もあり、使用するPCに逐一Python環境をインストールするのは避けたかったので、PyInstallerにて実行体に変換した。  
いくつかハマったことがあったので、後学のためにまとめておく。

ブログに起こすにあたってググってみたら、大半は下記の記事にあった・・・
- [PyInstallerを使ってみた](https://qiita.com/TakamiChie/items/8dba8459343db898b335)

# ハマったこと

## \_\_file\_\_の指すパスがおかしい

PyInstallerで実行体化すると、\_\_file\_\_シンボルが、実行体変換前のパスに置換されてしまう模様。  
参照URLでも言及されていたが、sys.argv[0]に置き換えて対処。

## PyInstallerで指定したモジュールよりも上の階層のソースコードが実行体に同梱されない

ソースコードは下記のようなフォルダ構成だった。  

```
├ Func1
│  ├ func1_entry.py
│  └ func1_body.py
└ Main
   └ main.py
```

main.pyから、上の階層のfunc1_entry.pyをimportして使用している。  
PyInstallerの対象モジュールとして、main.pyを指定すると、できた実行体を実行した際に、'func1_entry.py　が見つからない'旨の実行時エラーが発生する。  

これは結局解消できなくて、フォルダ構成を下記のように変更した。

```
└ Main
   └ main.py
      └ Func1
         ├ func1_entry.py
         └ func1_body.py
```

## pandasでcsv読み込む際の行デリミタのデフォルトが異なる

PyInstallerを実行するPython環境はAnacondaで作成したのだが、pandasのread_csv関数でcsvファイルを読み込む際に、'Cr', 'Lf'どちらも行デリミタとして認識されてしまった。  
Excel等で作成したcsvファイルは'Cr + Lf'が行デリミタなので、倍の行数があるように見えてしまった。  
read_csv関数に明示的にデリミタ設定することで対応。  

# 参照URL

- [PyInstallerを使ってみた](https://qiita.com/TakamiChie/items/8dba8459343db898b335)
- [pyinstallerでEXE化した後の実行で起動できない問題の調べ方と、今回のケースでの解決法](https://note.mu/yanchan2020/n/n623df3708c22)
Neptuneの個人的にだいじなところ


AWSより1/23に待望のNeptuneが利用可能になりました。やったぜ！！！
https://aws.amazon.com/jp/about-aws/whats-new/2019/01/amazon-neptune-available-in-asia-pacific-tokyo/


ここ数日業務でNeptuneを触らせてもらえる機会があったので、抜粋して（自分のために）まとめてみようと思います。


コスト感
---

東京リージョンのNeptuneは下記の[価格](https://aws.amazon.com/jp/neptune/pricing/)テーブルになっています。

![neptune価格テーブル.PNG](https://qiita-image-store.s3.amazonaws.com/0/18331/da516293-fc12-29bc-826e-9c05f421353a.png "neptune価格テーブル.PNG")

下記のRDSと比較すると若干割高ですね。

![RDS価格テーブル.PNG](https://qiita-image-store.s3.amazonaws.com/0/18331/6e8227a1-75ba-390e-15df-eb7c2c4ee175.png "RDS価格テーブル.PNG")


可視化
---

Neo4jの調査をしていたときに、グラフDBの可視化することで、調査効率が格段とあがりました。
しかし、Neptuneではそのような機能の提供がないため別途可視化ツールを容易します。

可視化ツールについては[BlackBeltのスライド](https://www.slideshare.net/AmazonWebServicesJapan/20180703-aws-black-belt-online-seminar-amazon-neptune?ref=https://aws.amazon.com/jp/blogs/news/amazon-neptune-tokyo-region/)内に紹介があります。


ちなみに私は[graphexp](https://github.com/bricaud/graphexp)を使っています。

READMMEにも記載があるのですがneptune用に`graphConf.js`ファイルに`SINGLE_COMMANDS_AND_NO_VARS = true`の変更を加え、neptuneはhttpsでの接続となるため

`graphioGremlin.js`の下記の部分をhttpからhttpsに書き換えました。

![スクリーンショット 2019-02-05 10.19.17.png](https://qiita-image-store.s3.amazonaws.com/0/18331/3112ac1f-14fd-4083-ae34-6e98929e87ef.png "スクリーンショット 2019-02-05 10.19.17.png")

今回Private Subnet内にNeptuneを配置したため接続周りでいろいろと苦労したのですが、
それは後ほど

冗長化
---

* スケールアップは簡単。
* リードレプリカの追加、これも簡単。

### singleAZでつくったものをMultiAZに変更できるか。
(RDSはできた記憶があるような、ないような）

[neptuneのCLI](https://docs.aws.amazon.com/cli/latest/reference/neptune/modify-db-instance.html)に、`modify-db-instance`というコマンドが用意されています。そのパラメータに`--multi-az | --no-multi-az`があります。

これを、singleAZ配置してしまった、インスタンスに対して実行すると。。。

![スクリーンショット 2019-02-04 14.13.44.png](https://qiita-image-store.s3.amazonaws.com/0/18331/0e2b65f0-8e01-860c-1dcc-50233034bf3e.png "スクリーンショット 2019-02-04 14.13.44.png")

とりあえず、できないということがわかりました。
Windows 10 Pro x64 + Excel2016 x86 VBA の ComboBox で複数の列を表示する

#目的
Excel VBA のUserForm上のComboBoxに複数列を表示したい時のメモ
普段はデータベースからひらってきたデータを表示することが多いんだけど
最小限必要なコードを張りつけてみる
##作成手順
・UserFormを1個追加する
・UserFormの上にComboBoxを1個追加する
・UserFormの上にCommandButtonを2個追加する
・CommandButton1をクリックしたときにComboBox1にデータを追加する
・CommandButton2をクリックしたときにComboBox1で選択されている
　データを表示する
対象データは[郵便番号データダウンロード](http://www.post.japanpost.jp/zipcode/dl/kogaki-zip.html)の全国一括(KEN_ALL.CSV)より一部抜粋
##サンプルコード
```vb
Option Explicit

Private Sub CommandButton1_Click()

    Dim varArry()   As Variant
    
    ReDim varArry(3, 2)

    varArry(0, 0) = "01"
    varArry(0, 1) = "北海道"
    varArry(1, 0) = "02"
    varArry(1, 1) = "青森県"
    varArry(2, 0) = "03"
    varArry(2, 1) = "岩手県"
'
    ComboBox1.Clear
'
    With ComboBox1
        .ColumnCount = 2            '1行に2個表示
        .TextColumn = 2             '2個目のデータを表示
        .BoundColumn = 1            '※1参照
        .ColumnWidths = "30, 50"    'カラムの幅
        .List() = varArry()         'リスト項目の設定
    End With

End Sub

Private Sub CommandButton2_Click()
'
    Dim strCode     As String
    Dim strName     As String
'
    If ComboBox1.ListIndex >= 0 Then
        strCode = Trim(ComboBox1.Column(0, Me.ComboBox1.ListIndex))
        strName = Trim(ComboBox1.Column(1, Me.ComboBox1.ListIndex))
    End If
'
Debug.Print strCode, strName
'
End Sub
```
※1
0 コントロールに ListIndex プロパティの値を割り当てます。
1 以上指定した列からコントロールに値を割り当てます。このプロパティを
　使用するとき、列には、1 から番号が付けられます (既定)。
##参考にしたのは以下のサイト
["BoundColumn/連結列" プロパティ](https://msdn.microsoft.com/ja-jp/VBA/Language-Reference-VBA/articles/boundcolumn-property)
("bufio".Reader) ReadString('\n') と ("bufio".Scanner) Scan() の微妙な違い

明確な違い
===

* `("bufio".Reader) ReadString('\n')`
    * 得られる行文字列（戻り値）は改行コードを含む
* `("bufio".Scanner) Scan()`
    * 得られる行文字列（`Text()`の戻り値）は改行コードを含まない

改行コードのない最終行の扱い
=====================

最後の行が `abcd`**[EOF]** というテキストの場合

* `("bufio".Reader) ReadString('\n')`
    * {`"abcd",io.EOF`}という戻り値となる
* `("bufio".Scanner) Scan()`
    * `Text()` は "abcd" という戻り値を返し、「次回」の `Scan()` が false になる

Scanner の方は定番であるところの、

```go
for sc.Scan() {
   line := sc.Text()
   fmt.Println(line)
}
```

という書き方で問題ないが、Reader の方は

```go
for{
    line,err := r.ReadString('\n')
    if err != nil {
        break
    }
    fmt.Print(line)
}
```

だと、最後の行が抜けてしまう。

```go
for{
    line,err := r.ReadString('\n')
    fmt.Print(line)
    if err != nil {
        break
    }
}
```

と書かないといけない（厳密には io.EOF 以外のエラーの時の処理を分けるべきだが…）。こう書くと「どんなケースでも常に Scanner を用いる」のが妥当なように思われるが、Scanner は最終行の改行の有無がわからないので、入力したデータをできるだけ変えずに出力するようなフィルター処理には向かない。