OmniAICreator/Qiita-1.07M huggingface dataset:
Androidアプリでよく使うletとapplyについてざっくり✏️

Androidアプリでよく使うletとapplyについてざっくり✏️。

Try Kotlinとかにコピペして実行すれば試せます。

```kotlin
fun sample() {
    /* apply */
    /*
     * イメージ：applyは自分自身に何かを適用する
     * 戻り値は自分自身を返す
     * Androidだと「BundleとかNotificatinのbuildなど、値をセットする」ときに使用することが多い印象
     **/
    val user = User("piyoyama", "hoge").apply {
        println("applyで変更前のファーストネームは、" + this.first + "です")// コンストラクタで定義したファーストネームを確認
        // 結果： applyで変更前のファーストネームは、hogeです
        
        // ここではUserのfirstを"hoge"から"piyota"に変更してみる
        // this.は省略できる
        this.first = "piyota"
    }
    println("applyで変更後のファーストネームは、" + user.first + "です") // applyで書き換えられているか確認
    // 結果： applyで変更後のファーストネームは、piyotaです
    println(user::class.java) // applyの戻り値の型を確認
    // 結果： class User


    /* let */
    /**
     * イメージ：letは自分自身に何かさせたい
     * 戻り値は、任意の型
     * Androidだと「activityとかのnullチェックと併用して、nullじゃなかったら何かする」ときに使用することが多い印象
     **/
    val sampleLet = user.let {
        // ここではitにtoUpperCase()させてみる
        println("ファーストネームを大文字で表記すると、" + it.first.toUpperCase() + "です") // letでuserの名前を大文字にして表示できるか確認
        // 結果： ファーストネームを大文字で表記すると、PIYOTAです
    }
    println(sampleLet::class.java) // letの戻り値の型を確認
    // 結果： class kotlin.Unit
}

class User(var last:String, var first:String) 

```

他のスコープ関数についてはまたいつか


