OmniAICreator/Qiita-1.07M huggingface dataset:
GCPのGoogleComputeEngineでDockerComposeを実行する最速の方法

釣り臭いタイトルですね。
内容は結構他の人とかぶってるんですが、公式通りするとハマる部分があったので書いておく。
※これは開発環境とかの用途で使って下さい、本番でやるんだったらGKEとかの方がいいです。
※GCPは使える、課金設定は済んでる前提です。

# GCPのGCEでDockerを動かす理由
これはずばりDockerに特化したOSが既に入っており、それを使うと楽だからです。
今回はSwaggerをみんなが見れるところで起動したかったので何か一番いいやつを探したら
GCP＋docker-composeでした。

## GCEマシンを立ち上げる
ふつーにWebGUIからGCEを立ち上げます。
開発用であんまりパワーいらないのでマシンタイプはmicroで十分。
ここでOSに「Container-Optimized OS 69-10895.172.0 stable」を選択します。

<img width="979" alt="スクリーンショット 2019-03-13 16.43.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/42110/abb79681-c88c-99fb-c286-babd0b2f97a4.png">

起動したらgcloudコマンドでsshします。
ここからgcloudコマンドは分かります。

## gitから必要なソースを取得
今回はswagger-all-in-oneという超絶便利なソースを使わせてもらいます。

git clone https://github.com/elevennines-inc/swagger-all-in-one-docker-compose.git

## docker-composeをインストール
公式の手順はこちら。
https://cloud.google.com/community/tutorials/docker-compose-on-container-optimized-os

docker-composeってdockerImagegaあるのねｗ

```
$ docker run docker/compose:1.22.0 version
```
この後公式では.barhrcにdocker-composeコマンドをaliasしていますが
この通りやるとハマりました。/rootfsってなんやねん。

```
$ echo alias dc="'"'docker run --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v "$PWD:/$PWD" \
    -w="/$PWD" \
    docker/compose:1.22.0'"'" >> ~/.bashrc
$ source ~/.bashrc
```
↑個人的にdocker-composeって打つのが面倒なのでいつもdcってコマンドでalias切ってます。

## docker-compose実行
さっきのcloneしたところに移動してdocker-composeを実行。

```
$ dc up -d --build
$ dc ps
     Name                   Command               State               Ports
----------------------------------------------------------------------------------------
swagger-api      /usr/local/bin/apisprout / ...   Up      0.0.0.0:8083->8000/tcp
swagger-editor   sh /usr/share/nginx/docker ...   Up      0.0.0.0:8081->8080/tcp
swagger-nginx    nginx -g daemon off;             Up      80/tcp, 0.0.0.0:8084->8084/tcp
swagger-ui       sh /usr/share/nginx/run.sh       Up      80/tcp, 0.0.0.0:8082->8080/tcp
```

# ファイアウォールに穴あけパンチ
GCEでデフォルトで作ったら80しか空いていないので8081〜8084の穴を開けましょう。
このリンクから辿っていって、tcp入力欄にカンマ区切りで8081,8082,8083,8084 って入力すればOK。
あとは作った設定をGCEに紐づけましょう。
<img width="883" alt="スクリーンショット 2019-03-13 16.57.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/42110/fe3679f2-7319-d4fe-5d28-8589bca2cd9f.png">


<img width="841" alt="スクリーンショット 2019-03-13 17.06.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/42110/62917181-b752-c158-8293-7cf14a858de6.png">
21日目。ProgateのPHPⅣでお料理サイトをパワーアップしました！


21目の今日はProgateのPHPⅣ。お料理サイトをパワーアップです！

トータルで４時間、いまいちピンとこないままクリアしたので、もう一回復習しました。
foreachとかif分は見なくても書けるようになりました。
一方で、$ありなし、privateとpubicの使い分け、staticのありなしと、こんがらかってしまいます。

それから、Progateを進めるコツがわかりました！
①分からなかったら、画面を更新してどのPHPの何行目でエラーになっているか確認。
②全部解けなくても「確認して次へ」ボタン。どこで引っかかったかヒントが出てきます。

行き詰まってもだいたいこれで見つけられる感じです。	
・・・でもヒントが時々間違っているという罠（笑）完璧じゃなくてもクリアするケースも（汗）

プログラミングだからしょうがないんですが、一文字違うと動かないんですね。
それがどこでを見つけるのがまた大変。

とりあえず達成感で一杯です！		

Progateお料理サイト
http://appdays.herokuapp.com/Day21

###リンクを作ろう
`<a>`タグで囲むだけ。楽勝！

###クエリ値を渡す
次のページに必要な情報を渡すことができる。
この場合は`show.php`に`CURRY`を渡している。
はてな`?`で区切って`クエリ＝内容`に気がつくのに手間取りました。


###詳細ページの中身を作ろう
クラスメソッド = `public static function`でいいのかな？
Menuクラスの呼び出し方は`Menu::findByName()`
カッコや一文字違いでエラーがあちこち。それを取るのが大変！


###Reviewクラスを作ろう
Menuを真似してつくればOK!

###Reviewのデータを作ろう
おなじくMenuを真似してつくればOK!

#レビューを表示しよう
これもMenuをまねして完成！
foreach文が難しかった。

```
<?php foreach($reviews as $review): ?>
          <h3><?php echo $review->getMenuName() ?></h3>
          <p><?php echo $review->getBody() ?></p>
        <?php endforeach ?>
```

###レビューを取得しよう
メソッドとは関数のこと。`public function`で定義。
ファンクションとどう違うの。こんがらかる。
http://php.net/manual/ja/language.oop5.basic.php

ヒントを見ないで作るとこんだけ間違う。
・`function`とstaticをまちがってた
・`$this`と`this`をまちがっていた
・`$review`の`$`がなんでか一個おおくて$$reviewになっていた
・`$reviewsForMenu[] = $review;`の`[]`が足りなかった。
・`return $reviewsForMenu;`の位置が間違っていた

「確認して次へ」で間違った箇所を教えてくれるのだけど、それが間違っていたりした。
・if分の中で文字列の比較には「==」 を使いましょう → 実際は「()」が足りなかった。時々こう言うことがあるって覚えておこう。


```
public function getReviews($reviews) {
      $reviewsForMenu = array();
      // 引数の$reviewsの要素を繰り返し処理しましょう
      foreach ($reviews as $review) {
        // $review（配列の要素）のmenuNameプロパティと、プロパティのnameが一致するか調べます
        if ($review->getMenuName() == $this->name) {
          // $reviewを戻り値用の配列に追加します
          $reviewsForMenu[] = $review;
        }
      }
      return $reviewsForMenu;
    }
```

 ###Userの追加
 `class`,`__construct` `ゲッター`の追加。
 classの中にみんな全部いれるんだった。に気がつくのに手間取った。

 ###UserとReviewを紐付けよう (10分)
 同じことも３回目だとなんとなく手が動く感じ。
 一文字違うとエラーになるし、なかなか見つからないのにイラつく！


 ###ユーザーの情報を表示しよう
 セミコロンがいるとかいらないとか
 ゲットするとかしないとか
 日本語が良く分からなかったり・・・
 `$review`に対して、引数を`$users`として`getUser`メソッドを呼び出して、戻り値を変数`$user`に代入してください
        
 ###ReviewとUserの紐付け
IDを生成してレビューと紐づける。
IDのカウントアップで悩みました。

```
self::$count++;

// idプロパティにクラスプロパティ$countの値を代入してください
$this->id = self::$count;
```

###完成！
Octoparse法人様向けプラン

