OmniAICreator/Qiita-1.07M huggingface dataset:
PMD Apexで静的解析

# はじめに

## PMDとは
[PMD](https://pmd.github.io/)とは、様々な言語のソースコードを静的解析するツールであり、以下のような潜在的問題を識別するためのルールセットがあります（参照：[Wikipedia](https://ja.wikipedia.org/wiki/PMD_\(ソフトウェア)）。

- バグの可能性：空のtry/catch/finally/switchブロック
- デッドコード：使われていないローカル変数、パラメータ、privateメソッド
- 空のif/whileステートメント
- 複雑な式：whileループを可能にしたforループのステートメントが必要ない場合
- 準最適コード：無駄な文字列/ストリングバッファの使用
- 高い循環的複雑度測定を使ったクラス
- 重複コード：コピー・アンド・ペーストされたコードはバグもコピー・アンド・ペーストされていると解釈でき、保守性が低下してしまう。

## PMD Apexとは
Apexとは、Force.comプラットフォーム上で実行する、強い型付けのプログラミング言語です。PMD Apexは、そのApexを静的解析するためのルールセットをまとめたPMDプラグインです。
ルールセットしては、下記のようなものを含みます。

| ルール       | 説明 |
|-------------|----------------------------------------------------------------------------------------------|
| ApexUnit    | These rules deal with different problems that can occur with Apex unit tests.                |
| Complexity  | The Complexity ruleset contains rules that find problems related to code size or complexity. |
| Performance | The Performance ruleset contains a collection of good practices which should be followed.    |
| Security    | These rules deal with different security problems that can occur within Apex. |
| Style       | The Style Ruleset contains rules regarding preferred usage of names and identifiers.         |

# 導入(Ant)

## ライブラリや設定を準備する
下記のようにPMDをAntで実行できるようにします。

- [PMD Webサイト](https://pmd.github.io/)からコンパイル済みのパッケージが入ったZipファイルをダウンロードします。
- Zipファイルを解凍します。今回はApache Antで実行できるようにするために、対象プロジェクトにlibをコピーします。
- 下記を参考にbuild.xmlを書き換えます。

```xml:build.xml
<?xml version="1.0" encoding="UTF-8" ?>
<project name="PMD Sample">
  <!-- PMDで利用するjarファイルにパスを設定する -->
  <path id="pmd.classpath">
    <pathelement location="${build}"/>
    <fileset dir="lib/">
      <include name="*.jar"/>
    </fileset>
  </path>

  <!-- PMD Antタスクを利用できるように設定する -->
  <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath"/> 
  
  <!-- PMD Antタスクをコールして静的解析する -->
  <target name="pmd">
    <mkdir dir="target"/>
    <pmd rulesetfiles="apex-apexunit,apex-complexity,apex-performance,apex-security,apex-style" encoding="UTF-8">
      <!-- 静的解析結果をXMLファイルに出力する -->
      <formatter type="xml" toFile="target/pmd.xml">
        <param name="linkPrefix" value="http://pmd.sourceforge.net/xref/"/>
      </formatter>
      <!-- 静的解析結果をコンソールに出力する -->
      <formatter type="text" toConsole="true" />
      <!-- 対象ファイル -->
      <fileset dir="src">
        <include name="**/*.cls" />
        <include name="**/*.trigger" />
      </fileset>
    </pmd>
  </target>
</project>
```

## 静的解析を実行する

以上で準備完了なので、コマンドラインよりAntを実行します。

```bash
> ant pmd
```

PMD Apexは、src以下のApexクラス、トリガーを静的解析し、target/pmd.xmlに静的解析結果をXMLファイルとして出力します。また、コンソールにも静的解析結果を出力します。

Jenkinsのプラグインも用意されているので、上記で生成されたpmd.xmlファイルを指定することで、Jenkinsから静的解析結果を参照できるようになります。
HTML形式で出力したい場合は、type="html"とした<formatter>タグを追加すると、HTML形式で表示できる静的解析結果が出力します。

# 結び

今回は、Force.com Apexで利用できる静的解析ツールであるPMDを紹介しました。また、CIで利用しやすいようにAntで実行する方法も紹介しました。
ソースコードの問題点を見つけ、きれいな状態に保つために静的解析は有用なツールですので、活用していきたいと思います。

# 追記
- (2017/2/1) PMD ５．５．３ で Security のルールセットが追加になりました。
JUMAN++のRubyラッパーGemを作った


JUMAN++は去年発表された、新型の形態素解析機です。

[(参考1)JUMAN++ - 黒橋・河原研究室 - 京都大学](http://nlp.ist.i.kyoto-u.ac.jp/index.php?JUMAN++)

[(参考2)新形態素解析器JUMAN++を触ってみたけど思ったより高精度でMeCabから乗り換えようかと思った話](http://qiita.com/riverwell/items/438e88427363511e9f28)

今回はGem作成の練習がてら、JUMAN++をRubyから使用するためのGemを作ってみました(最低限ですが・・・)。


[GitHub:EastResident/jumanpp_ruby](https://github.com/EastResident/jumanpp_ruby)

[RubyGem:jumanpp_ruby](https://rubygems.org/gems/jumanpp_ruby)

# 環境

OS: Mac OS X EI Capitan
Ruby: 2.3.1

# 準備

普通にbundle installしてください。

```rb
gem 'jumanpp_ruby'
```

```
$ bundle
```

OR

```
$ gem install jumanpp_ruby
```

環境にJUMAN++が入っていない場合は、適宜導入してください。Macならbrew一発で入ります。

```
brew install jumanpp
```

# 使用方法

## JumanppRuby::Juman#parse

基本的な使い方としては、`JumanppRuby::Juman`クラスのインスタンスを作成し、`parse`メソッドを呼び出すだけです。

第一引数のみを渡すと、渡した日本語文字列を形態素に分解し、表層形のみを一次元配列の形で返します。要するに**分かち書きして配列で返す**だけです。

```rb
require 'jumanpp_ruby'

juman = JumanppRuby::Juman.new(force_single_path: :true)
p juman.parse('モビルスーツの性能の違いが、戦力の決定的差でないということを教えてやる')
# => ["モビルスーツ", "の", "性能", "の", "違い", "が", "、", "戦力", "の", "決定", "的", "差", "で", "ない", "と", "いう", "こと", "を", "教えて", "やる", "EOS"]
```

また、`parse`メソッドに**ブロックを渡す**と、ブロックの中で構文解析結果の入った配列を処理することができます。

```rb
require 'jumanpp_ruby'

juman = JumanppRuby::Juman.new(force_single_path: :true)

jumanpp.parse('ララァ…私を導いてくれ！') do |word|
  p word
end
# =>["ララァ", "ララァ", "ララァ", "名詞", "6", "普通名詞", "1", "*", "0", "*", "0", "自動獲得:Wikipedia", "Wikipediaリダイレクト:ララァ・スン"]
# =>["…", "…", "…", "特殊", "1", "記号", "5", "*", "0", "*", "0", "NIL"]
# =>["私", "わたし", "私", "名詞", "6", "普通名詞", "1", "*", "0", "*", "0", "代表表記:私/わたし", "漢字読み:訓", "カテゴリ:人"]
# =>["を", "を", "を", "助詞", "9", "格助詞", "1", "*", "0", "*", "0", "NIL"]
# =>["導いて", "みちびいて", "導く", "動詞", "2", "*", "0", "子音動詞カ行", "2", "タ系連用テ形", "14", "代表表記:導く/みちびく"]
# =>["くれ", "くれ", "くれる", "接尾辞", "14", "動詞性接尾辞", "7", "母音動詞", "1", "基本連用形", "8", "代表表記:くれる/くれる"]
# =>["！", "！", "！", "特殊", "1", "記号", "5", "*", "0", "*", "0", "NIL"]
# =>["EOS"]
```

## Juman++設定の適用

`new`でインスタンスを作成する際には、以下のオプションを適用させることができます。オプションの詳細は[JUMAN++の公式ページ](http://nlp.ist.i.kyoto-u.ac.jp/index.php?JUMAN++)を参照してください。


```
beam: set beam width used in analysis (unsigned int [=5])
force_single_path: do not output ambiguous words on lattice(default false)
partial: receive partially annotated text(default false)
```

以下は適用例です。

```rb
JumanppRuby::Juman.new(
  beam: 5,
  force_single_path: :true,
  partial: :true
)
```

## String.parse

`String`クラスから、`parse`メソッドを利用することもできます。

```rb
require 'jumanpp_ruby'

p 'モビルスーツの性能の違いが、戦力の決定的差でないということを教えてやる'.parse
# => ["モビルスーツ", "の", "性能", "の", "違い", "が", "、", "戦力", "の", "決定", "的", "差", "で", "ない", "と", "いう", "こと", "を", "教えて", "やる", "EOS"]
```

この時、`parse`メソッドの引数として、前述したオプションを渡すことができます。

```rb
'Japanese Text'.parse(force_single_path: :true)
```

## バージョン情報とヘルプ

`JumanppRuby::Juman.version`でバージョン情報を出力できます。

```rb
print JumanppRuby::Juman.version
# => JUMAN++ 1.01
```

また、`JumanppRuby::Juman.help`で、ヘルプテキストが返ります。

```rb
print JumanppRuby::Juman.help
```

## 最後に

今回は簡単な方法で実装しましたが、できればRuby-FFIとか使ってもっと本格的な実装を試してみたいですね。mecabバインディングのnattoとかを参考にしつつ、少しずつ充実させていきたいです。
【Kotlin】 TypeAliasで関数リテラルに名前を付ける

# Problem

## SAM変換

Kotlinにはinterfaceに1つのみ関数が定義されている場合にのみLambda式として表せる[SAM変換](https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions)というものがあります。

例えばAndroidでボタンをクリックした際に呼ばれるOnClickListenerをJavaで書くとこうなります。

```Java:Java
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
       // click 
    }
});
```

`OnClickListener`はViewクラスのinterfaceに`onClick`というメソッドが1つのみ定義されているので

```Java:Java
/**
 * Interface definition for a callback to be invoked when a view is clicked.
 */
public interface OnClickListener {
    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
     void onClick(View v);
}
```

Kotlinでは簡潔にこれだけで書きます。

```Kotlin:Kotlin
button.setOnClickListener { 
    // click
}
```

しかしながら、SAM変換は**Javaで定義されたinterfaceのみ**対応していてKotlinで書かれているinterfaceは対応していません。
Kotlinは関数リテラルを型に持てるのでプロパティにコールバックを定義してリスナーの形をとることが可能なのですが、型に名前がつかないのでライブラリの様な不特定多数の人が使うものだと、やはり型名を付けたくなります。
プロパティに関数リテラルを定義してコールバックとして用いたやり方を以前このような記事を書いたので、参考にしてみて下さい。
[Kotlinでコールバック](http://qiita.com/AAkira@github/items/e0baa9e5ed42bd2300c0)

# Solution

## Type Alias

Kotlin1.1からTypeAliasという機能が導入されました。
C++やSwift等の他の言語にも似た機能があるので知っている人も多いと思います。

簡単に説明すると、例えばHogeというIntとStringを引数にとってStringを返すTypeAliasを定義して、
変数`hoge`の型としてHogeを指定することが出来ます。

```Kotlin:Kotlin
typealias Hoge = (Int, String) -> String

val hoge: Hoge? = { i: Int, str: String -> "hoge : $str : $i" }
```

## Callback (interface)
今まではJavaの様にinterfaceを使って書くとこのようになります。

```Kotlin:Kotlin
interface CallBackListener {
    fun onHoge(foo: String, bar: Int)
}

// caller
var callback: CallBackListener? = null
callback?.onHoge("foo", 100)

// callee
val callback = object : CallBackListener {
    override fun onHoge(foo: String, bar: Int) {
        print("$foo : $bar")
    }
}
```
これだと、Javaで書いているのとあまり変わりません…

## Callback (関数リテラル)

関数リテラルにして書いてみます。

```Kotlin:Kotlin
// caller
var callback: ((foo: String, bar: Int) -> String)? = null
callback?.invoke("foo", 100)

// callee
val callback = { foo: String, bar: Int ->
    print("$str : $i")
}
```

この形でも、Kotlinっぽく書けなくはありません。
ただ上記でも述べたように、型では無いので引数の型さえ同じなら任意の値を入れることが出来ます。

## Callback (TypeAlias)

上2つをTypeAliasで書き直すとこのようになります。
イメージとしてはinterfaceと関数リテラルの良いとこ取りをした感じです。

```Kotlin:Kotlin
typealias CallBackListener = (foo: String, bar: Int) -> Unit

// caller
var callback: CallBackListener? = null
callback?.invoke("foo", 100)

// callee
val callback = { foo, bar -> 
    print("$foo : $bar")
}
```

TypeAliasを使うとコールバックに型名を付ける事が出来るので、型安全かつKotlinっぽく書くことが出来ました。


2017年1月現在はまだKotlin1.1はbeta版ですが、近いうちに正式リリースされる予定なので是非使ってみて下さい。

※ 指摘がありましたので、2017/1/24にタイトル、内容を一部変更致しました。
Goで任意のbuild tagsをつけてビルドファイルを切り替える

背景
----

Goは環境固有の処理を書ける仕組みがあり、OSやCPUアーキテクチャによってビルドするファイルを選択できます。そしてbuild tagsをビルドパラメータに与えることで、任意の条件でビルドするファイルを切り替えることができます。この方法はcgoのincludeなど、ビルド時に解決したい依存関係があるときに有用です。

ビルドスクリプト
----------------

build tagは`go build`に`-tags`オプションで渡すことができます。2つのビルドで異なるバイナリを吐くようにGoを記述します。

```sh
go build -tags foo      # fooサポート環境
go build                # foo非サポート環境
```

この方法は、例えばファイル`/usr/include/foo.h`の有無でビルドを切り替えることができます。

```sh
if [ -f /usr/include/foo.h ]; then
  go build -tags foo
else
  go build
fi
```

build tagsを使ったビルドの切り分け
----------------------------------

Goのコードの先頭にビルドタグ`// +build`をつけるとこで、そのファイルをビルド対象かどうかを指定できます。`foo`が与えられた時とそうでない時のファイルを用意し、それぞれのファイルの先頭にビルド条件を記述します。

```go:run_foo.go
// +build foo

package main

import "fmt"

func run() {
	fmt.Println("Foo supported")
}
```

```go:run_nofoo.go
// +build !foo

package main

import "fmt"

func run() {
	fmt.Println("Foo not supported")
}
```

そしてmainから`run()`を呼び出すと、ビルドされたどちらかの`run()`を呼び出します。

```go
package main

func main() {
	run()
}
```
海外カンファレンスの翻訳から得た、翻訳のポイント

2017/01/23(月)に開催される [#1Creators Learning English Meetup ~2017年、今年こそ英語！~](https://clem.connpass.com/event/48456/) で発表する内容の日本語版です。発表およびスライドは全編英語になりますが、この記事の内容に準拠しています。

最近あるプログラミング言語のカンファレンスのトランスクリプトの翻訳を行っていて、感じたことや、ポイントみたいなものをお話できればと思います。

### 自己紹介

(略：発表スライドを見てください)

### 今日お話すること
* 技術記事の翻訳に必要なこと
* トランスクリプトの翻訳
* 翻訳するときのポイント
* 辞書に載っていない表現
* まとめ：翻訳していて楽しいこと

### 技術記事の翻訳に必要な知識

技術記事の構成要素 = 技術のお話が、英語で書かれている ≒ 学術論文

* 技術に関する知識 … その分野の専門用語 (`technical term`) がわかること
辞書なしでその記事を読むには、その分野のバックグラウンドがあることが前提です。日本語で読んでもわからないものを英語で読んだってわからないことの方が多いはずです。

例えば、`build`という簡単な単語1語にしても、プログラミングをやっている人からするとプログラムを書いたり実行することになるだろうし、建築業界の人からすると、建物を立てることになりますよね。

※もちろん日本語訳されたものを読んでわからないものは、原文にあたった方が理解が及ぶ場合があります。個人的にはそういう場合は、専門用語を無理やり日本語に訳してしまっていることが多いと思います。プログラミングで出てくる専門用語は日本語で普及していないものの方が多いので、英語のまま記載するか、カタカナ英語に置き換えることはよくやっています。

* 英語に関する知識 … 高校レベルの英語が読めること

基本的には具体的な内容で書かれているので読みやすく、読むための文法事項が理解できていれば難しくありません。大学入試のような抽象度の高い英文は基本的には情報を取り扱うということが主眼に置かれている記事になりません。
もし英語を読むための知識が足りない、忘れたということであれば、家にホコリ被って眠っている文法書(リファレンス)を読みましょう。

### トランスクリプトの翻訳

トランスクリプト = 文字起こし

* 書き言葉ではなく、話し言葉
書き言葉であれば、文章構成がしっかりしていてロジカルにかかれていることが多いですが、トランスクリプトの場合はロジカルではないことの方が多いです。

* そんなにロジカルにかかれていない
ロジカルな文章の場合は段落構成、文章構造(特に接続詞など)を意識して読みますが、トランスクリプトの場合は、話し言葉なので、英文自体はそんなにロジカルではなかったりします。特定の単語を無視してしまっても意味が取れるものが多く、ひどいものだと囚われてしまうと適切に訳せなくなる場合もあります。

### 翻訳するときのポイント

#### 英文は左から右へ読む
英語でも日本語でも、書き言葉でも話し言葉でも何でもそうですが、文章は前から読んでいきます。出て来る単語をつまみ食いせずに、文を読みます。英語で何書いているか理解する → 日本語で書く際のプロセスで結果的に並び替えた方が意味がつかみやすいことは多々ありますが、英語を読む時点でそれをやると余計に混乱します。
	
#### 前後の文脈を考慮する
英語から日本語に訳すとき、どうしてもギャップが生じます。訳してみて意味が通らないときは、前後の文脈から捉えます。
個人的な見解ですが、辞書は英語を日本語に訳すためのツールではなく、英語を日本語で理解するためのツールだと思っています。英語も日本語も、単語の意味は文脈に応じて変わります。
また、大学入試ではないので、この構文を習った通りに訳さなくてはいけない、といったことは全くなく、読み手に正しい意味が伝わる、伝わりやすいことの方が重要です。

### 読んでもわからないものに出会ったとき

前後の文脈から読んでもわからなかったとき、現代ではググることが許されています。例えば、こんなものです。

* drink the kool-aid

> Lately I’ve been drinking the functional programming kool-aid big time.

`kool-aid`ってなんだろうって思いますよね。飲むぐらいなので飲み物なんでしょう。わからないのでググってみるとWikipediaというページがでてきますね。

* [Drinking the Kool-Aid - Wikipedia](https://en.wikipedia.org/wiki/Drinking_the_Kool-Aid)

説明によると、kool-aidというのは毒の入った飲み物のようですね。この飲み物を飲めと言われると飲んでしまうぐらい、周りから見ると狂ったように信奉していたことのようです。これが転じて、狂ったように何かを信じている、という意味になっているようですね。

なので、

> Lately I’ve been drinking the functional programming kool-aid big time.

最近は、関数プログラミングがかなりいいものだと思ってしまっています。
ぐらいに訳すのがよさそうです。この文章の前後の文脈は関数プログラミングに対して肯定的にとらえていることから、関数プログラミングがかなりいいものだと思っていることには違いないのですが、しゃべっている本人もどこか否定的に思っているのかもしれませんね🤔

このプロセスを踏まないで、Google翻訳にかけても、意味は理解できません。

### まとめ：翻訳していて楽しいこと

* 読めば読むほど早く読める、訳せるようになる

初めて翻訳したとき、30分程度の講演のトランスクリプトを訳すのに5時間程かかっていましたが、記事によって違いはあるものの、今では3時間程で終わらせられるようになりました。

* 英語で情報収集できる

情報の発信源が英語の場合、日本語になって出てくるには、僕のように誰かが翻訳するものを待つことになります。技術の移り変わりが激しいこの業界で、翻訳を待っていては、最新の情報を取り逃がすことになります。

* スピーカーとの話題になる

講演の書き起こしなので、直接会ったときや、Twitterなんかで翻訳したことを報告できます。翻訳されてネガティブなコメントをもらったことは今のところ無いので、どんどん報告するようにしています。これもまたモチベーションになります。

英語のスキルアップ、というと会話に主眼が置かれがちですが、書いてある英語から情報のキャッチアップができるというのも重要なスキルだと思っています。
ぜひ今年こそは英語のスキルアップに励んでいきましょう！
Firebaseのデータベースにネスト保存する方法

データベースへの保存方法はデフォルトのリファレンスを確認するとして、
ネストでpushする方法などが情報としてまとまっっていなかったのでここにまとめます。

## データ保存のメソッドおさらい
|メソッド|使用例|
|:-----------------|------------------:|
| set()|users/<user-id>/<username> など、定義済みのパスへのデータの書き込みや、データの置換を行います。|
|push()|データのリストに追加します。push() を呼び出すたびに、Firebase によって一意のキーが生成されます。このキーは user-posts/<user-id>/<unique-post-id> のような一意の ID としても使用できます。|
|update()|データのすべてを置換することなく、定義済みのパスのキーの一部を更新します。|
|transaction()|同時更新によって破損する可能性がある複合データを更新します。| 

## 前提はネストはなるべく最小化すること
Firebaseでは最大32の深さまでデータをネストさせることができます。
ただし、基本的にはパフォーマンスや管理方法などの観点から極力ネストは浅く管理することが推奨されています。

```json:非推奨
{
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "messages": {
        "m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." },
        "m2": { ... }
      }
    },
    "two": { ... }
  }
}
```
```json:推奨
{

  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
      "timestamp": 1459361875666
    },
    "two": { ... },
    "three": { ... }
  },

  "members": {
    "one": {
      "ghopper": true,
      "alovelace": true,
      "eclarke": true
    },
    "two": { ... },
    "three": { ... }
  },

  "messages": {
    "one": {
      "m1": {
        "name": "eclarke",
        "message": "The relay seems to be malfunctioning.",
        "timestamp": 1459361875337
      },
      "m2": { ... },
      "m3": { ... }
    },
    "two": { ... },
    "three": { ... }
  }
}
```
しかしながら、場合によってはデータをグルーピングしたほうが設計として正しいこともあろうかと思います。
そんな場合のデータの追加方法を記します。

## 基本的なデータの追加方法（例としてpushメソッド）
```
let hogeRef = this.database.ref('hoge');
hogeRef.push({
        text: "hogehoge"
})
```
```json:結果
{
  "hoge" : {
      "text": "hogehoge"
  }
}
```

## ネストさせるデータの追加方法（同じくpushメソッド）
```
let hogeRef = this.database.ref('hoge');
hogeRef.child('fuga').push({
        text: "hogehoge"
})
```
```json:結果
{
  "hoge" : {
      "fuga": {
          "text": "hogehoge"
      }
  }
}
```

`.child()`をはさめばいいだけです。

以上。
Rust から WASM32 を出力するための準備

注意：[現在はEmscriptenを利用しなくてもwasmへのコンパイルができます](https://www.hellorust.com/news/native-wasm-target.html)。

Rust は 1.14 から WebAssembly（以下、WASM） へコンパイルできるようになりました。(c.f. [Rust 1.14 のリリースに関するアナウンス](https://blog.rust-lang.org/2016/12/22/Rust-1.14.html))

以前のバージョンでは、WASMへの出力にはRustコンパイラに加えて、[Emscripten](https://emscripten.org/)も必要でした。ただ、現在はstable版のRustコンパイラのターゲットアーキテクチャにWASMを追加することで、RustからWebAssemblyを出力できます。

## 必要なソフトウェア

* rustup：Rust コンパイラのバージョン管理ツール
* rustc / Cargo：Rust コンパイラ / パッケージ管理ツール

これだけのソフトウェアをインストールします。

### Rust コンパイラのインストール

rustup を利用して Rust コンパイラをインストールします。詳細は[rustup で Rust コンパイラを簡単インストール](http://qiita.com/chikoski/items/b6461367e8c3875bb235) を参照してください。

~~~sh
% curl https://sh.rustup.rs -sSf | sh
% source ~/.cargo/env
~~~

### Rust にターゲットアーキテクチャを追加

rustup はコンパイラをインストールする以外に、ターゲットアーキテクチャの管理も行えます。WASM をコンパイルするためには、wasm32-unknown-emscripten というアーキテクチャを追加します。追加は次のように行います。

~~~sh
% rustup target add wasm32-unknown-unknown
~~~

## Rust から WASM 出力

以上で準備は終了です。では実際に WASM を出力してみましょう。まず cargo コマンドで hello world を作成します。

~~~sh
% cargo new --bin hello
% cd hello
~~~

つぎにビルドをします。`target` オプションを使って`wasm32-unknown-unknown`をターゲットアーキテクチャに指定し、ビルドします。

~~~sh
% cargo build --target=wasm32-unknown-unknown
~~~

ビルドされたバイナリーは、`target/wasm32-unknown-unknown/debug` 以下に出力されます。

~~~sh
% ls target/wasm32-unknown-unknown/debug
build			examples		hello-world.wasm	native
deps			hello-world.d		incremental
~~~

## まとめ

`wasm32-unknown-unknown`をターゲットアーキテクチャに追加するのがポイントでした。`--release`オプションをつけてビルドすることで、最適化されたバイナリが出力されます。
MySQLのバージョンをあげたら、ログ出力される時間がおかしくなった

# 起きたこと
MySQL5.7にupgradeした際に、errorログ、slowクエリログなど、ログを確認したら、
時間がおかしいこと（utc）になっていた。

# 確認しても、どこもJSTになっているはず、、

* linuxのdateコマンド

```
$ date
2017年  1月 21日 月曜日 07:15:37 JST
```

* mysqlのtimezone設定

```
mysql> SHOW GLOBAL VARIABLES LIKE '%time_zone';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | JST    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.01 sec)
```

* mysqlのdatetime

```
mysql> SELECT NOW();
+---------------------+
| NOW()               |
+---------------------+
| 2017-01-21 07:15:37 |
+---------------------+
1 row in set (0.00 sec)
```


# 原因は、log_timestamps

mysqlの設定に、log_timestampsという項目が、5.7.2から導入されていた。
こいつによって、ログ出力時のdateは、log_timestampsの設定に依存されてしまう。
そして、デフォルト値がutcになっているため、ログが全てutcになっていた。

```
mysql> SELECT @@log_timestamps;
+------------------+
| @@log_timestamps |
+------------------+
| UTC              |
+------------------+
1 row in set (0.00 sec)
```

# my.cnfで設定値を変更

```
#/etc/my.cnf
[mysqld]
log_timestamps=SYSTEM
```
上記のように、SYSTEMに変更してあげることで、
ログ出力時の時刻はOSで設定されている時間を見るようになる。

# 再起動して、反映を確認

```
mysql> SELECT @@log_timestamps;
+------------------+
| @@log_timestamps |
+------------------+
| SYSTEM           |
+------------------+
1 row in set (0.00 sec)
```

error.log, slow.log, general.logなど、各種ログファイルがjstで
表示されるようになったことを確認。
技術英語 > If you do the addition first, / if you do the multiplication first,

@ Introducing Python: Modern Computing in Simple Packages by Bill Lubanovic
(No. 665 / 12833)

```
>>> 2 + 3 * 4
```

> If you **<font color=red>do the addition</font>** first, 2 + 3 is 5, and 5 * 4 is 20. But if you **<font color=red>do the multiplication</font>** first, 3 * 4 is 12, and 2 + 12 is 14.

<hr>
関連して思い出したのは

[技術英語 > ちょっと調べたんだ > I did a little research...](http://qiita.com/7of9/items/ca57a230b8eee48e4823)

<hr>
関連して思い出したのは

Addidtion theorem
https://en.wikipedia.org/wiki/Addition_theorem

```math
e^{x+y} = e^x + e^y
```

```math
F(x+y) = G(F(x), F(y))
```
fastTextの学習済みモデルを公開しました

fastTextの学習済みモデルを公開しました。
以下から学習済みモデルをダウンロードすることができます:

<!--
* [Download Word Vectors](https://drive.google.com/open?id=0ByFQ96A4DgSPNFdleG1GaHcxQzA)
* [Download Word Vectors(NEologd)](https://drive.google.com/open?id=0ByFQ96A4DgSPUm9wVWRLdm5qbmc)
-->

* [Download Word Vectors](https://drive.google.com/file/d/0ByFQ96A4DgSPNFdleG1GaHcxQzA/view?usp=sharing&resourcekey=0-dtRh36dTEOh9RETFJDOQbw)
* [Download Word Vectors(NEologd)](https://drive.google.com/file/d/0ByFQ96A4DgSPUm9wVWRLdm5qbmc/view?usp=sharing&resourcekey=0-of5Ks1fuoKNh1pEYE8uSFQ)


埋め込みベクトルの情報は以下のリポジトリにまとめているので、こちらもよろしく。
[awesome-embedding-models](https://github.com/Hironsan/awesome-embedding-models)

# Motivation
以下の記事では [icoxfog417](http://qiita.com/icoxfog417) が GitHub で公開していたリンクを貼りました。

* [いますぐ使える単語埋め込みベクトルのリスト](http://qiita.com/Hironsan/items/8f7d35f0a36e0f99752c)

ただ、公開されていたベクトルをダウンロードするのにGit LFSが必要であったり場所がわかりにくいといった問題がありました。そのため、今回は簡単にダウンロードできるように学習・公開しました。

# How to make
fastTextの使い方は以下の記事を参考にしました。fastTextの理論と使い方を解説している良記事です。

* [FacebookのfastTextでFastに単語の分散表現を獲得する](http://qiita.com/icoxfog417/items/42a95b279c0b7ad26589)


学習に使用したデータはwikipedia2017/01/01です。

* [jawiki 20170101](https://dumps.wikimedia.org/jawiki/20170101/)

ハイパーパラメータは以下のように設定しています。他のハイパーパラメータはDefaultの設定を用いています。

* dim: 300
* epoch: 10
* minCount: 20


# How to use
データをダウンロードしたら読み込みは以下のようにして行うことができます。(gensimの場合)

```py3
import gensim

model = gensim.models.KeyedVectors.load_word2vec_format('model.vec', binary=False)
```

関連する単語は以下のようにして求めることができます。

```py3
>>> model.most_similar(positive=['日本人'])
[('韓国人', 0.7338133454322815),
 ('中国人', 0.717720627784729),
 ('アメリカ人', 0.6725355982780457),
 ('日本人女性', 0.6723321676254272),
 ('外国人', 0.6420464515686035),
 ('フィリピン人', 0.6264426708221436),
 ('欧米人', 0.621786892414093),
 ('アジア人', 0.6192302703857422),
 ('台湾人', 0.6034690141677856),
 ('日系人', 0.5906497240066528)]
```

Good NLP Life!
iterm2での作業が終わったら自動でgrowlが通知してくれる機能を実装してみる

<a href="http://aming-blog.blogspot.com/2011/01/growl-notification-from-iterm-2.html" target="_blank">Growl Notification from iTerm 2<a/>というサイトをたまたま発見。そういえば時間がかかる処理を待ってる間実際他のことをしていることが多いし定期的にターミナルをチェックするのも面倒。終わった瞬間に通知してくれたらいいなと思っていたところ。中々役に立ちそうな実装だったので実践してみることに。

まずはgrowlを開いてitermとの連携をONに。

![Screen Shot 2017-01-22 at 12.25.58 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/8c519fdf-8e91-b17e-81c7-f9a4e1d24f71.png)

次に`mvim ~/.bash_profile`でバッシュプロファイルを開いて以下を追加。

```.bash_profile
# A bash function to display a growl notification using iTerm's magic
# escape sequence. This version will work under screen.
growl() { echo -e $'\e]9;'${1}'\007' ; return ; }
```

これで準備完了。

あとはコマンドを打つ際に`runfoo ;growl "foo finished"`と打つだけで処理が終わった際にgrowl経由で通知してくれる。
HoloLens チュートリアルの実機動作


## はじめに

HoloLens エミュレータでのチュートリアルを試してきましたが、実機が来ましたので、実機での動作をさせてみます。

- [HoloLens チュートリアル (Holograms 101E - 1 "Holo" world) - Qiita](http://qiita.com/Suna/items/c0efd88d151d087f9049)
- [HoloLens チュートリアル (Holograms 101E - 2 Gaze) - Qiita](http://qiita.com/Suna/items/f1bc81063cfc4d75c72d)
- [HoloLens チュートリアル (Holograms 101E - 3 Gestures) - Qiita](http://qiita.com/Suna/items/a8ac90ab53c959faa28c)

## HoloLens の IP アドレス確認

![j01.png](https://qiita-image-store.s3.amazonaws.com/0/20418/03e150bc-9078-394e-7614-ad5a53c10c75.png "j01.png")

- 「Settings」を選択
- 「Network & Internet」を選択
- 「Wi-Fi」-「Advanced Options」を選択

---

![j04.png](https://qiita-image-store.s3.amazonaws.com/0/20418/01531217-a951-c0c3-0864-6d3c01646ffb.png "j04.png")

- 「IPv4 address」を確認

---

## HoloLens を開発者モードへ変更

![j09.png](https://qiita-image-store.s3.amazonaws.com/0/20418/5123d5aa-217b-5059-86fa-8c664d3b17b7.png "j09.png")

- 「Update & Security」を選択

---

![j05.png](https://qiita-image-store.s3.amazonaws.com/0/20418/c8726aad-7ef3-b3ed-7c29-ded554998815.png "j05.png")

- 「For developers」を選択し、「Developer mode」を「ON」に変更

---

![j06.png](https://qiita-image-store.s3.amazonaws.com/0/20418/c20a0bc7-11ca-43c9-6a54-03bc2de41327.png "j06.png")

- 確認ダイアログが表示されるので「OK」を選択

---

## PC とのペアリング

![j07.png](https://qiita-image-store.s3.amazonaws.com/0/20418/0106c18b-2962-0603-30e3-790a4a180b7e.png "j07.png")

- 「For developers」を選択し、「Pair」ボタンを押下

---

![j08.png](https://qiita-image-store.s3.amazonaws.com/0/20418/134534d1-2cf5-a088-1166-2b4a6da614dd.png "j08.png")

- ペアリング用のコードが表示されます。PC 側で入力が必要な場面がありますので、その時に入力します。

---

## ビルド・実行環境設定の変更、実行

Visual Studio のプロジェクト生成までは、「[HoloLens チュートリアル (Holograms 101E - 1 "Holo" world) - Qiita](http://qiita.com/Suna/items/c0efd88d151d087f9049)」と同じになります。

![601b.png](https://qiita-image-store.s3.amazonaws.com/0/20418/122cd8ad-c207-bee8-70f6-84f9383d947a.png "601b.png")

- ソリューション構成を **「Release」** に変更
- プラットフォームを **「X86」** に変更

![602.png](https://qiita-image-store.s3.amazonaws.com/0/20418/e5ab5b84-1201-d309-fbe3-152af43a3991.png "602.png")

- 実行環境を **「リモートコンピューター」** に変更 (-> 接続先を指定するタイアログが表示されます)
- 「デバッグ」メニューから **「デバッグなしで開始」** を選択

![604.png](https://qiita-image-store.s3.amazonaws.com/0/20418/c3ed0635-622a-698a-3bab-7cc55d894626.png "604.png")

- 初回のみ接続確認のダイアログが表示されますので、コードを入力し、「OK」を選択

---

## 実機での実行

![j10.png](https://qiita-image-store.s3.amazonaws.com/0/20418/ac85ccfa-10f6-f8f3-ae86-1a3f0747a85a.png "j10.png")
アニメの視聴傾向を比較するツールを作ってみた

私はエンジニアです。

アニメや漫画はエンジニアの必修科目なので、
私は勿論、身の回りの友人たちも嗜んでいます。

というわけで、
特に意識せずともアニメの話をすることがあるのですが、
皆それなりの本数を見ているはずなのに、

* 不思議とお互い共通して見ているアニメが少ない
* 友人から超絶オススメされたアニメがそれほど刺さらない
* ハーレムものというか、むしろ男は1人も出なくていい。
* のんのんびより？何が楽しいかわからん。切ったわ。(開戦)

などなどあって、
誰がどのくらいアニメをみていて、
誰と誰の視聴傾向が似ているのか、という点が気になるようになりました。

そこで、Annict というウェブサービスを利用して、
データ取得とベン図を出力する簡易ツールを作ってみました。

# できたもの

* annict-watched-venn  
https://github.com/diescake/annict-watched-venn

Annict に登録された視聴済み情報を取得して、
こんな感じでベン図で出力します。

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/38837/8f3610f7-de9d-82fc-1be7-57de75fc88a4.png)

円の大きさが、アニメの視聴数を表していて、
重なっている領域が、共通してみているアニメの数を表しています。

# Annict について

* Annict  
https://annict.com/  
https://github.com/annict

Annict は見たアニメを記録して、共有できるウェブサービスです。
個人で運営していて Github にソースコードも公開されています。

本ツールは、Annict に記録された情報を参照しますので、
まずは Annict に情報を記録しておく必要があります。

詳しい説明は公式に譲りますが、
Twitter か facebook のアカウントを利用してサインアップした後に、

アニメの放送年順や、人気順などのグルーピングを利用して、
自分が「見てる」「見た」「見たい」「中断してる」「切った」などの状況を黙々と入力していきます。

スマホからではかなり疲弊するので PC 推奨です。

# annict-watched-venn について

## 使い方

[README.md](https://github.com/diescake/annict-watched-venn) をご参照ください。

といっても、一言で言ってしまえば、
`npm install` して `npm start` して `python -m SimpleHTTPServer` してブラウザで開くだけです。

## 中身の簡単な説明

nodejs の nightmare でウェブスクレイピングで取得したデータを JSON に吐き出して、
データの表示は html + javascript の D3.js, Venn.js で行っています。

Annict には [API](https://annict.wikihub.io/wiki/api) が公開されていますので、
ウェブスクレイピングなぞせずとも、API を使えば良さそうに思えたのですが、

どうも自分以外のユーザ情報を取得することはできないようなので、
泥臭くスクレイピングすることにしました。

html 側はとりあえず結果が見られる程度の適当なつくりです。

# 反省点とかぼやきとか

## ベン図の限界

実は比較したい友人たちは5人いました。

そう、察しの良い人は気づいているかもしれませんが、ベン図は2次元では3要素の表現が限界です。
意気揚々と 5人分のデータを Venn.js に食わせたら、大量の warning と共に明らかに情報の落ちているベン図が出力されてがっかりしました。

楕円使うと4要素表現できるらしかったり、カルノー図なら5要素くらいはいけそうですが、
少なくとも Venn.js はサポートしていないので、そこを自力でやる程のモチベーションはありませんでした…

暫定的な回避策として5人なので 5C3 = 10 というわけで、ベン図 10 個出力して比較してみましたが、
円の大きさの基準を統一しないと、なんとも分かりづらかったです。

どうビジュアライズするかって結構難しいものですね。

## co で Array.prototype.forEach が使えないのがストレスフル

あぁ＾～配列の走査で for ループなんか書きたくないんじゃあ＾～

## 他にもやりたかったこととか

### もう少しインタラクティブに

ベン図のマウスオーバーでその領域の作品リストをポップアップくらいはやろうと思ってましたが、
そもそも自分の目的としてた 5人の同時比較ができないことに気づいたので、
もうこれ以上何かする気が起きなくなりました。(かなしみ

### もう少し話のネタになりそうなデータを

* 全員が見ているアニメ
* この人だけ見ているアニメ
* この人だけ見ていないアニメ

とか、話のネタになりそうなデータが取れると良いんですが、
指標ごとに for ループ何度も書いて地道にやるのも芸がないし、かっこ悪いしで放置中です。

何か良い方法とかライブラリがあれば誰か教えてください＞＜

### ジャンル別視聴数とか

Annict の DB にはアニメのジャンルに関するデータはないのですが、
Wikipedia の各アニメのページや [dアニメストア](https://anime.dmkt-sp.jp/animestore/gen_sel_pc) では、分類されうるジャンルが記載されています。(絶対的なものではないと思いますが)

このあたりのデータと照らし合わせると、
ジャンル別視聴数から傾向がわかりそうです。

ただ、アニメの名称に文字揺れがあると思うので、そのあたりの照合をどうするかはネック。


しかし、苦痛に耐えて1クール視聴した「迷家‐マヨイガ‐」と2時間のOVAが同じ1作品(1ポイント)として扱われるのは解せぬ…。
XQuartz は最新なはずなのに Homebrew がバージョンが古いという


```bash
$ brew doctor
Warning: Your XQuartz (2.7.8) is outdated.
Please install XQuartz 2.7.9 (or delete the current version).
```

最新の XQuartz-2.7.11.dmg をダウンロードしてきてインストールしても警告は変わらない。`Applications/XQuartz` を起動してみると確かに 2.7.11 である。

Spotlight で `xquartz` を検索してみると、どうやらバックハードディスクに古いXQuartz-2.7.8 が存在する。 `brew doctor` は実際に使われている XQuartz のバージョンをチェックしているわけではなく、ひとつでも古い XQuartz がどこかに存在すると警告を出すらしい。古い XQuartz を削除したら（私は古いバージョンの入っている外部ディスクをはずしたら）警告がでなくなった。

```bash
brew doctor
Your system is ready to brew.
```

```bash
brew --version
Homebrew 1.1.7
Homebrew/homebrew-core (git revision 10ab; last commit 2017-01-22)
```
2点を通る円の描画

#小学生の時コンパスで遊んだアレ
貝みたいでやたら書きまくった記憶がある．
pythonで描いてみた．

![c.png](https://qiita-image-store.s3.amazonaws.com/0/96637/41f0270f-a66d-3e55-1a3a-fb4017570f4a.png)


```py:
import matplotlib.pyplot as plt
import numpy as np


def cir_th2p(x,y,p1,p2,r,inv=False):
  def cal_center(p,q,r):
    pt3 = (p + q) * 0.5
    r =r**2
    l1 = (q[0] - pt3[0])**2 + (q[1] - pt3[1])**2
    d  = np.sqrt(r / l1 - 1.0)
    dy,dx= d * (q - pt3)
    pc1 = [pt3[0] + dx, pt3[1] - dy]
    pc2 = [pt3[0] - dx, pt3[1] + dy]
    return pc1,pc2

  def cir_eq(x,y,a,b,r):
    return (x-a)**2+(y-b)**2-r**2

  r=float(r)
  p1=np.array(p1).astype("float")
  p2=np.array(p2).astype("float")
  center=cal_center(p1,p2,r)
  if inv:center=center[0]
  else:center=center[1]
  return cir_eq(x,y,center[0],center[1],r)


delta = 0.1
xrange = np.arange(-3, 3, delta)
yrange = np.arange(-3, 3, delta)
X, Y = np.meshgrid(xrange,yrange)

x=np.logspace(np.log10(1) , np.log10(5) , num=5)

for i in x:
  plt.contour(X, Y, cir_th2p(X,Y,(-0.5,-0.5),(1,0),i),[0])
  plt.contour(X, Y, cir_th2p(X,Y,(-0.5,-0.5),(1,0),i,inv=True),[0])


plt.gca().set_aspect('equal', adjustable='box')
plt.savefig("c.pdf",bbox_inches='tight')

```

#ノート

```
cir_th2p(x,y,p1,p2,r,inv=False):
```
* `x` xの格子
* `y` yの格子
* `p1`1つ目の点．(x,y)の座標で与える．
* `p2`2つ目．
* `r` 半径
* `inv`反転する

この関数，もう少しエレガントに書きたかったけど，急いでいたので強引な実装になってしまった．
気が向いたら整理しようと思う．
ヴォコーダーを作ってみた

## じこしょうかい

- 名前 -> ハル (@Thought_Nibbler)
- 楽器 -> ベース
- WebAudioAPI -> 初級者 

---

## きっかけ

- WebAudio.tokyo #2 に参加
- Advent Calendar の存在を知り参加
- LTさせていただくことに ← いまここ

---

## 今回の内容 = [Advent Calendar 12/8](http://qiita.com/Thought_Nibbler/items/a1ae0622fd3248d5bd6d)

- 作ったヴォコーダーの解説
- なんとなく Electron アプリ
- ソースは Github に
  - https://github.com/Thought-Nibbler/Vocoder

---

## 確認（前提知識）

### 音とは
- 波

![sin.png](https://qiita-image-store.s3.amazonaws.com/0/36612/6608b289-d150-3788-a9a8-8e0c1d322f60.png)


### 周波数とは
- 波が単位時間に上下する回数
- 自然界の音はいろんな周波数の波が混ざっている

### 周波数スペクトルとは
- 波の中にどんな周波数の波がどのくらい混じっているかを表したもの

[フーリエ変換 - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%95%E3%83%BC%E3%83%AA%E3%82%A8%E5%A4%89%E6%8F%9B)

---

## まずヴォコーダーってなんだ？

- 人間の声っぽい音（機械的な声）を出す楽器
- 人間の声≒言葉の発音

[YouTube](https://youtu.be/xgjAg9bMvYo?t=2m45s)

---

## どうやって声っぽい音を作るか？

- Q : 音から言葉（文字）を識別するために、人は何を利用しているのか？
- A : 音（波形）の周波数スペクトル。同じ音を発音するときは周波数スペクトルのピークが近くなる（フォルマント）。

→つまり、人間の声の周波数スペクトルを求めてそのピークを真似てやればよい！

---

## つまりこんなことをやっている！

![vocoder.png](https://qiita-image-store.s3.amazonaws.com/0/36612/298fa151-5152-1862-dcac-bf8dbcbf9805.png)

---

## ただし今回は...

- 楽器音の入力は省いて、`Oscillator`を使った
- `Oscillator`はカスタム波形を作れる
- →基本周波数とその整数倍周波数を混ぜる割合（＝倍音構成）を指定できる

※ピークが倍音と決めつけている（後述）

---

## 今回作ったヴォコーダーの流れ

1. 声を入力する
2. 入力された声の倍音構成を求める
3. その倍音構成を使ってカスタム波形を更新

---

## とりあえずデモを

- 正直微妙

---

## 注意とか

- Advent Calendar に指摘コメントがありました
- どうやら整数倍音では再現できないようです
- このあたり詳しい方いたら教えてください

---

## 以上！
STFをCentOS 7にインストールする

Smartphone Test Farmの自動起動設定をしてみました。（最終的に諦めてますが。）

# 概要

基本的には参考サイトの通りにインストールします。

- 参考：[OpenSTFをCentOS7にインストールしてみた](http://4009.jp/post/2016-02-29-openstf/)

特に問題もなくインストール出来たのですが、少し運用のことを考えて、手順を追加しました。

- RethinkDBに自動起動設定をして、Web UIへのアクセスを可能とする。
- adbに自動起動設定をする。
- STFを自動起動設定する。（諦めました）

# STFのインストール

以下のコマンド参考サイトで紹介されているので、詳細はそちらを御覧ください。
ここでは、超単純にコマンドだけ記載しておきmす。

```
[root@stf ~]# yum install wget git gcc gcc-c++
[root@stf ~]# git clone https://github.com/creationix/nvm.git ~/.nvm
[root@stf ~]# source ~/.nvm/nvm.sh
[root@stf ~]# nvm install 0.12.7
[root@stf ~]# wget http://download.rethinkdb.com/centos/7/`uname -m`/rethinkdb.repo -O /etc/yum.repos.d/rethinkdb.repo
[root@stf ~]# yum install rethinkdb android-tools GraphicsMagick zeromq zeromq-devel protobuf yasm
[root@stf ~]# npm install -g stf
```

# 各種自動起動設定

## RethinkDBの設定

過去の記事を参考にセットアップをします。
Web UIにアクセスしたいのですが、STFの起動させるディレクトリに`rethinkdb_data`というディレクトリがないと行けないので、シンボリックリンクを作成します。

- 参考：[RethinkDBをCentOS7にインストールする](http://qiita.com/tomgoodsun/items/f34f0278504e1c6b98e9)

```
[root@stf ~]# ln -s /var/lib/rethinkdb/default /root/rethinkdb_data
[root@stf ~]# systemctl enable rethinkdb
[root@stf ~]# systemctl start rethinkdb
```

## adbの設定

yumでインストールしているとsystemd用のユニットファイルは自動的にインストールされています。

```
[root@stf ~]# systemctl enable adb
[root@stf ~]# systemctl start adb
```

# STFの自動起動設定（途中で諦めました）

自動起動設定できるといいなと思ったので、試してみました。

本家ではDockerを使った手順が紹介されているっぽいですので、ちゃんとやる場合はそっちに従ったほうがいいかも。

私は気力が尽きました。
以下の方法は自動起動は最終的にエラーになるのですが、systemctlコマンドで起動は出来ます。

```sh:/usr/lib/systemd/system/stf.service
[Unit]
Description = Smartphone Test Farm daemon
After = NetworkManager.service rethinkdb@default.service adb.service

[Service]
ExecStartPre = cd /root
ExecStart = /root/.nvm/versions/node/v0.12.7/bin/node /root/.nvm/versions/node/v0.12.7/bin/stf local --public-ip {IPアドレス}
Restart = always
Type = simple
User = root
Group = root

[Install]
WantedBy = multi-user.target
```

STFの自動起動設定。

```
[root@stf ~]# systemctl enable stf
[root@stf ~]# systemctl start stf
```
rubyでファイルをダウンロード

後で見直すためにメモ

##ファイルを保存する
URLを指定してファイルを保存する

```ruby:hoge.rb
#pathも指定する
filename = "hoge/hoge.rb"
url = "http://hoge.com"
open(url) do |file|
  open(filename, "w+b") do |out|
    out.write(file.read)
  end
end
```

##時刻を扱う

```ruby:hoge.rb
t = Time.now
t.year
t.month
t.day
t.hour
t.min
t.sec
t.usec
```
こんな感じで各種時刻を出力
ファイル名などに時刻を入れたい場合に使用

#まとめ
たまにやり方を探す時に探すのが面倒くさいからメモ
Rancherの用語を調べました

# 馬鹿になれ

> 馬鹿になれ　とことん馬鹿になれ　恥をかけ　とことん恥をかけ
かいてかいて恥かいて　裸になったら見えてくる　
本当の自分が見えてくる
本当の自分も笑ってた　それくらい　馬鹿になれ
-   アントニオ猪木


[前回](http://qiita.com/ryota_hnk/items/71ffd932c8860f95566c)と[前々回](http://qiita.com/ryota_hnk/items/9d91d49d7f3646e7eaa9)で、なんとなくわかった気になったRancher。たしかに簡単だこれは。

でもちゃんと理解してないと運用なんてできるわけない。中途半端な理解でCloudstackを本番環境にブっこんで痛い目にあった俺だからわかる。（気になる方は[コチラ](http://www.slideshare.net/dongkayakuda/cloud-stack-55880199)見てください）

これは危ない。

猪木の言う通りだ。知ったかしないでちゃんと調べよう。

# 各用語の意味というか概念

[この辺](http://rancher.com/cattle-swarm-kubernetes-side-side/)と管理画面のHELPを参考にしました。あとは管理画面の日本語版。画面下部から言語選択できる。ローカライズしてくれた人に感謝。

以下。用語は太字にしてます。

## Environments

* リソースを複数の**Environment**にグループ化できる。
* それぞれが自身の**Service**やインフラリソースを持ち、一人、もしくは複数のユーザで所有できる。
* **Rancher**はいくつかのコンテナオーケストレーションプラットフォームをサポートしていて、それぞれをごっちゃに管理、作成するのではなく**Environment**の単位で分離して管理、作成する。

要するに、いわゆる「本番環境」とか「開発環境」の単位で**Environment**を作って、「開発環境」は誰でも触れるけど、「本番」は運用チームだけ触れるとかそういうことができて、**Environment**はコンテナオーケストレーションプラットフォームに応じて作ることができる。

本番なんだけど、Swarmとkubernetesが入り乱れる環境とかは向かないのかな。そんな人いないだろうけど。

### Cattle

で、環境作成時に選択肢として画面で出てくるのが、「Cattle」「Kuubernetes」「Mesos」「Swarm」「Windows」。

「**Catlle**」て何？他はググればいくらでも出てくる。直訳すると家畜の牛たち。

どうやら**Catlle**はRancherが初めてサポートしたオーケストレーションフレームワークのことらしい。特徴としては

* 最初からあるので熟成されている
* Dockerコマンドがベース
* docker-composeでアプリを定義
* アプリのデプロイは**Stacks**という単位でまとめられる
* アプリは**Catalog**から作成するか、UIで直接指定して作成する。
* **Catalog**は自動的に提供されるdocker-compose.ymlと、rancher-compose.yml（ヘルスチェックとかサービスのスケール設定が入ってるらしい）で提供される。**Catalog**自体はrancher/community-catalogというgithubリポジトリで管理されている。

### Stacks

**Stacks**の構成要素は以下の通り

* 主にDockerImageである**Service**
* スケールに関する情報、ヘルスチェック、サービスディスカバリなどの機能
* 構成可能なホスト

LoadBalance **Service**や外部サービス(物理DBサーバとか)を組み込むこともできる。

### Services

上の方に書いちゃったけど、同一のDockerImageから構成されたグループのこと。

**Service**が同じ**Stack**内の別のサービスにリンクされると、DNSレコードに登録され、発見できるようになる。

APとDBとかの単位でサービス作れば、きっといい感じに負荷分散とかしてくれるんだろうね。


## Rancher

「コンテナ管理ツールだろ？」て思ったでしょ。本来の意味は**農場経営者**です。

Immutable Infrastructureの流れもあり、サーバの扱い自体が愛情込めて大事に大事に扱うペットから、大勢を効率的に監視する家畜化してきている流れを汲んでるんでしょうね。だからCattle（牛さんの集まり）とかStack（干し草）という名前にしたのかもしれませんね。

ちょっとずつ分かってきた。あとはDockerの勉強もしないとなぁ
commit番号毎で、URLにアクセス出来るgalaxyというAPIを作った

# 概要
* アプリを開発する際、`http://commit番号-ドメイン`とかで見れるようになると凄い楽そうだなぁと思い、galaxyというAPIを作ってみました（commit番号は7桁）
* https://github.com/sioncojp/galaxy

# 仕組み
![galaxy](https://raw.githubusercontent.com/sioncojp/galaxy/master/doc/galaxy.png)

* 複雑に見えますがシンプルです。流れとしてはこんな感じです。
    * 事前にDockerをインストール
    * commit番号を保管する"galaxy.commits"テーブルを作成する
    * ベースとなるconfig.ymlを作る
    * `galaxy -c config.yml`　APIサーバ起動
    * `/repository -X POST`　作業用のworkdirを作る * ターゲットとなるリポジトリをgit cloneしたてくる。
    * `/container_proxy -X POST` config.ymlに指定したproxyサーバを立てる
    * `/container/:commit_number -X POST -F "commit_number=99c6894"` commit番号でdocker containerを立てる
        * "workdir/commit番号/"を作成し、"コンテナ：/tmp"にマウントされてる
        * "VIRTUAL_HOSTS変数 = commit番号-config.url"をセット
        * コンテナ起動後、ローカルスクリプトが実行可能（config.script）で、"引数$1 = workdir/commit番号/"となっている。<br>ここでbuildしたものやrailsだとcpなどで"workdir/commit番号/"に移してあげる
        * コンテナ起動後+ローカルスクリプト実行後、コンテナに対しbashコマンドが実行可能（config.docker.exec）
        * コミット番号40桁をDBに登録
    * /etc/hostsを書き換えれば、proxyを介してアクセス可能。
        * 例： `127.0.0.1 99c6894-test-app.com`
        * proxyは`jwilder/nginx-proxy`ベースで、建てたコンテナの"VIRTUAL_HOSTS変数"を読み取って動的に"/etc/nginx/conf.d/default.conf"を書き換える
        * また、workdirが/tmpにマウントされているので、コンテナ毎のapp.sockにアクセスすることが出来る
    * `/container/list` proxy以外のコンテナ一覧を表示
    * `/url/list` アクセス可能なURL一覧を表示



# サンプルその1 - Go
* https://github.com/sioncojp/galaxy/blob/master/doc/sample_go/README.md
* こちらの手順を踏んでもらえると、https://github.com/sioncojp/test-app でお試しできます
* 最終的にはこんな感じになります

![スクリーンショット 2017-01-12 1.34.33.png](https://qiita-image-store.s3.amazonaws.com/0/29405/1b9f2cb2-a6e8-c795-f7d8-32f926fa143e.png)![スクリーンショット 2017-01-12 1.34.24.png](https://qiita-image-store.s3.amazonaws.com/0/29405/3a26fe7f-f522-9398-ff82-312d7ead28de.png)

# サンプルその2 - Rails
* https://github.com/sioncojp/galaxy/blob/master/doc/sample_rails/README.md
* こちらの手順をふんでもらえると、https://github.com/sioncojp/test-app-rails でお試しできます
* 起動に2分くらいかかりますが、最終的にこんな感じになります。
![スクリーンショット 2017-01-23 0.16.28.png](https://qiita-image-store.s3.amazonaws.com/0/29405/f701012d-f8c6-5aca-1306-6305da1b618a.png)
![スクリーンショット 2017-01-23 0.16.23.png](https://qiita-image-store.s3.amazonaws.com/0/29405/63c0bd92-ba46-cddf-0973-cfdf287d9243.png)

# 最後に
* 社内の開発環境として適用出来たらいいなぁと実験をしてます
* 改善点はいっぱい（テスト書かないと）ですので、じっくり育てて行ければなと思います
Xcode8になってからAuto LayoutのUpdate Framesボタンの位置が変わった


# かなりいまさらな話
個人開発では基本的にIBを使わないでコードでViewをいじいじしているのですが，使い捨てのちょっとしたプロジェクトを作ってAuto Layout組んでいる時に「???」となった話です．

制約つけていざ思考停止的に**Update Frames**，と思ったらあれ位置変わんない… しかもconstantの値なんか勝手に変わってる…

![change_update_frame1.png](https://qiita-image-store.s3.amazonaws.com/0/35230/4c281a3b-1eaa-b771-8f21-5be022b67b92.png "change_update_frame1.png")

**Update Frames**がない???

数秒くらい焦って，よくよく見てみるとなんだか新しいボタンが増えている…

![change_update_frame2.png](https://qiita-image-store.s3.amazonaws.com/0/35230/6a1762cd-5be8-9b98-a806-330a9b1c6b06.png "change_update_frame2.png")

ここにいました😅 それだけの話．

# まじめな話
今までAuto Layout組んでいるときって，

1. Auto Layout組む
2. あぁずれてる
3. **Resolve Auto Layout Issues**クリック
4. **Update Frames**クリックしてIssuesを修正

の繰り返しか，制約を追加する度にAdd New Constraintsモーダル中の「All Frames in Container」を指定して修正していました．

この変更によって，後者の場合は特に手間は変わらないんですけど，前者の場合は1クリックで済みますし，subviewを持っているviewがアクティブになっている状態でこのボタンを押せば，subviewらのIssuesを一気に解決してくれるので，地味だけどわりとありがたい変更ですね．
Electronのセキュリティ パーミッション制御

Electronのセキュリティについて話すとき大抵話題になるのはXSSとnodeintegrationによる任意コード実行ですが、それだけ考えていればいいというわけではありません。

Electronのドキュメントでは最低限確認すべき事項をリスト化しており、`BrowserWindow`や`webview`で外部のコンテンツを読み込む場合の注意点に一つ項目を追加したので紹介します。

- [Security, Native Capabilities, and Your Responsibility - Electron](http://electron.atom.io/docs/tutorial/security/)
  - Use `ses.setPermissionRequestHandler()` in all sessions that load remote content (現時点では[masterブランチ](https://github.com/electron/electron/blob/master/docs/tutorial/security.md#checklist)にのみ記載)

## Electronは許可の必要な動作をユーザーに確認しない

例えばカメラやマイクへのアクセス許可です。WebRTCに対応したブラウザで https://webrtc.github.io/samples/src/content/getusermedia/gum/ を開くと、`getUserMedia()`の呼び出しのためにカメラへのアクセス許可を求められるはずです。そのためユーザーの許可なく外部コンテンツがカメラにアクセスすることはできません。

では、このページをElectronで開いてみましょう。何の確認もなく、いきなりカメラの映像が表示されると思います。

```main.js
// 作成時点のバージョン: 1.4.15
const {app, BrowserWindow} = require('electron');
let win;
app.on('ready', () => {
  win = new BrowserWindow({
    webPreferences: { nodeIntegration: false }
  });
  win.loadURL('https://webrtc.github.io/samples/src/content/getusermedia/gum/');
  win.on('close', () => {
    app.quit();
  });
});
```

## 問題点
先ほどの例では外部のコンテンツに対して何の確認もなくカメラへのアクセスを許可してしまいました。よって、Electronの`BrowserWindow`や`webview`で外部のコンテンツを表示したとき、XSSによって悪意あるコードが埋め込まれていてもカメラへのアクセスを許可してしまいます。

WebRTCを使ってカメラの映像やマイクの音声を垂れ流しにしたり、Geolocation APIで位置情報を盗んだりできるのではないでしょうか。(この辺りは詳しくないので、できないのかもしれませんが、攻撃者にデバイスへのアクセスを許してしまう時点であまり気持ちのいいものではないです)

## 対策
`Session`オブジェクト(大抵は`session.defaultSession`)の[`ses.setPermissionRequestHandler()`](http://electron.atom.io/docs/api/session/#sessetpermissionrequesthandlerhandler)を使います。

ユーザーへの確認が必要なAPIを呼び出したときにコールバックが呼ばれるようになるので、判定結果をさらにコールバック関数へ渡します。確認方法自体は用意されていないので、`dialog.showMessageBox()`をコールバック付きで使うのがお手軽です。
Windowsホストからvagrant-sshfsを使ってフォルダ共有してみた

# やってみた
[CentOSのブログで紹介](https://seven.centos.org/2016/12/updated-centos-vagrant-images-available-v1611-01/)されていたので、[vagrant-sshfs](https://github.com/dustymabe/vagrant-sshfs)を入れてみました。
CentOSさん的にはVirtualBoxの共有フォルダよりも、NFSやsshfsを推奨しているようです。

サイトではsftp-serverコマンドが要件となっていますが、[Git for Windows](https://git-for-windows.github.io/) 付属の Git Bash からであれば、`/usr/lib/ssh`にパスを通しておくだけでOKでした。（標準で同梱されていたみたいです）

MSYS2の方は、pacmanでopenssh入れて同様にパスを通せばOKではないかと思います。
Cygwinの方はサイトの記載通り、openssh入れるだけでOKぽいです。


# 感想
VirtualBox Guest Additionsで共有していたころは、 `clang-tidy -fix`が上書きに失敗する（[VirtualBox#4890](https://www.virtualbox.org/ticket/4890)）ので困っていたのですが、sshfsでの共有にしたらうまくいくようになりました。
~~今のところパフォーマンスの違いはあまり感じません。~~

# 積み残し
- VirtualBox Guest Additions との性能比較
- IssueやPR（MSYS2等でsftp-serverが入っていてもvagrant-sshfsが自動検出してくれない）*1 *2

*1: `VagrantPlugins::SyncedFolderSSHFS::SyncedFolder::find_executable`で、ある程度環境に合わせてパスを登録してくれているのだけれど、Cygwinでインストールされる`/usr/sbin`だけで、`/usr/lib/ssh`は登録してくれない。
*2: 環境分岐に使っている `Vagrant::Util::Platform` で、MSYS2として検出するか、Cygwinと同じとして検出してほしいが、そうなってない。（コマンドプロンプトと同じくくりになってしまう）

# 追記：2017/01/24
取り急ぎ普段の使い方で時間を計ってみました。
ホストはSSDで、/vagrant以下のソースコードを、out-of-sourceでtmpfsにビルド。（≒Readのみ）
※rsyncはvagrant up時にエラーが出て、まれにいくつかのファイルがコピーされないことがありました。

|        | real        | user       | sys       |
|:------:|:-----------:|:----------:|:---------:|
| sshfs  | 11m38.785s  | 1m15.201s  | 0m26.677s |
| vboxsf |  1m59.664s  | 1m20.970s  | 1m29.213s |
| rsync  |  0m38.236s  | 1m 3.831s  | 0m 7.747s |
PyPM - ローカルでパッケージインストール

# メモ
- 32bit版active python限定の様子(64bit版だとpypmが入ってなかった)
- [pipがあるからpypmを使わなくてもいい][1]が、pipやpypmでダウンロードできない状況で使えるかも？
- 参考：[How to configure my own local repository? | ActiveState Community Site][2]

# やりかた
### http://pypm-free.activestate.com にブラウザでアクセスしてダウンロード
フォルダ階層を合わせる形にしておく。たとえば、dirsyncを「C:\local-packages」以下におくなら・・・
![dirsync.png](https://qiita-image-store.s3.amazonaws.com/0/34777/81c83909-0c39-bc37-eb75-f51e4ae2898c.png)
※ dirsyncをimportしたときに、sixがないと言われるので、あらかじめダウンロードしています。sixがなくても次の手順は成功します。

### pypmを-Rでlocal-packagesを指定して実行する

```shell-session:dirsync
> pypm -R file:///C:/local-packages install dirsync
```
※ file:のあとのスラッシュは3つ


# 備考
- pipではpygraphvizのインストールに失敗した
- setup.pyを使ってのインストールを試行中

```shell-session:pip
> pip install pygraphviz
... : fatal error C1189: #error :  "Python needs a typedef for Py_ssize_t in pyport.h."
```

[1]:http://docs.activestate.com/activepython/2.7/faq.html#how-do-i-install-a-package-that-is-not-available-in-pypm
[2]:https://community.activestate.com/node/9171
PWAについて

## PWAとは

https://developers.google.com/web/progressive-web-apps/

（主にAndorid端末で）アプリっぽい挙動をするウェブページのこと。
主に、オフライン対応・プッシュ通知、Homeへの追加ができることが強み。

（定義は難しいが、オフライン対応していれば一般にWPAと呼ばれそう。）

---

## なにが嬉しいのか？

アプリとWebのいいとこ取りができる。

- インストール不要
- アプリ審査も不要でアップデートも簡単
- オフラインでもサクサク動く
- 通知もできるしアプリとしてHomeに並べられる。

---

## なにができるのか

- remote/local Push
- 現在地取得
- オフライン対応
  - ページの表示
  - 画面遷移
- Home画面への追加

---

## どうやってやってるのか？

ブラウザの各種API(geo, push, localStorage, history, ServiceWorker)を使っている。

http://qiita.com/y_fujieda/items/f9e765ac9d89ba241154

---

ちなみにブラウザの対応状況
http://caniuse.com/#feat=serviceworkers

http://caniuse.com/#feat=geolocation

http://caniuse.com/#feat=push-api

（Appleはアプリの利用が減るのを懸念してか、Safariへの対応が進んでいない）


---

## 広告&Analytics

- オフライン時は表示も遷移も出来ないと思う。
- オンライン時は、普通のWebページと同じ

Analyticsは、オフライン時にデータを溜めておいて後で送るができるっぽい。
https://developers.google.com/web/updates/2016/07/offline-google-analytics?hl=en
git で push しようとしたら Connection timed out したお話


## 状況
AWS 上から `git push` をしようとしたら、2分ほど待機したのちエラーが返ってくる。

## 原因
AWS のインスタンスのセキュリティグループのアウトバウンドに git 用のポートを指定していなかった。
諸般の事情で git の中央リポジトリは、 22,80,443 といった一般的なポート以外を使うようにしていた。

## 当たり前のことだ。
AWS 使うならセキュリティグループの設定は当たり前のことじゃろ？

## なぜハマった？
インスタンスを構築した人とその上にアプリを構築した人は違う人で、構築してから数年経っており、その人たちはすでにいない状態。
さらにドキュメントも残ってないという酷い状態だった。
そのうえ `git clone` など git を使った形跡があって、それなら普通にできるはずだと思い込んでいた。

おそらくだが、構築中はノーガードだったのだろう。
で、構築完了してからセキュリティ的なことに気づき、設定したものの git の設定をしなかった。
そしてサイト自体は CMS なので、直接ファイル更新することもなく、誰も git を使うことなく今日まで来てしまった。

## 原因究明の旅

### とりあえず git push
`fatal: unable to access 'https://git-no-server.com:00000/git/git-repo/': Failed to connect to git-no-server.com port 00000: Connection timed out`
Basic 認証はかかっていない。
当然 ID/PW は設定されているが、その応答すらでない。
だいたい2分超くらいでタイムアウトしていた。

### git サーバは生きてるのか？
生きてた

### 他のサーバで git push できるのか？
できた

### このサーバ（インスタンス）から git サーバに接続できるのか
`curl https://git-no-server.com:00000/` を発行。
応答: `curl: (7) Failed to connect to git-no-server.com port 00000: Connection timed out`
おっと？

### git サーバでこの ip を制限してないか？
`hosts.deny` -> ない
`hosts.allow` -> フルオープン (それもどうなんだ？)

### このサーバからのアクセスログが git サーバにあるか？
ない

### https の設定か？ (git サーバはオレオレ証明書だった…)
`echo $SSH_ASKPASS` -> 空行
`git config --list` -> `http.sslverify=false` がある
問題なさそう。

### ということは、このサーバから出られてないよね
サーバから出られないといえばファイアウォール。
ファイアウォールといえば `iptables` と思ったけど、基本の AWS インスタンスはそれを利用しない。
全てコンソールのセキュリティグループで行うので、ブラウザからコンソールにログイン。
アウトバウンドに該当のポートの設定がないことを確認。
[ カスタム TCP ルール | TCP | 00000 | 0.0.0.0/0 ] 追加。

### git push
できた！！！！

## 反省
### ドキュメント書こう
ほんと書いてください。

### デザイナも git 使お？
そもそもサイトが設置してあるサーバから push しようって思ったのが、中央リポジトリとサーバに多量の差分があることに気づいたからだ。
どうも歴代のデザイナたちは、必要に応じて FTP でファイルをアップロードしていたようだ。
仕事上作成したならソース1行だろうがアイコン1枚だろうが全て会社の財産なので、適切に管理すべきなのだ。

いちいち git するのは面倒くさい？
それもわかる。
わかるが、お願いします。
Groveの光センサをNefryで使うメモ #nefry #dotstudio


タイトル通りGroveの光センサをNefryで使うメモです。

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

Seeedのサイトは[こちら](https://www.seeedstudio.com/grove-light-sensor-p-746.html)

```light.ino
#include <Nefry.h>

int sensorValue;

void setup() {
  Nefry.print("Grove Light sensor SETUP");
  Nefry.setLed(0,0,0);
}

void loop() {
  sensorValue = analogRead(A0);
  Nefry.print("sensor = " );
  Nefry.println(sensorValue);
  delay(1000);
}
```

`setup()`内で`Nefry.setLed(0,0,0)`を指定していますが、ここでは **NefryのLEDを消灯させています。**

照度センサを使うときには閾値がおかしくなってしまうので大抵の場合はLEDは消しておいた方が良いでしょう。

![](https://i.gyazo.com/5d09acb9dac5775de96d84082a18489d.png)

> LEDつけっばなしで閾値がうまくない例↑
jquery accordion

dl要素の簡易アコーディオンです。
jquery1.7.2で動作を確認。

```ruby:jquery
jQuery(function($) {
  $('.accordion dd').hide();
  $('.accordion dt a').click(function(){
    $('.accordion dd').slideUp();
    $('.accordion dt a').removeClass("is-active");
    var Disp = $(this).parent().next().css("display");
    if(Disp != "block"){
      $(this).parent().next().slideDown();
      $(this).addClass("is-active");
    }
    return false;
  });
});
```

```ruby:html
<dl class="accordion">
  <dt><a href="#">アコーディオン1</a></dt>
  <dd>コンテンツ1</dd>
  <dt><a href="#">アコーディオン2</a></dt>
  <dd>コンテンツ2</dd>
  <dt><a href="#">アコーディオン3</a></dt>
  <dd>コンテンツ3</dd>
  <dt><a href="#">アコーディオン4</a></dt>
  <dd>コンテンツコンテンツ4コンテンツ4コンテンツ4コンテンツ4コンテンツ4コンテンツ4コンテンツ4コンテンツ4</dd>
</dl>
```
AMPについて

## AMPとは何か

- 静的コンテンツを高速で表示するために既存のHTMLを ~~拡張~~ 制限したもの。
- AMPの仕様を満たすHTMLを記載すると、通信回数や表示方法が最適化されます。
- GoogleがAMPの仕様を満たすHTMLを見つけると、キャッシュして高速配信します。
- もちろん普通のHTMLなのでどこでも表示できます。

https://www.ampproject.org/

---

## なぜAMPか

ページの表示が遅いと、特に以下の問題があります。

- 3秒以上かかると、ユーザーの40%は離脱する。
  - 提供者は色んなコンテンツを見てもらえない。
- AdBlockなどで表示速度を上げようとする。
  - 提供者の利益が減り、コンテンツの質が悪くなる。

この解決方法の一つは、特定のコンテンツを扱うことに最適化したプラットフォームを作ること。（スマホアプリなどが該当します）
しかし、これはプラットフォーム依存になるし、検索エンジンやURLでのシェアができなくなるなど、オープンではありません。

---

### そこでAMP

普通のWebで高速に表示することが実現できます。
AMPは、ただのHTMLでの高速表示のベストプラクティスを強制したものです。
利便性・マネタイズは損ねずに速度改善が期待できます。

---

## どうやっているか

- 一瞬で画面のベースが表示される
  - HTMLやCSSは、高さ・幅などの見た目を後から変えられない制約を掛ける
  - 全て最初のレスポンスで返すことで、表示をブロックするものを無くす。
  - 途中で見た目が変わりうるような、承認されてないJSは全て許可しない。

- 画像など重たいリソースの扱い
  - 外部リソースは全て非同期で読み込み、互いにブロックすることはしない
  - AMP JSがコンテンツの優先度から取得する順番を最適化

- Google検索の結果の表示を更に速く
  - GoogleがAMPコードをキャッシュし、ページ開く前にpre-fetch
  - 検索結果画面から、SPA的に画面遷移

全ての条件が揃うと、通信のコスト0で、HTMLの表示のロスがある程度なので数10ms〜100msくらいで表示できる勢いだと思います。

---

### できること

HTMLは、最近FormやButtonに対応したので大体はできます。

CSSは表示サイズを都度変更するものでなければ基本的に使えます。

自前のJSは全て許可されていないため、[こちら](https://github.com/ampproject/amphtml/tree/master/extensions)にコード/Linkが上がっているものだけ対応しています。

- 表示用にハードにチューニングされたUI
  - アコーディオン表示とか
- Ad
- Analytics
- GTM
- 一部SNSのWidget
- iframeを使えるので、そこでJS書く手もある。

など、静的ページで必要なものは一通り揃っているようです。
Analyticsの設定などはJSONに書いてHTMLに置いておくと後でそれを読みます。

---

### できないこと

- 自前で用意したJSの実行
- 上記スクリプトの同期読み込み
  - それぞれが単体で動く必要がある
- 外部CSS読み込み

など、動的なページは作れない。

---

### 気をつけること

AMPはグーグルがキャッシュすることがあるので、Cookieや通信されるドメインに注意する。[参照](https://github.com/ampproject/amphtml/blob/master/spec/amp-cors-requests.md)

画像やCSSは見た目を変えないようにサイズを固定する必要がある。

![Screenshot 2017-01-23 00:08:30.png](https://qiita-image-store.s3.amazonaws.com/0/7185/0fbe5e6f-85e6-f038-6993-503b31c2e194.png)

---

## 作るためのツール

- AMPの仕様を満たしているかチェック
- AMP Cacheに載るかチェック

---

## Vendorに参加する

https://www.ampproject.org/support/faqs/

> How can an advertising or technology vendor get involved in Accelerated Mobile Pages?

> Please review the contributing guidelines and get in touch via Github.