OmniAICreator/Qiita-1.07M huggingface dataset:
OpenCV-Pythonのimreadはpathlibを受け付けない

Python3.4 から、 Pathlib が標準ライブラリとして搭載されました。
もう Python3.7が出たというのに、恥ずかしながら今まで Pathlib を使っていなかったので試してみました。

私は普段、 OpenCV-Python を使用して画像の読み出し、書き込みを行っていますが、
そのときに困ったのが、OpenCV-Python では、Pathlib を画像のパスとして入力できないことでした。  


#　起こった問題  

```python
from pathlib import Path
import matplotlib.pyplot as plt
import cv2

path = Path('images')
pngs = path.glob('*.png')
for p in pngs:
  png = cv2.cvtColor(cv2.imread(p), cv2.COLOR_BGR2RGB)
  plt.figure(figsize=(10, 10))
  plt.imshow(png)
  plt.show()
```

とすると、 `TypeError: bad argument type for built-in operation` というエラーが出てしまいます。  


# 解法1
`pillow` の `Image` を使って、  

```python
from pathlib import Path
import matplotlib.pyplot as plt
from PIL import Image

path = Path('images')
pngs = path.glob('*.png')
for p in pngs:
  png = Image.open(p)
  plt.figure(figsize=(10, 10))
  plt.imshow(png)
  plt.show()
```

とすると、うまく画像を読み出すことができました。  

# 解法2

