OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonのunittestパッケージをコードリーディング（その2）

前回の記事で扱ったとおり，unittestがどのようにファイル内から継承したクラスを取り出すのかを確認しました。今回は，前回割愛した"継承したクラスからテスト用メソッドを取り出す方法"を確認したいと思います。

#前回のおさらい
unittest/loader.pyの119行目以降にあるコードによりunittestはファイル（モジュール）に定義された`case.TestCase`を継承するクラスを見つけ，`tests`リストに追加（append）されます。その際，抽出されたクラスに`self.loadTestsFromTestCase`メソッドが適用され，その結果が`tests`に追加されます。

```py3:unittest/loader.py
tests = []
for name in dir(module):
    obj = getattr(module, name)
    if isinstance(obj, type) and issubclass(obj, case.TestCase):
        tests.append(self.loadTestsFromTestCase(obj))
```


#loadTestsFromTestCaseメソッド
上記のように，`loadTestsFromTestCase`メソッドが抽出されたクラスをもとに戻り値を`append`メソッドにに渡しているため，こちらのメソッド（unittest/loader.pyの83行目以降）の中身を見ていきます。

```py3:unittest/loader.py
    def loadTestsFromTestCase(self, testCaseClass):
        """Return a suite of all test cases contained in testCaseClass"""
        if issubclass(testCaseClass, suite.TestSuite):
            raise TypeError("Test cases should not be derived from "
                            "TestSuite. Maybe you meant to derive from "
                            "TestCase?")
        testCaseNames = self.getTestCaseNames(testCaseClass)
        if not testCaseNames and hasattr(testCaseClass, 'runTest'):
            testCaseNames = ['runTest']
        loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
        return loaded_suite
```

メソッド内のコメント，メソッド名，変数名などから推測できるように，中段にある`getTestCaseNames`で`testCaseClass`クラス内に定義されたテスト用メソッドを抽出しているようです。

#getTestCaseNamesメソッド
`getTestCaseNames`メソッドは，unittest/loader.pyの222行目以降にあります。

```py3:unittest/loader.py
    def getTestCaseNames(self, testCaseClass):
        """Return a sorted sequence of method names found within testCaseClass
        """
        def isTestMethod(attrname, testCaseClass=testCaseClass,
                         prefix=self.testMethodPrefix):
            return attrname.startswith(prefix) and \
                callable(getattr(testCaseClass, attrname))
        testFnNames = list(filter(isTestMethod, dir(testCaseClass)))
        if self.sortTestMethodsUsing:
            testFnNames.sort(key=functools.cmp_to_key(self.sortTestMethodsUsing))
        return testFnNames
```

コメントにそのまま記述されているとおり，引数として受け取った`testCaseClass`を継承したクラス内からテスト用に定義したメソッドを抽出することが，このメソッドの目的のようです。ここで２つのことに目が行きます。１つは前回の処理と同様，対象候補を抽出するために`dir`を利用していることです。前回は，ファイル（モジュール）内のクラスを抽出する方法としてdirを利用していましたが，これと似た方法として，クラスからメソッドを抽出する際にもdirを利用しています。もう１つは，メソッド内に定義された`isTestMethod`メソッドです。`filter`関数の第1引数として利用されていることからも分かるとおり，このメソッドは判定に使用され，その判定条件は以下になります。

- dirで取得した属性名の先頭が"test"で始まるかどうか
- その属性名はコール可能か（すなわちメソッドかどうか）

上記の１つ目は，`isTestMethod`内で`startswith(prefix)`を利用していることからわかります。２つ目は，`getattr`を利用して属性名からオブジェクトを取り出し,`callable`によって呼び出し可能かどうかを判定していることからわかります。

#まとめ
以上のように，ファイル（モジュール）から特定のクラスを抽出するケースやクラス内の特定のメソッドを抽出するケースでは，以下の流れで進めることが有効であることがわかりました。

1. dir関数でそのモジュール（クラス）の属性名のリストを取得する
2. getattr関数で属性名からオブジェクトを取得し，そのオブジェクトが持つ性質を判定できるようにする
3. if文やfilter関数を利用して，条件にマッチする属性名を抽出する

個人的には，`getattr`関数をどの場面で場面で利用すればよいのかよくわかっていなかったため，上記のように，"dirで取得した属性名が抽出したい対象かどうかを判定するため，その属性名のオブジェクトを取得する"場面で利用できることがわかったのは大きな収穫でした。
Qiitaをズァーって感じで広く見るアプリ

