OmniAICreator/Qiita-1.07M huggingface dataset:
行ってよかったデブサミ2017夏

# はじめに
2017/07/28（金）にデブサミ行ってきました。

勉強会やコミュニティに参加していた自分は遥か昔。
外出先と言えば、職場と自宅近くのスーパーしか無い私ですが、今年こそもっとアクティブな人間になろうと決意していました。
しかし、今年も気付けば成果もないまま、折り返し後半戦。。。
焦燥感と動かない体、そして、焦燥感。。。
そんな自分に決別すべく、デブサミ参加で2017年後半戦、反撃の狼煙です。
（もちろん仕事は休んで参加しました。）

長くなりましたが、結果的には参加して良かったです。有意義でした。

というわけで、以下、参加したセッションの感想＆メモです。

# [A-1 SIerとオープンソースの美味しい関係](http://event.shoeisha.jp/devsumi/20170728/session/1412/)
Hadoopのコミッタである鯵坂さんの講演。

・**企業としてOSSのコミュニティに参加すると、以下のようなメリットがある。**
　⇒OSSの不具合に対して、独自パッチ当てる必要が無い
　　不具合はOSS本体にマージする
　⇒パッチをマージする際に、コミッタのレビューが入るので品質向上に繋がる
　⇒コミュニティ内部の事情が分るので、各機能の特徴（今不具合が多い機能、今後拡張しようとしている機能、等々）を把握できる
　　実装の際に、避けたほうがよい機能、組み方を選定できる
　⇒当該OSSの開発力を維持、向上させることで寿命を延ばす、競合に負けない品質を維持できる
　　SIerとして、当該OSSを組み込んだシステムの開発力、システム自体の品質向上

OSSは使うもので、不具合がでたら、バージョンアップを待つか、待てないならシステム独自で対応するしかないと思っていました。
が、確かに、企業自身がコミュニティに参加することで、他社に対して、そのOSSを利用したシステムの開発や保守の差別化を図ることができます。
ただ、これはある程度の体力がある会社でないとできない。。。
市場拡大戦略的のようなイメージを持ちました。

また、OSSのコミュニティ参加している前提で、SIのプリセールスをするので、OSS起因の不具合がでたときに、言い訳できないなぁと思い、
実際に、お客さんに対して、どのように説明しているのか、ご本人に質問させていただいたところ、やはり、そういうときはOSS起因だろうが、とにかく誠実に対応するしかないとのこと。
（そりゃ、そうです。アホな質問して申し訳なかったです。）

どんな契約条項なのかみてみたいな。

・**コントリビュータからコミッタになるためにはドキュメント修正がおススメ**
　⇒バグを比較的、簡単に見つけられる（新機能が出たら、とりあえずドキュメント通り、コマンド打ってみる）
　　修正は比較的に簡単。

それ以外にも、コミッタに対して、しつこくプルリクを送る、等々、ご自身の経験を交えた話は、面白かった。

# [B-3 コミュニティ活動がもたらす自身と会社への変革](http://event.shoeisha.jp/devsumi/20170728/session/1423/)
JAWS-UG代表を務めた金春さんから、自身のコミュニティ参加の経緯、遍歴と、活動を続けてきたことでビジネスに与えた影響をお話されてました。

・**最初は嫌々参加⇒でも勉強になるな、また顔出すか⇒運営とも顔見知りになる⇒運営側にまわる⇒ちょっと登壇してみる⇒色んなところで登壇する⇒その界隈で有名になる⇒媒体に取り上げられる⇒さらに有名になる⇒ビジネスにも良い影響が出始める**

ええストーリーや。。

・**世の中、アウトプットできる人は少ない**
・**アウトプットし続けることで、必ず見てくれる人はいる（媒体的も）**
・**アウトプットできる人はくいっぱぐれない**
　⇒くいっぱぐれないこそ、色々なことにチャレンジできる

若いエンジニアに聞いてもらいたい講演でした。

ビジネス面では、有名であることで、お客さんと商談や折衝する際に、信用してもらいやすいことや、採用によい影響がでているとのこと。

特に、ブランディングできていることで、採用ができていることは見習いたいところ。
採用はお金かかるから。。。

金春さんは、さすがお話が上手く、会場では何度も笑いをとっていました。
媒体の記事も多そうなので、ちょいちょい探してみようと思う。

# おわりに
技術そのものの話ではなく、オープンソースやコミュニティの状況とビジネスに関わる話を選択してみましたが、
タイムテーブルを見る限り、全体的にも、そんな話が多かった印象。

引きこもりとアルコール漬の脳みそはすっかり固くなってしまっているので、頑張って外にでようと思います。

