OmniAICreator/Qiita-1.07M huggingface dataset:
EMR Hiveの性能検証(TPC-HベンチマークでAuroraと比較)

# TL;DR

* Amazon EMRで構成したHiveの性能検証を，下記の観点で行いました．
    * RDBベンチマークTPC-Hによる計算時間の計測
    * AWS Auroraと，EC2上に構成したMariaDBを比較対象にしました
* 計測の結果，以下のことが明らかになりました
    * EMR Hiveは，費用が高い上，計算開始のセットアップに時間を要するので，使用用途を選びます
    * 一方で，より大きな問題に良いスケーラビリティを示すので，大規模データのバッチ処理に向いたクエリエンジンであると言えます
* [Auroraの性能検証（EC2との比較，データ量と計算時間の関係）](https://qiita.com/myoshimi/items/3fc65bb7e29ecd25f925)の続編です
    * この記事から読み始めることもできます

# 実験設定

## 計算処理

* [Auroraの性能検証（EC2との比較，データ量と計算時間の関係）](https://qiita.com/myoshimi/items/3fc65bb7e29ecd25f925)と同じ計算を実施しました
    * TPC-Hベンチマークを，ScaleFactor(SF)=1,4,8で実行し，計算に要する時間を計測しました

## 実験環境

* Amazon EMRはデフォルトの設定「3 x m3.xlarge(4vCPU,15GiB)」で構成しています
* Auroraは，db.r5.large(2vCPU, 16GiB)で作りました

## 実験手順

* EMRマスターインスタンスで，Query1から22まで，順番に実行します
    * Hiveの実行時オプション（データベース指定），および，クエリはHQLなるクエリ言語（MySQLと若干異なる）であることから，MySQLクライアントと若干祭があります

```bash
for i in `seq 1 22`;
do
    hive --database sf1 -f ${i}.sql
    hive -e "RESET QUERY CACHE;"
done
```

# 計算結果

## Hiveでは実行できないクエリ

* MySQLそのままでは，Hiveで実行できないクエリがありました．
    * Query 2
    * Query 8
    * Query 9
    * Query 11
    * Query 15
    * Query 16
    * Query 21
    * Query 22
* この記事では，実行できないクエリは比較対象から除きました
    * このようなクエリを実行したい場合は，別途クエリをHQL対応に修正することになります

## SF1での性能比較

* SF=1 (1GiB)のデータを対象にしたベンチマーク結果を示します
    * 比較のため，Aurora, EC2(t2.small)の計算時間も合わせて示します

![sf1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/5f12e6e8-f253-18d8-40fa-ec15169aa080.png)

### 考察：Hiveの起動オーバヘッドの大きさ

* EMRは，小さな問題でも40秒程度の時間を要する（起動時間，計算セットアップ時間など）
* Aurora, EC2は，クエリごと計算時間に関連がありそうな一方で，EMRは必ずしもそうではなさそう
    * Aurora/EC2はQ3がQ1よりも計算時間が大きい一方で，EMRでは計算時間が小さい
* 計算を始めるまでのオーバヘッド（クエリをMapReduceできる形に変換し，データを分割して並列計算する処理）が大きいので，Hiveはトランザクション処理というよりは，BI（大きいデータの分析処理）に向いている

## EMR Hiveで問題サイズでの比較

* EMR Hiveで， SF=1, 4, 8 を対象にした計算結果を示します

![emr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/6febe641-abd6-af64-f526-e2650f4838ea.png)

### 考察: スケーラビリティ

* データ量に応じた計算時間を要する
    * マルチノード構成で，メモリの総量が大きいので，極端に時間が掛かったクエリは無かった
* 計算時間はきれいにスケールするわけではないことも示された
    * Q1はテーブルをスキャンする処理なので，（起動オーバヘッドが各データサイズで同程度とすると）スケールしているように見える
    * Q4はSF=1とSF=4の計算時間の差に比べて，SF=4とSF=8の差が大きくなっている
    * 一方で，Q7は逆に，SF=1とSF=4の差が大きく，SF=4とSF=8の差は小さい


## 費用

* 東京リージョンの料金は，以下のとおりです
    * [Amazon EC2 料金表](https://aws.amazon.com/jp/ec2/pricing/on-demand/)
    * [旧世代のインスタンス](https://aws.amazon.com/jp/ec2/previous-generation/)

| サービス | インスタンスタイプ | USD/hour |
|---|---|---|
| EMR    | m3.xlarge x 3 | $0.385 \times 3 = 1.155 $ |
| Aurora | db.r5.large | $0.152$ |

* 時間単価が約7.5倍($1.155 / 0.152 = 7.60$)あるので，基本的にはAuroraに軍配が上がります
* 8GB程度のデータを対象とした場合，Hiveは起動＋セットアップ時間の占める割合が大きく，良い効果を得にくいです
* [Auroraのデータサイズごとの計算時間](https://qiita.com/myoshimi/items/3fc65bb7e29ecd25f925#%E8%A8%88%E7%AE%97%E7%B5%90%E6%9E%9C-1)から，Q14のように，メモリ量の関係から極端に計算時間が掛かるような処理に対応する際に，Hiveの効用が得られます
    * SF=8ではAuroraは力不足が顕在化し，EMRの方が3倍程度速くなるQ20のようなものも出てきます

# 参考資料

* [Amazon EMRでHiveのセットアップ](https://qiita.com/myoshimi/items/1ce78757a9f05d476bbb)
* [ベンチマークTPC-HをAmazon EMRのHiveで実行する方法](https://qiita.com/myoshimi/items/2b99d1eab45568200a18)
* [Auroraの性能検証（EC2との比較，データ量と計算時間の関係）](https://qiita.com/myoshimi/items/3fc65bb7e29ecd25f925)
bundle installすると"can't find gem bundler…"というエラーが発生

# bundle installでエラーが出る
## エラー内容
`bundle install`を実行したところ、
`find_spec_for_exe': can't find gem bundler (>= 0.a) (Gem::GemNotFoundException)`
というエラーが発生してbundleinstallできない。

## 原因
### rubyとbundlerのバージョンに注意！
rubygemとbundlerのバージョンの組み合わせによって発生するエラーらしい。

## 解決法
- **bundlerのバージョンを下げる**

最新ではなく少し前のバージョンを指定してinstallしてあげる。

```
$ gem install bundler -v '1.17.3'
```

## そもそもの確認
- **rubyとbundlerの場所を確認する。**

rubyとbundlerが片方ローカルを参照していて、もう片方はグローバルを参照しているなど、そもそもローカルにgemが入っていなかったケース。

```
$ which ruby
/Users/hoge/.rbenv/shims/ruby
$ which bundler
/Users/hoge/.rbenv/shims/bundler
```

## 参考
- [bundle install しようとしたら ruby のバージョン違くてコケた話](https://qiita.com/white_aspara25/items/d5e19b82be17048d9215)
- [新年早々Rubyのバージョン上げようとしたらRubyGemsとBundler2の組み合わせで問題にぶつかった
](https://blog.hokkai7go.jp/entry/2019/01/09/120110)
ディレクトリ内のファイルのみを mv する

#動機
カレントディレクトリの全ファイルを mv したいことがある。
だが mv にはファイルのみを対象にするオプションなどはなさそう。

#一行でやってみた

```
$ ls -l | grep ^- | awk '{print $9}' | xargs -I {} mv {} path-to-dir
```

チキンをさばくのに牛刀を用いている感が否めない。
ベターな方法があったら是非お教えください。
XAMPとMAMPを同一PCにインストールすることで起こる競合について

#XAMPPとMAMPが競合する問題の解決方法の備忘録
##事の発端について
XAMPPをインストールした環境にMAMPをインストールした際、MAMPのMySQLサーバが起動しない問題が発生した。
##この解決方法？
ポートを変えればなんとかなるかと思ったができなかったため、私の環境(Win10)では、まず環境変数からXAMPPに通されているMySQLのPathを削除。これでMAMPのインストールを行うことで、MySQLのPathをMAMP側に変更し、結果MySQLサーバが起動できた。
しかし、この状態だと何故かphpMyAdminを開くとエラーが出てくる。これを解決するにはMAMPのPHPconfを変えろとメッセージが表示されるが、XAMPPを開いとけばなぜかphpMyAdminを開くことができた。（もしかしたらXAMPPを起動しておけばMySQLのPathを変更しなくてもいけるかも）

###真の解決方法
そもそもWin環境でXAMPPを使いながらMAMPを入れなければ良いのだ。XAMPPだけで良くない？
GNU AWK 5.0を早速インストールしてみる

![awk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258841/c0618d8e-c30e-d6c7-b215-6d3403847f22.png)

## 背景

GNU AWK 5.0がリリース。8年ぶりのメジャーバージョンアップをしたというニュースを見て早速使ってみようと思いとりあえず使う段階まで行ったのでメモ的に残します。

[GNU AWK 5.0がリリース。8年ぶりのメジャーバージョンアップ。正規表現ライブラリがGLIBCからGNULIBへ移行、名前空間が実装
](https://www.publickey1.jp/blog/19/gnu_awk_508glibcgnulib.html)

## ビルド手順

①ソースを入手 解凍
下記から自分の使いたいバージョンを持ってこれる
今回は5.0.0.を使用
ftp://ftp.gnu.org/gnu/gawk

``` bash
$ wget ftp://ftp.gnu.org/gnu/gawk/gawk-5.0.0.tar.gz

$ cd gawk-5.0.0/

$ tar -zxvf gawk-5.0.0.tar.gz
```

②ビルド
configure⇒make⇒make installの流れでビルドからインストールまでできます。
※ 当然だがmake installだけ「root権」が必要

``` bash
$ ./configure

$ make clean ; make

```

## 試す

5.0.0になってることを確認しました。

``` bash
root@OPST-N394:~/work2/gawk-5.0.0# ./gawk --version
GNU Awk 5.0.0, API: 2.0
Copyright (C) 1989, 1991-2019 Free Software Foundation.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
```

## 変更点など

ソースと一緒に入っているNEWSに細かい変更点などが記載されています。
名前空間の実装がとても気になったので近々追記します。

``` console
11. Namespaces have been implemented! See the manual.  One consequence of this
    is that files included with -i, read with -f, and command line program
    segments must all be self-contained syntactic units. E.g., you can no
    longer do something like this:

        gawk -e 'BEGIN {' -e 'print "hello" }'
```

## 参考リンク

■ [GNU AWK 5.0がリリース。8年ぶりのメジャーバージョンアップ。正規表現ライブラリがGLIBCからGNULIBへ移行、名前空間が実装](https://www.publickey1.jp/blog/19/gnu_awk_508glibcgnulib.html)
■ [GNU awk 5.0.0がリリース - 名前空間が実装されたメジャーバージョンアップ版](https://www.softantenna.com/wp/software/gnu-awk-5-0-0/)
monorepo について調べた

採用してるプロジェクトをいくつか調べたりしたまとめ。
実運用に入る前の調査で、推測もあるので大目に見てほしい。

## 個人的なまとめ

- 今やろうとしてること的には yarn workspace だけでいいかも
- npm に公開したくなっても後から lerna 導入はできそう
- lerna 以外はなんとも

## monorepo とは

[babel の monorepo に関する話](https://github.com/babel/babel/blob/master/doc/design/monorepo.md)

monorepo 自体の良し悪しはググればそこそこ出てくる。
[babel の monorepo](https://github.com/babel/babel/blob/master/packages/) 1 つ 1 つを GitHub のリポジトリに切り出した地獄を想像すれば Pros はだいたい理解できる。

ざっと調べる限り monorepo 自体の考え方は、単に一つのレポジトリに複数のモジュールが突っ込まれているだけなので難しくなさそう。
共通ライブラリを作りたいならそのライブラリの設計のほうが、コード分割でアップデートし難さを解消したいならその分割単位を考えるほうが、よほど難しいはず。
問題を monorepo で解消できるならやればよい、って感じだろう。

## yarn を使って monorepo

yarn には [workspaces](https://yarnpkg.com/lang/ja/docs/workspaces/) という機能があり monorepo をサクッと実現できる。
実際に作ってみた monorepo が [こちら](https://github.com/macoshita/monorepo-yarn) 。 root の package.json に下記を記入するだけで、とくに変わったことはしていない。

```json
"private": true,
"workspaces": ["packages/*"],
```

また、 packages 以下の myrepo-shared, myrepo-awesome それぞれに package.json が書かれていて、両方の dependencies に lodash が書かれている。

これを clone して `yarn` を実行すると、下記のようなディレクトリ構成になる。

```
.
├── node_modules
│   ├── lodash
│   ├── myrepo-awesome -> ../packages/myrepo-awesome
│   └── myrepo-shared -> ../packages/myrepo-shared
├── package.json
├── packages
│   ├── myrepo-awesome
│   │   ├── index.js
│   │   └── package.json
│   └── myrepo-shared
│       ├── package.json
│       └── str-or-num.js
└── yarn.lock
```

各 packages 以下には node_modules ができておらず root にパッケージがインストールされる。さらに各 packages への symlink ができる。

[node.js の仕様上](https://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders)、 node_modules はディレクトリを遡って解決されるので、この状態で `cd packages/myrepo-awesome` とかに移動して `node index.js` を実行しても、ルートディレクトリで `node packages/myrepo-awesome/index.js` を実行しても、ちゃんと依存を解決できる。

なお React はこれで monorepo 運用している模様。 lerna も lerna.json で `"npmClient": "yarn", "useWorkspaces": true` とするとこれを使うようになる [(PR はこちら)](https://github.com/lerna/lerna/pull/899) 。

## lerna の使い所

上記の通り yarn workspace で単純な monorepo を作って共通モジュールを作ったりはできる。

なら lerna は何に使うのか？
公式は主要コマンドとして **bootstrap** と **publish** を挙げていて、このうち bootstrap は yarn workspace がやっている話なので、 publish がメインの用途となりそう。

各ディレクトリで run scripts を実行したい場合に `lerna run` が使える。

TBD

## lerna 以外の選択肢

こういうのすら乱立するのが JS の多様性。

- [bolt](https://github.com/boltpkg/bolt)
- [@microsoft/rush](https://rushjs.io/)
- [oao](https://github.com/guigrpa/oao)

https://www.npmtrends.com/@microsoft/rush-vs-lerna-vs-oao-vs-bolt

安心と信頼の lerna で良さそう。困ったら検討するかも？

## npm について

npm には yarn workspace に相当する機能はないので monorepo をやりたいなら現状は yarn を入れたほうが快適で安全っぽい。
[yarn workspace についてのブログ記事](https://yarnpkg.com/blog/2017/08/02/introducing-workspaces/) でも package ごとに yarn install するのでディスクが無駄になるとか、あとで lerna が張った symlink による dependencies の矛盾に yarn が気づけないとか、そういうのを解消するために yarn workspace を作ったと書いてある。

とはいえ lerna 自体が長いこと npm 対応し続けてるプロジェクトなので使えないってことはないんじゃないかと思われる。
yarn は brew upgrade で node.js を壊すことがあるので(あるよね？)、個人的には npm 側にこの実装がほしい……。

## まとめ

> [A monorepo, muhahahahahaha.](https://github.com/babel/babel/blob/master/packages/README.md)
JenkinsのパイプラインからSlackへ通知する

# 概要
パイプラインからSlack通知ができずハマったのでメモ。

# 結論
パイプラインスクリプト上で *slackSend* コマンドを召喚する。
引用：https://stackoverflow.com/questions/39140191/how-to-send-slack-notification-after-jenkins-pipeline-build-failed

# 調査
jenkinsでjobの結果をSlackに通知しようとした。
通常のジョブであれば、jenkinsのSlack Notification Pluginを入れて設定をすれば完結する。

が、パイプラインの設定にSlack Notificationの設定がない（というかビルド後の処理という項目がない）

ググると、パイプラインスクリプトでやるのがいいよ、とのこと。
waveモジュールのreadframes

Pythonのwaveモジュールをちょっとハックする記事です。

## waveモジュール
以前に音声系のネタをPythonでアレコレしていて、その時のメモをだいぶ前に記事にしてました。

[Pythonでのwavファイル操作](https://qiita.com/Dsuke-K/items/2ad4945a81644db1e9ff)

そこでとある[teratailの質問](https://teratail.com/questions/184872)が目に入ったのですが、何やらwavファイルを全部読み込みたい様子。

Pythonの公式ドキュメントにある[waveモジュールの説明](https://docs.python.org/3/library/wave.html#wave.Wave_read.readframes)に従うなら、次のようになります。

```Python
import wave

fname = 'xxx.wav' # mono

wf = wave.open(fname, 'rb')

nframes = wf.getframes()      # フレーム数を取得
buf = wf.readframes(nframes)  # 指定したフレーム数の読み込み
wf.close()
```

ところで、以前の記事にもちらっと書いたのですが、全てのフレームを読み込むだけなら`wf.readframes(-1)`とすればいいのでした。

```Python
import wave

fname = 'xxx.wav' # mono

wf = wave.open(fname, 'rb')

buf = wf.readframes(-1)  # データを全部読み込む
wf.close()
```

ただ、この方法がドキュメントに書かれていないのです。どういうことか気になってソースコードを見に行くと、実際の読み込みは内部に保持しているChunkクラスのインスタンスにデリゲートしていました。下記の`self._data_chunk`がChunkクラスのインスタンスですね。

https://github.com/python/cpython/blob/3.7/Lib/wave.py#L243

```python
class Wave_read:
    ...
    def readframes(self, nframes):
        ...
        data = self._data_chunk.read(nframes * self._framesize)
        ...
```

そこでさらにChunkクラスのソースコードを見に行くと、readメスッドの`size`引数がマイナスの値の場合はchunkの最後まで読み込む記載されていますね。
https://github.com/python/cpython/blob/3.7/Lib/chunk.py#L122-L126

```Python
class Chunk:
    ...
    def read(self, size=-1):
        """Read at most size bytes from the chunk.
        If size is omitted or negative, read until the end
        of the chunk.
        """
        ... 
```

実際のところ、実用上はのWave_read の`framesize`がマイナスになることはないので、`readframes(-1)`で全部読み込めたみたいです。ここまでくればもはや蛇足ですが、`-1`という値に特別な意味はなく、マイナスの値であればいいです。ただ、どうも値のチェックが甘い気がしますし、たぶん何もテストされてないと思われます。

## 結論

鼻から悪魔・・・とまでは言いませんが、データを読み込めるからといってハックするような使い方はあまりよろしくないようです。適切にフレーム数を指定して読み込むようにしましょう。
【学習メモ】Microsoftのライセンスまわりの略語をまとめる

PTやSPURを読んでいると略語がわからず何を言っているのかわからないことがあるのでまとめました。

英単語の読みをそのままカタカナ表記しているものは、日本語訳に「→」を付けています。
また日本語訳でプレフィックスとして「マイクロソフト」がつく場合でも、下記表記ではマイクロソフトを除いています。
読み方はMicrosoftの中の人が発音していた内容を記載しています。

# A-Z

|略語|読み方|日本語訳|全文|備考|
|:--:|:--:|:--:|:--:|:--|
|CAL|キャル|→|Client Access License|SAL/MLと比較される|
|DA||→|Date Available|日/年で書かれている|
|EA||→|Enterprise Agreement||
|EA/EAS||エンタープライズ加入契約/エンタープライズサブスクリプション貫入契約|Enterprise Agreement / Enterprise Ageement Subscription||
|ECL||→|External Connector License||
|EES||教育機関向け総合契約|Enrollment for Education Solutions|
|L||→|Licsnse|Open/SelectライセンスなどSA付き無しと区別するために製品条項に表記される|
|L/SA|||License/Software Assurance|
|LTSB|||Long Term Service Branch|
|ML||管理ライセンス|Management License|CALと比較される|
|MPN|→|→|Microsoft Partner Network||
|MSPA||マイクロソフト製品/サービス契約|Microsoft Products and Services Agreement||
|MSRC|||Microsoft Security Response Center||
|OL|→|→|Open License||
|PT|→|製品条項|Product Terms||
|PMC|→|→|Partner Membership Center|2019年ごろからMPNに移行する|
|S/S+||→|Select / Select Plus|
|SA|エスエー|→|Sofrware AssuranceまたはSchool Agreement|
|SCE||サーバー及びクラウド加入(契約)|Server and Cloud Enrollment|
|SL||→|Select License||
|OLS||→|Online Service|サブスクリプションが付く場合はOLSサブスクリプションと表記される|
|OSP||→|Online Subscription Program||
|OST||オンラインサービス条項|Online Service Terms||
|OV/OVS||→|Open Value / Open Value Subscription|
|OVS-ES||教育機関向け総合契約|Open Value Subscription -Education Solutions||
|SAL|サル|→|Subscriber Access License|SPLA製品のCAL|
|SPLA|スプラ|→|Services Provider License Agreement ||
|SPUR|エスプア|サービスプロバイダー製品使用権説明書|Service Providor Use Rights|SPLAの製品条項のようなもの|
|ULS||オンラインサービスユーザーサブスクリプションライセンス|Uer Subscription License|オンライン|
|VLSC|→|→|Volume Licensing Service Center|

# まだわかっていないもの

|略語|出てくる場所|
|:--:|:--:|
|-|-|
PDGでImageMagickを使う

# はじめに

PDGの中にImageMagickのノードが用意されているが、ImageMagickがインストールされていないマシンだと使えない問題が発生したので、使うまでの方法をいくつかまとめる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/9a395ded-65ff-18c3-406a-769a09428b37.png)

環境
> Windows 10
> Houdini 17.5.277
> Pilot PDG 17.5.277

# ImageMagickのインストール

[ImageMagickの公式サイト](https://www.imagemagick.org)から、インストーラーをダウンロードしてきてインストールする。
Windowsのインストーラーは種類が豊富に用意されているが、Descriptionが「Win64 dynamic at 16 bits-per-pixel component」になってるデフォルトのやつでいい。

Linuxなら、`sudo apt-get -y install imagemagick`。

# ImageMagick TOPで使えるようにする

### インストーラーによる環境変数

デフォルトインストールしている時点では、このパスが環境変数に登録されるので、そのまま動く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/f2d1d38a-cab9-3f94-5aa3-2d11f814f1ab.png)

### PDG_IMAGEMAGICK

`PDG_IMAGEMAGICK`という環境変数にImageMagickのインストールされているパスをセットして、Houdiniを起動する。

### パラメーターでの指定

この部分にImageMagickのインストールパスを記載することでも利用可能。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/0ab7a03c-d83d-73a4-039a-966e93e7cb05.png)
gRPCは、環境変数 http_proxy、https_proxyがセットされていると "Connect Failed" のエラーになる


python で呼ぶ時、クライアント側で

```
    channel = grpc.insecure_channel('localhost:50051')
    stub = hoge_pb2_grpc.AVRGatewayStub(channel)
    response = stub.Reply(hoge_pb2.ReplyRequest(message='hoge'))
```

みたいに呼ぶと、

```
  File "grpc_client.py", line 10, in run
    response = stub.Reply(hoge_pb2.ReplyRequest(message='hoge'))
  File "/Users/xxxxxx/anaconda/lib/python2.7/site-packages/grpc/_channel.py", line 562, in __call__
    return _end_unary_response_blocking(state, call, False, None)
  File "/Users/xxxxxx/anaconda/lib/python2.7/site-packages/grpc/_channel.py", line 466, in _end_unary_response_blocking
    raise _Rendezvous(state, None, None, deadline)
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
	status = StatusCode.UNAVAILABLE
	details = "Connect Failed"
	debug_error_string = "{"created":"@1555458254.922345000","description":"Failed to create subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":2715,"referenced_errors":[{"created":"@1555458254.922342000","description":"failed to connect to all addresses","file":"src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc","file_line":456,"referenced_errors":[{"created":"@1555458254.922322000","description":"Connect Failed","file":"src/core/ext/filters/client_channel/subchannel.cc","file_line":963,"grpc_status":14,"referenced_errors":[{"created":"@1555458254.922221000","description":"HTTP proxy returned response code 403","file":"src/core/ext/filters/client_channel/http_connect_handshaker.cc","file_line":220}]}]}]}"
>
```

みたいなエラーになる。これは、http_proxyとhttps_proxyが設定されている時にlocalhostに接続しに行くとこうなるみたいで、

```
% unset http_proxy
% unset https_proxy
```

としてから実行するとエラーにならない。

python の中で対応するには、

```
import os
```

してから、

```
os.environ.pop('http_proxy', None)
os.environ.pop('https_proxy', None)
```

とすると良い。

gRPCのバージョンは、

```
$ pip list | grep grpc
grpc                               0.3.post19
grpcio                             1.20.0
grpcio-tools                       1.20.0
```

gRPCのサンプルコードは、

https://qiita.com/shwld/items/c890a4681697ec84cd8c

を使ってます。

＃ ググると結構出てくるので、知っている人は知っている、という感じかな？正確には、「localhostに接続する時はエラーになる」という事なので、本当に分散環境でやる時はちゃんと考えないといけない。
RubyでAdWords APIを実行するときはadwords_api.ymlに注意

RubyでさくっとAdWords APIをたたいてみようかと思ったら、思わぬところではまったので、共有します。

大まかなRubyでAdWords APIを利用するまでの手順はこんな感じです。

1. gemの`google-adwords-api`をインストールする
2. 設定ファイルの`adwords_api.yml`を用意する
3. サービス等の処理が書いてあるrbファイルを実行する


この中で2.の`adwords_api.yml`を用意する際に注意が必要です。

[公式のリファレンス](https://developers.google.com/adwords/api/docs/guides/first-api-call?hl=ja#get_an_oauth2_refresh_token_and_configure_your_client)の中で`adwords_api.yml`のサンプルはこのようになっています。(必要な部分のみ抜粋)

```yml

[...]
:oauth2_client_id: xxxxxxxxxx.apps.googleusercontent.com
:oauth2_client_secret: zZxxxxxTxxxxxxxxxxx
:refresh_token: 1/dyOIp7ki-xxxxxxxxxxxxxxxxxxxxxxxx
:developer_token: 123axxxxxxxxxxxxxxxxxx
[...]
```

しかし、この通りに設定してもうまく動きません。
実際に動く形はこう。

```yml

:authentication:
  :oauth2_client_id: xxxxxxxxxx.apps.googleusercontent.com
  :oauth2_client_secret: zZxxxxxTxxxxxxxxxxx
  :oauth2_token:
    :refresh_token: 1/dyOIp7ki-xxxxxxxxxxxxxxxxxxxxxxxx
  :developer_token: 123axxxxxxxxxxxxxxxxxx
```

`refresh_token`は`oauth2_token`の下の階層が正しいです。
ちなみに、`expires_at`も`oauth2_token`の下になります。


## おまけ

`adwords_api.yml`は`$HOME`をデフォルトで探しに行きますが、API実行時に動的にパスを指定することもできます。

```rb:同じ階層にある場合
require "adwords_api"

config_filename = File.join(Dir.getwd, "adwords_api.yml")
adwords = AdwordsApi::Api.new(config_filename)

managed_customer_srv = adwords.service(:ManagedCustomerService, :v201809)
```

## 参考

詳しい手順や情報はこちらの記事を参照。

[最初の API 呼び出しを実行する | AdWords API | Google Developers](https://developers.google.com/adwords/api/docs/guides/first-api-call?hl=ja)
[Home · googleads/google-api-ads-ruby Wiki](https://github.com/googleads/google-api-ads-ruby/wiki)
[AdWords APIをRubyで一通り試してみる](https://qiita.com/selmertsx/items/fd3da84ca35b666836be)
Microsoft Flowで、[ユーザーがぽちっとしたらメール通知＋位置情報送信＋Power BIでレポート]する、を作ってみる　後編

[前編](https://qiita.com/hisssa0102/items/060cfc8a2fc0b3f1fa27)ではユーザーがボタンをぽっちとしたら、エクセルファイルに記録する処理まで作成した。後編では、PowerBIレポートに出してみる。

レポートでは、「地図上にプロット」「ユーザー別で絞りたい」「日付でフィルターしたい」「ある程度の期間で動きを見たい」を実現したい。

#  記録しているエクセルファイルを、データソースとして指定する

PowerBIを開いて、[マイ ワークスペース]→[作成]→[データソース]と進めると、以下のような画面になる。今回はエクセルファイルなので、ファイルの[取得]をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/bcbb4feb-ea5c-d5aa-ecaf-9da9a5fa5560.png)

エクセルファイルの保存先を選んで、ファイルを指定したら、[接続]をクリック。以下の画面になったら、今回は、インポートでOK。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/9bbb3445-82b4-dcd8-493c-124302f91e64.png)

少し待てば、先ほどの[データソース]に追加される。ここまで来たら、あと半分。

# データソースをもとに、レポートを作成する1(地図を置く）

[マイ ワークスペース]→[作成]→[レポート]と進めると、データソースを聞いてくる。先ほど作成したデータソースを選択して、[作成]をタップすると、全く白紙のレポートが表示される。

地図にプロットしたいから、まずはレポートに地図を置く。[ArcGIS MAP for Power BI]のアイコンをドラッグする。サイズはあとからでも変更できるので適当なサイズに拡大。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/f8ee3a50-40a7-4e1f-ad0f-789cd27fbcb2.png)

「視覚化」の各項目に、フィールドの項目を置いていく。ドラッグすればOK。

位置情報を置くと、地図に表示される。ちょっとうれしい。
緯度と経度は、ドラッグしたままだと平均になっているので、[集計しない]に変える。
色は、ユーザー。あとから見るときわかりやすいので。
時間は、日付で。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/f719a492-8811-912f-ae16-c12909759d27.png)


これだけで位置情報の動きをアニメーションさせたり、位置情報も拾えるようになっている。


# データソースをもとに、レポートを作成する2～スライダーを置く～

この2つやっておくと、使い勝手が良い。

ユーザー別で絞りたいので、「スライダー」を置く。キャンバスにスライダーをドラッグして、大きさを適当に変えて、フィールドにはDisplayNameをドラッグ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/d93c4fb1-e925-4a5f-3556-9e296fecd978.png)


期間で絞りたいので、また「スライダー」を置く。キャンバスにスライダーをドラッグして、大きさを適当に変えて、フィールドにはYYYYMMDDをドラッグ。
日付スライダーは地図の中にもあるんだけど、あとから「任意の期間で、動きを追いたい」時に選択しやすいので、置くのがおススメ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/915609e1-5fab-757c-9e87-80c9d365db58.png)


あとはいい感じにリサイズして、名前を付けて保存。
ここまできたら、レポートは作成完了。

# 使ってみましょう

Flowの実行ユーザーにユーザーを追加して、使ってもらう。


# まとめ

今回は位置情報はスマホでぽちってするだけ、としてる。IoTセンサーで自動車や自転車の位置情報を取って使う、ってことも同じようにできる。
これぐらいのレポートなら、ユーザー部門でも簡単にできるのでお試しあれ。
SSRの時間計測方法(Nextjs)

Nextjsはlibの中にrenderToStringが入っていて純粋にrenderToStringのみの計測ができなそうなので、以下のような感じで妥協するしかなさそう。

```js
const serverTiming = require('server-timing')

const ssrTiming = async ({ req, res, pagePath, queryParams }) => {
  res.startTime('ssr', 'SSR')
  const html = await app.renderToHTML(req, res, pagePath, queryParams)
  res.endTime('ssr')
  res.send(html)
}

app.prepare()
  .then(() => {
    const server = express()
    server.use(serverTiming())

    // SSRの時間を計測したいパス
    server.get('/', (req, res) => {
      return ssrTiming({ req, res, pagePath: '/' }))
    }

    server.get('*', (req, res) => {
      return handle(req, res)
    })

    server.listen(port, (err) => {
      if (err) throw err
      console.log('> Ready on http://localhost:' + port)
    })
  })
  .catch((ex) => {
    console.error(ex.stack)
    process.exit(1)
  })
```
Docker でキーバインドControl + pが2回押さないと反応しない件

##概要
Dockerにattach(Dockerに入るイメージ)し、コンソールで使うキーバインドControl+pを押すと1度目は反応せず、2度目で入力されたと見なされる。
Docker導入時、設定変更せずに使っていると起きるのだが...
原因としてはdettach keyというDockerにattachした後にdetach(Dockerから出るイメージ)するキーのデフォルト設定でControl+p Control+qが割り当てられているからであった。

##環境
Docker version 18.09.2, build 6247962

##対応策
Dockerの設定ファイルでdetachキーを変更すればよい。
私の場合、以下の場所に設定ファイルがあるので、このファイルに"detachKeys"という設定を追加する。

```linux:~/.docker/config.json
{
    "detachKeys": "ctrl-\\"
}
```

ちなみに`ctrl-\\`としましたが、キーバインドに設定されていないキーであればなんでもよいです。
`ctrl-^`でもよいので使いやすいように変更できます。

参考↓
[Docker コンテナの中で、Ctrl-p を二回押さないと使えない](https://qiita.com/YutakakINJO/items/eeb579f75feb50fa18ae)

[docker で Ctrl-p ２回押し問題 (detach-keys の問題) を解決するには](https://qiita.com/Yuki-Inoue/items/60ec916383025160fbb8#_reference-a2d9244a6c4496f4df05)



補足
macOS High Sierra 10.14.3
液晶の表示を高速化

[ili9325のパラレルインターフェース液晶](https://qiita.com/yamori813/items/8a721d8d5d7864088fb4)の表示を高速化してみました。

当初mruby-bsdgpioで1ビット単位でアクセスしていたのですが、これでは効率が悪すぎます。

pcduinoで使われているallwinner A10のデーターシートを見たところgpioはport単位でのアクセスになるようです。

またarm/allwinner/aw_gpio.cを見てみたところ32ビット単位でのアクセスがサポートされていました。

基板で作り直したときにデーターバスを同じポートにまとめて一回でアクセスできるようにしてみました。

新しいmrbgemsを作るのも面倒なので、mruby-bsdgpioを継承したクラスにメソッドを追加する事にしました。

![mrbgems.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/e5c87194-88a9-cfd5-cc7e-36805418a352.png)

https://github.com/yamori813/mruby-bsdgpio

https://github.com/yamori813/mruby-gpiotft

特に必要ないのでinitializeは用意してません。DATA_PTRも親のデータをそのまま使います。高速化のためにwriteregとsetlineというメソッドを用意しました。

GPIOのポートはPHとPIなので、これをまとめて処理しています。

信号線を整理したときにWRはデータバスと同じポートにしていました。たまたまなんですが、このおかげで一回のioctlでストローブできます。書き込みの方が多いので、良いと思います。

x(0x0020),y(0x0021)はpixelを送るとインクリメントされるようなので、一度だけ送るようにしました。またpixelのレジスタアドレス(0x0022)を1度送った後は、連続してpixelデータを送るようにしました。

![スクリーンショット（2019-04-17 8.46.49）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/13b9ae4c-a68e-152a-bd3b-9454c97d2dbd.png)

これで当初表示に70秒くらいかかっていたのが1秒まで短縮できました。

```ruby
def lcdCopy(g, c)
  arr = Array.new
  for i in 1..320 do
    rgba = c.getpix(0, i - 1, 240)
    g.setline(0,320 - i, 240, rgba)
  end
end

g = GpioTft.new(0)
lcdInit(g)
lcdReset(g)
lcdSetWriteDir(g)
lcdSetup(g)

c = Cairo.new(240, 320)
c.set_source_rgb(1 , 0, 0)
c.move_to(0, 0)
c.line_to(100, 100)
c.stroke()

lcdCopy(g, c)
```

この液晶はデフォルトでは左下が0,0で初期化のパラメータで変更できるようなのですが、分からなかったので、コピーするときに左上が0,0になるようにしてます。

ちなみにこの32ビットアクセスのioctlのGPIOACCESS32はおもいっきりバグっていました。

https://svnweb.freebsd.org/base/head/sys/dev/gpio/gpioc.c?revision=326255&view=markup#l195

第四引数が間違えてます。誰も使ってないのかもしれませんね。^ ^;

32ビット単位でのまとめての処理はaccessとconfigがあって、後から追加されたようです。まだlibgpioではラップされてません。

A10は中華パッドによく使われたSOCです。これらは内蔵のLCDコントローラーを使っているので高速な描画が可能ですが、GPIOにつながったLCDコントローラーではこんなところが限界かもしれません。


追記

cairoで変更のあったところだけをコピーするように、mruby-cairoにstroke_extentsというメソッドを用意してみました。strokeメソッドを呼ばれた以降にlineなどの変更領域が拾えます。

```ruby
def lcdCopyExtents(g, c, rect)
  arr = Array.new
  x1 = rect[0].floor
  y1 = rect[1].floor
  x2 = rect[2].ceil
  y2 = rect[3].ceil
  for i in y1..y2 do
    rgba = c.getpix(x1, i - 1, x2 - x1)
    g.setline(x1, i, x2 - x1, rgba)
  end
end

c.move_to(100,0)
c.line_to(100, 100)
rect = c.stroke_extents()
c.stroke()
lcdCopyExtents(g, c, rect)

sleep 2

c.move_to(0, 100)
c.line_to(100, 100)
rect = c.stroke_extents()
c.stroke()
lcdCopyExtents(g, c, rect)
```

SPIインターフェースのLCDの高速化のためにフレームデータのmrubyでの処理をなくしてみたのですが、同じようにポインター渡しにしてみました。しかし見えるほどの効果はなかったです。A10はpowerがあるのでmrubyでのオーバーヘッドが小さいのかもしれません。

初期化ルーチンをmruby-gpiotftのmrbgemのrubyコードに移してローカルの変数を追加するためにCコードにinitializeを入れました。

mruby-gpiotftのrubyコードとCコードにポートがハードコードされています。ポートのどこに接続されているかで32ビットアクセスが変わってくるので汎用化する良い方法が思いつきません。

mrbgemのrubyコードが動かなくてちょっとはまったのですが、rubyコードにも依存関係を書いておく必要がありました。
Spring(Spring Boot)でFormに入力された全角スペースや半角スペース、TAB等の不可視文字を一律Nullに変換して入力チェックに引っかける

Formに入力された値が全て全角スペース、全て半角スペース、全てTAB、等の不可視文字のみで構成されていた場合、それらの項目は入力チェックエラーとしたいという仕様に対する対応方法の紹介です。入力チェックをJSR-303 Bean Validationのアノテーションで行っている場合「[@NotBlank、@NotEmpty、@NotNullの挙動の違いをSpring Boot + Thymeleafで整理する](https://qiita.com/NagaokaKenichi/items/67a63c91a7db8717fc7d)」でも書いた通り、全角スペースの取り扱いが難しくなってきます（チェックエラーにならないため）。

### 対応方針
ControllerAdvice + InitBainderの組み合わせで共通処理として対応します。
※ControllerAdvice、InitBainder等の詳細はkazuki43zooさんの「[Spring MVC(+Spring Boot)上でのリクエスト共通処理の実装方法を理解する](https://qiita.com/kazuki43zoo/items/757b557c05f548c6c5db#controlleradvice)」がとても分かりやすいです。

### 実装サンプル
※「[@NotBlank、@NotEmpty、@NotNullの挙動の違いをSpring Boot + Thymeleafで整理する](https://qiita.com/NagaokaKenichi/items/67a63c91a7db8717fc7d)」で作成した簡易画面に肉付けする形で実装してみます。

Apache CommonsのStringUtilsを利用するためcommons-lang3への依存を追加します（バージョンはよしなに）。

```pom.xml
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-lang3</artifactId>
</dependency>
```

次にjava.beans.PropertyEditorSupportをextendsしてCustomeEditorを作成します（ここでApache CommonsのStringUtilsを利用します）。基本的にgetAsTextとsetAsTextをオーバーライドするだけでOKです。重要なのはsetAsTextで、このメソッドの引数としてFormに入力された値が渡ってくるので、それを解析し然るべき加工をしてsetValueメソッドに渡します。

```CustomeStringTrimmerEditor.java
package com.example.demo.support;

import java.beans.PropertyEditorSupport;

import org.apache.commons.lang3.StringUtils;

public class CustomeStringTrimmerEditor extends PropertyEditorSupport {

	private final boolean emptyAsNull;

	public CustomeStringTrimmerEditor(boolean emptyAsNull) {
        this.emptyAsNull = emptyAsNull;
    }

	@Override
	public String getAsText() {
		Object value = this.getValue();
		return value != null ? value.toString() : "";
	}

	@Override
	public void setAsText(String text) {
		if (text == null) {
			this.setValue((Object) null);
		} else {
			String value = StringUtils.strip(text);

			if (this.emptyAsNull && "".equals(value)) {
				this.setValue((Object) null);
			} else {
				this.setValue(value);
			}
		}
	}
}
```

最後にAdviceクラスを作成します。InitBinder#registerCustomEditorには上記で作成したCustomeEditorを指定します。

```HelloAdvice.java
package com.example.demo.support;

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;

@ControllerAdvice
public class HelloAdvice {

	@InitBinder
	public void initBinder(WebDataBinder binder) {
		binder.registerCustomEditor(String.class, new CustomeStringTrimmerEditor(true));
	}
}
```

なお、一連の大まかな処理フローは、「[（２）@RequestMappingメソッドの処理の流れ](https://sites.google.com/site/soracane/home/springnitsuite/spring-mvc/04-ji-ben-gai-nian-controllerno-chu-lifuro#TOC-RequestMapping-)」が分かりやすいです。

### Formクラスの入力フィールドに付与するアノテーション

正直@NotBlank、@NotEmpty、@NotNullどれでも引っかかるのでどれでもいいのですが、強いていうなら@NotNullが適切なのかなぁと思います。

ソースは以下です。
https://github.com/kenichi-nagaoka/spring-boot-form-validation-sample

以上です。

### 参考
https://howtodoinjava.com/spring-boot/custom-property-editor-example/
https://www.baeldung.com/spring-mvc-custom-property-editor
Hyper-VでVHDXをVHDに変換する

オンプレHyper-V環境のディスクイメージをクラウドに移行する際に，VHD形式である必要があったが，最近のHyper-VではVHDX形式でディスクイメージが保存されているため，これを変換する方法についてまとめた．

# VHDXをVHDへ書き出す
1. 書き出しする仮想マシンを停止する
2. 仮想マシンを選択して「ディスクの編集」を選択する
<img width="1106" alt="スクリーンショット 2019-04-17 6.40.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310137/7a92b96e-b767-0776-ff80-df23e2831f71.png">

3. 仮想ハードディスクの編集ウィザード
 - ディスクの場所／変換元のVHDXを選択する
 - 操作の選択／変換を選択する
<img width="697" alt="スクリーンショット 2019-04-17 6.41.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310137/cdd55557-9133-9d74-bd9d-3bcbdfdc160c.png">

 - 操作の選択／ディスクフォーマットの選択／VHDを選択を選択する
 <img width="699" alt="スクリーンショット 2019-04-17 6.42.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310137/c31aa78b-08ec-4885-413c-be42ed517e38.png">

 - 操作の選択／ディスクの種類の選択／容量可変を選択する
 <img width="695" alt="スクリーンショット 2019-04-17 6.42.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310137/6f226d55-fc87-9923-b940-73b921f618bc.png">

 - 操作の選択／ディスクの構成／書き出しパスを選択する

# 備考
書き出すイメージサイズのHDD容量よりも多めに空き容量を確保しておく必要がありそう
Pythonで必要なターミナルコマンドとPIPインストール、ver確認方法

# 【ターミナルコマンド】


1. ls = ファイルの表示
2. pwd = 現在いる場所を表示
3. cd [path] = 指定先のディレクトリに移動
4. mkdir [dir] = ディレクトリを作成する
5. mv [file] [dir] = ファイルを移動させる
6. mv [file] [new file] = ファイル名を変更する
7. cp = ファイルをコピーする 
8. rm = ファイルを削除
9. Ctl + L = 画面をクリアする
10. Ctl + D = ターミナル終了

参照元
https://qiita.com/kenju/items/77a2dc1b6a60697b1133

## Python　対話型コマンド

### 対話型
python3

### 対話型から脱出
exit()

### python version確認
python3 --version




参照元
https://www.sejuku.net/blog/50417
ディレクトリ間違えてrake db:drop db:create db:migrateした時のメモ

`rails s` して ローカル表示しようとしたらこんなのがでた

```error:error
ActiveRecord::NoEnvironmentInSchemaError:

Environment data not found in the schema. To resolve this issue, 
run:bin/rails db:environment:set RAILS_ENV=development
```

が、`rails db:environment:set RAILS_ENV=development`すると


```
== 20190328182436 ChangeContextToContent: migrating ===========================
-- add_column(:posts, :content, :text)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
```
その下の方を見ていくと
`SQLite3::SQLException: duplicate column name: content: ALTER TABLE "posts" ADD "content" text`

postsテーブルにcontentカラムが存在している？
同じ定義が複数あるのではないかということらしい。

####migrationファイルを見直して、なんか丸々一ついらないmigrationファイルがあったので削除、なんで。。

違う箇所にも同じような `Caused by:
SQLite3::SQLException: duplicate column name: content` というのが出ていたし、よ〜く読んで考えるようにしよ。。
Cannot find module '~/components/Card.vue'. Vetur

Nuxt 2.6.2 プロジェクトをTypeScriptに変更してアプリケーションはうまく動いているのに、VSCodeでVuterのエラーが消えない。

<pre>
Cannot find module '~/components/Card.vue'. Vetur(2073) [38, 18]
</pre>

もはやお手上げと諦めていたところで、

> ワークスペースでプロジェクトのフォルダを追加していたのですが、
これをファイル -> 開くでプロジェクトのフォルダを直接開いたらエラーが出なくなりました。

@rema424 さん、@peisan さんありがとうございました。

[memo]
VS Code バージョン1.33.1 (1.33.1)
Vetur 0.18.1
今更Electron環境構築めも

# 今更Electron
マルチプラットフォームなら使える！と思って勉強する。

## 前提
nodeJsインストール済。

## インストール

```bash
mkdir electron-test && cd $_
npm init -y

# --save-dev オプションが何を意味するかわからんけど、これじゃないとダメ
#npm install electron-prebuilt --save-dev ← 1.4.13
npm install -D electron@latest --save-dev ← 5.0.0(最新)
または（yarn導入してたら）
yarn add -D electron@latest --save-dev ← 5.0.0(最新)

# 実行はこれ。よくわかんないけど
./node_modules/electron/cli.js

・リンク張っておく
ln -s ./node_modules/electron/cli.js electron

※electron v5.0.0でなんかバグ？
---
FATAL:setuid_sandbox_host.cc(157)] The SUID sandbox helper binary was found, but is not configured correctly. Rather than run without sandboxing I'm aborting now.
---
ってでる。

sudo chown root node_modules/electron/dist/chrome-sandbox
sudo chmod 4755 node_modules/electron/dist/chrome-sandbox
ってやるといい。
```

```bash:electron-packagerインストール
### install electron-packager.
sudo npm i electron-packager -g

## なんかwin32なアプリの為には、wine32が必要らしい.
https://github.com/electron-userland/electron-packager/issues/654

## ↓の通りにwineをbuild & installする (かなり時間かかるよ)
https://ameblo.jp/kousakusya/entry-12333298836.html
```

```bash:asar実行
# asar pack {アプリケーションディレクトリ} {出力ファイル名}.asar
asar pack ./sample ./sample.asar
```

```bash:electron-packager実行
### make package.
electron-packager ./sample sample --platform=win32 --arch=x64 --electronVersion=5.0.0 --asar.unpack **/img/** --asar

・区分値
platform (all, linux, win32, darwin)
arch (all, ia32, x64)
electronVersion (Electron version)
```

```bash:NSIS
Windowsインストーラとして、NSISを使う。
面倒だからWindows側にいれて、そこからインストーラ作成。
https://sourceforge.net/projects/nsis/files/NSIS%203/3.04/nsis-3.04-setup.exe/download?use_mirror=jaist&download=
から
nsis-3.04-setup.exe
をgetしてインストール。
あとは、適当に"hoge.nsi"みたいなの作って
右クリックコンパイル。
細かい設定は割愛。
```

## 結論
まだわからんけど、Windows用バイナリはwine頼りってことはわかった。
electron-packagerがx64を非サポートで、wine32は、ソースからビルドするしかなく、buildで異様に時間がかかる。

後、自分の環境（CentOS7.6 + GNome）だと、ウィンドウの透明化はできなかった。
Windowsなら簡単にできた。

※未解決事項
・Windowsバイナリのアイコン指定ができない！

```
# なんでかわからないけど
rcedit.exe failed with exit code 1. Reserved header is not 0 or image type is not icon for 'i'
Fatal error: Unable to set icon
# がでて、electron-packagerのbuildに失敗する。
# electron-builderはよくわからないけどエラーがでる為、両方諦めた。
```
GAE/python3.7でbottle.pyする

いつの間にかGoogleAppEngineのStandardでpython3が使えるようになっていたので、bottle.pyしてみました。
チュートリアルはflask使ったりしてました。が、bottle好きなので。


python3については 以前からflexible環境なら使えてたらしーのだけれど、flexibleにするなら他のPaaSでいいしな、と久しく触ってなかったGAE。
py3使えるならそりゃ飛び付きますよ。鯖のお守りとかしたくないし。


導入の雑なステップとしては以下の通り

- SDKをインストール(本記事では割愛)
- app.yamlを書く
- requirements.txtを書く
- main.pyを書く


app.yaml
----

```yaml
runtime: python37
```

これだけでOK。
ずいぶんスッキリしている。

bottle.pyらしくだと、お好みでstatic以下のhandlerも追加してもいいかも。
handler指定がないのはmain.pyのappに勝手にルーティングされてくれるらしいのでそこは書いてないです。

```yaml
handlers:
- url: /(.*\.(css|png|jpg|gif|ico|js))$
  static_files: static/\1
  upload: static/.*\.(css|png|jpg|gif|ico|js)$
```



requirements.txt
---

pipのPodfile的なファイルらしい。
これに書いとくとdeploy時にpipでインストールしてくれるらしい。

```
Bottle==0.12.16
```

main.py
---

```py
from bottle import Bottle

app = Bottle()

@app.route('/')
def top():
	return "Hello, world!"

if __name__ == '__main__':
	app.run(host='localhost', port=8080,reloader=True,debug=True)

```

で、`gcloud deploy`すると、なんか動くみたい。

すごい楽チンだ。。。素晴らしい。。。

もちろん。`python3 ./main.py`でlocalhost:8080で動きます。

し、さらにこのあとFirestore試してたら認証周り勝手に設定してくれて、一切の苦労なしにローカルからリモートのDB覗けてる。すごい時代や。。。

その他
---
- ドキュメントが整備というか整理というかされてないけど[python-docs-samples](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/standard_python37)を眺めて、雰囲気で書いてたら無事になんか動くっぽい。
- `.gcloudignore`に正規表現を書いとくとdeploy対象外に指定できる（.gitignoreみたいに）


virtualenvしない
---

チュートリアルに`virtualenv`入れろとか書いてあるけど必須じゃないし、面倒いので
`pip3 install -r requirements.txt -t ./lib/`で適当なフォルダに突っ込んで、`main.py`の先頭でローカル実行ならソコ参照するように入れてみた。ちゃんと動く。
適当なフォルダを`.gcloudignore`へ追加するも忘れずに。

```py
if __name__ == '__main__': # add local lib path
	import sys,os
	sys.path.append(os.path.join(os.path.dirname(__file__), 'lib'))
```
Githubの芝を短いコードでAAにする


# コード

```javascript
for(r=w='';w--+7;r+='\n')$$('.day').map((v,i)=>i%7-~w?0:r+='口圏国因囚'[-~v.attributes[5].value[5]>>1]);r
```

# 実行

- Chromeで任意のGithubアカウントのページを開き、Consoleで上記コードを実行するとAAが得られます
    - サンプルに使用したのは、芝で絵を描くツール([skazhy/github-decorator](https://github.com/skazhy/github-decorator))のテストアカウント

<img width="901" alt="スクリーンショット 2019-04-17 2.48.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81176/db3a06c7-ea12-93a4-97a6-b3a2549960cb.png">

# 解説

最初はdata-count属性(contribute数)で判別していましたが、場合によって閾値が変わるようだったので没に。
fill属性(色)の5桁目が都合良くバラけていたのでそれを利用しています。

|色(v.attributes[5].value)|-~v.attributes[5].value[5]>>1|字|
|---|---|---|
|#ebedf0|0|口|
|#c6e48b|4|囚|
|#7bc96f|3|因|
|#239a3b|2|国|
|#196127|1|圏|

# 終わりに

JSゴルフは不慣れなので、短縮できたら教えて頂けると嬉しいです。
AWS ECRのライフサイクルポリシーとタグ付けの戦略

## ECRのライフサイクルポリシー

- 古いイメージがたまると、ストレージ料金が余計にかかる
- ECRリポジトリ1つにつき、イメージは1000まで

こういった問題に対して、ライフサイクルポリシーを適切に設定することで、自動で古いイメージを削除することができます。

[Amazon ECRのライフサイクルポリシーでコンテナイメージのクリーンアップ](https://aws.amazon.com/jp/blogs/news/clean-up-your-container-images-with-amazon-ecr-lifecycle-policies/)


## タグ付けルールとライフサイクルポリシー

実際のプロジェクトで、ライフサイクルポリシーがうまく機能するように、どのようにタグ付けのルールを工夫したか紹介します。
これは、私が携わっているプロジェクトの運用に応じたものなので、あくまで参考です。

### 前提

タグ付け以前に、次のような前提がありました。

- Github への Push をトリガーに CI が実行され、 docker image のビルドと Push が行われる
- 開発者は、任意の git branch (からビルドされたimage) を ECS にデプロイしたい

### どのようにタグ付けするか

また、次のような事情があります。

- 現在、ECS Service にデプロイされている image が消えてしまうと困る
    - Task が作り直された際に image が見つからなくて実行できない
- 開発者がデプロイしたいのは、ほとんどの場合、git branch の head に対応する image
    - branch の head より古い image は長く保持しておく必要がない
    - しばらく commit がない branch についても、ほとんどデプロイされることはない

そこで、次の3パターンのタグをつけることにしました。

- `git-hash.*`
- `git-branch.*`
- `deploy.*`

それぞれのタグについて、説明します。

CI で docker image をビルドしたら、そのときの git の hash に従って、 `git-hash.*` のタグを付けます。(例えば、 `git-hash.8db0a1` のようになります)
また、それと同時に、branch 名に従って `git-branch.*` のタグを付けます。
ただし、git の branch には、スラッシュ`/` など、 docker のタグとして使用できない記号が含まれる場合があります。なので、branch 名を SHA などで適当にハッシュ化してその先頭の数文字をとります。 (例えば、 `git-branch.7e5170` のようになります)

`deploy.*` タグは、実際にデプロイされたときに、後からつけます。デプロイ先の環境名をふくめて、例えば `deploy.production` のようにします。

### ライフサイクルポリシーの設定

それぞれのタグに、次のように expire を設定します。

1. `deploy.*` => 十分に長い期間(半永久的)
2. `git-branch.*` => 数週間・数ヶ月程度
3. `git-hash.*` => 数日程度

上に記載したタグほど、**優先度を高く** します。
そうすることで、`deploy.*` がついたイメージは消えず、 `git-hash.*` だけついた image はすぐに消えるようになります。

### 設定例

具体的な設定例を残しておきます。

```json:policy.json
{
  "rules": [
    {
      "rulePriority": 10,
      "description": "Keep images with the tag deploy.* forever",
      "selection": {
        "tagStatus": "tagged",
        "tagPrefixList": [
          "deploy."
        ],
        "countType": "sinceImagePushed",
        "countUnit": "days",
        "countNumber": 36500
      },
      "action": {
        "type": "expire"
      }
    },
    {
      "rulePriority": 20,
      "description": "Keep images with the tag git-branch.* for 14 days",
      "selection": {
        "tagStatus": "tagged",
        "tagPrefixList": [
          "git-branch."
        ],
        "countType": "sinceImagePushed",
        "countUnit": "days",
        "countNumber": 14
      },
      "action": {
        "type": "expire"
      }
    },
    {
      "rulePriority": 30,
      "description": "Keep images with the tag git-hash.* for 3 days",
      "selection": {
        "tagStatus": "tagged",
        "tagPrefixList": [
          "git-hash."
        ],
        "countType": "sinceImagePushed",
        "countUnit": "days",
        "countNumber": 3
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}
```

```shell
aws ecr put-lifecycle-policy --repository-name $repo --lifecycle-policy-text "$(cat policy.json)"
```
[Laravel]保存した画像が404エラーで表示されない

## 問題
画像を取得して表示させようとしたときに、データを取得してくることまではできたのですが、表示すると404エラーがでてきて、パスは間違っていないのに、表示できませんでした。


***開発環境***
PHP  :7.2.15
Laravel  :5.6

画像の取得、表示については公式リファレンスや[他の記事](https://qiita.com/u-dai/items/8a904cc7fd2795c0e70d)等で書いてあることを参考にしていたのですが、大まかには以下の流れです。
![無題 3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236873/5b320d0d-469a-0541-62d1-61dff8b4ce82.jpeg)


## 解決方法
画像自体のパスは間違っていなかったので、「Public」のシンボリックリンクのパスを調べたところ下のように「storage -> /Users/[ユーザ名]/laravel/application/storage/app/public」となっていました。

```console
root@qw2b32a12s7e:/var/www/public# ls -la
total 32
drwxr-xr-x 13 root     root      416 Apr 10 03:56 .
drwxr-xr-x 27 root     root      864 Apr 10 02:56 ..
drwxr-xr-x  3 root     root       96 Apr  1 08:07 css
-rw-r--r--  1 root     root     6148 Apr 10 07:53 .DS_Store
-rw-r--r--  1 root     root        0 Apr  1 08:07 favicon.ico
-rw-r--r--  1 root     root      593 Apr  1 08:07 .htaccess
-rw-r--r--  1 laradock www-data 1823 Apr  1 08:07 index.php
drwxr-xr-x  3 laradock laradock   96 Apr  1 08:07 js
-rw-r--r--  1 root     root       70 Apr  1 08:07 mix-manifest.json
-rw-r--r--  1 root     root       24 Apr  1 08:07 robots.txt
lrwxr-xr-x  1 root     root       56 Apr 10 03:56 storage -> /Users/[ユーザ名]/laravel/application/storage/app/public
-rw-r--r--  1 root     root      914 Apr  1 08:07 web.config

```

Storageのシンボリックリンクを変更します。↓

```console
root@qw2b32a12s7e:/var/www/public# ln -nfs /var/www/storage/app/public storage
```

↑のコマンドを入力するとStorageのパスが「storage -> /var/www/storage/app/public/」に変更され、画像が表示されました。

```console
root@qw2b32a12s7e:/var/www/public# ll
total 32
drwxr-xr-x 13 root     root      416 Apr 10 08:20 ./
drwxr-xr-x 27 root     root      864 Apr 10 02:56 ../
-rw-r--r--  1 root     root       11 Apr  9 08:41 aaa.html
drwxr-xr-x  3 root     root       96 Apr  1 08:07 css/
-rw-r--r--  1 root     root     6148 Apr 10 07:53 .DS_Store
-rw-r--r--  1 root     root        0 Apr  1 08:07 favicon.ico
-rw-r--r--  1 root     root      593 Apr  1 08:07 .htaccess
-rw-r--r--  1 laradock www-data 1823 Apr  1 08:07 index.php
drwxr-xr-x  3 laradock laradock   96 Apr  1 08:07 js/
-rw-r--r--  1 root     root       70 Apr  1 08:07 mix-manifest.json
-rw-r--r--  1 root     root       24 Apr  1 08:07 robots.txt
lrwxrwxrwx  1 root     root       27 Apr 10 08:20 storage -> /var/www/storage/app/public/
-rw-r--r--  1 root     root      914 Apr  1 08:07 web.config
```
JIS90で追加の2文字とSJIS外字のPostgreSQLでの取り扱い

## JIS90で追加の2文字

PostgreSQLが、JIS90で追加の2文字「凜(SJISではEAA3)」「熙(SJISではEAA4)」のSJISをUTF-8に変換できるか確認する。

- 1. テーブルhogeにSJISの「凜」と「熙」を格納する。

```sql
CREATE TABLE hoge (x TEXT);
SET client_encoding TO sjis;
\copy hoge from program 'echo "EAA3" | xxd -r -p'
\copy hoge from program 'echo "EAA4" | xxd -r -p'
```

- 2. UTF-8変換された2文字とそれらのコードを確認する。

```
SET client_encoding TO utf8;
SELECT x, to_hex(ascii(x)) FROM hoge;
```

- 3. 確認結果は以下となった。

```
 x  | to_hex 
----+--------
 凜 | 51dc
 熙 | 7199
(2 rows)
```

以上より、PostgreSQLは、JIS90で追加の2文字「凜(SJISではEAA3)」「熙(SJISではEAA4)」のSJISを、「凜(U+51DC)」「熙(U+7199)」のUTF-8に変換する。

## SJIS外字

PostgreSQLが、SJISのユーザ定義外字(F040〜F9FC)を格納できるか確認する。

- 1. テーブルhogeにSJIS外字(例えばF040)を格納する。

```sql
CREATE TABLE hoge (x TEXT);
SET client_encoding TO sjis;
\copy hoge from program 'echo "F040" | xxd -r -p'
```

- 2. 以下のエラーが発生してSJIS外字の格納に失敗する。

```
2018-12-06 02:28:45 JST ERROR:  invalid byte sequence for encoding "UTF8": 0xf0 0x40   
   ```
【Git】打倒 conflict

##git conflictに向けて事前に準備しよう

gitの同じブランチ上で複数人が同じ箇所を同時に編集してしまいcommitした際に起きるconflict
ちなみにgitに慣れてないと自分自身でconflictを起こす場合もあります

ちなみにボクは全然やってました

初心者だとconflictが起きると３時間とか5時間とか平気でかかっちゃうので早めに対策だけでも控えとくといいかもしれないですね

ちなみにボクは1回のconflictで5時間以上平気でかかってましたwww

開発現場でやると本当に笑えないですはいw


##conflictが起きたら次の順番で解決していきます

▼直前のcommitの打ち消し

```
$ git reset -- soft HEAD^
```

▼addの打ち消し

```
$ git reset ファイル名
```

▼自分の書いたコードを異次元に保存

```
$ git stash save
```

▼最終的にpushしたいコードを保存したので、branchを強制的に切り替える

```
$ git checkout -f master   //branch => master
```

▼pullする

```
$ git pull origin master  //master
```

▼さっきのbranchに戻る

```
$ git checkout branch     //master => branch
```

▼最新masterのコードをbranchにrebase

```
$ git rebase master
```

▼保存しておいたコードを反映させる

```
$ git stash pop
```

▼add

```
$ git add -u         //変更ファイルのみadd
```

▼commit

```
$ git commit -m "任意のコメント"
```

▼push

```
$ git push origin ブランチ名
```


###最後に


webエンジニアだとconflictは避けては通れない道です
はじめのうちはどれだけconflictを起こさないか
ではなくいかにconflictに強くなるかを意識して勉強、または開発する事をおすすめします

ファイト！！！
homebrewのインストールからMecabをpython3で利用できるようにするまで

#はじめに
研究で利用するためインストールしました。
色々ありましたがひと段落したので、まとめます。
OS:macOS Mojave ver10.14.4


##Homebrewのインストールとチェック
ぶっちゃけると公式サイトを見た方が早いと思う。
変わっている可能性があります。(2019年4月16日時点)
[Homebrew公式サイト](https://brew.sh/index_ja)

---
では簡単に説明を。

```console:terminal
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
これをターミナルにコピペすればインストール終了。ちょっと時間かかる人もいるかも。

インストールが終了したら必ず

```console:terminal
$ brew doctor
```

このコマンドを実行して問題なくインストールできるのか確認しましょう。
何か問題があったら警告が出るので表記に従って対応します。
私の場合は出なかったので多分大丈夫だと思います。

続いてmecabとpythonをインストールしていきます。

##Python3のインストール
Python3のインストールをしていきます。
これもやり方は簡単です。

```console:tarminal
$ brew install python
```
これでPython3がインストールされました。
バージョンの確認方法は

```console:tarminal
$ python3 --version
```
です。一応確認しておきましょう。

##mecabのインストール
続いてmecabのインストールです。
###mecabと辞書をインストール
同じようにターミナルを使ってインストールしていきます。

```console:terminal
$ brew install mecab mecab-ipadic
```
これでインストールは完了です。

```console:terminal
$ mecab
```
このコマンドでコンソール上でmecabを利用することができます。

```console:terminal
吾輩は猫である。名前はまだない。
吾輩	名詞,代名詞,一般,*,*,*,吾輩,ワガハイ,ワガハイ
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
猫	名詞,一般,*,*,*,*,猫,ネコ,ネコ
で	助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ
ある	助動詞,*,*,*,五段・ラ行アル,基本形,ある,アル,アル
。	記号,句点,*,*,*,*,。,。,。
名前	名詞,一般,*,*,*,*,名前,ナマエ,ナマエ
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
まだ	副詞,助詞類接続,*,*,*,*,まだ,マダ,マダ
ない	形容詞,自立,*,*,形容詞・アウオ段,基本形,ない,ナイ,ナイ
。	記号,句点,*,*,*,*,。,。,。
EOS
```
こんな感じ。
終了はControl＋Cです。
これをpython上で利用できるようにしておしまいです。

##mecabをpythonで利用できるようにする

###mecab-python3をインストールする

```console:terminal
$ brew install swig
$ pip install mecab-python3
```
これでインストールは終了です。
お疲れ様でした。

---
2019/04/17現在、mecab-python3の最新ver : mecab-python3 0.996.1で、
[node.surface() does not work as intended in version 0.996.1](https://github.com/SamuraiT/mecab-python3/issues/19)
というエラーが発生しています。
ユーザー側が対応できるレベルではないということなので、バージョンを下げる必要がありそうです。
バージョンを下げるには、

```console:terminal
$ pip3 uninstall mecab-python3
$ pip3 install mecab-python3==0.7
```
これでバージョンを下げることが可能です。

##参考
https://qiita.com/taroc/items/b9afd914432da08dafc8
https://teratail.com/questions/164787
Jenkinsのインストール

Jenkinsインストールの備忘メモ

## Jenkinsのインストール、起動

#### macOS

- Jenkinsのインストール

```
$ brew install jenkins
```

- Jenkinsの起動

```
$ brew services start jenkins
```

#### Windows

- Jenkinsのインストール
推奨されているWindowsインストーラーを使う。
Windows版のインストーラーは[公式サイト](https://jenkins.io/)上部メニューの[Download]をクリック、[LTS]か[Weekly]のWindowsを選択してダウンロードする。
![jenkins-download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241942/1f9b06ae-7304-d30d-9d96-122db4e27ccb.png)

`jenkins.msi`ファイルをダブルクリックしインストールする。
![install.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241942/4cbe8f96-6ac1-4857-1ab1-a1cd7f70d043.jpeg)



※ インストーラーではなく、コマンドラインのパッケージ管理ツール「[Chocolatey](https://chocolatey.org/)」を使ってインストール／アップデートしたい場合は、[ChocolateyのJenkinsパッケージ](https://chocolatey.org/packages/jenkins)を使えばよい。


#### Linux 
- Java 8のインストール

```
$ sudo yum -y install java-1.8.0-openjdk-devel
```

次のようにコマンドを打って、インストールしたJavaのバージョンが表示されればよい。

```
$ java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)
```

- yumへのJenkinsリポジトリの追加

```
$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
$ sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
```

- Jenkinsのインストール

```
$ sudo yum install jenkins
```

- Jenkinsの起動

```
$ sudo service jenkins start
```

## Jenkinsのセットアップ
トップヘージにアクセスする。
初回起動時は管理者パスワードの入力を求められる。
赤字のパスのファイル内に記載されているパスワードを入力する。
![setup_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241942/3fdc61fa-82c0-2c2b-c429-3cd45ce5be0d.png)

Jenkinsを拡張・カスタマイズするプラグインをインストールするためのページが表示される。推奨プラグインをインストールするか、自身で選択してインストールするかを選択する。
各種プラグインのインストールが完了するまで数分かかる。
![setup_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241942/7a10258a-3f6f-5144-af17-ccd384649ea6.png)


Adminユーザの作成を行う。必要な情報を入力する。
![setup_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241942/deb71747-037e-5342-9c2b-7888efd63376.png)


その後、画面の指示に従っていけば、ダッシュボード画面が表示される。
![setup_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241942/95209082-1f50-bdce-d7ac-82316773d9d1.png)

---

続き：[BlueOseanでGitHubとJenkinsの連携](https://qiita.com/yuuulf/items/cee10af0412c12bd9a28)
【学習アウトプット3】has_secure_passwordとvalidates :password, presence: trueの違い

# 背景
has_secure_passwordを設定したUserモデル

```erb:user.rb
class User < ApplicationRecord
  has_secure_password
```

が、以下のテスト

```erb:user_controller_test.rb
test "password should be exist when create" do
  @user.password = " "
  assert_not @user.valid?
end
```


で引っかかってしまう問題に悩んでいました。
（has_secure_passwordは空白にvalidationがかかると思っていたため https://qiita.com/Shantti-Y/items/19ea23b81f3421063fc5)

validates :password, presence: trueをつけるとテストをパスします。
じゃあ、has_secure_passwordのデフォルトvalidationとは一体...:rolling_eyes:



# 結論
Rails 4.2から以下のように変更されていたとのことです。

 *has_secure_password がデフォルトで空白のパスワードを許容するようになりました (例: 空白スペースのみのパスワード)。* https://railsguides.jp/4_2_release_notes.html

空白を許可したくない場合は別途`validates :password, presence: true`等の追加が必要みたいです。