## もっとじっくり読みたい人は
[Kotlinのapplyをじっくりと読む](https://qiita.com/oomasa/items/8cca88a586feab248d16)
hamlで動的にclass名/idを設定する

#hamlで動的にclass名を設定する

これでclassが設定できる

```
{class: status}
```

class名やidに対して動的に番号を振りたい場合は下記のようにできる。

```
.modal-content{id: "delete-modal#{ticket.id}"}
```

#参考記事
https://code-examples.net/ja/q/21d66f
JavaでPDFファイルをOCR処理してみた part2

#始めに
[JavaでPDFファイルをOCR処理してみた](https://qiita.com/triple4649/items/9f2839144c68df11cc41)の続編です。
主に、tess4j 4.1について書いています

#この記事の目的
tess4j 4.1に関してググってもあまり情報が出てこないので、動かし方と動かした結果を書いてみます
ネット上の情報のだけだと、実行時エラーでるので

#修正箇所
[JavaでPDFファイルをOCR処理してみた](https://qiita.com/triple4649/items/9f2839144c68df11cc41)から変更した個所を記載します。
## gradleファイル
```
compile group: 'net.sourceforge.tess4j', name: 'tess4j', version: '4.1.1'
```
な感じでモジュールの依存を記載します
## tessdata/configs/api_config
```
textord_tabfind_vertical_horizontal_mix T
```
を追記します。この記載がないと実行時エラーが発生します
## jpn.traineddata
[GitHub](https://github.com/tesseract-ocr/langdata/tree/master/jpn)からダウンロードした学習用データで上書きします

#実行
Gradleからrunコマンドで実行するだけです

#実行結果
##処理速度
Win10pro iCore5 2.2GH メモリ16Gで3系と4系の実行結果を「平成 28年 度 春 期　情報処理安全確保支援士試験　午後2」の変換処理で比較してみました
4系　約2分半
3系　約8分 
4系のほうが圧倒的に早いです

##文字認識
3系は日本語と英字が混じっていたら誤変換率が無茶苦茶高かったのですが、4系はこれが劇的に改善されていました
例えば、3系で

```
問ー 膿S の特徴はどれか。
ア 鐘長によつて, 段数が決まる。
```
と変換されていた箇所が4系で

```
問 ① AES の 特 徴 は ど れ か 。
ア 鍵 長 に よ っ て , 段 数 が 決 ま る 。
```
と意味のある文字にきちんと変換されるようになっています
PowerBIのDAX関数をつかってVLOOKUP的な機能をつける方法

# PowerBIでVLOOKUP的なことをしよう！
PowerBIでVLOOKUP的なことをしようとしたんですが、VLOOKUP関数は実装されていないので困ってしまいました。PowerBIの使い方として、そもそももしかしたらPowerBI上でVLOOKUP的なことをするんじゃなく、そういうのはExcelなんかでデータ整形しろって話かもしれませんが、他のソフトではきだしてきたCSVとかExcelやPythonなんかでいじることなくそのまま入れたいじゃないですか。面倒だし。
ということで、無理やりVLOOKUP的なことをしてみようというのが今回の趣旨です。

## 前提
テーブル（rawdata）には、date列（日付）、category列（カテゴリ）、center列（センター）、time列（時刻）、item列（商品名）が含まれているものとします。date列は「8月1日」、category列は「オススメ飲食物」、center列は「山形」、time列は「11:00」、item列は「玉こんにゃくゴルゴンゾーラ」みたいな。

時刻ごとに入っている元データから、「オススメ飲食物」だけ抽出して、一日ごとでまとめて（Visualizeではなくテーブルとして）表（Day)にしたいとしましょう。

## 条件で検索した結果が一つのみの場合

その日、そのセンターでの「オススメ飲食物」は必ず一種類と決まっている場合について。

この場合はLOOKUPVALUE関数を使います。
```
 LOOKUPVALUE( <result_columnName>, <search_columnName>, <search_value>[, <search_columnName>, <search_value>]…)
```
まずはDayテーブルの商品名以外の部分をそろえるとします。
この辺の作り方は、[【PowerBI】存在しない欠損データにダミーデータを入れる](https://qiita.com/ogaki_takahiro/items/80b3773464902a378086)を参考にしてみてください。

商品名以外の部分が準備できたら、「モデリング」から「列の追加」をしてitem列をつくっていきます。

```
= LOOKUPVALUE(rawdata[item], Day[date], rawdata[date], Day[category], 'オススメ飲食物', Day[center], rawdata[center])
```
みたいな感じ。ちなみに、このすべての条件に一致するものがなければ空白が返されます。ただし、この検索条件に当てはまるものがいくつかある場合にはErrorとなってしまいます。そんな時には以下を使いましょう。

## 条件で検索した結果が複数存在する場合

その日、そのセンターでの「オススメ飲食物」は基本的に一種類だけど、たまに2種類以上出している時があるという場合。そして、それはあくまでも例外的なものであって厳密に商品名で分けなくてよいものの、Error値ではなく何らかの商品名で出してほしい場合。
あんまりないかな？

この場合はCALCULATE関数とFIRSTNONBLANK関数、FILTER関数を使えばうまくいきます。
こんな感じです。

```
item = CALCULATE(FIRSTNONBLANK(rawdata[item],1),
          FILTER(ALL(rawdata[date]),rawdata[date]=Day[date]),
          FILTER(ALL(rawdata[center]),rawdata[center]=Day[center]),
          FILTER(ALL(rawdata[category]),rawdata[category]='オススメ飲食物'))

```

原理は簡単。
CALCULATEとALL、FILTERをつかって、元の列から条件に適合するデータを抜き出していきます。そして、その中からFIRSTNONBLANK関数で空白でないデータを取り出してやっています。どちらかといえばこっちのほうがVLOOKUP関数には近いですね。ただ、先に書いたように検索結果が複数あるのに一つだけ無理やり出すのもどうかと思いますし、あくまでもなんちゃってということで。
厳密に出したい場合はアプローチがまったく変わってきます。

以上になります！
word2vecをtensorflow servingに載せた話

## 想定読者
コンテナへのモデルの転送が必要なせいでビルドに時間がかかるし, モデルの入れ替えにデプロイが必要だし大変だ, という方.
この記事はそうした方向けです.

## まずは成果物
作ったものは [github](https://github.com/Yasu-umi/word2vec-tf-model) にあります.
tf1.9で動作確認しましたが, 使ってる機能も多くないので多少古くても動くかと.

## なにをしたのか
`tf.contrib.lookup.HashTable`と`tf.nn.embedding_lookup`を使ってword2vecをtensorflowに持たせるようにしました.

## なぜそんなことをするのか
[tensorflow serving](https://www.tensorflow.org/serving/) にword2vecを持たせたかったからです.
tf-servingとはtensorflowのモデルを良い塩梅にversioningとかしつつ, TensorProtoでのリクエストを受けて推論を実行して結果を返してくれる便利なやつです.詳しくはリンク先参照.

## なぜ一回idを経由してvecを取るのか
`id -> word`の変換が必要だったからです.
`word->vec`しか必要ない場合`SimpleWord2VecTfModel`というのもあるのでそちらをどうぞ.

## 所感
`HashTable`の存在を知らなかったせいでserving自体に手を入れかけていたのですが, 既存機能だけでさらっとできて良かった.
servingには最近REST APIも生えたのでブラウザから直接呼び出しもできて便利です.もっと流行って情報が増えて欲しいところ.
自然言語処理パイプラインを全部servingに面倒見て欲しいという気持ちがあり, `mecab`の辞書でも同じことがやりたいのですがc++は全然わからないし, servingは大きくて手を入れるのがつらい…
どなたか[これ](https://www.tensorflow.org/serving/custom_servable)読んで一緒に作りませんか.
TDD/BDDでないプロジェクトでの成功体験、ついてくるのはインタフェースだった

## **はじめに**

### **この記事でのインターフェースとは**

ここでいうインターフェースはインターフェースクラスではなく、何かと何かの境界という意味合いで書いています。
例えば外部API仕様、もしくはチーム間の役割分界点とか。

### **古臭い開発スタイルしか経験のない自分**

私はかれこれ10年くらいシステム開発に携わってきましたが、実際Qiitaの記事で見かけるようなTDDやBDDといった開発プロセスでの開発は正直行ったことがありません。
(テストコードは書きますけど、テストファーストはありません。TDDやBDDといった開発プロセスの記事にいいねをするたび心が痛む。)
しかも長いこと続く成熟したプロジェクトではなく未成熟のプロジェクトが大半。

そんなプロジェクトばかりでしたがいつも酷い品質のものが出来ているかというとそうでもなく、ちゃんとうまくいっているプロジェクト/チームも結構ありました。

### **自分の成功体験のキーワードは「インターフェース」**

そんな過去の成功・失敗体験を思い返してみると、出てくるキーワードが「インターフェース」でした。
いいプロジェクト/チームは大体どの面でも「インターフェース」がしっかりしてるんですよね。

ごく当たり前のことをつらつら書いてるだけかと思いますが、これくらいの意識でもなんとかなるところもあるんだなくらいに思っていただけるとありがたいです。

ちなみに自分は１メンバー～PL(～5人くらい)まで経験してます。

## **システムとしてのインターフェース**

ここではモジュール間とかの外部インターフェイスと捉えてください。
品質がいい、流用しやすいいいものづくりが出来ているチームや開発担当者はこんな意識を持っていた気がします。

### **インターフェースの使いやすさを意識して提供している**

例えば同じプロセス間通信を実現しなければいけないケースでも、

「UNIX Socketを使いましょう。メッセージはこんなbyte列で」
という定義の仕方よりも、
「コールバック形式のライブラリを提供する形にしましょう。ライブラリ内でプロセス間メッセージはうまい事やるので。」
という定義の仕方の方がインターフェースとして意識すること(パディングとかバイトオーダーとか諸々)が減るため相互の認識違いが起きにくく、結合がすんなりいきます。
後はメッセージでも既存メッセージ形成フォーマットを使うとか。

とにかくインターフェースを提供する側が、情報を隠ぺいするなりして「出来るだけわかりやすいものにしよう！」
と相手を意識したインターフェース設計をしているものは、品質もよく、流用しやすいものが出来ていました。

### **インターフェースのテストをしっかりしている**

充実したテストコードを書けるのが理想ですね。
色々な事情でそこまでいかなくても、品質のいいものづくりにはちゃんとしたインターフェースへの評価・品質担保があったように思います。

### **インターフェース仕様変更の及ぼす影響を理解している**

当たり前ですよね。でもライブラリAPIを変えるのに事前合意を全体でとらないとか、事後報告でメーリスに流すだけとか。
そんな逆を行くチーム・開発者は結構見かけます。正直自分がやらかしたこともあります。

## **チーム間のインターフェース**

ここではチーム間のやりとりという意味合いで捉えてください。
うまくいっているチームはこんな感じでした。

### **役割分担を互いに意識して作業をしている**

互いが絡む新規要件が出てきたらすぐに連絡取り合って意識合わせ。相手に仕事を押し付けるんじゃなく、
「プロジェクト内の互いの役割だとどれをどっちがやるんだよね」と客観的に意識して作業決め出来るチームは所属が自分でも相手でも仕事がスムーズに進みます。

逆に半分予想で「相手はこうするでしょ。次の打ち合わせで話すよ」と意識も合わせず進めると、大体意識が違ったりしますね。

### **相手に必要な情報が発信される**

ポーリングしなくても情報が出てくるチーム。なんて素晴らしいんだろう。
結構な確率で、「こちらから話を聞きにいかないと、こちらに関わる情報なのに出てこない！」ってチームはありました。

### **情報過多にならない**

とにかく情報発信！じゃなくて影響のあるチームをきちんと取捨選択して情報を発信する。
これが出来るチームはその時関係のない他チームのノイズにならないのでいいですよね。情報抜けがあると本末転倒なので難しいですが。

私は迷ったらとにかく発信するタイプなので、ノイズになってたりすることもあるんだろうな。

### **険悪な雰囲気じゃない**

やり取りしやすい雰囲気って大事ですよね。

## **管理層とのインターフェース**

ここではPMさんと各チーム、もしくはプロジェクト間の関係と捉えてください。

### **トラブル時に適切な旗振り役がいる**

例えば新規仕様が出てきた時に、旗振り役が出てこないもしくは複数出てくると話が全然前へ進まないです。
ここでPMさんとチームとの関係がしっかりしているところは、ちゃんと旗振り役が出来て話が進む気がします。

自分が率先して旗を振るPMさんもいれば、各チームへの意識づけをしっかりして自然とその時々の旗振り役が出てくるプロジェクト作りをしている人もいました。

### **状況に合わせて適切にリスケされる**

チーム状況をよく見ているのか、ヒアリングしているのか、もしくはちゃんとアラートを拾い上げているのか、
気付いたら「今ここがやばいよね」と危機を察知してリスケしてくれるPMさん、とてもやりやすかったです。

逆にアラート出し続けてもなんやかんや言いながら結局頑張れしか言わないとか、徹夜休出のパワープレーで潰されるなんてのは最悪ですね。

### **険悪な雰囲気じゃない**

やり取りしやすい(ry

## **最後に**

外部仕様という意味でも人との関わりという意味でも、もちろんクラスとしての意味でも、システム開発でインターフェースは重要な意味を持つと思います。
そんな当たり前に重要なものをちゃんと扱い、実践していれば、古臭いスタイルでもしっかりとしたものが作れるんじゃないかなと思いました。

じゃあお前はどうなのよと言われると、うまくできたことも、明らかに失敗したことも沢山あります。
意識しているつもりでもつい手を抜いてしまったり、見落としがあったり。
そういう時って大体問題が表面化して、「あ～、あの時手抜きしなければ」ってなるんですけどね。

TDDやBDDみたいな開発手法を導入していれば、自然とこういったことを補えるのかもしれませんし面白そうですが、自分が実践できそうのはインターフェースハイプライオリティな開発くらいかなと思い、つらつらポエムを書いてみました。
pyenv installすると_ctypes云々でエラー in archlinux

# ある日

会社のarch linux環境でpyenvを入れたら `pyenv install 3.7.1` でコケるようになってしまった
ぐぐっても情報なかったので参考になれば幸いです

## 結論

```shell-session
$ sudo pacman -S libffi
$ LDFLAGS="-L/usr/lib" CFLAGS="-I/usr/lib/libffi-3.2.1/include -O2" pyenv install 3.7.1
Downloading Python-3.7.1.tar.xz...
-> https://www.python.org/ftp/python/3.7.1/Python-3.7.1.tar.xz
Installing Python-3.7.1...
Installed Python-3.7.1 to /home/kc5m/.pyenv/versions/3.7.1
```

## 過程

```shell-session
$ pyenv install 3.7.1
...
ModuleNotFoundError: No module named '_ctypes'
...
```

上記のようなエラーが出て早速ぐぐると以下の記事が。
https://qiita.com/hitochan777/items/941d4422c53978b275f8
なるほどlibffiを入れれば良いのだなと `# pacman -S libffi` をしてみたものの同じエラーで止まる。3.6.5でも同様だ。

どうせいつものncurses5互換ライブラリの問題だろと入れてみたものの変わらず
とりあえずlibffiパッケージに含まれているファイルを確認してみる

```shell-session
$ pacman -Fl libffi
libffi usr/
libffi usr/lib/
libffi usr/lib/libffi-3.2.1/
libffi usr/lib/libffi-3.2.1/include/
libffi usr/lib/libffi-3.2.1/include/ffi.h
libffi usr/lib/libffi-3.2.1/include/ffitarget.h
libffi usr/lib/libffi.so
libffi usr/lib/libffi.so.6
libffi usr/lib/libffi.so.6.0.4
libffi usr/lib/pkgconfig/
...
```

ここでヘッダファイルが変な位置(`/usr/include`に配置されると思ってた)にあると気がつく
とりあえず試してみる

```sh
$ LDFLAGS="-L/usr/lib" CFLAGS="-I/usr/lib/libffi-3.2.1/include -O2" pyenv install 3.7.1
Downloading Python-3.7.1.tar.xz...
-> https://www.python.org/ftp/python/3.7.1/Python-3.7.1.tar.xz
Installing Python-3.7.1...
Installed Python-3.7.1 to /home/kc5m/.pyenv/versions/3.7.1
```

通った。
めでたしめでたし

### 余談

自宅環境の幾つかのarchlinuxでは上記エラーが再現しなかった。
しかもそれら環境にはlibffiが入っていない。
:thinking:
Google Play Console 段階的公開

アプリ開発者として不具合が起きないように心がけるのは当たり前のことですが、
どんなにドッグフーディングやβテストをしていても、いざ公開してから不具合が発覚することもありますよね。

不具合を修正してリリースする時に慌ててリリース手順を調べたりしなくて済むように、
Androidアプリの段階リリースについて有り得そうなケースを✏️。

あくまでもこんな感じで使えそうという程度です。



:warning: 注意 :warning: 
具体的なリリース方法などを保証するものではないので、詳細は[Play Consoleのヘルプ](https://support.google.com/googleplay/android-developer)とか、実際に問い合わせるなどをしてください。
何かトラブルがあっても責任は取れませんので、このドキュメントのリリース方法を参考にされる場合は自己責任でお願いします。
（間違いの指摘などあれば、是非ご指摘いただければ幸いです！）


# 段階リリース
ユーザーに公開するapkの範囲を指定できる。

例えばこんな感じのケースがありそう
 1. 10%公開
 2. 不具合がないことを確認。10%→50%に上げる
 3. 50%公開
 4. 不具合がないことを確認。50%→100%に上げる
 5. 100%公開🎉


# 段階リリース後不具合発覚 → 修正 → 再アップロード
段階リリースの途中で不具合が発覚したときは、
そのバージョンをリリースを中止して不具合を解消、その後新しいバージョンとして段階リリースを再開させられる。

再度リリースしたときは完全に公開が完了する前であれば、前のバージョンのユーザーグループに公開される模様（[ココ](https://support.google.com/googleplay/android-developer/answer/6346149)を参考にした）。よくできている :smile: 

例えばこんな感じのケースがありそう
 1. バージョン0.0.1を10%公開
 2. バージョン0.0.1で🚨不具合を発見🚨
 3. バージョン0.0.1の段階リリースを中止
 4. バージョン0.0.1の不具合を修正して、バージョン0.0.2としてapkを作り直す
 5. バージョン0.0.2として新たに10%公開（バージョン0.0.1で選ばれた10%に公開されるらしい）
 6. バージョン0.0.2の不具合が解消されたことを確認
 7. 50%公開
 8. 不具合がないことを確認。50%→100%に上げる
 9. 100%リリース

# まとめ
Google Play Consoleの段階的公開とても便利　:pray:
uwsgi-nginx-flask-dockerでFlaskを楽々Docker運用

# はじめに

Flaskは開発用簡易サーバー機能があって開発時は楽なんですが、運用するとなると Nginx(or Apache) + uWSGI で動作する環境を用意する必要があって面倒です。

Nginx + uWSGI で Flask を動作させるDocker環境が、まさしく [uwsgi-nginx-flask-docker](https://github.com/tiangolo/uwsgi-nginx-flask-docker) という名前で公開されていたので使ってみました。

ディレクトリ構成の違いやタイムゾーンの設定など、サンプルと異なる部分もあるので備忘録として記事に残しておくことにします。

# ディレクトリ構成

１つのコンテナで動作するので、プロジェクトルートに Dockerfile と docker-compose.yml を置くことにしました。

```
.
├── Dockerfile
├── README.md
├── docker-compose.yml
├── myapp/
├── requirements.txt
├── run.py
└── uwsgi.ini
```

# docker-compose.yml

まずは docker-compose.yml から。
プロセスごとにコンテナを用意するという Docker のベストプラクティス的には、Nginx のコンテナと uWSGI のコンテナは分けるべきなのかもしれませんが、uwsgi-nginx-flask-docker は１つのコンテナで両方を動作させます。

```yaml
version: "2"

services:
  web:
    build: ./
    ports:
      - "80:80"
    volumes:
      - .:/app
    environment:
      - FLASK_APP=run.py
      - 'RUN=flask run --host=0.0.0.0 --port=80'
```

web と run.py はお好きな名前に変更して構いません。

# Dockerfile

次に Dockerfile です。
ベースとなるイメージに Alpine ベースのものを利用し、タイムゾーンを Asia/Tokyo に設定しています。

```dockerfile
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7

ENV STATIC_PATH /app/myapp/static

RUN apk --update add tzdata && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    apk del tzdata && \
    rm -rf /var/cache/apk/*
COPY ./requirements.txt /app
RUN pip install -r requirements.txt
```

RUN の最初４行はタイムゾーンの変更です。
その後にプロジェクトの requirements.txt に記載されている必要なパッケージをインストールしています。

# run.py

先述した通り、ファイル名は好きな名前で構いません。

```python
from myapp import app

if __name__ == '__main__':
    # 開発中のみ利用
    app.run(host="0.0.0.0", port=8080, debug=True)
```

「開発中のみ利用」と書いてある部分は、開発中は

```bash
python run.py
```

を実行して、デバッグ有効の開発用簡易サーバーを立ち上げて使えるようにするためです。
Docker 環境では利用されません。

自分の場合は myapp/\_\_init\_\_.py に以下のように記述しています。

```python
from flask import Flask

app = Flask(__name__)
app.config.from_object('myapp.config')

# （以下略）
```

# まとめ

uwsgi-nginx-flask-docker を使うことで、本家のサンプルそのままではないものの、かなり楽に Flask の Nginx + uWSGI 環境を Docker で構築することができました。

こうしてメモしておけば次はもっと楽できます。
これを見た人にも参考になれば幸いです。
自分にとってストレスの少ない仕事の見つけ方

# みなさん、楽しく仕事してますか？
私は2月に新卒で入社した仕事を辞め、転職しました。

転職してほぼ半年ほど経過したのですが、ありがたいことに今のところいい感じで仕事をさせてもらっています。
運やタイミングが良かったり、いい人に出会えたのが大きいかなと思っています。

一方で前職や現職で周りの人をみていて、自分に合わない仕事をストレス抱えながらやっている人ってそれなりにいるんじゃないのかなと思いました。

# 楽しく仕事をするにはどうしたらいいのか
## 1. 自分にとって「楽しい仕事」の条件をみつける
そもそも楽しく仕事をするとはどういうことなのでしょうか。これは人によって違うと思います。
仕事に楽しさを求めないのであれば、ストレスの少ない仕事に置き換えても大丈夫です。

私の場合であれば、以下のような環境が重要な指標でした。

* 個人の裁量が大きい環境
   * 自分の思った意見を提案できる（通れば受け入れられる）
   * 仕事のやり方に決まりがなく、自分で決められる
   * 自分のペースで進められる（他の人に邪魔される要因が少ない）
* 理不尽と感じる業務命令が少ない環境
   * お客さんに言われたからとりあえずやって、みたいなのが少ない
   * 責任はとれないけどとりあえずやって、みたいなのが少ない
   * いいからやれ、みたいなのが少ない

要するに私の場合はストレス耐性が低く、思った通りに仕事ができるとやりがいを感じるタイプです。
もちろんこの基準は人によって違います。

逆に私が理不尽と思う業務命令にそこまでストレスを感じない人もいますし、お金やステータス、お客さんからの感謝の言葉などにやりがいを感じる人もいると思います。

## 2. 自分にとって「妥協できる」条件をみつける
とりあえず楽しい仕事だけをあげていくときりがないので、比較的優先順位が低い条件も考えていきましょう。

私の場合であれば、以下の条件は優先順位が低かったです

* 会社の規模・知名度が良いところ。大企業
* 高給（ただし極端に低い場合はNG）

うーん、今思うとあんまり妥協できてないですね。。
しいて言えば、あの有名企業に転職してやったぜ！どやっ的なのは別にいいかなと思ってました。
まぁエージェントさんに人生で一番転職しやすいタイミングって言われたので強気だったのかもしれません。

## 3. 自分にとって「楽しい仕事」をするための行動をとる
自分にとって「楽しい仕事」「ストレスの少ない仕事」がわかったら、行動すべし！です。
要は自分のやりたいことを言ったり、環境改善の提案をして実行したり、自分の求める環境を探して転職すること、などなど。

正直ここが一番難しいんじゃないのかなと思います。
誰しも未来はわからないですし、へたうって損したくないという保守的な気持ちは芽生えるのが普通だからです。

ただ、何も言わない・何も行動しないことは、何も変わらない結果しか待っていないと思います。
（偶然いい組織に部署移動したとか、いい上司に出会えた、くらいはあると思いますが）

転職して思ったのですが、会社が変わると本当に「当たり前」ががらっと変わります。
前職は〇〇が当然でしょ、という感じでも現職では〇〇なんかどうでもいいよ、なんていくらでもあります。もちろん逆もしかり。

なので今の会社の「当たり前」を受け入れて我慢しているのであれば、その必要は全くないです。
違う文化を持つ会社なんでごまんとあります。
前職の人に他の会社も変わんないでしょ、と言う人は多かったのですが、、、本当にそんなことはないです。まぁ新卒入社が多い会社だったのでそう思うのは仕方ないとは思いますが、それにしてもね。。

もちろん前職の方がよかったところもありますが、トータルで見ると転職してより自分に合う環境に移れたと思っています。

会社の文化や制度を変えるのは結構大変ですが、会社を変えるのはそんなに大変じゃないですよ。。

# まとめ
結局転職ごりおしかい！と思うかもしれませんが、人によって合う環境合わない環境は本当に様々だと思います。

それを新卒でたまたま入った会社が自分に合った会社で、定年までつづけられる幸運な人ってかなり少ないと思うんですね。

もっとみんなが「我慢」して「妥協」しないで、楽しく働けるといいのになって思います。
まぁ、これは私が仕事好きだからそう思うのでしょうが。。個人の感想でした。
【仕事メモ】OpenAM(Ver13) データストアの連携とローカル認証の確認（１）

#OpenAMとデータストア(OpenDJ)の連携
前回からの続きなんですが、この作業を実施する前提条件として以下を挙げておきます。
　・OpenAMのインストールが完了していること
　・OpenDJのインストールおよびローカル認証に必要なスキーマ拡張が終了していること

##OpenAMから連携先のデータストアを指定
体裁無視で操作を行った順に記載していきます。

まずはamAdminユーザーにてOpenAMの管理コンソールへログインします。
トップ画面に表示されている「Top Level Realm」を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/68c1b11e-f0c7-0bb6-3a86-899d12056fdd.png)

そして、画面左部のメニューより「REALEMS」‐「Data Stores」を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/81b182f5-06f4-ae45-96c1-eda37010c4ef.png)

データストアの一覧が表示されるのですが、デフォルトで「embeded」の設定が入っているので削除してください。これはOpenAMが内蔵しているOpenDJの設定ですが今回はデータストアを外部連携するので削除します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/b4e4083e-28be-b18f-2669-243913af576f.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/a25f8cfc-15c6-3239-1d73-c0d58fb0fd4b.png)

次に「新規」をクリックします。
新規作成画面が表示されるので、「名前」欄には任意の名前を入力して、「タイプ」に「OpenDJ」を選択して「次へ」をクリックします。

不要なデフォルト値が入っているので削除して、前の記事で作成したOpenDJサーバを指定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/b87cd3c1-dcf5-ef37-a5c5-73a1ee7144d1.png)

次にLDAP接続を行うためのbindユーザー情報を設定します。
bindユーザーはOpenDJ構築時に作成されたDirectory Managerを使います。
何をキーとして属性の取得を行うのかも指定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/9e1980fe-da40-c9ba-f8fc-f4a70199c5fd.png)

参照する組織のDNと接続方式を指定します。
組織はOpenDJ構築時に作成したもの、接続方式は今回はLDAPを使用します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/bd8a7692-45cd-5331-c45f-6d65065e8446.png)

次にLDAP接続のパラメータチューニングですが、ここはデフォルト値のままにします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/54b932aa-2bb7-e229-f8a6-22bd4b931b3d.png)

プラグインの設定もデフォルト値のままとします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/c6f3da99-e925-4f77-925e-7cbef144d448.png)

認証に使用するユーザーの属性値を指定しますがここもデフォルト値のままとします。
※OpenDJ構築時にデフォルト値に対応できるようにデータを作成しています。
　デフォルト値の属性ではcn、dnが指定されています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/fa5a384e-a7cc-8d94-bfdf-26cb2318cebc.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/4baefde7-4861-5672-b340-ab593bc6df9f.png)

認証で使用する属性値を定義します。
今回はデフォルト値のuidで認証を行う構成とします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/446db59b-887c-7080-63ba-3e1eba521dac.png)

グループの設定値も今は関係ないのでデフォルト値のままとします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/445f48a4-f14e-7adb-b0f5-11d202b93366.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/7bc41fe8-c62d-d586-1b90-1ad6a04fcf8c.png)