![P7290002-2.png](https://qiita-image-store.s3.amazonaws.com/0/141209/8a196412-d5fe-b4f8-034d-fb5da40fef48.png)
MySQLをMySQL公式aptリポジトリからインストールする


# 目的
Ubuntu 16.04のサーバに
公式のaptリポジトリからMySQL Server(Community版)をインストールする

# 手順

## aptリポジトリ設定用のdebパッケージ入手

https://www.mysql.com/downloads/
にアクセスする。

![image](https://qiita-image-store.s3.amazonaws.com/0/40692/a856d685-aa1d-6720-4bd4-b50d02b30699.png)

画面下部にあるMySQL Community Editionのダウンロードページに進む
![image](https://qiita-image-store.s3.amazonaws.com/0/40692/fcf98a9e-20a4-9637-26a8-d30e7231f7a5.png)

遷移先ページの左側、MySQL APT Repositoryのリンクをクリックする
![image](https://qiita-image-store.s3.amazonaws.com/0/40692/55a6620c-1aed-1df3-fb26-0dbd9d6a645b.png)

ページ下部にあるDownloadリンクをクリックする
![image](https://qiita-image-store.s3.amazonaws.com/0/40692/eedbd823-04f9-2ffc-9576-f027b78322c7.png)

Oracle OTN?のシングルサインオンのIDおよびパスワードを求められるので、
入力するとdebパッケージがダウンロードされる

## aptリポジトリの導入

```bash
sudo dpkg -i mysql-apt-config_0.8.7-1_all.deb
```

まさかのインストール画面。
欲しいのは現在のバージョンのMySQL Serverとその周辺ツールなので
上二つがEnableであることを確認して先に進める。

![image](https://qiita-image-store.s3.amazonaws.com/0/40692/814a2a53-71ed-8974-1270-7f32afcc5621.png)

OKと出ればaptリポジトリの設定は完了

```bash
以前に未選択のパッケージ mysql-apt-config を選択しています。
(データベースを読み込んでいます ... 現在 59599 個のファイルとディレクトリがインストールされています。)
mysql-apt-config_0.8.7-1_all.deb を展開する準備をしています ...
mysql-apt-config (0.8.7-1) を展開しています...
mysql-apt-config (0.8.7-1) を設定しています ...
OK
```

## MySQL Serverのインストール

```bash
sudo apt-get update
sudo apt-get install mysql-server
```

またもやインストール画面。俺の知ってるものと違う...

![image](https://qiita-image-store.s3.amazonaws.com/0/40692/c62e120a-7d20-eb67-1e4c-76259bb548f7.png)

ひとまずrootパスワードを決めて先に進める。
あとはエラーが出たりしなければ正常にインストールは終わっているはず

## MySQL Serverのインストール確認

正常に動作していることが確認できればこれでOK。

```bash
$ sudo service mysql status
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: active (running) since 土 2017-07-29 16:36:40 JST; 49s ago
 Main PID: 4965 (mysqld)
   CGroup: /system.slice/mysql.service
           └─4965 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

 7月 29 16:36:38 mysql systemd[1]: Starting MySQL Community Server...
 7月 29 16:36:40 mysql systemd[1]: Started MySQL Community Server.
```


ログインしてみて動作確認。

```bash
$ mysql -uroot -pパスワード
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.19 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

問題なさそう。
ロリポップにBitnami:Redmineでredmineをインストール

# ロリポップにBitnami:Redmineはインストールできません
結論から書いておきます。
ロリポップレンタルサーバーにBitnamiは**インストールできません**。

Google先生に聞いても明確にこのことを書いているページがなかったので、これ以上無駄な時間を使う人が出ないように書いておきます。

ロリポップにBitnameをインストールしようとする人がいるのかは分かりませんが、自分はこれで１時間ほどネットをさまよったので。

## インストールできない理由
Bitnamiをインストールするためにはサーバー側でコンパイルしてやる必要があり、そのためにはGCCが必要なのですが...

**ロリポップにはGCCが入っていません。**また、GCCを追加でインストールすることもできません。

よってロリポップにBitnamiはインストールできません。あきらめましょう。

##参考までにエラーコード
ターミナルでインストールしようとすると、以下のようなエラーが表示されます。

```
エラー: エラーが発生しました。
The installer is unable to detect your glibcxx version. You can find how to proceed at https://docs.bitnami.com/installer/linux-faq/#what-is-the-minimum-version-of-libs
tdc-needed-for-bitnami-stacks. Please ensure that you have the minimun version required "3.4.9" before proceeding.
```
###↑の中で重要な部分
*The installer is unable to detect your glibcxx version.Please ensure that you have the minimun version required "3.4.9" before proceeding.*

＜簡単に要約すると＞
*インストーラーがGCCのバージョンを認識できませんでした。必須バージョンである"3.4.9"以上のバージョンがインストールされていることを確認してください。*

でもインストールできません。

つまりはそういうことですね...
お疲れ様でした。
Raspberry Pi Zero で自律飛行ドローンを作るぞ（第3回：フライトコントローラを使いました...）

# はじめに

前回の[Raspberry Pi Zero で自律飛行ドローンを作るぞ（第２回：姿勢制御は簡単にできないぞ！！）](http://qiita.com/shigeru-yokochi/items/746a520b6c0c00243993)　から約5か月 

いろいろ試してみたが納得する成果は得られませんでした。。。。

## で？

うーん。ここまで進捗が無いのは想定外。このまま進めても納得する成果が出る見立てはなく。。
しかも、9歳の息子からはまだ飛ばないの？と言われ続け父親としての面目が立たない。。
ということで、フライトコントローラに手を出しました。

## 結果は？

姿勢制御はフライトコントローラー任せなので飛ばすことはできました。
息子は凄く喜んでくれたので良かったですが、複雑な気分です。。

# 飛ばした構成

フライトコントローラをPWMドライバとESCの間に組み込みます。
選択したフライトコントローラはCC3D,フライトコントローラ設定用アプリはLibrePilotを使用しました。
※フライトコントローラの設定については割愛します。

![drone構成.PNG](https://qiita-image-store.s3.amazonaws.com/0/146154/e3a7e0d5-02f9-4606-e766-0dd63aa67d40.png)


# 動作検証

 RaspberryPiからは、まだスロットル制御だけなのでどこに飛んでいくかわからない状態です。
 なので少しだけ上昇することを確認しました。

```:設定値(スロットル値は上昇3秒後に2秒下降するような値を探して設定したが結構難しい。。)
#define DEBUG_MAINLOOP_TO    5.0	//デバッグ用メインループタイムアウト指定(sec)
#define FLIGHT_TIME          3   	//DEBUG_MAINLOOP_TO - FLIGHT_TIME = landing time
#define OFFSET_POWER         350
#define LANDING_POWER        310
```

![20170812.PNG](https://qiita-image-store.s3.amazonaws.com/0/146154/fe3ff01c-de0b-7560-f1e7-a544d952d718.png)



動画はこちら(YouTube)
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/fes9h9F4-Ys/0.jpg)](https://www.youtube.com/watch?v=fes9h9F4-Ys)



# 機体の外観

- 上側

![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/146154/a7caf587-6ef2-0028-66b7-dcf2ec1a7f57.jpeg)

- 下側

![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/146154/ac8e2066-bc7b-55ec-e1bc-87b1d6ab48a4.jpeg)



## 振り返り

約5か月良い勉強ができました。
悔しいけど、RaspberryPiのみでは、
ロール/ピッチ/ヨーに対する加速度/ジャイロ/PID制御からESCへのPWM値計算処理能力不足で機体のふらつきを抑えるのが困難でした。RTOSを使っても処理は追い付かない気がします。

フライトコントローラを使えば飛ばすことはできると思っていましたが、
実際に使ってみたらほんとに簡単に飛ばすことができました。スロットルを上げるだけでした。
でも、初めからフライトコントローラを使っていたら姿勢制御の難しさはわからなかったと思います。
ちなみに、今回使ったフライトコントローラは2000円程度。凄すぎ！

## 次にやること（やりたいこと）

- 飛んでいる位置を制御したい。
- 安全に高度を上げたい

ということで、まだまだ挑戦は継続します。


この続きは、[Raspberry Pi Zero で自律飛行ドローンを作るぞ（第4回：気圧センサで高度を維持させる）](http://qiita.com/shigeru-yokochi/items/2264be3180272c9db262)

# コード(GitHub)
https://github.com/shigeru-yokochi/drone
Raspberry Pi Zero W をUSBケーブルだけで簡単にセットアップする方法

UbuntuでRaspberry Pi Zero Wを初期設定したときの作業ログです。
私の環境は Ubuntu 17.04 です。

基本的に [Raspberry Pi Zero(W)のセットアップ](http://qiita.com/hishi/items/8bdfd9d72fa8fe2e7573) を参考にしていますが、
[USB経由でのインターネット接続を有効にする](http://qiita.com/hishi/items/8bdfd9d72fa8fe2e7573#usb%E7%B5%8C%E7%94%B1%E3%81%A7%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E6%8E%A5%E7%B6%9A%E3%82%92%E6%9C%89%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B) の部分で上手く行かなくて、
Wifiの設定を母艦から直接書き込んだほうが早かったという話です。

# microSDにイメージをインストールする

[https://www.raspberrypi.org/downloads/raspbian/]()
ここからイメージをダウンロードしてきて、ddで焼きます。

```bash
dd bs=4M if=2017-07-05-raspbian-jessie-lite.img of=${/dev/sdbとか}
```

# Wifiでログインできるようにする

先程のmicroSDはbootと、rootになるパーティションの2つが存在するので、どちらもマウントして、
bootパーティション直下に`ssh`という名前のファイルを作成することで、sshdを有効化して、
`cmdline.txt` と `config.txt` というファイルを編集することで、Wifiモジュールを読み込んでもらうようにします。

```bash
cd /media/${USER}/boot
touch ssh
sed -ie 's/quiet/modules-load=dwc2,g_ether quiet/' cmdline.txt
echo "dtoverlay=dwc2" >> config.txt
```

# Wifiのパスワードを設定する

root(bootじゃないよ)になるパーティションをマウントして、
`/etc/wpa_supplicant/wpa_supplicant.conf` に直接Wifiの設定ファイルを突っ込みます。

```bash
cd /media/${USER}/${bootじゃない方のパーティション}/etc/wpa_supplicant
wpa_passphrase "アクセスポイント名" "パスワード" >> wpa_supplicant.conf

# Wifiのパスワードが履歴に残るのが嫌なら、標準入力からも渡せます。
# wpa_passphrase "アクセスポイント名" < パスワードの書かれたファイル >> wpa_supplicant.conf
```


以下のようなものが追記されます。

```
network={
        ssid="SSID名"
        #psk="生のパスワード"
        psk=暗号化されたパスワード
}
```

# 起動してみる

これでmicroSDをラズパイに挿してブートしてあげると、
無事にWifiに接続して、SSHで待ち構えてくれます。

```bash
ssh pi@raspberrypi.local -o PreferredAuthentications=password
```

PreferredAuthenticationsを付けるのを忘れていて困ったw
パスワードはraspbianだそうです。
自宅にいるときだけ Android の音が出るようにする

# 自宅にいるときだけ Android の音が出るようにする

## 要件
- 自宅にいる時に音が出るようにする
- 外出したらミュート
- 寝たらミュート
- 起きたら音が出るようにする

## 環境
- 自宅の WiFi ルーターは、起床後の初回PC起動時に起動、就寝時に停止

## 設計
1. 自宅の WiFi に繋がったら音量設定
2. 0時、1時、2時にミュート（0時に寝たいけど、起きていることもあって WiFi につながることで音が出るようになるため ）
3. 7時に音量設定
4. 外出したらミュート

## 実装（IFTTT）
1. Android Device: Connect to specific WiFi network -> Android Device: Set ringtone volume;
2. Date&Time: Every day at -> Android Device: Mute ringtone; 0時、1時、2時の3個
3. Date&Time: Every day at -> Android Device: Set ringtone volume; 7時
4. Location: You exit area -> Android Device: Mute ringtone;

## 備考
- WiFi に繋がったらでなく、自宅の位置にいたら音量設定をしようと思ったけど、寝ているときも音量設定されることになるので NG。
Excel2016でワークシートからVBAの自作関数を呼び出す手順

Excelワークシートのセルの中から、VBAの自作関数を呼び出したいときに必要な作業。

たまにVBAをいじろうとすると、いつもやり方を忘れてしまうので、自分のための備忘録をここに記述。

## どんなことができるか
標準でExcelに用意されている関数ではできない下記のような処理をブックから利用することができる。

- VBAで背景色情報を取得し、背景色データの値によって処理を変える（カレンダーやWBS等で背景色でデータを記入している場合も自動集計できようになる）
など。

## VBAを使うための準備
昔と違って、そのままではVBAを利用できない。
目的のブックをマクロ有効のファイル（*.xlsm）で保存しなおす必要がある。

- VBAを利用するためには目的のブックを開いた状態で、[ファイル]-[名前をつけて保存]-[参照]でダイアログを表示し、
- ファイルの種類で Excel マクロ有効ブック（*.xlsm）を選択し、保存ボタンを押下する。
- メニューから[開発]-[Visual Basic]を選択し、VBのウィンドウを開く
- 左上部分のプロジェクトのウィンドウに目的のブックが表示され、その下に Microsoft Excel Object が、さらにその下にシートがぶら下がっているのを確認する
- Microsoft Excel Object と同じ階層に標準モジュールが存在するか確認する。
- 存在しない場合にはルートのVBAProjectを選択した後に右クリックし、[挿入]-[標準モジュール]を選択し、標準モジュールを挿入する

## VBA式を追加する
- 左上部分のプロジェクトのウィンドウで、標準モジュールを選択する
- 右上のソースコードを書くウィンドウに Function hoge()~End Functionの形式で自作関数を記述する

## シートから自作関数を呼び出す
- セル内に、=hoge()のように、通常の関数と同じよう形式で自作関数を呼び出す式を記述する
- 「無効な名前のエラー」が表示される場合、自作関数がExcelに見えていない、アクセスできていない。標準モジュールに記述しているか確認する
Redmine チケットの文中に画像プレビューを載せる裏技

# Redmineのチケットに画像プレビューをつけたい時ってありますよね？
Redmineで「こんな感じにお願い！」、「ここ変になってるよ！」などを伝える際に実際のスクリーンショットや写真があったほうが断然わかりやすいのは言うまでもありません。
↓イメージ↓
<img width="1109" alt="スクリーンショット 2017-07-29 15.03.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/77e6afc7-6945-a0a3-6654-f7689d3ca5bd.png">


しかし、RedmineにはQiitaみたいに画像プレビューを「ぽんっ:open_hands:」と表示する機能はありません。
※あるかもしれませんが知りません

# Redmineチケット上での画像の扱い
ここで画像をアップすると
<img width="1076" alt="スクリーンショット 2017-07-29 14.39.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/97ac25c4-801a-d827-59e6-4d21cd90a4b6.png">
こんな感じにアップされますね
<img width="1091" alt="スクリーンショット 2017-07-29 14.42.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/403de043-9d84-ca33-243b-8401838c3a3c.png">

チケット内容の説明のために必要な画像だとしたら、
「ここがおかしいので修正よろー（添付画像参照）」
といったように本文を書くことになると思います。

しかし、Redmineのチケット上のファイルアップロード機能はこういう用途ではないのでしょう。
「追加資料です！」とか、「添付画像をファビコンとして使用してください！」とかそういうのに使うんだと思います。

# チケット本文中に画像を載せるならURLを指定すればいい
URL指定で画像を載せることができます。
<img width="912" alt="スクリーンショット 2017-07-29 14.51.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/096f7999-48d6-b6dc-0ec7-cea1af76d003.png">
しかしローカルにある画像ファイルにグローバルなURLなんて存在しません。
なので、先ほどチケットに添付した画像のURLを指定します。
<img width="1088" alt="スクリーンショット 2017-07-29 14.52.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/3b5b179c-d5a5-8a5d-13d0-9d99561c5f52.png">
プレビューはいい感じですね。
しかし添付画像がダサいとても。

# つまりグローバルな画像URLが簡単に作れればいい
ここに行き着くと思います。
リモートストレージに設置してそのURLを....ってめんどくさいわ！！！
ということで画像のURLを作る裏技を紹介します。

## Githubを使う方法
ここに画像をアップします。
<img width="1144" alt="スクリーンショット 2017-07-29 15.05.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/29d27348-dbb7-ba24-c26e-4aa5e537c55e.png">
グローバルなURLが作成されます。
<img width="1073" alt="スクリーンショット 2017-07-29 15.06.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/7c741ce8-b435-1642-e151-1e1b44356ddb.png">

# 作成したURLをRedmineで使う
Qiita or Githubで作成したグローバルのURLを使います。
<img width="1055" alt="スクリーンショット 2017-07-29 15.10.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/a304ec3a-66a2-cbd3-bebc-1ea9d04919f4.png">
プレビューはこんな感じになります。
<img width="1109" alt="スクリーンショット 2017-07-29 15.03.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/77e6afc7-6945-a0a3-6654-f7689d3ca5bd.png">

担当者に優しい説明になりましたね:relaxed:

# 注意
- 今回のGithubの使い方はサービスにとって正しい使い方ではありません。
- くれぐれも自己責任でお願いいたします。
- Githubの無料枠には100MBの制限があります。
- ~~実はQiitaでも同じことがでk~~
【誤送信防止】Outlookにて、社外秘メールの送り先に社外アドレスが含まれていないかチェック

# <i class="fa fa-check-circle-o"></i> よくある問題
上司「おーい、この社外秘の内容をメールで送ってくれー」

ぼく「原価情報も入っているなぁ。社内の関係者各位を宛先に入れて、、、送信！」


ぼく「**しまった！ 社外の人にも送っちまった！**」

上司「おい！どうなってる！ 始末書もんだぞ！」

# <i class="fa fa-check-circle-o"></i> 解決策
メールの宛先ミスは、大きな損失を被ります。社内への宛て先ミスであればゴメンナサイで済みますが、社外宛てでは始末書どころでは済まないことにも。。

情報漏洩に関する意識が高い会社は、誤送信を防止する仕組みを取り入れています。お値段もそれなり、、組織としての導入になるので、個人的に導入というわけにはいかないですね。

富士通系
>基本ライセンスパック10：4万5000円
>年間保守：1万2000円
>
>FUJITSU Security Solution SHieldMailChecker 誤送信防止 - 特長 : 富士通ソーシアルサイエンスラボラトリ
http://www.fujitsu.com/jp/group/ssl/products/network/security/network-security/data-leakage-prevention/shieldmail/merit/

NTT系
>年間サブスクリプション価格（税別）
>50ユーザ ／ 80,000円
>
>メール誤送信防止・暗号化対策 CipherCraft/Mail
https://www.ntt-tx.co.jp/products/ccraftmail/

air 
>エアーの誤送信防止Outlookアドイン「WISE Alert」
https://air.co.jp/cat_03/4888/


また某社では、署名部分に自己チェックリストが挿入されています。チェック欄も削除されずにメールに含まれてくることもあるので、皆さんも見覚えがあるでしょう。

>□宛先に社外アドレスが入っていないか
>□添付ファイルを確認したか
>□公開前の開発ネームを削除したか

上記の各項目をチェックしてから送信するようです。ただ、自己チェックは面倒くさいですし、形骸化すれば効果が薄れてしまいます。そこで、**簡単なスクリプトを設定して、警告が出るように**してみました。使用しているのはMS-Outlookです。

なお、コードのうち90%はこちらのWebページを参考にしています。私は単純に確認ダイアログを追加しただけです。ご自由にお使いくださいとのことですので、私も参考にさせていただいています。

Outlookで宛先をチェック・制限するマクロ | Re：WEBマガジン
http://magazine.re-web.org/outlook-atesakicheck/

# <i class="fa fa-check-circle-o"></i> いきなりコード
自社の「***.co.jp」以外のドメインが宛先に含まれた場合のみ、Yes/No の確認ダイアログが表示されます。Yesならそのまま送信、Noなら送信をキャンセルします。キャンセル後はメールを再編集できます。

コードはこちら。

```vbnet
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)

'定義内容説明
'MY_DOMAIN→許可するドメイン
'RECV_INFO→受信者
'ATESAKI→宛先
'ATE_LIST→宛先リスト
'ALERT_MSG→警告メッセージ

MY_DOMAIN = "***.co.jp"  '許可する宛先ドメイン指定

For Each RECV_INFO In Item.Recipients
ATESAKI = RECV_INFO.Address
    If Right(ATESAKI, Len(ATESAKI) - InStr(ATESAKI, "@")) <> MY_DOMAIN Then
        ATE_LIST = ATE_LIST & ATESAKI & vbCr
    End If

Next RECV_INFO

    If ATE_LIST <> "" Then
        ALERT_MSG = "社外アドレス、" & vbCr & vbCr & _
        ATE_LIST & vbCr & _
            "へ送信しますか？" & vbCr

        If MsgBox(ALERT_MSG, vbYesNo + vbExclamation) = vbYes Then

        Else
            MsgBox ("キャンセルしました。")
            Cancel = True
        End If
    End If

End Sub
```

MS-Outlookでマクロ設定する方法は、先程と同様のこちらのページをみてくださいね。

Outlookで宛先をチェック・制限するマクロ | Re：WEBマガジン
http://magazine.re-web.org/outlook-atesakicheck/

補足
 Office 2016から、署名ツールの場所が変更されました。

C:\Program Files (x86)\Microsoft Office\Office16 フォルダー内に、SELFCERT.EXE があります

# <i class="fa fa-check-circle-o"></i> 効果のほど

上司「おーい、この社外秘の内容をメールで送ってくれー」

ぼく「原価情報も入っているなぁ。よし、関係者各位を宛先に入れて、、、送信！」

*ドゥン！*
*「社外アドレス、hoge@example.com へ送信しますか？」*


ぼく「**あぶねー！ 社外の方も宛先にいれてたわ！消しとこう**」

セーフ！
sisito + sisimaiをEC2にインストールしてブラウザからアクセスする

バウンスメールの管理で[sisimai](http://libsisimai.org/ja/)を試すことがあったので、[sisito](https://github.com/winebarrel/sisito)と合わせてEC2上に環境構築をしました。
とりあえずブラウザからアクセスしてsisitoの画面が表示されるまでです。

メールサーバーの構築やsisimaiの利用はこの先試して、記事をアップデートします。

# 前提
- EC2セットアップ済み
- sisimaiはruby版を利用
- ruby、mysql、nodejs、rails、bundlerインストール済み

# sisito x sisimaiの環境構築
## 環境
- Amazon Linux
- Ruby2.4
- rbenv 1.1.1-2-g615f844


## 手順
- EC2上での作業になります

### sisito、sisimaiインストール

```
cd ~
git clone https://github.com/winebarrel/sisito.git
cd sisito
echo "gem 'sisimai'" >> Gemfile
bundle install
```

- databaseの設定を自身の環境に合わせます

```
vi config/database.yml
```

- dbをcreate&migrateします

```
bundle exec rake db:create
bundle exec rake db:migrate
```

- 起動させます

```
rails server -b 0.0.0.0
```

### ブラウザからアクセス
<img width="1275" alt="screen.png" src="https://qiita-image-store.s3.amazonaws.com/0/71146/c27a9fbf-a702-ea54-e8c0-90c34a7001b4.png">

とりあえずDBの中身を表示するところまでいきました。
次回は[sisito](https://github.com/winebarrel/sisito)のREADME.mdのサンプルを参考にバウンスメールを収集、解析するスクリプトをいじってみます。
[備忘録]ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock'

##よくわからないsplのエラーでもめました。

```
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
```

上のエラーが出た時の対処法。
自分は、以下のコードを実行することによって治りました。

```
$ mysqld_safe --skip-grant-tables &
```

詳しくは自分もわかっていないので...
python3からMeCab使って形態素解析する①

python3からMeCab使って形態素解析をしました．
今回は，環境設定でいろんな記事が出回っていて，正直よくわからず苦戦したので，現時点での解決案を残しておきます．（今日は，2017/07/29）


## 環境
- Mac OSX Sierra
- Python 3.6.1


## やったこと
ポイントはパッケージインストールにありました．

- ①python3上で　`mecab-python3`　をpip install

```bash:installation
pip install mecab-python3
```

- ②bash上で`mecab-ipadic`をbrew install  

```bash:installation
brew install mecab-ipadic
```

本当にこれだけ．

## 結果

```py3:morphological_analysis
import MeCab
m = MeCab.Tagger()
print(m.parse('形態素解析をしたい文章を入れる'))

>
形態素	名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析	名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
し	動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
たい	助動詞,*,*,*,特殊・タイ,基本形,たい,タイ,タイ
文章	名詞,一般,*,*,*,*,文章,ブンショウ,ブンショー
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
入れる	動詞,自立,*,*,一段,基本形,入れる,イレル,イレル
EOS
``` 


---
とりあえずこれでうまくいくはずです．
もしうまくいかなかったらコメントください．
【PostgreSQL】ターミナルでデータベースを最低限いじれるようになるコマンド集

##Homebrewのインストール

ターミナルを起動し以下のコマンドを入力
```$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"```

もしくは[こちらのHP](https://brew.sh/index_ja.html)に乗っているコマンドをそのまま使えばok

以降は以下も参考になります
http://qiita.com/tstomoki/items/0f1a930bd42a8e1fdaac

##PostgreSQLインストール
HomebrewでPostgreSQLをインストール
```$ brew install postgresql```

DB初期化
```$ initdb ~/usr/postgres(←データベースサーバ作成階層指定) -E utf8（←文字コード指定）```

PostgreSQLサーバの起動
```$ postgres -D ~/階層指定```

データベース一覧表示
```$ psql -l```

ユーザ作成
```$ createuser --createdb --superuser --password postgres(←パスワード指定)```
※この後に聞かれるパスワードもpostgresにする

データベース作成
```$ createdb -U postgres(←ユーザ名指定) -E utf-8(←文字コード指定) -W -e db_name(←DB名指定)```

データベース接続
```$ psql -U postgres(←ユーザ名指定) db_name(←DB名指定)```
⇒このコマンドを打つと、SQLを実行することできるようになる。
　改行を入れてSQLを書き、最後に「;」を入れてエンターを押すと
　実行される。（「;」入れない限りはエンター押下しても改行されるだけ）


postgres=# 以降(DB接続後)
===============


○テーブル一覧表示
\z

○db一覧表示
\l

○ユーザ一覧表示
\du

○データベース情報開示
\conninfo

○db間移動
\c db_name

○テーブル定義を確認
\d table_name

○データベースから切断
\q
【個人メモ】 CentOS epel remi リポジトリの追加と有効化

# epel remi リポジトリを追加

環境構築時によく使うが、毎回ググってしまうためメモ

yum実行時に `--enablerepo` するのが面倒なため、有効化までを行う。

CentOS 6.8でやっています。

## 手順

epelのリポジトリを追加

```
sudo yum -y install epel-release
```

remiのリポジトリを追加

```
wget http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
sudo rpm -Uh ./remi-release-6.rpm
```

両方をデフォルトで有効化

```
sudo yum-config-manager --enable epel remi
```

### yum-config-manager のコマンドがありません

yum-utilsをインストールしてから実行します。

```
yum -y install yum-utils
```

## 参考にしました

- [yumリポジトリ一追加リスト 完全版](http://qiita.com/bezeklik/items/9766003c19f9664602fe)
- [Centos5,6,7にEPEL/REMIのyumリポジトリの追加をする]
(http://qiita.com/chidakiyo/items/3b81a442dda34d439b42)
BTCの送金のしくみについて

# はじめに

Aさんが自分のウォレットから、Bさんのアドレス宛に1BTCを送金した場合の、流れについて個人的にまとめてみた。

# BTCの送金のしくみ

AさんがBさんに1BTC送金すると、AさんがBさんに1BTC送金しましたよという取引データが作成される。これをトランザクションという。

作成されたトランザクションは、インターネット上にブロードキャストされる。要は、ビットコインの取引に関わっている全ての人にブロードキャストされる事になる。BTCの取引は世界中で行われているため、日夜膨大なトランザクションがネット上に流れている。

複数のトランザクションはまとめられて、１つのブロックという単位が作られる。１つのブロックは数百のトランザクションで構成されている。そのブロックを、最終的にはブロックチェーンという台帳に書き込むのだが、その前にマイニング（採掘）と呼ばれる作業が入る。

マイニングにも様々な仕組みがあり、BTCで採用されているのが、PoW（Proof of Work）という仕組み。直訳すると「作業による検証」ってところだろう。PoWによるマイニングには膨大な計算量が必要になるため、それなりのコンピュータパワーが必要になってくる。

PoWの計算方法についてだが、sha256というハッシュ関数があり、この関数に適当な値をランダムに代入していく。値を代入すると、ハッシュ値を出力してくれるのだが、このハッシュ値に、先頭から0が16桁並んだ値が現れれば正解という事になる。

何の値を入力すれば、このハッシュ値を出力してくれるのか分からないので、見つかるまでランダムに代入していく事になる。この代入する値の事をナンス値という。そして、このナンス値を見つけるのが各マイナーの間で競争になる。誰よりも早く正解のナンス値を見つけられた人が晴れて、ブロックチェーンの最終列に新しいブロックを追加できる名誉ある権利を得る事ができる。そして、その人にはBTCの報酬が与えられる。これがインセンティブになって、マイナーはBTC稼ぎのためにマイニングに精を出すのだ。

この計算競争なのだが、マシンパワーが大きければ大きい程有利である事には違いはないのだが、どうもどれだけ高性能のマシンでマイニングしたとしても、ナンス値が見つかるまで10分前後かかるように自動的に調整がかかるようになっているようだ。

さて、マイニングに成功して、ブロックを既存のブロックチェーンに追加する前に、整合性チェックという工程が入る。マイニングに成功したブロックは、ネット上にブロードキャストされ、マイニングによって見つかったナンス値とハッシュ値との整合性が本当に妥当かどうか、複数人によって再計算のチェックが入る。整合性チェックがＯＫであれば、晴れてブロックチェーンに追加される事になる。

流れは、まだ終わりではない。

Bさんに送られたトランザクションなのだが、本当に送信元がAさんなのか、Bさん側で確かめる必要がある。この本人確認が公開鍵暗号化方式という仕組みで行われる。

公開鍵暗号化方式の仕組みについてだが、Aさんはトランザクションをハッシュ化して、それに、自分の秘密鍵を用いてデジタル署名を付加させる。そしてBさんに送付する。受け取ったBさんは、Aさんの公開鍵を用いて、デジタル署名からハッシュ値を取得する。その後、送られてきたトランザクションをハッシュ化してみて、そのハッシュ値と比較して同じ値であれば、改竄されていないと判断する事ができる。

これで晴れて、BさんはAさんから1BTCを受け取ったという事になる。
tmpwatch の速度


`tmpwatch` と `find` のコマンドラインの比較とか言及してるところは多いけど、実際の処理速度とかに言及してるところがなかったので、とりあずやってみる。

なお、実行コマンドの間に、

```
# sync && sysctl -w vm.drop_caches=3
```

を実行してキャッシュの影響を排除する。

## tmpwatch とは

RedHat 系に用意されてる、ログ削除用ツール。

ぐぐって下さい。

## 準備

まず適当なファイルを毎分つくるスクリプト作成

```bash:make_tmp.sh
#!/bin/bash

arr=($(date '+%Y/%m/%d/%H/%M %Y%m%d%H%M'))
mkdir -p /home/bunzaemon/test/tmpwatch/${arr[0]}
mkdir -p /home/bunzaemon/test/find/${arr[0]}
for i in $(seq 0 999 ) ; do
    echo "sample" > /home/bunzaemon/test/tmpwatch/${arr[0]}/${arr[1]}_$i
    echo "sample" > /home/bunzaemon/test/find/${arr[0]}/${arr[1]}_$i
done
```

で cron で毎分回す。

```
* * * * * /bin/bash /home/bunzaemon/test/make_temp.sh
```

あとは、適当に待つ[^1]

[^1]: ディスクフルと、inode 枯渇に気をつける。

## 状態と検索条件

```
$ pwd
/home/bunzaemon/test
$ find find/ -type f | wc -l
1249000
$ find tmpwatch/ -type f | wc -l
1249000
```

最終修正[^2]が10時間以上前のものを条件にした。

[^2]: アクセスではない。

### 検索だけ

削除させず、検索だけ。

```
$ time find find -type f -a -mmin +600 > /dev/null
find find -type f -a -mmin +600 > /dev/null  1.16s user 14.63s system 33% cpu 46.532 total

$ time tmpwatch -t -m 10 ./tmpwatch > /dev/null
tmpwatch -t -m 10 ./tmpwatch > /dev/null  4.20s user 14.81s system 36% cpu 52.384 total
```

### 検索と削除

```
$ time find find -type f -a -mmin +600 -delete
find find -type f -a -mmin +600 -delete  1.00s user 23.64s system 28% cpu 1:25.61 total

```

```
$ time tmpwatch -m 10 ./tmpwatch
tmpwatch -m 10 ./tmpwatch  4.02s user 24.85s system 38% cpu 1:15.61 total
```

うーーーん。結局は誤差範囲程度と考えるべき？

複数回検証する気にはならんかったから、これで止め。

## memo

純粋に比較するなら -d をつけるべきだった、、、

- tmpwatch は、通常は空になったディレクトリも削除してくれる。
    - '-d' を指定して排除しない事も出来る。
- debian 系には、 tmpwatch がない。
    - CentOS 系の `/etc/cron.daily/tmpwatch` の代わりに `/etc/default/rcS`[^3]
  

[^3]: ん？ /var/tmp の挙動は？？
kvm: ゲストが勝手に起動します。


「ホスト再起動時に、`/etc/libvirt/qemu/autostart` に指定していないのに、ゲストが勝手に起動する。@CentOS6.8。どーして？」

# 自動起動の設定

そもそも、自動起動の設定は二つあって、以下の順で指定可能

1.	`/etc/sysconfig/libvirt-guests` => すべてのゲストの自動起動の挙動を指定。
2. `/etc/libvirt/qemu/autostart`  => 個々のゲストの自動起動の可否を決める。
    - 1.で自動起動させていない場合のみ

片方設定してないんだったら、もう片方で設定してるに決まってる。

## /etc/sysconfig/libvirt-guests

HOSTの /etc/sysconfig/libvirt-guests

```bash:
ON_BOOT=ignore
```

を記載すると、乗ってる全ゲストが自動起動しなくなる。 

- 起動時のデフォルトパラメータは、起動実行スクリプト `/etc/init.d/libvirt-guests`[^1] 中ほどにて宣言されている。
 
[^1]: CentOS6.8 の場合。バージョンとか違うと、若干パスとファイル名に違いが生じるので注意。

## /etc/libvirt/qemu/autostart

登録する。

```shell-session:もちろんHOSTで
# virsh autostart DOMAIN
```
削除する。

```shell-session:
# rm /etc/libvirt/qmenu/autostart/DOMAIN.xml
```

# 疑問

巷では、上記 1. に言及せず、いきなり 2. の説明をしてるサイトが目に付く。

で、`/etc/init.d/libvirt-guests` でぐぐると、 [ubuntu の場合だと](https://www.apt-browse.org/browse/ubuntu/xenial/main/amd64/libvirt-bin/1.3.1-1ubuntu10/file/etc/init.d/libvirt-guests) 最初から `ON_BOOT=ignore` であるっぽい。なるほど、そっちの人だと、2. から説明するのだろう。

それはそれで解決したのだが、ん? CentOS の場合は?

今回の対象サーバは、立ててから時間が経てる。誰が立てたのかも判らない。デフォルトでは、`ON_BOOT=ignore` で、誰ぞが改造したものを見ていたのかもしれない。

あいにくネット検索しても言及してそうなところに行きつかない。

てんで、配布ソースに当たってみようと。

## rpm をみる。

CentOS では、 `libvirt-client` のなかに、 `libvirt-guests` は含まれてる。

対象サーバのやつは、けっこう古そうなバージョン `libvirt-client-0.10.2-62.el6.x86_64`

探し回って、[生き残ってたリンク](http://rpm.pbone.net/index.php3/stat/4/idpl/36337797/dir/centos_6/com/libvirt-client-0.10.2-62.el6.x86_64.rpm.html) からダウンロードして中身を見る。

```
$ wget -q ftp://mirror.switch.ch/pool/4/mirror/centos/6.9/os/x86_64/Packages/libvirt-client-0.10.2-62.el6.x86_64.rpm
$ rpm2cpio libvirt-client-0.10.2-62.el6.x86_64.rpm | cpio -idv
$ cat ./etc/rc.d/init.d/libvirt-guests
(略)
ON_BOOT=start
ON_SHUTDOWN=suspend
(後略)
```
ここには載せないが、最新版と思しきもの[^2]でも `ON_BOOT=start`。

[^2]: `/usr/libexec/libvirt-guests.sh`

ということで、 CentOS では、デフォルトでホスト OS 再起動したら、ゲストも起動しますよ。

## memo

今回のとは無関係だけど、`/etc/sysconfig/libvirt-guests` について。

>START_DELAY - ゲストが起動する間の遅延期間を設定します。この期間は秒単位で設定されます。遅延がないようにし、かつすべてのゲストを同時に起動させるには時間設定の 0 を使用します。
[引用元](https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Virtualization_Administration_Guide/sub-sect-Shutting_down_rebooting_and_force_shutdown_of_a_guest_virtual_machine-Manipulating_the_libvirt_guests_configuration_settings.html)

当り前だけど、これに適当な秒数を記載すると、最初の GUEST も HOST が起動してから、指定秒数待ってスタートする。

GUEST で HOST の特定プロセスを呼ぶ様なモンが動いている場合は素直に、遅らせよう。
clara-rulesの世界(4)

[前回](http://qiita.com/iku000888/items/7bb53bd3af51ea2e9e68)

clara-rulesのセッションの中身を外から調べるための[クエリ機能](http://www.clara-rules.org/docs/queries/)があるので使い方を調べてみた。

- 基本的にはルールの左辺だけを定義する。

## ルールとの役割の違い
- ルールはセッションに追加された既存のファクトから新しいファクトを導き出すために使う
- クエリは純粋にセッションの中を調べるために使う
    - デバッグ
    - 計算が終わったセッションから情報を取り出し、別の処理に渡すための中間ステップ

## コード例

```clj

(ns  clara-rules.join
  (:require [clara.rules :refer [defrule fire-rules insert
                                 mk-session query defquery]]))

(defrecord TypeA [attr-a join-key])

(defrecord TypeB [attr-b join-key])

;;Queries
(defquery find-all-As
  [];;parameters
  [?a <- TypeA];;Matching condition
  )

(defquery find-As-by-attr
  [:?value];; Parameter needs to be a keyword
  [?a <- TypeA (= attr-a ?value)])

(defquery find-join-key-of-As
  []
  [TypeA (= ?jk join-key)])

(defquery find-A-and-B-pair-by-join-key
  [:?value]
  [?a <- TypeA (= join-key ?value)]
  [?b <- TypeB (= join-key ?value)])

(def sess (-> (mk-session)
              (insert (->TypeA "a1" :foo)
                      (->TypeA "a2" :bar)
                      (->TypeA "a3" :baz)
                      (->TypeB "b1" :foo)
                      (->TypeB "b2" :bar)
                      (->TypeB "b3" :baz)
                      (->TypeB "b4" :qux))
              (fire-rules)))

(query sess find-all-As)
;; ({:?a {:attr-a "a1", :join-key :foo}}
;;  {:?a {:attr-a "a2", :join-key :bar}}
;;  {:?a {:attr-a "a3", :join-key :baz}})

(query sess find-As-by-attr :?value "a1")
;; => ({:?a #clara_rules.join.TypeA{:attr-a "a1", :join-key :foo}, :?value "a1"})

(query sess find-join-key-of-As)
;; => ({:?jk :foo} {:?jk :bar} {:?jk :baz})

(query sess find-A-and-B-pair-by-join-key :?value :foo)
;; => ({:?a {:attr-a "a1", :join-key :foo},
;;      :?value :foo,
;;      :?b {:attr-b "b1", :join-key :foo}})
```

## 上記コードの注目点
- `defquery`はパラメターを外部受けとることができること以外は、`defrule`の左辺と同じ様に書ける
    - 変数の束縛etc
- `query`は`defquery`内で束縛された変数を結果のマップのキーとして返す
- `query`はマッチした物をマップのシークエンスとして返す

## 感想
以前までの例では結果を確認するためにはルールの右辺で副作用を(println)用いる事しかしていなかった。
副作用を用いずに結果を確認する手段が無いものかと触った時から抱いていた疑問が一つ解けたので嬉しい。

[次回](http://qiita.com/iku000888/items/a98837369f18459f9755)
Swiftの16進数小数の指数のポイント

Swiftの16進数小数で、勘違いしていた部分があったのでまとめを書きました。

# Swiftの16進数小数は必ず指数部分を付けないといけない

```swift
let a = 0x1.0p0 //OK
let b = 0x1.0 //NG
let c = 0x1 //OK 整数は指数が必要ではない
```

# 指数表記はpで始める

```swift
let a = 0x1.0p0 //OK
let b = 0x1.0e0 //NG
let c = 1.0e0 //OK 10進の場合はe
```

# 指数表記は10進数で表記する

```swift
let a = 0x1.0p10 //OK
let b = 0x1.0pa //NG
```

# 小数点移動は2進数状態で行われる（ここが盲点）

```swift
let a = 0x1.0p1
let b = 0x10.0p0 //10進数で16
let c = 0x2.0p0 //10進数で2
a == b //false
a == c //true
```

小数点移動は2進数状態で行われることが盲点でした。
Goでのアルゴリズムクイックリファレンス第2版(深さ優先探索)

Goに慣れるためとアルゴリズムの復習の為に週1ぐらいで更新していきます。[アルゴリズムクイックリファレンス 第2版](https://www.amazon.co.jp/gp/product/4873117852/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4873117852&linkCode=as2&tag=amesho-22&linkId=b7688201ae37a6234596fa96dfd3ccdd)を読んで各種アルゴリズムをGoで実装して行きます。

前回: [Goでのアルゴリズムクイックリファレンス第2版(二分探索木)](http://qiita.com/amesho/items/6f9eeec76c039e58d41f)

今回は[深さ優先探索](https://ja.wikipedia.org/wiki/%E6%B7%B1%E3%81%95%E5%84%AA%E5%85%88%E6%8E%A2%E7%B4%A2#.E5.86.8D.E5.B8.B0.E3.81.82.E3.82.8A)

> 深さ優先探索（ふかさゆうせんたんさく、英: depth-first search, DFS、バックトラック法ともいう）は、木やグラフを探索するためのアルゴリズムである。アルゴリズムは根から(グラフの場合はどのノードを根にするか決定する)始まり、バックトラックするまで可能な限り探索を行う。「縦型探索」とも呼ばれる。

https://play.golang.org/p/cAaUt5zFQA

```go
package main

import "fmt"

type Graph struct {
	List []int
}

func DepthFirstSearch(g *[]*Graph, n int, visited *[]int) {
	fmt.Printf("n:%d\n", n)
	(*visited)[n] = 1
	fmt.Println(*visited)
	for _, v := range (*g)[n].List {
		if (*visited)[v] == 0 {
			DepthFirstSearch(g, v, visited)
		}
	}
}

func main() {
	gl := make([]*Graph, 0)
	gl = append(gl, &Graph{[]int{1, 2}}) // 0
	gl = append(gl, &Graph{[]int{3, 4}}) // 1
	gl = append(gl, &Graph{[]int{2}})    // 2
	gl = append(gl, &Graph{[]int{5}})    // 3
	gl = append(gl, &Graph{[]int{3}})    // 4
	gl = append(gl, &Graph{[]int{0}})    // 5

	visited := make([]int, len(gl))
	DepthFirstSearch(&gl, 0, &visited)
}
```

どこからも接続されてないところは訪問する必要性が無いはずなのでこれでいいとは思うんだけど。

次回は幅優先探索です。
改行コードがCRLFのファイルをjavascriptの正規表現の^と$で処理する際の注意

# はじめに

javascript の RegExp を使って CRLF の入った文字列を処理する場合に、`^`や`$`を使うと処理がおかしくなります。
javascriptのバージョンなど環境によっては異なるかもしれません。

# LF

まずは比較のために、LFの文字列の処理結果を書いてみます。

ソース1

```.js
result = "1\n2\n".replace(/^/mg, "^");
console.log(result);
```

出力結果1

```text
^1
^2
^
```

ソース2

```.js
result = "1\n2\n".replace(/$/mg, "$");
console.log(result);
```

出力結果2

```text
1$
2$
$
```

ソース1もソース2も正常な動作です。

# CRLF

次に改行コードをCRLFにして実行させてみます。

ソース3

```.js
result = "1\r\n2\r\n".replace(/^/mg, "^");
console.log(result);
```

出力結果3

```text
^1^
^2^
^
```

ソース4

```.js
result = "1\r\n2\r\n".replace(/$/mg, "$");
console.log(result);
```

出力結果4

```text
1$$
2$$
$
```

余計な場所までマッチしてしまっています。

# CR

CRがおかしいのかもしれませんので試してみます。

ソース5

```.js
result = "1\r2\r".replace(/^/mg, "^");
console.log(result);
```

出力結果5

```text
^1
^2
^
```

ソース6

```.js
result = "1\r2\r".replace(/$/mg, "$");
console.log(result);
```

出力結果6

```text
1$
2$
$
```

環境によっては改行されないなど差異があるかもしれませんがこのような出力になると思います。
正常ですね、
と書いてしまってましたが、CRを改行コードとして認識するのが問題なのかもしれません。
CRは復帰コードで改行コードではないという記述も見たことありますが、CRの動作を規定する規則はあるのでしょうか?

# LFCR

こんな改行コードは無いですが実験してみます 。

ソース7

```.js
result = "1\n\r2\n\r".replace(/^/mg, "^");
console.log(result);
```

実行結果7

```text
^1
^
^2
^
^
```

ソース8

```.js
result = "1\n\r2\n\r".replace(/$/mg, "$");
console.log(result);
```

実行結果8

```text
1$
$
2$
$
$
```

異常な出力と言えるのか、正常な出力と言えるのか。
CRを改行コードとして考えれば正しいのでしょうか。

# まとめ

以上の事から、CRもLFもそれぞれ1つの改行コードとして扱われていることが分かります。
CRLFの動作も正常と言えるのかもしれません。

現状、CRLFのファイルを使う際は気を付けたほうが良いですね。
CRLFを扱う事の方が珍しいのかもしれませんが。
Windowsを窓から投げ捨てろと、言う事でしょうか（・A・）

余談ですがAtomエディターでWindowsのファイルを扱うと、これが原因で手間が増える事が多いです。
原因に気が付くまで大変でした。

# 番外

Python3でも試してみました

```python
>>> import re
>>> start = re.compile("^", re.M)
>>> end = re.compile("$", re.M)
>>> start.sub("^", "1\n2\n", 6)
'^1\n^2\n^'
>>> end.sub("$", "1\n2\n", 6)
'1$\n2$\n$'
>>> start.sub("^", "1\r\n2\r\n", 6)
'^1\r\n^2\r\n^'
>>> end.sub("$", "1\r\n2\r\n", 6)
'1\r$\n2\r$\n$'
>>> start.sub("^", "1\r2\r", 6)
'^1\r2\r'
>>> end.sub("$", "1\r2\r", 6)
'1\r2\r$'
>>> start.sub("^", "1\n\r2\n\r", 6)
'^1\n^\r2\n^\r'
>>> end.sub("$", "1\n\r2\n\r", 6)
'1$\n\r2$\n\r$'
```

CRを改行コードとして扱わないようです。
HTMLメルマガを書いてみる

こんにちは、そして初めまして。色々と乱雑に勉強中のycrackといいます。

HTMLの勉強を始めてしばらく経ったので、HTMLメールを書いてみようと思ったら、WebのHTMLと全然違ってこれまた大変だったので、備忘録がてら書いておきます。

# DOCTYPE
今のWebのスタンダードといえばHTML5+CSS3な感がありますが、先進的なのはブラウザだけでメーラーはかなり対応がまちまちです。なので、安全策も兼ねて以下の2つが良さそうです。どちらにするかはお好みで。

- HTML 4.01 Transitional

```html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">hogefuga</html>
```
- XHTML 1.0 Transitional

```html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">hogefuga</html>
```


# 文字コード
HTML5だと簡単にこのように書きますが、

```html
<meta charset="UTF-8">
```

HTML4.01かXHTML1.0を使うので、`http-equiv`を使って書きます。Eメールなので`UTF-8`ではなく`iso-2022-jp`が良さそうです。

```html
<meta http-equiv="Content-Type" content="text/html; charset=iso-2022-jp">
```

## 追記 [2017-07-29 17:48 JST]
`iso-2022-jp`に対応してるエディタがあんまり無さげなので、`UTF-8`で編集しておいて、後からコピペする際に`iso-2022-jp`にする、といった手段の方が良いと思います。


# レイアウト
Webだとかなり自由にレイアウトできるのですが、HTMLメールは`<table>`を使ってレイアウトします。いわゆるテーブルレイアウト。マジかよ…


# style
外部CSSは当然ながら、`<head>`内の`<style>`すら読んでくれないケースがあるので、全部タグの属性に書きます。
おのれGmail。


```html
<table style="border-collapse: collapse; padding: 0; border: 0; width: 640px;">
  <tr>
    <td>hoge</td>
    <td>fuga</td>
  </tr>
</table>
```


# その他気になったこと
何故か`<img>`を入れると`padding`を0指定にしていても1px追加されてしまう問題が発生。気に食わないけど、`cellpadding="0"`とすることで解決。

```html
<table style="border:0; padding:0;" cellpadding="0">
  <tbody>
    <tr>
      <td>
        <img src="hoge.png">
      </td>
    </tr>
  </tbody>
</table>
```
NginxとApacheの違い

# Apache とは
HTTPプロトコルを用いて、Webブラウザから「GET」や「POST」などのリクエストを受け取り、そのリクエストにしたがって処理するサーバー

# Nginx とは
高い並行性と処理性能、メモリ使用量の小ささに重点を置いて開発されたオープンソースのWebサーバ

#### Webサーバの接続処理のアーキテクチャ

## マルチプロセスモデル
　・クライアントからの接続毎に、プロセスをフォークして処理する
　・フォークのコストが高いため、通常はプレフォーク（事前にフォークしておく）モデルを採用

<利点>
・メモリ空間が子プロセス毎に独立しているため、スクリプト言語などを組み込みやすい
　ex.) Apache HTTP Server mod_php
<欠点>
・メモリ空間が共有できないため、プロセス間の情報共有が難しい
・同時接続数が増えると、その分だけ子プロセスも増える
　→ メモリを大量消費
　→ コンテキストスイッチのオーバーヘッドが大きくなる
 ※ コンテキストスイッチ・・・複数のプロセスが1つのCPUを共有できるように、CPUの状態(コンテキスト (情報工学))を保存したり復元したりする過程のこと

## マルチスレッドモデル
・クライアントからの接続毎にスレッドを生成して処理する
・バリエーションとしてマルチプロセスとマルチスレッドのハイブリッドモデルもある
　ex.) Apache HTTP Server - MPM worker
<利点>
・メモリ空間が各スレッドの間を共有できる
・マルチプロセスモデルに比べると、メモリ消費量やコンテキストスイッチのオーバーヘッドが小さい
<欠点>
・メモリ空間を共有しているため、スクリプト言語を組み込めないことがある
　→ なぜ？
・同時接続数が増えると、その分だけスレッド数も増える
　→ コンテキストスイッチのオーバーヘッドが大きくなる。（メモリ空間の切り替えがない分、マルチプロセスモデルよりは小さい）

## イベント駆動モデル
・クライアントからの接続毎にイベント処理を行う
・1プロセスは1CPUしか使えないので、CPUの数だけプロセスを用意するワーカーモデルが使われる
ex.) Apache HTTP Server -MPM event , Nginx
<利点>
・メモリ空間が共有できるというか1つ
・同時接続数が増えてもプロセス数やスレッド数が増えることはない
　→ メモリ消費帳やコンテキストスイッチのオーバーヘッドが小さい
<欠点>
・メモリ空間を一つであるため、スクリプト言語を組み込めないことがある
　→ なぜ？


▼Nginx
・「C10K問題」クライアント1万台問題
　→ 
・マルチプロセスモデルやマルチスレッドモデルのWebサーバ
　同時接続が増える
　→ プロセス数やスレッド数が増える
　→ コンテキストスイッチのオーバーヘッドが大きくなる
    → 本来の処理に時間が割けなくなる

## なぜ、「Nginx」を利用するのか？
・イベント駆動型モデル
　コンテキストスイッチのオーバーヘッドが小さい
　→ 「C10K問題」の解決策
・メモリ空間は、一つであるため同時接続数が増えてもメモリの使用量は小さい
　→ 仮想マシンのインスタンスを小さくできる
　→ リソースの効率的な利用

## NginxとApacheで何が違うのか
①メモリの消費量
　フットプリントの小ささ
　→ フットプリントとはなに？？
　apache2.4からは、MPMがあるが
　→ MPMとは？

②同時アクセス数
　C10K問題を意識した設計

③速度
　静的ファイルは早い
　動的コンテンツは、mod_* で組み込んだapacheのprefork MPMの方がオーバーヘッドがない分速い
【Java】形態素解析「lucene-gosen」を利用してスパム判定

# やったこと
##### 機械学習のための第一歩として、形態素解析を利用したスパム判定をやってみた(開発言語は、Javaで、playframeworkを利用)

# lucene-gosenとは
#### Javaの形態素解析ツールで、jarを落とすだけで利用可能

下記サイトからjarをダウンロード
https://code.google.com/p/lucene-gosen/

# 解析したいファイルの読み書き

``` 
public static void writing(File readfile,File writefile) throws IOException, FileNotFoundException{
	StringTagger stirngTagger = SenFactory.getStringTagger(null);
		
		Reader reader = new InputStreamReader(new FileInputStream(readfile), "UTF-8");
		StreamTagger tagger = new StreamTagger(stirngTagger, reader);
		FileWriter filewriter = new FileWriter(writefile);
		BufferedWriter bw = new BufferedWriter(filewriter);
		
		while (tagger.hasNext()) {
			Token token = tagger.next();
			bw.write(token.getSurface());
			bw.newLine();
		}
		bw.close();
	}
```

# 分かち書きにしたワードをカウントをして、出現数の多い順に並び替える

```
public class Wordseparated {
		public CountTable count(String readfile,String writefile) throws IOException, FileNotFoundException{
		
			CountTable table = new CountTable();		
			BufferedReader brfile = new BufferedReader(new FileReader(readfile));			
			BufferedWriter bwfile = new BufferedWriter(new FileWriter(writefile));

			while (true) {
		                String linefile = brfile.readLine();
				if (linefile == null) {
					break;
				}
				for (String s : linefile.split("\\s+")) {
					if (!s.equals("")) {
						int count = table.get(s);
						table.add(s);
					}
				}
			}
			brfile.close();
			
			for (String s : table.getKeysByCount()) {
				int count = table.get(s);

				bwfile.write(s);
				bwfile.newLine();
			}
			bwfile.close();
			return table;
		}
}
```
複数回キーワードが出現するシーケンスを塊で取得する(Linq)

##目的

１ファイルの中に特定の文字列をキーワードにして、取得を行いたい。。。
キーワードが1つだけなら、SkipWhile()拡張メソッドで対応できるけど、キーワードが複数回出現する場合だと対応できなくなってしまうので、それなら作ってしまおうということで作ってみた。

#使用環境
言語 : C#


##実際のソース

```c#:IoUtil.cs
using System;
using System.Collections.Generic;
using System.Linq;

    public static class IoUtil
    {
        /// <summary>
        /// キーワードが出てきたら次のキーワードが出てくるまでのシーケンスを返す
        /// </summary>
        /// <param name="fileText">入力ソース</param>
        /// <param name="keyword">キーワード</param>
        /// <returns>キーワードの行を除いたシーケンス</returns>
        public static IEnumerable<IEnumerable<string>> RepeatSkipToKeyword(this IEnumerable<string> fileText, string keyword)
        {
            // データがなければ終了
            if (!fileText.Any())
            {
                yield break;
            }

            while (fileText.Any())
            {
                var text = fileText.SkipWhile(x => !x.Contains(keyword)).Skip(1);
                var targetText = text.TakeWhile(x => !x.Contains(keyword));
                yield return targetText;
                fileText = text.SkipWhile(x => !x.Contains(keyword));
            }
        }
    }

```

これで、一応キーワードが出現したところから次のキーワードまでを取得することができたので、サンプルも書いてみる。

##実際に動かしてみた

```c#:Program.cs
using System;
using System.Collections.Generic;
using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            var stringList = new List<string>();
            string keyword = "keyword";

            stringList.Add("hoge");
            stringList.Add(keyword);
            stringList.AddRange(Enumerable.Range(1, 10).Select(x => x.ToString()));
            stringList.Add(keyword);
            stringList.AddRange(Enumerable.Repeat("これはサンプル", 13));
            stringList.Add(keyword);
            stringList.Add("hoge");

            Console.WriteLine($"{new string('-', 30)}そのまま表示{new string('-', 30)}");
            foreach (var oneLine in stringList)
            {
                Console.WriteLine(oneLine);
            }

            Console.WriteLine($"{new string('-', 30)}使ってみた時の表示{new string('-', 30)}");
            foreach (var oneLine in stringList.RepeatSkipToKeyword(keyword).SelectMany(x => x))
            {
                Console.WriteLine(oneLine);
            }

        }
    }

```

サンプルを使用したときの戻り値はシーケンスで取得されるので、SelectMany()拡張メソッドを使用して平坦化した。
実行するとこんな感じ

```text:output.txt
------------------------------そのまま表示------------------------------
hoge
keyword
1
2
3
4
5
6
7
8
9
10
keyword
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
keyword
hoge
------------------------------使ってみた時の表示------------------------------
1
2
3
4
5
6
7
8
9
10
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
これはサンプル
hoge
```

こんな感じで、foreachで回すことができる。
numpy > savetxt() > リスト(一次元のデータ)を書き出す > 要素ごとの改行を抑制する > np.newaxisを使う

```txt:動作環境
GeForce GTX 1070 (8GB)
ASRock Z170M Pro4S [Intel Z170chipset]
Ubuntu 16.04 LTS desktop amd64
TensorFlow v1.1.0
cuDNN v5.1 for Linux
CUDA v8.0
Python 3.5.2
IPython 6.0.0 -- An enhanced Interactive Python.
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
```

### v0.1 

```test_savetxt_170729a.py
import numpy as np

res = np.random.rand(5)

print(res)

OUT_FILE = 'test_170729a.txt'

np.savetxt(OUT_FILE, res, fmt='%.3f')

```

```txt:run
$ python3 test_savetxt_170729a.py 
[ 0.81387563  0.26052892  0.17297069  0.00281516  0.72174926]
$ cat test_170729a.txt 
0.814
0.261
0.173
0.003
0.722
```

勝手に改行がつく。

### v0.2 > 成功

参考: https://stackoverflow.com/questions/33716509/numpy-savetxt-saving-every-element-on-new-line
jmeさんの回答を参考にして、np.newaxisを指定する方法を使いました。

```test_savetxt_170729a.py
import numpy as np

res = np.random.rand(5)

print(res)

OUT_FILE = 'test_170729a.txt'

np.savetxt(OUT_FILE, res[np.newaxis], fmt='%.3f')

```

```txt:run
$ python3 test_savetxt_170729a.py 
[ 0.54185518  0.71771867  0.27951855  0.97966931  0.29287969]
$ cat test_170729a.txt 
0.542 0.718 0.280 0.980 0.293
```

### 過去の記事

4月末に似たようなことしていた。

[numpy > savetxt() > 1次元のデータ書き出しは、各要素に改行が入る > 2次元にする](http://qiita.com/7of9/items/36c6f6a5cb90afc20dda)

解決方法は今回のものと少し違う。
ChoregrapheでつくるPepperアプリで自分自身のバージョンを取得する


# 事情というか経緯
今、Pepper for Biz向けの野良アプリを複数ユーザさんに使ってもらっています。
野良アプリなので、[ロボアプリマーケット for Biz](http://bizapp.robot.softbank.jp/)が使えません。
ユーザさんたちへの実行ファイル配布は、Choregrapheでパッケージファイルを作成し、各ユーザさんに送付し、各ユーザさんたちがChoregrapheでPepperにインストール、という作業フローになっています。

で、自分自身がユーザだったら、と思うととても良くわかるのですが、利用者さんたちにとって「どのバージョンをインストールしたか」なんてどうでもいいというか特に意識しないので(それが正しいです)、何かトラブルが起きたときとかに「どのバージョン使ってます？」と聞いてもわからないわけです。

…というような事情で困ってますー、という内容をFacebookのグループでつぶやいたところ、ナイスなやり方を教えていただいた上にサンプルコードまで頂いちゃいました。
公開グループではあるんですが、FacebookのグループってGoogle先生に拾ってもらえたっけ？というあたりが微妙なので、Qiitaに書いておこうと思った次第です。



# ベースになるソース
ChoregrapheでPythonボックス作って、

```
    def onInput_onStart(self):
        #self.onStopped() #activate the output of the box
        pass

```

のところを下記のように書き換えたら、とりあえずログに出力されます。

```
    def onInput_onStart(self):
        import os
        import xml.etree.ElementTree as ET
        aPath = self.behaviorAbsolutePath()
        rPath = self.behaviorRelativePath()
        if rPath == ".":
            appFolder = aPath
        else:
            appFolder = aPath.replace(rPath, "")
        appPath = os.path.join(appFolder,"manifest.xml")
        tree = ET.parse(appPath)
        root = tree.getroot()
        myVersion = root.attrib["version"]
        self.logger.info(myVersion)
        self.onStopped()
        pass

```

やっていることは、自分自身のパスから manifest.xml の場所を生成して、そのファイルをXMLとして読み込んでバージョン情報を参照してログに書き出す、という流れとなります。

なお、manifest.xmlの中身はこんな感じになります。xxxxxのところにアプリ名、yyyyyのところにUIDが振られています。

```
<?xml version='1.0' encoding='UTF-8'?>
<package version="0.0.0" uuid="xxxxx-yyyyy">
 <names>
  <name lang="en_US">Untitled</name>
 </names>
 <supportedLanguages>
  <language>en_US</language>
 </supportedLanguages>
 <descriptionLanguages>
  <language>en_US</language>
 </descriptionLanguages>
 <contents>
  <behaviorContent path="hoge">
   <userRequestable/>
   <nature>interactive</nature>
   <permissions/>
  </behaviorContent>
 </contents>
</package>
```

Choregrapheの画面でいえばこの情報となります。

![Kobito.VJ0V1e.png](https://qiita-image-store.s3.amazonaws.com/0/35808/c862132b-a59f-07a2-cfa8-229e1dca0f09.png "Kobito.VJ0V1e.png")


# ロボットライブラリにアップしました

上記のソースをベースに、ちょっとだけ手を入れてボックスにしたものを[ロボットライブラリ](https://robo-lib.com/repositories/summary/120) にアップしました。

![Kobito.qNGUWu.png](https://qiita-image-store.s3.amazonaws.com/0/35808/e82d372d-2c8f-96a3-6a46-b8a808b29654.png "Kobito.qNGUWu.png")

こちらは、プロジェクトに追加して、onStartに入力があると上記と同じ方法でバージョン番号を取得します。スパナアイコンをクリックしてメモリの名前を指定でき、取得したバージョン番号はこのメモリに保存されます。また、文字列として出力する口もつけてみたので、すぐに使うときはここから直接取り出すことも出来ます。




# 余談 (マイアプリ登録の罠)

「ロボアプリ配信管理」の「マイアプリ」のところ、野良アプリをアップロードして管理下にあるPepperに配信できる便利機能なのですが、同じロボアプリ名で複数のSBRアカウントからの登録ができません。

たとえば、Aというアカウントでマイアプリ登録したのと同じロボアプリは、Bというアカウントでアプリ登録しようとすると下記のように怒られます。

![Kobito.rJMfGc.png](https://qiita-image-store.s3.amazonaws.com/0/35808/dfe67e05-5818-7d7a-0981-a561d1da1721.png "Kobito.rJMfGc.png")

それこそ manifest.xml の内容をごにょごにょすれば回避できそうな気もしますがそれもねぇ…。

何の情報もなく「エラーが発生しました」としか出てこないので、この問題に気づくのに時間かかりました💦
UMLの基本

## UMLとは
Unified Modeling Languageの略で、設計においてシステムをモデル化する際の記法を規定した言語のこと。
言語とあるが、広く捉えれば、「意図を表現し，伝達し， 記録するもの」と考えれば納得。

#### UMLを使うことによるメリット
- 自分の考えの整理することができる
 
- チーム間でのプログラムの構造や動きを（言葉で説明するより）共有しやすくなる

以下、よく使われるダイアグラム

| ダイアグラム |内容  |目的|
|---|---|---|
|クラス図  |静的なクラス間相互関係を表現  ||
|ユースケース図 |動的なシステムの境界，使用機能を定義  |エンドユーザー視点でみるため、要求に対する相互の理解を保証することができる。<br> システムの外部と内部との境界を明確にさせる。|
|シーケンス図 |オブジェクト間の連携や動作の流れを表現するダイアグラム ||

### クラス図
・集約とコンポジションは、どちらも双方のオブジェクト間に「全体-部分」の関係が成り立っているが、「全体-部分」において双方が存在して初めて成り立つような関係のときにコンポジションが利用される。（言い換えるなら、集約よりもコンポジションの方が結びつきが強い）

・矢印の向きに注意
#### クラス図のルール
以下のサイトがわかりやすかったのでメモ
http://www.itsenka.com/contents/development/uml/class.html
numpy > genfromtxt() > 先頭行をスキップ > skip_header

```txt:動作環境
GeForce GTX 1070 (8GB)
ASRock Z170M Pro4S [Intel Z170chipset]
Ubuntu 16.04 LTS desktop amd64
TensorFlow v1.1.0
cuDNN v5.1 for Linux
CUDA v8.0
Python 3.5.2
IPython 6.0.0 -- An enhanced Interactive Python.
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
```

参考: https://docs.scipy.org/doc/numpy/reference/generated/numpy.genfromtxt.html

genfromtxt()を使って読込するときに先頭行をスキップするにはskip_headerを使う。

データファイル

```sample_170729a.txt
1 1 1 
2 2 2
3 3 3
4 4 4 
5 5 5
```

```test_genfromtext_170729.py
import numpy as np

INPFILE = 'sample_170729a.txt'

dat = np.genfromtxt(INPFILE, delimiter=' ',
                    skip_header=2)
for elem in dat:
    print(elem)

```

```txt:run
$ python3 test_genfromtext_170729.py 
[ 3.  3.  3.]
[ 4.  4.  4.]
[ 5.  5.  5.]
```
CSVから PostgreSQL Upsert SQL を生成するVBAコード

# Upsert SQL を生成するVBA

- PostgreSQL version 9.5 から Upsert が使える
    - 参考 : http://www.oss-db.jp/measures/dojo_21.shtml
- Upsert = INSERT して キーがかぶったら UPDATE （便利！）
- 文法は  INSERT ~ ON CONFLICT ~ DO UPDATE
- でも update 対象の列はすべて指定しないといけない（めんどう）

ということで、投入するCSVの文字列からUPSERTするSQLを生成しちゃおうという話。
※CSVから取り込んだり、PostgreSQLへ接続してSQL発行するのは別に用意が必要ですのであしからず。

# 具体例

こんな感じの配列から・・・

| user_name  | user_email       | user_address    |
|------------|------------------|-----------------|
| test_user  | test@example.jp  | Tokyo           |

テーブル
- テーブル名: sample_table
- キー : sample_pkey
に投入するためにこんな感じのSQLをつくる。

```sample.sql
     INSERT INTO sample_table(
      user_name, user_email, user_address
     )
     VALUES (
      test_user, test@example.jp, Tokyo
     )
     ON CONFLICT ON CONSTRAINT sample_pkey DO UPDATE
     SET  user_name = EXCLUDED.user_name
      ,  user_email = EXCLUDED. user_email
      ,  user_address = EXCLUDED. user_address
```


# 使い方

```sample.bas
Sub test___BuildUpsertSql()

  Dim res As String
  res = BuildUpsertSql("sample_table", _
                                    "sample_pkey", _
                                    "user_name, user_email, user_address", _
                                    "test_user, test@example.jp, Tokyo")
End Sub
```



# コード本体

```upsert.bas
'#-----------------------------------------------------------------------------
'# Build  INSERT OR UPDATE SQL  for PostgreSQL
'#-----------------------------------------------------------------------------
Function BuildUpsertSql(sTable As String, _
                                      sTableKey As String, _
                                      sHeaders As String, _
                                      sValues As String) As String

  Dim aHeaders() As String
  Dim sUpdValues As String

  aHeaders = Split(sHeaders, ",")
  sUpdValues = ""

  '# head: | a | b | c | d |
  '# =>    a = EXCLUDED.a , b = EXCLUDED.b , c = EXCLUDED.c , d = EXCLUDED.d
  Dim h As Long
  For h = LBound(aHeaders) To UBound(aHeaders)
    If h <> LBound(aHeaders) Then sUpdValues = sUpdValues & "  ,"
    sUpdValues = sUpdValues & " " & aHeaders(h) & " = EXCLUDED." & aHeaders(h) & vbCrLf
  Next

  Dim sSql As String
  sSql = " INSERT INTO $_TABLE_$( " & vbCrLf
  sSql = sSql & "  $_HEADERS_$ " & vbCrLf
  sSql = sSql & " )" & vbCrLf
  sSql = sSql & " VALUES (" & vbCrLf
  sSql = sSql & "  $_VALUES_$ " & vbCrLf
  sSql = sSql & " )" & vbCrLf
  sSql = sSql & " ON CONFLICT ON CONSTRAINT $_KEY_$ DO UPDATE " & vbCrLf
  sSql = sSql & " SET " & sUpdValues

  sSql = Replace(sSql, "$_TABLE_$", sTable)
  sSql = Replace(sSql, "$_HEADERS_$", sHeaders)
  sSql = Replace(sSql, "$_VALUES_$", sValues)
  sSql = Replace(sSql, "$_KEY_$", sTableKey)

  BuildUpsertSql = sSql
End Function
```