[Qiow](https://github.com/nju33/qiow)っていうアプリをちまちま作りました。１ページでズァーって見れるアプリです。Macしか持ってないのでMac版だけです。

> ![qiow.png](https://qiita-image-store.s3.amazonaws.com/0/84144/f32ea119-fec8-9316-5cc4-dff437a133c9.png)

## 主に使った技術/テンプレート

- [electron/electron](https://github.com/electron/electron) 😄
- [SimulatedGREG/electron-vue](https://github.com/SimulatedGREG/electron-vue) 😆
- [ReactiveX/rxjs](https://github.com/ReactiveX/rxjs) » というか[vuejs/vue-rx](https://github.com/vuejs/vue-rx) 😇
- 他ネットサーフィンしてて気になってたやつとか

## 使い方

### インストール

[ここ](https://github.com/nju33/qiow/releases/latest)から`qiow.dmg`をダウンロード ➡️ 起動 ➡️ `/Applications`へコピーします。

> 「セキュリティで開けません…」的なことが聞かれた場合は、初回だけ`/Applications/qiow`を右クリックして「開く」をすると起動できるようになります。

### 個人アクセストークン取得

起動するとアクセストークンを入力する画面が出ると思うのでそこで登録する必要があります。

> ![qiow.png](https://qiita-image-store.s3.amazonaws.com/0/84144/ad2d739f-7768-86c8-8fc2-814ac2510804.png)
> ---
> ~~もし間違えた場合は、設定ファイルを直接削除してください。（実装めんどかった）~~
> アプリから直接変更できるようになりました。
> 
> ```bash
> # 多分
> rm /Users/<あなたのユーザ名>/Library/Application\ Support/qiow/storage/token.json
> ```
>




アクセストークンは、設定 ➡️ アプリケーション ➡️ 新しいトークンを発行する ➡️


![アプリケーション_-_Qiita_🔊.png](https://qiita-image-store.s3.amazonaws.com/0/84144/eee8e2f5-2d48-418f-5fce-93b794d193ec.png)

適当に説明入力 ➡️ 「発行する」 で発行できます。

![個人用アクセストークンを発行する_-_Qiita_🔊.png](https://qiita-image-store.s3.amazonaws.com/0/84144/cc41731a-9328-9a2b-2948-59ffcc9d6a46.png)

発行されると前の画面に戻るとアクセストークンがあるはずなのでコピーして、qiowアプリのフォームへペーストします。

![アプリケーション_-_Qiita_🔊.png](https://qiita-image-store.s3.amazonaws.com/0/84144/923b17e8-9ac8-f1ed-871d-b2d56c55ff09.png)

## 適当に使う

といっても検索するだけｗ

### タグ検索フィード

多分 Qiita の「キーワードを入力」で`tag:...`と検索したのと同じ感じで。多分使用頻度高いのでコレだけ分けました。

### テキスト検索フィード

これはそのまんま検索したものと同じですね。

### 説明苦手なのでGif

![jkkj.gif](https://qiita-image-store.s3.amazonaws.com/0/84144/fa84a5d4-ff97-9546-fc4e-869983beaae0.gif)


![ezgif-4-9a7464d585.gif](https://qiita-image-store.s3.amazonaws.com/0/84144/c9bd08c5-bef3-6833-9cba-1a87cea8f103.gif)

> `x`じゃなくて`ESC`でも閉じれます。

あとは、5分毎に最新の記事を取りに行って、もしあれば更新と通知を行うような機能もあります。

## おわりに

（多分バグありますが）良ければ使ってみてください<😞>

--- 

```markdown:CHANGELOG.md
### v0.0.3
- フィードのアイテムが2倍に増殖してしまいめちゃくちゃ重くなるバグあったので直しました。
```
Windows10でTeXLive2017

十年ぶりくらいでTeX触ったらいろいろと変わっててびっくりしたよ。

# インストール
## いまどきはTeXLive
むかしはteTeXでしたね。Win32TeXもありました（今もある）。

[インストーラ](https://www.tug.org/texlive/acquire-netinstall.html)をダウンロードして実施する。install-tl-advanced.batを利用して最低限の環境だけセットアップする（フルスキームのインストールとか言ったら、うちの型落ちの環境だと一日かかるよ無理だよ）。

 * 不可欠なプログラムとファイル
 * Windows限定サポートプログラム

![2017-10-15 (4).png](https://qiita-image-store.s3.amazonaws.com/0/43992/a3d4e6af-803c-a0da-c7af-e42c06dfffed.png)

インストール先も可搬設定にしておきましょう。トレイアイコンからしか使わないので。
![2017-10-15 (3).png](https://qiita-image-store.s3.amazonaws.com/0/43992/a269fdfb-0532-4f23-a61f-92b6c63a34dc.png)

# 日本語環境
大きく分けると2種類になると思う。

 * uplatex + dvipdfmx（従来資産活用型）
 * lualatex（グローバル追従型）

## upLaTeX + dvipdfmx
日本で主流なplatex系列。従来資産が豊富。ネット上の情報だけでもノウハウが充実している。コンパイルが高速。フォントの設定は魔窟。でも最近はほんとに良しなにやってくれる。

インストールパッケージは大体以下を指定すればよい。

 * uplatex dvipdfmx
 * babel-japanese jsclasses japanese-otf-uptex
 * adobemapping updmap-map ptex-fontmaps

埋め込みフォントを指定する（ここでは小塚明朝、配布時はライセンス注意）。
![2017-10-15 (5).png](https://qiita-image-store.s3.amazonaws.com/0/43992/c59646de-1404-f281-908c-9d910afbdf0d.png)


## luaLaTeX
海外で主流なpdfTeXの後継。pandocとか使うならこちらでないと連携できない。コンパイル遅い。とにかく遅い。

インストールパッケージは大体以下を指定すればよい。

 * luatex latex-bin
 * luatexbase luatexja luaotfload
 * ctablestack oberdiek ifluatex xkeyval etoolbox filehook
 * adobemapping ms lm ipaex amsfonts l3kernel l3packages fontspec

# 実例
## 和文縦書き
```tex
%% for lualatex
\documentclass{ltjtarticle}
\usepackage[kozuka-pr6n]{luatexja-preset}

%% for uplatex
% \documentclass{utarticle}
% \usepackage[expert]{otf}

\begin{document}
\part{幸田露伴「雲のいろ〳〵――卿雲」}
景雲といひ、卿雲といひ、慶雲といへる、しかと指し定められたる雲にはあらざるべし。
卿雲爛たり糺縵〻たり、といへる、煙にあらず雲にあらず紫を曳き光を流す、といへる、
大人作矣、五色氤氳、といへる、金柯初めて繞繚、玉葉漸く氤氳、といへる、
還つて九霄に入りて沆瀣を成し、夕嵐生ずる處鶴松に歸る、
といへる詩の句などによりて見れば、歸するところは美しき雲といふまでなり。
\end{document}
```

### upLaTeX
![2017-10-14 (1).png](https://qiita-image-store.s3.amazonaws.com/0/43992/70bcd0b7-68d2-f0f6-9f2c-bc9d2ff840ab.png)

### luaLaTeX
![2017-10-15 (1).png](https://qiita-image-store.s3.amazonaws.com/0/43992/94f2930c-359f-b66c-73e0-5d75776df38b.png)

## euler フォント
```tex
%% for lualatex
\documentclass{ltjsarticle}
\usepackage[kozuka-pr6n]{luatexja-preset}
\usepackage{amsmath}
\usepackage{unicode-math}
\setmathfont{Neo Euler}[math-style=upright]
\usepackage{luatexja-ruby}

%% for uplatex
% \documentclass[uplatex]{jsarticle}
% \usepackage{mathptmx}
% \usepackage{euler}
% \usepackage{okumacro}

\title{ミルカさんとフィボナッチ数列\footnote{http://www.hyuki.com/story/genfunc.html}}
\author{結城浩\footnote{http://www.hyuki.com/\ Hiroshi Yuki \copyright\ 2005, All rights reserved.}}
\date{2005年10月}

\begin{document}
\maketitle
…
```
### upLaTeX
TeXLiveにeulerパッケージを導入する。 
![2017-10-14.png](https://qiita-image-store.s3.amazonaws.com/0/43992/4a4456de-6a37-94ed-7e76-bce52aefd599.png)

### luaLaTeX
OSにNeo Eulerフォントを導入する。
![2017-10-15.png](https://qiita-image-store.s3.amazonaws.com/0/43992/c4fe4be8-4a69-88c2-bff4-ee8c0e65f507.png)

ちょっとΣの文字の大きさが違ってたりする。
MEAN.IOのバグに対応してみた

[この記事](https://qiita.com/matsum0623/items/dde32ec3cd4aaf228824)でmean.ioのインストールをした。
さらに、[その中で使われているツールになっとくいかない個所があった。](https://qiita.com/matsum0623/items/332ab8967c0185739ef3)

ということで自分なりに改修してみた。

## 対応方針
もともとの思想では、呼び出すだけでデフォルトでいくつかのDBパターンが使えるようになっているらし。
しかし、スキーマ定義に手を加えようと思うと、node_module側に修正が必要となるため、定義もすべてアプリ側で行えるように修正した。というよりデフォルトなんて使わない。

## 結果
npmに公開した。

[github](https://github.com/matsum0623/matsumgraph)
[npm](https://www.npmjs.com/package/matsumgraph)

README書き直さなきゃなぁと思いつつ、手が回らない。。。
Bugsnag 5.4でinfoレベルのRailsのエラーも通知されてしまう場合の対処方法

Bugsnag5.4.0からそれまでデフォルトで除外されていたエラーもinfoレベルで通知されるようになっているので、以下のどちらかの方法でメール通知から除外しておくほうが運用上良さそう。

## ignore_classes設定に追加する


```ruby:config/initializers/bugsnag.rb
Bugsnag.configure do |config|
  config.api_key = "xxxxx"
  config.notify_release_stages = %w[production staging]

  config.ignore_classes.merge([
    AbstractController::ActionNotFound,
    ActionController::InvalidAuthenticityToken,
    ActionController::ParameterMissing,
    ActionController::RoutingError,
    ActionController::UnknownFormat,
    ActionController::UnknownHttpMethod,
    ActiveRecord::RecordNotFound,
    SignalException,
  ])
end

```

## Bugsnag側の設定でinfoレベルはメール通知されないように設定する

1. Bugsnagのプロジェクトページを開く
2. Settings -> Email notifications -> Filter by severity
3. `info`からチェックを外す

## 参考リンク
* https://github.com/bugsnag/bugsnag-ruby/blob/master/CHANGELOG.md#540-02-oct-2017
* https://github.com/bugsnag/bugsnag-ruby/issues/360
PINE A64+ を mackerel で監視する（ CPU温度も監視する ）

[PINE A64+](http://amzn.to/2gk5c4f) を mackerel で監視したくて、mackerelのagentをインストールしようとしたら公式の手順通りには行かずハマったので、手順をまとめました。

ちなみに[PINE A64+](http://amzn.to/2gk5c4f)は、Raspberry Piよりシンプルで安いシングルボードコンピューターです。
お家でちょっとしたサーバーを動かしたい時に便利です。
スペックは[Raspberry Pi 3](http://amzn.to/2gkMDfU)と同等ですが、1Gb Ethernetに対応しています。wifiやbluetoothは対応していません。
秋月電子で2980円で買えます。

# mackerel agentのインストール手順
以下の前提で手順を書いています。
※Ubuntu 16.04.2
※agentのバージョンは2017/10/15時点の最新版の0.46.0-1

### ファイルのダウンロード
```
wget https://mackerel.io/file/agent/deb/mackerel-agent_0.46.0-1_all.deb
wget https://github.com/mackerelio/mackerel-agent/releases/download/v0.46.0/mackerel-agent_linux_arm.tar.gz
```

### インストール
```
sudo dpkg -i mackerel-agent_0.46.0-1_all.deb
```
※この時点では、intel cpu（x86）向けにインストールされているので、まだ動きません。

### ARM CPU用バイナリを上書き
```
tar zxf mackerel-agent_linux_arm.tar.gz
sudo cp mackerel-agent_linux_arm/mackerel-agent /usr/bin
```

### 設定
```
sudo nano /etc/mackerel-agent/mackerel-agent.conf
```
apikeyを以下の様に書き換える。

```mackerel-agent.conf
～（略）～

apikey = "(mackerelの管理画面で取得したAPIキー)"

～（略）～
```
※元はコメントアウトされているので#を外す！
※APIキーを記入


### 起動
```
sudo /etc/init.d/mackerel-agent start
```
※自動起動も設定されています。

### ログの確認（起動しない場合）
```
cat /var/log/mackerel-agent.log
```



# CPU温度監視の手順
さらにCPU温度の監視（カスタムメトリクス）したい場合は以下の様にします。
### プラグインスクリプト（cputemp.sh）の作成
```
sudo nano cputemp.sh
```

```cputemp.sh
#!/bin/bash
SECONDS=`date '+%s'`

NAME='temperature.cpu'
TEMP=`cat /sys/class/thermal/thermal_zone0/temp`
echo -e "${NAME}\t${TEMP}\t${SECONDS}"
```
※ラズベリーパイみたいにthermal_zone0の値（温度）が1000倍されてない

### 実行権限付与
```
sudo chmod 755 ./cputemp.sh
```

### プラグインを設定ファイルに登録
```mackerel-agent.conf
～（略）～

[plugin.metrics.temp]
command = "/home/ubuntu/cputemp.sh"

～（略）～
```
※追加場所はapikeyの下あたりでOK

### agentの再起動
```
sudo /etc/init.d/mackerel-agent restart
```

# 参考URL
[raspberrypi] mackerel-agent を簡単に導入する
http://blog.hidekiy.com/2015/07/raspberrypi-mackerel-agent.html

Raspberry Pi を Mackerel で監視する
https://qiita.com/ww24/items/5409aefd87f14beff504
Macで、Djangoでrunserver時「サーバー"localhost"が見つかりません」となってしまう

###・開発環境
macOS Sierra
virtualenvの仮想環境で
Djangoのチュートリアルを実行
https://docs.djangoproject.com/ja/1.11/intro/tutorial01/

###・エラー内容
`$ python manage.py runserver`
を実行した後
http://localhost:8000/polls/
にアクセスしたが
*「サーバー'localhost'が見つかりません」*
というエラーがでた。

###・解決方法
「システム環境設定」→「ネットワーク」→「状況」
の下に記載してあるIPアドレスをlocalhostと置き換えれば良い。

`$ python manage.py runserver`

ではなく

`$ python manage.py runserver IPアドレス:8000`

として実行した後、

http://localhost:8000/polls/

ではなく

http://IPアドレス:8000/polls/

にアクセスすると期待通り
`Hello, world. You're at the polls index.`
と表示された。

###・まとめ
localhostのアドレスが間違っている?まだまだ素人なので勉強しなければいけない。
ALBの概観図

AWSのALBの設定をするときに概念が混乱し始めて来てしまったので、全体の概念図をまとめようとおもいました。

今後、始めてALBを設定する人の参考になれば幸いです。

# 全体図

![image.png](https://qiita-image-store.s3.amazonaws.com/0/151852/dc3dc876-6441-33e8-91e9-551db861d20e.png)

各設定に関してはAWSのドキュメントや様々な記事が参考になるので詳しい設定方法は省略します。

1. Route53で、ドメイン名を、ALIASでALBと紐付ける。
2. ALBのListenerのTargetGroupを設定します。
3. TargetGroupに当該のEC2インスタンスを紐付けます。


# セキュリティグループをつける

![image.png](https://qiita-image-store.s3.amazonaws.com/0/151852/8082fb06-ab63-2344-3c8f-20d272dabeeb.png)

ALBと各EC2にそれぞれセキュリティグループをつけます。 
ALB  -> インバウンド：全て                    アウトバウンド:EC2のセキュリティグループ
EC2  -> インバウンド:ALBのセキュリティグループ    インバウンド: 全て
にそれぞれ設定します
Brewを使わずにMacにMongoDBを入れ、自動で起動するようにした時の備忘録


## 背景

仕事で使ってるMongoDBのバージョンが2.6でbrewで入れようとしたらhigh sierraだと入れれなさそうだったので(2017/10/13時点で)brewを使わずに入れてみた。


## MongoDBのダウンロード


任意のディレクトリに移動しておく

```
$ cd ~/
```


MongoDBのダウンロード

```
$ wget https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.6.5.tgz
$ tar zxvf mongodb-osx-x86_64-2.6.5.tgz
$ rm mongodb-osx-x86_64-2.6.5.tgz
```

名前を変更する

```
$ mv mongodb-osx-x86_64-2.6.5 mongodb
```

これでインストールされました。

## Pathを通す

```
$ vi ~/.bash_profile
```

中に以下を追記

```~/.bash_profile
export PATH=/Users/sugawara_ryosuke/mongodb/bin:$PATH
```

これでどこからでもmongoコマンドが使えるようになります。

```
$ mongod -version
```


## MongoDB起動

まずは必要なディレクトリを作成します。

```
$ mkdir ~/mongodb/log
$ mkdir ~/mongodb/db
```

起動

```
$ mongod --fork --logpath /Users/sakura/mongodb/log/mongodb.log --nojournal --noprealloc --dbpath /Users/sakura/mongodb/db
```

以下のようなのが表示されれば起動成功です。

```
note: noprealloc may hurt performance in many applications
about to fork child process, waiting until server is ready for connections.
forked process: 2926
child process started successfully, parent exiting
```

## Macを再起動しても自動で起動するようにする

これだけだとMacを再起動するたびに起動させなければなりません。

launchd/launchctl で起動するように設定。

```
$ sudo vi /Library/LaunchDaemons/org.mongodb.mongod.plist
```

中に以下を記入します。

```/Library/LaunchDaemons/org.mongodb.mongod.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>org.mongodb.mongod</string>
        <key>RunAtLoad</key>
        <true/>
        <key>ProgramArguments</key>
        <array>
               <string>/Users/sakura/sakura/mongodb/bin/mongod</string>
               <string>--dbpath</string>
               <string>/Users/sakura/sakura/mongodb/db</string>
               <string>--logpath</string>
               <string>/Users/sakura/sakura/mongodb/log/mongodb.log</string>
        </array>
</dict>
</plist>
```

念のためオーナーやパーミッションも変更。

```
$ sudo chown root:wheel /Library/LaunchDaemons/org.mongodb.mongod.plist
$ sudo chmod 644 /Library/LaunchDaemons/org.mongodb.mongod.plist
```

最後に読み込めば完了。

```
$ launchctl load /Library/LaunchDaemons/org.mongodb.mongod.plist
```


## MongoDBが自動起動しない場合
自動起動できていなかった場合は以下のコマンドを実行します。

```
$ rm /Users/sakura/mongodb/db/mongod.lock
$ sudo mongod --dbpath=/Users/sakura/mongodb/db --repair
```

これで完了です。


## 参考
* https://qiita.com/n0bisuke/items/9def9f1c5e8d878c0811
* http://babie.hatenablog.com/entry/20100601/1275420266
* https://qiita.com/momota10/items/cbe5c7e20b6f8d27e391
winAppDev > ファイルのロック条件 > Excelで開いている時

```txt:動作環境
Excel 2013 on Windows 8.1 pro(64bit)
C++ Builder XE4 on Windows 7 pro (32bit)
```

ファイルのロックに関して。

### Case 1. Excelで開いている時 > メモ帳で編集

- Excelで開いた状態で
- 同じファイルをメモ帳で開き、編集後に保存

> プロセスはファイルにアクセスできません。別のプロセスが使用中です。

### Case 2-a. メモ帳で開いている時 > Excelで編集

- メモ帳で開いた状態で
- 同じファイルをExcelで開き、編集後に保存

エラーなく保存された。

### Case 2-b. メモ帳で開いている時 > C++ Builder実装ソフトで編集

- メモ帳で開いた状態で
- C++ Builder実装ソフトで上書き
    - SaveToFile()使用

エラーなく保存された。
メモ帳上の表示は変更されないが、メモ帳を終了しファイルを開きなおすと、上書き内容が表示された。

### 関連情報

https://superuser.com/questions/294826/how-to-purposefully-exclusively-lock-a-file

外部ロックファイルを作りたいとの質問。
関連して、以下のコメントがある。

> answered Jun 10 '11 at 8:11
> Open it with MS-Excel... this app locks a file while open.
Railsでは一度に何個のファイルをアップロードできるのか試してみた結果

**127** 個まででした。

128 個目で次のエラーがでます。

```
Puma caught this error: Too many open files - Maximum file multiparts in content reached (Rack::Multipart::MultipartPartLimitError)
```

が、限界値は `Rack::Utils.multipart_part_limit` や環境変数 **RACK_MULTIPART_PART_LIMIT** で変更できるようになっていました。設定しなかったら初期値の 128 です。

**0**だと**制限なし**になります。

制限なしにした場合、755Kb のファイル 1000 個でも普通にアップロードできました。

## 初期値は 128 と指定があるのに 127 個までしかアップロードできなかった理由は？

RACK_MULTIPART_PART_LIMIT の値は、アップロード可能な数ではなく **part の総数** です。ファイルのpartと、その他のpartを1つ合わせて128としているので、ファイルアップロードの上限は 128 - 1 で 127 だったというわけです。
javaじゃんけん

なんとなくじゃんけんぷろぐらむを作ってみました。

```java:janken.java
import java.util.Random;

public class janken {
    // ぐーちょきぱー定数定義
    int GU = 0;
    int CHOKI = 1;
    int PA = 2;

    // プレイヤー;
    int player1;
    int player2;
    // 手
    String te1;
    String te2;

    // プレイヤー1の出す手を乱数で決める
    public void player1() {
        Random random = new Random();
        int hand1 = random.nextInt(3);
        switch (hand1) {
            case 0:
                player1 = GU;
                te1 = "ぐー";
                break;
            case 1:
                player1 = CHOKI;
                te1 = "ちょき";
                break;
            case 2:
                player1 = PA;
                te1 = "ぱー";
                break;
        }
    }
    // プレイヤー2の出す手を乱数で決める
    public void player2() {
        Random random = new Random();
        int hand2 = random.nextInt(3);
        switch (hand2) {
            case 0:
                player2 = GU;
                te2 = "ぐー";
                break;
            case 1:
                player2 = CHOKI;
                te2 = "ちょき";
                break;
            case 2:
                player2 = PA;
                te2 = "ぱー";
                break;
        }
    }

    public static void main(String[] args) {
        janken janken = new janken();
        janken.player1();
        janken.player2();


        System.out.println("player1とplayer2でじゃんけんをします。");
        System.out.println("player1の手: " + janken.te1);
        System.out.println("player2の手: " + janken.te2);

        // 判定
        if (janken.player1 == 0 && janken.player2 == 1) {
            System.out.println("ぷれいやー1のかちー");
        } else if (janken.player1 == 1 && janken.player2 == 2) {
            System.out.println("ぷれいやー1のかちー");
        } else if (janken.player1 == 2 && janken.player2 == 0) {
            System.out.println("ぷれいやー1のかちー");
        } else if (janken.player1 == janken.player2) {
            System.out.println("ひきわけ");
        } else {
            System.out.println("ぷれいやー2のかちー");
        }
    }
}
```
UbuntuのCtrlキー(Superキー)で起動する鬱陶しいLauncherを起動しない方法


# 概要
UbuntuのターミナルでCtrl+CとCtrl+Vでコピペするようにしようとしたら、超鬱陶しいLauncherが起動するので、こいつを大人しくさせる方法を記載する。

# 設定ツールのインストール
```Bash
$ apt install compizconfig-settings-manager
```

# Launcher無効化
1. CompizConfig Settings Managerを起動
2. カテゴリ「デスクトップ」→「Ubuntu Unity Plugin」→「Launcher」タブ
3. 「Key to show the Dash, ...」を無効化
オフラインリアルタイムどう書くの過去問(続柄）

2013.1.13の問題です。－>http://nabetani.sakura.ne.jp/hena/ord6kinship/
F06と同様にツリーが使えそうですので解いてみました。

```prolog
tree(N,[]):-N>40,!.
tree(N,List):-N2 is N*3,N1 is N2-1,N3 is N2+1,tree(N1,L),tree(N2,M),tree(N3,R),
                List=[N,L,M,R].
                
re(me,X,Y,_):-X=:=Y .
re(da,X,Y,L):-search(X,Y,L).
re(mo,X,Y,L):-re(da,Y,X,L).
re(si,X,Y,L):-re(mo,X,Z,L),re(da,Z,Y,L),X=\=Y.
re(au,X,Y,L):-re(mo,X,Z,L),re(si,Z,Y,L).
re(ni,X,Y,L):-re(si,X,Z,L),re(da,Z,Y,L).
re(co,X,Y,L):-re(au,X,Z,L),re(da,Z,Y,L).
re(-,_,_,_).

search(_,_,[]):-fail.
search(X,Y,[N,L,M,R]):-
       (X=N,(L=[Y,_,_,_];M=[Y,_,_,_];R=[Y,_,_,_]));
       (search(X,Y,L);search(X,Y,M);search(X,Y,R)).

solve(_,[]).
solve(L,[A,B,C|T]):-
       split_string(B,"-",">",[X,Y]),number_chars(X1,X),number_chars(Y1,Y),atom_chars(C1,C),
       re(R,X1,Y1,L),write(A),(C1=R->write(" yes  ");write(" no    ")),write(R),write("\n"),
       solve(L,T),!.

start:-str(S),tree(1,T),split_string(S,"\s,\n","\s",L),solve(T,L).
%start.

str("0       5->2    mo
1       28->10  au
2       1->1    me
3       40->40  me
4       27->27  me
5       7->2    mo
6       40->13  mo
7       9->3    mo
8       4->1    mo
9       1->3    da
10      12->35  da
11      3->8    da
12      6->19   da
13      38->40  si
14      9->8    si
15      4->2    si
16      15->16  si
17      40->12  au
18      10->4   au
19      21->5   au
20      8->2    au
21      3->5    ni
22      11->39  ni
23      2->13   ni
24      13->32  ni
25      14->22  co
26      40->34  co
27      5->8    co
28      12->10  co
29      1->27   -
30      8->1    -
31      12->22  -
32      2->40   -
33      32->31  -
34      13->14  -").

```
検索画面を表示せずに目的のディレクトリに飛べて、history機能も備えたcdコマンド拡張gcdを作ってみた

__greater cd command for lazy programmer.__

## 何がしたかったか

cdコマンドは面倒くさいが検索画面が出るcd拡張も面倒くさい。なので、検索画面を出さずに一発で目的のディレクトリに飛べるようにした。

## 何ができるか

よく使うディレクトリを$GCDPATHに登録しておくと、そのディレクトリ、あるいはその直下のディレクトリに直接飛べる。検索画面は呼ばない限り表示されない。<-重要

誰でもカスタマイズできるように必要な機能だけバイナリで提供し、あとはShellで書くようにした。

## デモ

```shell
aimof@host:~$ echo $GCDPATH 
/home/aimof/.vim:/home/aimof/go/src/github.com/aimof:/home/aimof
aimof@host:~$ gcd gcd            
aimof@host:~/go/src/github.com/aimof/gcd$ gcd .vim 
aimof@host:~/.vim$ 
```

`gcd xxx`で、$GCDPATHに登録したディレクトリかその直下のディレクトリに検索画面を経ずに飛ぶことができます。

## history機能

さほど強力ではありませんが、history機能も備えています。

`gcd latest`か`gcd frequent`で、gcdの履歴を最新/頻度の順番で改行区切り標準出力します。こいつをfzfやpecoなどに渡すことで、（面倒だけど）検索してジャンプすることも可能です。

## 実装

gcdリポジトリは、パスを解釈して絶対パスを返すgcdpath、絶対パスを受け取って記録するgcdhist、それらをつなぎ合わせるgcdコマンドの例、で構成されています。

gcdpathとgcdhistはバイナリですが、それ以外はshellコマンドの組み合わせなのでカスタマイズ性が高いです。（使い方をユーザーに丸投げしているとも言う）

詳しくはgithubのREADME.mdに書きましたが、中身はこんな感じ

```zsh
gcd() {
	TARGET=`gcdpath $1`
	gcdhist add $TARGET
	cd $TARGET
	ls $TARGET # if you need to run ls when you move directory.
}
```

## src

[github.com/aimof/gcd](https://github.com/aimof/gcd)

## 結びに

便利そうだなと思ったら、ぜひ使ってみてください！

もともとやりたかったことはだいたい終わっているので、欲しい機能ができたら追加していきます。
proguardで動作しない時の確認事項

　javaFXプロジェクトをエクスポートして、作成されたjarファイルを難読化しようとしてハマった話。
　結論から言うと、proguardで難読化した際にアノテーションが消えていたのが原因。対策としては、まず、下記の様な何もしない設定で難読化してみた。

```` 
#sample.pro
#何もしない設定

-injars  'C:\******\input.jar'
-outjars 'C:\******\output.jar'

#外部jar
-libraryjars 'C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar'
-libraryjars 'C:\****\*****.jar'
-libraryjars 'C:\****\*****.jar'

#属性設定
-keepattributes *Annotation*, Signature, Exceptions, InnerClass

#クラス設定
-keep class * {
    *;
}

````

これで動作しない場合は、jarファイルの設定が間違っている可能性がある。
動作する場合は、ここから難読化する部分を除いていく。
例えば、下記の様にパッケージごとに分類して、それぞれ個別に設定するなど。

```` 
$sample2.pro
#パッケージごとに個別設定

-injars  'C:\******\input.jar'
-outjars 'C:\******\output.jar'

#外部jar
-libraryjars 'C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar'
-libraryjars 'C:\****\*****.jar'
-libraryjars 'C:\****\*****.jar'

#属性設定
-keepattributes *Annotation*, Signature, Exceptions, InnerClass

#クラス設定
-keep class package1.* { *;}
-keep class package2.* { *;}
-keep class package3.* { *;}
-keep class package4.* { *;}

````
raspberry pi の起動時にipをslackに通知させる

#raspberry pi にnode.jsインストール

すでにインストールされている場合は古いバージョンをアンインストール

```
sudo apt-get autoremove nodejs
```

新しいやつインストール

```
sudo npm cache clean
sudo npm install n -g
sudo n stable
```

```
node -v
最新！
```


#slack連携 
今回はwebhooksを使う
以下サイトから自分のチャンネルに登録する(詳細は略)　
https://slack.com/services/new/incoming-webhook

API Tokenをコピーしておく

#raspberry pi が起動した時にipをslackに通知するようにする
今回はhomeディレクトリ直下に記載する

```ip_addr.js
'use strict'

const os = require('os');
let interfaces = os.networkInterfaces();
let mes = '';

for (let dev in interfaces) {
    interfaces[dev].forEach((details) => {
        if (details.internal || details.family !== 'IPv4') return;

        mes = `${os.hostname()}:${details.address} (standupi!!)`;
        console.log(mes);
	slack();
    });
}

function slack() {
  var now = new Date();
  var Year = now.getFullYear();
  var Month = now.getMonth() + 1;
  var Day = now.getDate();
  var Hours = now.getHours();
  var Minutes = now.getMinutes();
  var Seconds = now.getSeconds();
  var gettime = Year+"/"+Month+"/"+Day+"  "+Hours + ":" + Minutes +  ":" + Seconds;

//requestをrequire
var request = require('request');

//ヘッダー
var headers = {
'Content-Type':'application/json'
}
//オプションを定義
var options = {
  url: '先ほど取得したAPI Tokenを記載',
  method: 'POST',
  headers: headers,
  json: true,
  body: {"text":mes +"----"+ gettime}
}
//リクエスト送信
request(options, function (error, response, body) {
})
}
```

ここで一回試す

```
node ip_addr.js
```

ipアドレスが取得できてslackに通知されていればok

こういうエラーが出たら

```
module.js:529

    throw err;

    ^

Error: Cannot find module 'isstream'
```

以下コマンドで個別にモジュールをインストールする(何回もエラー出てモジュールインストールしまくった　汗)

```
npm install <module_name> --save
```

##起動時にslack通知する
/etc/rc.localに以下追加(exit 0の前)

```/etc/rc.local
sudo -u pi /usr/local/n/versions/node/8.2.1/bin/node /home/pi/ip_addr.js
```

`/usr/local/n/versions/node/8.2.1/bin/node` は自分の環境に合わせて！！

これで起動した時のipをslackに通知する様になった



参照サイト
[地味に便利！Raspberry Piが起動したらIPアドレスを通知するチャットボットを作る](https://dotstud.io/blog/raspberry-pi-ip-notification/)
pythonでjson形式でログを出す

## TL;DR

`python-json-logger`便利

[madzak/python-json-logger: Json Formatter for the standard python logger](https://github.com/madzak/python-json-logger)

- わりかし簡単にjson形式でログが出せるようになる
- 出力も柔軟に設定出来る
  - カスタムのフォーマッタを定義したり
  - info呼ぶところでアドホックにキーを足したり(`logger.info(extra={'a': 10})`的な)


## パッケージインストール

```console
$ pip install python-json-logger
```


## logger定義

プロジェクト用の`JsonFormatter`と`getLogger`を定義しておく例

```python
import logging
import datetime
from pytz import timezone
from pythonjsonlogger import jsonlogger


# https://github.com/madzak/python-json-logger#customizing-fields
class JsonFormatter(jsonlogger.JsonFormatter):

    def parse(self):
        """
        他に出したいフィールドがあったらこのリストに足す
        https://docs.python.jp/3/library/logging.html
        """
        return [
            'process',
            'timestamp',
            'level',
            'name',
            'message',
            'stack_info',
        ]

    def add_fields(self, log_record, record, message_dict):
        super().add_fields(log_record, record, message_dict)
        if not log_record.get('timestamp'):
            # https://qiita.com/yoppe/items/4260cf4ddde69287a632
            now = datetime.datetime.now(timezone('Asia/Tokyo')).strftime('%Y-%m-%dT%H:%M:%S%z')
            log_record['timestamp'] = now
        if log_record.get('level'):
            log_record['level'] = log_record['level'].upper()
        else:
            log_record['level'] = record.levelname


def getLogger(module_name):
    """プロジェクトごとにハンドラの設定などをしたい場合はここでやる"""
    logger = logging.getLogger(module_name)
    handler = logging.StreamHandler()
    formatter = JsonFormatter()
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.setLevel(logging.DEBUG)
    return logger
```


## 使う側

- 使う側のスクリプトにて`getLogger(__name__)`で初期化
- `extra`にdictを渡すとそれも出力してくれる

```python
from project_logging import getLogger
logger = getLogger(__name__)
logger.info('Inserting rows into MySQL', extra={'rows': rows})
```

```
{
  "process": 43274,
  "timestamp": "2017-10-15T12:28:13+0900",
  "level": "INFO",
  "name": "etl.mysql",
  "message": "Inserting rows into MySQL",
  "stack_info": null,
  "rows": 10
}
```


## 参考

- [Python標準のloggingでログをJSON形式で出力する - Qiita](https://qiita.com/termoshtt/items/8963132893cc37990352)
- [Logging HOWTO — Python 3.6.1 ドキュメント](http://docs.python.jp/3/howto/logging.html)
- [ログ出力のための print と import logging はやめてほしい - Qiita](https://qiita.com/amedama/items/b856b2f30c2f38665701)
Raspberry piをBluetoothヘッドセットとして認識させる

# 注意
Raspberry pi側のオーディオ設定等はありません。
そのため、下記の設定のみではBluetoothヘッドセットとして認識はしますが、Raspberry piから音声が出たり、マイク等を使えたりはしません。
また、備忘録のため、いろいろと説明を省いています（そのうち入れます）。

# 動作環境
* 端末
    * Raspberry pi 2 (Raspbian kernel:4.9)
* Bluetoothアダプタ
    * BSBT4D09BK  
      http://buffalo.jp/product/peripheral/wireless-adapter/bsbt4d09bk/
* その他
    * Python3

# 初期セットアップ
https://www.raspberrypi.org/downloads/raspbian/
上記よりOSをインストールし、SDカードに適当にWriteする。
環境の都合上、初回起動時よりssh接続が可能にしたかったため、Write後に"ssh"ファイルを作成しました。

# アップデート
ひとまず最新の状態へアップデート

```shell-session
sudo apt-get update
sudo apt-get update
```

# pulseaudioのインストール
下記以降は、rootユーザで操作しています。

```shell-session
apt-get install pulseaudio-module-bluetooth python-gobject python-gobject-2
apt-get install paprefs
```

インストール後にデーモンとして起動する。

```shell-session
pulseaudio -D
```

# ペアリングの確認
bluetoothデバイスをコマンドライン上から操作するため、bluetoothctlを使用する。Bluetoothアダプタが問題なく認識できていれば`[bluetoothctl]#`でコマンド入力可能となる。

```shell-session
bluetoothctl
[bluetoothctl]# discoverable on
[bluetoothctl]# pairable on
[bluetoothctl]# trust XX:XX:XX:XX:XX:XX
```

上記のコマンドでスマホなどからRaspberry piが検出可能となる。
ペアリングしようとすると失敗するが、下記のコマンドでデバイスを許可してあげる。

```shell-session
[bluetoothctl]# trust XX:XX:XX:XX:XX:XX
```

もう一度スマホ側からペアリングすると成功するはずです。
問題なくペアリングできれば、一度接続を解除してください。

# ofonoのインストール

```shell-session
apt-get install ofono

# ofonoをサービスとして登録して起動
systemctl enable ofono
systemctl start ofono
```

インストール後、pulseaudio側の設定(/etc/pulse/default.pa)を変更する。

```bash:変更前
load-module module-bluetooth-discover
```
```bash:変更後
load-module module-bluetooth-discover headset=ofono
```

設定変更を反映させるため、pulseaudioを再起動させる。
再起動後にbluetoothctlから再度ペアリングを行う。

```
pulseaudio -k
pulseaudio -D
```

# Pythonスクリプト動作セットアップ
必要なものをインストールする。

```
apt-get install python-dbus
```

# 動作確認
下記のofonoサンプルスクリプトをダウンロードし、スクリプトを実行する。
https://github.com/DynamicDevices/ofono/blob/master/test/monitor-ofono

```
wget https://raw.githubusercontent.com/DynamicDevices/ofono/master/test/monitor-ofono
python monitor-ofono
```

問題なく動作できていれば、電話着信等でメッセージが表示されるはず！

# 参考URL
* http://tokieng.hatenablog.com/entry/2017/09/14/214527  
こちらのサイトではpulseaudio, ofonoをビルドしていたが現環境では必要ないようです(apt-getでインストールされるバージョンが更新された模様？)
* http://d.hatena.ne.jp/penkoba/20130909/1378744109
Pythonでvenvするときにエラーが出た

# Pythonでvenvするときにエラーが出た

### ・エラー内容
`$ python3 -m venv myvenv`

でmyvenvという名前のvirtualenv（仮想環境）を作成しようとしたが

```
Error: Command '['/Users/nakajimahidenari/mysite/myvenv/bin/python3', 
'-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1.
```

というエラーが出た。

###・解決方法

`$ python3 -m venv --without-pip myvenv`

`--without-pip`をつければ無事に作成できた。
何故かpipできるのだが...
MacBookでShogiGUI(Windowsソフト)を使う方法


#概要
- macOSに直接Wineを入れてShogiGUIを起動してみたところ、エンジン設定が出来ず、フリーズするなど、正常に動作しなかった。
- そこで、VirtualBox上でUbuntuを起動して、Ubuntu上でWineを使ってShogiGUIを起動したところ正常に動作したので、その手法を記す。
- この方法で、将棋AIエンジン「技巧」も動作した（当然ながら、PCに対応CPUが載っていることが前提）。
- ちなみに、ShogiGUIに限らず、他のWindowsアプリも同様の方法で動作させることも可能である。
- とはいえ、以下の設定だけでは動作しないソフトもあるので悪しからず。

#環境
- VirtualBox 5.1.28
- Ubuntu 16.04 LTS
- wine 2.0.2
	- winetricks 20170823-next
- ShogiGUI 0.0.6.11

#構築
##VirtualBox上にUbuntuをインストール
1. 文末のダウンロードリンクから、VirtualBoxとUbuntuをダウンロードする。
2. macOSにVirtualBoxをインストールする。
3. VirtualBoxを起動して、以下の手順で、仮想マシンを作成する。
	- 「新規」ボタンをクリックする。
	- 「名前」に「Ubuntu」と入れて、「続ける」をクリックする。
		- このとき、「タイプ」と「バージョン」は自動的に設定された。
	- メモリサイズは、2048MBにした。
	- ハードディスクは、「仮想ハードディスクを作成する」を選択する。
	- ハードディスクの設定は、VDI、固定サイズ(20GB)にした。
4. 作成した仮想マシンを選択して、「設定」ボタンから、Ubuntuを快適に使用するための各種設定をする。
	- 「システム」→「プロセッサー」
		- プロセッサー数: 2
		- 使用率制限: 100%
	- 「ディスプレイ」→「スクリーン」
		- ビデオメモリー: MAX (128MB)
		- アクセラレーション: 「3Dアクセラレーションを有効化」にチェック
5. 作成した仮想マシンにUbuntuをインストールする。
	- 「ストレージ」→「[光学ドライブ]空」をクリックし、ダウンロードしたUbuntuのイメージファイル(.iso)を選択する。
	- 「起動」ボタンを押し、仮想マシンを起動して、Ubuntuをインストールする。

## UbuntuにVirtualBox VMのドライバーをインストールする。
1. Ubuntuが起動したら、「VirtualBox VM」ウィンドウのメニューから、「Devices」→「Insert Guest Additions CD Image...」をクリックする。
2. インストーラーが起動するので、指示通りにインストールする。
3. これで、画面解像度の設定変更等ができるようになる。

## UbuntuにWineをインストール
Wineをインストールする。

```Bash
# Wineをインストール
$ sudo dpkg --add-architecture i386
$ wget -nc https://dl.winehq.org/wine-builds/Release.key
$ sudo apt-key add Release.key
$ sudo apt-add-repository https://dl.winehq.org/wine-builds/ubuntu/
$ sudo apt-get update
$ sudo apt-get install --install-recommends winehq-stable

# インストールしたWineのバージョン確認
$ wine --version
```

## Wineにフォントやランタイムをインストール
winetricksをインストールする。

```Bash
$ cd ~
$ mkdir winetricks
$ cd winetricks
$ wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
$ chmod +x winetricks
```

winetricksのGUIを起動する。

```Bash
$ ~/winetricks/winetricks
```

1. フォントをインストールする（これをやらないと、日本語文字が全て"□"になる）。
	- 「Select the default wineprefix」→「install a font」→「allfonts」→「OK」
2. MS.NET 4.5ランタイムをインストールする。
	- 「Install a Windows DLL or component」→「dotnet45」→「OK」
	- 警告ウィンドウが何回も出るが、構わず最後までインストール
3. 一応、Ubuntuを再起動しておく。

## ShogiGUIを起動
1. 下記の公式サイトからzip版のShogiGUIをダウンロードする。
2. 任意のディレクトリに解凍する。
3. 以下のコマンドで、ShogiGUIを起動する。

```Bash
$ wine <ShogiGUI.exeのパス>
```


# ダウンロードリンク
- VirtualBox: https://www.virtualbox.org/wiki/Downloads
- Ubuntu: https://www.ubuntulinux.jp/download/ja-remix
- wine: https://wiki.winehq.org/Ubuntu
- winetricks: https://wiki.winehq.org/Winetricks
- ShogiGUI: http://shogigui.siganus.com/download.html
- 技巧 (将棋AI): https://github.com/gikou-official/Gikou/releases
GoogleのPWA Roadshowの話(1)

2017/9/22に開催されたGoogle主催のProgressive Web Apps Roadshow Tokyo 2017に参加したので、その時に聞いた話を自分なりの解釈をもとにざっくりとまとめてみました。

正確な内容が知りたい場合は、以下のURLより講演で使用されたスライドを参照してください。
https://goo.gl/ESUahe

# PWAとは
PWA(Progressive Web Apps)とは、Webアプリケーションをホーム画面に追加し、オフライン状態での利用、PUSH通知などによりネイティブアプリのように利用できるようにすることでUXを向上させること。
本質としては、UXを根本的に向上させることであり、機能などではなく概念を表す。


# Chapter1:Progressive Web Apps
## なぜPWAが必要なのか
最近ではモバイルの利用者数が多くなってきており、さらにモバイルの利用率としてはWebサイトよりアプリの方が圧倒的に高い状態になっています。（資料では、Webサイトが１３％、アプリが８７％）
しかし、アプリは一部のものばかり使用されており、新しいアプリをインストールすることもあまりないのですが、Webサイトに関しては幅広く利用されている傾向にあります。
そこで、Webサイトの利用範囲の広さとアプリのような使いやすさを満たすことでUXを向上させようというのがPWAの考えです。

## PWAで重要なこと
PWAを構築するために重要なこととして、4つのキーワードがあり、それぞれの頭文字をとってFIREと言います。
`F：Fast(ロード時間を速くする)
I：Integrated(Webを意識させない（ホーム画面に追加）)
R：Reliable(オフラインでも動作する)
E：Engaging(関心を引く（PUSH通知）)`

各項目の細かい内容は、次章以降で説明されます。
上記を実現するものの一つとして、Service Workerがあります。
また、サービスの安全性を確保するためにHTTPS化が必須となります。
ほとんどのAPIがHTTPS化していないと使用できないとのことです。

## PWAを始めるには
PWAを始めるにあたって、いくつかの取り組み方があります。
`From the ground up(全体を一から作る)
a simple version(簡易なバージョンで作成する)
a single feature(１つの機能を作成する)`

一から作り直すのか、どれかの機能に絞ってやるのか、システムによって取り組み方は柔軟にできそうです。
しかし、大事なことは**どれが一番UXの向上に繋がるか**ということ。
それを念頭に取り組むのが良いと思います。

#おわりに
ここでは、PWAがどういうものかということをざっくりとまとめてみました。
この話を聞くまでは、PWAというのはアプリのように使えるようにする機能を指すのだと思っていたので、少し驚きました。
次からはPWAを実現するための話をまとめていきたいと思います。

[GoogleのPWA Roadshowの話(2)](https://qiita.com/MurakumoA/items/f841fb606778698007f9)
OpenBSD 6.2 の Vagrant Box を作ってみた

# 前提
VirtualBoxをproviderとして、VMにクリーンインストール済みのOpenBSDをVagrant Box化する。

# 環境

| 区分 | バージョン |
|---------|----------------|
| ホストOS | macOS 10.13 High Sierra |
| Vagrant | 2.2.3 |
| Oracle VirtualBox | 6.0.0 |
| ゲストOS | OpenBSD 6.4 |

※ おそらく、ホストOS は何でも良さそう。Vagrant も 1.9系でも動くかと思います。

# 手順
https://github.com/SierraX369/packer-templates を参考にしました。

## VM 上での作業
以下の操作は VM 上で行う（別にSSH経由でなくともよい）

### 1. doas設定
まずは、OpenBSDの `sudo` の代わりのコマンドである `doas` の設定を行う。

```$ksh
echo 'permit vagrant' >>/etc/doas.conf
echo 'permit nopass setenv { PKG_PATH ENV PS1 SSH_AUTH_SOCK } :wheel' >>/etc/doas.conf
```

### 2. curlインストール
参考にしている Packer テンプレートでは、ftp コマンドを使っているようだが、今回は curl を使用するため、 `pkg_add` にてインストールする。

```$ksh
doas pkg_add curl
```

### 3. Vagrant公開鍵設定
Vagrant の公開鍵をダウンロードしてして配置する

```
curl --insecure --location "https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub" -O $HOME_DIR/.ssh/authorized_keys;
chown -R vagrant ~/.ssh;
chmod -R go-rwsx ~/.ssh;
```

### 4. syspatch設定
セキュリティーアップデートをバイナリーアップデートで適用するための `syspatch` コマンドの設定をする。
ソースコードからアップデート適用するような場合は設定不要だと思います。
※ URLの末尾が `OpenBSD` で終ること。 `/` で終ると動きません

```$ksh
su -
echo 'https://fastly.cdn.openbsd.org/pub/OpenBSD' >> /etc/installurl
exit
```

### 5. Box サイズを小さくする

```$ksh
su -
dd if=/dev/zero of=/EMPTY bs=1M || echo "dd exit code $? is suppressed";
rm -f /EMPTY;

sync;
exit
```

## ホスト側で作業
### Box 化
`vagrant package` コマンドで Box として固める。

### Vagrantfileの変更
Vagrantfileに 以下の設定を追加する

#### doas コマンド設定
`sudo` コマンドの代わりに `doas` コマンドを使用する

```$ruby:Vagrantfile
config.ssh.sudo_command = "doas env %c"
```

#### シェルコマンド設定
`bash` ではなく `ksh` なので、以下のように設定する(多分、kshを指定しても良い)

```$ruby:Vagrantfile
config.ssh.shell = "sh"
```

#### OpenBSD がゲストであることを記載
要らないかも知れないが、ゲストOSが OpenBSD であることを記載する

```$ruby:Vagrantfile
config.vm.guest = :openbsd
```

#### 共有フォルダー設定
VirtualBox guest addition が対応していないため、 `vboxfs` による共有フォルダー機能は使えない。
そのため、NFS設定にて共有フォルダー設定する。
共有フォルダーを使用しないのであれば、共有フォルダーを無効にするように設定する。

```$ruby:Vagrantfile
config.vm.synced_folder ".", "/vagrant", type: "nfs"
```

------------
これで、OpenBSD をVagrant Boxとして使えます。

何かあって消すこともいずれはあるかと思いますが、以下に作ったものをアップロードしてあります。
ちなみに、 VirtualBoxの UEFI を有効にして、パーティションテーブルも GPT にしています。 
https://app.vagrantup.com/poad/boxes/openbsd
Socket.IOプロトコルの読み方

リアルタイム通信といえばwebsocketですが、このwebsocketを簡単に扱えるようにしたものとしてNode.jsのsocket.ioが使われることが多いと思います。今回はこのsocket.ioの通信プロトコルについて説明したいと思います。

#詳細なプロトコルの必要性

なぜ、socket.ioのプロトコルについて書くかと言うと

- socket.ioのプロトコルをまとめているはずのsocket.io-protocolに具体的な説明がない
- 公式ドキュメントに詳細な説明がない
- ネット上に情報が少ない
- socket.ioサーバーに対してJMeterで負荷試験するときにプロトコルを知らないとデータの送受信ができない
理由を上げると切りがないですが、最後にあげた理由が一番ですね。

実際、使用するだけならサンプルコードを参考にすれば何の問題もなく簡単に扱うことができます。

だからこそプロトコルについての詳細な情報が必要とされていないのだと思います。JMeterを使用した負荷試験の記事はまた別で書きたいと思います。

#プロトコルの種類

まずはじめに、socket.ioは２つのプロトコルで動作しています。それがsocket.io-protocolとengine.io-protocolです。

ここでは２つの役割については説明しませんが、socket.ioはクライアントから受け取ったデータをsocket.ioプロトコルとengine.ioプロトコルに従って処理を行なっています。

##Socket.IOプロトコルについて

ここからが本題になります。例えば下記データの場合、先頭の4はengine.ioプロトコルで、それ以降はsocket.ioプロトコルになります。

4はengine.ioプロトコルでmessage packet typeとなり、2はsocket.ioプロトコルでEVENT typeとなります。/chatはnamespaceで[ ]で挟まれた部分がsocket.ioで処理されるデータになります。

このデータの場合、socket.ioでは”join”イベントが発火され{room:1}のデータが渡されます。namespaceは/のときに限って省略することが可能です。

これがsocket.ioのプロトコルの全てと言っても過言ではありません。この法則させ抑えて置けば他のデータのやり取りも容易に理解できるようになります。

```
42/chat,[“join”,”{room:1}”]
```
 
#websocket接続時のデータ

次はsocket.io接続時に実際に送られてくるデータを見ていきたいと思います。今回はUpgradeなしのいきなりwebsocketで繋ぎに行く場合のデータを紹介します。

まずこれはwebsocket接続時に一番最初にサーバーから送られてくるデータです。先頭の0はengine.ioプロトコルでopen packet typeなので接続完了を表します。

ここではsocket.ioプロトコルの0: CONNECT typeは省略されます。socket.ioのCONNECT typeはnamespaceに対しての接続だからかもしれません。

```
0{“sid”:”co4sBxs6vQ8m4us5AAAA”,”upgrades”:[],”pingInterval”:25000,”pingTimeout”:60000}
```
websocketのコネクションが確立すると次に下記データがサーバーから送られてきます。これはmessage packet typeとCONNECT typeの組み合わせでnamespace ’/’に接続したことを表します。40は40/と同じ意味になります。

```
40
```
#まとめ

ここまでくればあとは上記のプロトコルに従えば自由にデータのやり取りをsocket.io上で行うことができます。

どうでしたでしょうか？プロトコルを理解すればすごくシンプルだということが分かったかと思います。もし、説明に間違いがあれば教えていただければと思います。

下記個人ブログにSocket.IOやNode.jsについて他にも色々書いているのでぜひ読んでいただきたいです。
よろしくお願いします。

http://tomokazu-kozuma.com/category/socket-io/
UbuntuのApache設定ファイル、どうやるんだっけ？

# UbuntuのApache設定ファイルで戸惑ったら。

Ubuntu 16.04

しばらく使ってないと、えーと、どうなってたっけ・・・とすぐ忘れるのでメモかねて。

ぱっと見わかりづらいですが面白い仕組みになってます。


まず/etc/apache2のディレクトリには\*\*\*-availableと\*\*\*-enabledという命名規則のディレクトリが対になってます。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/205767/c071c9a7-4e22-f8de-6049-8d0fcb3c376f.png)


そして、apache2.confはこのうち***-enabled内の.confや.loadファイルをすべて読み込むようになってます。


![apache2conf-file1.png](https://qiita-image-store.s3.amazonaws.com/0/205767/3e1e1903-e88a-911b-55ab-fba8bf11bbe5.png)


![apache2config-file2.png](https://qiita-image-store.s3.amazonaws.com/0/205767/ff3a003a-ae08-4f5c-f45f-43368fd81555.png)



見ての通り、\*\*\*-enabledの中身はすべて***-available内のファイルへのシンボリックリンクです。


![3.シンボリック.png](https://qiita-image-store.s3.amazonaws.com/0/205767/90305b8f-ecd0-83dd-9e01-0b71879061ca.png)


***-availableに実際の設定ファイルがあります。



ここで重要なのは、シンボリックリンクと設定ファイルは必ず同じ数だけ対になっているわけではないということです。
そしてこのシンボリックの有無がapache2.confから***-available内のファイルが読み込みに関係してきます。

つまり、設定を無効にしたければシンボリックを消せばいいわけで、逆に有効にしたければシンボリックを作成すればいいわけです。


そして、そのためのコマンドがそれぞれ用意してあります。


|ディレクトリ|シンボリックの削除|シンボリックの作成|説明|
|:--|:--|:--|:--|
|mods-enabled | a2dismod | a2enmod | モジュールの設定ファイル |
|sites-enabled | a2dissite | a2ensite | 仮想ホストの設定ファイル |
|conf-enabled | a2disconf | a2enconf | その他設定ファイル |


a2はApache2、disは無効、enは有効という意味かな・・・？
いや、知りませんよ。




---

例えば、

    sudo vi /etc/apache2/sites-available/sample.conf

で適当な設定ファイルを書いて、


    sudo a2ensite sample

を打つと、/etc/apache2/sites-enabled/sample.conf が作成されます。
これは../sites-available/sample.confへのシンボリックリンクです。。


    sudo a2dissite sample

を打つと、/etc/apache2/sites-enabled/sample.conf が削除されます。


---


図で見たほうが一目瞭然。

![a2-1.png](https://qiita-image-store.s3.amazonaws.com/0/205767/0462c85b-4935-4a4c-a994-bd282f31fd4f.png)

    sudo vi sample.conf

　
![a2-2.png](https://qiita-image-store.s3.amazonaws.com/0/205767/c45602cf-a878-f4a8-f6d2-1dfb3cba8c39.png)

    sudo a2ensite sample

　
![a2-3.png](https://qiita-image-store.s3.amazonaws.com/0/205767/64e2e56d-4551-5f72-7c39-cc2ed82c2032.png)

    sudo a2dissite sample

　
後はApacheを再起動
Python入門③（繰り返し処理）

この記事は、[Python入門②（条件分岐編）](http://qiita.com/kameda05/items/35e4105fe5f69845e6e7)からの続きです。

#繰り返し処理
## Pythonの繰り返し処理

Pythonの繰り返し処理は、**while**と、**for**の2種類があります。
それぞれに長所・短所があります。

for文は配列データと密接なかかわりがあるため、配列の部分で説明します。

ここでは、while飲み説明しることにします。

## whileによる繰り返し

では、早速**while**文に関して説明していきましょう。一般的な出単純なケースと、途中で流れが変わるケースを見てみましょう。

###①単純なケース

まずは、whileによる繰り返しから見てみましょう。

```while1.py
while i < 10:
    print(i)
    i += 1
print "End"
```
これを実行すると以下のようになります。

```
0
1
2
3
4
5
6
7
8
9
End
```

while文では、条件式が成り立つ限り、処理が繰り返されます。**繰り返し処理は、インデントされている部分**です。

したがって、変数iの値を表示し、その値に1を足すことを、**iが10未満の間繰り返します**。

###②breakによって抜けるケース



```while2.py
i = 0
while True:
    print(i)
    i += 1
    if i == 5 :
        break
print "End"
```

実行結果は次のようになります。

```
0
1
2
3
4
End
```

whileの次に、**True**を持ってくると、終わらないループができます。これを**無限ループ**と言います。

**break**は、ループから抜ける処理です。無限ループでも、breakがあれれば抜け出すことができます。

この例では、iの値が５になったらループから抜け出しています。

## while ～ else

whileは、条件式が真(**True**)の間、繰り返しを処理します。これに、elseをつけると、偽(**False**)の時の処理を書くことができます。

```while3.py
n = 0
while n < 3:
  print "n = " + str(n)
  n += 1
else:
  print "last : n = " + str(n)
print "End"
```
実行結果は以下の通りです。

```
n = 0
n = 1
n = 2
last : n = 3
End
```

ループはn<3の間、つまり「n<3」という命題が**True**の間は繰り返されます。
しかし、n = 3となると、**False**となるので、**else**の部分が実行され、ループが終了します。
SRE本まとめ（20章 データセンターでのロードバランシング）

自分の理解を深めるためにまとめてみました。[19章](https://qiita.com/bassbone/items/3652503804a1f366cdaa)の続きです。

## 20章 データセンターでのロードバランシング

### サブセットの設定によるコネクションプールの制御
適切なサブネットを選択するためには、サブセットの大きさ（各クライアントが接続するバックエンドタスク数）と選択アルゴリズムが大切である。以下のような場合にはサブネットを大きくするとよい。

- クライアントがバックエンドよりもはるかに少数の場合
- クライアントのジョブにおいて、負荷の不均衡が頻繁に生じる場合

### サブセットの選択アルゴリズム
当初はランダムな選択を行っていたが効率的に処理が分散されなかったため、決定的なアルゴリズムが採用された。そのアルゴリズムではクライアントをラウンドごとにグループ化し、各ラウンドはシャッフルされた同じリストを使用する。

### ロードバランシングのポリシー
方法としては以下がある。

- 単純なラウンドロビン
    - ただ順番にラウンドロビンさせるだけ。タスクやサーバの大きさにばらつきがあるため、不安定になりやすい。
- 最小負荷ラウンドロビン
    - アクティブなタスク数が最も少ないサーバに振り分けを行う。一見ベストな方法に見えるが、何かしらの原因でエラーを返してしまっている場合に、そのサーバにタスクが集中してしまうというリスクがある。（エラーページは通常のページよりもレスポンスが速い場合が多いので）
- 重み付きラウンドロビン
    - やや複雑な方法ではあるがベストな方法。バックエンドから提供される情報（クエリとエラーのレート、CPU使用率等）を判断のプロセスに取り入れている。

（[21章](https://qiita.com/bassbone/items/090173eb652704ad4d7c)に続く）
ReactとMaterial-UIでControlled Componentを実現する

ReactとMaterial-UIを使ってフォームを作るときにどのようにControlled Componentを実現するかで少し悩んだので、ご参考までに自分なりの解決策をご紹介します。

* 対象バージョン：material-ui: 0.18.6

### 理想の実装方法

通常のHTMLの場合と同様に下記のように実装できると理想的です。

* JSX

```html
<input name="number" type="number" value={this.state.value} onChange={this.handleChange} />
```

* イベントハンドラ

```javascript
handleChange(event) {
	this.setState({value: event.target.value});
}
```

ところがMaterial-UIのコンポーネントではいくつかの問題が発生します。


### 1. SelectFieldではイベントハンドラのevent.targetにMenuItemが設定される

event.targetには選択したMenuItem（実際にはMenuItemが変換されたdiv要素）が指定されます。
このため、SelectFieldのname属性に他のコンポーネントと同じようにアクセスできません。

* 参考
	* https://github.com/callemall/material-ui/issues/5044
	* https://stackoverflow.com/questions/35379140/reactjs-materialui-selectfield-event-handling

### 2. イベントハンドラのコールバック関数の形式がバラバラである
	

| コンポーネント | コールバック関数の形式                                     |
|----------------|------------------------------------------------------------|
| TextField      | function(event: object, newValue: string) => void          |
| SelectField    | function(event: object, key: number, payload: any) => void |
| DatePicker     | function(null: undefined, date: object) => void            |

### 3. イベントハンドラを登録する属性名がバラバラである
		
| コンポーネント | 属性名   |
|----------------|----------|
| Checkbox       | onCheck  |
| RadioButton    | onChange |
| Toggle         | onToggle |
| TextField      | onChange |
| SelectFiled    | onChange |
| DatePicker     | onChange |
| TimePicker     | onChange |

### 4. id属性もしくはname属性を設定しないと警告メッセージが表示されるコンポーネントがある

RadioButton、TextField、Timepickerにid属性もしくはname属性を設定しないと下記の警告メッセージが表示されます。

```text
Warning: Material-UI: We don't have enough information to build a robust unique id for the TextField component. Please provide an id or a name.
```

これは既知のバグのようで、現在のところは特に設定する理由がなくても属性を設定しておくのが良さそうです。

参考：https://github.com/callemall/material-ui/issues/4659

### 解決策

色々と悩んだ結果、イベントハンドラで直接stateを変更するのではなく、フォームの名前を渡してstateを変更する関数を返す、という実装で上記の問題を回避しました。

* JSX

```html
<TextField
	name="tf" 
	value={this.state.tf} 
	onChange={this.handleChange('tf')}
/>
```

* イベントハンドラ

```javascript
handleChange(name) {
	var _this = this;
	return function(event, a, b) {
		if(typeof b === 'undefined') {
			_this.setState({[name]: a});
		} else {
			_this.setState({[name]: b});
		}
	}
}
```

* ソースコード：https://github.com/unhurried/material-ui-html-form-example
* デモ：https://unhurried.github.io/material-ui-html-form-example/
Ruby で英語の typo を生成するコマンドを作った

英語の typo を生成するコマンドを作りました。

https://github.com/siman-man/typogen

ruby 2.0 以上で動く（はず）

## インストール方法

```
gem install typogen
```

## 使用方法


```
typogen [word]
```

例

```
typogen sample
```

出力

```
ample
smple
saple
samle
sampe
sampl
asmple
smaple
sapmle
samlpe
sampel
```

こんな感じで渡された `word` に対して想定される typo パターンを出力してくれます。

プログラム内で使用したい場合は `TypoGen::Typo.create` を使用します。

```rb
irb(main):001:0> require 'typogen'
=> true
irb(main):002:0> TypoGen::Typo.create('sample')
=> ["ample", "smple", "saple", "samle", "sampe", "sampl", "asmple", "smaple", "sapmle", "samlpe", "sampel"]
```

## 実装している typo パターン

- 1文字抜け (install -> intall)
- 文字の入れ替わり (install -> nistall)
- 語尾の発音が似てるものに置換 (creator -> creater)
ざっくばらんメモ_10：kaggle, 創造性について


###kaggle zillow
[code](https://github.com/festa78/kaggle_zillow)
zillowは今週末で提出期限．
Kernelに公開されている手法で二種類のxgboostとlightgbmを組み合わせる事
で好成績を叩き出している手法が存在しているので，
これらを取り入れる事にする．
kernelで公開されている手法とパラメータをそのまま使ってみる。
結果0.0655292 -> 0.0649626で結構改善．
しかしkernelで公開されている手法より性能は低いままであった．
結局は，学習そのものよりも前処理やアンサンブルなどに問題があると思われる．
他の公開手法を見てみても普通にxgboostやlightgbm等を使っているだけで
0.064台を達成出来ているので，もう少し前処理やモデルの組み合わせ方の部分に気を配るべきであった．
またモデルの学習などにおいて，適切のハイパーパラメータが選ばられているとは言えず，
次以後は簡単で良いのでちゃんとパラメータ選択を行う事にする．

###kaggle Porto Seguro
新たなkaggle challengeとしてPorto Seguro’s Safe Driver Prediction Challengeへ取り込む事とする．
今回は保険会社からのお題で，ドライバが次年に保険適用申請するか
どうかを予測するというもの．
問題自体はシンプルだが，今回扱うデータは２値出力のラベルがかなり偏っている
のどそれを念頭に入れる必要がある．
こうしたimbalanceデータに対しては例えばwieghted lossの適用や，
Subsampling+boosting，exemplar learning的の手法などがある．

###消費と創造の関係
何かを消費するたびに何かを知る事が出来る．
その知る事に付随した驚きや感動を覚える事で，それをまた期待
しさらなる消費によって，さらに知ろうとする．
しかし消費を続ける内に新たに知る事の絶対量は減っていき，
最終的に物足りなさを感じるようになる．
あるいは今まで知った事に基いて，これから知りたい事に対する興味の
方向性が決まってくると，消費される物がその方向性に対して
正確に最適化されていない事に気づき，ストレスを感じるようになる．
こうした状態に至ると初めて消費から創造へのシフトが起きる．
この時，創造の動機は自己の内へ向いている．
自分が本当に知りたい（消費したい）事は何かを探求し，それを創造する
過程で知る（消費する）事を達成する．
ここで創造されたものは，自己の興味に最適化しており，創造されたもの（消費されるもの）
と自己の興味が接近し，理想的には一体化する．
これはまさに自己表現の形であると考えられる．
ただ上記した創造の動機は自己の内だけでなく外にも向いている場合が多く，
その場合，社会的な承認欲求（あるいは自己超越？）などと組み合わさっている
と思われる．