ユーザー検索を行うベースDNを指定します。デフォルト値は削除して、OpenDJで作成したエントリを指定します。
あとは検索フィルタおよび検索のスコープをサブディレクトリを含めて検索するかなどを指定できます。
エラーハンドリングとキャッシュ制御の設定もデフォルト値とします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/138274/b1851d4b-6a58-4836-176f-b04b5e283808.png)
Ansible—リモートマシンのファイルの中身を読む

## slurp モジュールを使う

- 結果を register でいちど変数に入れる
  - slurpで取れた文字列は base64 decode する必要があるっぽい。
- 次に debug モジュールで表示させる

```in_some_playbook_tasks.yml
...
    - name: slurp file
      slurp:
        path: example.txt
      register: slurp_file

    - name: echo file body
      debug:
        msg: "{{ slurp_file.content | b64decode }}"
```

[slurp - Slurps a file from remote nodes — Ansible Documentation](https://docs.ansible.com/ansible/2.6/modules/slurp_module.html)

## shell モジュールを使う

素直にcatしてして標準出力を見る方法

```in_some_playbook_tasks.yml
...
    - name: cat file
      shell: cat example.txt
      register: cat_file

    - name: echo file body
      debug:
        msg: "{{ cat_file.stdout }}"
```

## lookup は？

こちらはリモートマシンではなく、手元 ( Control Machine ) のファイルを見る方法のようだ。

[file - read file contents — Ansible Documentation](https://docs.ansible.com/ansible/2.6/plugins/lookup/file.html)

## 環境

- ansible 2.6.1

## Gist

- [Ansible—slurp module](https://gist.github.com/YumaInaura/3902607dddac246ca15395b5aedcc2fb#file-slurp-yml)








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
moodle3.5をlolipopサーバにインストール

### 本家から最新版のmoodleをダウンロード


### tar.gzファイルをwebサーバのディレクトリに配置


### tar.gzを解凍する
tar.php をcronで動かす
```<?php
    system("tar -xzvf ./moodle-latest-35.tgz");
?>
```

### cronの結果を受信するメールアドレスを設定
    必須では無い


### データディレクトリ作成
    moodledata
    mod:705
    own:[デフォルト]


### サブドメイン設定


### WAF設定、海外アタックガード
    自動で有効になったか確認


### 独自SSL（無料）設定
    少し時間がかかる


### moodle web install
    sslでインストールURLにアクセス
    https://moodle.URL/

1. 言語設定 = ja
2. パスを確認する（自動で表示されている）
    * URL
    * Moodleディレクトリ
    * データディレクトリ
3. データベースドライバを選択する `Inproved MySQL(ネイティブ/mysqli) `
4. データベース設定
    ` サーバの管理・設定＞データベースから参照`
    * データベースホスト：(lolipopの設定ページから)
    * データベース名：(lolipopの設定ページから)
    * データベースユーザ：(lolipopの設定ページから)
    * データベースパスワード：(lolipopの設定ページから)
    * テーブル接頭辞：mdl_
    * データベースポート：3307
    * Unixソケット：/var/lib/mysql3307/mysql.sock
5. 著作権表示
6. サーバチェック
    * opcache.enable_cli：offからonへ設定変更
7. その他のチェック
    * site not https は無視
    * mysql_full_unicode_support は無視
8. インストレーション（全て成功）
9. インストレーション（管理者アカウント作成）
    * 管理者パスワードが入力出来ない。→pwのinput要素のvalueをインスペクタで無理やり記載して進めた。
10. インストレーション（新しい設定 - フロントページ設定）


### WAFの設定
    以下の２ファイルがブラウザからは403エラーとなって、管理メニューのプルタウンなどが操作出来なかった。

```
[ドメイン]/theme/yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js
[ドメイン]/theme/yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.css
```
    WAFのログに出ていたので除外設定
    https://lolipop.jp/support/faq/cgi/000681/

```
touch .htaccess
chmod 604 ./.htaccess
vi ./.htaccess
--
SiteGuard_User_ExcludeSig [*WAFのログで確認した許可したいシグネチャ*]
--
```

### moodeleのcron設定

スケジュール：5分毎
ファイルパス：/home/users/2/[ドメイン]/web/moodle/admin/cli/cron.php



###
haproxyでのhttpsリダイレクト設定

備忘録的なメモ

haproxyでhttpからhttpsへリダイレクト設定を入れるには以下設定をフロントエンド部分に記載すればよい。

```
frontend http-in
    bind *:80
    redirect scheme https code 301 if !{ ssl_fc }
```
【AWSメモ】S3の書き込み/読み込み性能が向上

[docomo Developer support](https://dev.smt.docomo.ne.jp/)の[@akatsukaha](https://qiita.com/akatsukaha)です


下記の通りAWSからS3のパフォーマンス向上について発表がありました．

- [Amazon S3 が、リクエストレートのパフォーマンス向上を発表](https://aws.amazon.com/jp/about-aws/whats-new/2018/07/amazon-s3-announces-increased-request-rate-performance/)

下記のサイトでも記載されていますが，簡潔に何がどうなったのか記載します．

- [【速報】全てのS3ユーザ必見！S3の性能が大幅パワーアップ！面倒なアレが不要に！
](https://dev.classmethod.jp/cloud/aws/amazon-s3-announces-increased-request-rate-performance/)

# **S3の書き込み/読み込みの性能が向上**

S3の書き込み/読み取りの性能は下記の通りに変更

- PUT/POST/DELETE：3,500リクエスト/秒/**プレフィックス**
- GET：5,500リクエスト/秒/**プレフィックス**

ポイントは**プレフィックス毎**というところです．

これまでは，プレフィックスごとにデータを分散することでS3への書き込み/読み込み性能を向上させることが可能となっていました．要するにS3に保存されているデータはプレフィックスごとに分散されて保存されているので，プレフィックスを意識しデータを保存することで書き込み/読み込みの性能を改善出来るということです．基本的にはこの方針は変わらず，単純に今回はプレフィックスごとの書き込み/読み込み性能が改善したという内容です．

# **プレフィックスを意識したデータ構造とは?**

下記の通り`examplebucket`というS3バケットがあり，下記のようなデータが入っている場合は，プレフィックスは`0001`の1個なので，GETですと，5,500リクエスト/秒の読み取り性能が期待できます．

```
samplebucket/0001/photo1.jpg
samplebucket/0001/photo2.jpg
samplebucket/0001/photo3.jpg
samplebucket/0001/photo4.jpg
samplebucket/0001/photo5.jpg
samplebucket/0001/photo6.jpg
```

下記の通り`examplebucket`というS3バケットがあり，下記のようなデータが入っている場合は，プレフィックスは`0001`と`0002`と`0003`の3個で,GETですと，それぞれ5,500リクエスト/秒の読み取り性能が期待でき,データのアクセスが均等の場合は，16,500リクエスト/秒の読み取り性能が期待できます．

```
samplebucket/0001/photo1.jpg
samplebucket/0001/photo2.jpg
samplebucket/0002/photo3.jpg
samplebucket/0002/photo4.jpg
samplebucket/0003/photo5.jpg
samplebucket/0003/photo6.jpg
```

今回の変更で単純にプレフィックスごとの読み取り，書き込み性能が向上していますが，よりスループットを上げたい場合は，これまで通り，プレフィックスを意識した構造を検討する必要があります．
MacbookPro2018でターゲットディスプレイモードが使えない

#MacbookPro2018 でターゲットディスプレイモードが使えない


##2018/9/3追記
10.13.6追加アップデート2として、OSアップデートがきたがこのアップデートでも本件は解消しない模様。
時期OSアップデートに盛り込むと言っていたのだけれど...

##結論
2018/8/1時点では MacbookPro2018 でターゲットディスプレイモードが使えない。
次期OSアップデートでターゲットディスプレイモードが使えるようになるそうなので、今はただただ待つしかないとのこと。

##現象
MacbookProとiMacをターゲットディスプレイモードで接続すると、iMac上に画面が映りはするが、一定間隔で点滅したり画面全体にノイズが走ったりする。

せっかく1万円だしてケーブル類を用意したものの、使い物にならなかった...

##環境
- MacbookPro2018 15inch/Corei9/32GB/SSD1TB/HighSierra ver10.13.6
- iMac late2012 27inch/Corei5/16GB/HDD1TB/HighSierra ver10.13.6
- Thunderbolt 3（USB-C）- Thunderbolt 2アダプタ
- Apple Thunderboltケーブル（2.0 m）- ホワイト

##試してみたこと
1万円出したのに使えないのは流石に悔しいので、色々調べて下記を試してみた。

- SMCリセット
- NVRAM/PRAMリセット
- セーフモード起動
- 接続ポートの変更
- 再起動

どれもダメ。
解決ならず。
がーん。

##Appleに問い合わせてみた
諦めきれず、Appleに問い合わせてみた。

問い合わせてはみたものの、既にこちらで試したことばかり提示される。結局解決には至らず...
Appleの方でも現象確認してみて、明日電話しますとのこと。

とりあえず明日の電話を待つ。

次の日の夜に電話がかかってきた。
Apple本社の方でも本現象が再現確認できたそうで、OSに問題があったとのこと。
次のOSリリースまでには必ず修正しますとのことだったので、現状はOSアップデートを待つしか術がないですね。

ちなみに、MacbookPro2018でのみ本現象が確認できているそうです。
また、システム要件を満たしているiMacであれば、どのiMacであったとしても本現象が起こるとのこと。
iMacが悪いわけではなく、MacbookPro2018の方が悪さをしている模様。

iMacのシステム要件は下記の システム条件 を参照。
https://support.apple.com/ja-jp/HT204592
jQueryの書き方について簡単にまとめた

#RubyだけじゃなくてJSもやらなあかん
Rubyしかやってきてないけど、JSは必須なので勉強しないと。
ってことでjQueryについて。

JSを書きやすくしたもの（ライブラリが）jQuery。
jQueryなら簡単にJSを書くことができます。

#使い方
jQueryを使い始める２パターンについて（他にも方法はあると思います）。

###①jQueryのサイトを開いて、ダウンロードして使う
⇒HTMLファイルにダウンロードしたjQueryファイルを紐づける。

```html

<head>
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
</head>
```


###②jQueryをダウンロードせずに、他のサーバーにあるものを使用する
GoogleやMicrosoft、jQuery本家などのサーバーが配信しているjQueryを使います。
専門用語でCDN（コンテンツデリバリネットワーク）と言って、アクセス元から近いサーバーと通信をとって高速化をはかるものです。
なんかよくわからんですが、こういう方法もあるってことで。
以下のように記述します。

```
<head>

<!-- headの中に以下のように記述 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

</head>
```

src=””のリンク先については、それぞれ希望のCDNのURLを入れます。これでjQueryファイルの紐付けができました。
この②の方法を使えば、自分でダウンロードせずにjQueryを使えるので、こちらのほうがミスもなく簡単。

#JavaScript（jQuery)のコードを書く場所
これについては依然まとめた記事があるのでそちらを参照
https://qiita.com/ryuuuuuuuuuu/items/6420353e8e2db4d28f20

#jQueryの書き方
###基本形

```js
$(function(){
    ここに処理を書く
});
```

基本形の中に処理を書いていくと以下のようになります。

```js

$(function(){
  $(A).B()    ⇦AをBする
});
```

Aを***「セレクタ」***といい、
Bを***「メソッド」***、
Bの直後のカッコ内を***「パラメータ」***といいます。

ちゃんと記入するとこんな感じに

```js

$(function(){
  $(".hoge").css("color","blue")     ⇦「.hoge」のcolorをblueにする
})
```
***「セレクタ」***とは任意の範囲、要素を指定するためのもので、jQueryを覚える上で欠かせない要素です。
なお、セレクタはCSSと同じような記述をするため、CSSを勉強済みであれば比較的簡単に覚えることができます。
下記のように書きます。

```
$(“#hoge”) – idセレクタ
$(“.hogehoge”) – クラスセレクタ
$(“li a”) – 子孫セレクタ
$(“p.hoge, p.hogehoge”) – グループセレクタ
```

*セレクタは「“」（ダブルクォーテーション）、もしくは「’」（シングルクォーテーション）で囲う必要あり。

jQueryはこの「セレクタ」で指定した場所に、
***メソッド***および***パラメータ***で記述した命令が処理されていく、と言うのがおおまかな流れとなります。


#イベントを使う
jQueryを扱う上でもう一つ欠かせない要素、それが***「イベントメソッド」***。
イベントとは、セレクタを「クリックした時」や「マウスのカーソルをあてた時」など（他にもいろいろあるが）、次に記述したメソッドを実行する「きっかけ」のこと。

```js

$(function(){
  $("A").B(function{ 　　　⇦AをBしたとき
    $("C").D()        　⇦CをDする
  });  
});
```

Bがイベントです。
イベントには「.click（セレクタをクリックした時に実行）」や「.mouseover（セレクタにマウスを当てた時に実行）」など色々あります。


###「.click」を使った 例

```
<div class="hoge">クリックすると青色になります</div>
```

```js

$(function(){
    $(".hoge").click(function(){
        $(this).css("background-color","blue")
    });
});
```

上記の例では、class名がhogeの「クリックすると青色になります」をクリックすると、
clickイベントが走り、背景色が青になる。という感じです。

*「this」はイベント時に同じセレクタを使用するということです。
QGIS3でウェブ地図利用が劇的に変化した

QGIS3がリリースされてしばらくたちました。2018年8月1日現在、最新バージョンは3.2となりました。ウェブ地図利用が圧倒的にわかりやすくなったので整理します。

### ブラウザを表示する

デフォルトで表示されている場合もありますが、そうでなければ手動で追加します。
「ビュー」→「パネル」→「ブラウザ」

![01.png](https://qiita-image-store.s3.amazonaws.com/0/60438/4b6a6918-71bc-99f2-ed5b-5a9037fe0347.png)


### XYZタイルレイヤを使用する

ブラウザに「XYZ Tiles」というレイヤが表示されるので右クリック

![02.png](https://qiita-image-store.s3.amazonaws.com/0/60438/f9c8786f-de78-1eb0-6960-9c74b5eb1bb6.png)

「新しい接続」をクリック

![03.png](https://qiita-image-store.s3.amazonaws.com/0/60438/d3f42b06-2b0d-1aa6-6147-d7e349c2e8e4.png)

「XYZ接続」というパネルが開く

![04.png](https://qiita-image-store.s3.amazonaws.com/0/60438/3523586e-969d-1f29-ee42-1f9bef071fd4.png)

「URL」にタイルのURLを指定する。
ここではMIERUNEのURLを指定しています。

![05.png](https://qiita-image-store.s3.amazonaws.com/0/60438/6a497acd-25b0-cf88-7386-7e110cdd4880.png)

![06.png](https://qiita-image-store.s3.amazonaws.com/0/60438/83929a3a-a226-e0aa-2da7-efdb5745ede4.png)


### 入れておきたいタイル地図
```
MIERUNE
https://tile.mierune.co.jp/mierune/{z}/{x}/{y}.png  

MIERUNE mono
https://tile.mierune.co.jp/mierune_mono/{z}/{x}/{y}.png 

北海道のCS立体図
http://kouapp.main.jp/csmap/tile/hokkaido/{z}/{x}/{y}.jpg

国土地理院標準地図
https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png

国土地理院淡色地図
https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png

国土地理院航空写真
https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg

Stamen_Watercolor
http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg

```
auto.arimaで学習した結果はあるんだけど，best modelの次数を忘れちゃった時

単なるメモ注意．

```R
model <- auto.arima(x, trace=T, stepwize=T, seasonal=T)
# (中略)

Best model: ARIMA(3,0,2)(0,1,0)[1008]
```

って学習しても，周期の入れ方とか学習期間とかが大量にあると，best modelなんて覚えてられないよね．

どこに格納されているのか探してみる．

```R
> objects(model)
 [1] "aic"       "aicc"      "arma"      "bic"       "call"      "code"      "coef"      "fitted"    "loglik"    "mask"     
[11] "model"     "n.cond"    "nobs"      "residuals" "series"    "sigma2"    "var.coef"  "x"        
```

うーむ，modelかarmaが怪しい．
で，うっかりmodelを見ようとすると，学習データが入っているのでデータ数が多い時は注意．
Rがしばらく固まる．

```R
> cts.arima$arma
[1]    3    2    0    0 1008    0    1
```

あった．

前から順に AR次数，MA次数，季節要素のAR次数，季節要素のMA次数，季節要素の期間，差分，季節要素の差分．

よくよく読めば，ドキュメントに書いてあんだけどね．
bestmodelって属性作って文字列として格納しておいてくれれば便利なのにー．

> arma
A compact form of the specification, as a vector giving the number of AR, MA, seasonal AR and seasonal MA coefficients, plus the period and the number of non-seasonal and seasonal differences.
[arima function \| R Documentation](https://www.rdocumentation.org/packages/stats/versions/3.1.1/topics/arima)
HTMLの要素にタッチイベントを実装する

#個人的に多用するHTMLへのタッチイベント実装方法

タッチイベントはボタンのクリックイベントよりも反応速度が速い場合が多い。


#実装準備
まず、HTML要素をidで取得しておく。

```javascript
var touchPannel = document.getElementById("touchPannel");
//ここに以下のいずれかのコードを記述

```

#実装方法

タッチイベントの種類
・"touchstart"
　指定した要素をタッチしたら関数を実行
・"touchmove"
　指定された要素をタッチし、指を動かすと関数を実行
・"touchend"
　指定された要素をタッチし、指を離すと関数を実行


以下2つの方法を挙げる。




##方法１：　
タッチイベント用関数を先に定義("addEventListener"の引数は2つで、一つ目が「イベントの種類」で二つ目が「実行する関数名」)

```javascript

function touch(e){
  alert("done")
}
touchPannel.addEventListener("touchend",touch);
```

この方法は、同じ関数を複数の要素にタッチイベントとして実装する場合に便利。
##方法２：
要素にタッチイベントを実装("addEventListener"の引数は3つで、一つ目が「イベントの種類」、二つ目が「実行する関数」、三つ目が"false")

```javascript
touchPannel.addEventListener("touchend",function (event){
  alert("done");
},false)
```
SQLにおけるNULLの危険性 -実例で学ぶNULLの仕組み-

#対象読者
- SQLでNOT INを使おうとしている方
- SQLにおけるNULLの仕様を知りたい方

# NOT INを使ってみる
## 前提となるテーブル

グループA

|名前|都道府県|
|:--|:--|
|山田|千葉|
|田中|東京|

グループB

|名前|都道府県|
|:--|:--|
|アラン|千葉|
|イーサン|東京|
|ウィリアム|北海道|
|ベンジー|東京|
|ルーサー|東京|

## SQLを実行してみる
**グループBの行のうち、グループAに存在しない都道府県の値を持つ行を取得する**
この場合、北海道はグループAに含まれないため、ウィリアムがSQLの結果として抽出されるはずです。

```sql
SELECT * FROM group_b
WHERE prefecture NOT IN (SELECT prefecture FROM group_a);
```

実行結果

|名前|都道府県|
|:--|:--|
|ウィリアム|北海道|

期待通りの結果が出力されました。特に問題ないように思えます。しかし、 データにNULLがある場合はどうなるでしょうか。

## 前提となるテーブル(NULLあり)
グループAに対して、新たに鈴木さんを追加します。ただし、鈴木さんの都道府県はNULLとします。

グループA

|名前|都道府県|
|:--|:--|
|山田|千葉|
|田中|東京|
|鈴木|<font color="red">NULL</font>|

グループB

|名前|都道府県|
|:--|:--|
|アラン|千葉|
|イーサン|東京|
|ウィリアム|北海道|
|ベンジー|東京|
|ルーサー|東京|

## SQLを実行してみる(NULLあり)
先ほどとまったく同じSQLを実行してみます。

```sql
SELECT * FROM group_b
WHERE prefecture NOT IN (SELECT prefecture FROM group_a);
```

実行結果

|名前|都道府県|
|:--|:--|
|　|　|

**な、なんと0件！！！**
先ほどのウィリアムが出力されなくなっていしまいました。

# なぜNULLがあると出力されなくなったのか
それは、このSELECT文で**WHERE句の評価が一度もtrueとならなかったためです**。
SQLでは、WHERE句の評価結果がtrueになった行のみを処理対象とします。WHERE句がtrueにならなければSELECTの処理対象となりません。

## なぜWHERE句がtrueにならないのか
雑な説明ですが考え方は以下の図の通りです。
グループAの都道府県列にNULLが1件でも存在する限り、**WHERE句の評価結果は必ずunknownとなります**。SQLを何度実行しようともWHERE句がtrueになることはないため、1行も処理対象として抽出されません。
<img src="https://qiita-image-store.s3.amazonaws.com/0/212045/67c38bfc-7441-446a-e258-ba32b323521a.png" width=80%>
覚えておくべきことは**「AND演算の中に1つでもunknownがあると、結果は絶対にtrueにならない」**ということです。NULLの仕様を理解しないと予期しない結果を出力するSQLを作ってしまうかもしれないので注意が必要です。

## おまけ：解決策
1. NOT EXISTSを使う
2. NOT NULL制約を設ける

```sql
SELECT * FROM group_b bb
WHERE NOT EXISTS (SELECT * FROM group_a aa WHERE aa.prefecture = bb.prefecture);
```

解説は省略します。
ZenHub API : ZenHubのIssue情報を取得してみる。サンプルコードあり。（curl,python,node.js）

### ■ 概要
ZenhubにあるIssueをAPI経由で取得します。APIの種類は、下記をご覧ください。
https://github.com/ZenHubIO/API

### ■ 事前準備

事前準備として行うことは1つだけです。

*Authentication*
https://app.zenhub.com/dashboard のURLから『API Token』を発行します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122901/1311636e-88c9-bd4d-e2e7-648ce6efae0d.png)

※Enterprise版は別途違う操作が必要です。

ここで取得したAPI Tokenはcurlでいれば下記のように埋め込みます。

```bash
curl -H 'X-Authentication-Token: TOKEN' URL
```


### ■ API取得方法
Zenhubのエンドポイントはhttps://api.zenhub.io/ になります。Enterprise版は、それぞれのhost名になります。(api.zenhub.io → xxxxxx)

試しに『[Get Issue Events](https://github.com/ZenHubIO/API#get-issue-events)』のAPIを使ってIssue Dataを取得してみます。

```bash:api_info
Get Issue Events

Get the events for an issue.
Endpoint
GET /p1/repositories/:repo_id/issues/:issue_number/event
```

--- 

では、実際に動かしてみましょう。

```bash:サンプルコード
curl -H 'X-Authentication-Token:{tokens}' https://api.zenhub.io/p1/repositories/{repo_id}/issues/{issue_number}/events
```
※ {token}は、事前準備で発行したトークンを埋め込みます。
※ {repo_id}とは、Boardを開いたときのURLで『repos=xxxxx』のことです。
※ {issue_number}は、そのままissueの#1の数値を入れればよいです。

**実行結果**
あるリポジトリのissue#1のデータを取ってきます。

```bash
$ curl -H 'X-Authentication-Token:xxxxxxxxxxxxx' https://api.zenhub.io/p1/repositories/{repo_id}/issues/1/events | python -c 'import sys, json; print json.dumps(json.load(sys.stdin), indent=2, ensure_ascii=False)'
[
  {
    "type": "addEpicToIssue",
    "created_at": "2018-08-01T10:24:48.286Z",
    "user_id": xxxxxx
  },
  {
    "type": "transferIssue",
    "created_at": "2018-08-01T10:23:41.827Z",
    "user_id": xxxxxx,
    "from_pipeline": {
      "name": "New Issues"
    },
    "to_pipeline": {
      "name": "Backlog"
    }
  },
  {
    "type": "estimateIssue",
    "created_at": "2018-07-31T15:30:16.991Z",
    "user_id": xxxxxx,
    "to_estimate": {
      "value": 13
    }
  }
]
```
※JSONの整形は自由にお願いします。


### ■その他、言語でのサンプルコード

```python:python
import requests
 
headers = {
    'X-Authentication-Token': 'xxxxxxxxxxxxxx',
}
 
response = requests.get('https://api.zenhub.io/p1/repositories/{repo_id}/issues/1/events', headers=headers)

print(response.json())
```
※未整形

```js:node.js
var request = require('request');
 
var headers = {
    'X-Authentication-Token': 'xxxxxxxxxxxxxx'
};
 
var options = {
    url: 'https://api.zenhub.io/p1/repositories/{repo_id}/issues/1/events',
    headers: headers
};
```
※未整形

エラーコード
401	トークンは無効です。認証を参照してください。
403	APIへのリクエストの上限に達しました。API制限を参照してください。
404	見つかりません。

| エラーコード       |        |  
|:-----------------|:------------------:|
| 401             |           トークンは無効です。[Authentication](https://github.com/ZenHubIO/API#authentication)を参照してください。   | 
| 403           |          APIへのリクエストの上限に達しました。[API Rate Limit](https://github.com/ZenHubIO/API#api-rate-limit)を参照してください。      |       
| 404             |              Not found. |
python3でネイピア数の値を求めてみる

#pythonでネイピア数(自然対数の底)の値を調べる。

```python
#$1
#"x"を定義(ゼロに限りなく近づける用の変数）
x = 1

#for文を回します。
for i in range(1,200):
    #ネイピア数の定義に従います。(ここで、x→0ならば(1 / x)→∞)
    e = (1 + x) ** (1 / x)
    #次for文で帰ってくるときのためにxを少しだけ小さくします
    #ここでxを小さくしすぎると有効桁数の関係でeの値が1になってしまいます。
    x = x * 9 / 10
    #$2
#出力
print(e)
```

このコードでは、
2.7182820629887425
という値が出てきました。

#ちなみに

上記コード内のコメントアウト$1のところに
 
```python
import matplotlib.pyplot as plt
```

$2のところに

```python
plt.plot(i,e,"bo")
```

と記述すると以下のようにグラフで2.71828...に収束しているのが視覚的に確認できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/277070/b4f2ccea-713d-f992-9df4-91e11dd3238f.png)
【GoogleBigQueryTips】standardSQLで、秒・ミリ秒・マイクロ秒タイムスタンプを->日付に変換する..他

## はじめに
タイムスタンプを日付に変換するというのは、分析をしているとしょっちゅう使うクエリではあるのものの、毎回忘れてしまうのでこちらに残しておきます。

特に、FirebaseAnalyticsから、BigQueryにデータをエクスポートしている場合には、"初めてアプリを開いた日"がミリ秒のタイムスタンプとして保持されているので、ユーザー分析を行う上で以下の変換を行うことは良くあるかと思います。

ご参考までに!


## 秒 --> 日付に変換
````sql:
EXTRACT(DATE FROM TIMESTAMP_SECONDS("タイムスタンプ[秒]")　AT TIME ZONE 'Asia/Tokyo') AS date
```

## ミリ秒 --> 日付に変換
```sql:
EXTRACT(DATE FROM TIMESTAMP_MILLIS("タイムスタンプ[ミリ秒]")　AT TIME ZONE 'Asia/Tokyo') AS date
```

## マイクロ秒 --> 日付に変換
```sql:
EXTRACT(DATE FROM TIMESTAMP_MICROS("タイムスタンプ[マイクロ秒]")　AT TIME ZONE 'Asia/Tokyo') AS date
```

## おまけ
## UTCタイムスタンプ --> 　時間帯を抽出
```sql:
FORMAT_TIMESTAMP("%H", timestamp, 'Asia/Tokyo') as hour
```

## UTCタイムスタンプ --> 　　週を抽出
```sql:
EXTRACT(DAYOFWEEK FROM date(timestamp, 'Asia/Tokyo')) as week
```

##  FROM句で○○日前を指定
```sql:
FROM XXX
WHERE
 _TABLE_SUFFIX BETWEEN REPLACE(CAST(DATE_SUB(CURRENT_DATE, INTERVAL 8 day) AS string), '-', '')
  AND REPLACE(CAST(DATE_SUB(CURRENT_DATE, INTERVAL 1 day) AS string), '-', '')
```
##  timestampと本日との差分を抽出する
*以下は、年変換する事で年齢を抽出

```sql:
ROUND(TIMESTAMP_DIFF(CURRENT_TIMESTAMP(),birthday,DAY)/365,0) as AGE
```
Python 2 > C実装の標準出力をRS-232C出力する (pySerial 2.6使用)

```txt:動作環境
Raspberry Pi 2 Model B (以下RPi)
Raspbian Jessie
Python 2.7.9
Python 3.4.2
gcc (Raspbian 4.9.2-10) 4.9.2
pySerial 2.6
USBシリアルケーブル (Prolific Technology社のドライバで動作)
  変換名人 USB-RS232 (コネクタ部分は青い透過型のハウジング）
```

### 関連

- [Python 2とPython 3 > C実装の標準出力を受けて標準出力する](https://qiita.com/7of9/items/5758155d7a2f13507124)

### 概要

- C実装で1秒おきに標準出力される
- その標準出力を受けて、PythonでRS-232C出力する

### C > 1秒おきの標準出力

[こちら](https://qiita.com/7of9/items/5758155d7a2f13507124#c--1%E7%A7%92%E3%81%8A%E3%81%8D%E3%81%AE%E6%A8%99%E6%BA%96%E5%87%BA%E5%8A%9B)の実装をそのまま使います。

### 接続環境

RPi -- USBシリアル -- RS-232Cケーブル(クロス) -- PCのRS-232Cポート

PC側ではTeraTermを起動し、9600bpsでの受信待ち状態にする。

```txt:PCの環境
Windows 10 Pro (64bit) バージョン 1803 (April 2018 Update)
Tera Term Version 4.9.0 (SVN# 6338)
```

### Python 2 > 標準出力をRS-232C出力する

```redirect_serial_180801.py
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import serial

# on pySerial 2.6
# on Python 2.7.9

CRLF = '\r\n'

with serial.Serial('/dev/ttyUSB0', 9600, timeout=10) as con1:
    while True:
        try:
            res = raw_input()
            con1.write(res)
            con1.write(CRLF)
        except EOFError:
            break

```

### 実行

```txt:RPi側
$ ./tickTime_180801 | python2 -u redirect_serial_180801.py 
```

PC側 (TeraTerm) : 9600 bps設定
![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/71ca2a13-0d93-a934-587e-8a202dd5a2ad.png)

### 用途

Cで実装したI2C通信(下記の発展版)の標準出力をPythonでRS-232Cに出力する。

- [Raspberry Pi > C > RPi_i2c_comm_180227: v1.1 > clock stretching対応 (ソフトウェアI2C)](https://qiita.com/7of9/items/e2b92facbacf8825b19f)

### 関連

- [Raspberry Pi > pySerial 2.6 > bug? > 受信バッファにデータが残る場合がある](https://qiita.com/7of9/items/52bc4892ce07d90437ac)
- [Raspberry Pi > pySerial 2.6 > [CR]はreadline()のdelimiterに使えない | [CR]まで読込む実装](https://qiita.com/7of9/items/02bd8dcc3238c73f84c9)

### 検索用キーワード

- redirect
- UART
ArduinoMega2560にHC-06と、RC522を接続する

・RC522とArduinoMega2560の接続

|RC522     | SDA | SCK | MOSI | MISO | IRQ | GND | RST | 3.3V |
|:--------:|:---:|:---:|:----:|:----:|:---:|:---:|:---:|:----:|
|Arduino   |  53 |  52 |  51  |  50  | --- | GND |  5  | 3.3V |

・HC-06とArduinoMega2560の接続

|HC-06  | VCC  |  GND |  TXD |  RXD |
|:-----:|:----:|:----:|:----:|:----:|
|Arduino|  5V  |  GND |  RX  |  TX  |
【ハンズオン】MySQL5.0からMySQL5.7にデータベースを移行する

# はじめに
移行元のMySQL5.0データベースのダンプをとって、移行先のMySQL5.7にインポートします。
前回までのサーバ移行計画のエントリはこちら

- [【未解決問題】AWSのEC2インスタンスをt1.microからt2.microにしたい話](https://qiita.com/hamham/items/307adcd4841f5f39c226)
- [【ハンズオン】AWS上にAsterisk13をインストールして電話してみる](https://qiita.com/hamham/items/9c15ae2fa5c025dc402d)
- [【ハンズオン】Amazon Linux2にApache、PHP、MySQLをインストールする](https://qiita.com/hamham/items/fd77bb0bb167a150dc8e)


# 移行元サーバでのDBエクスポート

ここでは「SIPDB」という名前のDBをエクスポートします。

```shell-session
# mysqldump -u root -p SIPDB > SIPDB.dump
```

パスワードを入力すると作業ディレクトリにSIPDB.dumpが作られました。
ログテーブルは約100万レコードあるのですがサイズは46MBほどです（意外と小さい）
中身を見るとCREATE TABLEしてデータの中身をINSERTするSQLが書かれています。


# 移行先サーバでのDBインポート

WinSCPなどでdumpファイルを持ってきます。
まずはインポートする前にDBの箱を作っておきます。

```sql
mysql> create database SIPDB;
mysql> use SIPDB
mysql> show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
```

インポートします。


```shell-session
# mysql -u root -p TEST < SIPDB.dump
```

パスワードを入力するとインポート完了です。
mysqlにつないで「show tables」でテーブルが作られていること、
「select * from テーブル名」で中身が入っていることを確認します。

# さいごに

データベース移行はあっさり終わりました。
ダンプファイルがGB単位になると思ってたので、EBSで新規ボリュームアタッチ→ファイルシステムをフォーマット→マウントとやってたのですがそんな必要なかったです。
この後、さらに以下のことをやりました。

- PHPからMySQLへの接続確認
- EC2インスタンスのElastic IPの付け替え（Classic→VPC）
- sip.confの修正（グローバルIPを指定している部分）
- CloudWatch（CPU＆ネットワーク監視）の再設定

そして、
![soudan_splash.jpg](https://qiita-image-store.s3.amazonaws.com/0/272753/4ca3aedd-ab86-4842-f651-606e2de79767.jpeg)

[相談電話](https://play.google.com/store/apps/details?id=foo.bar.soudan&hl=ja)のAndroidアプリから接続することができました！
これで旧世代のt1.microで月3000円ほどかかってたサーバ費用が、t2.nanoで月600円程度に抑えられます！
ただサーバ側の動作がかなりもっさりなのでやっぱ、t2.microくらいにしておいたほうがいいかも。

# 参考にしたサイト

- [mysqldumpまとめ](https://qiita.com/PlanetMeron/items/3a41e14607a65bc9b60c)
ApacheのOrder設定allow,deny(サイトのアクセス制限)でどハマった話

# Apcheの設定でローカルホストからのみ接続を許可したい
設定ファイルに下記のような記述をした場合

```httpd.conf
<Directory "D:/Apache Group/Apache2.2/htdocs">
    Order allow,deny
    Allow from 127.0.0.1
    Deny from all
</Directory>
```

「あー、これでローカルホストからだけ繋がるようになるんだなー」と察するかと思いますが、
違います。

実は上記の設定を行うと

**ど こ か ら も 繋 が り ま せ ん**

# どうするのが正解？
ローカルホストからのみ接続を許可したい場合は
下記のように設定します

```httpd.conf
<Directory "D:/Apache Group/Apache2.2/htdocs">
    Order deny,allow
    Allow from 127.0.0.1
    Deny from all
</Directory>
```

何が変わったかというと
**Order allow,deny**
が
**Order deny,allow**
に変わりました。

このallow,denyの順番が非常に重要で

```httpd.conf
<Directory "D:/Apache Group/Apache2.2/htdocs">
    Order allow,deny
    Allow from 127.0.0.1
    Deny from all
</Directory>
```
の設定の場合は
「ローカルからの接続はだけは許可する→やっぱり全面的に接続を拒否する！」という感じの順番で処理される為、
「全面的に接続を拒否する！」が効いてしまい、
**ど こ か ら も 繋 が り ま せ ん**
となります。

```httpd.conf
<Directory "D:/Apache Group/Apache2.2/htdocs">
    Order deny,allow
    Allow from 127.0.0.1
    Deny from all
</Directory>
```
の設定の場合は
「全面的に接続を拒否する！→だけどローカルからの接続は許可するよ...」という順番で処理される為、
ローカルからだけ接続が許可されます。
Graylog2.4 を Multi-node で構築

# Graylog2.4 を Multi-node で構築

- [AmazonLinux2にGraylog2.4をインストール](https://qiita.com/watarin/items/1bafdd9ec1d63cc5965b) の続編
- Graylog を AWS上に、Multi-node で構築したので、そのメモ
- 基本的に http://docs.graylog.org/en/2.4/pages/configuration/multinode_setup.html の通りでできたので留意点だけ


## 構成

http://docs.graylog.org/en/2.4/pages/architecture.html#bigger-production-setup
をAWSを利用してつくる

```
ALB(https終端) 
    |
    v
EC2(nginx + graylog * mongoDB)x3 
    |
    v
ES(3インスタンス)
```

- ALB : https終端とロードバランス
- EC2 3台
   - nginx (port 80でlistenしてproxy)
   - graylog (multi node)
   - MongoDB (ReplicaSet)
- ElasticSearch Searvice
   - インスタンス3台


## ポイント

### 全般

- MongoDB ReplicaSet の要件で、3台が最低台数

### MongoDB ReplicaSet

https://docs.mongodb.com/manual/tutorial/deploy-replica-set/ に従って設定すればOK


なお、レプリケーションしないのにレプリケーションの設定をいれると、動かないので注意

```
replication:
   replSetName: "rs0"
```



### Elasticsearch cluster

- Amazon ElasticSearch Service使うので、クラスタを3台以上にすればOK
   - https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomains より3台以上が推奨
   - 今回はAZ冗長にはしなかった

### ALB

- https終端はこれでやる（ACMで無料証明書使えるので）
- http://docs.graylog.org/en/2.4/pages/configuration/load_balancers.html#loadbalancer-integration に従い、ヘルスチェックのパスは `/api/system/lbstatus` にする
- ヘルスチェックのタイムアウトは長めの方が良さそう


### Nginx

- ログとりと `X-Graylog-Server-URL` Header つけるために利用する
    - http://docs.graylog.org/en/2.4/pages/configuration/web_interface.html#making-the-web-interface-work-with-load-balancers-proxies
- https://qiita.com/watarin/items/1bafdd9ec1d63cc5965b の時と同じ設定でOK


### Graylog Multi-node

設定

- 1台だけ `is_master = true` 、それ以外は `is_master = false` にする
   - 全台  `is_master = false`  だとgraylogが起動しなかった。
   - 複数台 `is_master = true` は試していない
- `rest_listen_uri = http://0.0.0.0:9000/api/` にする
- `rest_transport_uri` はprivate IPを指定する
- `web_listen_uri = http://0.0.0.0:9000/` にする
   - localのnginx経由でも、`http://127.0.0.1:9000/` だと駄目
   - `rest_listen_uri` と違うと別ポートを要求されるので、一緒にする


## 1台殺してみた結果

- 1台殺しても、何もしなくてもちゃんと動いた
   - `is_master = true` のノード殺しても大丈夫
      - でも一部操作がずっと読み込み中になったので、できない操作はあるのかもしれない
      - 特に他のものがmasterに昇格するわけではなさそう。
   - ログの取り込みも継続して動いた
- 復帰させたら、何もしなくてもちゃんと戻った
Proxy 環境下の Rundeck で Slack に結果を投げたかった

## Proxy 環境下の Rundeck で Slack に結果を投げたかった
タイトルのとおり。
Job の結果を Slack に投げたくて、[これ](https://github.com/higanworks/rundeck-slack-incoming-webhook-plugin)を入れたのですが

```
ERROR NotificationService: Error sending notification: Notification{eventTrigger='onsuccess', type='SlackNotification', content='{"webhook_url":"https://hooks.slack.com/services/ほげほげ"}'}: class com.bitplaces.rundeck.plugins.slack.SlackNotificationPluginException: Error putting data to Slack URL: [接続がタイムアウトしました (Connection timed out)].
```

Proxy が原因だってのはすぐに分かったんですが、Plugin の設定では無さそうだし、Rundeck にもそれっぽい設定が見当たらない。。

## 調べた結果
JVM のオプションに `https.proxyHost` ってのがあったので、これを使ってみました。

```:/etc/rundeck/profile
RDECK_JVM="-Djava.security.auth.login.config=$JAAS_CONF \
           -Dloginmodule.name=$LOGIN_MODULE \
           -Drdeck.config=$RDECK_CONFIG \
           -Drundeck.server.configDir=$RDECK_SERVER_CONFIG \
           -Dserver.datastore.path=$RDECK_SERVER_DATA/rundeck \
           -Drundeck.server.serverDir=$RDECK_INSTALL \
           -Drdeck.projects=$RDECK_PROJECTS \
           -Drdeck.runlogs=$RUNDECK_LOGDIR \
           -Dserver.web.context=/rundeck \
           -Drundeck.config.location=$RDECK_CONFIG_FILE \
           -Djava.io.tmpdir=$RUNDECK_TEMPDIR \
           -Drundeck.server.workDir=$RUNDECK_WORKDIR \
           -Dserver.http.port=$RDECK_HTTP_PORT \
           -Dhttp.proxyHost=ホスト名 \
           -Dhttp.proxyPort=ポート番号 \
           -Dhttps.proxyHost=ホスト名 \
           -Dhttps.proxyPort=ポート番号"
```

下の2行を追加して、rundeckd の再起動。

・・・出来た。

Proxy 環境下でお困りの方はご参考に。

## 仲間募集中
[弊社](https://www.nittsu-infosys.com/)ではエンジニアを募集中です。インフラからアプリ、ユーザサポートまで幅広く業務を行ってます。
https://www.nittsu-infosys.com/recruit/2019/index.html
githubの2段階認証をhttpsのまま回避する方法

# 背景
githubアカウントの２段階認証ONにするとhttpsプロトコルでのpushが弾かれるようになる
`fatal: Authentication failed`

その回避方法についてメモ

# 回避方法
まあSSHにすれば良い。のだが、
ちょろっと普段使ってないデバイスでpushしたい時など、鍵の設定が面倒な時もあるかと思います。
httpsのままでいきたいならば、手っ取り早くAccessTokenをパスワードに入力すれば良い

```
$git push origin master
$username: username
$password: 以下で作成するAccessToken
```

# そのAccessTokenの作り方
- githubにログインしてsettingsから以下のDevelopers settingをクリック

<img width="731" alt="スクリーンショット 2018-08-01 12.38.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/105662/f6538986-454b-7011-0928-645d8ea77bb1.png">

- 左メニューのpersonal access tokenをクリック

<img width="911" alt="スクリーンショット 2018-08-01 12.51.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/105662/44dc94e7-dffd-96fa-e2ce-b8484d68238d.png">

- Generateを・・・

<img width="949" alt="スクリーンショット 2018-08-01 12.43.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/105662/ec5196bb-fcec-3c7d-7927-31f9a3884e32.png">

- 適当に名前つけて、repositoryへのアクセス権限を付与してやる（ここは用途に合わせて）
- 終わったら一番下のgenareteをクリックする

<img width="679" alt="スクリーンショット 2018-08-01 12.44.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/105662/69c17346-3d06-b446-5191-5f9376701029.png">

- あとは画面上に生成されたTokenが表示されるのでパスワードにぶち込んでやれば良い
- tokenは初回にしか表示されないので、わからなくなったら再度生成してね
redashで簡単にファネルを作る

##はじめに
こんにちは。
いきなりですが、ファネルを作って欲しいと言われたことはありますか？僕はあります。

Mixpanelやらのツールを使っていれば楽なのでしょうが、あいにく生のログデータがDBにあるだけ。
頼みのredashにはファネル表示機能は無いし・・・などと思っていたら、**redash4.0.0でファネル表示機能が追加されていました！**

![image.png](https://qiita-image-store.s3.amazonaws.com/0/49019/5ce13a58-545e-c85e-e335-0d9412500417.png)


##アップグレード
4.0.0は正式版が既にリリース済みです。下記を参照してアップグレードします。

[How to Upgrade - redash](https://redash.io/help/open-source/admin-guide/how-to-upgrade)

```sh

cd /opt/redash/current
sudo bin/upgrade

Continue with upgrade? (y/n): y
Downloading release tarball...
Unpacking to: redash.4.0.1.b4038...
Changing ownership to redash...
Linking .env file...
Installing new Python packages (if needed)...
Running migrations (if needed)...
Linking to current version...
Restarting...
Done! Enjoy.
```

私は3.0.0からのアップグレードだったのですが、特に問題なく一発で通りました。
人によってはPyOpenSSL周りでハマることがあるかもしれません。そんな時は以下の記事が参考になります。

[Redashのupgradeでハマったお話](https://qiita.com/s5601026/items/5c1cbe4c0c295585d83b)


##ファネルを表示
アップグレードも完了したので早速ファネルを表示します。
ファネル表示のためには、以下のような形式でクエリの結果を出力する必要があります。

![Funnel Output.png](https://qiita-image-store.s3.amazonaws.com/0/49019/f64bed13-69a6-dc01-31ca-4b304274c6f8.png)


これを生のアクションログが入ったテーブルから出力しようとすると、例えば以下のようなクエリになります。

```sql

select
action_type,
count(distinct id_user) as count
from
action_log_table
where action_type in ("register", "action1", "action2", "action3", "action4") 
group by action_type
order by count desc
```

無事出力できたら、`New Visualization`からFunnelの表示設定を行います。特に難しいところはなく、`Visualization Type`に`Funnel`を指定し `Step Column Name`にaction_typeカラムを、`Funnel Value Column Display Name`にcountカラムを指定すればOKです。

![Funnel Visualization.png](https://qiita-image-store.s3.amazonaws.com/0/49019/fa140590-43b2-a78a-1536-8ab21538e2a3.png)


**できました！！超簡単です**

![Funnel Result.png](https://qiita-image-store.s3.amazonaws.com/0/49019/21e153cd-4098-7e19-ca9b-c652a6a5afd0.png)


##まとめ
redashは2年ぐらい前から使っているのですが、どんどん便利になっていて嬉しい限りです。
v4.0.0からファネルも簡単に作れるようになったので、是非プロダクト改善の第一歩として使ってみてください。