`cv2.imread()`の引数の画像パスを、 `str()` で囲ってあげることによって読み出すことができました。
path.glob を for で回しても、その中身は、 `<class 'pathlib.PosixPath'>` になっていて、
OpenCV-Python が `pathlib`のオブジェクトを受け付けていないから起こっていた問題でした。  
ちなみに、pathlib の取り扱いについては、[こちらの記事](https://qiita.com/meznat/items/a1cc61edb1e340d0b1a2) がとても参考になりました！


```python
from pathlib import Path
import matplotlib.pyplot as plt
import cv2

path = Path('images')
pngs = path.glob('*.png')
for p in pngs:
  png = cv2.cvtColor(cv2.imread(str(p)), cv2.COLOR_BGR2RGB)
  plt.figure(figsize=(10, 10))
  plt.imshow(png)
  plt.show()
```

# まとめ

今まで(Python3.4より前)の記法で、  

```python
import glob
pngs = glob.glob('/data/*.png')
for p in pngs:
  png = cv2.cvtColor(cv2.imread(p), cv2.COLOR_BGR2RGB)
  plt.figure(figsize=(10, 10))
  plt.imshow(png)
  plt.show()
```

という風に書いていると怒られるということでした。
よしなに変換していきましょう！
【Python】フォルダ内のすべての画像に対してOpenCVで顔検出を行う

以前に投稿した記事です
[【Python】OpenCVの顔認証するときにとあるWebサイトを参考にしてつまった方、ご覧ください](https://qiita.com/blueHornet/items/2eda8432a6df4693be04)
【OpenCV】つながりで、今回はフォルダ内に無数にある画像データに対して
顔検出をかけるコードを掲載します。

書いてることは、以前の記事にFor文を追加しただけなので
大したことしてないです。

今回はデスクトップにpicというフォルダを作りその中に入っている画像を対象として実施します。
画像はフリー素材サイトからお借りしました。
![samplePic.PNG](https://qiita-image-store.s3.amazonaws.com/0/203445/28fce588-6d89-77bf-c1b4-e614dc8cb0fe.png)


実際のソースコードは以下となります。

```python:faceDetection.py
import cv2
import numpy as np
import glob

face_cascade = cv2.CascadeClassifier('C:\ProgramData\Anaconda3\pkgs\libopencv-3.4.1-h875b8b8_3\Library\etc\haarcascades\haarcascade_frontalface_alt.xml')
#要注意ポイント　ここでつまったら、以前の投稿をご覧ください。

#ディレクトリ名などは適切に書き換えてください
files =glob.glob("C:\\Users\\user\\Desktop\\pic\\*")
#picフォルダの後のアスタリスクがポイント
#ここでfilesにフォルダ内のファイル名が代入される
#フォルダ名などに日本語がなどが入っているとエラーになる可能性が高いです。半角英数字で対応してください。

for fname in files:    #あとはForで1ファイルずつ実行されていく
	bgr = cv2.imread(fname, cv2.IMREAD_COLOR)
	gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)
	face_rects = face_cascade.detectMultiScale(gray, 1.1, 3)
	if len(face_rects) > 0:
		for (x,y,w,h) in face_rects:
			cv2.rectangle(bgr, (x,y), (x+w,y+h), (255,0,0), 3)	
                        #(255,0,0)→枠の色は青
                        #最後の引数は太さ(-1にすると塗りつぶし)!
		cv2.imwrite(fname, bgr)	

cv2.destroyAllWindows()

```

前回と違うのは、顔の検出ができなかった場合、printで【no faces】表示をさせていましたが
省いています。

こちらをエディターなどにコピペ＆ディレクトリを編集し
Picフォルダ内でもいいですし、任意のフォルダに保存します。
コマンド画面で、カレントフォルダを先ほどソースコードを保存したファイルがあるディレクトリをしていし
以下のコマンドを実行

```cmd:コマンド画面
！ディレクトリをご自身のディレクトに合わせてください！
C:\Users\user\Desktop\pic> Python faceDetection.py
```



実行結果
![samplePic2.PNG](https://qiita-image-store.s3.amazonaws.com/0/203445/3267d626-17ee-ef78-4e8b-bc08b93a4431.png)



1つだけ認識されなかったものがあります。
白い中に顔があったりすると認識が悪くなる傾向があるようです。




face_cascadeへはhaarcascade_frontalface_alt.xml以外に別のものを代入、検出することができます。
OpenCVには予めHaar-like特徴分類器がいくつか用意されています。
(以下はその一部です)

| ファイル名      |      内容 | 
|:-----------------|:------------------|
| haarcascade_eye.xml |目 |
| haarcascade_smile.xml |笑顔 |
| haarcascade_fullbody.xml|全身 |
| haarcascade_upperbody.xml|上半身 |
|haarcascade_lowerbody.xml |下半身|


Haar-like特徴分類器に関してちょっとイミフって方は以下のリンクをご覧になってください。
[Slideshare 図が多くて分かりやすい](https://www.slideshare.net/MPRG_Chubu_University/ss-32258845)
[百聞より一見 haar-like特徴分類器可視化動画](https://vimeo.com/12774628)

もちろん検出以外のいろいろな用途でOpenCVは使われていますし、
[オライリー](https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3-OpenCV-%E2%80%95%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%83%93%E3%82%B8%E3%83%A7%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86%E3%83%BB%E8%AA%8D%E8%AD%98-Gary-Bradski/dp/4873118379/ref=sr_1_1?ie=UTF8&qid=1536719173&sr=8-1&keywords=OpenCV)からは鈍器のような分厚くデカい専門書籍も出版されています。

もし認識した部分を塗りつぶしたい(マスク加工)のであれば
cv2.rectangle(bgr, (x,y), (x+w,y+h), (255,0,0), 3)
を
cv2.rectangle(bgr, (x,y), (x+w,y+h), (255,255,255), -1)
に
変更すればできますし、
モザイク加工など、画像で遊んでみるにはうってつけです。

出来たら近所に住んでるおばちゃんとかに
「人工知能の開発とかできるんだぜ～」って自慢してみるのもいいかもしれません。
これもれっきとした人工知能プログラムを使った作業なのです。


【参考資料】(SpecialThanks)
[Python + OpenCV で顔検知のWebサイト](https://www.kunihikokaneko.com/dblab/improc/facedetect.html)
Systems Manager(SSM) のセッションマネージャー機能を試してみた

## はじめに
社内の Slack で、この URL が流れてきたので、試してみた
https://dev.classmethod.jp/cloud/aws/ssm-session-manager-release/

## SSM について
ざっくりいうと、パッチの適用とか、コマンドの実行とかを GUI からポチポチできちゃう機能
https://aws.amazon.com/jp/systems-manager/

## 試してみた
Amazon Linux 2 で試してみた
↓がその画面

![image_20180912_11.50.29.png](https://qiita-image-store.s3.amazonaws.com/0/269938/c7078d04-76ee-c4a2-b868-e143f44693cc.png)

- ブラウザのリロードをすると、新しいセッションが始まる
- コピーペーストは、マウスの右クリックからできた
- あとはクラスメソッドの[記事](https://dev.classmethod.jp/cloud/aws/ssm-session-manager-release/)を読めばいいと思う

なぜか、SSH でログイン出来なくなったとか、緊急時に備えて導入しておくのはアリかと。

## 仲間募集中
[弊社](https://www.nittsu-infosys.com/)ではエンジニアを募集中です。インフラからアプリ、ユーザサポートまで幅広く業務を行ってます。
https://www.nittsu-infosys.com/recruit/2019/index.html
Ruby — eval の変数代入を main に反映させる



## 例

```ruby
#!/usr/bin/env ruby

alice = nil

binding.eval('alice = "liddle"')

p alice # "liddle"
```

## Ref

- [Class: Binding (Ruby 2.4.2)](https://ruby-doc.org/core-2.4.2/Binding.html)

## Versions

- ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-darwin16]

## Links

- [Gist](https://gist.github.com/YumaInaura/cb408345413bbe789f2fa277d91efe1d)
- [Medium—Imported](https://medium.com/supersonic-generation/ruby-set-variable-with-eval-to-main-704efdac730)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
cookieでvuexのstoreをリロードしても維持する方法

vuexを使って開発してると、リロードした時にstateの値がリセットされちゃって辛いことがある。

それを解決するために、一時的にstateの値をcookieやlocal storageに格納し、それがあればその値を取ってくるみたいな処理を書く必要がある。

それなりにめんどくさい。

vuex-persistedstateを使えば、stateの値をcookieやLocal storageに保存できる。

pluginsに読み込めばLocal Storageに保存してくれるようになる。
https://www.npmjs.com/package/vuex-persistedstate


```
import Vue from "vue";
import Vuex from "vuex";
import createPersistedState from 'vuex-persistedstate'
 
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState()]
})
```

## ただしcookieに保存する場合は容量を考慮する必要がある。

[【PHP】Cookieの検証 (保存出来る最大サイズを調べたり、圧縮した文字列をセットしてみたり)をしてみた – 2016年5月](https://blog.shimabox.net/2016/05/15/php_verify_cookie/)

上の記事を読んだところ4095byteを越えるとよくないことが起こる。

僕の場合はstateの値を登録してるつもりがスルーされていた。

4095byteを超えないように、vuex-persistedstateの`reducer`を使って、保存したいstateの値を明示してあげる。

```
import Vue from "vue";
import Vuex from "vuex";
import createPersistedState from 'vuex-persistedstate'
import Cookies from "js-cookie"
 

const options = {
  reducer: state => ({
    hoge: state.hoge,
    fuga: state.fuga
  }),
  storage: {
    getItem: key => Cookies.get(key),
    setItem: (key, value) => Cookies.set(key, value, { expires: 365 }),
    removeItem: key => Cookies.remove(key)
  }
}

const store = new Vuex.Store({
  // ...

  plugins: [createPersistedState(options)]
})
```
[解決]AVPlayerでリモートの音声ファイルを再生しようとしてエラー

2016年1月に作ったアプリを久しぶりに起動したらAVPlayerが再生に失敗する
びっくりして直そうとしました

## エラー内容

```
CredStore - performQuery - Error copying matching creds.  Error=-25300, query={
    class = inet;
    "m_Limit" = "m_LimitAll";
    "r_Attributes" = 1;
    sync = syna;
}
```

## 調べたら同じことになっている人がちらほら

https://stackoverflow.com/questions/48384256/credstore-performquery-error-copying-matching-cred-error-when-opening-vim

https://stackoverflow.com/questions/46434004/cant-play-mp3-file-over-http-via-avplayer

## ドハマリした

いろいろやりましたが、どうにも解消できず。深夜3時まで頑張ったんだよー。
次の日も仕事だから寝た。
stack overflowでも最終的にどうにもなってなくて悲しみ
会社の昼休みにサーバーサイドじゃね？ってなってやってみたら動いた。よし！

## レスポンスヘッダーからHSTSとったら動きました。

h2oですけど以下のやつね。

```
header.add: "Strict-Transport-Security: max-age=31536000"
```

## 原因がわからない

原因はわからないです。とりあえず動いたので良いのですが、いつ動かないくなるかわからないので不安です。

以上です。よろしくお願い申し上げます。
Statspackを読み解くヒント（番外編）

> Statspackにはいくつか不具合があるので、参考までに紹介します（詳細は[MOS](https://support.oracle.com/)参照）。 適宜アップデートしていきます。

### 新しいアイドル・イベントが誤って STATSPACK レポートに表示される (ドキュメントID 2106498.1)

12cから新規に追加されたいくつかのアイドル・イベントが以下のサンプルのSTATSPACKレポートのように上位待機イベントとして表示されてしまいます。リリース12.2以降で修正されています。

```text:sample-statspack-report
Top 5 Timed Events                                                    Avg %Total
~~~~~~~~~~~~~~~~~~                                                   wait   Call
Event                                            Waits    Time (s)   (ms)   Time
----------------------------------------- ------------ ----------- ------ ------
AQPC idle                                          120       3,601  30009   33.1
heartbeat redo informer                          3,600       3,600   1000   33.1
lreg timer                                       1,199       3,599   3002   33.1
CPU time                                                        45            .4
direct path read                                52,957          11      0     .1
          -------------------------------------------------------------
```
EC2にSplunkをサクっと立ててみる

#　内容
Splunkをちょっと試す必要があったので初期設定メモを残しておく。
あくまでメモ
サクッと試すだけならマーケットプレイスから立てれば良い

# 手順

```shell:変数
INSTALL_FILE="splunk-7.1.2-a0c72a66db66-Linux-x86_64.tgz"
WGET_URL="https://www.splunk.com/bin/splunk/DownloadActivityServlet?architecture=x86_64&platform=linux&version=7.1.2&product=splunk&filename=splunk-7.1.2-a0c72a66db66-Linux-x86_64.tgz&wget=true"
PASSWD="HogeHoge1234!"
DOMAIN_NAME="<ドメイン名>"
MAIL="<メールアドレス>"
```

```shell:実行
# 環境変数にSplunkのHOMEを設定
export SPLUNK_HOME="/opt/splunk"

sudo yum update -y

# ユーザー・グループ作成
sudo groupadd -g 501 splunk
sudo adduser -u 501 -g 501 splunk

#　Splunkの取得
wget -nv -O ${INSTALL_FILE} ${WGET_URL}
sudo tar zxf /home/ec2-user/$INSTALL_FILE -C /opt/
sudo chown -R splunk:splunk /opt/splunk

# 設定
sudo -u splunk /opt/splunk/bin/splunk start --accept-license --answer-yes --seed-passwd ${PASSWD}
sudo -u splunk /opt/splunk/bin/splunk set default-hostname $(hostname) -auth admin:${PASSWD}
sudo -u splunk /opt/splunk/bin/splunk set servername $(hostname) -auth admin:${PASSWD}
sudo /opt/splunk/bin/splunk enable boot-start -user splunk

# 再起動
sudo -u splunk /opt/splunk/bin/splunk restart

# 証明書取得(letsencrypt)
git clone https://github.com/certbot/certbot.git
cd certbot
sudo ./certbot-auto certonly –domain ${DOMAIN} –email ${MAIL} –no-bootstrap –debug

#　証明書の設定
sudo -u splunk mkdir -p $SPLUNK_HOME/etc/auth/webcerts
sudo cp /etc/letsencrypt/live/${DOMAIN}/cert.pem $SPLUNK_HOME/etc/auth/webcerts/
sudo cp /etc/letsencrypt/live/${DOMAIN}/privkey.pem $SPLUNK_HOME/etc/auth/webcerts/
sudo chown -R splunk:splunk /opt/splunk/etc/auth/webcerts/

# web用証明書の設定
echo "[settings]" | sudo tee -a $SPLUNK_HOME/etc/system/local/web.conf
echo "enableSplunkWebSSL = 1" | sudo tee -a $SPLUNK_HOME/etc/system/local/web.conf
echo "serverCert = $SPLUNK_HOME/etc/auth/webcerts/cert.pem" | sudo tee -a $SPLUNK_HOME/etc/system/local/web.conf
echo "privKeyPath = $SPLUNK_HOME/etc/auth/webcerts/privkey.pem" | sudo tee -a $SPLUNK_HOME/etc/system/local/web.conf
sudo chown -R splunk:splunk $SPLUNK_HOME/etc/system/local/web.conf

# HTTP経由でログを送信するための証明書設定
sudo -u splunk mkdir $SPLUNK_HOME/etc/auth/kinesiscert
sudo cat ./cert.pem \
    ./privkey.pem \
    ./chain.pem | sudo tee $SPLUNK_HOME/etc/auth/kinesiscert/server.pem
sudo chown -R splunk:splunk /opt/splunk/etc/auth/kinesiscert/server.pem
sudo -u splunk mkdir $SPLUNK_HOME/etc/apps/splunk_httpinput/local
sudo -u splunk sh -c "cat << _FIN_ >> $SPLUNK_HOME/etc/apps/splunk_httpinput/local/inputs.conf
[http]
disabled = 0
serverCert = $SPLUNK_HOME/etc/auth/kinesiscert/server.pem
_FIN_"

# 再起動
sudo -u splunk /opt/splunk/bin/splunk restart
```

KHFとの連携用にSplunkを立てたときのメモ。
あくまで自分メモ
WebのLGTM画像メイカーなら addtext.com がおすすめ

## サイト

https://addtext.com/

## 良いところ

- Webサービスだ
- 操作が簡単
- 文字サイズ・位置などを調整可能
- LGTM以外の文字も入れられる

## 悪いところ

- 動作は遅め
- 設定を記憶してくれないので、毎回フォントサイズや文字を選び直す必要がある


## 元画像

以下を利用

[表情が豊かな人のイラスト（男性） | かわいいフリー素材集 いらすとや](https://www.irasutoya.com/2016/11/blog-post_751.html) 

## アップロード

Mac ならクリップボードの画像を `Command+V` でもOK。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/5eb35ebb-a0b7-7733-2522-337f8384fc02.png)

## 調整

- 文字
- 文字サイズ
- 位置

などを調整する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/1a146512-7067-b983-7072-d152b5f2fb1a.png)

## ダウンロード


![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/2150b2e3-c1ca-2581-ba26-2c48c54dff9c.png)

## 結果

無料版だとロゴが入る模様

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/685dcdf6-e68c-6061-a289-63d23b62570b.png)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
JavaScriptのオブジェクトって難しすぎませんか…？

たぶん書き方が悪いだけだと思いますが、不可解な現象に出くわしたのでメモ。

# 実装したコード

```js:JavaScript
var API = API || {};
API.getRequestBody = function() {
    var body = {
      "customer" : {
        "companyName" : {
          "kanji" : Data.customer.companyName.kanji,
          "kana" : Data.customer.companyName.kana
        }
      }
    };

    return body;
}


var Data = Data || {};
Data.customer = {};
Data.customer.companyName = {};
Data.customer.companyName.kanji = '株式会社○○';
Data.customer.companyName.kana = 'カブシキガイシャマルマル';
console.log(Data);// 1


var body = API.getRequestBody();
console.log(body);// 2


var customer = {
  "companyName" : {
    "kanji" : 'あああああああああああああ',
    "kana" : 'いいいいいいいいいいいい'
  }
};
console.log(customer);// 3

customer.companyName.kanji = 'xxxxxxxxxxxxxxx';
customer.companyName.kana = 'yyyyyyyyyyyyyyy';
body.customer = customer;
console.log(body);// 4


var body = API.getRequestBody();
console.log(body);// 5

```

# console.log()の出力結果

console.log()の後ろにコメントで番号を振ってあります。
それぞれの出力結果を御覧ください。

## 1
```:consoel.log()
customer : {
  companyName : {
    kana : "カブシキガイシャマルマル",
    kanji : "株式会社○○"
  }
}
```
まぁ、想定通りですね。


## 2
```:consoel.log()
customer : {
  companyName : {
    kana : "yyyyyyyyyyyyyyy",
    kanji : "xxxxxxxxxxxxxxx"
  }
}
```
えぇっ！？何で書き換わってるんですか？下の行はまだ実行されてませんよね？？


## 3
```:consoel.log()
customer : {
  companyName : {
    kana : "yyyyyyyyyyyyyyy",
    kanji : "xxxxxxxxxxxxxxx"
  }
}
```
えぇっ！？変数宣言しただけなのに何で書き換わってるんですか？？


## 4
```:consoel.log()
customer : {
  companyName : {
    kana : "yyyyyyyyyyyyyyy",
    kanji : "xxxxxxxxxxxxxxx"
  }
}
```
まぁ、想定通りですね。

## 5
```:consoel.log()
customer : {
  companyName : {
    kana : "カブシキガイシャマルマル",
    kanji : "株式会社○○"
  }
}
```
えぇっ！？何で戻っちゃったんですか？？


# まとめ
JavaScript難しすぎる…。
[トラブルシューティング]ScanSnap iX500 WiFi自動接続できない（ネットワークプロファイルをパブリックにして解決）

パソコンを変更したところ、ScanSnap iX500にWifi自動接続できなくなりました。（手動でのWiFi接続/読み取りは問題なし）
[メーカー公式サイトのFAQ](http://faq.pfu.jp/category/search?id=1&keyword=Wi-Fi%E6%8E%A5%E7%B6%9A&site_domain=scansnap&commit=)を検索しても該当する症状・対処が記載されていませんでした。
結局、サポートに問い合わせて解決しました。

同じ症状でお悩みの方もいらっしゃるかと思いますので共有します。（そのうち公式サイトのFAQにも記載されるのではないかと思いますが。）

# 症状

- ScanSnap iX500にWifi自動接続できない
- 手動操作によるWiFi接続と読み取りは問題ない
- 接続オプションの「以前接続したScanSnapと自動的にWi-Fi接続する」にはチェックしている

![Wi-Fi接続ダイアログ](https://i.gyazo.com/28b0b16a4d8d3059ded8606956fcef1d.png)

# 当方の環境

- Windows 10 Professional 64bit
- ScanSnap iX500
- ScanSnap Manager 6.5 L61

# 原因と解決策

ネットワークプロファイルが「パブリック」になっていたためでした。
「プライベート」にすることで解決しました。

![ネットワークプロファイル](https://i.gyazo.com/991d4ce1327365b1cc87ef96dd3aa082.png)

# 付録（詳細手順）

サポートからの回答を抜粋編集しました。

## ネットワーク設定画面を表示
[スタート]-[設定]-[ネットワークとインターネット]とたどります。

## ネットワーク表示
パソコンのインターネットへの接続方法が有線LANの場合は左側の[イーサネット]をクリックします。
無線LANの場合は左側の[Wi-Fi]をクリックします。

## ネットワークプロファイル表示
右側に接続済みのネットワーク名が表示されますのでダブルクリックします。

![](https://i.gyazo.com/392143357516ef31ea3258aac2de2d84.png)

## ネットワークプロファイル変更
[ネットワークプロファイル]の項目で[パブリック]が選択されている場合は[プライベート]に変更します。

![](https://i.gyazo.com/991d4ce1327365b1cc87ef96dd3aa082.png)

## 動作確認（Wi-Fi手動接続）
iX500の電源が入っている状態で時刻表示付近または隠れているインジケーター内に存在するScanSnap ManagerのSのアイコンがグレーかWi-Fi接続状態なのかを確認します。

ScanSnap Manager のSのアイコンがグレーの場合は右クリックして[Wi-Fi接続]をクリック後、
「以前接続したScanSnapと自動的にWi-Fi接続する」にチェックが入っていることを
もう一度確認してから表示されたScanSnap名の右側の[接続]ボタンをクリックしてWi-Fi接続します。

![](https://i.gyazo.com/28b0b16a4d8d3059ded8606956fcef1d.png)

## 動作確認（Wi-Fi自動接続）
一度iX500の給紙カバーを閉じて電源を切り、
10秒程度経過してから再度、給紙カバーを開いて電源を入れ、
ScanSnap ManagerのSのアイコンが自動的にWi-Fi接続されることを確認
pythonとEmbulkで複数データソース横断のにわかETLを作る

最近、TreasureDataと自社のDBのデータを合わせた集計をバッチ処理することが多くpythonでいったんcsvに書き出してEmbulkでアップロードしていましたが、データソースが増えると面倒になっていくのでより簡単で汎用化した書き方を考えました。
結局はWF使ってやったらいい話なので需要があるか不明ですが、WF勉強するのも時間がかかるので慣れてる言語でてっとり早くETLを作りたい人向けの内容です。

# 前提条件
## この記事が適している人
- 普段はpythonを書いているのでなるべくその範囲でETLしたい
- pandas-tdの動きが不安定すぎて使えない
- シェルでの実現方法を調べる時間もない

##  達成したい機能
- SQLさえ作ればバッチを追加できるETLの箱を作る
- 入出力のテーブルが変わっても手間がかからない
- 記述した順番に処理が実行され、進捗が通知される

# 環境の準備
## Embulkのインストール
すでに存在するTipsで詳しく説明されています。
![Embulkをインストール](https://qiita.com/reflet/items/be31629735db210ae0d1)

## Embulk用プラグインのインストール
input用とoutput用でプラグインが分かれています。インストールは以下のようなコマンド一発で簡単です。

```sh:
$ embulk gem install embulk-input-td
```
今回はPostgreSQLからinputしてtdにoutputしたいのでembulk-output-postgresqlを入れました。
こちらからプラグインを探すことができます。
![Embulk(エンバルク)プラグインのまとめ](https://qiita.com/hiroysato/items/da45e52fb79c39547f69)

# にわかETLの実装
## 取り込み設定yaml（liquid）の準備
変数で後から値変更できるようにした取り込み設定ファイルを作成します。プラグインのページにExampleがあるので基本そこをコピペして自分の環境に合わせます。

```yaml:load_sample.yml.liquid
in:
  type: postgresql
  host: 0.0.0.0
  user: user_name
  password: pass
  database: db_name
  query: |
    {{ env.sql }}
filters:
- type: add_time
  to_column: {name: time, type: timestamp}
  from_value: {mode: upload_time}
out: {type: td, apikey: xxxxxxxxx, endpoint: api.treasuredata.com,
  database: {{ env.o_db }}, table: {{ env.o_tbl }}, time_column: time, mode: append, default_timestamp_format: '%Y-%m-%d
    %H:%M:%S'}
```
### 動的変数の設定
{{ env.xxxx }}が動的な値になり環境変数から参照されます。後のpythonで環境変数の設定とEmbulkの呼び出しをすることになります。
ここではホストやID・PWは固定していますが、動的にしても良いですし、固定のパラメタでもログイン情報系は.bashrcか.bash_profileに変数登録しておけばpythonから渡さなくても自動で読み込まれますのでyamlを複数作る際のメンテナンス性およびセキュリティ向上につながります。

### スキーマ設定について
私の場合はoutputがTreasureDataだったのでスキーマ設定なしですが、普通のDBに出すときはout:パートにschemaを設定しないと、勝手にpublicに設定されテーブルが見つからないエラーになるので注意。


## ETL用pythonの準備
### 汎用部分の作成
```python:etl_batch.py
import os

def td2pg(o_db, o_tbl, sql):
	os.system('export o_db=' + o_db + ';export o_tbl=' + o_tbl + '; export sql="'+ sql.replace("\n", " ") + '"; embulk run /path_to_liquid_file/load_sample.yml.liquid')
```
yamlで設定する予定の動的変数はすべて追加してください。ここまで来ればあとはSQLを作って設定した関数を呼ぶだけです。

### ETL処理の記述
SQLと出力先DBなどの動的変数を指定して関数を呼ぶ処理を書いていくだけです。
どこかでエラーになった場合のために進捗をprintしておきます。

```python:etl_batch.py
# task1
sql = """
select * from tbl
"""
o_db = "output_db_name"
o_tbl = "output_tbl_name"
td2pg(o_db, o_tbl, sql)

print("task1 is done.")
```

## cronの登録（バッチ稼働させたい人用）
最後にcronで作ったpythonを定期実行する設定をします。
[クーロン(cron)をさわってみるお](https://qiita.com/katsukii/items/d5f90a6e4592d1414f99)

以下のようにメール送信設定をしておくと、実行時にEmbulkのログとprintした内容が送られてくるのでエラー時にどこまで進捗したか追うことができます。

```sh:
MAILTO="xxxx@example.com"
30 15 * * * /path_to_python_file/etl_batch.py
```
この例だと毎日15時30分にETLバッチが実行されることになります。

### yamlで.bashrcの環境変数を呼び出している場合
.bashrcに登録した変数を呼び出す場合は、python実行前に変数を有効化する記述が必要です。cronの登録ユーザーが自分であっても.bashrcだけだとエラーになり、フルパスで指定する必要があるので注意。

```sh:
MAILTO="xxxx@example.com"
30 15 * * * source /user_home/.bashrc; /path_to_python_file/etl_batch.py
```

#最後に
私はSQL内で動的に日付指定したかったので、pythonでdatetimeもimportして日付生成しています。シェルでもできると思いますが使い慣れた言語のほうが早いですし、途中にpythonのデータ加工を挟むこともできます。
あとは大きなデータでもEmbulkが勝手に分散処理してくれるのでメモリオーバーの心配もありません。
…とはいえpython使い以外には誰得な内容なので誰かのお役に立てれば幸いです。

以上
Javaで並列実行する際は、スレッドセーフに気を使わないとハマるお話

# はじめに
お仕事で、下記のような相談を受けました。
「なんかCompletableFuture使って並列処理してると、数十回～数百回に1回くらい、正しく値が返ってこない場合がある」

その時の対応をメモ書きしておきます。

# 問題
実行環境は、

 - JDK1.8 ( 8u181 )
 - dockerコンテナ上で実行 (alpine linux)

です。

下記のような処理があります。
CompletableFutureを利用し、並列的にsummaryItemに情報を格納しています。
`xxxAPI.search(number);` は、外部のAPIを呼び出してItemの情報を取得しています。
どこにバグが潜んでいるでしょうか？

```java
  public List<Item> search(int length) {
    //検索結果を保持する変数
    List<Item> summaryItem = new ArrayList<>(length);

    List<CompletableFuture<Void>> futures = new ArrayList<>(length);
    for (int i = 0; i < length; i++) {
      final int number = i;
      CompletableFuture<Void> f = CompletableFuture.runAsync(() -> {
        //外部APIを呼び出して、データの取得
        Item item = xxxAPI.search(number);
        summaryItem.add(item);
      }, pool);
      futures.add(f);
    }

    //全ての並列処理が終わるまで待機
    CompletableFuture<Void> all =
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[length]));
    all.join();

    return summaryItem;
  }
```

# 回答

下記処理の部分ですね。
※実行環境は関係ありません:yum:

```java
        summaryItem.add(item);
```

summaryItemは、java.util.ArrayListです。ArrayListは、 **スレッドセーフではありません。**
JavaDocを見てみましょう。

https://docs.oracle.com/javase/jp/8/docs/api/java/util/ArrayList.html
> **この実装はsynchronizedされません。**複数のスレッドが並行してArrayListインスタンスにアクセスし、それらのスレッドの少なくとも1つがリストを構造的に変更する場合は、外部でその同期をとる必要があります。構造的な変更とは、1つ以上の要素を追加または削除したり、基になる配列のサイズを明示的に変更したりする処理のことです。要素の値だけを設定する処理は、構造的な変更ではありません。これは通常、リストを自然にカプセル化する一部のオブジェクトでsynchronizedすることによって達成されます。そのようなオブジェクトが存在しない場合は、Collections.synchronizedListメソッドを使用してリストを「ラップ」するようにしてください。リストが誤ってsynchronizedなしでアクセスされるのを防ぐために、作成時に行うことをお薦めします。

しっかりと書いていますね。


# 対応

スレッドセーフなListを使う。もしくは、そもそもスレッドセーフな処理に変更する。
という形のアプローチで対応しました。

## スレッドセーフなListを使う

`java.util.concurrent` パッケージにちゃんと同期化されたリストがあります。こちらを使いましょう。

```java
List<Item> summaryItem = new ArrayList<>(length);
```

上記コードを、下記のように変えるだけで正常に動作するようになります。

```java
List<Item> summaryItem = new CopyOnWriteArrayList<>(length);
```

場合によっては、 `Collections.synchronizedList` を使う事で解決はしますが、iteratorを使う場合は、やはり自分で同期化が必要になります。


## スレッドセーフな処理に変更する

そもそも、java.util.function.Supplier形式で値を返すようにすれば良いです。
※私はこの方が好きです。summaryItemを長いスコープで利用しくなるからです。

```java
  public List<Item> search(int length) {
    // 検索の並列実行処理
    List<CompletableFuture<Item>> futures = new ArrayList<>(length);
    for (int i = 0; i < length; i++) {
      final int number = i;
      CompletableFuture<Item> f = CompletableFuture.supplyAsync(() -> {
        //外部APIを呼び出して、データの取得
        return xxxAPI.search(number);
      }, pool);
      futures.add(f);
    }

    // 検索結果の収集
    try {
      List<Item> summaryItem = new ArrayList<>();
      for (CompletableFuture<Item> f : futures) {
        summaryItem.add(f.get());
      }
      return summaryItem;
    } catch (ExecutionException | InterruptedException ex) {
      throw new RuntimeException(ex);//適当に書いてます。
    }
  }
```

ものすごい偶発的に発生しますし、Java APIのある程度の知識が無いと、問題が発見しにくいのがポイントですね。
テストコードも (大体) スルーしてしまいます。

こういった部分はデバッグ等よりもコードレビューを行う事が役立つと思います。


# もっとやりたいこと

CheckStyleじゃ多分発見できないけど、静的コード解析系のツールで問題を発見できそうな気がする。
今後探してみようと思います。
Welcartでカテゴリーごとにバナーを切り替える

WelcartBasicの子テーマを使ってカスタマイズの備忘録。
子テーマを作成後親テーマからコピペしたcategory.phpを編集します。

```php:category.php
<header class="page-header">
	<?php
    the_archive_title('<h1 class="page-title">', '</h1>');
    the_archive_description('<div class="taxonomy-description">', '</div>');
    ?>
</header> <!-- .page-header -->
```
ここを書き換えてきます。（画像は本家welcartBasicの公式デモより）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/289172/3cc02b0c-f43f-cc13-fb0f-57384bcaccf6.png)

```php:category.php
<?php
$cat = get_category( $cat );
$catslug = $cat->slug;
?>
<div id="cat_img">
	<img src="<?php echo get_stylesheet_directory_uri() ?>/img/category/<?php echo $catslug; ?>.jpg" alt="<?php single_cat_title(); ?>">
</div>
```
子テーマにimgというフォルダに更にcategoryというフォルダを作る。
（カテゴリーのスラッグと同じ名前）.jpgという画像を入れると反映されます。
スラッグが分からなかったらダッシュボードからカテゴリーで確認しましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/289172/1caab491-0086-0ee2-392e-9187e72456d7.png)
【Docker入門】公式Docsの「Get Started」を日本語で要約しながらやってみる（Part1）

## Dockerを学んでいる背景

- 機械学習を勉強する環境構築するのに便利そう
- API作ってDockerでデプロイする必要が出てきた


## なぜこの記事を書くのか

- Docker公式のdocsに「Get Started」という、チュートリアルパートがあるので、やってみることにした（ https://docs.docker.com/get-started/ ）
- 公式は英語で書かれているので、適当に読んでると中身が入ってこない
- そこで、日本語で要約しながら進めることにした


## Dockerのコンセプト

Dockerは開発者やシステム管理者がコンテナを使ってアプリケーションを開発、デプロイし、稼働させるためのプラットフォーム。

Linuxコンテナを使ってアプリケーションをデプロイすることを「コンテナ化する」と言う。

コンテナ化の人気が出てきているのは、以下のような特徴があるから。

- Flexible(柔軟)：どんなに複雑なアプリケーションでもコンテナ化できちゃう
- Lightweight(軽い)：コンテナはホストカーネルを共有・活用するから軽量設計
- Interchangeable(互換可能)：更新を即デプロイ可能
- Portable(どこでも使える)：ローカルで開発し、クラウドにデプロイ。そして、どこでも稼働する
- Scalable(拡張性)：コンテナのレプリカを拡張・自動でシェアして広めることができる
- Stackable(積み上げていける)：サービスを素早く積み上げていける

### イメージとコンテナ

#### イメージ：
コードやライブラリ、ランタイムなど、アプリケーションを稼働させるために必要なものを全て搭載した、実行可能なパッケージ。

イメージを稼働させることで、コンテナがローンチされる。

#### コンテナ：
コンテナはイメージのランタイムのインスタンス。イメージが稼働された時に、メモリに置かれる。

## コンテナと仮想マシンの違い

![image.png](https://qiita-image-store.s3.amazonaws.com/0/158916/4354dd64-9eaf-8801-d415-dedb65c13858.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158916/eec1b48a-93d8-16f6-d033-6182509880ae.png)
（https://docs.docker.com/get-started/）より引用

コンテナはホストマシンのカーネルを他のコンテナと共有する構造になっている。コンテナごとにプロセスを分け、最小限のメモリしか使わないため、軽量。

対して、仮想マシンは、フルな仮想OSを提供するため、各アプリケーションが必要とする以上のリソースを提供してしまう。


## Dockerをインストール

以下のページから自分のOSに合ったDockerを選んでインストール。

https://docs.docker.com/install/


## Dockerがちゃんとインストールされてるか確認し、Hello Worldしてみよう


インストールしたDockerのバージョンを確認。

```
docker --version
```

より詳細な状態を表示

```
docker info
```

dockerでHello Worldしてみる。

```
docker run hello-world
```

ローカルで「hello-world」というイメージが見つからないと、リモートから探してpullしてくれる。

すごい。

「hello-world」というイメージが追加されているか、lsコマンドで確認

```
docker image ls
```

hello-worldイメージによって生成されたコンテナを見てみる。

```
docker container ls
```

稼働していないコンテナも全て表示するには、`--all`をつければ良い。

```
docker container ls --all
```

## まとめ

コンテナを使うことによって、継続的な統合・開発をシームレスに行うことができる。

例えば、

- アプリケーションのシステム環境依存がなくなる。（環境の差異で苦しむことがなくなる）
- アプリケーションのどの部分に対しても、アップデートをかけることが可能。（コンテナごとにプロセスが独立しているから、他アプリケーションへの影響なく更新できちゃうっていう意味かな？）
- 　リソースの密度を最適化することができる。（必要なコンテナの、必要な分のリソースだけを使うことができる）


以上！！


続きは、こちら。

[【Docker入門】公式Docsの「Get Started」を日本語で要約しながらやってみる（Part2）](https://qiita.com/jnaiFy04EJ0cP2L/items/c484560ea645f8c00b4a)
WPF > フォルダ選択



# 背景
WPFにはフォルダ選択コントロールが無い



# 準備
WindowsAPICodePackを使う模様

nuget で WindowsAPICodePack-Shell を検索

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/b0e05db6-8717-d903-c844-fbc72b3684d4.png)

ダウンロード数が多く、バージョンNOが高い版を選択。（作成者：Aybe）

WindowsAPICodePack-Core とWindowsAPICodePack-Shell がインストールされます。
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/d1224795-c542-9e2d-2775-a41b04bd0b38.png)

# 使い方

## XAML

ボタンとテキストボックスを配置します。

```xml
<Grid>
    <Button Content="Button" HorizontalAlignment="Left" Margin="564,84,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    <TextBox Name="TextBox1" HorizontalAlignment="Left" Height="23" Margin="61,85,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="481"/>
</Grid>

```

## コードビハインド(C#)

```csharp

using Microsoft.WindowsAPICodePack.Dialogs;


/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var dlg = new CommonOpenFileDialog("フォルダ選択");
        dlg.IsFolderPicker = true;
        var ret = dlg.ShowDialog();
        if (ret == CommonFileDialogResult.Ok)
        {
            TextBox1.Text = dlg.FileName;
        }
    }
}



```



# 結果

フォルダ選択ダイアログが出ました。

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/91fef0d1-d3e7-7030-7b75-c13b0f8cd54a.png)



# 参考
[wpfでvsのフォルダ選択ダイアログみたいなダイアログを表示したい - Qiita](https://qiita.com/jugemjugemu/items/48bdd18033b84d4cfcfc)
Trailheadで複数形の表示ラベル記入を指示されたときの対処方法


`Plural Label (表示ラベル (複数形)): `

という形で複数形を入力するよう指示されたとき、無視して進めてもChallengeが通る場合もあれば通らない場合もある。
この記事は、通らないときの対処法。
これをやらないばかりに取りこぼすポイントがそこそこある。

[Setup]->
[Rename Tabs and Labels]->
Custom Tabsから編集したいカスタムオブジェクトの[Edit]->
Pluralテキストエリアを編集

2018/11/9追記
組織の言語設定を変更するとオブジェクト作成時に設定できました。
自分がやってて今まで出てこなかったのは、「私の設定」の方で言語設定をしたいたからでした。
しかし組織の言語設定のみ変更しても不具合が生じることがあるので、組織、私の設定両方で言語を変えることをお勧めします。
EC2でLet's encryptの証明書を簡単に取る方法

# 内容
Let's encryptで証明書を取得する必要あったのでその時の手順をメモしておく
**certbot**を使用して取得している。
ワイルドカード証明取る場合自動化できるか不明。
頑張れば自動化いける？

# 環境
- EC２

取得の際に**certbot**を使用する場合ほかのミドルウェアは特に必要ない。
SGで外部から80が入れるようにする必要があります。

ドメインはRoute53を用いて管理している。
ワイルドカードで取得

#　手順

```shell:command
sudo yum update -y
sudo yum install -y git
```

```shell:command
git clone https://github.com/certbot/certbot.git
cd certbot
```

```shell:変数
ADMIN_MAIL="<メールアドレス>"
DOMAIN="<証明書取得要ドメイン>"
ENDPOINT="https://acme-v02.api.letsencrypt.org/directory"
```

```shell:実行
sudo ./certbot-auto certonly \
  --manual \
  --domain ${DOMAIN} --domain *.${DOMAIN} \
  --email ${ADMIN_MAIL} \
  --agree-tos \
  --manual-public-ip-logging-ok \
  --preferred-challenges dns-01 \
  --server ${ENDPOINT} \
  --debug
```

```shell:結果
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for <証明書取得要ドメイン>
dns-01 challenge for <証明書取得要ドメイン>

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
************.<証明書取得要ドメイン> with the following value:

**********************************

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
```

> Please deploy a DNS TXT record under the name

の指示通り、***の文字列が出てきたらDNS設定に文字列を入れ込んで反映してから`Enter`を押す。
このやり取りが２回発生した。

```shell:証明書の確認
cd /etc/letsencrypt/live/${DOMAIN}
```
上記に格納されているので確認する。

### サブドメイン単体で取る

```shell:変数
ADMIN_MAIL="<メールアドレス>"
ENDPOINT="https://acme-v02.api.letsencrypt.org/directory"
DOMAIN=“<ほしいドメイン>”
```

```shell:実行
sudo ./certbot-auto certonly 
–domain ${DOMAIN} 
–email ${ADMIN_MAIL} 
–no-bootstrap 
–debug
```

### 備考
ACMで証明書の取得は可能でが、すべての経路を暗号化したい場合ALBでACM証明書を終端して、サーバーにこの証明書を入れ443で通信しなきゃいけない時に役に立つと思います。

あくまでメモレベル。
Go言語でシンプルなWebAPIサーバーを実装する

Go言語 初心者向けハンズオン用資料です。
https://techdo.connpass.com/event/100306/

簡単なWebサーバーの書き方と動かし方を説明します。

Go言語ではパッケージと呼ばれる様々なライブラリを取り込んで使うことのできる機能が備わっています。
パッケージには言語に組み込まれている内部パッケージ、有志によって開発された外部パッケージがあります。

* net/http(内部パッケージ)
* julienschmidt/httprouter(外部パッケージ)

## 1. 外部パッケージを導入する

```bash
$ go get github.com/julienschmidt/httprouter
```

## 2. Webサーバーとして動くコードを書く

*main.go*

```go
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
)

// /Hello/:langにハンドルされているHello関数
func Hello(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	lang := p.ByName("lang") // langパラメーターを取得する
	fmt.Fprintf(w, lang)     // レスポンスに値を書き込む
}

// /ExampleにハンドルされているExample関数
func Example(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	defer r.Body.Close() // Example関数が終了する時に実行されるdeferステートメント

	// リクエストボディを読み取る
	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		// リクエストボディの読み取りに失敗した => 400 Bad Requestエラー
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// JSONパラメーターを構造体にする為の定義
	type ExampleParameter struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	}
	var param ExampleParameter

	// ExampleParameter構造体に変換
	err = json.Unmarshal(bodyBytes, &param)
	if err != nil {
		// JSONパラメーターを構造体への変換に失敗した => 400 Bad Requestエラー
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// 構造体に変換したExampleParameterを文字列にしてレスポンスに書き込む
	fmt.Fprintf(w, fmt.Sprintf("%+v\n", param))
}

func main() {
	router := httprouter.New() // HTTPルーターを初期化

	// /HelloにGETリクエストがあったらHello関数にハンドルする
	// :langはパラメーターとして扱われる
	router.GET("/Hello/:lang", Hello)

	// /ExampleにPOSTリクエストがあったらExample関数にハンドルする
	router.POST("/Example", Example)

	// Webサーバーを8080ポートで立ち上げる
	err := http.ListenAndServe(":8080", router)
	if err != nil {
		log.Fatal(err)
	}
}
```

## 3. Webサーバーを起動する

```bash
$ go run main.go
```


## 4. Webサーバーにアクセスする

ブラウザで``http://localhost:8080/Hello/golang``にアクセスしてみましょう。
POSTリクエストはcurlコマンドで叩いてみましょう。

```bash
$ curl -XPOST -d "{\"id\": 1, \"name\": \"yukpiz\"}" http://localhost:8080/Example
```
OSごとにオプションの違うコマンドのaliasの設定

# 概要
OSによってオプションの変わるコマンドあります。（`ls` など）
`.bashrc` などの設定ファイルをOSごとに変えるのは面倒なので、共通して使える`alias` の設定方法について記します。

# 例えば `ls`
MacとUbuntuで色をつけるオプションが違います。

## Mac
```
% uname
Darwin
% ls -G
<色がついた結果が表示される>
% ls --color
ls: illegal option -- -
usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]
 <t-abe@mac-no-MacBook-Pro-2.local>
```

## Ubuntu
```
% uname
Linux
% ls --color
<色がついた結果が表示される>
% ls -G
<エラーになならないが白黒の結果>
```

# 設定例
if / case で場合分けしただけですが、`.bashrc` などに以下のように書くとOSが違っても同じ設定ファイルを使いまわせます

## `uname` コマンド
```bash
if [ $(uname) = 'Linux' ]; then
    alias ls='ls --color'
else
    alias ls='ls -G'
fi
```

## ~~環境変数~~ シェル変数 `${OSTYPE}`
`uname` コマンドを実行する必要がない分、~~環境変数~~ シェル変数を使う方がようさそうな気がします。

```bash
case ${OSTYPE} in
    darwin*)
        alias ls='ls -G'
        ;;
    linux*)
        alias ls='ls --color'
        ;;
esac
```

# まとめ
OSが違っても同じ設定ファイルを使いまわせる `alias` の設定ができました
**他により良い方法がありましたら教えていただけるとうれしいです**
Nodejsでヤフオクのオークションアラート

#目的
ヤフオク検索の自動化をしたく作成しました。
私はこのスクリプトとGoogleAppsScriptを組み合わせて日々のリサーチを自動化しています。

#フロー
下記の内容のJSONをサーバーにPOST

```postContent.json
{
	"data": {
		"keyword": "ヤフオクで検索するキーワード",
		"limit_purchase_price": "価格上限を指定（任意）",
		"already_checked_auction_ids": "すでにチェック済のオークションIDをカンマ区切りで指定（任意）"
	}
}
```

↓
サーバーでヤフオクにアクセス・スクレイピングし新しいオークションのIDをカンマ区切りの文字列でreturn

#実行環境
・Node.js 8.9.4
・npm 5.6.0
・Heroku上で実装

#構造
ファイル数が2つだけなので同じディレクトリです。

ー server.js
ー newAuctionAlert.js

#事前準備
・モジュールのインストール

```npm_install.cmd
npm install --save express
npm install -save body-parser
npm install --save cheerio-httpcli
```

#コード
##server.js
```server.js
"use strict";
const express = require('express');
const body_parser = require('body-parser');
const newAuctionAlert = require('./newAuctionAlert');
const app = express();

//***サーバー作成***
const server = app.listen(process.env.PORT || 3000, function() {
	console.log("server listening..");
});

//***express設定***
app.use(body_parser.urlencoded({
	extended: true,
	limit: '5KB'
}));
app.use(body_parser.json({
	limit: '5KB'
}));

//***expressルーティング***
app.post('/newAuctionAlert', async(req, res, next) => {
	const data = req.body.data;
	if (data.keyword) {
		const itemData = JSON.parse(req.body.data);
		const new_auction_ids = await newAuctionAlert.main(data);
		res.status(200).send(new_auction_ids); //カンマ区切り
	} else {
		res.status(404).send('キーワードの指定は必須です');
	}
});

```

##newAuctionAlert.js
```newAuctionAlert.js
"use strict";
const cheerio = require('cheerio-httpcli');

async function main(data) {
	return new Promise(async(resolve, reject) => {

		//***1. オークションページのHTMLを取得***
		cheerio.fetch(
			'https://auctions.yahoo.co.jp/search/search', {
				p: data.keyword.replace(/\+/g, ' '), //検索キーワード
				s1: 'end', //残り時間が長い順
				o1: 'd',
				ngram: 1, //あいまい検索
				istatus: 2, //中古のみで検索
				fixed: 0,
				ei: 'UTF-8',
				auccat: 0,
				slider: 0,
				tab_ex: 'commerce',
			}).then((res) => {
			//*** 2. 検索結果が存在すれば、価格が条件にマッチしているものをnew_auction_idsに追加する***
			const enddate_elms = res.$('.ti'); //オークション終了まで○日の部分
			const new_auction_ids = [];
			const already_checked_auction_ids_array = data.already_checked_auction_ids.split(/\,/g);

			if (enddate_elms.first().text() !== "") { //検索結果最上位の終了日を取得 検索結果が無ければ""
				enddate_elms.each(function() {
					const $parent_dom = res.$(this).parent();
					const auction_id = $parent_dom.find('.a1wrp').first().find('a').first().attr('href').match(/\/\w+?$/)[0].replace(/^\//, '');

					//上限価格が設定されている場合は価格チェック
					var price_flag = true;
					if (data.limit_purchase_price) {
						const auction_now_price = Number($parent_dom.find('.pr1').first().text().replace(/\D/g, ''));
						if (data.limit_purchase_price < auction_now_price) price_flag = false;
					}
					//価格がOKですでにチェック済のオークションで無ければ新しいオークション情報として登録
					if (price_flag && already_checked_auction_ids_array.indexOf(auction_id) === -1) new_auction_ids.push(auction_id);
				});
			}
			resolve(new_auction_ids.join());
		}).catch((e) => {
			reject(e);
		});

	});
}

exports.main = main;

```
::aftarなどの擬似要素にhover:を付ける

HTML

```html:test.php
<div class="test_box">
  <a href="#">test</a>
</div>

```


SCSS

```scss:_test.scss
	.test_box {
		border-top: 1px solid #616161;

		a {
			display: block;
			position: relative;
			padding: 10px 30px 10px 10px;
			border-radius: 0 0 5px 5px;
			color: #fff;
			font-family: Shin Go Bold;
			font-size: 0.75rem;
			line-height: (16/12);
			text-align: right;

			&::after {
				content: "";
				position: absolute;
				top: 0;
				right: 16px;
				bottom: 0;
				width: 7px;
				height: 7px;
				margin: auto;
				transform: rotate(-225deg);
				border-top: 2px solid #fff;
				border-left: 2px solid #fff;
			}

			&:hover {
				color: #fff100;

				&::after {
					border-color: #fff100;
				}
			}
		}
	}

```
Sphinxを導入してみた日

###ドキュメントをsphinx使ってかいてみようとす

```
$ pip install sphinx
```

作成したいフォルダに移動し、

```
$ sphinx-quickstart
Welcome to the Sphinx 1.7.7 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).
```

このあと諸々設問が出てくるので、y/n or 任意の文字列を入力していけば雛形の完成です。



参考：https://www.slideshare.net/tututen/sphinxdemo
　　：http://www.sphinx-doc.org/ja/stable/tutorial.html
CLI 環境構築 グローバルインストールとローカルインストールの違いについて

CLIでの環境構築記事は巷に溢れていますが、
実際に自分で環境構築した時に躓いた点を書き留めておきたいと思います。
今回はその中でも一番最初のインストール時に疑問に感じたグローバルインストールとローカルインストールについてです。

※こちらの記事は開発環境初心者向けの記事になりますので、バリバリ開発環境構築してるぜ！という方は、記事に対するツッコミや補足をお願いいたしますm(_ _)m
※本記事は小規模〜中規模サイトの環境構築を想定しています。
※シンプル、最低限の環境作成を目標としているため、gulp、webpack、parcelは使用しません。

## npmって？？
npmとはNode Package Managerの略です。
Node.jsのライブラリや、パッッケージを管理することができます。
プロジェクトによってはFacebookが開発したJavaScriptパッケージマネージャーのYarnが使われる事もあります。

関連リンク：
[npm互換のJavaScriptパッケージマネージャーYarn入門](https://ics.media/entry/13838)



## グローバルインストール？ローカルインストール？

CLIの環境構築を勉強していて、最初に「？」となったのが、
グローバルインストールとローカルインストールについてでした。
参考にしている記事によってはグローバルインストールさせている記事もありますし、ローカルインストールの記事もありますし、バラバラです。

```sh
#グローバルインストール
$ npm i -g ejs
```
この場合、package.jsonに記載されません。  
そしてインストール場所もグローバルとローカルで違います。
↓下記のコマンドを打ってみましょう。
  
```sh
#グローバルインストールされているものを確認
$ npm list -g
```
「/Users/uu123089/.nodebrew/node/v5.6.0/lib」
モジュールがインストールされる場所と、既にグローバルインストールされているモジュールがあれば、そのモジュールが表示されているはずです。

ここにインストールされたモジュールは各ディレクトリでコマンドを打って使用することができます。

```sh
#コマンド実行例
ejs-cli "*.ejs" --out dest/ --options data.json
```
ではローカルインストールはどうでしょうか？

```sh
#ローカルインストール
$ npm i -D ejs-cli
#↓省略しない場合
$ npm install --save-dev ejs-cli
```
こちらのコマンドをカレントディレクトリで打つと、package.jsonと同じ階層に
「node_modules」というディレクトリが作成され、その中に、インストールしたモジュールが入ります。
※実行する場合はnpm init でpackage.jsonを作成した後で実行してください。
※npm init については次のstep1の記事で解説いたします。


では先ほどと同じコマンドで実行すると・・・

```sh
#コマンド実行例
ejs-cli "*.ejs" --out dest/ --options data.json
```
#### 「-bash: ejs-cli: command not found」
が表示されます。
ローカルインストールした場合、インストール先がグローバルと異なるため、
パスが通っておらずエラーになってしまうのです。
下記のコマンドのようにパスを指定すれば実行ができます。

```sh
./node_modules/.bin/ejs-cli "*.ejs" --out dest/ --options data.json
```


なんだか、ローカルインストールは不便に思えてきますね。
でも、環境構築するにはローカルインストールの方がメリットがあるのです。
#### 1.他の環境に引っ越し、他のプロジェクトでの使い回しがしやすくなる


まず一つ目のポイントについてですが、ローカルインストールでインストールした場合、package.jsonにインストールされたモジュールが記載されました。
このモジュールが記載されたpackage.jsonをディレクトリに配置し、

```sh
npm i
```

をするとインストールしながらpackage.jsonを作成した時と同じ環境がコマンド一つで作成できるのです。
これは他のプロジェクトで使い回すのもそうですが、
複数人で開発環境を揃えるのにも役立ちます。
グローバル環境でインストールされた環境ですと、人によってインストールされてないものがあったり、バージョンが差異が出てエラーになってしまったり、開発をスムーズに行うことができません。


#### 2.グローバル環境を汚染しない
ローカルインストールされたものはプロジェクトディレクトリの中の「node_modules」というディレクトリにインストールされるため、グローバル環境を綺麗に保てます。

ここで一つ問題がありました。
パスの問題です。
その問題はnpm scriptsで解決できます。

## npm scriptsって？
package.json内のscriptsフィールドにシェルスクリプトやエイリアスコマンドを登録することができます。

```json:sample/package.json
~省略
"scripts": {
    "build:html": "ejs-cli *.ejs --out dest/ --options data.json"
  },
```

普段使っているプロジェクトのpackage.jsonを開くと、このような記述があるかと思います。
ここに登録したコマンドはパスを通して実行されるのです。（「./node_modules/.bin/」の記述が不要になります。便利ですね！）
登録したコマンドは

```sh
$ npm run 〇〇○←登録したタスク名
```

で実行できます。

今回の記事では
・npmについて
・ローカルインストールとグローバルインストールの違い
・npm scripts
の3点について触れました。


### 参考サイト
[Qiita 僕がnpm installに-gをつけないわけ](https://qiita.com/Mic-U/items/cd456d6bea72937464f8
)

[Qiita npmのグローバルインストールとローカルインストール](https://qiita.com/tsuda/items/175ef29d45d155b3f405)


[Grunt/Gulpで憔悴したおっさんの話](https://t32k.me/mol/log/npm-run-script/)
ChainerでCNNの実装例

必要最低限の使い方を覚書き。

# AlexNet
画像認識コンテスト（ILSVRC）で2012年に優勝したCNN。
[ImageNet Classification with Deep Convolutional Neural Networks](http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf)

```python:
import chainer
from chainer import Chain
from chainer import links as L
from chainer import functions as F

class AlexNet(Chain):
    def __init__(self, num_class, train=True):
        super(AlexNet, self).__init__()
        with self.init_scope():
            self.conv1=L.Convolution2D(None, 96, 11, stride=4)
            self.conv2=L.Convolution2D(None, 256, 5, pad=2)
            self.conv3=L.Convolution2D(None, 384, 3, pad=1)
            self.conv4=L.Convolution2D(None, 384, 3, pad=1)
            self.conv5=L.Convolution2D(None, 256, 3, pad=1)
            self.fc6=L.Linear(None, 4096)
            self.fc7=L.Linear(None, 4096)
            self.fc8=L.Linear(None, num_class)

    def __call__(self, x):
        h = F.max_pooling_2d(F.local_response_normalization(
            F.relu(self.conv1(x))), 3, stride=2)
        h = F.max_pooling_2d(F.local_response_normalization(
            F.relu(self.conv2(h))), 3, stride=2)
        h = F.relu(self.conv3(h))
        h = F.relu(self.conv4(h))
        h = F.max_pooling_2d(F.relu(self.conv5(h)), 3, stride=2)
        h = F.dropout(F.relu(self.fc6(h)))
        h = F.dropout(F.relu(self.fc7(h)))
        h = self.fc8(h)

        return h
```

# LeNet-5
Yann LeCunらによって考案されたCNN。
[Gradient-Based Learning Applied to Document Recognition](http://yann.lecun.com/exdb/publis/pdf/lecun-01a.pdf)

```python:
import chainer
from chainer import Chain
from chainer import links as L
from chainer import functions as F

class LeNet(Chain):
    def __init__(self, num_class, train=True):
        super(LeNet, self).__init__()
        with self.init_scope():
            self.conv1=L.Convolution2D(None, 6, 5, stride=1)
            self.conv2=L.Convolution2D(None, 16, 5, stride=1)
            self.conv3=L.Convolution2D(None, 120, 4, stride=1)
            self.fc4=L.Linear(None, 84)
            self.fc5=L.Linear(None, num_class)

    def __call__(self, x):
        h = F.max_pooling_2d(F.local_response_normalization(
            F.sigmoid(self.conv1(x))), 2, stride=2)
        h = F.max_pooling_2d(F.local_response_normalization(
            F.sigmoid(self.conv2(h))), 2, stride=2)
        h = F.sigmoid(self.fc3(h))
        h = F.sigmoid(self.fc4(h))
        h = self.fc5(h)

        return h
```

# 今後も追加予定
作ったモデルを可能な限り追加掲載していく。修正も適宜。
ルーティングに渡すparamをslugからnicknameに切り替えた話

- 最初、ユーザーの詳細ページへのルーティングには、`SecureRandom.uuid`で作成した**一意な`slug`フィールドを渡していた。**

```rb
# ユーザーの詳細ページ
resources :users, param: :slug, only: :show

# こんな感じになる
# => http://example.com/users/2bbccb03-596f-4d6c-b26a-589452d65596
```
- しかし、それではURLが長くなるし、わかりにくいと言われる。
- ならば、`slug`の代わりに`nickname`（ユニーク属性）を使ってみてはどうか。
- でも`nickname`属性は途中から取得し始めたから全部のモデルにないよ‥‥。
- **じゃあこういうルーティングにしよう。**
    - `slug`の入ったURLは今まで通り全部使えるようにする。
    - ただし`nickname`属性を持つモデルならば、**`slug`ではなく`nickname`の入ったURLにリダイレクトしてもらい、同じページを表示する。**
- というルーティングを作った話。

## 想定している読者
- Railsのルーティングに渡すパラメーターを切り替えたい人。
- 切り替える先のパラメーターが必ずしも存在してなくて、どうしようって人。

## 前もってもっておいてほしい知識
- `id`ではなく、`slug`といった別のパラメーターを使う方法。（[ドキュメント](https://railsguides.jp/routing.html#%E5%90%8D%E5%89%8D%E4%BB%98%E3%81%8D%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%AE%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%82%92%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%A9%E3%82%A4%E3%83%89%E3%81%99%E3%82%8B)）

## 結論
- Userコントローラーの`show`アクションの最初に以下のようにコードを変更する。

```rb
# before
def show
  @user = User.find_by_slug(params[:slug])
  # 処理
end
```

```rb
# after
def show
  # slugパラメーターにはslug（uuidで作成）かnicknameかのいずれかのフィールドが入ってくるため。
  @user = User.find_by_slug(params[:slug]) || User.find_by_nickname(params[:slug])

  # slugパラメーターにslugが渡ってきていて、且つnicknameが存在しているなら、
  # nickname入りのURLにリダイレクト
  return redirect_to user_path(slug: @user.nickname) if params_slug? && @user.nickname.present?
  # 処理
end

private

# パラメーターがslugかどうかを判定する。（slugはuuidで作成しているため、uuidのパターン一致で判定できる）
def params_slug?
  uuid_regex = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/
  uuid_regex.match?(params[:slug])
end
```

## 唯一の問題点
- 上の方法だと、（可能性は極めて低いが）`nickname`属性がuuidのパターンと一致してしまう（params_slug?がtrueになってしまう）と、延々とリダイレクトループしてしまう。

## 今後の反省点
- 今回はたまたま`slug`に`SecureRandom.uuid`という**判定できるパターンをもったものを格納していたため、`slug`判定ができて事なきを得た。**
- 今後もこういうことが起こりうるので、`slug`だからと適当な値を入れずに、**判定可能な文字列を使おうと思った**。
- というか[friendly_id](https://github.com/norman/friendly_id)使うべきだった。
HTML,CSSをはじめる

<h2>はじめに</h2>
◆HTML,CSSを学ぶ目的
主にウェブサイトの作成に用いられる。
HTMLで骨組みをつくり、CSSで装飾をする。

◆環境設定
・機種：Mac
・ブラウザ：Google Chrome
・エディタ：brackets
・ファイルの拡張子は表示させておく
　「Finder」「環境設定」「詳細」「すべての拡張子」

・インスペクターツール（developerツールや開発コマンドといったりする）
　「詳細」「設定を」
  開発していく中で、反映が正しくされているかなど、確認する。
　気になるサイトがどう作られているかなどものぞける。

◆学んだ方法
・書籍かドットインストール、プロゲートなど。
・学びはノートに書く。今日やること、やったことはノートへ。
・知り合いのエンジニアに書いたコードを、見せる。
　
<h2>HTML、CSSとは何か</h2>

◆HTML(hyper text markup language)とは。
ハイパーテキストを、マークアップする言語のこと。
つまり、複雑な文書の各要素に目印をつけ、コンピュータが文書の構造を理解できるようにする。
シンプルに言うと、要素の集まり。

◆CSSとは(cascading style sheet)とは。
コンピュータが文書の各要素についた目印を頼りに、定義されたスタイルをつけにいく。
シンプルに言うと、要素の集まりであるHTMLをいじくること。

◆たとえば
HTMLは見出しや、文章、画像などを配置する。
CSSは、見出しの前にアイコンをつけたり、背景色をつけたり、画像を左寄せにするなどできる。

<h2>HTMLについて</h2>
◆要素の集まりであるHTMLだが、基本的な要素は先に書いておく。
・<!DOCTYPE html>と書き、宣言する。
・HTMLの構造は、headとbodyに分かれている。
・文字コードはUTF-8が基本 
  <meta charset="UTF-8">　
・HTMLとCSSをリンクする方法
<link href="css/ファイル名" rel="stylesheet">

◆タグの書き方　
<> </>
<>の中にh1とかpとかdivとか要素をいれる。
</>で閉じる。

例
```
<div>
　あああああ
</div>
```


<h2>CSSについて</h2>
@charset "UTF-8";をつける。

cssはセレクタ、プロパティ、値がセットになっている。
各々、どこに、何を、どうするか。

◆セレクタ=どこに書くかを表す。
例）
id="アイディー名"
class="クラス名"

使用例）
```
<div class="test-txt">
 <p>ああああ
</div>
```

◆プロパティ=何を書くかを表す。
例）
文字サイズ　font-size
文字の太さ　font-weight
文字の間隔　letter-spacing
行間　line-height

・ボックスモデル
例）
要素と要素の幅　margin
要素内の幅　padding
幅 width
高さ　height

・色の指定
文字の色　color
背景の色　background-color

◆値=セレクタ、プロパティをどうするか。
例）
文字サイズを18ピクセルに font-size:18px;
幅を240ピクセルに width:240px;
文字の色を白に color:#ffffff;

<h2>ディレクトリとパスについて</h2>

◆ディレクトリとは。
ファイルの保存場所のこと。

◆パスとは。
・絶対パス 自サイト外を示す時に使う。
・相対パス 今いるところから、階層が上なのか下なのか。

◆階層を分ける。
・同じディレクトリ。
　ファイル名のみ。

・上位階層を示すやり方。
　　../  　 一つ上
　　../../　二つ上

・下位階層を示すやり方。　　　
　　/

◆ファイルの準備
「Document」の中にファイルをつくる。
そのファイルの中にhtmlファイルと、cssフォルダ、画像フォルダをおく。
cssフォルダには、cssファイル、画像フォルダには画像を入れておく。


<h2>つまずいたポイント</h2>
開発が始まる前に、詳しい人を探して確認をしておいた方がいいもの。

・フィードバックをもらうタイミング。
　8割をこなした段階でフィードバックをもらいたい。
　最後の残りの2割を仕上げるのに、また同じくらいの時間がかかる。

・テスト環境について確認をしておく
開発スケジュールの早い段階で、粗くても良いので、試すのが大事。
またGITHUBを使用するチームであれば、これも積極的にキャッチアップしておく。

・デザインについて
　デザイナーの方に、画面サイズが変わった時の動きを確認しておく。
　※せっかくコーディングしたのに、最後に大幅にHTMLの書き直しをしたりしないために。
  
・画像について
pngは周りの白が残らないけど、重い40KBくらいまで落とせば大丈夫。
JPEGは軽いため、周りの白が残るので、アイコンなどは不向き、背景などに使用。 
※重すぎると動かず、特にファーストビューが開かないと離脱が増えるので、重要。

・画像の重さを削る方法
photoshopで画像のサイズを変えるか。
使用する色数を減らす。