OmniAICreator/Qiita-1.07M huggingface dataset:
SharePoint の日付と時刻型は UTC で保存されている

[ブログからの転載](http://1bed.allright.life/?p=2691)

## 経緯

後輩ちゃんから聞かれました。  
「SharePoint にバッチでどうのこうのする実装終わってテストしていたら、日付と時刻型が -9 時間になっていることに気づいて調べたのですが、UTC というものらしく、JST への戻し方を調べていたのですが上手く見つけられなかったです。いい方法知っていますか？」

「私はこうやっているよ」というアウトプットをしますね。

## そもそも UTC とは？

UTC は協定世界時というものです。
私の拙い説明をつらつらと並べるより、詳しくは [Wikipedia](https://ja.wikipedia.org/wiki/%E5%8D%94%E5%AE%9A%E4%B8%96%E7%95%8C%E6%99%82) を読んでください。

私達が使っているのが JST で、UTC より 9 時間進んでいます(UTC+9)にです。未来を生きてる日本カッコいい！！ 

ちなみに、3 ヶ月ほど前に仕事でマレーシアに行きましたが、マレーシアは UTC+8 となっているので、日本とテレカンする時に「朝の 9 時から会議しましょう。 .... ちょっとまって、日本時間で 10 時です！！」というやり取りがありました。海外出張慣れしてないのがバレバレです。

## 検証環境

検証用で、SharePoint Online に次のリストを作りました。

| 列名 | 内部列名 | 列の型 |
| --- | --- | --- |
| タイトル | Title | 1行テキスト |
| 日付と時刻型 | TypeOfDatetime | 日付と時刻 |

## なにが問題なのか

早速先程のリストに登録されたアイテムを PowerShell で取得してみます。

ブラウザから登録したデータ

[![](http://1bed.allright.life/wp-content/uploads/2018/06/1-300x143.png)](http://1bed.allright.life/wp-content/uploads/2018/06/1.png)

PowerShell で取得したデータ

```powershell
TypeOfDatetime      Title
--------------      -----
2018/06/16 15:00:00 テスト1 
2018/06/17 3:00:00  テスト2 
2018/06/17 8:00:00  テスト3 
2018/06/17 14:00:00 テスト4 
```

時間が 9 時間ずれてますよね。

次に、PowerShell から 1 件データを登録してみます。  
※コード抜粋

```powershell
$item = $list.AddItem((New-Object Microsoft.SharePoint.Client.ListItemCreationInformation))
$item["Title"] = "PowerShell Add1"
$item["TypeOfDatetime"] = "2018/07/01 00:00:00"
$item.Update()
$ctx.ExecuteQuery()
```

ブラウザで確認すると、登録したデータに +9 時間されてます。  
`2018/07/01 00:00:00` で登録したいのに困りますよね。

[![](http://1bed.allright.life/wp-content/uploads/2018/06/2-300x153.png)](http://1bed.allright.life/wp-content/uploads/2018/06/2.png)

次はサイトの設定 → 地域の設定でタイムゾーンを変更してみます。

[![](http://1bed.allright.life/wp-content/uploads/2018/06/3-300x147.png)](http://1bed.allright.life/wp-content/uploads/2018/06/3.png)

タイムゾーンを UTC+8 に変更後にブラウザで確認すると、登録したデータに +8 時間されているのが確認できます。

[![](http://1bed.allright.life/wp-content/uploads/2018/06/4-300x152.png)](http://1bed.allright.life/wp-content/uploads/2018/06/4.png)

つまり、SharePoint Online 側の設定次第になるので、タイムゾーンを合わせて登録する必要があります。

## どうやるの？

ベストプラクティスかどうか判らないですが、私はこうやっています。

```powershell
$datetime = $ctx.Web.RegionalSettings.TimeZone.LocalTimeToUTC("2018/07/01 00:00:00")
# サーバーに時間を問い合わせる
$ctx.ExecuteQuery()

$item = $list.AddItem((New-Object Microsoft.SharePoint.Client.ListItemCreationInformation))
$item["Title"] = "PowerShell Add2"
$item["TypeOfDatetime"] = $datetime.value
$item.Update()
$ctx.ExecuteQuery()
```

ブラウザで確認してみます

[![](http://1bed.allright.life/wp-content/uploads/2018/06/5-300x185.png)](http://1bed.allright.life/wp-content/uploads/2018/06/5.png)

予定通りの値が入っているのが確認できます。
grpc-gatewayでのCORS対策

https://github.com/grpc-ecosystem/grpc-gateway/issues/132
にある通りに、`gorilla.handlers.CORS` が使えるので、ありがたく使わせていただく。


下記のように使う。

```go
mux := runtime.NewServeMux(opts...)
newMux := handlers.CORS(
	handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS"}),
	handlers.AllowedOrigins([]string{"http://localhost:3000"}),
	handlers.AllowedHeaders([]string{"content-type", "x-foobar-key"}),
)(mux)
http.ListenAndServe(":8080", newMux)
```
Nginxのパラメータと Linuxカーネルパラメータのチューニング


### worker_processes

```
worker_processes auto;
```

CPUコアの数に設定してくれる。

```
$ lscpu
...
CPU(s):                4
...
```

この場合workerプロセス数は4になる。

---

### worker_connections

```
events {
    worker_connections 8192;
}
```

http://nginx.org/en/docs/ngx_core_module.html#worker_connections

一個のワーカープロセスによって同時に開くことができる接続数の最大値.

---

### worker_connections

※注意

* 同時接続数はNginxが開けるファイル数の上限を超えることはできないことでそれはworker_rlimit_nofileで変更できる
* 必要であればOSが設定しているエフェメラルポートの数を調整する

---

#### エフェメラルポート

nginxが接続をはるとき、エフェメラルポートの数以上には接続できないのでOSで設定されている数を確認して必要であれば変更する。

確認方法

```
$ sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768    60999
```

---

#### エフェメラルポート

カーネルパラメータを調整して広げる

```
$ sudo sysctl -w net.ipv4.ip_local_port_range='1024 65535'
[sudo] password for watanata:
net.ipv4.ip_local_port_range = 1024 65535
$ sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 1024     65535
```

広げた。こうすると64,511くらいは使える。

リバースプロキシとして使うとき1コネクションあたりソケットを2つ使うらしい(検証の余地あり[stackoverflow](https://serverfault.com/questions/787919/optimal-value-for-nginx-worker-connections/791055))ので、32000くらいというところから32768にした

---

workerの数は4だから
32768 / 4 = 8192

```
worker_connections 8192
```

---

### worker_rlimit_nofile

```
worker_rlimit_nofile 16384;
```

http://nginx.org/en/docs/ngx_core_module.html#worker_rlimit_nofile

workerプロセスが開くファイル数の上限。

<!-- 金言 from jackie

> 確かfdはreverse proxyとしての利用の場合リクエストの受け付けとupstreamへのリクエストで1接続につき2つ使うはずです
なのでworker_rlimit_nofileは基本的にworker_connectionsの2倍以上に設定しておくと安心だと思います！ -->

---

### worker_rlimit_nofile

※注意
Nginxはリバースプロキシとして使う場合リクエストの受付とupstreamへのリクエストで1接続につき2つのファイルを使用する。

8192 * 2 = 16384でFA?

いいえ、OSの上限を確認する必要があります。

---

### file discriptor

OS全体でオープン可能なファイル数の上限

```
$ cat /proc/sys/fs/file-max
1590275
```


<!-- 1プロセスでオープンするデフォルトのプロセス数の上限

```
$ ulimit -n
1024
``` -->

worker数は4つなので
16384 * 4 = 65,536

余裕でした

---

### ここまでで

* エフェメラルポートの拡張
* エフェメラルポートの数から`worker_processes`を決定
* `worker_processes`の2倍以上の数を`worker_rlimit_nofile`に設定

しました。

---

### その後...

検証環境でのボトルネックを確認したところ、今回はどうやらネットワークが詰まってるっぽい。

`net.ipv4.tcp_tw_reuse`を設定してみる

---

### net.ipv4.tcp_tw_reuse

#### これはなに？

https://qiita.com/tmshn/items/b49f1b51bfc472968b30
TCP接続終了時の最後の`TIME_WAIT`の終了を待たずにその接続を他の接続に再利用する

---

### net.ipv4.tcp_tw_reuse

#### どう設定する？

```
$ sysctl net.ipv4.tcp_tw_reuse
net.ipv4.tcp_tw_reuse = 0
$ sudo sysctl -w net.ipv4.tcp_tw_reuse=1
```

---

### 注意

カーネルパラメータを変更する場合は
`/etc/sysctl.conf`
を編集しておく

```
sudo vim /etc/sysctl.conf
```
Qiita記事を書くためのポイント

# はじめに

社内でQiitaへの記事投稿を目的とした、もくもく会を開催するにあたり、
初投稿者に向けて、記事作成時のポイントや注意点を自分なりにまとめてみました。

（試しにスライドモードを試してみたかったという目的があったのは内緒です）

---

## 目次

- 記事を書く目的
- 作成のコツ
- Qiita Markdown記法
- 画像の挿入
- コードブロック
- codepen
- 注意点（記述内容）
- 注意点（画像やロゴ）

---

## 記事を書く目的

- 他のエンジニアに同じ苦労をさせないため
- 自分のノウハウを記録として残すため
- 今までお世話になったエンジニア(ブログや記事)に対してのお礼
- 保有スキルのアピール

一番の目的はアピール（忘れないようにするため）と思いますが、
**同じ業界で苦労するエンジニアに対して有効となる情報を残しておく！**
という意識を持つとモチベーションを保ちやすいです。

また、[Qiitaのガイドライン](https://help.qiita.com/ja/articles/qiita-community-guideline)に記載されてように、
**プログラミングに関する再利用・汎用性の高い**
記事を投稿するようにしましょう！

---

## 作成のコツ

<img src="https://qiita-image-store.s3.amazonaws.com/0/140704/2e6be135-0ce2-dbe4-d950-5ec8e9303373.png" width=50%>

記事作成時の画面に、
Qiita公式が用意してくれている[良い記事を書くためには](https://help.qiita.com/ja/articles/qiita-article-guideline)
というページに（別タブで）遷移します。

そのページに記載されている**意識すると望ましいもの**の
内容を参考にすると良いです。

- 具体的で簡潔なタイトルをつける
- 環境や前提条件を説明する
- 引用元や参考元へのリンクを書く

---

## Qiita Markdown記法

基本的にはGitHubのMarkdown記法に似ていますが、
スライドモード等、Qiita独自のMarkdown記法が存在します。

詳しくは、[Qiita公式がまとめたMarkdownチートシート記事](https://qiita.com/Qiita/items/e84f5aad7757afce82ba)を参照ください。

---

## 画像の挿入

添付画像が大きい場合は、imgタグを使うと良いです。
参考URLは[こちらの記事](https://qiita.com/hkusu/items/1ba2de200f731e5ef374)です。

##### そのまま添付した場合

![qiita-text.png](https://qiita-image-store.s3.amazonaws.com/0/140704/f1ca4280-0d41-b706-d42e-8ed1bbef4aba.png)

##### imgタグ使用時

<img src="https://qiita-image-store.s3.amazonaws.com/0/140704/f1ca4280-0d41-b706-d42e-8ed1bbef4aba.png" width=200px>

---

## コードブロック

```ruby:test.rb
a = "bbb"
puts a if a.nil?
```

記事にコード挿入する記法のことです。
シンタックスハイライト可能な言語についても、
[Qiita公式がまとめた記事](https://qiita.com/Qiita/items/e84f5aad7757afce82ba)があるので要参照。

---

## codepen

Web上でHTML/JS/CSSを３要素を見ながら、
開発が行えるWebサービス。
**Qiita記事の埋め込みが可能！**

方法は[こちらの記事](https://qiita.com/Qiita/items/edae7417214c8e957f54)から

---

## codepenのサンプル表示

※スライドモードでは表示不可

<p data-height="300" data-theme-id="0" data-slug-hash="mKpwBg" data-default-tab="html,result" data-user="zucky_zakizaki" data-embed-version="2" data-pen-title="bootstrap_sample" class="codepen">See the Pen <a href="https://codepen.io/zucky_zakizaki/pen/mKpwBg/">
bootstrap_sample</a> by zucky (<a href="https://codepen.io/zucky_zakizaki">@zucky_zakizaki</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

---

## 注意点（記述内容）

みなさん認識されていると思いますが念のため。

- 顧客や常駐先が特定できる情報は記載しない
    - IPアドレス、システム名称 等
- いい加減な情報（嘘）は記載しない
    - 閲覧者に迷惑をかけてしまうため
    - 間違いに気づいた or 指摘いただいたら早めに修正すること

---

## 注意点（画像やロゴ）

こちらも認識済みと思いますが念のため。

- 著作権フリーな画像を使用すること
    - IPアドレス、システム名称 等
- ロゴの場合は規約に沿って使用すること
    - Qiitaの場合は[こちらのURLから](https://help.qiita.com/ja/articles/others-brand-guideline)
    - ロゴのURLをまとめた[記事](https://qiita.com/tkit/items/932316c5f5f7b162b61e)も参考に

--- 

# おわり
Buffaloのルータを寝ている間に手を触れずに再起動させる方法

# はじめに
IPv6 IPoE方式対応のBuffaloのルータ WXR-1751DHP2を購入し、我が家のインターネット回線をIPv6に変更して高速になった回線に喜んでいたら、事件は起こった。このルータ、何と起動して数日経つとWi-Fiアクセスポイントが使えなくなってしまうのである。何を言っているのか分からないと思うが、一番困惑しているのはうっかりこのルータを購入してしまった自分である。
参考にしたブログ記事[1]によると、何と半ば仕様であるようで、サポートに問合せしても埒が明かないので乗り換えたという報告が。これは安物買いの銭失いだろうか。しかし、安物とは言っても12,000円程度とどう考えても安物のルータの価格ではない。
ちなみに、決断が2週間遅ければ[NECのルータ](http://www.aterm.jp/product/atermstation/info/2018/info0604.html)を選んでいたと思う。本当にタイミングが悪い。

# モチベーション
しかし私は諦めない。
そのうち、再起動せざるを得ないということなら、先に再起動してしまえばいいのである。Buffaloのルータは、Webの設定画面に再起動ボタンが付いているので、これを自分や家族が寝ているうちに何とかして押すことを目指す。物理ボタンでもいいんだけど、ピタゴラスイッチを組んだらさすがに怒られそうなので今回は考慮しない。ちなみに、コードのテスト中にうっかりルータを何回か再起動させてしまい妻に怒られた。始末書ものである。

# 基本方針
毎日AM5:00にルータを再起動させる。バッチはPythonで記述し、動作環境はDockerコンテナ内に作成する。

バッチの全体の流れは以下のとおりである。
1. ルータのWeb画面を開く
2. ログイン情報を入力してログインボタンを押す
3. 管理者としてログイン後、再起動ボタンを押す
4. ルータ再起動

# ログイン画面の突破
## 実装手順
Chromeの開発者モードを使ってデバッグを行うとログイン時のFormに入力した値が分かる。そこで、ログインに必要な値をバッチ内で生成、あるいは設定ファイルから読み込み、リクエストを作成してログインを試行すれば良い。しかし、問題はいきなりここで発生した。Formの中のInput要素にない、encrypted値の存在である。
## 暗号化
このように、HTMLの要素にない値が唐突に出てくる場面では、大半がJavaScriptの仕業であると考えられる。案の定、今回もSubmitを押した際にJavaScriptが走る仕様になっていた。
ところが、これを追いかけたところ、雲行きはどんどん怪しくなっていった。何と入力したパスワード文字列がRSAで暗号化されて、encryptedに格納されているのである。
BuffaloのルータのWeb画面はデフォルトでHTTP通信となっており、暗号化がされていない。恐らく、パスワードを保護するための暗号化だろう。こんなところに労力を割くならHTTPS化すればいいのに、大人の事情であろうか、何とも辛いものである。私も辛い。
## 挫折
RSAの暗号化はJavaScriptで書いてあったため、Pythonに移植しようと思ったが、[PyCryptodome](https://pycryptodome.readthedocs.io/en/latest/)で実装してもうまくいかず諦めた。たかだかルータのログイン画面なのになんでこんなに頑張ってしまったんだろう。ここまでに大体5時間かかった。

# Selenium Web Driverの利用
暗号化部分が面倒なので、JavaScript部分はJavaScriptのまま動かしたいと考えていたところ、いっそのことChromeで動かしてしまえば良いではないかと思い当たり、Seleniumの導入を決意した。
Seleniumを入れたところで、全体の流れは基本方針のままである。最近はChrome Headlessの実装やPython wrapperなどが整っており、ログイン画面の突破と再起動ボタンを押下するまでは比較的簡単に実装することができた。はずだった。

# ログイン画面の突破(再)
テストを繰り返す中で、何回かに一回しかログインができないことに気が付いた。しかも、ログインできない原因は「パスワードが違います」という画面に遷移するためであった。なんでやねん。
headlessモードを解除してデバッグしてみたら、過去にログインを試行した際のログイン名が自動入力されるようになっていた。取り急ぎ、設定値を入力する前に値をクリアすることで対応した。

# コンテナ化
最新のlibrary/python:3.6であれば、chromium 66が利用できたため、これにChrome Web Driver 2.40とSelenium 3.11.0を利用した。コンテナであろうがおおよそ問題なく動く。
ただし、コンテナで動かす場合はChrome起動時のオプションに--disable-dev-shm-usageを付けた方がいいかもしれない。また、Cronで動かすときのdocker runのオプションは-itではなく、-iのみで動かす。
ここまででおおよそ10時間。前半の5時間を返して欲しいところではあるが、結果は上々である。

# おわりに
Cronがdocker runするたびにBuffaloのルータが再起動するスクリプトができた。簡単なスクリプトだけの割にはイメージサイズが大きくなってしまい、少し悲しい。

コードはMITライセンスで以下に公開しましたので、ご参考までにどうぞ。大したことはしていないはず。
https://github.com/TK403/buffalo-rebooter

# 参考文献
1. [WXR-1750DHP2のルータのワイヤレスのランプが消えて使えない！残念な決着](https://yocchko.blogspot.com/2017/09/wxr-1750dhp2.html)
Laravel/Homesteadでafter.shを使ってphpMyAdminをインストール

Laravelの開発環境をHomesteadで構築している場合、phpMyAdminはパッケージに含まれていませんので手動でインストールを行わなければいけません。

Homesteadに含まれているafter.shを使えば、お手軽にインストールすることができます。
下記をafter.shに記述してください。

```after.sh
#!/bin/bash

# phpMyAdminのインストール
# 最新バージョンは https://www.phpmyadmin.net/downloads/ でチェック
if [ -d /home/vagrant/phpmyadmin ]; then
    sudo echo '--- phpMyAdmin already installed. --- '
else
    sudo wget -k https://files.phpmyadmin.net/phpMyAdmin/4.8.1/phpMyAdmin-4.8.1-all-languages.tar.gz
    sudo tar -xzf phpMyAdmin-4.8.1-all-languages.tar.gz -C /home/vagrant/
    sudo rm phpMyAdmin-4.8.1-all-languages.tar.gz
    sudo mv /home/vagrant/phpMyAdmin-4.8.1-all-languages/ /home/vagrant/phpmyadmin
    sudo echo '--- phpMyAdmin 4.8.1 install complete ---'
fi
```

次に、homestead.yamlにnginxで動作するように設定を追加しましょう。

```homestead.yaml
sites:
    - map: phpmyadmin.local
      to: /home/vagrant/phpmyadmin
```

さらに、hostsファイルにサイトの情報を追加

```hosts
192.168.10.10 phpmyadmin.local
```

※IPアドレスは、homestead.yamlに設定しているものを指定してください。


最後に、vagrant provision コマンドを実行すれば after.sh が動作してインストールされます。

```
$ vagrant provision
```


これで、http://phpmyadmin.local にアクセスしてphpMyAdminのログイン画面が表示されれば完了です。
デフォルトでは、ユーザー名: homestead パスワード：secret でログインできます。
CentOS7でKVMを使って仮想マシンをつくってみた

昨今では、コンテナ(Docker、LXC)や仮想化ソフトウェア(VMware、VirtualBox)などが充実しています。
そんな中で、Linux KernelにマージされているKVM(Kernel-based Virtual Machine)を触ったことがなかったので、ハンズオンしてみました。
基本的にKVMはサーバ用途で使用するものなので、CUIオンリーで構築しました。構築する仮想マシンのOSはCentOSとしました。
その構築手順を備忘録として残しておきたいと思います。

#環境
- OS  :  CentOS 7.5
- CPU :  Intel Core i5 (仮想化支援機能あり)

#パッケージインストール
まずは必要となるパッケージのインストールをします。

```
$ sudo yum install -y qemu-kvm libvirt virt-install libvirt-python libvirt-client
```
GUIで仮想マシンを構築・管理したい人は、`virt-manager`もインストールしておきましょう。
インストールが終了したら、デーモンを起動させましょう。

```
$ sudo systemctl start libvirtd
$ sudo systemctl enable libvirtd
```

#仮想マシン構築
今回構築するマシンのパラメータは以下のようにします。
実際に構築する際は、各パラメータを各自の環境に合わせてください。

|parameter|value|
|:-:|:-:|
|name|demo|
|memory|1024M|
|disk|20G|
|vcpu|1|
|location of image|/tmp/CentOS-7-x86_64-DVD-1804.iso|
|network|default (NAT)|
|graphics|none|
|extra-args|ttyS0の標準出力をtty0に表示|

では、構築していきましょう。

```
$ sudo virt-install --name demo --memory 1024 --disk size=20 --vcpu 1 --location
 /tmp/CentOS-7-x86_64-DVD-1804.iso --network default --graphics none --extra-args='console=tty0 console=ttyS0'
```
成功すれば、インストール画面が表示されます。
ここからは普段のインストールとは変わらないので、説明を省きます。

#確認
構築が済んだら、実際に仮想マシンにSSHしてみましょう。

```
$ sudo virsh list --all
Id   Name    State
---------------------
-    demo   shut off


$ sudo virsh start demo    #demoの起動(シャットダウンは「virsh shutdown demo」)

$ sudo virsh list --all
Id   Name    State
---------------------
1    demo   running


$ sudo virsh domifaddr demo    #demoのIPアドレスの取得
Name      MAC address       Protocol     Address
------------------------------------------------------
xxxx   xx:xx:xx:xx:xx:xx    ipv4      192.168.100.10/24


$ ssh root@192.168.100.10
Enter password:
```
これでパッケージのインストールから構築まで終了しました。

VMで何か検証したい時や複数のサービスをデプロイしたいときなど、手軽に構築したり壊したりできるので、ぜひ試してみてください。

#参考
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/sect-installing_the_virtualization_packages-installing_virtualization_packages_on_an_existing_red_hat_enterprise_linux_system
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/sect-guest_virtual_machine_installation_overview-creating_guests_with_virt_install
Raspberry PIでデスクトップ環境無しでChromiumを起動する

Raspberry PIとGoogle Homeを買って色々連携させようと模索中なのだけど、I/Fが音声だけというのは味気ない。
Raspberry PI自体はリビングのテレビにHDMIで接続しているので、こいつを活用できないかと言うのが最初の動機。

QtやSDLで今更に頑張ってもいいのだけど、手慣れたWeb関連の技術的が使えた方が楽だからなんか出来ないかと探してみたら以下の方法できたのでメモ。

## 基本方針

- X起動用に小さなWindowManagerをバックエンド起動
- 上記のDISPLAYにchromiumをキオスクモードで起動

最初、FrameBufferとかでChromiumとかを動かせないかとも考えたんだけど、今回はマシンパワー自体が足かせになるわけじゃないので、シンプルにX経由で起動。
かといってGnomeとか入れるのも嫌なので軽量WMのmatchbox-window-managerを入れる形に。

## インストール

まずは必要なライブラリーの準備をします。

```bash
sudo apt-get install -y xinit matchbox-window-manager chromium-browser
```

## Xの起動

続いてXの起動。まずは単純に以下を実行。

```bash
$ xinit matchbox-window-manager
/usr/lib/xorg/Xorg.wrap: Only console users are allowed to run the X server
xinit: giving up
xinit: unable to connect to X server: Connection refused
xinit: server error
```
たぶん、こんな感じで死にます。 Xwrapper.configで起動ユーザーを絞ってるのが原因なので、以下のように変更します。

```bash
$ diff Xwrapper.config /etc/X11/Xwrapper.config 
15c15
< allowed_users=anybody
---
> allowed_users=console
$ cp Xwrapper.config /etc/X11/Xwrapper.config 
```

で再びWMを起動します。

```bash
xinit matchbox-window-manager &
```
今度は上手く起動したはずです。


## Chromiumの起動

続いてChromiumを起動します。

```bash
$ DISPLAY=:0 chromium-browser
```

上記で問題なく起動したと思います。DISPLAYを指定してるのでSSH経由の実行でも問題なく動作します。

キオスクモードにしてかつ適当なURLを指定して見ましょう。

```bash
$ DISPLAY=:0 chromium-browser -kiosk "http://www.youtube.com"
```

無事、フルスクリーンで起動したとおもいます。あとはURLのところを自分のnodejsとかにして、WebSocketで通信して操作すればGoogle Homeの音声コマンド等と連携してして色々出来そうです。

それではHappy Hacking!

## 参考

- [Installing Chromium on Raspberry Pi without desktop](https://www.ketzler.de/2017/12/installing-chromium-on-raspberry-pi-without-desktop/)
puppeteerで要素のリアルな座標と幅を得る

tl;dr
---------------

puppeteerでpage.mouse.move等をする場合、zoom値を考慮しましょう。



``` javascript
// 例:#btn要素を見つけてその座標を得る
const selector = "#btn";

await page.waitForSelector(selector);

const info = await page.evaluate((selector) => {
    var el = document.querySelector(selector);
    var zoom = 1.0;
    for (var e = el; e != null; e = e.parentElement) {
        if (e.style.zoom) {
            zoom *= parseFloat(e.style.zoom);
        }
    }
    var rect = el.getBoundingClientRect();
    return {
        height: rect.height,
        width: rect.width,
        x: rect.left,
        y: rect.top,
        zoom: zoom
    };
}, selector);

// 使用例: selectorの要素のど真ん中をクリックしたい場合
const center_height = info.height / 2;
const center_width = info.width / 2

const click_x = (info.x + center_width) * info.zoom;
const click_y = (info.y + center_height) * info.zoom;

console.log("move: %s(%s) => (%s,%s)", selector, JSON.stringify(info), click_x, click_y)

await page.mouse.move(click_x, click_y, { steps: 1 });
```


背景
---------

mouseでクリックする動作をさせたいと考えた場合に、その要素の座標を得る必要があるが、getBoundingClientRectで得た座標では一致しないことがあった。


なぜ？
------

page.mouse.moveする際の座標は、ブラウザ側で得たgetBoundingClientRectの情報だけではうまくいかない時がある。

以下の例では"Box2"の座標と縦横の幅がzoomによって影響を受けている例。しかし開発者ツールで座標や幅を確認すると、zoomを考慮した値になっていない。
例: https://jsfiddle.net/6hab9ems/2/

（追記: 開発者ツールなしでもわかるようにした例: https://jsfiddle.net/129anf06/1/）

この現象はデザイン時ならば、あまり問題ないはずだが、puppeteer等で操作する場合は考慮する必要がある。

雑な計算になるが、zoom値は子要素に対して作用するので、selector要素からhtml要素まで遡って、zoom値が設定されていたらかけ合わせていけば良い。

getBoundingClientRectで得た座標と幅に、zoom値をかけてやる事で、「リアルな座標と幅」（puppeteer側から見た座標と幅）を得ることができる。


なお、以下でブラウザ側でmouseの位置を表示する方法について話されているが、zoomの影響を考慮していない。
https://github.com/GoogleChrome/puppeteer/issues/374


(追記) zoomについて
------------------

zoomはIE独自拡張のstyleで、FireFox 81.0.1ではサポートされていなかった。
Chromeは85.0.4183.121でもまだサポートしている(なのでpuppeteerでもサポートしている)ので、この記事のように考慮する価値はまだあるかもしれない

zoomではなく、`transform: scale(1.5)`などを使うべき。transformのscaleの場合はgetBoundingClientRectの値をそのまま使って良くて、今回のハックは必要ない。


蛇足
----------

puppeteer関係ないな？
Ubuntu18.04にNvidia Driver, CUDA, cuDNNを入れる

Ubuntu 18.04 LTSでNvidia Driver, CUDA, cuDNNを入れる際、色々苦戦したのでこちらでまとめておきます。なお、Ubuntuのインストールは完了している前提で話を進めます。

#### 今回試した環境
- Ubuntu 18.04 LTS
- NVIDIA GeForce GTX 1070 Ti
- nvidia-driver 390.48
- CUDA 9.1
- cuDNN 7.1.2

### nvidia-driver導入手順

~~~bash
# これ一発でインストールできる
$ sudo ubuntu-drivers autoinstall

# インストールが終わったら再起動
$ sudo reboot

# 確認
$ nvidia-smi
Mon Jun 18 02:09:02 2018       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.48                 Driver Version: 390.48                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 107...  Off  | 00000000:01:00.0  On |                  N/A |
|  1%   53C    P0    38W / 180W |    358MiB /  8116MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1136      G   /usr/lib/xorg/Xorg                            18MiB |
|    0      1187      G   /usr/bin/gnome-shell                          76MiB |
|    0      1957      G   /usr/lib/xorg/Xorg                           112MiB |
|    0      2102      G   /usr/bin/gnome-shell                         137MiB |
+-----------------------------------------------------------------------------+
~~~

### CUDA導入手順

~~~bash
# Ubuntu18.04のリポジトリからインストール
sudo apt install nvidia-cuda-toolkit nvidia-driver-390
sudo reboot
~~~
この方法だと、Ubuntu18.04である限り、CUDA9.1が入るみたい。

### cuDNN導入手順
[https://developer.nvidia.com/rdp/cudnn-archive](https://developer.nvidia.com/rdp/cudnn-archive)ここからメンバー登録して、cuDNN v7.1.2 (Mar 21, 2018), for CUDA 9.1 & 9.2のdebパッケージをダウンロードする。

~~~bash
tar xzvf cudnn-8.0-linux-x64-v5.1.tgz 
sudo cp -a cuda/lib64/* /usr/lib/cuda/lib64/
sudo cp -a cuda/include/* /usr/lib/cuda/include/
~~~

.bashrcに以下を書き込む

~~~bash
## CUDA and cuDNN paths
export PATH=/usr/lib/cuda/bin:${PATH}
export LD_LIBRARY_PATH=/usr/lib/cuda/lib64:${LD_LIBRARY_PATH}
~~~

### 後始末
~~~bash
sudo apt autoremove
sudo apt clean
~~~
docomo雑談対話APIが終了するので自然対話APIに移行する

docomoの雑談対話APIが2018年6月末で終了するというメールが届いており、自然対話APIに移行しました

https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=dialogue&p_name=api_reference

```
自然対話APIのリリースにあたり、既存の対話系APIは2018年6月末に廃止を予定しております。
以下の対話系APIにつきましては自然対話APIで同等の機能をご提供しておりますので、サポート終了までに移行をご検討いただきますようお願い申し上げます。
（多くのご要望をいただいたため、5/28より自然対話APIの商用利用が可能になりました。） 
・「雑談対話」→「自然対話：雑談対話」
・「発話理解」→「自然対話：意図解釈」
・「知識Q&A」→「自然対話：知識検索」
・「シナリオ対話」→「自然対話：FAQチャット」
お手数をおかけしますが、ご検討をお願いいたします。
```


私の場合はgasで運用しているslack botだったのでそのサンプルになります
botはtypescriptで書いています

対応内容について、githubでセルフでプルリクエストを出したので、具体的な対応内容はそちらを御覧ください
https://github.com/abeyuya/gas-slack-bot-aoba/pull/1/files

## やったこと

- APIエンドポイントの差し替え
- APIに渡すデータの構造などがかわっていたので対応
- 帰ってくるデータ構造も変わっていたので対応


## 感想

- ドキュメントがわかりやすくて助かりました
- 相変わらず口調はデフォルト、関西弁、あかちゃん :baby: でした
- ちょっとだけ前より会話精度が上がっているような気がしなくもない



## 参考

自然対話APIのドキュメント
https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=natural_dialogue&p_name=api_4#tag01
Obniz ディスプレイへアクセストークンを使ってNode.jsで表示してみる。

昨日は、

自分のサーバーから Node.js で obniz に Hello Obniz! 
https://qiita.com/toshirot/items/0222ef1f494b21060134

というのをやってみましたが、実際に obniz を業務などで使うとしたら、もう少しセキュアにしたいところです。そこで、今日は obniz毎に発行できるアクセストークンを使ってアクセスする方法を試してみます。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Obniz は 個々の obniz 毎にアクセストークンを発行できるので、<br><br>明日は それを使ったセキュアな操作をやってみようと思います。<br>実際に業務で使うなら、わずか8桁の数字IDでアクセスするというのはまずいのでこれは必須な処理かなと思います。 <a href="https://t.co/3YPP0AJsTi">https://t.co/3YPP0AJsTi</a></p>&mdash; 高橋登史朗 ( T blockchain T ) (@toshirot) <a href="https://twitter.com/toshirot/status/1008029316750368769?ref_src=twsrc%5Etfw">2018年6月16日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


というわけで、アクセストークンを「マイページ」で設定してNode.jsから obniz でディスプレイに文字を表示するところまでやってみます。

1. Obnizのページでログイン https://obniz.io/users/me
2. マイページで対象obnizの[設定ボタン]クリック
3. 
![token1.png](https://qiita-image-store.s3.amazonaws.com/0/7103/6aba18dc-6201-36cd-69cc-e267054a1ba8.png)

3.左のメニューから[Access Control]を選んで[Generate Access Token]ボタンを押す

![token2.png](https://qiita-image-store.s3.amazonaws.com/0/7103/db1bdf05-52ba-b541-069a-bd83ea687ed4.png)

4.その後もう一度[Access Control]を選ぶとトークンが生成されています。下の[Renew Access Token]ボタンは文字通りアクセストークンの再発行ボタンであり、[Make obniz Public]ボタンはアクセストークンを使わないパブリックなモードに戻すボタンです。

![token3.png](https://qiita-image-store.s3.amazonaws.com/0/7103/ecb84a13-05ed-bd3d-f2a1-2e6ae06a3f54.png)

5.この時、マイページに戻ってみると対象のobnizに(Private)と表示されてセキュアなモードになっていることがわかります。この状態では、アクセストークン無しでアクセスすることができません。

![private.png](https://qiita-image-store.s3.amazonaws.com/0/7103/19ff2a62-9793-c918-40e4-1a5d11f75367.png)

6.このアクセストークンを使って例えば下記のようにコードを書きます。

### 前回のパブリックなコード

```Node.js
const Obniz = require("obniz");

const obniz = new Obniz("1234-5678");//1234-5678は自分のobnizIDに書き換える
obniz.onconnect = async function () {
  obniz.display.clear();
  obniz.display.print("Hello Obniz!")
}
```

### アクセストークンを入れたプライベートなコード

```Node.js
const Obniz = require("obniz");

const obniz = new Obniz("1234-5678", { access_token:"BR7dzjGKsd4n3uKvAx9iiqG88uocEVV2LewI0t88YbiJvUVb--Hct20wu3mOtHBxVmRIRyngfThBwlf1ie$$sGEtqUP1-h8y20UK_yXbFliQ$3AezSx0Rh0AV_L3EBI3" })
obniz.onconnect = async function () {
  obniz.display.clear();
  obniz.display.print("Hello Secret!")
}
```

### 表示

そうするとこう表示されます。もはや、前回のパブリックなコードではこの obniz へはアクセスできません。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Obniz ディスプレイへアクセストークンを使って表示してみる。 <a href="https://t.co/QReYWkYUW5">pic.twitter.com/QReYWkYUW5</a></p>&mdash; 高橋登史朗 ( T blockchain T ) (@toshirot) <a href="https://twitter.com/toshirot/status/1008394524152852480?ref_src=twsrc%5Etfw">2018年6月17日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
windowsのネットワークコントロールパネルを一発で開く


## windowsのネットワークコントロールパネルを一発で開く



`windowsキー + r`
もしくはwindows10の場合
`windowsキー`
を押して以下のショートカットキーを入力する

```
ncpa.cpl
```

以上。たったこれだけ
だが塵積である


![windowsnetwork_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/102978/75f20c0b-2c08-b12e-4dce-fc5b19de382a.jpeg)



## なにがいいのか

* 早くて楽
* windowsのバージョンに左右されない
* 再現性が高い
* 手順書に書く時らく
Jupyter notebookからpdfに変換する[mac]

Jupyterからpdfに変換するためにかなり引っかかったのでメモ
画像付きで文書は英語のみのファイルを変換しようとしました

## 環境
- macOS High Sierra
- ver. 10.13.4
- 環境管理は`pyenv-virtualenv`

## やったこと

```shell

$ pip install notebook --upgrade
$ brew install pandoc
$ brew cask install basictex
$ echo "export PATH=/Library/TeX/texbin:$PATH" >> ~/.zshrc
$ source ~/.zshrc  # ここと一つ上はbashの方は.bash_profileやらに変更
$ sudo tlmgr update --self --all
$ sudo tlmgr install adjustbox
$ sudo tlmgr install collectbox
$ sudo tlmgr install ucs
$ sudo tlmgr install collection-langjapanese collection-luatex collection-latexextra  # 日本語のファイルを変換する場合に必要らしい
$ sudo tlmgr install collection-fontsrecommended
$ jupyter nbconvert your_filename.ipynb --to pdf  # pdfに変換する
```

## 参考
- [Pandocの比較的簡単なインストール方法](https://qiita.com/sky_y/items/3c5c46ebd319490907e8)
- [PDF download: nbconvert failed: '/path/to/benchmarks.ipynb' exists but is not a directory](https://github.com/jupyter/notebook/issues/2987)
- [compiling latex: pplr8t.log font is missing](https://stackoverflow.com/questions/27177491/compiling-latex-pplr8t-log-font-is-missing)
- [jupyter notebookをTex，PDFへと変換](http://ossyaritoori.hatenablog.com/entry/2017/10/25/jupyter_notebook%E3%82%92Tex%EF%BC%8CPDF%E3%81%B8%E3%81%A8%E5%A4%89%E6%8F%9B)
Flutterでのファイルアクセス

Flutterでのファイルアクセスってどんな感じなのかちょっと触ってみたので、その備忘録

# Asset

基本はこれ。

以下に詳しく書いてあるので、一度読めばだいたい分かると思います。

https://flutter.io/assets-and-images/

`pubspec.yaml`にあらかじめassetで呼び出すファイルを指定します

```yaml
flutter:
  ...

  # To add assets to your application, add an assets section, like this:
  assets:
    - assets/test.png
```

呼び出しは画像用とbyteと文字列が呼び出せます。

## 文字列

```
Future<String> loadAsset() async {
  return await rootBundle.loadString('assets/config.json');
}
```

## 画像

```
new AssetImage('graphics/background.png')
```

## 動画・音声

ドキュメントではテキストファイル(文字列)と画像しか触れていませんが、動画やたぶん音声も扱えます。

動画は[video_player](https://github.com/flutter/plugins/blob/master/packages/video_playe)プラグインが提供されており、こちらはassetした動画をプラットフォームから参照しています。


https://github.com/flutter/plugins/blob/master/packages/video_player/ios/Classes/VideoPlayerPlugin.m#L327-L338

```objc
    if (dataSource) {
      NSString* assetPath;
      NSString* package = argsMap[@"package"];
      if (![package isEqual:[NSNull null]]) {
        assetPath = [_registrar lookupKeyForAsset:dataSource fromPackage:package];
      } else {
        assetPath = [_registrar lookupKeyForAsset:dataSource];
      }
      player = [[FLTVideoPlayer alloc] initWithAsset:assetPath frameUpdater:frameUpdater];
    } else {
      dataSource = argsMap[@"uri"];
      player = [[FLTVideoPlayer alloc] initWithURL:[NSURL URLWithString:dataSource]
                                      frameUpdater:frameUpdater];
    }
```

音声はちょっと探せてないので、確認できた方いらっしゃいましたらぜひ教えてください🙇

# Filesystem

[path_provider](https://pub.dartlang.org/packages/path_provider)プラグインが提供されており、
こちらはアプリのファイルシステムにアクセスできます。

```dart
// 一時ファイル(よく消える)
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;

// ドキュメントファイル（アプリ削除するまで消えないディレクトリ）
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
```

こちらはアプリ側で生成したものを読み込む、といった使い方になると思うので、アプリに組み込むファイルは[Asset](#Asset)を使いましょう。

## 最後に

今後公式提供のプラグインが潤沢になればうれC

Android java書いたことないので、自力で実装はしんどいかも。。。(興味はある)
WSL上のUbuntu初期設定

忘れないためのコマンド置いていく。

## apt-update

```bash
sudo apt update
```

## apt-upgrade

```bash
sudo apt upgrade
```

## 掃除

いらなくなったパッケージを削除します

```bash
sudo apt autoremove
```

## 日本語のマニュアルページのインストール

```bash
sudo apt install manpages-ja manpages-ja-dev
```

## ロケールの確認

```bash
sudo locale
```

## ロケールの変更（デフォルトロケールの変更）

```bash
sudo update-locale LANG=ja_JP.UTF-8
```

## ロケールの変更（現セッション）

```bash
export LANG=ja_JP.UTF-8
```

## タイムゾーンの変更

```bash
sudo dpkg-reconfigure tzdata
```
Linuxの権限と8進数、なんで775とか600とかって言うの？

「ここは775にしといて」「ここは750でしょ」とか
理工系出身者なら高校・大学で親しみがあるからスッと理解できるけど、
そうじゃないと最初はわけがわからない。

というわけで解説。頭の中でイメージできるようにするのが目的。

■権限と8進数
-rwxr-x---
・・・読み上げると750になる。でもなんで？

読み方
r・・・Read、数字で4、読み取り権限
w・・・Write、数字で2、書き込み権限
x・・・eXecute、数字で1、実行権限

2進数に直すと
4(r)・・・2進数で100
2(w)・・・2進数で010
1(x)・・・2進数で001

つまり
7(rwx)・・・2進数で111
6(rw-)・・・2進数で110
5(r-x)・・・2進数で101
※3は権限としておかしいので除外

だから？
どこにフラグが立っているかを2進数で表している。
それを8進数で読むと7とか6とか5とかになる。
コンピュータの世界は2進数で人間が読みやすくするために
8進数とか16進数で表している。
日常生活で使っている10進数は変換が大変なのであまり使われない。
2進数がよくわからない場合は年月と時計の読み方を考えて調べてみると良い。

最後に
権限が意味すること
777・・・だれでもなんでもできる。構築作業時など外部通信がない場合。
770・・・所有者かグループユーザだけがなんでもできる、その他ユーザはなにもできない。システム運用中の作業用など。
750・・・所有者はなんでもできる、グループユーザは編集はできない、その他ユーザはなにもできない。
755・・・所有者はなんでもできる、グループおよびその他ユーザは編集はできない。
700・・・所有者だけがなんでもできる。まず使わない。
600・・・所有者だけが読み取りと実行だけできる、編集はできない、システム的に重要なファイルなど。
UbuntuにVimをインストールする

## 環境
- Ubuntu

## Vimをインストールする
以下のコマンドを叩く

```
sudo apt-get install vim
```
## Vimがインストールされたか確認する
以下のコマンドを叩き、バージョンが表示されていればOK

```
dpkg -l vim
```
[書評]PowerShell実践ガイドブック ~クロスプラットフォーム対応の次世代シェルを徹底解説~

##先行レビューに当選！
![61ywcS7woNL._SX260_.jpg](https://qiita-image-store.s3.amazonaws.com/0/143735/e49b5bba-b084-6d6e-0001-7571443b4625.jpeg)
[PowerShell実践ガイドブック ~クロスプラットフォーム対応の次世代シェルを徹底解説~](https://www.amazon.co.jp/PowerShell%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89%E3%83%96%E3%83%83%E3%82%AF-%E3%82%AF%E3%83%AD%E3%82%B9%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E5%AF%BE%E5%BF%9C%E3%81%AE%E6%AC%A1%E4%B8%96%E4%BB%A3%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%92%E5%BE%B9%E5%BA%95%E8%A7%A3%E8%AA%AC-%E5%90%89%E5%B4%8E-%E7%94%9F/dp/4839965986/ref=pd_ecc_rvi_1)

twitterで技術情報を探していたら、たまたま見かけた先行レビュー募集のお知らせ。私みたいな初心者には関係ないなと思っていたら、著者の[@guitarrapc_tech](https://twitter.com/guitarrapc_tech)さんがこの本についてブログでこう触れていました。

>  この本は過去の「PowerShellを触り始めた直後の自分」がほしかった本でもあり、今の自分が幅広い利用者を想定して書き出せる限界ギリギリを絞りました。 コードパズルに近いマニアックな内容にならず、プログラマーでないとわからないということがないように気を使っています。
(http://tech.guitarrapc.com/entry/2018/05/08/144132)

業務でたまに使うことがあるくらいで、勉強したいけどどうやって学べばいいのか…迷っていた私はこの言葉にとても励まされ、ぜひ読んでみたいと思いダメもとで応募したらありがたいことに当選、レビューを書かせていただくことになりました。

##わたしのレベル
- PowerShellの使用はコピペのみ
- 他のスクリプトも書けない
- クライアント運用管理2年目

##よかった点
解説がとにかくめちゃくちゃ丁寧。第1章でインストールから詳しく説明されていたので、実際に手を動かしながら読み進めることができました。
私はWindowsでしたが、MacOSやLinux環境での解説もそれぞれあって、自分の使い慣れた環境で勉強できたのも良かったです。
一通り書き写しながら勉強すれば、時間はかかるけどかなり理解が深まると思います。ただ1回じゃ到底理解できないと思うので、2～3周くらいやってみると世界が変わりそう！

##気になった点
他のコマンドラインを使ったことない人や業務経験の浅い人だと第2章以降知らない言葉も多く出てくるので、適宜自分で調べながら進めていくことになります。内容もより実践的になるので、ある程度業務知識がないと難しいかも（私は難しかった）。
著者も『幅広い利用者を想定して』と言っているので、利用者のレベルに応じて、この本の使い方や道しるべのようなものがどこかにあると、初学者でももっと読み易くなるのかなと思います。
あと600ページと非常にボリューミーなので、持ち歩きには向きません。

##さいごに
今まで仕事で必要になったコマンドをコピペして、書かれている意味を全く知らないで使っていたPowerShell。この本のおかげでPowerShellの基本が理解できて、他のスクリプトとの違いや、どういう時に使うのかもなんとなく分かるようになってきました。
まだしっかり理解できていない部分も多いので、これから繰り返し読んでいきます。
※ 学んだことは今後追記していきます。
プロセスのリソース制限をさせる『rcon』

#概要
どうも。はにです。あまり専門ではないのでわかりませんが、双極性障害なんじゃないかと思いこむこの頃です。
さて、私はあるサービスを運用しています。ところが、現在はサービスのプロセスが仮想マシン上でぐちゃぐちゃして稼動しているのでいろいろな意味でよくないです。だから整理する方法を考えています。
んで、見つけたのが<a href=https://github.com/matsumotory/rcon>『rcon』</a>。
プロセスのi/oやCPUを制限できるらしいです。メンテされておらず、動くか怪しいので検証してみます。

#環境
Ubuntu 16.04

#導入

```shell
apt install rake bison flex libpam-dev 

git clone https://github.com/matsumotory/rcon

cd rcon
#ビルド
rake
```
ビルドは多少待たされます。
終わると
```shell
mruby/bin/rcon
```
にビルド物はできています。

(信用できれば、使ってどうぞ。http://haniokasai.com/file/binary/rcon__linux-x86_64.tgz)

#テスト
```shell:ヘルプ
 ./rcon --help
Usage: rcon [options] --user username --command "yes >> /dev/null"
    --cpu VAL
      default: 30 (%)
    --memory VAL
      default: 512000000 (MiB)
    --read VAL
      default: 10000000 (Byte/sec)
    --write VAL
      default: 10000000 (Byte/sec)
    --group VAL
      default: rcon
    --dev VAL
      default: 8:0
    --pids VAL
      default: nothing
    --version
```

```shell:CPU制限、ユーザーusernameで実行する。yesコマンドを10％に制限。
./rcon --user username --command "yes >> /dev/null" --cpu 10

top
#####
  PID USER          PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND  
13511 username      20   0    8300    812    744 R   9.9  0.0   0:12.08 yes
#####
```
ここで重要なポイントがあります。--userで必ずLinuxユーザーを指定しないといけないのです。ですから、rootじゃないと動かないかと、、、。
ちゃんと機能してますね。動かしてる間、±0.6％でおさまってました。

```shell:i/o制限、ユーザーusernameで実行する。ddを1M/sに制限。
sudo ./rcon --user username --command "dd if=/dev/zero of=tempfile bs=1M count=1000 oflag=direct" --write 1024000

iotopは壊れてた。
```
結局こればかりは動作してるか確認するすべがなく、、、。

#まとめ
本記事では、プロセスに各種制限を書けることが容易であることを示した。
自らリソース制限をかけられないソフトにとっては役立つだろうし、cpulimitに比べて圧倒的に柔軟性もあるし、利用価値が高い。なにかホリホリしてる人にいいかもしれない、例えばminerdとか。

#参考文献
https://blog.yuuk.io/entry/diy-container?amp=1
似てるようで違う、PHPのエルビス演算子とNull合体演算子

細かい部分を若干間違えて覚えており、危うくバグを出すところだったので、きちんと調べ直しました。

# エルビス演算子 `?:`
公式サイトには単体での説明はなく、三項演算子の項目に説明がありました。PHP 5.3 以降で使用可能です。

[三項演算子](http://php.net/manual/ja/language.operators.comparison.php#language.operators.comparison.ternary)
>式 expr1 ?: expr3 の結果は、expr1 が TRUE と同等の場合は expr1、 それ以外の場合は expr3 となります。

要するに、`expr1 ? expr1 : expr3`のシンタックスシュガーということですね。

# Null 合体演算子 `??`
こちらは独立した項目として説明されていました。PHP 7 以降で使用可能です。

[Null 合体演算子](http://php.net/manual/ja/language.operators.comparison.php#language.operators.comparison.coalesce)
>式 (expr1) ?? (expr2) は、 expr1 が NULL である場合は expr2 と評価され、それ以外の場合は expr1 と評価されます。
> この演算子は、左側の値が存在しない場合でも notice が発生しません。

`isset(expr1) ? expr1 : expr2`と同様の結果になります。
expr1がNULLや未定義でなければexpr1と評価されるので、falsyな値になる場合もあります。[^1]

【2020/4/8 追記】
いただいたコメントによると「issetはgetterによる値の取得を試行しない」とのことで、正しくは 「`!is_null(expr1) ? expr1 : expr2` と同様」のようです。

# 色々な値で検証してみる
以前、[PHP/JavaScriptの真偽と型](https://qiita.com/jshindo/items/981ffe65859ccba38e16)という記事で色々な値の真偽を調べましたが、その時と同様のデータで2つの演算子の結果を調べてみました。


| $aの値 | エルビス演算子<br>`$a ?: $b` | Null合体演算子<br>`$a ?? $b` |
| :--- | :---: | :---: |
| TRUE | TRUE | TRUE |
| FALSE | **$bの値** | FALSE |
| -1 | -1 | -1 |
| 0 | **$bの値** | 0 |
| 1 | 1 | 1 |
| -0.1 | -0.1 | -0.1 |
| 0.0 | **$bの値** | 0.0 |
| 0.1 | 0.1 | 0.1 |
| 文字列 'a' | 'a' | 'a' |
| 空文字列 '' | **$bの値** | '' |
| 文字列のゼロ '0' | **$bの値** | '0' |
| NULL | **$bの値** | **$bの値** |
| 空の配列 array() | **$bの値** | array() |
| 空でない配列 array(0) | array(0 => 0) | array(0 => 0) |
| 空のオブジェクト new stdClass() | stdClass::__set_state(array( )) | stdClass::__set_state(array( )) |
| 未定義の変数 $none | **$bの値**<br>（`Notice: Undefined variable` が発生し、nullとして評価された結果） | **$bの値**<br>（Noticeは発生しない） |
| 未定義のインデックス $my_array['none'] | **$bの値**<br>（`Notice: Undefined index` が発生し、nullとして評価された結果） | **$bの値**<br>（Noticeは発生しない） |
| 未定義のプロパティ $my_object->none | **$bの値**<br>（`Notice: Undefined property` が発生し、nullとして評価された結果） | **$bの値**<br>（Noticeは発生しない） |

表にはありませんが、エルビス演算子が`$a ? $a : $b`と同じで、Null合体演算子と`isset($a) ? $a : $b`が同じ結果になることも検証してあります。
\$aが未定義の可能性がある場合は、エルビス演算子を使わずに`!empty($a) ? $a : $b`とするのが安全ですね。


[^1]: ここを誤解して覚えていました
Chefのattributeで値を設定する際、その値に属性を追加する可能性があるならば、その値は予めキーとして設定しておく

#問題

```ruby:attributes/default.rb

default['foo']['bar']['file'] = '/tmp/test.txt'
```

などと最終的な値をdefault[]に代入すると、後からその属性情報を以下の様な感じで追加できない。

```ruby:attributes/default.rb

default['foo']['bar']['file']['/tmp/test.txt']['owner'] = 'usr1'
```
#対応
この様な拡張が後からできる様にするには、最初から以下の様にkeyにしておけば良い。


```ruby:attributes/default.rb
default['foo']['bar']['file']['/tmp/test.txt'] = nil

# あるいは、通常は省略しているactionなどをあえて書いておく。
default['foo']['bar']['file']['/tmp/test.txt']['action'] = :create
```



これなら、

```ruby:attributes/default.rb

default['foo']['bar']['file']['/tmp/test.txt'] = nil

# 追加で属性を拡張
default['foo']['bar']['file']['/tmp/test.txt']['owner'] = 'usr1'
```

などとできる。
この例の場合、もし行の順序が逆となると属性が消されてしまうので注意。それを考慮するとactionなど追加キー込みで設定した方がやや安全


#蛇足 : 片方向連結リスト構造の様に、すべてのattributeの最後をnilで終わらせてみる

```ruby:attributes/default.rb

default['foo']['bar']['file']['/tmp/test.txt'] = nil
default['foo']['bar']['file']['/tmp/test.txt']['owner']['usr1'] = nil
```

ユーザーデータが途中のキーだったり最後の値だったりという状況から、途中のキーに統一されて分かりやすくはなった


取り出す際のレシピへの影響はどうだろう。

```ruby:attributes/default.rb
  
# 最後の値のみ.keys.firstをつける
node['foo']['bar']['file'].each do |f_name, f_attr|
  file f_name do
    owner f_attr['owner'].keys.first
  end
end

# もしくは
# すべての値はhashに対する.eachでキーを取り出す
node['foo']['bar']['file'].each do |f_name, f_attr|
  file f_name do
    f_attr['owner'].each do |o_name, _o_attr|
      owner o_name
    end
  end
end

```

最後の値だけ.keys.firstが必要という綺麗な実装では無い。
もしくは、ユーザーデータの扱いをhashに対する.eachに統一できるという点では整合性はとれているが、不必要に長い感触。

総合するとあまりメリットを感じなかった。

#参考
[\[\]= (Hash) Rubyリファレンス](https://ref.xaio.jp/ruby/classes/hash/element_assign)
AWS CodeCommitを利用してみる

#前提
- AWSのアカウント取得済み。
- デプロイするアプリがある。
- EC2インスタンスにSSHでリモートログインできる。
- Gitでcommitとかpushとかできる。


#CodeCommitを使う
## CodeCommitとは
Gitのホスティングサービスです。

- GitHub
- GitLab

とかみたいなやつ

- ５ユーザまでは無料で利用できる、それ以降は１ユーザ　１USD
- プライベートに使えるよ。

GitHubとかに比べて大きな機能的なアドバンテージはないと思います。

## 使う

ダッシュボード
<img width="1232" alt="dashbord.png" src="https://qiita-image-store.s3.amazonaws.com/0/202764/4a4cebb7-a7fd-9f0f-09c7-5886b2ca20dd.png">
[リポジトリ作成ボタン]を押して

<img width="700" alt="makerepo.png" src="https://qiita-image-store.s3.amazonaws.com/0/202764/1185dbfd-fafb-9688-52c4-c33247f871ea.png">
リポジトリ名、説明を入力を記入して[リポジトリ作成]ボタンを押せばリポジトリができる。

## 認証

[AWSのコンソール](https://console.aws.amazon.com/iam/home#/home)から

- SSH公開キーの登録
- [AWS CLI HTTP接続の設定](https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/setting-up-https-unixes.html)
- [Git認証HTTP認証情報を取得する](https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/getting-started.html)

<img width="1383" alt="Git.png" src="https://qiita-image-store.s3.amazonaws.com/0/202764/d3f80f60-fc00-eed8-d7bf-b4c8edcc12b0.png">

認証が済んだら
ローカルのGit remoteに作成したリポジトリを指定して
リモートへPushしてみる。

AWSのCodeCommitコンソール画面にPushしたアプリがアップされていればOK。
Google Apps ScriptでTwitter APIを叩く

## やりたいこと

- gasからTwitterAPIを叩きたい
- access token, access token secretを持っているのに、それを使わずにoauth認証するような実装をしなきゃいけないのが面倒
- 直接これらを渡して、直接API叩く方法無いのかな？
- あった！


## どうやったか

gasのOAuth1ライブラリに`setAccessToken`というメソッドが用意したあったのでそれを使えばOKでした
サンプルとかドキュメントにはこのメソッド出てこないが、ライブラリのソースコード読んでたら見つけました


```js

var getTwitterService = function () {
  return OAuth1.createService("Twitter")
    .setAccessTokenUrl("https://api.twitter.com/oauth/access_token")
    .setRequestTokenUrl("https://api.twitter.com/oauth/request_token")
    .setAuthorizationUrl("https://api.twitter.com/oauth/authorize")
    .setConsumerKey("xxx")
    .setConsumerSecret("xxx")
    .setAccessToken("access token", "access token secret"); // これだよ！！
};

var service = getTwitterService();
var res = service.fetch("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=qiita");
```

事前にOAuth1ライブラリをgasに導入しておく必要あり → https://github.com/gsuitedevs/apps-script-oauth1#setup


## 参考

- https://github.com/gsuitedevs/apps-script-oauth1/blob/master/samples/Twitter.gs
- https://github.com/gsuitedevs/apps-script-oauth1/blob/master/src/Service.gs#L213-L220
Javaでenumを使ってシングルトンを素早く実装する

当記事は[Javaでenumを使ってシングルトンを素早く実装する | Think Twice](https://thinktwice.tech/it/java/quickly_implement_a_singleton_using_enum_in_java/)へ移管しました。

<!--
当記事は[Javaでenumを使ってシングルトンを素早く実装する | Think Twice](https://thinktwice.tech/it/java/quickly_implement_singletons_using_enums/)へ移管しました。

当記事は[Javaでenumを使ってシングルトンを素早く実装する | Think Twice](https://fumokmm.github.io/it/java/quickly_implement_singletons_using_enums)へ移管しました。
-->
ReactNativeの世界一シンプルなFlatListサンプル

FlatListは動的なlistコンポーネントだ。
静的なリストはScrollViewを使う。

使い方は簡単で配列をdataに渡し、renderItemで表示を示す。


```react

<FlatList data={[1, 2, 3]} renderItem={({item}) => <Text>{item}</Text>}/>
```

結果
1
2
3

以下は公式のサンプル。ハッシュも使える。

```react
<FlatList
　　　　data={[{key: 'a'}, {key: 'b'}]}
  renderItem={({item}) => <Text>{item.key}</Text>}
/>
```

結果
a
b
BingWebSearchAPIを利用して、深層学習用の画像データを収集する方法

# はじめに
TensorFlowで画像分類器を作成するために、ネットから画像を収集するためのプログラムを作成しました。近年はウェブスクレイピングが難しくなりつつあるので、BingWebSearchAPIを利用しました。

# 経緯
最初は、Python3のbeautifulsoupを使って実装しようとしていましたが、挫折しました。画像スクレイピングのハードルは、まだまだ高いと思います。
近年の大手米ITベンダーのAPIはとても使いやすくとても優れているので、使わない手はないです。

# Azureのアカウント作成
多少めんどくさいので、ここでは割愛します。

# 実際のコード
コンフィグファイルとコードは以下の通りです。


```ruby:config.ini

  1 [keys]
  2 key1 : APIキーその１
  3 key2 : APIキーその２
  4 
  5 [search]
  6 url  : https://api.cognitive.microsoft.com/bing/v7.0/images/search
  7 term : 検索クエリのワード
  8 
  9 [params]
 10 count  : 100
 11 offset : 100
 12 itr    :   5
 13 
 14 [dir]
 15 name : ディレクトリ名
 16 
 17 [file]
 18 name : 連番ファイル名

```


```ruby:image_collection.py
  1 import requests
  2 import configparser
  3 
  4 # Read the Configurations
  5 config = configparser.ConfigParser()
  6 config.read('Config.ini')
  7 
  8 # Push the Configurations
  9 headers = {"Ocp-Apim-Subscription-Key" : config['keys']['key1']}
 10 
 11 # Search
 12 results = []
 13 for i in range(int(config['params']['itr'])):
 14     params  = {"q": config['search']['term'], "count": config['params']['count'], "offset": i*int(config['params']['offset'])}
 15     response = requests.get(config['search']['url'], headers=headers, params=params)
 16     response.raise_for_status()
 17     search_results = response.json()
 18     thumbnail_urls = [img["thumbnailUrl"] for img in search_results["value"]]
 19     print(len(thumbnail_urls))
 20     results.extend(thumbnail_urls)
 21 
 22 print(len(results))
 23 
 24 from PIL import Image
 25 from io import BytesIO
 26 
 27 for i in range(len(results)):
 28     image_data = requests.get(results[i])
 29     image_data.raise_for_status()
 30     image = Image.open(BytesIO(image_data.content))
 31     filename = config['dir']['name']+"/"+config['file']['name']+str(i+1)+".jpg"
 32     image.save(filename)

```
Ruby on Rails 取り敢えず形にしてみる

第一にメモ代わりに書いております。
それから、プログラミングの一歩で挫折しない人が増えれば楽しいという気持ちで
できるだけ自分なり噛み砕いてに仕組みを書いてみました。
書いている私も至らない点が多いと思いますので、誤記がありましたらご指摘いただけると幸いです。


作業環境
Mac OS
エディタ：Atom 

___

1.これから作成するデータの保管場所を作成
`mkdir フォルダ名(任意)` **+ Enter**
![スクリーンショット 2018-06-17 18.09.21.png](https://qiita-image-store.s3.amazonaws.com/0/197693/e83fc691-0260-b17b-d0bf-e4c54ba5b782.png)
ここではrutkoというフォルダを作成できました。

___
2.先程作ったフォルダ場所まで移動
`cd フォルダ名(先程作ったやつ)` **+ Enter**

3.フォルダをAtomで起動
`atom .` **+ Enter**
![スクリーンショット 2018-06-17 18.24.51.png](https://qiita-image-store.s3.amazonaws.com/0/197693/4a32a028-332d-a75b-0715-a78f5bdde080.png)
Atomでフォルダを作業する準備ができました。
まだ何もファイルが出来ていない状態です。
___
3.Railsアプリケーションの環境を作成
`rails new アプリケーション名(任意)` **+ Enter**
![スクリーンショット 2018-06-17 18.31.23.png](https://qiita-image-store.s3.amazonaws.com/0/197693/730678f3-2c77-cdc8-cdfe-1a02ae73d847.png)
ここではtwitterというアプリケーション名のフォルダが作成されその中に開発に必要なフォルダが入りました。

4.作成したアプリケーションフォルダまで移動
`cd アプリケーション名` **+ Enter**

5.Railsサーバー起動
`rails s`**+ Enter**
![スクリーンショット 2018-06-17 18.41.15.png](https://qiita-image-store.s3.amazonaws.com/0/197693/c841e396-ab9a-5403-0ae8-14af00644238.png)
ブラウザで` localhost:3000 `を入力すると可愛いページが表示されます。
___

ここからはターミナルを2つ使います。(1つはサーバーを動かしてるのでほっておきましょう)
6.アプリケーションのTOP画面を作成
`rails generate controller home top`
![スクリーンショット 2018-06-17 18.47.36.png](https://qiita-image-store.s3.amazonaws.com/0/197693/04a69167-dd72-9377-7adf-2b0ee56fdd7b.png)
ブラウザで` localhost:3000/home/top `へアクセスするとTOP画面が表示されます。

`rails generate controller ファイル名 ページ名`
ページを表示するために必要なファイルを作るコマンドくらいの理解でよろしいと思います。

次はページの作成をしていきます。
___


7.Atomからページの見た目を変更(view)
`twitter/app/views/top.html.erb`
![スクリーンショット 2018-06-17 19.39.49.png](https://qiita-image-store.s3.amazonaws.com/0/197693/ed1cd44b-59e6-fc56-bc1c-db29b2fd2b27.png)
viewsの中に作成したページファイルがあるので、htmlを書く要領でページの見た目を作成しましょう。


___
8.viewファイルをブラウザに反映させる(controller)
`twitter/app/controller/concerns/home_controller.rb`
![スクリーンショット 2018-06-17 23.04.13.png](https://qiita-image-store.s3.amazonaws.com/0/197693/413d9b6c-f2db-a939-5b2e-5794956a8d5e.png)
`def ~ end` ブラウザのhomeの中の~に　`views/home/~.html.erb`を送信するアクションです。

___
9.URLを読み込む部分を作成(routing)
`twitter/config/locales/routes.rb`
![スクリーンショット 2018-06-17 23.20.02.png](https://qiita-image-store.s3.amazonaws.com/0/197693/d1ea51a7-61b8-ee95-b184-7b1a90720e7f.png)
`get 'home/top(URL)' => 'home(コントローラ名)#top(アクション名)'`
`localhost:3000/home/top`のURLに`home_controller.rb`で指示した`top.html.erb`を表示してくださいと命令を出す感じです。

なので、URLの部分は書き換えても表示されます。
![スクリーンショット 2018-06-17 23.27.50.png](https://qiita-image-store.s3.amazonaws.com/0/197693/747e0455-e85c-3d32-d127-0b73d447e42b.png)
こんな感じです。

____
10.各ページを作成する
`rails generate controller user main`
![スクリーンショット 2018-06-17 23.42.15.png](https://qiita-image-store.s3.amazonaws.com/0/197693/3dd9e2b8-2fc8-aec4-644f-af20b58c3ff9.png)
`rails generate controller user main`
コントローラ名とアクションは同じものを使うことができないので違うものを入れる必要があります。
7.8.9の手順を使えば沢山のページを作ることができます。
___
Pythonについて vol05.while文

今回はwhile文です。
自分の感覚で言うと、ifの繰り返し文という感じです。
条件を満たす限り(条件文がTrueの限り)実行されます。

基本形

    while <条件文>:
        <繰り返し文>

例えば、何かの状態が変わるまで実行する、というような使われ方をします。

    while flag==True: # while flag:　とも記載可能
        <繰り返し文>

また無限Loopを作る際は、

    while True:
        <繰り返し文>
とします。（何かでbreakしないと終わりません。）

あと、continueとbreakとelseが使える点はfor文と同様です。（詳細省略）
Pythonについて vol04.for文

今回は繰り返しのfor文です。次回は繰り返しのwhile文をやるつもりです。

pythonのfor文はtcshで言うところのforeach文と同じで、
複数データを順番に処理する、という使い方をします。
配列や辞書などと一緒に使われます。

使い方

    list = ['a', 'b', 'c', 'd']
    for i in list:
        prinf(i)

iにlistの要素が順番に格納されます。実行結果は、

    a
    b
    c
    d
となります。

またrange()と一緒に使うこともあります。
range()は指定の回数、0からカウントします。
range(5)だと0～4、range(1,6)だと1～5、range(1,10,2)だと1,3,5,7,9と2つづ増えます。
range(start,stop,step)とすると、startからstop-1までstepづつカウントアップ。という感じです。
数字が1つだとstartには0が入って、stopにはその数字が入ります。
ってどういう定義してるんだ？と思ったら、2つのrange定義されているそうです。
range(stop)
range(start, stop[, step])
貼り付け元  <https://docs.python.jp/3/library/functions.html#func-range> 
なるほど。そうだよな。第1引数を省略可能ってなんだよって思いました。

あとfor文で使われるのはbreakとcontinueとelseです。
for文でもelseが使えます。使用例です。

    for i in range(100):
        if i % 10 == 0: # 10の倍数の時
            print('現在' + str(i) + 'です。')
            continue
        print('処理中です。')
    
        if i == 85:
            print('処理を中断しました。')
            break
    else:
        print('この処理は' + str(i) + 'まで実行しました。')

というのを作ってみたんですが、breakするとelseは処理されないんですね。。。
通常は「処理中です。」が表示されますが、
10の倍数の時だけ「現在xxです。」と表示され、continueがあるのでその時点で次の数字に進みます。
「処理中です。」は表示されません。
また85になるとbreakがあるので、for文が終わります。elseも含め後の処理は実行されません。
なので、breakをコメントアウトして実行すると、i=99で繰り返し処理が終わり、最後に「この処理は99まで実行しました。」が表示されます。
または最後のprintをfor文の外に出せば、いくつまで実行されたのか表示されます。
Pythonについて vol03.if文

今回からロジックに入っていきます。
まずはif文についてです。
 
基本形

    if <条件文>:
        <命令文>
    elif <条件文>:
        <命令文>
    else:
        <命令文>

各々の命令文の行頭にインデントを入れてください。
python界ではインデントはスペース4つが定説です。
（って後輩に借りパクされたオライリーに書いてあった気がする。）

条件文には以下の比較演算子が利用できます。
数字：==, !=, >, >=, <, <=
文字：==, !=
オブジェクト：is, is not

等号、不等号の順番は固定です。（必ず不等号が先）
またオブジェクトのis, is notはNone(Null)の時に使う。くらいに覚えておけばよいです。
 
記述例)

    if var is None:
        print('var is None')
    elif var is not None:
        print('var is not None')

またif文とin演算子の組み合わせは便利です。
配列や辞書をfor文で繰り返す必要がありません。
 
記述例）

    array = ['a', 'b', 'c', 'd']
    if 'c' in array:
        print('There is c in array')

    dict = {'key1':'value1', 'key2':'value2', 'key3':'value3'}
    if 'key3' in dict:
        print('key3 is '+dict['key3'])
    else:
        print('There is not key3 in dict')

valueを探す場合

    if 'value3' in dict.values():
        print('There is value3 in dict')
※value3の時のkeyを見つけるにはforを使わないとだめかなぁ。