OmniAICreator/Qiita-1.07M huggingface dataset:
AlexaのエンドポイントLambdaのバージョン制御

Alexaスキルは大きく分けると次の２つから構成される。

- インテントやサンプル発話で構成される**対話モデル**
- 各インテントを受けて返答を生成する**バックエンド**

この２つがかみ合ってスキルとして正しく動作する。

対話モデルについてはAlexaコンソールで作るしかないが、バックエンドについてはAlexaサービスとやり取りできれば何で作っても構わない。
その中でLambdaを利用するのが手軽なので、使っているスキルも多いと思う。
素朴にやると、Lambda関数の`$LATEST`のARNをそのまま、エンドポイントとしてスキルに設定してしまうがそうするとスキル公開後にアップデートする場合に困ったことになる可能性がある。

この困ったことと、バックエンドがLambdaの場合の私なりの対処方法について書いてみる。

## 対話モデルとバックエンドの更新タイミングはずれる
バックエンド側は任意のタイミングでデプロイして処理内容をアップデートできる。これはスキルを公開する前はもちろん、公開した後も同様にLambdaをデプロイし直せばアップデートできる[^1]。
一方、対話モデルの方はちょっとでも変更すると再申請しないと公開されない。したがって、対話モデルとバックエンドを同時にアップデートしたくてもどうしても審査の時間の分だけタイムラグが発生する。

[^1]: 運用上便利ではあるのだけど、公開申請に通ったあと、規約に抵触するような変更もできてしまう。Amazonは何らかチェックをしているのだろうか？

いま、すでに公開されているスキルをアップデートする場合を考えてみる。
最初の状態では <font color="Blue">対話モデルA</font>＋<font color="Blue">バックエンドv1</font>で動作している。それを最終的に<font color="red">モデルB</font>＋<font color="red">バックエンドv２</font>にしたいというケースだ。モデルを変更するので公開には再申請が必要となる。

<font color="red">バックエンドv２</font>には<font color="red">モデルB</font>への変更に対応した変更が加えられている。申請を行うと、<font color="red">モデルB</font>＋<font color="red">バックエンドv２</font>がAmazonのスキル審査により評価できるようにしなければならない。

しかし<font color="Blue">対話モデルA</font>と<font color="red">モデルB</font>に設定されたエンドポイントのARNが同一の場合、一般ユーザに公開されている対話モデルは<font color="Blue">対話モデルA</font>なので、<font color="Blue">対話モデルA</font>と<font color="red">バックエンドv２</font>の組み合わせでもエラーなく動作しないとエンドユーザがエラーでスキルが使えなくなる。

単純なインテントやサンプル発話の追加程度なら、<font color="Blue">対話モデルA</font>と<font color="red">バックエンドv２</font>の組み合わせでも動作に問題は生じないだろう。
しかし、<font color="Blue">対話モデルA</font>にとって破壊的な変更が<font color="red">バックエンドv２</font>に含まれる場合、困る。

破壊的な変更を含めないように注意して<font color="red">バックエンドv２</font>を実装するとか、<font color="red">バックエンドv２</font>を別のLambda関数としてデプロイするとかすれば回避できるが、開発中には<font color="red">対話モデルB</font>＋<font color="red">バックエンドv2</font>を目指して実装するので<font color="Blue">対話モデルA</font>のことを考慮したくないし、このような変更のたびに新しいLambda関数を作っていくのも面倒だ。

## では、どうするか？
Lambdaには**バージョン**と**エイリアス**(別名)という機能がある。
作成するとバージョンごと、あるいはエイリアスごとに異なるARNが発行される。

バージョンを作成するとバージョン番号を付けられてその時点の`$LATEST`のコードが保存される。ARNの末尾に`:<バージョン番号>`を付加すると特定のバージョンを指し示すことができる。なお、バージョン番号は自動的にインクリメントされていく。任意にはつけられない。

エイリアスは任意に名前をつけることができ、そのエイリアスに対応するバージョンを設定する。エイリアスが指し示すバージョンは任意のタイミングで変更できる。`$LATEST`を設定しておけば常に最新のバージョンを指し示すこととになる。
特定のエイリアスを指し示すにはARNの末尾に`:<エイリアス名>`をつければ良い。

この機能を活用すれば、前述の困ったことは回避できる。

まずは、新規申請でも、既存公開スキルの再申請でも構わないので、バックエンドのエンドポイントにエイリアスを設定している状態にする。
1. Lambdaのエイリアスを作成し、 バージョンに`$LATEST`を設定する。
2. AlexaスキルのバックエンドのエンドポイントにはこのエイリアスのARNを設定してスキルを申請、公開する。

次の再申請のときには次の手順で申請する。
1. 再申請前にLambdaのバージョンを作成し、エイリアスにそのバージョンを設定してバージョンを固定する。
2. 新たなエイリアスを作成し、バージョンに`$LATEST`を設定する。
3. 対話モデルのエンドポイントに新しいエイリアスのARNを設定して再申請する。

こうすれば、<font color="blue">対話モデルA</font>は旧エイリアスで固定されたLambdaバージョンとやり取りして動作し、<font color="red">対話モデルB</font>は最新のLambdaバージョンとやり取りして動作させることができる。しかもLambdaをアップデートすればバックエンドの処理は任意のタイミングで変更することが可能となる。

## まとめ
AlexaスキルのバックエンドにLambdaを利用するときにはエンドポイントにエイリアスを設定しておこう。
Rails session情報削除ボタンの作り方