3周年を迎える際に、[Octoparse](https://www.octoparse.jp/)は法人様向けプランをリリースしました！法人様向けプランは複数ユーザーのアクセス、Webベースのデータ管理と検索、拡張性のあるクラウドリソースを特徴として、あらゆる規模のデータスクレイピングを達成できます。
Octoparse 法人様向けプランは、様々な大規模なデータ抽出プロジェクトを通じて、法人顧客にWebスクレイピングを簡単にご使用いただくことを 目的としています。

 
#効果的に協働する

今、チームワークすることができます！ Octoparse法人様向けプランには、管理者（Administrator）と エージェント（Agent）という2つの役割があります。
![管理者の役割.png](https://qiita-image-store.s3.amazonaws.com/0/262932/de357d2a-557c-b45d-37c6-5480314c318c.png)


管理者は主にアカウント管理、データ管理を担当し、エージェントによって抽出されたすべてのデータにアクセスすることもできます。 ２名のデフォルトエージェントに加えて、必要に応じてエージェントを追加することができます。

さまざまな役割を分担することで、チームはアカウントリソース、スクレイピングタスク、クラウドデータをより効果的に管理し、協力することができます。


#どこでもクラウド内のデータにアクセスできる

クライアントのことを忘れ、今、いつでもどこでもデータを管理することができます。

Octoparse Webコンソールを使うと、いつでもクラウド内のデータにアクセスできます。さらに重要なのは、どのブラウザからでもクラウド内のデータをダウンロードすることです。 新しいデータが抽出されましたか？ 心配しないで、データが自動更新されます。
 

#拡張できるように設計される

法人様向けプランは、拡張性を備えた強力なWebスクレイピング用に設計されています。

デフォルトでは、Octoparse法人様向けプランには2名のエージェントと40個の同時プロセスがあります。必要に応じて、エージェントとプロセスを追加することができます。

 

#Webコンソールを備える

Webコンソールは、法人様向けプランのみ利用可能な新機能です。Webコンソールを使うと、アカウント管理者は簡単に

✔ エージェントの権限を管理する

✔ タスク/データの状況を監視する（クラウド内）

✔ 抽出したデータをどのブラウザからでも直接ダウンロードできる
![Webコンソール.png](https://qiita-image-store.s3.amazonaws.com/0/262932/836bae79-e34f-69c9-8f35-c6a7ad5feed3.png)

 

 

 

#クラウドリソースの管理

少ないリソースでより強力なスクレイピングが可能です。法人アカウントであれば、クラウドリソースを拡張・管理する可能です。 以下の方法で、クラウドリソースの利用を最適化できます。

✔ エージェント間でのリソース共有を有効化/無効化する

✔ 各エージェントに利用可能なリソースを調整する

 

[Octoparseクラウド抽出を使って動的データを抽出する方法](https://www.octoparse.jp/blog/extracting-data-from-dynamic-websites-in-real-time/)について

 

#いつでも力になる！

上記の限定機能に加えて、Octoparseの法人顧客は次のサービスを利用できる：

**高級なトレーニング**

4時間のパーソナライズされたトレーニングとウェビナーを通じて、法人様向けプランを最大限に活用する方法を学びます。

**最優先のサポート**

ご不明な点がある場合は、いつでもお気軽にお問い合わせください。弊社のカスタマーサポートが丁寧にお応えします。

**専任のサクセスマネージャー**

ご利用中のプロセスに、弊社の専任のカスタマーサクセスマネージャーがお客様と協力して、法人様向けプランのすべてが期待通りに機能することを確保します。
![力になる.png](https://qiita-image-store.s3.amazonaws.com/0/262932/7a8296ab-901f-1117-85b9-a0d711725f42.png)

 

 

デモの予約、要求の打ち合わせ、Octoparseの詳細について[お問い合わせください](https://www.octoparse.jp/contact-sales)。
AWS Cloud9 で node.jsのデバッグが出来るバージョンに制限がある

AWS Cloud9 はクラウド上のIDEとして非常に優秀なので最近使い始めた。
しかし、node.jsのプログラムをデバッグしようとしてハマった。
2019/03/13現在、node.jsのデバッグが出来るNode.jsのバージョンは7.7未満らしい。

詳細は
https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/language-support.html
に書かれてるので参照して欲しい。
cloneしたリポジトリを別リポジトリとしてリモートにpushする

自分用メモ。

# 1.githubでリポジトリを作成
[こちら](https://github.com/login)からgithubへログインして新しくリポジトリを作成する。

# 2.リポジトリをクローンする
クローンするコマンド↓

```
$git clone クローンしたいリポジトリのURL 新しいプロジェクト名
```

「クローンしたいリポジトリのURL」は下画像の赤枠をクリックしてコピーする。
![スクリーンショット 2019-03-13 16.27.10.png](https://qiita-image-store.s3.amazonaws.com/0/97829/6efb0e71-1c2f-b3b8-d658-d16257aaf80b.png)

「新しいプロジェクト名」は最初に作成したリポジトリ名と同じものにする。

# 3.リモートへpushする
## 3-1.リモート元URLの確認

まず、クローンしたリポジトリがどのURLからクローンしたものなのかを確認↓

```
$git remote -v
```
結果↓


```
origin	クローンしたいリポジトリのURL (fetch)
origin	クローンしたいリポジトリのURL (push)
```
この「クローンしたいリポジトリのURL」の部分を「最初に作成したリポジトリのURL」に変更する。

## 3-2.リモート元URLの変更
※「最初に作成したリポジトリのURL」は手順２と同じ方法でコピーする。

```
git remote set-url origin 最初に作成したリポジトリのURL
```

再度リモート元URLの確認↓

```
$git remote -v
origin	最初に作成したリポジトリのURL (fetch)
origin	最初に作成したリポジトリのURL (push)
```

## 3-3.リモートへpush
```
$git push origin master
```

念のため手順１で作成したリポジトリを確認し、pushされていれば終了。
Centosでnginxをインストール手順

## 前置き
centosでnginxを動かせたい時に、事前にやるところをリストします。

- centosのバージョン確認
- nginxのrepositoryを用意する
- nginxのインストール＆サービスを常駐させる

## 手順
### centosのバージョン確認
```
[user@localhost ~]$ cat /etc/redhat-release
CentOS release 6.9 (Final)
```
### nginxのrepositoryを用意する
```/etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repository
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1
```
### nginxのインストール＆サービスを常駐させる
#### nginxのインストールと起動する
```
[user@localhost ~]$ sudo yum -y --enablerepo=nginx install nginx

[user@localhost ~]$ sudo service nginx status
nginx is stopped
[user@localhost ~]$ sudo service nginx start
Starting nginx:                                            [  OK  ]
```
[NginxのRPMリスト](http://nginx.org/packages/centos/6/x86_64/RPMS/)
#### サービスを常駐させる
```
[user@localhost ~]$ chkconfig --list | grep nginx
nginx          	0:off	1:off	2:on	3:on	4:on	5:on	6:off
nginx-debug    	0:off	1:off	2:off	3:off	4:off	5:off	6:off

[user@localhost ~]$ sudo chkconfig nginx off
[user@localhost ~]$ chkconfig --list | grep nginx
nginx          	0:off	1:off	2:off	3:off	4:off	5:off	6:off
nginx-debug    	0:off	1:off	2:off	3:off	4:off	5:off	6:off

[user@localhost ~]$ sudo chkconfig nginx on
[user@localhost ~]$ chkconfig --list | grep nginx
nginx          	0:off	1:off	2:on	3:on	4:on	5:on	6:off
nginx-debug    	0:off	1:off	2:off	3:off	4:off	5:off	6:off
```

## 雑談
[web serverのシェア状況](https://news.netcraft.com/archives/2019/01/24/january-2019-web-server-survey.html)
**nginxの伸びがすごいっす**
![Screen Shot 0031-03-13 at 16.46.46.png](https://qiita-image-store.s3.amazonaws.com/0/26016/2787ee05-935c-9aa5-326b-8c3bfb6adabc.png)
Nextcloud へのWebDAV接続

#はじめに
Nextcloudはオンラインストレージを構築できるオープンソースソフトウェアです。通常、Nextcloudへのアクセス方法としては、WebブラウザーやNextcloudの同期アプリケーションでアクセスを行いますが、エクスプローラーで利用したいという声もよく聞きます。同期アプリケーションでも、エクスプローラーで利用できますが、自分のPCにもファイルが保存されてしまうのが嫌という方もいます。NextcloudはWebDAVでのアクセスも可能ですので、今回は、エクスプローラライクに利用できるWebDAVでのアクセス方法について、紹介したいと思います。

#WebDAV用のアドレスを確認
まず、Webブラウザーのファイル操作画面を開き、画面左下の設定アイコンをクリックします。
![182.png](https://qiita-image-store.s3.amazonaws.com/0/308127/fa2c35d3-0ecb-b41b-ea64-d73a4a0793c2.png)

設定アイコンをクリックすると、WebDAV用のアドレスが表示されます。以下のようなアドレスとなっていますので、コピーしておきます。
https\://NextcloudのURL/remote.php/webdav/
![183.png](https://qiita-image-store.s3.amazonaws.com/0/308127/07974f75-58a0-7e82-ca40-1bdf2bb6d8de.png)

#WebDAVアプリを使って接続
今回は、フリーソフトのCarotDAVを使って、Nextcloudへ接続します。
![184.png](https://qiita-image-store.s3.amazonaws.com/0/308127/4c00d9dc-1313-e62b-d221-eb4d536838a7.png)

CarotDAVを起動し、File→New Connection→WebDAVを選択します。
![185.png](https://qiita-image-store.s3.amazonaws.com/0/308127/e741933c-f948-b859-d542-0b4cb3b59642.png)

WebDAVの接続設定画面が表示されますので、先ほどコピーしたWebDAV用のアドレスを入力し、ユーザID・パスワードも入力します。（Setting Nameは任意の設定名（今回はNextcloud）をつけます。）入力が完了したら、OKをクリックします。
![186.png](https://qiita-image-store.s3.amazonaws.com/0/308127/3ed042fe-53f8-6412-5459-b0038da013f8.png)

接続画面に戻ります。先ほど設定したものが表示されますので、ダブルクリックします。
![187.png](https://qiita-image-store.s3.amazonaws.com/0/308127/c8ab02c1-2a6e-620b-8ee6-c11b3de9c285.png)

Nextcloudへ接続できました。
![188.png](https://qiita-image-store.s3.amazonaws.com/0/308127/2ec7c927-2671-2725-2236-c26c4ff593db.png)

#まとめ
今回、CarotDAVでの接続方法を紹介しましたが、他のWebDAVアプリでも同じ方法でNextcloudで接続できます。他のアプリですと、Cyberduckもあります。また、スマートフォン用のWebDAVアプリでも同じように接続できます。

この記事は、[スタイルズ社のNextcloudサイト](https://nextcloud.stylez.co.jp/nextcloudblog)にも公開しております。
デベロッパーツールで見ると<noscript>の子要素が文字として扱われて戸惑った話

## はじめに

タイトルそのままです。

googleタグマネージャーを埋め込むときに初めて`<noscript>`をコピペしました。

## これ

あれ、`<iframe>`が要素としてじゃなくて文字として扱われてる・・・ようにみえた

<img width="744" alt=" 2019-03-13 16.26.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/367855/6c0c6c0e-f598-7bf3-a6f5-ad64290e5af3.png">


## みえただけ

ブラウザのjavascriptを無効にしたら要素として読み込まれた
[各ブラウザでJavaScriptを無効にする](https://qiita.com/ha_g1/items/a227731ebea961e8b4e2)

<img width="846" alt=" 2019-03-13 16.35.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/367855/14ba89a3-b133-bd4c-0f15-feca97260fec.png">
SmarterCSVで文字コードを指定して読み込む方法

RubyのハッシュにCSVファイルを読み込むとき、SmarterCSVを利用すると1行で書けてとても便利です。

ただし、デフォルトではUTF-8としてファイルが読み込まれます。
しかし、Windowsで作成されたCSVだとエンコーディングが'cp932'[^1]になっていることもありますので、明示的にcp932を指定して読み込む必要があります。[^2]

その指定方法を調べるのに10分ほどかかってしまったので、メモしておきます。


```ruby:code
require 'smarter_csv'

csv_hash = SmarterCSV.process(filepath, {file_encoding: 'cp932'})

```

### 参考
https://www.rubydoc.info/github/tilo/smarter_csv
https://stackoverflow.com/questions/30085334/smartercsv-and-file-encoding-issues-in-ruby

[^1]: いわゆるShift_JIS。MS独自の拡張が入っているので、厳密にはcp932とかWindows-31Jと呼ばれます。
[^2]: 歴史的経緯もありますが、そろそろUTF-8に統一してほしいものです。。。
Flaskでformを受け取る時formが存在するか確認する方法

なぜかハマったので、書いておきます。

## 結論

textというフォームが存在したら、フォームを取得

```python
if('text' in request.form):
    t = request.form['text']
```


## request.formについて
[ドキュメント](http://flask.pocoo.org/docs/1.0/api/#incoming-request-data)にある通り、request.formはイミュータブルなMultiDictです。
つまり辞書型。
なので、

```python
'form名' in request.form
```
でformが含まれているか確認することができます。

## あとがき
~~もしかしたら、同じようにハマる人がいるかも。~~
誰かの役に立てることができれば幸いです。
もし何か間違っていたら教えてください！
Pillow(PIP)のインストール (Windows)

#Pillow(PIP)のインストール
1. https://www.lfd.uci.edu/~gohlke/pythonlibs/#pillow を開いて、Pillow‑5.4.1‑cp37‑cp37m‑win_amd64.whl (32ビットの場合は Pillow‑5.4.1‑cp37‑cp37m‑win32.whl) をダウンロードする  
![WS000080.JPG](https://qiita-image-store.s3.amazonaws.com/0/284812/68377587-3c9d-7809-67ee-5015ef7c0b70.jpeg)  
2. コマンドプロンプトを「管理者として実行」で起動しする。  
![WS000077.JPG](https://qiita-image-store.s3.amazonaws.com/0/284812/327e2a85-8f40-2a90-036a-53d969872d5f.jpeg)
3. pip install [ダウンロードしたファイル名] を実行する。  
![WS000081.JPG](https://qiita-image-store.s3.amazonaws.com/0/284812/382a4998-b419-0fa6-241c-27d76abfdc2e.jpeg)

以上でインストールは完了です。
FFMPEG のインストール (Windows)

# FFMPEG のインストール
1. https://www.ffmpeg.org/download.html を開き、Get the packages の下のWindowsのアイコンをクリックして、Windows Packagesの下の Windows Buildsをクリックする
![WS000064.JPG](https://qiita-image-store.s3.amazonaws.com/0/284812/a64bd35e-0b81-9324-0e13-c6019449454b.jpeg)
2. Version はリリースされたバージョン(画像では 4.1.1)を選択し、
Architecture はOSに合わせて64bitもしくは32bitのアーキテクチャを選択して、Linking は Static を選択してDownload Build を押す
![WS000065.JPG](https://qiita-image-store.s3.amazonaws.com/0/284812/d9908989-f2ab-b008-fc97-8b84b54eba1d.jpeg)
3. ダウンロードしたファイルを任意のフォルダに解凍する。

以上でインストール完了です。
Swiftにおける画面遷移には、2つある


# 初めに

この記事は、メモがわりです。ご了承ください。

画面遷移については、こちらを参考にしてください。
https://ja.stackoverflow.com/questions/17290/swift-segue%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6


# 通常の画面遷移の場合

```swift

self.present(SenddetailViewController, animated: true)
```

戻る場合は、

```swift

   @IBAction func tapCloseBtn(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
    }
```


# navigation cotlollerの場合

```swift

 let SecondViewController = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC") as! SecondViewController
            
            self.navigationController?.pushViewController(SecondViewController, animated: true)
            //遷移先のBox変数に、このコードないの変数Stringを代入する
            SecondViewController.Box = String

```

戻る場合は、

```swift

   @IBAction func tapCloseBtn(_ sender: Any) {
   self.navigationController?.popViewController(animated: true)
    }
```

この場合は、Storybordでどこへ遷移させるのかを遷移ものとのVIew(上のコードを書くview)の左上の丸印から
遷移先のviewの全体に対してControl で繋げる必要がある。


#追記
NavbarやTabbarの先頭に戻りたいとき

segueを利用して戻る
performSegue()で利用する

といい。
/var/lib/docker/containers の容量が多いとき、docker hostがdisk 100%になったときの対処法

## 原因のコンテナを探す
まず容量が多いcontainerを探す。80Gのやつがいる。

	[root /]# du -ha --max-depth=1 /var/lib/docker/containers
	32K	/var/lib/docker/containers/a4aba1c80836238c75700566d9b3bfcebba0051c90bffc55bc18258eda0bf091
	40K	/var/lib/docker/containers/e812ac8bf89a9310090bd49922312cf8883ff687e88c853e93895ac2aa97f3c7
	64K	/var/lib/docker/containers/2a1b2540bd28e882d759a87b83cc209f65bfb1605fb2c5c07fdb831a26e8ad3b
	672K	/var/lib/docker/containers/341ed988466fa070613740b39eed4ed8fc565874fbb96d4d8e7e1be325db0a66
	80G	/var/lib/docker/containers
	80G	/var/lib/docker/containers/5f678d8b7aad742b94c31288094b5bcecca2cb379c5093ffb1d0165b0e8f689d


このhashが何のコンテナ？はこれでわかる

     docker container inspect 5f678d8b7aa(省略)b0e8f689d | grep -i name

で、コンテナ自体のvolumeは10G固定なんで、なんで80Gあるかというと

```ruby
    [root@:/var/lib/docker/containers/5f678d8b7aad(省略)d016d]# ll
    -rw-r----- 1 root root 80G 2019-03-13 14:25:27 5f678d8b7aad(省略)d016d-json.log
```

こいつlogが多いんすね。

## logをへらす方法
logging optionを使います。docker-composeのv3からだけ使えます。

    # cat docker-compose.yml
    version: '3'

    services:
      web:
        image: <image>
        logging:
          driver: "json-file"
          options:
            max-size: "200M"
            max-file: "1"

### logging option

> Specify logging options for the logging driver with the options key, as with the --log-opt option for docker run.
Logging options are key-value pairs. An example of syslog options:
> 
    options:
      max-size: "200k"
      max-file: "10"

>  https://docs.docker.com/compose/compose-file/#logging
NimのMatrixライブラリ、Neoを入れる

# インストール

Nimで行列演算とかできる[Neo](https://unicredit.github.io/neo/)をインストールする手順です。

~~普通に`nimble install neo`でインストール出来るかと思いきゃ、依存パッケージの`nimblas@0.2.2`がnimのバージョンを0.19.9以上に指定しており、入るはずがありません(現在のNimのバージョンは0.19.4)。
一つ前のバージョンのnimblasを入れてあげれば解決します。~~

**最新のneo 0.2.5では`nimble install neo`だけでインストールできました。**もし問題があるようなら以下の手順を試してみてください。

```sh
# nimblas 0.2.1をインストール
nimble install nimblas@0.2.1
# neoをインストール
nimble install neo
```
これでneo自体のインストールは完了です。

**しかし多くの環境では、依存ライブラリのblas等が入っていないので、[こちらの記事](https://qiita.com/nek0log/items/5733b8b886b9ad93ae11)を参考にインストールしてください。**

## テスト
試しに、ランダムなMatrix(行列)a, bを作り、転置行列を求めたり掛け算をしてみましょう。

```nim:test.nim
import neo

let a = neo.randomMatrix(2, 3)
echo "a:"
echo a
# a.Tで転置行列を求める
echo "a.T: "
echo a.T

# 行列の掛け算(Numpyのdotに相当)
let b = neo.randomMatrix(a.N, a.M)
echo "b:"
echo b
echo "a * b:"
echo a * b
```
結果が以下のようになっていれば成功です🎉
(a, bの値はランダムです)

```sh
a:
[ [ 0.2326961497609559	0.3333379470197706	0.4437264946689483 ]
  [ 0.8228467011541094	0.9894961846897405	0.07581602342631522 ] ]
a.T:
[ [ 0.2326961497609559	0.8228467011541094 ]
  [ 0.3333379470197706	0.9894961846897405 ]
  [ 0.4437264946689483	0.07581602342631522 ] ]
b:
[ [ 0.5936563635008223	0.8244128746481869 ]
  [ 0.195534693152861	0.6844019291752474 ]
  [ 0.5258890850057507	0.4899364645980169 ] ]
a * b:
[ [ 0.4366716035287096	0.6373726257982174 ]
  [ 0.721839832363471	1.392723546483812 ] ]
```
Node.jsサーバにおけるHTTPリクエスト処理

#前提
この記事は以下の方を対象に記事を書いています。

- npmコマンドについて理解している
- Node.jsの環境構築が完了している
- Node.jsでサーバを立ててリクエスト処理を行いたい

#HTTPリクエスト処理について
自分の備忘録とNode.js初心者用に、
Node.jsサーバ上でHTTPリクエストごとに処理を行う方法を説明します。

まず、HTTPリクエストとは基本的に
クライアント側からWebサーバ側に要求を行うことを指します。
その際、リクエストの種類によってWebサーバ側は
クライアント側に対してレスポンス（返答）を返す必要があります。

<img width="380" alt="スクリーンショット 2019-03-13 15.10.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/212521/e8351cdf-2cb7-697e-b91e-a59a4022a0b8.png">
#サーバの構築
HTTPリクエストの種類には、
主なものとしてGETリクエストとPOSTリクエストがあります。
以下でNode.jsサーバの構築とリクエスト処理について説明します。
※ 規格はES6で記述します。
##Node.jsサーバの構築
Node.jsサーバの構築に必要な
以下のnpmモジュールをインポートします。
- request
- http

```javascript:index.js
const http = require('http');

```
続いて、HTTPサーバを構築します。
わかりづらい箇所は随時コメントで説明します。

```javascript:index.js
//httpモジュールを利用して、HTTPサーバを作成します
//createServer関数の引数であるコールバック関数を通して
//リクエストオブジェクトとレスポンスオブジェクトが利用可能
const http_server = new http.createServer((req, res)=>{
  //このスコープ内にサーバの処理を記述します
  //レスポンスヘッダの定義の設定
  res.setHeader('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type, Accept');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
}).listen(8080); //ポート番号の指定
```
##リクエストごとの処理
クライアントから送られてくるリクエストの種類の情報は、
リクエストオブジェクトに紐付けられている
methodプロパティを参照する必要があります。

```javascript:index.js
const require = require('require'),
      http = require('http');

const http_server = new http.createServer((req, res)=>{
  res.setHeader('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type, Accept');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  //リクエストごとに処理を記述
  if(req.method==="POST"){
    //POSTリクエストを受け取った際のレスポンス処理
    //リクエストの終了処理
    req.on("end", ()=>{
      res.writeHead(200, {"Content-Type": "application/json"});
      res.write();
      res.end();
    });
  } else if(req.method==="GET"){
    //GETリクエストを受け取った際のレスポンス処理
    //リクエストの終了処理
    req.on("end", ()=>{
      res.writeHead(200, {"Content-Type": "application/json"});
      res.write();
      res.end();
    });
  }
}).listen(8080); 
```

このリクエスト処理はAPIサーバなどに利用できます。
レスポンスオブジェクトやリクエストオブジェクトのプロパティも
色々と面白いので一度内容を確認するのも面白いかもしれません。

間違いなどご指摘ありましたら気軽にお願いします。
docker-composeでphabricatorをインストールする

## はじめに
JIRAに近いプロジェクト管理ツールで無料のものがないか探していたら見つけた[phabricator](https://www.phacility.com/phabricator/)
ちょっと動かして触ってみたかったのでdockerで構築しました。
その時のメモです。

## 環境
- CentOS 7.2
- docker、docker-composeインストール済み

## インストール

[ここのdocker-composeで構築する](https://github.com/bitnami/bitnami-docker-phabricator)

```docker-compose.yml
version: '2'
services:
  mariadb:
    image: 'bitnami/mariadb:latest'
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
    volumes:
      - 'mariadb_data:/bitnami'
  phabricator:
    image: 'bitnami/phabricator:latest'
    labels:
      kompose.service.type: nodeport
    environment:
      - PHABRICATOR_HOST=マシンのIPまたはホスト名
      - SMTP_HOST=メールサーバーのホスト
      - SMTP_PORT=587
      - SMTP_USER=メールアカウントユーザー
      - SMTP_PASSWORD=メールアカウントパスワード
      - SMTP_PROTOCOL=tls
      - PHABRICATOR_USERNAME=管理者ユーザー名
      - PHABRICATOR_PASSWORD=管理者パスワード
      - PHABRICATOR_FIRSTNAME=管理者ユーザー名(プロファイル用）
      - PHABRICATOR_LASTNAME=管理者ユーザー性(プロファイル用）
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - 'phabricator_data:/bitnami'
    depends_on:
      - mariadb
# /var/lib/docker/volumes/配下に保存される
# permission errorがこれだと出ない
volumes:
  mariadb_data:
    driver: local
  phabricator_data:
    driver: local
```

最初の設定は管理者でログインして行うので、ユーザー名とパスワードが必要です。
プロファイル用の氏名はログイン後の表示用プロファイルのものなのでわかりやすいものを。
メール認証もあるのでメールサーバーも用意しましょう。


では起動

```
docker-compose up -d
```

サーバーのIPをブラウザで叩くと初期設定画面が表示されます。


###Site Not Foundが出ちゃう場合の対応

https://github.com/bitnami/bitnami-docker-phabricator/issues/94
ここの最後に書いてあるように



>vim /opt/bitnami/phabricator/conf/local/local.json
>change phabricator.base-uri to host:port

ここのphabricator.base-uriをPHABRICATOR_HOSTと同じにする

vimインストール 

```
$ docker exec -it dockerコンテナ名 /bin/bash
root@3ec9a1e31a92:/# apt-get update
root@3ec9a1e31a92:/# apt-get install vim
```

local.jsonを編集して保存


###データボリュームの永続化をする場合
上記の場合はコンテナを削除したらデータは消えてしまう
ディスクボリュームをマウントして永続化をする場合

```
version: '2'
services:
  mariadb:
    image: 'bitnami/mariadb:latest'
    environment:
      - ALLOW_EMPTY_PASSWORD=no
      - MARIADB_ROOT_PASSWORD=DB ROOTユーザーのパスワード
    volumes:
      - /srv/docker/phabricator:/bitnami
  phabricator:
    image: 'bitnami/phabricator:latest'
    labels:
      kompose.service.type: nodeport
    environment:
      - PHABRICATOR_HOST=マシンのIPまたはホスト名
      - SMTP_HOST=メールサーバーのホスト
      - SMTP_PORT=587
      - SMTP_USER=メールアカウントユーザー
      - SMTP_PASSWORD=メールアカウントパスワード
      - SMTP_PROTOCOL=tls
      - PHABRICATOR_USERNAME=管理者ユーザー名
      - PHABRICATOR_PASSWORD=管理者パスワード
      - PHABRICATOR_FIRSTNAME=管理者ユーザー名(プロファイル用）
      - PHABRICATOR_LASTNAME管理者ユーザー性(プロファイル用）
      - MARIADB_PASSWORD=DB ROOTユーザーのパスワード
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - /srv/docker/phabricator:/bitnami'
    depends_on:
      - mariadb
```

mariadbのほうはpermisiionエラーが出てしまうので
マウントするディレクトリのpermissionを変更する

```
sudo chown 1001:1001 -R /srv/docker/phabricator
```
Shellの基本を学ぶ（１）シェルスクリプト

私は、Shellプログラムに弱い。見様見真似で書けるけど、理解しているとは程遠い。簡単なシェルプログラムを書くタスクをする必要があったので、この際まとめて勉強することにした。少しづつ、書いていきたい。これは、Pluralsights のとてもよかったコースの自分用勉強メモです。

* [Shell Scripting with Bash](https://app.pluralsight.com/library/courses/bash-shell-scripting/table-of-contents)

# Shell Script

Shellのコマンドが書かれたファイルで上から実行される。`#!/bin/sh` という記述が無くても実行できる。コメントは、`#`

_hw_

```bash
# Print Hello World.
echo Hello World
```

# 実行可能にする

ファイルは実行可能にする必要がある。`chmod` コマンドを使って実行可能にする。

```bash
$ chmod u+x hw
$ ./hw
Hello World
```

ダブルクオートとかシングルクオートとか無しで動くのね。

# ファイル名

重複しないようにする。`type` コマンドが便利

```bash
$ type ls
ls is /bin/ls
$ type some
-bash: type: some: not found
```

# パスを通す

パスを通すと普通のコマンドのように実行できる。レイジーだから余計なのをタイプしたくないらしい。

```
$ PATH=$PATH:/User/ushio/Codes/Bash/bin
$ hw
Hello World
```

# Substitution

Substitution というコンセプトがサクッと出てきたけど、実は十分理解できていないので、理解してみる。

## Command Substitution

Command Substitution はコマンドの実行結果で該当のコマンドを置き換える方法。`$(command)` と`` `command` `` という方法がある。両方だったのね。例えば

```bash
$ ls
bin		hello_world.sh	tn.sh
$ echo $(ls) 
bin hello_world.sh tn.sh
```
 
コマンドの実行結果で置き換えているからか、フォーマットはされないけど、実行結果で置き換えられています。

[Command Substitution](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html)

# Variable Substitution
変数は、高級言語のそれでは無くて、ターゲットの文字列を置き換えるという感じの様子。`$` をつけることで、変換される。

```bash
$ variables=23
$ echo variables
variables
$ echo $variables
23
```

ちなみに、`$variables` は `${variables}` の簡単なフォームです。

## 代入ミスの振る舞いの違い

最初のものは、VARIABLEというコマンドを実行しようとする。２つめのは、`VARIABLE` という変数に、"" をアサインして、value というコマンドを実行しようとする。（エラーメッセージに注意）

```bash
$ VARIABLE =value
-bash: VARIABLE: command not found
$ VARIABLE= value
-bash: value: command not found
```

## Whilte space
空白の扱いはこんな感じです。`"` でくくると、ホワイトスペースがキープされますが、くくらないと、ホワイトスペースは、１つになります。

```bash
$ hello="A B  C   D"
$ echo "$hello"
A B  C   D
$ echo $hello
A B C D
```

## シングルクオート

動きません。そのままに

```bash
$ echo '$hello'
$hello
```

## 複数の変数代入

ホワイトスペースで区切られていたら、複数の変数代入を１行で書けます。

```bash
$ var1=21 var2=22 var3=23
$ echo "var1=$var1 var2=$var2 var3=$var3"
var1=21 var2=22 var3=23
```

## ホワイトスペースには、ダブルクオートが必要

真ん中のは、other_numbers=1 がSubstitute 指定で、2 というコマンドを実行しようとしている。

```
$ numbers="one two three"
$ other_numbers=1 2 3
-bash: 2: command not found
$ other_numbers="1 2 3"
```


## ホワイトスペースのキャンセル

バックスラッシュで

```bash
$ mixed_bag=2\ ---\ Whatever
$ echo $mixed_bag
2 --- Whatever
```

## 未代入/Unsetは何もなしに

```bash
$ echo "uninitialized_variables = $uninitialized_variable"
uninitialized_variables =
$ uninitialized_variables=
$ echo $uninitialized_variables

$ uninitialized_variables=23
$ echo $uninitialized_variables
23
$ unset uninitialized_variables
$ echo $uninitialized_variables

```

# 変数のネーミング

変数は、Case sensitive で、全部大文字のが、pre-defined のもので、小文字スタートがそうではないもの。

[Variable Substitution](https://www.tldp.org/LDP/abs/html/varsubn.html)

# Parameter Substitution
パワーシェルでDataCore SANsymphonyのLoopback Portを削除する（失敗）


SANsymphonyをインストールすると各サーバーに4つずつ作られますが、はっきり言って使いみちがないから削除したい。
そんなときにいちいちデバイスマネージャーを開かなくても一気に全部消してしまう方法です。
このポート、超高速なのにSCSI-3 Persistent Reservationsが通らないからクラスター環境では全く使い道がありません。なのでうっかり使われて欲しくないです。

さっそくやってみましょう。
データコアサーバーのデスクトップにあるショートカットからパワーシェルを開きましょう。そうしないと2.のコマンドレットがない。

#####1. デバイスマネージャー上の対象デバイスを無効にする(GUIならできるけどパワーシェルで削除の仕方が分からなかった）
``get-pnpdevice |where friendlyname -match " DataCore Null FCP Port Adapter"| Disable-PnpDevic``
#####2. Loopbackポートを削除する
``Connect-DcsServer``
``Get-DcsPort | where PortType -eq loopback | Remove-DcsServerPort``
``Disconnect-DcsServer``


###再起動したらデバイスが復活してしまったので無効にするだけでは駄目だった。
#失敗！
Nuxt.jsで存在しないURLにアクセスされた時に404ページ(任意のページ）を表示する方法

# 解決したいこと
Nuxt.jsで存在しないURLでアクセスされた時に任意の404ページを出力させたい。

# 解決方法
nuxt.config.jsに以下のようにルーティングルールを設定することで解決することができます。

```js:nuxt.config.js
  // Routing configuration
  router: {
    extendRoutes (routes, resolve) {
      routes.push({
        name: 'custom',
        path: '*',
        component: resolve(__dirname, 'pages/errors/404.vue')
      })
    }
  }
```

あとはcomponentで指定したページを用意するだけです。

```html:pages/errors/404.vue
<template>
  <p>出力される404ページ</p>
</template>
```

# 404以外のエラーも一括で対応したい時
エラー系のページは全部同じレイアウトでええ！って時はlayouts/error.vueが便利です。
エラーが起きた時はlayouts/error.vueが表示されます。ファイルを置くだけなので簡単です。
エラーコードによる文言の出し分けも、もちろんできます。

```html:layouts/error.vue
<template>
  <div class="container">
    <h1>{{ error.statusCode }}</h1>
    <p v-if="error.statusCode === 404">
      ページが見つかりません
    </p>
    <p v-else>
      エラーが発生しました
    </p>
  </div>
</template>

<script>
export default {
  props: {
    error: {
      type: Object,
      default: null
    }
  }
}
</script>
```

# まとめ
今回は存在しないURLにアクセスされた時に任意のページを表示する方法を紹介しました。
普通はlayouts/error.vueを置く方法で404系は対応できますが、
404を凝ったページを表示したい時や、出し分けせずに別ページで対応したい場合などの用途にお使いください。
WSL(openSUSE)にPython3.7.2をインストール

#概要
WSL(openSUSE Leap15)にPython3を導入したがzypper経由だと3.6.5までしか入らない(2019/03/13現在)．最新の3.7.2をビルドしたらいろいろハマったのでメモ．

#導入
まずはPython3をインストール．

```Fish
sudo zypper install python3
```
ついでにpipも入れた．

```Fish
sudo zypper install python3-pip
```
#最新版のビルド
[LinuxにPython3系をインストールする手順](https://shimi-dai.com/install-python3-on-linux/)
[Unix プラットフォームで Python を使う](https://docs.python.org/ja/3/using/unix.html)
を参考に最新版をビルドした．
**(注)make installはPython3のバイナリを破壊する可能性があるらしいのでmake altinstallが推奨されている．これについては「あとがき」参照．**

```Fish
wget https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tgz
tar -xvzf Python-3.7.2.tgz
cd Python-3.7.2
./configure
make
sudo make install
```
すると最後らへんにこんな文言が出た．

```
zlib not available
make: *** [install] Error 1
```
zlibないのか～と思ってインストールを試みる．

```
sudo zypper install zlib                                                                                 14:45:32 [sudo] password for root:
Loading repository data...
Reading installed packages...
'zlib' not found in package names. Trying capabilities.
'libz1' providing 'zlib' is already installed.
Resolving package dependencies...

Nothing to do.
```
zlibというパッケージ名ではないようだが，あるにはあるらしい．困った．
ということで
https://github.com/pyenv/pyenv/wiki
を参考にコードを走らせる．

```
zypper install gcc automake openssl-devel ncurses-devel readline-devel zlib-devel tk-devel libffi-devel sqlite3-devel
```
そんで，再び

```
./configure
make
sudo make install
```
すると無事3.7.2になりました．

#あとがき
ビルドの時に参考にしたPython本家ドキュメントには
>警告 make install は python3 バイナリを上書きまたはリンクを破壊してしまうかもしれません。そのため、make install の代わりに exec_prefix/bin/pythonversion のみインストールする make altinstall が推奨されています。

とあるので，make installする前に

```
./configure
make 
sudo make altinstall
```
をした．
すると

```
setuptools in /usr/local/lib/python3.7/site-packages (40.6.2)
pip in /usr/local/lib/python3.7/site-packages (18.1)
```
と出力され，Python本体のバージョンは変わらなかった．
仮想環境で3.7.2を入れられるようになったということだろうか．
自分は本体も更新したかったのでmake installした．
この辺は詳しい事情を知らないので誰か教えてください．オナシャス．


#参考資料
URLの再掲．
[LinuxにPython3系をインストールする手順](https://shimi-dai.com/install-python3-on-linux/)
[Unix プラットフォームで Python を使う](https://docs.python.org/ja/3/using/unix.html)
https://github.com/pyenv/pyenv/wiki

初投稿につき参考にさせて頂きました．ありがとうございます．
[Qiita初心者の投稿方法備忘録](https://qiita.com/cloversoft/items/0f12f3a739312d35cb8f)
[Qiita記事の書き方〜基本の基本〜](https://qiita.com/48saaan/items/ec2e823e598b457d42eb)
Elmのパッケージインストール支援ツールを作ってみた

どうも、うじまるです。
ちょっと前々からほしいと思っていたElmのパッケージインストール支援のツールをgolangの勉強がてら作って見たので紹介します。

# 作った経緯
Elmは標準のコマンドでパッケージのインストールをしてくれるサブコマンドを提供してくれてます。
ターミナルで

```sh
$ elm install "author/package-name"
```

みたいな感じでやればインストールしてくれます。
ただ、個人的に若干不便なところがあって「パッケージの作成者名をつけないとインストールがされない」というところです。
同じパッケージ名にされると一意性がなくなってしまうので必要なものなのですが、「パッケージ名は知っていても作成者名は覚えていない」っという場面が多々あります。（`elm-ui` の場合だと `mdgriffith/elm-ui` とか）

`elm install` でも雰囲気あっていたら「これじゃない？」みたいな感じで候補をいくつか出してくれるのですが作成者名が脳の片隅にもないような状況だと厳しいです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/159238/0ddcf127-a907-9c66-a606-84bbc622b9ce.png)
(優しい`elm install`の図)

# 作ったもの
![][1]
そこで作ったものが `Elm Package install Supporter` 約して `eps` です。
あくまでも **Supporter** なのでCLIの中で `elm install` を使っています。
[リポジトリ][2]

elmのパッケージ一覧を全表示してFuzzyFinderで「確かこんな感じの名前だったよな・・・」みたいな状況でもinstallできるようにしました。
あと、LicenseとSummaryを表示するようにしてみました。パッケージ名が被っている場合に使えればなーっと思っています。

# 使い方
インストールの方法ですが、まだ頻繁に変更・修正があると思うので[リポジトリ][2]をcloneして `go build && go install` で入れてください:pray: (golang製のツールのメジャーな配布方法を知らないので教えてください！！）

使い方としては、`elm init` してあるディレクトリで

```sh
$ eps
```

と入力してもらえば上の画像のような画面になるのでほしいpackage名を入力すれば候補のものにハイライトが付きます。 `ctrl + j` で上に `ctrl + k` で下に移動します。
最後に `enter` でパッケージをインストールすることができます。

# 作ってみて
個人的にはいいと思っています。
Elmは公式のパッケージが充実しているので `elm/` のパッケージでいい時が多いですが、`elm-ui`などのStyle系のライブラリがほしいときや `extra`系パッケージが欲しい時にいちいち名前を検索するためにブラウザで検索して・・・って言うのはちょっとめんどくさいです。そのひと手間がなくなっただけでもかなり良かったなっと思いました。

あと、golangめちゃくちゃすぐできてしまったので最高だなって思いました。むつかしい部分はとても素晴らしいライブラリを使って作ったのですがそれでも半分寝てるような脳みそでサクッと作れたのでCLIを作るときはgolangを使って行きたいと思いました。

# 最後に
いろいろと問題点が多いと思っているので、よかったらアドバイスやPull-Requestを投げてもらえたら嬉しいです:bow:
[リポジトリ][2]

[1]: https://qiita-image-store.s3.amazonaws.com/0/159238/c8f34897-7abe-5653-68fa-5346fbdbb1b9.png
[2]: https://github.com/uzimaru0000/eps
NFSのパラメータ値について

# まずはマニュアルを見よう
https://linuxjm.osdn.jp/html/util-linux/man5/nfs.5.html

# Timeout値の単位に注意
timeoオプションの単位は1/10秒単位で指定する必要がある。
30秒を設定しているつもりで `timeo=30` と設定しても実は3秒です。
form外のボタンでsubmitできない時の対処法

#解決したいこと(1)
フロント(デザイン)の関係でformタグ内に各種パーツ(inputやsubmitボタンなど)を配置できないが、form外のパーツを送信したい。

以下のような場合↓

```html
　<form action="">
　　<label for="">formタグ外のボタンからテキストを送信したい。</label>
　　<input type="text">
　</form>

　<div>
　　<button type="submit">submit</button>
　</div>
```

#対処法(1)
- formタグにidを付与
- buttonにformクラスを追加し、formタグのidと同じものをつけて紐付ける。

###対処後のコード

```html
<form id="hoge" action="">
　<label for="">formタグ外のボタンからテキストを送信したい。</label>
　<input type="text">
</form>

<div>
　<button type="submit" form="hoge">submit</button>
</div>
```

#解決したいこと(2)
HTML内でPHPのforeachで回した時にハマったこと。

- テーブルセルの編集をクリック→送信→DBを更新したい
- 常に一番上にあるセルのレコードのみが更新されてしまう

#対処方(2)
常に同じレコードしか更新されないため、**送信されるもの（inputされたもの）が厳密に識別されていないのでは**、と推測。

###失敗パターン
modalの紐付け部分抜粋

```html

<div>
　<button type="button" class="btn btn-light" data-toggle="modal" data-target="#moge-modal">クリックで送信formを開きます。</button>
</div>
<div class="modal fade" id="moge-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
```
.modal-body部分のみ抜粋

```php
<div class="modal-body">
　<form id="moge" action="form_update.php?feed_update=<?php echo $r['id']; ?>" method="POST">
　　<label for="">formタグ外のボタンからテキストを送信したい。</label>
　　<input type="text" class="form-control" name="feed_update">
　</form>
　<div>
　　<button type="submit" class="btn btn-light" form="moge">submit</button>
　</div>
</div>
```
###成功パターン
modalの紐付け部分抜粋

```php
<div>
　<button type="button" class="btn btn-light" data-toggle="modal" data-target="#moge-modal<?php echo $r['id']; ?>">クリックで送信formを開きます。</button>
</div>
<div class="modal fade" id="moge-modal<?php echo $r['id']; ?>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
```
.modal-body部分のみ抜粋

```php
<div class="modal-body">
　<form id="moge<?php echo $r['id']; ?>" action="form_update.php?feed_update=<?php echo $r['id']; ?>" method="POST">
　　<label for="">formタグ外のボタンからテキストを送信したい。</label>
　　<input type="text" class="form-control" name="feed_update">
　</form>
　<div>
　　<button type="submit" class="btn btn-light" form="moge<?php echo $r['id']; ?>">submit</button>
　</div>
</div>
```

#参考および使用したもの
###参考
[Bootstrap4移行ガイド](https://cccabinet.jpn.org/bootstrap4/)
###今回のコード
以下のソースでは、submitボタンの位置やデザインが上記のコードとは異なりますのでご注意下さい。表示位置およびデザインが異なるだけで挙動は同一です。
[GitHub](https://github.com/exchange-wata/Qiita-form)

#終わりに
今回は、テーブルのレコード（横一列）を丸ごとforeachで回していたので、formタグのidとボタンのformクラスにDBからのidを追加することで識別できました。

開くmodalの識別も必要になります。formタグ等と同じようにDBからのidを付与し、**厳密な識別**を行なってください。

表示させるもの全てが、foreachの中にあるからこそできることですね。ボタンがformタグの中にない、foreachの中にもないとなった時にはJSを動かす必要がありそうです。
pythonでJSONファイルを書き出すときに、日本語を文字化けしないようにする

```python
import json
d = {"日本語":81}
fw = open('keywords_appearances.json','w', encoding='utf8')
json.dump(d,fw,indent=4,ensure_ascii=False)
```

open()の中のencodingをutf8にした後、json.dumpのensure_ascii=Falseに設定する
jqでparse error: Invalid string: control characters from U+0000 through U+001F must be escapedが出るときの対応

# はじめに


json形式のレスポンスをパースしようと思ってjqを使ったが、

```bash
$ sh log.sh
parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 7, column 3
```

こういうエラーがでた。

# 環境
* WSL

```bash
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.5 LTS
Release:        16.04
Codename:       xenial
```

* jq

```bash
$ jq --version
jq-1.5-1-a5b5cbe
```

# 原因
> どうやら要素における改行が認められなくなったようで、jq 1.5がこのようなエラーを出します。
https://mbahack2.syui.cf/blog/2015/08/20/json-u-plus-0000-through-u-plus-001f/

ということらしい。

# 対処法

jqでパースする前にtrで制御文字を全部消してみる。

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

echo '
[{
  "hoge": "huga",
  "foo": "
    baa
    piyo
  "
}]
' | tr -d '[:cntrl:]' | jq .
```

```bash
$ sh jq.sh
[
  {
    "hoge": "huga",
    "foo": "    baa    piyo  "
  }
]
```

一応これでやりたいことはできるようになった。
GoogleChromeの検索結果もダークモードにする方法

GoogleChromeにダークモードが追加されたなら検索結果も黒くしようよ
<img width="1373" alt="スクリーンショット 2019-03-13 13.39.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/354659/b1bcde3e-b0fd-cb7f-f5c6-9aa8c6a2b0eb.png">


# Dark Theme for Google のダウンロード

Chromeウェブストアで **[Dark Theme for Google](https://chrome.google.com/webstore/detail/dark-theme-for-google/apiabgjfojnkcepfmbdechlhfocpeenc)** と検索

<img width="802" alt="スクリーンショット 2019-03-13 13.49.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/354659/fcb52d92-9968-5730-91ca-3d033b03a143.png">

# 配色の設定

デフォルトの色はあまり好きじゃないから配色を変える
ブラウザの設定画面に移動して **拡張機能** を開く

<img width="1440" alt="スクリーンショット 2019-03-13 13.56.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/354659/6134a73d-8003-dbaf-4a20-4013b56f2d3f.png">

拡張機能管理画面の中にある **Dark Theme for Google** の詳細を開く

<img width="415" alt="スクリーンショット 2019-03-13 13.50.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/354659/f5f180bc-3742-23b2-6647-336341e05eb0.png">

<img width="1440" alt="スクリーンショット 2019-03-13 13.52.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/354659/0d8cb471-c1d2-1ebe-f1a6-c222cdb5342c.png">

**拡張機能のオプション** という項目を開いて配色を設定する
僕の配色はこんな感じ

<img width="1440" alt="スクリーンショット 2019-03-13 13.52.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/354659/2e2e4a50-4871-1a35-4a07-ec9e1a7db63a.png">

やっぱり黒配色の方がCoolだよね
良きChrome Lifeを！
メソッド内に変数を束縛する

# 最初に

フィボナッチ数列をメソッドに記述することを考えます。
[フィボナッチ数列](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0)は
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55,……
と続いていく数列です。
式としては
F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2) （n>=2の場合）
と表されます。
※1から始める場合もあるようですが、今回は0から始める数列としました。

これをそのままC#で記述しようと思えば以下の様になります。

``` cs

private int Fib(int n)
{
	if (n == 0)
	{
		return 0;
	}
	else if (n == 1)
	{
		return 1;
	}
	else
	{
		Fib(n-1) + Fib(n-2);
	}
}

```

しかし、このメソッドでは n>=2 の場合に行われる Fib(n-1) と Fib(n-2) の計算で重複しており、速度上の問題を抱えています。

# メソッドを高速化する

簡単に高速化を考えるのであれば、計算した結果をキャッシュして置き、計算済みのものはそこから取得するようにすることが思いつきます。

``` cs

private static readonly Dictionary<int, int> Cache = new Dictionary<int, int>();

private int Fib(int n)
{
	int result;
	if (Cache.TryGetValue(n, out result))
	{
		return result;
	}
	
	if (n == 0)
	{
		result = 0;
	}
	else if (n == 1)
	{
		result = 1;
	}
	else
	{
		result = Fib(n-1) + Fib(n-2);
	}
	
	Cache.Add(n, result);
	return result;
}

```

このメソッドにおける問題としては、計算結果を保存しておく Cache が他のメソッド等から書き換えられる可能性があります。
※メソッドが複雑になったこと、非同期呼び出しについての意見もあると思いますが、それは別の検討事項としたいと思います。

# メソッド内にメンバを閉じ込める

メソッド内に計算結果を保存する変数を閉じ込めることを検討します。
以下の様に記述します。

``` cs

private static readonly Func<int, int> Fib = CreateFib();
private static Func<int, int> CreateFib()
{
	Func<Dictionary<int, int>, int, int> fib = (cache, n) =>
	{
		int result;
		if (cache.TryGetValue(n, out result))
		{
			return result;
		}

		if (n == 0)
		{
			result = 0;
		}
		else if (n == 1)
		{
			result = 1;
		}
		else
		{
			result = Fib(n - 1) + Fib(n - 2);
		}

		cache.Add(n, result);
		return result;
	};
	
	return val => fib(new Dictionary<int, int>(), val);
}

```

これによりCreateFib内で作成されるDictionaryのインスタンスは他のメソッド等からアクセスされないため、安全に使えます。

# 最後に

実際にフィボナッチ数列を高速化するのであれば一般解を求め、一般解をメソッド化することが安全で高速な方法だと思います。（実際にフィボナッチ数列を業務で書く人もいないと思いますし）
定義を素直に記述すると再帰が発生し、遅くなる可能性がある例として利用しましたが、
この技法そのものは特定のメソッドでしか使用しない特定のメンバをメソッド内に閉じ込め、安全性を高めることに利用できると思います。
detox でテスト毎に端末を初期化する

# はじめに
[前回の記事](https://qiita.com/dhythm/items/df17f0c80d80c74a7d02)で`detox`の導入について書きました。

自分が携わってるアプリでは、ログインの有無で表示画面の内容が変わります。
ログイン情報は`react-native-keychain`で管理しているのですが、テストの冪等性を保証するために奮闘した内容を記載します。
(もっと良い解決策があればご教示いただけるとありがたいです。)

# デバイスの初期化処理
初期化をするにあたり、[公式ドキュメント](https://github.com/wix/Detox/blob/master/docs/APIRef.DeviceObjectAPI.md)で使えそうな関数がいくつかあります。

### `device.reloadReactNative();`
> If this is a React Native app, reload the React Native JS bundle. This action is much faster than device.launchApp(), and can be used if you just need to reset your React Native logic.

挙動としては `CMD+R`によるリロードが行われているようです。
（初期画面に戻ります。クレデンシャルはリセットされません。）


### `device.launchApp(params)`
##### `newInstance: true`

> Terminate the app and launch it again. If set to false, the simulator will try to bring app from background, if the app isn't running, it will launch a new instance. default is false

この設定を入れることで、新たなインスタンスとしてアプリを起動してくれそうです。

##### `delete: true`

> A flag that enables relaunching into a fresh installation of the app (it will uninstall and install the binary again), default is false.

この設定を入れることで、アプリをデリート→再インストールしてくれそうです。

上記を踏まえて、下記の形でテストを実行してみました。

```typescript
describe('example', () => {
  beforeEach(async () => {
    await device.launchApp({
      delete: true,
      newInstance: true,
    });
  });

  it('test is described here', async () => {
    // ...
  }
});
```

しかし、結果としてクレデンシャルはリセットされず…。


### `device.resetContentAndSettings()`

> Resets the Simulator to clean state (like the Simulator > Reset Content and Settings... menu item), especially removing previously set permissions.

xcode でシミュレーターをリセットする際に実施する手順と同じ内容を実行できます。

この関数を単体で利用した場合にはテストが終了しなかったので、`device.launchApp`と合わせて使ってあげる必要がありそうです。

最終形としては下記になりました。

```typescript
describe('example', () => {
  beforeEach(async () => {
    await device.resetContentAndSettings();
    await device.launchApp({
      delete: true,
      newInstance: true,
    });
  });

  it('test is described here', async () => {
    // ...
  }
});
```

# デメリット

### 処理時間
この方法は、`device.reloadReactNative()`と比べて非常に時間がかかります。
サービスの初期画面がログイン処理で、すべてのテストの冪等性を…と考えると全テストの前にこの処理を配置することになるので処理時間は悪夢です。

### ヘッドレスモード
上記の処理を使わずテストを動かしている際に、ぬるぬる動く画面を見て処理の状況を確認できました。
また、`detox test`コマンドは`--record-videos`オプションをつけると処理の動画も保存してくれます。

ですが今回、上記の処理を付加すると`--record-videos`オプションを使用してテストを実行できませんでした。


# おわりに
テストの冪等性は非常に重要だと思います。
とはいえ、この方法だと非常にテストに時間がかかってしまうので、クレデンシャルのリセットをもう少し早くできる手法が欲しいものです。
wordpressのSimpleMembershipでログインしていない時の文章を変える

"このコンテンツを閲覧するにはログインが必要です。お願い ログイン. あなたは会員ですか ? 会員について"を変更したく色々調べたもののドンピシャのがなかったのでメモ。

wp/wp-content/plugins/simple-membership/classes/class.swpm-access-control.php

から div class="swpm-post-not-logged-in-msg"を探し（48行目あたり）後に続く.$text.を

```
$text = 'このコンテンツを閲覧するにはログインが必要です。<br />
会員の方は<a href="#">ログイン</a>して下さい。<br />会員登録は<a href="#">こちら</a>';
```

のような感じで書き換える
EclipseでCtrl + マウスホイールによる拡大縮小

見当たらなかったので。

`Ctrl+マウスホイール`による拡大/縮小は基本的人権の1つ[^1]である(要出典)が、Eclipseは対応していない。キーバインドのズームイン/アウトにマウスを割り当てることはできないようだ。
こんな暴虐が許されてなるものかと思ったのでサクッとググった。

#解決方法
[AutoHotkey](https://www.autohotkey.com/) で `Ctrl+マウスホイール`を`Ctrl+"+"`, `Ctrl+"-"`に[割り当てれば良い](https://stackoverflow.com/questions/790720/eclipse-ide-how-to-zoom-in-on-text)ようだ。
AutoHtokeyを[導入](https://qiita.com/chr/items/47f50e36703d3bb20371)した後、以下の`.ahk`ファイルを作成し、スタートアップにでも登録しておく。

```ahk:eclipse_zoom.ahk
; Ctrl+MouseWheel zooming in Eclipse.
; Only for 109 keyboard layout.
#IfWinActive ahk_exe eclipse.exe
    ^WheelUp:: Send ^+;
    ^WheelDown:: Send ^-
#IfWinActive
```
日本語キーボード(109レイアウト)なので`Ctrl + Shift + ";"`が拡大コマンドとなる。縮小はそのまま`Ctrl + "-"`で良い。
参考元のスクリプトでは`ahk_class`が`SWT_Window0`であることのみ判断しているので、`SWT`を利用しているアプリ上ではほとんど全て有効となってしまうようだ。Eclipse で開発されたアプリは引っかかる確率が高い[^2]。(あと多分、インスタンスによってはSWT_Window1とかになる気がする)
したがって`#IfWinActive ahk_exe eclipse.exe`で[Eclipseのみを指定する](http://ahkwiki.net/Window#.E3.83.97.E3.83.AD.E3.82.BB.E3.82.B9.E5.90.8D.E3.81.AE.E6.8C.87.E5.AE.9A)。これはAutoHotkeyのVer1.1.1以降の対応であるため、旧バージョンからアップデートできない場合は参考元のスクリプトを参照して頂きたい。

なおAutoHotkeyのタスクトレイアイコンを`右クリック`>`Window Spy`あるいはインストールディレクトリ以下の`WindowSpy.ahk`をダブルクリックすることで、アクティブウィンドウのack_exeなどを[取得できる](https://rcmdnk.com/blog/2013/07/29/computer-windows-autohotkey/#window%E3%81%94%E3%81%A8%E3%81%AE%E8%A8%AD%E5%AE%9A)。


#参考
[Eclipse IDE: How to zoom in on text?](https://stackoverflow.com/questions/790720/eclipse-ide-how-to-zoom-in-on-text)
[Windows10へAutoHotkeyの導入（キーマップの変更）Qiita](https://qiita.com/chr/items/47f50e36703d3bb20371)
[AutoHotkey 公式ドキュメント - ウィンドウ指定の方法](http://ahkwiki.net/Window#.E3.83.97.E3.83.AD.E3.82.BB.E3.82.B9.E5.90.8D.E3.81.AE.E6.8C.87.E5.AE.9A)
[AutoHotkeyの使い方2](https://rcmdnk.com/blog/2013/07/29/computer-windows-autohotkey/#window%E3%81%94%E3%81%A8%E3%81%AE%E8%A8%AD%E5%AE%9A)


[^1]: もちろん`Ctrl+"+"`, `Ctrl+"-"`による操作で十分という人も居るし、UI論的には`二本指ズーム`に対応していない点で論外という主張もあるだろう
[^2]: 社用PCではIBM Notesが引っかかった。まぁ当該アプリは拡大縮小そのものが存在しないので問題なかったが(良くねぇ)
【Processing】UDPの送受信

初投稿です^^
ロボット業界でエンジニアをしているものです。
プログラムは勉強中なので、アドバイスをいただけると嬉しいです！

#概要
・目的：　Processingを用いた、UDPの送信と受信を簡易的に行えるようにする。
・内容：　送信ボタンを押すとUDP通信で受信のログに記載される。
・準備：
　　1.　Processingのダウンロード
　　2.　ライブラリのインポート
　　3.　コードを書く
　　4.　実行

#実践
###1. Processingのダウンロード


　　[ダウンロードはココから](https://processing.org//　"プロセッシング")


###2. ライブラリのインポート
　　1. Processingを起動し、「スケッチ/ ライブラリをインポート.../ ライブラリを追加...」の順で進んでください。

　　2. “UDP”と“controlP5”をインストールしてください。
　　 　「Status」に緑のチェックがついている「Name」を選択し、「Install」をクリック。

　　　  ※“ControlP5”はProcessingにおけるGUIコントローラの一種です。

![ConIP5a.png](https://qiita-image-store.s3.amazonaws.com/0/375869/3ed618a0-be44-1693-4802-d33e74737541.png)
![UDP.png](https://qiita-image-store.s3.amazonaws.com/0/375869/36d83870-550d-cc51-35f4-7e0e07d131b9.png)


  インストールを終わったら、完了です！


###3.　コードを書く
　　
　　では、コードを書いていきます。
　　
　　送信側のコードは下記のとおりです。

```pde:udpSend.pde
import hypermedia.net.*;
import controlP5.*;

UDP udp;
ControlP5 cp5;

final String IP = "localhost";
final int PORT = 1000;　　　　　//送信側のポート番号

String msg = "test_messege";   //UDPで送るコマンド

void setup() {
  size(200, 200);
  
  cp5 = new ControlP5(this);
  udp = new UDP( this, 2000 );
  
  ControlFont cf = new ControlFont(createFont("メイリオ",20));
  
  cp5.addButton("UDP_Msg")
    .setFont(cf)
    .setLabel("送信")
    .setPosition(50,50)
    .setSize(100,100);
}

void draw() {
  background(200);
}

void UDP_Msg(){
  udp.send(msg,IP,PORT);
}
```



　　受信側のコードは下記のとおりです。

```pde:udpReceive.pde
import hypermedia.net.*;
import controlP5.*;

UDP udp;

final String IP = "localhost";
final int PORT = 2000;

void setup() {
  udp = new UDP(this, 1000);
  udp.listen( true );
}

void draw() {;}

void receive( byte[] data, String ip, int port ) {
  String message = new String( data );
  println( "receive: \""+message+"\" from "+ip+" on port "+port );
}
```


###4.　実行
　　実行結果すると下記の図のようになります。
　　「送信」ボタンを押すとreceiveで受け取れてるのがわかりますね！

![名称未設定.png](https://qiita-image-store.s3.amazonaws.com/0/375869/8dc68483-f439-16ae-969c-7a6ccab07d79.png)


　　以上、簡単にご紹介しました。
　　ご質問や、アドバイス等があれば気軽にコメントしてください。


#余談

　　PCの壁紙が目に悪いと言われますが、この色が好きなのです！

　　今年のカラー・オブ・ザ・イヤー2019に選ばれたのが『Living Coral（リビングコーラル）』です。
　　
　　　・PANTONE：16-1546 Living Coral
　　　・カラーコード：#FF6F61
　　　・RGB：R255, G111, B97
　　　・CMTK：C0, M65, Y54, K0

　　この色を今年は多く取り入れれば、良いことあるかもです！
PHP: Unicodeのコードポイントを求める関数

UTF-8文字からUnicodeのコードポイントを求める関数です。

```php
var_dump(toCodePoint("\0")); //=> string(6) "U+0000"
var_dump(toCodePoint("\n")); //=> string(6) "U+000A"
var_dump(toCodePoint("A")); //=> string(6) "U+0041"
var_dump(toCodePoint("a")); //=> string(6) "U+0061"
var_dump(toCodePoint("あ")); //=> string(6) "U+3042"
var_dump(toCodePoint("𠮷")); //=> string(7) "U+20BB7"

function toCodePoint(string $char): string
{
	return sprintf("U+%04X", hexdec(bin2hex(mb_convert_encoding($char, 'UCS-4', 'UTF-8'))));
}
```
Laravelのログインを改造してみた

# やりたいこと

システムのリニューアルのためLaravelで作っていたら、旧システムのユーザーをパスワードの変更なく移行したくなった。
なお、旧システムのパスワードは平文ではなく、謎ロジックで認証が動いているが、ロジックは移行可能とする。

# どうやるか

\app\Http\Controllers\Auth\LoginController.phpを改造（カスタマイズ）する。

ログイン時に通常のLaravelの認証を通して失敗した後、独自のロジックで認証を行い、成功した場合はログインするという方向で検討。

なお、Laravelのバージョンは5.7とする。

## 調べる

AuthenticatesUsersを調べると
`public function login(Request $request)`
の中で
`$this->attemptLogin($request)`
がtrueを返す場合にログイン成功しているようなので、attemptLoginをオーバーライドして改造すれば良さそう。

## やってみる

とりあえず独自の認証ロジックは、固定のID、パスワードで成功するかどうかで試してみる。

```php:LoginController.php
protected function attemptLogin(Request $request)
{
    $attempted = $this->guard()->attempt(
        $this->credentials($request), $request->filled('remember')
    );

    if (!$attempted) {
        // ここに旧ユーザー用の独自の認証を作る
        if ($request[$this->username()] == 'hoge@hoge.jp' && $request['password'] == 'fuga') {
            $user = User::where('email', $request->input($this->username()))->first();
            if ($user) {
                // 本来のパスワードに保存
                $user->password = Hash::make($request->input('password'));
                $user->save();
                // 認証が通ったらログイン処理をする
                \Auth::login($user);
                $attempted = true;
            } else {
                $attempted = false;
            }
        }
    }

    return $attempted;
}
```

条件をパスした後にUserオブジェクトを取得して`Auth::login($user)`してあげることで、ログインできた。