###ボタンの記述方法をググった結果
[Railsリファレンス](http://railsdoc.com/references/button_to)より
>
```erb
使い方
button_to(文字列 [, オプション, HTMLオプション]
<%= button_to "削除", { :action => "destroy", :id => @page.id }, :confirm => "本当に削除しますか?", :method => :delete %>
```

参考例が記述してあったが、:actionや:idが何なのか説明もなく初心者には全く分からない。
[button_toでgetメソッドを指定しようとしたら手間取った](https://qiita.com/EastResident/items/11cd287ef7a8927318cf)
[button_to ボタンでリンク rails
](https://doruby.jp/users/katsuo_on_rails/entries/button_to___rails)
などを参考に、button_toはlink_toは基本的に使い方は同じだと理解。

```
button_to 'リンク',パス,アクション指定
```

###Railsにおけるボタンの記述例
ここではセッションに保存した情報を削除する
rails routes の cart delete には /cart/:id とあり idを要求されているのでパスの
引数に指定しなければならない。
metod: :deleteは削除する際のおまじない的なもので、これを記述したことにより
コントローラーの方でdestroyアクションを定義することになる。

```erb
<%= button_to "Clear Cart", cart_path(session[:cart]), method: :delete%>
```

###controllerの記述
session削除には複数の記述方法があるが、ここではreset_sessionを用いています。
session情報を削除した後は、元のページに戻って欲しいのでredirect_toでパスを指定

```ruby
def destroy
    reset_session
    redirect_to cart_index_path
  end
```

###実行結果

```terminal
Started DELETE "/cart/6" for 127.0.0.1 at 2018-08-14 20:45:01 +0900
Processing by CartController#destroy as HTML
  Parameters: {"authenticity_token"=>"dkOpjA4gWeHzVhsgvbC06PmGPkdsvy9C1I4XZ2pObZYf0IbtDRG6oGiUKOffE+lvtjyyjkknAoKgImK3OgMrrA==", "id"=>"6"}
Redirected to http://localhost:3000/cart
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)


Started GET "/cart" for 127.0.0.1 at 2018-08-14 20:45:01 +0900
Processing by CartController#index as HTML
  Rendering cart/index.html.erb within layouts/application
  Rendered cart/index.html.erb within layouts/application (5.3ms)
Completed 500 Internal Server Error in 15ms (ActiveRecord: 0.0ms)

ActionView::Template::Error (No route matches {:action=>"show", :controller=>"cart", :id=>nil}, missing required keys: [:id]):
    17: <br>
    18: <% end %>
    19: 
    20: <%= button_to "Clear Cart", cart_path(session[:cart]), method: :delete%><br>
    21: <%= link_to 'Check Products', root_path %>
```
missing required keys: [:id]　:idが見つかりませんとエラーを吐く。
ブラウザではなくterminalにてlogを確認するとdeleteアクションを実行した後、redirectに設定したパスに戻る際のgetアクションでエラーが生じている。
戻った先のページ内にて別リンクに飛ぶパスの記述がこのままではダメですよーとのこと。
少し考えた後に、削除ボタンを実行した為にsession[:cart]が空になっているので、リンクに指定しているcart_path(session[:cart])の引数がないからエラーが起きていたのだと理解。

###完成形ボタンコード

```erb
<% if session[:cart] != nil %>
<%= button_to "Clear Cart", cart_path(session[:cart]), method: :delete%><br>
<% end %>
```
session[:cart]が空でない時のみに削除ボタンを出現させるように条件式を記述したら無事解決。
つくづくRails gで生成されたコードやそれに加える変更は全てがおまじないに見えるので、paizaスキルチェックでrubyのコードを書いてた頃とは違い自分が何をしているかが分からない感覚が悲しい・・。
Firebase Admin SDK で Firestoreのドキュメントフィールドへ任意の時刻のTimestampを設定する

`firebase.firestore.FieldValue.serverTimestamp()` でサーバー時刻を取得できるけど、任意の時刻のTimestampが作りたい

```js
const firebase = require('firebase-admin')

const date = new Date('2018-08-08T11:24:15.971Z')

const timestamp = firebase.firestore.Timestamp.fromDate(date)

console.log({timestamp})
```

`firestore.Timestamp` というクラスが生えているのでこれを使うといいらしい。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/229/7fb774ba-020b-298c-0965-8b6b49b54f89.png)

Databaseコンソールの表示が String や Number じゃなくて `timestamp` になっていればok

- [Cloud Firestore にデータを追加する  \|  Firebase](https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ja)
netcat で /var/run/docker.sock を叩く

# netcat で tcp を bash から叩く

netcat はシェルの標準入出力から TCP|UDP を叩くことができるコマンドです。
HTTP サーバや HTTP クライアントも作ることができます。
`-U` オプションを使えば unix domain socket も叩くことができます。

## HTTP サーバ

```bash
#!/bin/bash
nc -l 8080 -q0 << 'EOF'
HTTP/1.1 200 Ok
Connection: close
content-type: plain/text
Hello World

EOF
```
`-q0` で STDIN の EOF を検出したら0秒で終了します

## HTTP クライアント

```bash
#!/bin/bash
nc localhost 8080 -q1 <<'EOF'
GET / HTTP/1.1
Host: localhost:8080

EOF
```

サーバの応答を待つために 1 秒だけ待っています

## unix domain socket を叩く

/var/run/docker.sock も叩けます

```bash
#!/bin/bash
nc -U /var/run/docker.sock -q1 <<'EOF'
GET /containers/json?all=1&size=1 HTTP/1.1
Host: localhost:8080

EOF
```

デバッグなどに便利ですね

## 参考

* https://orebibou.com/2015/11/ncnetcat%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%A7%E8%A6%9A%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E4%BD%BF%E3%81%84%E6%96%B98%E5%80%8B/
* http://blog.livedoor.jp/sonots/archives/34703829.html
* https://unix.stackexchange.com/questions/189454/netcat-doesnt-terminate-when-stdin-closes
* https://stackoverflow.com/questions/1270027/how-can-i-close-a-netcat-connection-after-a-certain-character-is-returned-in-the
「「サマータイム導入はコンピュータシステム的に難あり」は本当か」は本当か

# 「「サマータイム導入はコンピュータシステム的に難あり」は本当か」は本当か

引用元は以下となる。最終訪問日: 2018/8/14 19:27

https://www.mag2.com/p/news/367461/3
https://www.mag2.com/p/news/367461/4

上記内容について考えたことを簡単にまとめる。
こちらの勘違い、解釈の誤りなどがあればご指摘いただければ幸いである。

----

> コンピュータ（システムやプログラム）には「時間経過」の概念がありません。命令を受けた瞬間からの経過時間は、秒単位でカウントアップしていくだけで、つまり「その瞬間」しかコンピュータは認識していません。
> これをプログラミングにより擬似的に、時間経過の概念があるように見せかけているのが、エアコンなどの「タイマー機能」です。
「時間経過」の概念がない、といいつつ、経過時間を秒単位でカウントアップしていく、は矛盾に見えます。また、プログラムには時間経過の概念がないはずなのに、プログラミングで概念があるかのように見せかけている？というのは一体何を意味しているのかよくわかりません。

一般的なlinuxにおいては、jiffiesという時間経過の概念があり、これは秒単位でのカウントでもない。

https://www.valinux.co.jp/technologylibrary/document/linuxkernel/timer0002/
> Jiffies は、tick、すなわち 1/HZ 秒 (RHEL では HZ = 1000で、1 ミリ秒) 毎に 1 ずつ増えるグローバル変数 (符合なし整数) で、カーネル内部で時間を測るのに利用できます。

----
>サマータイムとなり自然時間の定義が変われば、コンピュータも同時に変えなければと「思いこみ」ますが、コンピュータが処理に用いているのは、埋め込まれたクォーツが刻む「内部時間」だけです。
日時の処理は、内部時間を変換して行っているに過ぎず、自然時間の概念をコンピュータは必要としません。

**コンピュータは自然時間の概念がなければ、内部時間を自然時間から/へ変換することができない**のではないか？

まず、前提条件を確認する。人間はわざわざタイムゾーンがどちらであるかを判別したくないため、自然時刻で入出力したい。

- 人間は、人間可読性のある自然時刻しか入出力できない。
- コンピュータは、人間可読性の無い内部時刻しか処理できない。

次に、実際のデータの流れをまとめる。

・人間は、自然時刻を、コンピュータへ入力する。
- コンピュータは、自然時刻を内部時刻に変換する。
- コンピュータは、内部時刻を処理する
- コンピュータは、内部時刻を自然時刻に変換する 。
- 人間は、コンピュータが出力する自然時刻を読み取る。

例えば、2019年7月1日~9月30日まで2時間前倒しにすると仮定する。この場合１分毎に日付と時刻は以下のように変化すると想定される。

| 日付 | 時刻 |
|:-:|:-:|
| 2019年6月30日 | 23:57 |
| 2019年6月30日 | 23:58 |
| 2019年6月30日 | 23:59 |
| 2019年7月01日 | 02:00 |
| 2019年7月01日 | 02:01 |

ここで「2019年7月1日、 01:59」の自然時刻で入力された場合、コンピュータは内どう処理すべきだろうか。

(a) 2019年6月30日 23:59 とみなす
(b) 2019年7月 1日  3:59 とみなす
(c) 2019年7月 1日  2:00 とみなす
(d) エラーにする

いずれの選択をとってもコンピュータは、どの値域が有効な自然時間であるのかを理解する、すなわち、自然時間の概念を必要としててしまうのは明らかである。

---

>コンピュータは考え得る限りの状況をテストしてから製品となり、日時を扱うシステムなら「2100年に2月29日はあるか」という処理までチェックするものです。
<略>
プログラミングとは、その時点において考え得るすべてを洗い出し、対応できることは対応し、将来、予想されることに備えておくものです。

**コンピュータは考え得る限りの状況をテスト**とする点がポイントになる。これはすなわち、**テスターが想定していない使い方はテストできない**ことになる。

例えば、電化製品の場合、想定している寿命は長くても15年でしょう。それなのに、2100年が設定できるかどうかをテストしたならば、**テスターが本体製品仕様で想定されない無駄なことをしている**といわざるを得ない。

日本国内におけるJSTをいじくるレベルでのサマータイム対応は、おそらくここ数年間で予見できた人間はいないのではないか。あらかじめ計画されたものではないことも考えると、いないと考えることに無理はない。

想定できない問題に対して、事前に想定しろということは、無理難題になってしまう[^1][^2] 。

----
>サマータイムも同じく、「サマータイム」のフラグが立っていれば、サマータイムの開始日時を参照し、その切り換え日ならば、必要な時間調整をするというだけのもの。プログラミング初心者でもできる程度の処理です。

これ「日時」を表示させるだけのプログラムならばともかく、現実的には自然時間の入出力や計算が入ると、単純な問題にはならない。

例えば、時間が連続的でなくなる点について、どのようにユーザーへ表現すべきか、などの実際に起こりうるケースが十分考慮できていない。この場合、データ欠損と誤解されないためにはその部分を飛ばすなど、また新たな処理を追加せざるをえない。

プログラミング初心者レベルの単純な「おもちゃ」であれば、おそらくそこまで難しいプログラムにはならない。だが、現実に存在する「システム」を考えると、単純な問題であると結論付けるのは難しい。

---
# 所感
「無理にコンピュータのシステムを成さずとも、人力でやれば対応できる」という主張は読み取れた。

すべてのものを対応せずとも、人の柔軟性を生かせば必要コストは削減できる、という主張は理解できる。

しかしながら、基本的に想像や予想に基づいた記載内容が多い。また、技術的裏付けが乏しい、あるいは、誤解を招く表現に見える部分も少なくない。そのため、これらの事象は本文章の主張の裏付けになっていない。

現場において、具体的な課題は何か確認したうえで、主張を訴えるに値する根拠があるか、再考することを提案したい。

---
[^1]: 例えば、MS-DOS時代に、マルチコアでハイパースレッティングで64bitでGPU内蔵の、AVX対応CPUの対応が検討できるだろうか？ありとあらゆる拡張性を考慮したうえで設計・実装を行うと開発コスト、生産コストが膨大になる点も一考するべきである。
[^2]: **time_t が32bitだったり！ offset_t が signed intだったり！！ char がARMとx86でsigned だったり unsigned だったり！！！UTF-8が1文字表現するのに最大6byte必要だったり！！！！** 最初からわかってないことのほうが多いです。
Kibana6.2でindex patternとしてエイリアスを使用する

公式の[issue](https://github.com/elastic/kibana/issues/16705)にもありますが、kibana6.2.xだとindex patternとしてエイリアスを利用できません。古いバージョンだったら利用できたのに...

6.3.xでは利用できるようになりましたが、運悪くこのバージョンに当たった場合はDev Toolsから直接指定して回避できます。

```
PUT .kibana/doc/index-pattern:<エイリアス名>
{
    "index-pattern": {
      "title": "<エイリアス名>"
    },
    "type": "index-pattern"
}
```

index patternを一度も作ったことのない状態で↑をやってしまうとkibanaの動作がおかしくなるので注意。

その場合 .kibana indexをDELETEすると良いです。
Vue.js 開発環境構築

Vue.jsの開発環境を構築したときのメモです。

#### 環境・バージョン

* Windows 10
* Vue.js 2.5.17

#### ビルドツール

公式のツールである [Vue CLI 3](https://cli.vuejs.org/) で開発用アプリケーション起動からリリース用ビルドまでできる。

##### インストール

```shell
# vue-cli (1.x or 2.x) がインストールされている場合はアンインストールする。
npm uninstall vue-cli -g
npm install -g @vue/cli
```

##### 使い方

```shell
# プロジェクトの新規作成
vue create {プロジェクト名}
# 対話形式で利用するプラグインを指定する。
```

```shell
# 開発用にアプリケーションを起動する。
npm run serve
# リリース用にアプリケーションをビルドする。
npm run build
# Lintを実行する。
npm run lint
```

##### 参考

* https://jp.vuejs.org/v2/guide/installation.html
* https://cli.vuejs.org/guide/installation.html

#### エディタ

IDEでワンストップ開発・有償ライセンスを用意できる場合は [WebStorm](https://pleiades.io/help/webstorm/vue-js.html)、オープンソース系でやりたい場合は Visual Studio Code + [Vetur](https://vuejs.github.io/vetur/) が人気がある。私の場合は開発環境が非力で Vetur がもっさりしていたので Vim + [vim-vue](https://github.com/posva/vim-vue) を使っている。

##### 参考

* https://www.reddit.com/r/vuejs/comments/864s79/best_ide_for_vuejs/
* https://github.com/vuejs/awesome-vue#source-code-editing

#### デバッガ

[vue-devtools](https://github.com/vuejs/vue-devtools) でコンポーネントの状態やVuexで管理されている状態、イベントの監視などができる。スタンドアロンアプリケーション（Electron製）の他にChromeもしくはFirefoxプラグイン（ベータ版）が提供されている。
ターミナルのPATH設定をミスってコマンドが使えなくなったときにしたこと

ターミナルのPATH設定をミスって、ほとんどのコマンドが「command not found」となってしまったので、解決策をメモ。。。

```bash
# PATHを設定し直す
vi .bashrc
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/loacl/bin:/usr/local/sbin:/home/hoge/bin

# 反映確認
echo $PATH

# 設定を反映
source .bashrc
```
dockerでjenkinsを立てる+その中でDockerを走らせる(docker in docker)


## docker-compose.ymlファイル

```jenkins-docker-compose.yml
version: '2'

services:
  jenkins:
    image: 'jenkins:2.60.3'
    container_name: jenkins
    user: root
    restart: always
    ports:
      - '8080:8080'
      - '50000:50000'
    volumes:
      - ./data/jenkins:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
```

ポイント：
1. volumeでdocker.sockをhost(どっかーを動かすマシン)と共有することで、立ち上げたDockerの中でもDockerを使えるようになる。（が、Dockerの中からでも、立ち上げたContainerを削除できてしまうので、注意が必要）
2. `/var/jenkins_home`はdockerイメージが読む場所なので、変えてはいけない。Host側の`/data/jenkins`は好きな場所にしてよい。こうすることで、Docker自体が死んでも、Dataは残っているので、もう一回立ち直せば、同じ状態に復元できる。

## JenkinsをDockerで立ち上げる


```
docker-compose -f jenkins-docker-compose.yml up
```

これで、localの場合は、`http://0.0.0.0:8080`でJenkinsにアクセスできる。


## Jenkins内でDockerを使う

jenkins のbuild shellの中で以下を書くと

```
docker --version
docker run --rm hello-world
```

ちゃんとHelloworldが出来てることがわかる。

```
+ docker run --rm hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
9db2ca6ccae0: Pulling fs layer
9db2ca6ccae0: Verifying Checksum
9db2ca6ccae0: Download complete
9db2ca6ccae0: Pull complete
Digest: sha256:4b8ff392a12ed9ea17784bd3c9a8b1fa3299cac44aca35a85c90c5e3c7afacdc
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
```

## DockerでJeninsを立てた時にJenkins内でVolumeを共有できない場合の対応　後から更新(2018/08/28)

Dockerで立てたJenkins内にMountしたVolumeをそのまま,jenkinsから立てるDocker container内でmountできない。

hostの./data/jenkins -> jenkins containerの /var/jenkins_homeにマウントしているが、

Jenkins内のプロジェクトをdocker-composeで管理している時に、そこから別のプロジェクトのDirをマウントしたいときが出てくる(かも)

その時に、

1. jenkins上でrepoを持ってくる
2. 持ってきたrepoを新しいcontainerにMountする

をやろうとすると、そもそも1のJenkinsのworkspaceはホストにmountされた部分なので(なのでなのかわからないが)、あるコンテナ内のdirを別のコンテナにマウントすることになり、これはできない模様。（同じマウントオプションにするには、`volumes_from`というオプションがある）

そこで仕方ないので、jenkinsがマウントしているHost上でのPathに実態があるので、それを新しく作るcontainerのdocker-compose.ymlに書いて解決した。

hostの`./data/jenkins`の絶対パス。今回は、`/home/ubuntu/docker-compose/data/jenkins`は、自分で変更する必要がある！`/home/ubuntu/docker-compose/`の下で、jenkinsの`docker-compose.yml`を動かしたとして。

```yml:内側で動かすdocker-compose.yml

services:
  my_container:
    ...
    volumes:
      - "/home/ubuntu/docker-compose/data/jenkins/workspace/<別のjenkins jobのrepo>:/another_repo"
      - "/home/ubuntu/docker-compose/data/jenkins/workspace/my_repo/<repo内で引っ張ってきたrepo>:/cloned_repo"

...
```




参考

1. https://stackoverflow.com/questions/49312100/docker-in-docker-volumes-not-working-full-of-files-in-1st-level-container-em

2. https://damnhandy.com/2016/03/06/creating-containerized-build-environments-with-the-jenkins-pipeline-plugin-and-docker-well-almost/

3. https://github.com/jenkinsci/mesos-plugin/issues/159
simple_format にインデントをつけたい

#やりたいこと
ruby on railsのデータベースの文章を表示すると、改行が反映されないので、simple_formatを使えば、上手くいくが、その後、表示された文章の文頭を少し下げて表示したくなった。つまり、データベースの文章をインデントをつけて文章を表示させたいということである。

##before

```
  <%= simple_format(@user.comment_1) %>
  <%= simple_format(@user.comment_2) %>
```
文字列の入った変数をsimple_formatの引数に取って、改行はするようになったが、このままでは文頭のインデントが表示できていない。


#解決策
なんとかいい方法はないか、「simple_format　インデント」でwebを検索したが見つからず。そのため、以下のような解決策を考え、上手くいった。


```
  <%= simple_format("&nbsp;&nbsp;" + @user.comment_1) %>
  <%= simple_format("&nbsp;&nbsp;" + @user.comment_2) %>
```

スペースを増やしたい場合は、&nbsp;の数を増やせばよい。
[Java]トランザクションをネストした場合に必要なコネクションの数

# トランザクションのネスト数＝必要なコネクション数だっけ？？？

マルチスレッドなバッチ処理のコネクションプールのプールサイズを見積もった際、トランザクションのネストが発生するので **当然ネストする分のコネクションも必要** ということで、`スレッド数` × `トランザクションのネスト数` でプールサイズを設定しました。

あとになって、「ほんとにそう（ネスト分も必要）だっけ？」と自分の中の **当たり前** に漠然とした不安を覚え、ググってみても **そのものズバリの回答にたどり着けなかった** ので、サンプルコードを組んで確認することにしました。

## 結論

いきなり身も蓋もないですが、
　`トランザクションのネスト数＝必要なコネクション数`
でした。

ということで、結果だけを知りたかった場合は、以下はスルーして構いません。

## 検証環境

* Oracle JDK 8 u161
* spring-boot 1.4.3
* Tomcat JDBC Connection Pool 8.5.6

## サンプルコード（抜粋）

```application.properties
# ConnectionPool
spring.datasource.tomcat.maxActive=1
spring.datasource.tomcat.maxIdle=1
spring.datasource.tomcat.minIdle=0
spring.datasource.tomcat.initialSize=0
```
```java:App.java
@SpringBootApplication
public class App {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(App.class, args);
        Main bean = context.getBean(Main.class);
        bean.doNestedTransaction();
    }

}
```
```java:Main.java
@Component
public class Main {

    @Autowired
    private MainTarnsaction mainTransaction;

    public void doNestedTransaction() {
        mainTransaction.beginTransaction();
    }

}
```
```java:MainTarnsaction.java
@Component
public class MainTarnsaction {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private NestedTransaction nestedTransaction;

    @Transactional
    public void beginTransaction() {
        jdbcTemplate.execute("update Hoge set val = 'aaa' where id = '1'");
        nestedTransaction.beginTransaction();
    }

}
```
```java:NestedTransaction.java
@Component
public class NestedTarnsaction {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void beginTransaction() {
        jdbcTemplate.execute("update Hoge set val = 'bbb' where id = '2'");
    }

}
```

## 実行結果

(1) プールサイズを `1` （`spring.datasource.tomcat.maxActive=1`）に設定して実行した場合

```
org.springframework.transaction.CannnotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is org.apache.tomcat.jdbc.pool.PoolExhaustedException: [main] Timeout: Pool empty. Unable to fetch a connection in 30 seconds. none available[size:1; busy:1; idel:0; lastwait:30000].
...
at xxx.NestedTransaction$$EnhancerBySpringCGLib$$xxx.beginTransaction(<generated>)
...
at xxx.MainTransaction$$EnhancerBySpringCGLib$$xxx.beginTransaction(<generated>)
at xxx.Main.doNestedTransaction(Main.java:xx)
...
```

上記の通り、ネスト側のトランザクションのためのコネクションをプールから割り当ることができず、例外が発生しました。

(2) プールサイズを `2` （`spring.datasource.tomcat.maxActive=2`）に設定して実行した場合

（予想通りですが）正常終了しました。

## おわりに

自分の中のモヤモヤはこれでスッキリしました。
同じ疑問にぶつかった人の参考になれば幸いです。
fastlaneでXCTestを実行してコードカバレッジレポートを取得する【iOSアプリ】

fastlane でXCTestを実行した時に、[slather](https://github.com/SlatherOrg/slather)を使ってこんな風なコードカバレッジのレポートを取得する方法です。

サマリー

![サマリー](https://qiita-image-store.s3.amazonaws.com/0/95528/42ca368d-8eb0-f011-5879-e4beddc20ebc.png)

詳細一部(上記サマリーでFileを選択してクリック)

![詳細](https://qiita-image-store.s3.amazonaws.com/0/95528/182230b7-c8c4-c44a-7465-fafc7542b5c7.png)

# 設定方法

## 前提

- XCTest用のテストコードは作成済み
- fastlaneはインストール済み

## "Gather coverage data"を有効にする

Xcodeで、Edit scheme... > Test > Gather coverage data にチェックを入れて有効にする

## slatherのインストール

fastlaneをインストールしただけだと、slatherはインストールされないのでインストールします。ターミナルで下記コマンドを実行。

```
gem install slather
```

## Fastfileにslatherのアクションを追加する

最低限の定義例は次の通りです。scheme, projは対象のプロジェクトに合わせて変更してください。

```Fastfile
default_platform(:ios)

platform :ios do

  desc "run test"
  lane :tests do
    run_tests(
      scheme: "samplebot",
      code_coverage: true,
      clean: true
    )
    slather(
      proj: "samplebot.xcodeproj",
      scheme: "samplebot",
      html: true
    )
  end

end
```

XCTestを実行するrun_testsアクションで、コードカバレッジを生成するためにcode_coverageをtrueに設定。slatherアクションで、カバレッジレポートをHTMLに出力するために、**htmlをtrueに設定**。

## テストを実行

Fastfileの定義した、testsを実行します。プロジェクトフォルダでターミナルから下記コマンドを実行。

```
fastlane tests
```

## 実行後

正しく実行できれば、レポート結果がhtmlフォルダに出力されます。index.htmlがサマリーです。

# 参考

この辺りを参考に。

- [CircleCI 2.0 + fastlane + Slather でコードカバレッジの変化を Slack に通知する](https://tech.recruit-mp.co.jp/mobile/post-15290/)
- [XCTestでカバレッジを確認する] (https://qiita.com/okuderap/items/de574685592fe0bee8ea)
- [slather](https://docs.fastlane.tools/actions/slather/)

slatherを試してサマリーしか見られないかと思いきや、htmlをtrueにするだけでレポートができました。
AWS Cloud9で作ったGo言語のプログラムをLambdaにアップロードする方法

メモです。
メモなので、ほぼ字です。


# 事前準備
- 先にGo1.xのランタイムのLambdaを作っておく
    - CLIでもManagement Consoleでもどちらでも可
    - AWS Cloud9の「Create serverless application」では、Go言語のランタイムは選択不可なので
- ソースは[File]->[New From Template]->[Go File]で雛形を作成可能
- 2018/08/14(JST)現在のCloud9上のGoのバージョンは以下

```bash:
$ go version
go version go1.9.1 linux/amd64
```

# Lambda向け実装
こちらは、[AWS Lambda で Go が使えるようになったので試してみた](https://dev.classmethod.jp/cloud/aws/aws-lambda-supports-go/)を参考している

- 以下ターミナル上で、コマンドでパッケージをインストール
    - ターミナルは[Window]->[New Terminal]で開く

```bash:
go get -u github.com/aws/aws-lambda-go/lambda
```

- パッケージをインポート

```golang
import "github.com/aws/aws-lambda-go/lambda"
```
- main()内で処理を行う関数ハンドラを呼び出す

```golang
lambda.Start(helloLambda)
```

# ビルド＆アップロード
- LambdaのコンテナはLinux(AmazonLinux？)と思われるので、Linux向けにビルド
- 以下全てターミナル上での作業

```bash:
GOOS=linux GOARCH=amd64 go build -o Lambdaのハンドラ名
```

- Zip圧縮

```bash:
zip zipファイル名 ビルド済み実行ファイル（Lambdaのハンドラ名）
```

- アップロード

```bash:
aws lambda update-function-code --function-name [Lambda関数名] --zip-file fileb://[作ったファイル名]　 [--region ap-northeast-1]
```
--region オプションは東京リージョンなど、AWS Cloud９が展開されていないリージョンのLambdaにアップロードする場合は必須

- 以下のようなレスポンスが返ってくればOK

```bash:
{
    "TracingConfig": {
        "Mode": "PassThrough"
    }, 
    "CodeSha256": xxxxxxxxxxxxxxxxxxxxxxxxxxxxx, 
    "FunctionName": [Lambda関数名], 
    "VpcConfig": {
        "SubnetIds": [], 
        "VpcId": "", 
        "SecurityGroupIds": []
    }, 
    "MemorySize": 128, 
    "FunctionArn": [Lambda関数のロール], 
    "Version": "$LATEST", 
    "Role": [Lambda関数のロール], 
    "Timeout": 4, 
    "LastModified": "2018-08-13T11:05:43.413+0000", 
    "Handler": [ハンドラ名], 
    "Runtime": "go1.x", 
    "CodeSize": xxxxxxx, 
    "Description": ""
}
```

あとは、テスト実行するなり、API越しに叩くなり。。。

# 参考
[AWS Lambda で Go が使えるようになったので試してみた](https://dev.classmethod.jp/cloud/aws/aws-lambda-supports-go/)
MacBook ProのRetinaディスプレイでパリッとした疑似「高」解像度を得るには

MacBook Pro 13" をデスクトップ画面広めで作業したいときはDisplay MenuやEasyResなどの解像度変更アプリをインストールすることで1920x1200以上の解像度を得られます。2560x1600ならばdot by dotでくっきりですが自分には文字などが少し小さいので眼が疲れます。2560x1600以下の解像度だと標準(1x)のスケーリングが働いてぼやけてどうにも眠たいです。これをパリッさせるべくHiDPIモード(2x)の好みの解像度を追加します。サポートされていない解像度なので自己責任で。

#SIPを無効
詳細は割愛します。設定ファイルの書き換え作業が終わったら有効に戻しましょう。

```shell-session
# csrutil enable --without fs
```

#Display IDの確認
編集対象の設定ファイルを知るためにDisplay IDを調べます。Macbook Pro 13" 2018はこんな感じです。

```shell-session
$ ioreg -lw0 | grep DisplayVendorID
    | |   | | |       "DisplayVendorID" = 1552
$ ioreg -lw0 | grep DisplayProductID
    | |   | | |       "DisplayProductID" = 41022
```
16進数にします。

```shell-session
$ printf '%x %x\n' 1552 41022
610 a03e
```

#疑似解像度を追加
先程の16進数をたよりに編集するファイルを探しあてます。

```shell-session
$ cd /System/Library/Displays/Contents/Resources/Overrides/DisplayVendorID-610/
$ sudo cp -a DisplayProductID-a03e{,.bak}
$ sudo vi DisplayProductID-a03e
```
自分が追加した解像度はこれ。

```xml

        <key>scale-resolutions</key>
        <array>
                <data>AAASAAAAC0AA</data>        <!-- 2304x1440(HiDPI) -->
                <data>AAAQAAAACgAA</data>        <!-- 2048x1280(HiDPI) -->
                <data>AAAPAAAACWAA</data>        <!-- 1920x1200(HiDPI) -->
                <data>AAANIAAACDQA</data>
                <data>AAALQAAABwgA</data>
                <data>AAAKAAAABkAA</data>
                <data>AAAIAAAABQAA</data>
                <data>AAAKAAAABkAAAAABACAAAA==</data>
                <data>AAAKAAAABaAAAAABACAAAA==</data>
```

あとはOSを再起動すれば解像度変更アプリで追加した項目が選択できます。

また上記のように1920x1200(HiDPI)を追加すると System Preferences -> Displays -> More Space がそれになります。Larger Textなどの他の項目も15インチモデルと同じ設定になります。

<img width="780" alt="Screen Shot 2018-08-14 at 19.18.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/71559/1eb6121d-0b59-55ee-2bda-03006d9fd206.png">

||変更前|変更後|
|:--:|:--:|:--:|
|Larger Text|1024 x 640|1280 x 800|
|Default|1280 x 800|1440 x 900|
||1440 x 900|1680 x 1050|
|More Space|1680 x 1050|1920 x 1200| 

今現在の解像度を確認するコマンドは

```shell-session
$ osascript -e 'tell application "Finder" to get bounds of window of desktop'
0, 0, 1920, 1200
```

# HiDPIな疑似解像度のデータを得る
設定ファイルで用いる解像度のデータを得るには16進ダンプしたものをBASE64に変換します。HiDPIモードは縦横の数値をそれぞれ2倍します。

```shell-session
$ printf '%08x%08x00\n' $((2304*2)) $((1440*2)) | xxd -r -p | base64
AAASAAAAC0AA
```
2016年より前のMacだとこっちかもしれません。

```shell-session
$ printf '%08x%08x00000001\n' $((2304*2)) $((1440*2)) | xxd -r -p | base64
AAASAAAAC0AAAAAB
```

#参考
[Enabling 1920 x 1200 HiDPI Resolution on the 13" Retina MacBook Pro](https://www.reddit.com/r/apple/comments/2ia242/enabling_1920_x_1200_hidpi_resolution_on_the_13/)
[HOWTO: 2880x1800 Without Scaling in OS X](https://forums.macrumors.com/threads/howto-2880x1800-without-scaling-in-os-x.1387363/page-2#post-15052764)
UnityのWebSocket-Sharpを使用する際、error CS0246になる場合。

Unityでwebsocketを使用する方法は、多くの記事に書かれています。
[UnityでWebSocketを使用する](https://qiita.com/oishihiroaki/items/bb2977c72052f5dd5bd9)
などの記事をご参照ください。
本記事ではMonoDevelopでなくVisualStudioを使用しております。

多くの記事ではwebsocket-sharpを使用していますが、C#でサーバーやクライアントの処理を書いた際にUnity側で`error CS0246: The type or namespace WebSocketSharp could not found. Are you missing an assembly reference?`というエラーが出ることがあります。その時の対処法についてです。
***
##エラーメッセージ
1. UnityのConsoleで`error CS0246: The type or namespace WebSocketSharp could not found. Are you missing an assembly reference?`や`error CS0246: The type or namespace WebSocket could not found. Are you missing an assembly reference?`がでる。

2. Assets配下、もしくはAssets/Plugins配下にあるwebsocket.sharpファイル（これは`websocket-sharp/bin/Release/websocket-sharp.dll`ファイルをUnityにインポートしたファイルです）をInspectorで見た際、`Plugin targets .NET 4.x and is marked as compatible with Editor, Editor can only use assemblies targeting .NET 3.5 or lower, please unselect Editor as compatible platform`がでる。

##解決法
エラーの原因は.NETのバージョンが異なっていることです。どうやら.NET 4.x と.NET 3.5以下は全く別の種類らしく、websocket-sharpでは.NET 3.5以下を使用する必要があるそうです。そこでもう一度dllファイルを.NET 3.5形式で作り直します。

1. GitHubからもう一度websocket-sharpをダウンロードし、解凍。
2. websocket-sharp-master配下のwebsocket-sharp.slnを開く、その後いくつかのポップアップメッセージの後に 、`ターゲットを .NET Framework 4.5 に変更する。`、`.NET Framework <バージョン> のターゲット パックをダウンロードします。プロジェクトは変更されません。`、`プロジェクトをロードしない。`の3つの選択肢が出てくると思います。その時に`.NET Framework <バージョン> のターゲット パックをダウンロードします。プロジェクトは変更されません。`を選択します。
3. 検索エンジンが開き、.NETのページが開くと思います。その場所で**.NET Framework 3.5 SP1**を選択し、ダウンロードします。このダウンロードには少し時間がかかります。
4. .NET 3.5がダウンロードできたら、もう一度websocket-sharp.slnを開きます。するとそのままポップアップメッセージがでることなく開けると思うので、ソリューションエクスプローラーからExample系4つを削除し、Releaseモードにしてデバッグを行います。
5. `websocket-sharp/bin/Release/websocket-sharp.dll`ができると思うので、そのファイルをUnityのAssets配下もしくはAssets/Plugins配下にインポートします。そうすると問題なくUnityで実行できるようになるはずです。
LINEAPIとGASを使って遊んでみた2

# Weblio中国語検索君

## 説明
[Weblio中国語](https://cjjc.weblio.jp/)を使用したLINEBotです。

## 使い方
１：LINEで文字を入力して送信します。
２：LINEに入力したキーワードを、[Weblio中国語](https://cjjc.weblio.jp/)で検索した結果が返ってきます。

## コード
```中国語辞書君.gs
var PROPERTIES = PropertiesService.getScriptProperties();

var LINE_ACCESS_TOKEN = PROPERTIES.getProperty('LINE_ACCESS_TOKEN')
var LINE_END_POINT = "https://api.line.me/v2/bot/message/reply"
var reply_token;
var query;

function doPost(e){
if (typeof e === "undefined"){
 reply_token = ""
 query = "本"
} else{
    var json = JSON.parse(e.postData.contents);
    reply_token= json.events[0].replyToken;
    //送られたLINEメッセージを取得
    query = json.events[0].message.text;
  }
　　Logger.log("検索キーワード"+query);
 postBookToLine(query);
}

function postBookToLine(query){
var messages = [{
 "type": "text",
 "text": "https://cjjc.weblio.jp/content/" + query
}];
Logger.log(messages)
UrlFetchApp.fetch(LINE_END_POINT, {
 'headers': {
   'Content-Type': 'application/json; charset=UTF-8',
   'Authorization': 'Bearer ' + LINE_ACCESS_TOKEN,
 },
 'method': 'post',
 'payload': JSON.stringify({
   'replyToken': reply_token,
   'messages': messages,
 }),
});   
}
```
Vector

vector型とは
c++で配列の長さを変えることができる配列を扱うためのクラス
また、この長さを変えることができる配列のことを可変長配列という
vectorをincludeするためにはvectorというライブラリをincludeする。
vectorは以下のように宣言する
vector<型名>変数名;
要素を先に確保して、さらに全ての要素を同じ値で初期化したい時は
vector<型名>変数名(要素数);
vector<型名>変数名(要素数,値);

c++11以降は配列のように直接値を入れることができる
vector<型名>変数名={要素1,要素2};
また、vectorで二次元以上の配列を宣言するには
vector<vector<型名>>変数名;

 int ar[] = {1, 2, 3, 4, 5, 6, 7};
    vector<int> v{9, 8};
    v.assign(&ar[0], &ar[3]);        // v の内容は {1, 2, 3} になる

 vector<int> v{9, 8};
    v.assign(3, 1);    //  v の内容は {1, 1, 1} になる

 const int SZ = 10;          // 要素数
    std::vector<int>v(SZ);        // 指定要素数で、vector を生成
    for(int i = 0; i < SZ; ++i)
        v[i] = i;             // 要素を 0, 1, 2, 3, ... 9 に設定

 const int SZ = 10;          // 要素数
    std::vector<int>v(SZ);        // 指定要素数で、vector を生成
    for(int i = 0; i < SZ; ++i)
        v.at(i) = i;             // 要素を 0, 1, 2, 3, ... 9 に設定

std::vector<int> v{1, 2, 3, 4};
    std::vector<int>::iterator itr = v.begin();   // 最初の要素を指すイテレータ
    std::cout << *itr << "\n";      // 最初の要素の値を表示
    ++itr;   // 次の要素に移動
    *itr = 9;    // 二番めの要素の値を 9 に変更

std::vector<int> v(100);
    for(int i = 0; i < 100; ++i)
        v[i] = rand() % 100;

初期値 0 で、10個の int型 vector オブジェクトを生成し、[5] の位置に 7 を挿入するコードを書きなさい

std::vector<int> v(10, 0);
    v.insert(v.begin() + 5, 7);

std::vector<int> v{3, 1, 4, 1, 5};
    v.pop_back();    //  末尾データ（この場合は 5）を削除

std::vector<int> v{3, 1, 4, 1, 5};
    int last = v.back();     // 末尾データを取り出しておく
    v.pop_back();            //  末尾データ（この場合は 5）を削除

 std::vector<int> v, z;
    v, z にデータを追加
    v.swap(z);     // v と z の内容を入れ替える

 std::vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    std::cout << std::count(v.begin(), v.end(), 5) << "\n";    //  要素5の数を返す

#include <numeric>
.....
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::cout << std::accumulate(v.begin(), v.end(), 0) << "\n";
↑最初から最後まで要素を全加算最後の０は初期値で通常は０

#include <algorithm>
.....
    std::vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    std::sort(v.begin(), v.end());
↑まあ普通のソート

std::vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    std::reverse(v.begin(), v.end());       // 順序反転
    for(auto x : v ) std::cout << x << " ";
    std::cout << "\n";
↑要素の順番を逆にする
Watson Studioで自動運転に必要な画像処理技術を学ぶ（３）の後半

自動運転に必要な画像処理技術シリーズの3回目の後半。[前半](https://qiita.com/schiyoda/items/c339ca1e59949f3f72f4)で作成したモデルを使って、道路標識を認識するアプリを作成します。

# 手順
## モデルのデプロイ
[前半](https://qiita.com/schiyoda/items/c339ca1e59949f3f72f4)で作成したモデルの Actions メニューから Save model を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/e1204041-1f73-5463-05f6-dbc5aaae2c9e.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/038acebb-bb30-9c95-66f5-d2d5746b7acc.png)

プロジェクトのページに戻ると Watson Machine Learning models にモデルが保管されたことが分かるので、モデル名をクリックします。

Deployments タブから Add Deployment をクリックし、適当な名前をつけてSave します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/462cc067-ad11-a203-07a0-d54e87e39e92.png)

STATUS が DEPLOY_SUCCESS となったらデプロイ完了です。

デプロイすると、モデルを呼び出すための Scoring End Point やアプリ作成に使えるコードが生成されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/2c9d2ae6-bd55-3ac6-0fe0-8e91bc678b0c.png)

# アプリの作成
以下に作成したサンプルアプリを公開しています。
https://github.com/schiyoda/TrafficSignRecognition

以下の手順で実行可能です。

1.コードの取得

```
$ git clone https://github.com/schiyoda/TrafficSignRecognition.git
$ npm install
```

2.server/routers/main.js で Scoring Endpoint および WML の Credential を設定

3.起動

```
$ npm start
```

こちらが作成したアプリになります。
http://trafficsignrecognition.mybluemix.net/

![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/6fd605e2-5d45-b1cd-2eb5-052570c9057e.png)

アプリで使用している標識画像は学習時には使用しなかった「Test datasetを[こちら](http://benchmark.ini.rub.de/?section=gtsrb&subsection=dataset)から取得しました。

いくつか試してみると、そこそこ良い結果なのではないかと思います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/9cb79f67-8dde-4b50-ed80-25569dd3dde8.png)
SharePoint でアイテムをダイアログボックス(ポップアップ)で表示する

#はじめに
今更ですが、カスタムリストのアイテムをダイアログボックス(ポップアップ)で表示する方法をまとめます。
今回はSharePoint Online のクラシック表示で行います。
#手順
######⓪フォームがページ全体に表示されます。
![スクリーンショット 2018-08-14 19.25.29.png](https://qiita-image-store.s3.amazonaws.com/0/276299/f1d09242-2c95-102a-dde3-dfcb7a759c76.png)

######①カスタムリストにアクセスし、[リストの設定]をクリックします。
![スクリーンショット 2018-08-14 18.28.25.png](https://qiita-image-store.s3.amazonaws.com/0/276299/0449b6c0-adaa-a0e8-5763-f584f85ee515.png)

######②[詳細設定]をクリックします。
![スクリーンショット 2018-08-14 19.03.17.png](https://qiita-image-store.s3.amazonaws.com/0/276299/3af3458b-0068-a016-91c3-5e653ee5d1da.png)

######③[ダイアログ ボックス]で[はい]選択し、画面下の[OK]をクリックします。
![スクリーンショット 2018-08-14 19.15.34.png](https://qiita-image-store.s3.amazonaws.com/0/276299/3821160e-7644-16a3-5d7b-1d63f3ac7ea2.png)

######④アイテムがダイアログ ボックスで表示されます。
![スクリーンショット 2018-08-14 19.20.52.png](https://qiita-image-store.s3.amazonaws.com/0/276299/675a6f0e-098f-4092-ad77-b16ad3a51c5f.png)
FlutterでStatefulWidgetではなくStateにbuild()がある理由

## はじめに
「[なぜ`StatefulWidget`ではなく`State`が`build`メソッドを持っているのか - Qiita](https://qiita.com/yshrsmz@github/items/4c7e6e1daa3762c0f43e "なぜStatefulWidgetではなくStateがbuildメソッドを持っているのか - Qiita")」によると、`StatefulWidget`に`build()`を持たせると、①`build()`内のクロージャが、`StatefulWidget`の再`build()`後も古い`StatefulWidget`のインスタンスを参照するthisをキャプチャしてしまうから、②Stateを無用に子クラスに公開しないといけないから、だそうです。このあたりは、「[FAQ - Flutter: Why is the build() method on State, not StatefulWidget?](https://flutter.io/faq/#why-is-the-build-method-on-state-not-statefulwidget "FAQ - Flutter")」と、そこから参照する「[build method - State class - widgets library - Dart API](https://docs.flutter.io/flutter/widgets/State/build.html "build method - State class - widgets library - Dart API")」に記載されています。

本ブログでは再描画の範囲限定の観点で見ていきます。

## 想定
こんな`Widget`ツリーを考えます。
![FlutterのStetefulWidgetの意味.png](https://qiita-image-store.s3.amazonaws.com/0/37980/3bc54826-3cab-41df-c33e-1c54a775ea6c.png)

## 考察
再描画のパフォーマンスを考えると、無闇に`StatefulWidget`にすべきではなく、また、`State`はなるべく下位のサブツリーに限定すべきとのことです。裏を返すと`State`更新時に`StatefulWidget`を頂点とするサブツリーは全体が再描画(再`build()`)される(可能性がある)ことを意味します。

このあたりは、「[StatefulWidget class - widgets library - Dart API](https://docs.flutter.io/flutter/widgets/StatefulWidget-class.html "StatefulWidget class - widgets library - Dart API")」で説明されています。

ここで、`Widget`同士のhas aの関係を改めて見ると、`State`でサブツリー(点線で囲んだ領域)に分断されていることがわかります。つまり、`State`が変更されても、`StatefulWidget`を持つ`Widget`ツリーの`build()`は(必ずしも)呼び出す必要が無く、その`State`が持つ`build()`チェーンを呼び出せば、良いということのようです。こうしてみると、とても合理的です。
【AWS】無料のサーバ証明書を公開鍵ピンニングする

AWSで発行した無料サーバー証明書を使って公開鍵ピンニングする時のメモです。

## 公開鍵ピンニング（HPKP）とは
アクセスしたWEBページが妥当なサーバ証明書を持っているか、不正に変更されていないかという確認を行うための仕組みです。2回目以降の接続時に、以前の接続の時にピン留めしたものとサーバ証明書が同じであるかを確認します。

逆に言えば間違った公開鍵情報をピンニングしてしまうと正しい証明書を持つサーバーにアクセスできなくなるので、挿入の際は慎重になる必要があります。

## 公開鍵ピンニングの実装

ACMで発行されるサーバーの証明書は比較的短期間で更新され、その時点で古い公開鍵をピンニングしていると上で述べたようにサーバーにアクセスできなくなります。そういった問題があるのでAWS公式でACMを利用して公開鍵ピンニングする場合は

- 自分で発行した証明書をACMにインポートする
- ピンニングするのは中間認証局以上のサーバ証明書にする

のいずれかの手段を取ることが推奨されています。
[Troubleshoot Certificate Pinning Problems - AWS Certificate Manager](https://docs.aws.amazon.com/acm/latest/userguide/troubleshooting-pinning.html)

ACMで完結させたいので、今回は後者の手法で進めます。

### 中間認証局やルート認証局のサーバ証明書を取得する

AWSの中間認証局やルート認証局の証明書は以下のページで見ることができますが、どれが自分の持っている証明書の親に当たるのかわかりにくいかと思います。
[Amazon Trust Services Repository](https://www.amazontrust.com/repository/)

ということで特定の証明書の先祖を全て辿るopensslコマンドのオプションがあるので、今回はそれを用います。

```bash
$ echo | openssl s_client -connect <domain_name>:443 -showcerts
```

`-showcerts`オプションで先祖を全て辿ってくれます。出力結果が

```bash
...
-----BEGIN CERTIFICATE-----
...
...
...
...
-----END CERTIFICATE-----
...
```

のようなブロックの繰り返しになるかと思います。下に行くにつれてルート認証局に近づきます。この`BEGIN CERTIFICATE`と`END CERTIFICATE`で囲われた部分が公開鍵で、これを`.pem`形式で保存します。

```bash:example.pem
-----BEGIN CERTIFICATE-----
...
...
...
...
-----END CERTIFICATE-----
```

### 証明書をBase64エンコードする
最後にヘッダーを付与するときに使用します。先ほどのpemファイルに対して

```bash
$ openssl x509 -in <先ほどのpemファイル> -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
```

として得られた結果の文字列をそれぞれ記録します。

### 最後にヘッダーを記述する
PHPであれば以下のように書くだけです。

```php
header('Public-Key-Pins: pin-sha256="<Base64エンコードされた中間認証局以上のサーバ証明書1>"; pin-sha256="<Base64エンコードされた中間認証局以上の証明書2>"; max-age=5184000; includeSubDomains; report-uri="<report_uri>"');
```

- `pin-sha256` Base64でエンコードされた証明書の公開鍵情報。保険で二つ書いておく。
- `max-age`で公開鍵をピン留めする期間を指定しする
- `includeSubDomains` サブドメインに関してもピンニングを行うか
- `report-uri` 改ざんを報告する送信先

先ほども述べたとおり、公開鍵情報が間違っていると`max-age`で指定した期間サイトにアクセスできなくなるので注意が必要です。

保険として二つの公開鍵情報を書く、`max-age`を短めにする、`Public-Key-Pins`ではなく`Public-Key-Pins-Report-Only`ヘッダーを用いるといった予防策がとれます。ただHPKPの意味上`max-age`は長い方が好ましいです。


## 参考
[HTTP Public Key Pinning (HPKP) - Web セキュリティ | MDN](https://developer.mozilla.org/ja/docs/Web/Security/Public_Key_Pinning)
[Troubleshoot Certificate Pinning Problems - AWS Certificate Manager](https://docs.aws.amazon.com/acm/latest/userguide/troubleshooting-pinning.html)
Seleniumでタグに囲まれた文字列を.textで取得すると空文字が返ってくる

# 背景
Webブラウザの自動操作をするために、タグで囲まれた文字列をtextメンバで取得しようとしたのですが、
下記の実装例のように実装すると、"TEXT1" という文字列が取得できず、空文字が返ってきました。
少しハマったので、文字列"TEXT1"を取得するための方法についてメモします。

# 環境
- Ubuntu 16.04
- Google Chrome 68
- ChromeDriver 2.41.578700
- Python 3.5.2 (恐らくPythonのversionは関係ない)

# 問題の実装例
```HTML:HTML
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Test</title>
</head>

<body>
    <div id="text1" style="display: none">TEXT1</div>
    <div id="text2">TEXT2</div>
</body>

</html>
```
```python:Python
from selenium import webdriver


driver = webdriver.Chrome("./chromedriver")
url = "呼び出したいURL"

driver.get(url)

text1 = driver.find_element_by_id("text1").text
text2 = driver.find_element_by_id("text2").text
print(text1)
print(text2)
```



```出力結果:出力結果


TEXT2
```
※ print(...)で出力しているので、"TEXT2"の上部は1行空行が入ります。

# 原因
```
<div id="text1" style="display: none">TEXT1</div>
```
のようなCSSプロパティがdisplay: noneのタグに対して、
```
text1 = driver.find_element_by_id("text1").text
```
のように.textで取得しようとすると、空文字が返ってくる仕様のようです。
他にも、CSSプロパティがvisibility: hiddenであっても同様の現象に遭遇します。
※ まだあるかも。

**[2018/08/16  追記]**

下記のような画面上に存在しないものは、「無いもの」として扱われるので、文字列は取得できないとのこと。
(@Luice さん、ご教授ありがとうございます。)
[コメント原文はこちら](https://qiita.com/riikunn1004/items/68c7621baaa54cf27230#comment-a0fa6951ba0dc49f9551)

-  display:noneやvisibility:hiddenで表示されていないもの
-  カルーセルで表示されていないもの
-  ブラウザのWindow表示枠の外にあるもの(スクロール可の場合は除く) のようにソース上は存在しているが、表示されていないもの


# 解決方法
```
text1 = driver.find_element_by_id("text1").get_attribute("textContent")
```
のように、 .get_attribute("textContent")に変えると解決しました。

# 検証例
```HTML:HTML
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Test</title>
</head>

<body>
    <div id="text1" style="display: none">TEXT1</div>
    <div id="text2">TEXT2</div>
    <div id="text3" style="visibility: hidden">TEXT3</div>
</body>

</html>
```

```python:python
from selenium import webdriver

driver = webdriver.Chrome("./chromedriver")
url = "呼び出したいURL"

driver.get(url)

text1 = driver.find_element_by_id("text1").text
text2 = driver.find_element_by_id("text2").text
text3 = driver.find_element_by_id("text3").text
print(text1)
print(text2)
print(text3)
print("---")
textcontent1 = driver.find_element_by_id("text1").get_attribute("textContent")
textcontent2 = driver.find_element_by_id("text2").get_attribute("textContent")
textcontent3 = driver.find_element_by_id("text3").get_attribute("textContent")
print(textcontent1)
print(textcontent2)
print(textcontent3)
```
```出力結果:出力結果


TEXT2

---
TEXT1
TEXT2
TEXT3
```
フレームワークは絶対に直接使うな

## はじめに

* フレームワークを直接継承して使わないで欲しいのでその警鐘
* 今回は例として`FuelPHP`を使います
* 使うと不都合がある一例なので直接継承した方が良いケースもあるかもしれません

## 問題のあるケース

* `FuelPHP`を入れる
* `user`モデルを`Orm\Model`を継承して作成

```php:user.php
class Model_User extends Orm\Model{
}
```

* `company`モデルを`Orm\Model`を継承して作成

```php:company.php
class Model_Company extends Orm\Model{
}
```

* `user`と`company`に共通のメソッドを持たせたくなった（例えばクエリログを仕込むなど）
* 親に持たせておけば今後増えるクラスにも自動で入るのでありがたいが親クラスはフレームワークなので触りたくない
* とはいえ`user`と`company`両方に同一のメソッドを生やすのは二重管理になるし、今後クラスが増えた時に同一メソッドを書く必要がある
* 詰んだ＼(^o^)／

## 要するに

フレームワークを直接継承すると中間層がなく、共通の親クラス＝フレームワークになってしまうので、共通処理を入れたくなった時に「フレームワークを修正する」という選択肢が出てきてしまう
なので必ずフレームワークと実際に使うクラスの間に中間の親クラスを設けるようにしましょう
この際中間クラスは空でも可です
空でも間に入っていることで後の拡張性が高いです

```bash
fuel/app/classes/model/
├── base.php
│   ├── company.php
│   └── user.php
```

## 経験則

これは個人的な意見ですが、DBを扱うモデルに関していえば更に以下のようにしておくと後々楽になるケースが多い気がします

```bash
fuel/app/classes/model/
├── base.php
│   ├── auth.php
│   │   ├── company.php
│   │   └── user.php
│   │
│   ├── master.php
│   │   ├── company_type.php
│   │   └── user_type.php
```

`auth.php`はログインしている企業・ユーザのみがアクセスすることができるテーブルの親で、データのアクセスに必ずログイン中のuser_idやcompany_idを必須とするような親クラスです
こうしておくことで意図せず他社・他人のデータをアクセスできてしまうような穴を構造で防ぐことができます
`master.php`はマスタデータを持つようなデータの親で、ログイン中の企業・ユーザーに関係なくアクセスできて良いようなデータに使います
例えば企業やユーザーのタイプや分類などのマスタが該当します
こうしておくことで例えばマスターデータをモデルではなく配列やjsonで返したい、1度データを取得したら2回目以降はキャッシュを参照したいなどのケースの時に親クラスに書けば済むようになります

## おわりに

ORMは特に中間層は絶対に作っておきましょう
クエリの根っこの部分になるので差し込みたい処理がたくさん出てくるはずです
その他コントローラーの根っこ、プレゼンターの根っこなど、必要になってから作成でもいいですが空でも設置しておくと後々楽になります
今回は`FuelPHP`を例に取り上げましたが他のフレームワークでも理屈は同様なので、クラス設計する際には是非中間層の導入の検討を:smile:
macOSにwine3.0とollydbg2.0をインストールする ー フォントとの戦い

#はじめに
.exeファイルの解析にはOllyDbgやexeを動かす環境がほしいので、wineを入れることにしました。
フォントの設定で四苦八苦中です。。(解決していない)

#環境
MacBook Air (11-inch, Early 2015)
macOS High Sierra バージョン 10.13.6

(本記事では以下をインストールします)
wine-3.0.2
winetricks/20180603
ollydbg 2.00


#インストール
## wineのインストール
`$ brew install wine`

メモ帳を起動したいなら
`$ wine notepad`

フォントが汚い。。

## wineのフォントをきれいにするための戦い
※まだうまくいってませんので注意*

フォントがいまいちすぎるので、きれいにします。

`$ brew cask install xquartz`
(wine 3.0でもまだ一部必要なようです。)

`$ brew install zenity`
    (winetricksのGUIアプリを表示するために入れます)

`$ brew install winetricks`
`$ winetricks allfonts`
(結構、時間がかかります)

~/.wine/dosdevices/c:/windows/Fonts/
の中にフォントがインストールされます。c:/以降はタブ補完できませんが、打つと表示されます。

これで `$ notepad` と打つと美麗なフォントで、、、、
表示されない。。

regeditで書き換えてみます。

HKEY_LOCAL_MACHINE -> Software -> Microsoft -> Windows NT -> CurrentVersion -> FontSubstitutes の中の"MS Shell Dlg"と"MS Shell Dlg 2"を「Hiragino Kaku Gothic Pro W6」とします。

![スクリーンショット 2018-08-14 20.38.44.png](https://qiita-image-store.s3.amazonaws.com/0/272771/8c49a2bf-ef04-bad9-cafb-ba01f672583a.png)

若干きれいになった気がします。。

`$ winetricks`
と打つとGUIが立ち上がり、いろいろ設定できそうです。

##OllyDbgのインストール
http://www.ollydbg.de/
から
左メニューにある、
http://www.ollydbg.de/odbg200.zip
をダウンロード、解凍します。

`$ wine ./ollydbg.exe`

ollydbgが起動します。

でもフォントが汚い。。

Options>Options>Appearance>Fonts
でFontを一つ一つ選び、「Change」で好きなフォントを設定していきます。
だいぶましな見た目になりました。

#感想
wineってだいぶ進化したんですね。

システムフォントはどうやればきれいになるんだろう。。

#参考

http://moebuntu.blog48.fc2.com/blog-entry-1138.html

https://htlsne.hatenablog.com/entry/2017/01/17/120802

http://www.nekochango.com/entry/linux/wine

[システムフォントの入れ替え](
http://yanor.net/wiki/?Windows%2F%E3%83%95%E3%82%A9%E3%83%B3%E3%83%88%2F%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%95%E3%82%A9%E3%83%B3%E3%83%88%E3%81%AE%E5%85%A5%E3%82%8C%E6%9B%BF%E3%81%88)
regeditでフォントを入れ替える話(native windowsで)
面倒でまだ試してない

https://mattintosh.blog.so-net.ne.jp/2012-08-02_wine_font-smoothing

#履歴
2018/08/14 初版
Go言語でSetLocalTime

## もくてき

Golangで時刻同期に関連するプログラムを作成している時に、コンピュータの時刻を変更したかったんですが、windows環境のsyscallにはどうやらSettimeofday()が無いようなんですね。
WindowsのAPI的にはSetLocalTime()とSetSystemTime()なのですが、そのどちらも実装されてなさげでした。

そもそもGettimeofday()の方はともかく、Settimeofday()をWindowsで使うなんて需要はあんまりないのかなぁ？と思いつつ、DLLから関数呼ぶ練習ということで、SetLocalTime()を実装してみました。

## 作ってみたもの

https://github.com/mako2kano/systime/tree/develop

## やったこと

"golang.org/x/sys/windows"をimportして、↓のように書いてあげるとAPIの情報を得られます。

``` Go
modkernel32       = windows.NewLazySystemDLL("kernel32.dll")
procSetLocalTime  = modkernel32.NewProc("SetLocalTime")
```

syscall.Syscall()にprocSetLocalTime.Addr()と、適切な引数を渡してあげると、APIを使えました。
この時の適切な引数は、MSDN等で調べて合わせてあげる必要があります。

``` Go
r0, _, e1 := syscall.Syscall(procSetLocalTime.Addr(), 1, uintptr(unsafe.Pointer(st)), 0, 0)
```

今回はSetLocalTime()なので、[SetLocalTime function (MSDN)](https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms724936.aspx)に書いてある通りの形で、引数は[SYSTEMTIME structure (MSDN)](https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms724950.aspx)と同じ形にしたものを渡してます。

## 参考にしたページ

今回は、[syscallのsource](https://github.com/golang/go/blob/master/src/syscall/zsyscall_windows.go)を参考にしました。
作り終えた後に気がついたのですが、*Code generated by 'go generate'; DO NOT EDIT.*って書いてあるんですよね(；´∀｀)

なので、私がやってみた方法は邪道もいいとこかもしれません。
【初心者向け】DiscordのBotを作る上で知っておくといいこと

discordがきっかけでBot作りに興味を持った初心者向けです。



## 文字列の引っ掛け方
サンプルのプログラムを見ると、

```python

import discord
import asyncio

client = discord.Client()

@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')

@client.event
async def on_message(message):
    if message.content.startswith("はろー"):
        m = "こんにちは、" + message.author.name + "さん"
        await client.send_message(message.channel,m)

client.run('token')
```

`    if message.content.startswith("はろー"):`

という形で、
message.content.startswith
というメソッドを使って条件分岐等をしていますが、

```py
print (message.content)
```
とやってみると、発言された内容（文字列）を取ることができるので、

```python

if re.match("やっほー", message.content):
```

といった形で引っ掛けられたりします。
なおこのre.matchを使う場合は、

```python
import discord
import asyncio
```

でimportしているところに、

```python
import discord
import asyncio
import re
```

と書いてあげる必要があります。

re.matchやre.searchはbotを作る上でかなり使うことになるので覚えておくと幸せになれます。

startswithは普段あまり使うことないので個人的に上記の形で処理を分けたりしています。

今日はそれくらいです。
もし他になんかあったら追記していきたいです。
Javascript 流程控制 - 迴圈 By 彭彭


```ruby:qitta.rb
<!--
	網頁前端工程入門
	3. Javascript 流程控制 - 迴圈 By 彭彭
	a. 判斷式
	b. 回圈
		b.1 while 回圈
		b.2 for 回圈
-->
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8"></meta>
	<title>Javascript</title>
	<script type="text/javascript">
	/*
		while(判斷){
			若判斷的結果是正確的(true),則執行大括號區塊中的程式碼.
			知道判斷結果是錯誤的(false),才跳離整個回圈結構.
		}
	*/
/*
	var n = 0;// 初始化
	while(n <= 50){
		n++;
	}
	alert(n);
*/

/*	var sum = 0;
	var i = 1;
	while(i <= 100){
		sum = sum + i;
		i++;
	}
	alert(sum);
	
	/*
		for(初始區塊;判斷;回圈區塊){
			判斷概念同 while 回圈
			請在講解中注意「初始區塊」與「回圈區塊」的執行時機
		}
	*/
/*
	var sum = 0;
	for(var i = 1; i <= 100; i++){
		sum = sum + i;
	}
	alert(sum);
*/
	//	break;  强制跳出回去圈
	//	continue; 强制進行下一次的回圈
	var x = 0;
	for(var n = 0;n <= 100;n++){
		if(n%4 == 0){
			continue;
		}
		x++;
	}
	alert(x);
/*	var n = 0;
	while(n <= 100){
		if(n == 50){
			break;
		}
		n++;
	}
	alert(n);
*/
	</script>

</head>
<body>
</body>
</html>
```

```ruby:qitta.rb
<!--
	網頁前端工程入門
	3. Javascript 流程控制 - 迴圈新手教學 By 彭彭
		流程控制
		 附錄/新手篇
-->
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8"></meta>
	<title>迴圈新手教學</title>
	<script type="text/javascript">
	/* 1+2+3...+50 */
	var sum = 0;
	var n = 1;
	while(n <= 50){
		sum = sum + n;
		n++;
	}
	alert(sum);
	/*和循環相關的變數追蹤 
	0:
		sum:0, n:1
	1:
		sum:1, n:2
	2:
		sum:3, n:3
	3:
		sum:6, n:4
		
		...
		...
		...
	50: 
		sum:1275, n:50
	*/
	
	/* continue 命令與執行流程 */
	var x = 0;
	for(var i = 1;i < 100; i++){
		if(i%2 == 0){
			continue;
		}
		x++;
	}
	alert(x);
	</script>

</head>
<body>
</body>
</html>
```
miniconda と python と openblas

チラ裏。

conda の小さい版 miniconda を使って、python と openblas を入れる。
pyenv で python を入れる場合ビルドしないといけないが、miniconda ならダウンロードだけ。

# install miniconda

https://conda.io/docs/user-guide/install/linux.html

```
# wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
# bash Miniconda3-latest-Linux-x86_64.sh
wget https://repo.continuum.io/miniconda/Miniconda3-4.5.4-Linux-x86_64.sh
bash Miniconda3-4.5.4-Linux-x86_64.sh
```

デフォルトで `$HOME/miniconda3` に入った。bin にパスを通しておく。

```shell:.bashrc
[[ -d "$HOME/miniconda3" ]] && export PATH="$HOME/miniconda3/bin:$PATH"
```

# install python

すでに `$HOME/miniconda3/bin` に入ってるので、パスも通っている。

# install openblas

https://anaconda.org/anaconda/openblas

仮想環境を切らずにいれた所、最初からある `$HOME/miniconda3/lib`, `$HOME/miniconda3/include` に混ざって入ってしまい、都合が悪かったので、仮想環境を切ってから入れることにした。

```shell
conda create -n myenv
source activate myenv # 抜けるには source deactivate
```
インストール

```shell
conda install -c anaconda openblas
```

`$HOME/miniconda3/envs/myenv/lib`, `$HOME/miniconda3/envs/myenv/include` この辺に入る。myenv までのパスは source activate した際に `CONDA_PREFIX` 環境変数に設定される。


```shell:.bashrc
if [ -d "$HOME/miniconda3/envs/myenv" ]; then
  source activate myenv
  export LD_LIBRARY_PATH="$CONDA_PREFIX/lib:$LD_LIBRARY_PATH"
  export LIBRARY_PATH="$CONDA_PREFIX/lib:$LIBRARY_PATH"
  export CPATH="$CONDA_PREFIX/include:$CPATH"
  export LDFLAGS="-L$CONDA_PREFIX/lib $LDFLAGS"
  export CFLAGS="-I$CONDA_PREFIX/include $CFLAGS"
fi
```

# conda env export

conda 環境を設定ファイルに吐いておけば、別の環境で簡単に再現できる。

```
$ conda env export > myenv.yml
```

```yaml:myenv.yml
name: myenv
channels:
  - anaconda
  - defaults
dependencies:
  - libgcc-ng=7.2.0=hdf63c60_3
  - libgfortran-ng=7.2.0=hdf63c60_3
  - libopenblas=0.2.20=h9ac9557_7
  - openblas=0.2.20=4
  - openblas-devel=0.2.20=7
prefix: /home/sonots/miniconda3/envs/myenv
```

再現

```
$ conda env create -f myenv.yml
```

# References

* https://qiita.com/yubessy/items/2dd43551aa8308dc7eca
* https://conda.io/docs/user-guide/tasks/manage-environments.html