OmniAICreator/Qiita-1.07M huggingface dataset:
新人エンジニアに教えたい Google 検索のコツ

新人と話してて「先輩、ググるの上手っすね」という話になったので、（特に目新しいことは無いと思いますが）普段自分が意識していることを文章にしてみました。

# この記事で書かないこと
- Google の細かい使い方(例: OR検索, AND検索)
- Google 以外を用いた検索テクニック(例: 変数名関数名に迷ったら GitHub で調べる)
- 「エンジニアには英語は必須なので勉強すべき」的な意見(筆者も英語は苦手です)
- 英語に関する学習方法

# (コツ1) 英語でも検索してみる
技術情報は日本語圏よりも英語圏の方が圧倒的に多いので、日本語で見つからない時に英語で探してみるとすぐに見つかることが結構あります。

## 例: 「Windows 用のファイラーを探している」
日本語だと `windows ファイラ おすすめ` といったキーワードになるでしょう。おそらく XFinder, Tablacus Explorer, As/R, Clover あたりがヒットすると思います。

これを英語で検索すると、たとえば `windows file best` というキーワードになるでしょう。上記以外のファイラーもヒットします。日本語検索でしかヒットしないファイラーのいずれも気に入らなかった場合でも、気に入るものが見つかるかもしれません。

## 英語で検索する際の三つの障壁
「英語で調べる」と聞くと難しそうに思えますが、意外とそうでもありません。

英語で検索する時の壁は以下二つがありますが、

- (1)日本語の検索キーワードを英語に直す
- (2) 1 で検索した結果（英語のページ）を読む

1 も 2 も別に英語が上手でなくともこなせます。ここは具体的なテクニックというよりも慣れによるところが大きいです。私も TOEIC でいうと 400-500 あたりですが、今は当たり前のように英語でググって問題を解決できています（100%解決できるかというともちろんそんなことはありませんが、日本語でググっていただけの頃よりは解決率が高くなったのを実感しています）。

# (コツ2) 英語版 Google も使う
英語で検索する際、日本語版ではなく [英語版のGoogle](https://www.google.com/webhp?hl=en) を使うと、より英語圏のサイトにヒットしやすいです。

日本語版に英語を打って検索した時に「なんか目的の情報が見つからないなぁ」と思ったら、英語版で検索してみるとよいでしょう。

# (コツ3) リファレンスサイト名をひっつけて検索する
たとえば Windows 絡みの調査なら「MSDN」を、Javascriptのブラウザ毎の動作状況についての調査なら「MDN」をひっつけて検索すると、それらサイトの記述にヒットしやすいです。

※[MSDN](https://msdn.microsoft.com/ja-jp/library/ms123401.aspx) とは Microsoft 製品の技術情報を載せた公式ドキュメント集です。また [MDN](https://developer.mozilla.org/ja/) とは主に Mozilla がまとめているウェブ情報リファレンスサイトです。

下手なサイトよりも、こうしたしっかりしたサイトの方が情報がしっかりしており、かつ網羅的なので重宝します。まあしっかりしすぎていて気軽に読むには辛い時もあるのですが、これらをサクサク読めるようになれるとかなり楽できます。

# (コツ4) 定番の英語フレーズを使ってみる
これも英語検索ネタですが、英語にも定番の言い回しがあるので、知っておくと探しやすくなります。

| 英語 | 意味 |
| ---- | ---- |
| how to ～ | ～の仕方、～する方法 |
| ～ not working | ～が動かない、～が動作しない |
| cannot ～ | ～できない |
| what is  ～ | ～とは何？（定義など） |
| why ～ | なぜ～なのか、～なのはなぜ？ |
| difference (between) A (and) B | AとBの違い |
| enable/disable ～ | ～を有効/無効にする（方法） |
| is it possible ～ | ～は可能？ |
| best ～ | ～に関するランキングネタにヒットしやすい |
| alternative ～ | ～の代替（代わりになる手段） |

# (コツ5) エラーメッセージをコピペしてググる
よく知られたエラーなら大体ドンピシャでヒットします。

ヒットしない場合、コピペする範囲を絞りましょう。

- 絞るコツ
  - たいていは一文、二文で事足ります
  - 環境固有情報（ファイル名やクラス名やユーザー名など）は省きましょう
  - （エラーメッセージが長い場合は）最初か最後の一文を使ってみましょう

それでもダメならエラーメッセージをもう一度熟読して、エラーの原因を考えてみます。（経験や勘も必要かもしれませんが）「あ、そういうことか！」と次はどんなキーワードで探せばいいかがわかったりします。（特に忙しい時など）安易に「深く考えないでテキトーにコピペして探して答えが当たったらラッキーマン」になってしまうことが多いですが、落ち着いて対処した方が実は早く解決できたりします（経験則） :sweat:

# おわりに
以上、Google 検索している時に意識していることをまとめてみました。参考になれば幸いです。
すごいぞitertoolsくん

## なに
Atcoderなどのプログラミングコンテストでいろいろ試行錯誤しているうちに、itertoolsというライブラリにたどり着いた。古来このライブラリの使い勝手の良さには多くの人が感動してきたと思うが、私もご他聞に漏れず感激したので、いつでも使えるように記録しておく。

## いろいろできるぞ
### 累積和

```python
ary = [1, 3, 5, 7, 9]
cumsum = itertools.accumulate(ary)
```

accumulateを使うとリストの累積和のイテレータが返ってくる。すごい。

```python
print(list(cumsum))
# -> [1, 4, 9, 16, 25]
```

イテレータなので一気に出力するにはlistを使う。numpy.cumsumでももちろん可能だけど……

```python
s = ['ab', 'bc', 'cd']
print(list(itertools.accumulate(s)))
# -> ['ab', 'abbc', 'abbccd']
```
文字列でも使えるのはすごい。

### ある値が何個あるか
groupbyという関数には大変感動した。

```python
bi = [0,0,0,1,1,0,0,0,1,1,0,1]
```

こんなリストにgroupbyを使うと、値をkey,同じ値の集まりをgroupとしたイテレータを返してくる。

```python
gr = itertools.groupby(bi)
for key, group in gr:
    print(f'{key}: {list(group)}')

# 0: [0, 0, 0]
# 1: [1, 1]
# 0: [0, 0, 0]
# 1: [1, 1]
# 0: [0]
# 1: [1]
```

というように、リストの最初から数えて同じ値のものを区切って出力してくれる。groupがイテレータになっているのもあとの処理がいろいろできて楽しい。Atcoderでは大変お世話になりました。

### 忘れちゃいけない組み合わせ
itertoolsの真骨頂ともいえる組み合わせの出力。簡単な全探索ならこれで出力しちゃってもいいんじゃないだろうか(速度はどうなんだろう)。

#### 順列
permutationsという関数にiterableなものを渡すと、全部の順列組み合わせを出してくれる。

```python
print(list(itertools.permutations([1, 2, 3])))
# -> [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
```

第2引数には何個取り出すか選べる。
文字列もiterableなのでもちろん可。

```python
print(list(itertools.permutations('Qiita')))
# ->冗談でやったらめっちゃ出力出てきたんで省略。まあ120通りだもんね……。
```

#### 組み合わせ
もちろんCombinationsもある。

```python
print(list(itertools.combinations([1, 2, 3], 2)))
# -> [(1, 2), (1, 3), (2, 3)]
```

調べて知ったけど、重複を許すCombinationsもあるらしい。

```python
print(list(itertools.combinations_with_replacement([1, 2, 3], 2)))
# -> [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
```

ちょっと使いどころがわからなかった。

直積も便利。例えば0と1の組み合わせをrepeatで指定した桁出力することができる。

```python
print(list(itertools.product([0,1], repeat=3)))
# -> [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
```

まあビットで考えたら早いんだけど、リストにできるのはちょっぴり嬉しい。

## 結局は
[ここ](https://docs.python.jp/3/library/itertools.html)にすべてが載っている……。わかりやすい。

## やりたいこと
上でやれることはだいたいnumpyとかでもできるはずで(cumsumとか)、どちらが速いのかはちょっと気になる。itertoolsのほうが遅いみたいな記事を見たけど、数字は書いていなかったし、都度生成のitertoolsとそうではないnumpy.arrayを比較するにはちょっと工夫がいる気がする。
そんなことを出張中の新幹線車内で書きなぐっていたのでした。
2018年現時点でのパスワードのautocompleteを無効化する方法

パスワードのautocompleteを無効にするにはちょっとしたハックが必要です。
単純に `<form autocomplete="off">` としてもChromeやFireFoxなどでは無効化できません。

これは、開発者の意図よりもユーザーの利便性を優先しているためと思われます。
しかし、開発者も様々な工夫をこらしてこの問題に立ち向かっているようで、検索すると様々なハックを目にします。

ですが、ブラウザベンダーもそれに対抗しており、今では機能しないハックも存在します。

この記事では、2018年5月時点で有効だったハックを紹介します。

## 前提
以下のバージョンで確認しています。

- Chrome 65
- FireFox 59

## 追記
Chromeにおいては `<form autocomplete="new-password">` とすることでautocompleteを無効化できます。
しかし、2018年12月現在、FireFoxでにはこの仕様が実装されていないのでご注意ください。

[autocomplete 属性とログイン欄 | MDN](https://developer.mozilla.org/ja/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion#The_autocomplete_attribute_and_login_fields)

両ブラウザーで対応を行う場合は、以降の内容をご覧ください。

## autocompleteの無効化（うまくいかなかった例）
まず、比較的新しい（2016年）下の記事を参考に実装してみました。
[autocompleteをめぐるChromeとの仁義なき戦い - Qiita](https://qiita.com/saitoxu/items/f565172da3028c1544f7)

記事中では以下のように紹介されています。

```html:引用
<form action="/login" method="post">
  <input type="password" name="dummypass" style="visibility: hidden; top: -100px; left: -100px;" />
  <input type="text" name="username" />
  <input type="password" name="password" />
  <input type="submit" />
</form>
```

ダミーのpassword入力欄を追加し、見えない位置に配置するハックです。
これにより、ダミーの入力欄がオートコンプリートの対象となり、本来の入力欄のオートコンプリートを無効化する狙いです。

しかし、このハックはFireFoxではうまく機能するのですが、現在のChromeでは通用しませんでした。

## autocompleteの無効化（うまくいった例）
上記の例に少し手を加えることでChromeでも機能させることができました。

```diff:修正例
<form action="/login" method="post">
+  <input type="password" name="dummypass" style="top: -100px; left: -100px;　position: fixed;" />
-  <input type="password" name="dummypass" style="visibility: hidden; top: -100px; left: -100px;" />
  <input type="text" name="username" />
  <input type="password" name="password" />
  <input type="submit" />
</form>
```

`visibility: hidden` のstyleを削除しています。
（おそらく、ハック対策のためにhiddenな要素にオートコンプリートを適用しないようになっているのだと思います）

また、確実にダミーを画面外に出すために `position: fixed;` も加えました。

## おわりに
今後、ブラウザ側の対応により上記のハックも使えなくなる可能性がありますのでご注意ください。
このような面倒なことをしなくてもいい時代が来てほしいです… :joy:
[Python] Haskellのキモいフィボナッチ数列をPythonで書いてみる

皆さんはHaskellのキモいフィボナッチ数列を知っていますか？

```haskell
fib :: Num a => [a]
fib = 0:1:zipWith (+) fib (tail fib)
```

無限リストの生成に自分自身を利用している所が，関数型言語っぽい書き方みたいです．[Haskellのキモいフィボナッチ数列がやっと理解できたからこれでもかという程に細かく説明してみた #Haskell](https://qiita.com/Tatsuki-I/items/97bdf8c2579b31b62fd8)を読んでなんとなく理解できたので，さっそくPythonで書き直してみたいと思います．

# 作成したコード
とりあえず最初に書いたコードを示しておきます．

```python
from itertools import chain, islice
from operator import add

def fib():
    yield from chain([0, 1], map(add, fib(), islice(fib(), 1, None)))
```

どうでしょうか？Pythonで実装した割には，それっぽいコードになっていると思います．
利用時の注意点ですが，```fib()```は無限に値を生成するジェネレータ関数なので，以下のように利用すると無限ループしてしまいます．

```python
for n in fib():
    print(n)
```

そのため```itertools.islice()```でのスライスや，for文の途中での```break```が必要です．

```python
print(*islice(fib(), 10))

for i, n in enumerate(fib()):
    print(n)
    if i >= 10:
        break
```

ちなみにこのコードですが，再帰で生成されるジェネレータが指数的に増えるため，残念ながら実用的ではないです．．．
以下の実装をオススメします．

```python
def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b
```

性能は悪いですが，見た目がいい感じで原作(Haskell)に忠実？なので私はとても気に入ってます．

```haskell
fib = 0:1:zipWith (+) fib (tail fib)
```

```python
def fib():
    yield from chain([0, 1], map(add, fib(), islice(fib(), 1, None)))
```

では，これからこのコードについて解説していきたいと思います．

# 最初に書いたコード
[Haskellっぽくフィボナッチ数列を書きつつIEnumerableの評価タイミングを確認](https://qiita.com/yuba/items/2613c824a9ec00cd22d1)のLINQのコードを参考に，最初にこのようなコードを書きました．

```python
def fib():
    yield 0
    yield 1
    for n in (a + b for a, b in zip(fib(), islice(fib(), 1, None))):
        yield n
```

はじめの要素を飛ばしたイテレータの取得のために，```itertools.islice()```を利用しています．ジェネレータは無限に続くため，リストにしてからスライスをするような全体を先に評価する処理はできません．

```python
for n in (a + b for a, b in zip(fib(), list(fib())[1:])):    # これはできない
```

# for文を短くしたい
現在のコードは```zip()```してからジェネレータ式でタプルの加算をしているため，少し冗長です．そこで，Haskellの```zipWith```と同様の動作をするPythonの関数を探した所，```map()```は複数のイテレータを引数に取れることが分かりました．```operator.add()```と合わせて利用することで，```in```以下を短縮します．

```python
def fib():
    yield 0
    yield 1
    for n in map(add, fib(), islice(fib(), 1, None)): 
        yield n
```

# for文でのyieldが気に入らない
ジェネレータから生成される値をfor文で一つ一つ```yield```しているところが気に入らなかったのですが，Python3.3からはサブジェネレータにジェネレータの操作の一部を委譲できる，```yield from```という素敵な構文があるみたいです．これを使って先程のコードを書き換えると

```python
def fib():
    yield from[0, 1]
    yield from map(add, fib(), islice(fib(), 1, None))
```

のようにシンプルになります．
そして，```itertools.chain()```で全体の連結を行って完成です!!!!!


```python
def fib():
    yield from chain([0, 1], map(add, fib(), islice(fib(), 1, None)))
```

# せっかくなのでワンライナーにしてみる
関数定義部分を合わせると2行になってしまっているので，```lambda```を使ってワンライナーにしてみたいと思います．
再帰を利用したコードのワンライナーは，[闇Pythonista入門(Pythonワンライナーのテクニック集)](https://qiita.com/cocuh/items/37bfdc0f24750127e7d3)を参考にしました．

```python
fib = (lambda f: f(f))(lambda f: (yield from chain([0, 1], map(add, f(f), islice(f(f), 1, None)))))
```

自分自身を引数で受け取る```lambda```で再帰を実現しています．ここまで来ると原型を留めていないですね．．．

# おわりに
最初はここまでいい感じに書けると思っていなかったので，自分でも驚いています．このフィボナッチ数列のコードは性能が悪いので実用性は無いですが，```itertools```やジェネレータ・イテレータについての理解が深まったので良しとします．
いい感じにフィボナッチ数列を書けた方がいれば，コメントで紹介して頂けると非常に嬉しいです．
今期アニメ名をスクレイピングで取得する

chinachuでアニメを録画する上で、アニメタイトルを取得する必要があった。
Jsoupを使い、[アニメハック(http://anime.eiga.com/program/)](http://anime.eiga.com/program/)をスプレイピングして、タイトルを取得することにした。

###コード
```main.java
package animeScreiping;

import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

public class main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String url = "http://anime.eiga.com/program/";
		try {
			Document d = Jsoup.connect(url).get();
			Elements ele = d.select("div.seasonBoxImg");
			for(int i=0; i< ele.size(); i++ ){
				System.out.println(ele.get(i).text());
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}

```

###結果
```text:結果
アイカツフレンズ！
あっくんとカノジョ
あはれ！名作くん（第3期）
甘い懲罰～私は看守専用ペット
あまんちゅ！～あどばんす～
ありすorありす
イナズマイレブン アレスの天秤
イラストアニメーションムービー レディスポ
うさぎのマシュー
宇宙戦艦ティラミス
ウマ娘 プリティーダービー
SNSポリス
おしりたんてい
お前はまだグンマを知らない
俺たちゃ妖怪人間G
かくりよの宿飯
Caligula -カリギュラ-
カードファイト!! ヴァンガード（2018）
ガンダムビルドダイバーズ
キャプテン翼（2018）
キャラとおたまじゃくし島
Cutie Honey Universe
キラッとプリ☆チャン
銀河英雄伝説 Die Neue These 邂逅
実験品家族 クリーチャーズ・ファミリー・デイズ
黒猫モンロヲ
グラゼニ
ケッケロケー
ゲゲゲの鬼太郎（第6期）
こねこのチー ポンポンらー大旅行
こみっくがーるず
ゴーちゃん。～モコと氷の上の約束～
ゴールデンカムイ
されど罪人は竜と踊る
シュタインズ・ゲート ゼロ
食戟のソーマ 餐ノ皿 遠月列車篇
重神機パンドーラ
蒼天の拳 REGENESIS
ソードアート・オンライン オルタナティブ ガンゲイル・オンライン
多田くんは恋をしない
立花館To Lie あんぐる
テレビ野郎 ナナーナ
デビルズライン
デュエル・マスターズ！（2018）
東京喰種トーキョーグール：re
奴隷区 The Animation
ニル・アドミラリの天秤
信長の忍び～姉川・石山篇～
ハイスクールD×D HERO
バディファイトＸ オールスターファイト
Butlers～千年百年物語～
パズドラ
ひそねとまそたん
一人之下 全性篇
ヒナまつり
美男高校地球防衛部 HAPPY KISS！
ピアノの森
踏切時間
フューチャーカード　神バディファイト
フルメタル・パニック！Invisible Victory
ベイブレードバースト 超ゼツ
PERSONA5 the Animation
鬼灯の冷徹（第弐期その弐）
僕のヒーローアカデミア（第3期）
魔法少女 俺
魔法少女サイト
メガロボクス
メジャー セカンド
妖怪ウォッチ シャドウサイド
ラストピリオド ―終わりなき螺旋の物語―
3D彼女 リアルガール
ルパン三世 PART5
レイトン ミステリー探偵社 ～カトリーのナゾトキファイル～
鹿楓堂よついろ日和
LOST SONG
Lostorage conflated WIXOSS
若おかみは小学生！
ヲタクに恋は難しい
アイスくりたろう
ケッケロケー（タテアニメ）
ちびあいりんのゆるやかな日常
トキノ交差
```
Cognos Analytics 11.0.11 新機能紹介

#Cognos Analytics 11.0.11 リリース
Cognos Analytics 11.0.11が先週末にリリースされました。

**Cognos Analytics Release R11 (11.0.11) is here!**
https://www.ibm.com/communities/analytics/cognos-analytics-blog/cognos-analytics-release-r11-11-0-11-is-here/

主たる新機能は、以下の4点のようです。

今後実際の環境で検証して、新機能を紹介するリンクを作成して、本記事を更新していきます。

**地図機能の拡張**
レポートやダッシュボードでの地図機能に、自作のポリゴン表示を重ねて表示できるようになりました。

**ページの機能(一部)復活**
これはうれしいです。Cognos 10 BIで使用できた、「ページの機能」が復活したようです。
<2018/5/17追記>
こちらに詳細情報を投稿しました。完全復活とまでは行かないようですね。
**Cognos Analytics 11.0.11 新機能 - Portal Pages の機能**
https://qiita.com/shinyama/items/69fd135c10a326a7a568

**ダッシュボードでのキャッシュの利用**
ダッシュボードの機能で、キャッシュが利用できるようになり、パフォーマンスの向上が期待されます。

**Cognosポータルのコンテンツの可視化の設定**
コンテンツを全体的に見えるか見えないかの設定ができるようになりました。

今後の情報Updateにご期待下さい。
NanoPI NEO2にGPSをつなぐ（PPS編）

# 摘要
上一次，我写了一篇关于将GPS连接到没有PPS的NanoPI并同步Chrony以创建NTP服务器的演讲。 除了连接器周围没有连接，因此可以在不焊接的情况下制造。 但是，由于GPS具有PPS功能，因此无法使用它。 这次，我将制作一台高精度的GPS NTP服务器，这需要焊接但使用PPS。

# はじめに

前回、PPSなしでNanoPIにGPSを繋ぎChronyを同期させNTP Serverを作る話を書きました。コネクタ回り以外接続は行わないのではんだ付けなしに作れます。でも、折角GPSにPPS機能がついているのですからこれを使わない手はありません。今回は、はんだ付けがいりますがPPSを使った、高精度のGPS NTP Serverを作ります。

# 準備

まず、[NanoPI NEO2にGPSをつなぐ(PPSなし）簡易編](https://qiita.com/maclineto/items/5236bb31fe1ec271c672)をすべて実行しPPSなしのNTP Serverを作ってください。

#  pps-toolsの導入

```
apt  install pps-tools
```

# 設定
## /boot/armbianEnv.txt

GPIO18をPPS入力に指定します。
```
dtoverlay=pps-gpio,gpiopin=18
```
私のようにRoot FSをMaicroSDでなく、SSDにしている場合、これはboot時の指定ですので、MicroSDにあるFileを変更しなくてはなりません。

```
mkdir /a
mount /dev/mmcblk0p1 /a
vi /a/boot/armbianEnv.txt
```
## /etc/modules
必要なmoduleを指定します。
```
g_serial
pps-gpio
```
## /etc/chrony/chrony.conf
クロックソースにPPSを追加

```
# information about usuable directives.
pool ntp.jst.mfeed.ad.jp
refclock SHM 0  delay 0.5 refid NEMA
refclock SHM 1 offset 0.0 delay 0.1 refid PPS
```

# halt
halt commandでSystemを一旦停止し電源を切ります。
 
# 配線

大したことありません。NanoPI コネクタのGPIO18 (pin12)とGPSの１PPSを接続します。
USBシリアルを繋ぎGPSもつないでPower On!

# 確認

```
#  lsmod | grep pps
pps_ldisc              16384  2
pps_gpio               16384  0
```

```
# chronc
> sources
210 Number of sources = 5
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#- NEMA                          0   4   377    18   +218ms[ +218ms] +/-  251ms
#? PPS                           0   4     0     -     +0ns[   +0ns] +/-    0ns
^* ntp1.jst.mfeed.ad.jp          2   6   177    35   -415us[ -378us] +/-   75ms
^+ ntp3.jst.mfeed.ad.jp          2   6   177    36   +535us[ +572us] +/-  114ms
^+ ntp2.jst.mfeed.ad.jp          2   6   177    39   +275us[ +312us] +/-  101ms
```

# 結論

またしてもあっさり繋がりStratum 1のNTP Serverが出来上がりました。使用したLinux Kernelを/proc/config.gzで確認したところPPS用にBuldされていたのでKernel Buildは行わずに済みました。
URLがSlackで展開されない理由

## SlackのURL展開条件おさらい

前回、[Qiitaの記事がSlackで展開されない理由](https://qiita.com/harunbu/items/491e7200137dbf9f5710)を調べ、
**`og:description`にHTMLタグが混じるとプレビューが展開されない**という事実が判明しました。

SlackのURL展開には[OGP](https://cont-hub.com/knowledge/glossary/ogp/)用に設定されたメタデータが利用されます。
具体的には`<meta property="og:description" value="hogehoge">`というタグが必要です。
（他に`og:title`や`og:image`も使われますが、`og:descrption`だけでも存在すれば展開はされるようです）

Qiitaの場合は、本文の先頭117文字が`og:description`に採用されるため、
ここにHTMLタグを含ませると、`og:description`にもHTMLタグが含まれる状態となってしまいます。
こうなるとslackで展開されない記事になってしまう、というのが[前回の記事](https://qiita.com/harunbu/items/491e7200137dbf9f5710)での結論でした。

slack側でのパースがうまくいってないってことですかね。

※HTMLタグというよりも、**`<`が含まれているとアウトで、`>`だけであればセーフ**のようです。
また、[特殊文字](http://weblan3.com/html/special-character.php)にエンコードされていてもダメです。

## 展開されないページ

こちらのURL。

> Windows 10 / Windows Server 2016 の Windows Update 後の自動再起動の制御方法
https://blogs.technet.microsoft.com/jpwsus/2018/02/08/manage-reboot/

ソースを見ると、ちゃんと`og:description`が設定されてます。
また、内容にも、`>`は含まれているものの、`<`は含まれていません。
ちゃんと展開されるように見えますが、このURLをslackに張り付けても、**展開されません。**

## 調査

元ページの`<meta property="og:description">`を空のページにコピペして試してみると・・・**展開されます。**
しかし、`<head>`～`</head>`をコピペしてみると・・・**展開されません。**

うーむ・・・`<head>`の中に原因がありそうです。

内容を少しずつ減らしたりもとに戻したりしながら調べてみたところ、
以下の`<div>`タグが`<head>`内に含まれているのを見つけました。

```html
<div id='msccBanner' dir='ltr'>（省略）</div>
```

これはアヤシイ！

## 原因

HTMLでは、[いくつかの閉じタグは省略することができます。](https://qiita.com/labocho/items/54fd70c73ced35c8ba49)
`</head>`も省略可能です。

前述のページのソースコードには、`<div>`の後ちゃんと`</head>`が出てきます。
しかし本来、`<div>`は`<head>`内に含めることはできません。
slack側のHTMLパーサがHTMLを解析する際、**`<div>`が来た時点で`<head>`の終わりと判断され、
その後の`<meta>`が認識されなかった（`<head>`の中ではないので無視された）**
のではないかと思います。

試しに件の`<div>`を`<head>`の一番下に持ってくると、ちゃんと展開されます。

## 感想

マイクロソフト公式のブログでこういった問題が発生しているのはなんだか不思議な感じです。
slackでちゃんと展開されるページを作りたければ、正しいHTMLでページを作りましょう。
【PHP】foreachで繰り返す回数を指定する

```php
$i=0;
foreach ($array as $key => $value) {

	if($i>count($array)){
		break;
	}

	if ($array[$key]==$array[$key+1]) {
		unset($array[$key]);
	}

	$i++;

}

```

たとえば、多次元配列内で重複する要素がある場合、その要素を削除したい場合などに利用できます。
attrgetterを使って読みやすいソート

タプルやリストでソートする際、ソートkeyを指定することがあると思いますが、keyを変数名で指定してより見やすくなる方法を知りました。ここにメモしておきます。

よくkeyの指定ではlambda式が用いられていますが、attrgetterというものを使えばより見やすく書けるみたいです。

```python
from operator import attrgetter
class Student:
    def __init__(self, name, grade, age):
        self.name = name
        self.grade= grade
        self.age = age
    def __repr__(self):
        return repr((self.name,self.grade,self.age))

student_objects = [
    Student("john","A",12),
    Student("aeha","C",71),
    Student("argea","F",2),
]

print(sorted(student_objects, key= attrgetter("age")))
```


出力結果
`[('argea', 'F', 2), ('john', 'A', 12), ('aeha', 'C', 71)]`

print文の箇所をlambda式で書くと
`print(sorted(student_objects, key=lambda x: (x.age,)))`

となるので、記号xやわかりにくいカンマが入らない分、少しばかり見やすくなったと思います。

###参考にしたサイト
https://docs.python.org/2/howto/sorting.html
https://qiita.com/tag1216/items/485217b5c88dfcf00d34
ConstraintLayoutのGroupでView.INVISIBLEが効かない

# バグ！？
View.GONE は出来るけど View.INVISIBLE は出来なかったので、下記の方法で対応しました。

バージョンは↓です。

```
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
```

TextView ２つをグループ化

```xml:content.xml
<android.support.constraint.Group
    android:id="@id/text_group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:constraint_referenced_ids="textView1,textView2"
    tools:ignore="NotSibling"/>
```

View.VISIBLE, View.INVISIBLE の前に View.GONE を挟むと上手くいきました。。。

```kotlin
if (text_group.visibility == View.VISIBLE) {
    text_group.visibility = View.GONE
    text_group.visibility = View.INVISIBLE
} else {
    text_group.visibility = View.GONE
    text_group.visibility = View.VISIBLE
}
```
【HTML5】<font>タグのsizeとCSSのfont-size対応表

#目的
fontタグはHTML5では廃止されているので、CSSで換装したい。
その際に役立つ換装表。ググっても意外と出てこなかったので残しておきます。
#表
|fontタグの size|CSSの font-size|
|:-:|:-:|
|1  |x-small  |
|2  |small  |
|3  |medium  |
|4  |large  |
|5  |x-large  |
|6  |xx-large  |
|7  |-webkit-xxx-large |
LINE Messaging API をいじって気づいたこと（メディア編）

最近Messaging APIをいじりまくっていて気付いた点をまとめようと思い備忘録的に記録していきます。<br/>
※：これは投稿時点でのAPIの動作になりますので、今後変わる可能性があります。

#Messaging APIでのメディアの制限について
##画像について
- 画像の解像度について
    - 1024px以上のサイズも受け付けるが、APIの仕様に沿っていないため、おすすめできない。
- 公開した画像ファイル
    - 公開済みの画像は一度ユーザーが表示した後は、画像ファイルを削除してもLINE側で表示されている。これはLINEで画像送信した時と同じで一度表示したりしてアクセスした画像はLINE側で保持し、しばらくたったら削除されるようです。
    
##動画について
- 動画の拡張子がmp4のみ
    - 実は拡張子がmp4以外のファイルのURLでもAPIは受け付ける。<br/>ただし音声が再生されない等、動作が保証されない。

# 所感
今のところAPI側の動作がイマイチ制御しきれていないと考えられるので、Messaging APIを利用するサービス側できちんとAPIの仕様にそった制御をかけるほうが安全だとは思います。
しかし、イメージマップはPNGがOKで画像送信は明示的にOKしていないのは何か理由があるのでしょうか…。
fzfでインタラクティブにgit checkout する

# 対象

ブランチ変更時に毎回 __feature/__ とタイプするのが面倒、またそのためのだけにGUIを使いたくないという人向け。

# やりたいこと

gitでのブランチ変更を`fzf` (or `peco`)などのinteractive grepと組み合わせて、 ブランチ一覧からインタラクティブにブランチ変更したい。

# 結果

![qiita_git.gif](https://qiita-image-store.s3.amazonaws.com/0/67790/e5adba83-59c8-61c0-b92a-31b00f0fe222.gif)

# やったこと

`git branch` の結果を`fzf` で選択して、 `xargs` で `git checkout`する。

```sh
git branch -a | fzf | xargs git checkout
```

これを`git cof` というエイリアスに定義しているだけ(checkout fzfでcofとしているだけです)。

```yaml:~/.gitconfig
# ~中略~
[alias]
    cof = !git branch -a | fzf | xargs git checkout
```

もちろんshellのrcに定義してもOKですし、peco使ってる人はfzf→pecoで問題なく動くと思います。

aliasを定義できることはgitをCUIで使う時大きなメリットとなると思います。
ConstraintLayoutでincludeレイアウトが指定位置に表示されない

ConstraintLayoutでincludeレイアウトが指定位置に表示されなくて地味にはまったので備忘録として残しておきたいと思います。

リストUIの区切りとして下記dividerを用意してinclude。

```xml:divider.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical">
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#555"/>
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#999"/>
</LinearLayout>
```
layout_width, layout_height を忘れずに！

```xml:content.xml
・・・

    <include
        layout="@layout/divider"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/textView3"
    />

・・・
```

これで任意の場所に表示できました。。。
クレジットカードの登録不要！無料で使えるモックアップ環境比較[now/heroku/firebase]

# はじめに
・ささっとモックアップを作りたい
・ちょっとした検証用のサイトを作りたい
・簡単にプッシュ通知できるアプリを構築したい
そんなことございませんか？

そのような場合以下のような選択肢があると思います。
・社内にある環境を利用する
→外部に公開するにはなかなか抵抗がありますね。
・AWSなどでEC2を利用したりLambda/S3のサーバーレス環境を構築
→クレジットカードの登録やら、組織に属している場合はその許可をもらったり。。。

もっと簡単にデプロイしてすぐにチェックできるやりかたはないものか。

そんなとき私は以下の３つを使いまわしております。
・now
・heroku
・firebase functions/hosting
主観で比較記事を作成しますが、他にもあったらコメントお待ちしてます。
まだ完璧にフィットしたサービスを見つけていませんので。
(無料でつかっているのに何文句言っているんだって感じですね・・・)

ちなみに普段はMacを使用しています。

# サービスの比較
先人の知恵を拝借してサービスの説明をしたいと思います。
## nowとは
https://qiita.com/nkzawa/items/8bf62549f79ebbcaafd8
https://qiita.com/high-u/items/2dcef131002db3036291

## herokuとは
https://qiita.com/Arashi/items/b2f2e01259238235e187
https://qiita.com/daisukeoda/items/42e802c498ca8a78b8f2

## firebaseとは
firebaseはmBaasと呼ばれてますが、
functionsとかhostingとかもはやなんでもありです。
https://qiita.com/kohashi/items/43ea22f61ade45972881
https://qiita.com/gupuru/items/25a6722f6f802d3a5250

# どんな時に使い分けたらいいの？
## iOS/Androidアプリと連携したものを作りたい
Firebase一択です。
Firebase functionsとCloudMessagingなどを活用することで、
プッシュ通知をとても簡単に実装することができます。
それだけでなく、特定のグループやトピックなどへの通知の出しわけも可能です。
RealTimeDatabaseという機能も使えたり、これ本当に無料か！？というレベルですね。

ただし無料で利用するに当たって大きく１つ問題点があります。

Google以外のAPIやURLへリクエストを送ることはできません。
例えばこんなケースです。
・Line bot/notifyのサンプルをサクッとつくりたい
・IFTTTのMakerへリクエストしたい
・AWSのApiGatewayやLambdaへデータを送りたい
そんなことは（無料環境では）不向きです。

ちょっと他の２つのサービスと違って土俵が違う感じはありますが、
似たようなことを実現できます。

## 機械学習系のデモサイト構築
これはherokuを選択しています。
nowでもDockerFileを利用することでPython環境などを構築できるらしいのですが、
面倒なので試してません。
herokuの場合はstaticフォルダ配下に学習済みモデルファイルを配置して、
予測などに使っています。
とはいえ無料環境だとメモリが足らずにエラーが起きることが多いです。
１から学習させたMNIST的な文字予測モデルを構築した時はエラーもほぼおきなかったのですが、
Kerasでファインチューニングしたモデルを組み込んでみたのですが、５割くらいはエラーがでていました。

## とにかく素早くwebアプリを公開したい
nowです。名前の通り「今すぐ！公開したい！」そんな時はnowを選択します。
無料アカウントでデプロイできる数がherokuは５個に対してnowは原則無いです。
上のサービス紹介のページのURLでは20という情報もあるようですが、今のところ困ってはいないですね。
１つのプロジェクト単位で複数デプロイができます（履歴のように残っている感じです）がそれは３個までとなってますので、
ちまちま不要となったら消したりしています。
そんな状況を踏まえても便利ですね。

なおherokuとnowの無料プランでは一定時間アクセスがないとアイドル状態になります。
これは例えばモックといえども自分の手の届かない人たちがチェックする時につらみがありますので、ご注意ください。

# 個人的なまとめ
・アプリのデモ作りたい → Firebase
・アイドル時間は無しがいい！ → Firebase
・認証/解析とかも簡単にやりたい → Firebase
・機械学習系サクッとデモ → heroku
・Paasになれてない。検索して情報が多いのがいい！ → heroku
・すぐデプロイ/すぐチェックしたい → now
・５個だとちょっと少ないな → now
・AWSとかと連携を！ → heroku/now
結果としてどれも好きです！いつもありがとうございます！
WindowsPEのPXEサーバーを作った

# WindowsPE用PXEサーバーの構築手順
## 前提条件
今回はあくまでも技術検証としておこなうことを目的としたため192.168.0.0/24(ローカルエリアネットワーク)内にWindowsPE環境を構築したPXEサーバー用PC(192.168.0.1)とPXEブートを行うPC(192.168.0.2)を設置した(GWはなし).

## 構築手順
- tftpd64,windowsADKをダウンロード
	[tftpd64](http://www.jounin.net/tftpd32_download.html)
	[WindowsADK](https://docs.microsoft.com/en-us/windows-hardware/get-started/adk-install)
	それぞれzipの解凍なりインストールを行う.
	WindowsADKのインストールは大抵2〜30分かかります.

- WindowsADK「検索」に「展開」と入力し展開及びイメージングツール環境を管理者として実行しcopypeコマンドを実行.

#### copypeコマンドについて
Copype ツールは、Windows プレインストール環境 (Windows PE) ファイルの標準セットを含む作業ディレクトリを作成します。これらのファイルを使ってイメージ (および Makewinpemedia スクリプト) をカスタマイズし、起動可能なメディアを作成します
(https://msdn.microsoft.com/ja-jp/library/windows/hardware/dn898514(v=vs.85).aspx)
	
copype.cmdの第2引数はx86(32bit),amd64(64bit),arm(スマホ向け?)が指定可能なので状況に合わせて選択

今回はamd64で実行したと仮定する.

```text:64bit用
copype.cmd amd64 C:¥winpe_amd64
```

実行できた場合
**C:¥winpe_amd64**, **C:¥winpe_amd64¥fwfiles**, **C:¥winpe_amd64¥media**, **C:¥winpe_amd64¥mount**ディレクトリが作成される.

Dismコマンド使ってC:¥winpe_amd64¥mount以下にイメージファイルをマウント
	
```
Dism /mount-image /imagefile:C:¥winpe_amd6¥media¥sources¥boot.wim /index:1 /mountDir:C:¥winpe_amd64¥mount
```

解凍したTFTPD64フォルダ内に**PE-BIOS**ディレクトリを作成

**C:¥winpe_amd64¥media**以下全てを**PE-BIOS**内にコピペ

**C:¥winpe_amd64¥mount¥Windows¥Boot¥PXE**内のbootmgr.exeとpxeboot.n12をPE-BIOS¥Boot内にコピペ

「検索」に「tftpd64」と入力しtftpd64を起動
	
下部にあるSettingsを選択
	
TFTPタブを開きBaseDirectoryにBrowseからPE-BIOSを指定

- DHCPタブ
	- IP pool start address欄に192.168.0.10
	- Size of Pool欄に10
	- Lease欄に2880
	- BootFile欄にPE-BIOSからの相対パスでBoot¥pxeboot.n12のパスを指定
	- Def. router〔opt3〕欄に192.168.0.1
	- Mask〔opt1〕欄に255.255.255.0
	- DNSServers〔opt6〕欄に192.168.0.1
	- DHCPSettingsのBind DHCP to this addressにチェックをつけ今設定したipアドレスを選択

- SYSLOGタブ
 - 「Syslog Server」のチェックを外す

右下のOKをクリック.警告が出たらそれもOKをクリック

tfptd64を起動

PXEブート用のPCをメーカーごとの操作方法でBIOS画面に入りネットワークブート

参考サイト
ADKのインストール: http://rms-099.hatenablog.jp/entry/2015/10/04/053336
TFTPD64の設定関連: https://www.youtube.com/watch?v=JqxBbn5xhDo
(TFTPD64のファイル構成が若干違うので注意, 動画ではローカルの仮想環境を動かしているのでそこも注意)
Intervention Imageで「Unable to init from given binary data.」に悩まされた話

# 解決策
gd拡張にjpeg supportをつけてビルドする

# 経緯
```php
use Intervention\Image\Facades\Image;

function hoge($image_url)
{
    Image::make($image_url)->//処理
}
```
上記のようなコードで、「Unable to init from given binary data.」のエラーのみが出て原因が分からず...

[issue](https://github.com/Intervention/image/issues/634)を見て解決。
ありがとうございます🙏

悩みまくったのでメモ

GD使わずImagick使おう!!!!
【Facebook】ポリシーのアップデート＆Graph API v3.0 リリース

GW中に、Facebookページ管理人宛てにメールが届いていました。
　
Facebookプラットフォーム製品の新たな変更とポリシーのアップデートがあったので**「changelogを読んでね！」**とのこと。
https://developers.facebook.com/docs/graph-api/changelog/breaking-changes/?translation

　
ざっくり調べてみたところ、複数機能の廃止と、一部機能が 2018年8月1日に廃止されます。

- Facebookアナリティクスで使用されている App Insights API の 「app_event」
- Facebookアナリティクスで使用されている Graph API の 「application_analytics_app_events_exports」
- Facebookログイン
- InstagramグラフAPI
- Messengerプラットフォーム　など


『Facebookページの表示だけ』、『「いいね！」「シェア」ボタンの表示だけ』 など
シンプルな機能のみを使用している場合は、影響がなさそう* ですが、
言語などの振り分けも廃止になった他、年齢制限を設けているページ（酒類など）では、「age_min」に設定できる値が「13、17、18、19、21」のみになったので、確認や調整が必要になりそう。
（※念のため、後日きちんと調べます。）
 
　
なお、アプリには再審査が必要になるようです...。
（参照）
●Enhanced Developer App Review and Graph API 3.0 Now Live - 開発者向けFacebook（公式）
https://developers.facebook.com/blog/post/2018/05/01/enhanced-developer-app-review-and-graph-api-3.0-now-live/
●Facebook Graph API v3.0 リリースと同時にログイン審査がリニューアルされた件
https://damelog.com/sns/facebook/facebook-graph-api-v3_0-released-and-app-review-restored/
コーディングいらず！GUIでお手軽に自然言語処理実装ができる「Dialogflow」の紹介

![Dialogflow_dsa.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/1852681f-3f7c-38fd-f79b-47ec82b489bc.png)

※この情報は2018年4月26日（木）のものです。

データサイエンスアカデミーの河部です。
今回は、自然言語処理ツールが実装できるDialogflow(旧:api.ai)を紹介します。


#まず簡単に「データサイエンスアカデミーって何？」
次世代のデータサイエンティスト人材の育成・輩出を行う会社です。
現在、自社ブログでもデータサイエンスに関するコラムを連載しております。
ご興味がある方は、ぜひご一読ください！
[ブログについてはこちら](https://d4c-academy.org/topics/category/column)

それでは今回の本題に入っていきましょう。

#Dialogflowとは？

Googleがサポートしている自然言語処理系のサービスです。
「今日の天気を教えてください」という質問に対して
「今日は晴れです」と返すチャットボットなどをつくることができます。

Dialogflowで作成したチャットボットなどは、
GoogleHomeなどのハードウェアや、Twitter、スカイプ、
Facebook Messenger、Slackなどのアプリと連携させることが可能であり、
ユーザーとコミュニケーションを図ることができます。

本記事では、登録した内容を返すだけの
簡単な自然言語処理ツールを作成方法を紹介します。

#まずは公式サイトに行き登録

公式サイトへ行きます。
https://dialogflow.com/


![1.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/cf42b3c9-231b-dff4-a946-7731390813c7.png)
![2.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/bf1cc3df-62ef-1dae-486e-5ff2b6dee4ad.png)





#エージェントの作成
自然言語処理を行うエージェントを作成します。
![3.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/390b587a-9e45-169f-5196-36e2656b506c.png)



必要な情報を登録します。

![4.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/e9db3acc-c8fb-94c5-2257-2ea330ddc092.png)



#質問内容と関連するキーワードをテキストにまとめる
ユーザーから届く質問はどんなものか、関連するキーワードは何か
メモ帳やノートなどのテキストにまとめます。
想定した質問内容とキーワードは以下の通りです。

| 質問内容 | キーワード|
|:-----------|:-----------|
| データサイエンスアカデミーとは何か |データサイエンスアカデミー |  
| セミナーは何をしているのか     | セミナー |   
| セミナーの日程は？      | セミナー|   


#質問内容に関連するキーワードをEntitiesに登録する
Entitiesとは、自然言語を認識するために単語をまとめて置いておく場所です。

![5.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/d3970c5c-6ad4-34de-e6f1-53b3f27578b0.png)


「データサイエンスアカデミーとは何か」という質問に対して、
関連するキーワードは何か入力します。
![6.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/8f82d99e-c708-bb09-f485-85eaa356d692.png)


タイトルは、英語名でしか入力できないので気を付けてください。
どんな入力があるかわからないので、1単語につき、英語、カタカナ、かなを入力しておきます。
最後は、SAVEをクリックして保存します。


#質問内容をIntentsに登録する

Intentsとは、ユーザーからの質問内容を置いておく場所です。
![7.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/005bdddf-aa58-6020-0d6e-5b0e99d7975e.png)


質問1つにつき、Intentsを用意します。
質問内容を入力し、SAVEをクリックして保存します。
![8.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/36a33e61-d3db-f051-8732-30f6cd95a08a.png)



「Action and parameters」に
EntityとIntentsの結びつきが表示されます。
![9.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/f3b372f6-1f0f-1515-55c5-20b4233340a0.png)



質問への回答を入力し、SAVEをクリックして保存します。
![10.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/3b01ea54-aac2-1ca7-5e2f-458751708d03.png)


#試験
Try it nowに「データサイエンスアカデミーについて教えてください」と入力します。
質問内容に該当した返答が得られれば成功です。
![11.PNG](https://qiita-image-store.s3.amazonaws.com/0/253492/a332eaac-5784-db7d-d1ae-6370acd9a0cc.png)


#この他にも自社ブログで技術系コラムを連載中！
データサイエンスアカデミーでは自社ブログでも
データサイエンスに関するコラムを連載しております。
ご興味がある方は、ぜひご一読ください！
[ブログについてはこちら](https://d4c-academy.org/topics/category/column)
ラズパイ起動と共にpm2でスクリプト起動


ラズパイ3が起動したらslack-bot.jsというスクリプトをpm2で自動起動させたい

foreverでやってみようと頑張ったが、pm2でやったほうがはるかに簡単だった

## 前提
- ラズパイは起動設定済み
- npmとnodejsはインストール済み

# pm2インストール

```
$ npm i -g pm2
```

# まずスクリプト実行

```
$ pm2 start main.js --name slack-bot
```

`--name`オプションで`slack-bot`というアプリ名で実行できる。

名前指定したほうが絶対便利なのでオススメする

# 自動起動スクリプトを作成

マシンに自動的に設定された起動スクリプトを取得するには、次のコマンドを入力する必要がある。

```
$ pm2 startup
```

どうやらOSによって自動起動させる構成が違うらしく、それを`pm2 startup`がよろしくやってくれるようだ。

startupのログ

```
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi
```

メッセージに、「スタートスクリプトを設定するには以下のコマンドをコピペしてね」、と出たので
`sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi`

さっそくこのコマンドをコピペで実行してみる

```
$ sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi
```

ログの最後あたりに`[DONE]`と表示されていればOK

あとは起動するアプリを保持するため以下を実行する

```
$ pm2 save
```

これで設定は完了

確認としてラズパイを再起動してみる

再起動後、ssh接続して

```
$ pm2 list
┌───────────┬────┬──────┬─────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
│ App name  │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
├───────────┼────┼──────┼─────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
│ slack-bot │ 0  │ fork │ 720 │ online │ 0       │ 15m    │ 0%  │ 53.8 MB   │ pi   │ enabled  │
└───────────┴────┴──────┴─────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
```

slack-botが無事に自動起動していた！

これにて任務完了

## 参考リンク
- 公式 [PM2 - Startup Script](http://pm2.keymetrics.io/docs/usage/startup/)
Macにhomebrewを使ってjavaとandroid-sdkをインストールする

## javaをインストールする

- javaがインストールされているかどうか調べます
- バージョンが表示されればインストールされています
- javaがインストールされていなければ、javaもついでにhomebrewでインストールします

```bash
 java -version
```

- homebrew 自体はインストール済みの前提です
- javaのインストールでもandroid-sdkのインストールでもcaskが必要なので使えるようにtapします


```bash
brew tap caskroom/versions
```

- caskを使って最新バージョンのjavaをインストールします

```
brew cask install java
```

- 必要ならjava8などもインストールします

```bash
brew cask install java8
```

- インストールしたjavaを確認します

```bash
/usr/libexec/java_home -V
Matching Java Virtual Machines (2):
    10.0.1, x86_64:	"Java SE 10.0.1"	/Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home
    1.8.0_172, x86_64:	"Java SE 8"	/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home
```

- ~/.bash_profile に使用するバージョンのjavaの設定をおこないます
- ~/.bash_profile がない場合は[こちらを参考](http://blog.ruedap.com/2010/09/13/mac-bash-bashrc)に新規に作成します
- ちなみに .bashrc と.bash_profileの使い分けは[こちらを参考](https://qiita.com/magicant/items/d3bb7ea1192e63fba850)にしてください
- 以下ではバージョンを8に指定しています

```bash
# javaのバージョン切り替え(installはbrew cask install)
export JAVA_HOME=`/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java_home -v "1.8"`
PATH=${JAVA_HOME}/bin:${PATH}
```

- バージョンを10にする場合は以下のようにします

```bash
# javaのバージョン切り替え(installはbrew cask install)
export JAVA_HOME=`/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java_home -v "10"`
PATH=${JAVA_HOME}/bin:${PATH}
```

- 設定を反映します

```bash
source ~/.bash_profile 
```

- javaのバージョンを確認します

```bash
 java -version
```


## android-sdkをインストールする

- caskを使ってsdkとplatform-toolsをインストールします

```bash
 brew cask install android-sdk
 brew cask install android-platform-tools
```

- ~/.bash_profile にパスを追加します

```bash
# android-sdk toolsのパス設定(installはbrew cask install)
export ANDROID_HOME=“/usr/local/share/android-sdk”
export PATH=“${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools”
```

- 設定を反映します

```bash
source ~/.bash_profile 
```

- adbコマンドが使えることを確認します

```bash
witch adb
```

## adbコマンドを使って、実機のログを参照します

- USBデバイスに実機を接続します
- 実機のログを以下のコマンドで参照します

```bash
adb logcat -v time
```

- 監視したいアプリケーションを起動します
Vapor 3.0 でのルーティングでリダイレクト or ビューのレンダリングをする (1)

例えば、

- ログインしていればビューをレンダリング
- ログインしていなければログインページにリダイレクト

をしたい場合を考える。

Vapor 3.0 ではルーティングにバインドされたハンドラーメソッドの戻り値として `Future` でラップされた `ResponseEncodable` 準拠型を返す必要がある。

したがって、以下は戻り値の型が一致しないためコンパイルエラーになる。


```routes.swift
...

public func routes(_ router: Router) throws {
    let articleController = ArticleController()
    router.get("articles", "new", use: articleController.new)

    ...

    let userController = UserController()
    router.get("users", "login", use: userController.new)

    ....
}
```

```ArticleController.swift
final class ArticleController {

    ...

    func new(_ req: Request) throws -> Future<View> {
        guard isLoggedIn(req) else {
            return Future.map(on: req) { req.redirect("/users/login") } // => これは Future<Response> なので型が合わない

        }
        return try req.view().render("articles/new")
    }

    ...

}
```
    

## ResponseEncodable に準拠する enum を用意する

```swift
final class ArticleController {

    ...

    enum ViewOrRedirect: ResponseEncodable {
        func encode(for req: Request) throws -> Future<Response> {
            switch self {
            case .redirect(let path): return Future.map(on: req) { req.redirect(to: path) }
            case .view(let view): return try view.encode(for: req)
            }
        }

        case redirect(String)
        case view(View)
    }

    ...

    func new(_ req: Request) throws -> Future<ViewOrRedirect> {
        guard isLoggedIn(req) else {
            return Future.map(on: req) { .redirect("/users/login") }
        }
        return try req.view().render("articles/new").map(to: ViewOrRedirect.self) { view in
            return .view(view)
        }
    }

    ...

}
```

こうすることで、リダイレクトの場合もビューをレンダリングする場合も、返り値の型が `ResponseEncodable` に準拠した `ViewOrRedirect` 型になるので型安全性を保ったまま状態に応じて処理を変えることができる。
試しにdockerでspark / spark-shellを触ってみる

お試し用にdockerでspark / spark-shellを触ってみる

##全体の流れ

dockerイメージはいろいろあるが、以下を利用
https://github.com/Semantive/docker-spark

docker-composeで master x 1、worker x 2 のdockerベースのsparkクラスタを単一node上に簡単に作れる。

そしてspark-shellで以下のquick startを試す
https://spark.apache.org/docs/latest/quick-start.html

##1. dockerでsparkクラスタ立ち上げ

事前にgit、docker/docker-composeがインストールされている必要があるが、その方法は割愛。

手順は、下記サイトからdockerfileをcloneして、docker-compose upするだけ。
https://github.com/Semantive/docker-spark

```
git clone https://github.com/Semantive/docker-spark.git

cd ./docker-spark/

docker-compose up
```

しばらくすると、masterとworkerのコンテナが立ち上がる

```
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                                                            NAMES
5b391b766cbc        semantive/spark     "bin/spark-class org…"   2 hours ago         Up About an hour    0.0.0.0:8081->8081/tcp                                                                           dockerspark_worker1_1
12a25ad7a708        semantive/spark     "bin/spark-class org…"   2 hours ago         Up About an hour    0.0.0.0:8082->8082/tcp                                                                           dockerspark_worker2_1
ef6cf053d560        semantive/spark     "bin/spark-class org…"   2 hours ago         Up About an hour    0.0.0.0:4040->4040/tcp, 0.0.0.0:6066->6066/tcp, 0.0.0.0:7077->7077/tcp, 0.0.0.0:8080->8080/tcp   dockerspark_master_1
```

##2. spark-shellをたたいてみる

masterノードでspark-shellを実行するだけ

```
docker exec -it [masterのcontainer id] spark-shell

例）
docker exec -it ef6cf053d560　spark-shell
```

すると、以下のようにspark-shellが起動し、scalaでインタラクティブに処理を実行できる。

```
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 2.1.1
      /_/

Using Scala version 2.11.8 (OpenJDK 64-Bit Server VM, Java 1.8.0_131)
Type in expressions to have them evaluated.
Type :help for more information.

scala> 
```

Quick Startを実行してみる
https://spark.apache.org/docs/latest/quick-start.html

```
scala> val textFile = spark.read.textFile("README.md")
textFile: org.apache.spark.sql.Dataset[String] = [value: string]

scala> textFile.count()
res0: Long = 104

scala>  textFile.first()
res1: String = # Apache Spark

scala> val linesWithSpark = textFile.filter(line => line.contains("Spark"))
linesWithSpark: org.apache.spark.sql.Dataset[String] = [value: string]

scala> textFile.filter(line => line.contains("Spark")).count()
res2: Long = 20

else b)textFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a
res3: Int = 22
```

とりあえず動いた。

ちなみに、AWSのt2.microのように、リソーススペックが低すぎると処理が重すぎて動かない可能性あり。

##3.モニタリング

http://[host IP]:8080で、Sparkが提供するGUIにもアクセスできる。

![spark.png](https://qiita-image-store.s3.amazonaws.com/0/112537/4bd18939-2d76-631b-6a1f-5ceae6d5a3c8.png)
Androidのイヤホンの抜き差しを検知する

## はじめに
動画系のアプリを作ることになって調べた時のメモです。

## 概要
今やどの動画/音楽再生系のアプリも常識的に実装されている機能だと思いますが、電車で動画を見ている際にうっかりイヤホンが抜け、大音量で音声が鳴り響くなんて悲劇を避けるために、イヤホンが抜けたタイミングで再生を停止するためにはイヤホンの抜き差しを検知する必要があります。

## 実装
調べてみたら[BroadcastIntent](https://developer.android.com/reference/android/content/Intent#ACTION_HEADSET_PLUG)が飛んで来るようなのでそいつを拾って実現します。

BroadcastReceiverを継承したクラスを実装し、onReceive内で`Intent.ACTION_HEADSET_PLUG`の`state`から判別していきます。

```kotlin:HeadsetEventReceiver.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.media.AudioManager

class HeadsetEventReceiver :BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent == null || intent.action != Intent.ACTION_HEADSET_PLUG) {
            return
        }

        val state = intent.getIntExtra("state", AudioManager.SCO_AUDIO_STATE_ERROR)
        when(state) {
            AudioManager.SCO_AUDIO_STATE_DISCONNECTED -> {
                // 切断された時の処理
            }
            AudioManager.SCO_AUDIO_STATE_CONNECTED -> {
                // 接続された時の処理
            }
            else -> {
                // その他の場合の処理
            }
        }
    }
}
```

EmptyActivityに少しだけ実装を追加し、上記で定義したHeadsetEventReceiverクラスを登録/解除していきます。
今回はMainActivityですが、Serviceでも可でライフサイクルに沿ってregister, unregisterしてやれば良さそうです。

```kotlin:MainActivity.kt
import android.content.Intent
import android.content.IntentFilter
import android.support.v7.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

    private lateinit var receiver: HeadsetEventReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        receiver = HeadsetEventReceiver()
        registerReceiver(receiver, IntentFilter(Intent.ACTION_HEADSET_PLUG))
    }

    override fun onDestroy() {
        unregisterReceiver(receiver)
        super.onDestroy()
    }
}
```

ここまで完了したらビルドして実行すると、イヤホンの抜き差しのたびHeadsetEventReceiverのonReceiveに切断/接続のstateが送られてきます。

## おわりに
思いの外簡単な実装でイヤホンの抜き差しが検知できるようになりました。

## 参考
https://stackoverflow.com/questions/13610258/how-to-detect-when-a-user-plugs-headset-on-android-device-opposite-of-action-a
Reactで非同期に現地を取得する

# 概略
ReactとReduxとFirebaseを使ったアプリを書いているのですが，このたび **任意のタイミングで現在地を取得** することになりました．
現在地の取得には時間がかかるので非同期処理として扱うべきなので，今回はReact+Redux環境でよく使われるという[redux-thunk](https://github.com/gaearon/redux-thunk)の導入とその利用法について書きます．


# 導入
yarnを使ってredux-thunkを入れましょう．npmでもflatにインストールできるようになって久しいですが，yarnの方が高速で更にセキュアに入れてくれます（参考: [npm vs yarn](https://www.keycdn.com/blog/npm-vs-yarn/)）．

```bash
yarn add react-thunk
```


# 利用法
storeを生成しているところで，以下のようにReduxと混ぜて使います．

```jsx:index.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers';

const store = createStore(
  reducer,
  applyMiddleware(thunk),
);
```

次に，アクションに非同期処理を書いていきます．
...が，Storeを弄るコードと混ざって見づらくなるので，middlewareに本命の非同期処理を書いてactionから呼ぶようにしました．

```jsx:actions/index.js
import { getPosition } from '../middlewares';

export const getPresentLocation = () => {
  return async dispatch => {
    try {
      const position = await getPosition(); //middlewareで非同期処理
      await setPresentLocation(position); //他のアクションでstoreに結果を保存
    } catch(e) {
      alert(e)
    }
  }
};
```

```jsx:middlewares/index.js
export const getPosition = () => new Promise(resolve, reject) => {
  if(!navigator.geolocation) {
    reject("このブラウザは現在地の取得に対応していません:(");
  }

  navigator.geolocation.getCurrentPosition(position => resolve({
    lat: position.coords.latitude,
    lng: position.coords.longitude,
  }), e => reject(`エラー(${e.code}): ${e.message}`));
};
```

あとは，Storeを弄るのと同じようにdispatchでその非同期処理を行っている関数を呼ぶだけです．

```jsx:components/main.js
import React from 'react';
import getPresentLocation from '../actions';

const main = ({ dispatch }) => (
  <button onClick={dispatch(getPresentLocation())}>
    現在地取得！
  </button>
);

export default connect()(main);
```
htmlspecialcharsとFILTER_SANITIZE_SPECIAL_CHARS

# 経緯
ぼく「POSTされた値を受け取るときのフィルタってなにがええんやろな～」
ぼく「お、`FILTER_SANITIZE_SPECIAL_CHARS`安全そうでええやん！」
～数日後～
ぼく「POSTで来た値をHTMLに出力するときには`htmlspecialchars`！常識だよね！」
～半年後～
お客様「`'`って入力したら`&#39;`に文字化けするんだけど！！」
ぼく「ふええええ」


# 原因
- [除去フィルタ - PHPマニュアル](http://php.net/manual/ja/filter.filters.sanitize.php)

> FILTER_SANITIZE_SPECIAL_CHARS
> '"<>& および ASCII 値が 32 未満の文字を HTML エスケープします。オプションで、 特殊文字を取り除いたりエンコードしたりします。

- [htmlspecialchars - PHPマニュアル](http://php.net/manual/ja/function.htmlspecialchars.php)

>ENT_QUOTES
>シングルクオートとダブルクオートを共に変換します。

つまり、

```PHP
$input = filter_input(INPUT_POST,"hoge",FILTER_SANITIZE_SPECIAL_CHARS);
echo htmlspecialchars($input,ENT_QUOTES,'UTF-8');
```
とすると、
`'"<>&`が多重エスケープされてしまいます。

本来なら、入力の受け取り時はバリデーションのみ、出力時にエスケープとするのが妥当(らしい)なのですが、
PHPの除去フィルタのうちの一部が除去するだけでなくエスケープまで行っているので、こうなってしまいました。

### おまけ

ヌル文字とかを弾きたかったら、`FILTER_SANITIZE_STRING`と`FILTER_FLAG_STRIP_LOW`を使って以下のようにするのをおススメします。（フィルタ名にはサニタイズが入っているが、エンコードじゃなくて除去をしてくれる。）

```PHP
$input = filter_input(INPUT_POST,"hoge",FILTER_SANITIZE_STRING,FILTER_FLAG_STRIP_LOW);
```

注意点としては、`\n`などの制御文字も弾かれてしまいます。(ASCIIで32未満なので。)
ちなみに`FILTER_FLAG_STRIP_HIGH`を使うとマルチバイト文字が弾かれてしまいます。英数字のみ入力のときに使えます。

どうしてもサニタイズしてほしくない人は、`FILTER_UNSAFE_RAW`と各種フラグを使えば良さそうです。

[PHPマニュアル](https://www.php.net/manual/ja/filter.filters.sanitize.php)をよく読んで、自分に合った君だけの除去フィルタを手に入れよう！
javascript初心者がobjectを移動させる際にハマったこと

#ハマったこと
1. オブジェクトの取得の仕方
2. 位置をもつプロパティがどれか
3. 代入しているはずなのに変わらない

# 1. オブジェクトの取得の仕方
```javascript
//IDで取得
var object = document.body.getElementById("hoge");
```
詳しくはこちらに色々書いてあったのでおいおい読みたい
https://qiita.com/amamamaou/items/25e8b4e1b41c8d3211f4

# 2. 位置をもつプロパティがどれか
位置を持つプロパティはobject.style.topなど
多分styleはcssのこと

```javascript
//位置を取得
console.log(object.style.top);
```

# 3. 代入しているはずなのに変わらない
これでどのプロパティをいじればいいかがわかったのでここに普通に代入して見ようと次のようなコードを書いたところ動かない。

```javascript
//10の位置に動けや
object.style.top = 10;
```

どうやらobjectのcssでいうpositionがabsoluteになっていないと動かないのでjsで指定してあげる

```javascript
//位置を親からの絶対位置に指定
object.style.position = "absolute";
//10の位置に動けや
object.style.top = 10;
```

しかし動かない。調べてみると訳のわからん事実が判明した。
どうやら後ろに + "px"とつけると動くらしい

```javascript
//位置を親からの絶対位置に指定
object.style.position = "absolute";
//10の位置に動くぜ
object.style.top = 10 + "px";
```

おそらくだがjavascript上でobjectのstyle(css)を指定するときは全てstringで指定しなくてはなのでは。
ここでつまづいたので同じ思いをした人は助かってください。
node.jsのpg@7を使ってみた

# はじめに
node-postgres@7から記述方法が変わりました。
公式：https://node-postgres.com/

# 書き方
記述方法は複数あります。

- コールバック
- Promise
- await/async

一番簡単なPromise方式をご紹介します。(jQueryのajax的な書き方)

```js
  const { Pool, Client } = require('pg')

  // 接続情報定義 
  const client = new Client({
    user: 'user',
    host: 'localhost',
    database: 'db_name',
    password: 'password',
    port: 5432,
  })

  // 接続
  client.connect()

  // クエリ実行
  client.query('select * from t_todo')  // 必要であれば第二引数に配列で変数を渡す プレースホルダは$1 $2…
  .then(result => {
    console.log(result.rows[0])
    res.json(result.rows)
    client.end()
  })
  .catch(e => {
    console.error(e.stack)
    res.json({error: 'error!!!'})
    client.end()
  })
```

簡単に使えるので是非。
nim读写注册表的小例子

nim读写注册表的小例子
2018年5月7日 15:11:58  codegay

贴一个nim读写注册表的例子，虽然简单，但是nim官方没有写windows注册表相关的文档，
我贴的例子兴许能帮大家省点时间，以下代码是读取计算机描述和设置计算机描述的：

```nim
import registry

const path = r"SYSTEM\CurrentControlSet\services\LanmanServer\Parameters"
const key = "srvcomment"

proc getsrvcomment():string {.discardable.} =
    getUnicodeValue(path, key, HKEY_LOCAL_MACHINE)

echo getsrvcomment()


proc setsrvcomment(comment: string) {.discardable.} =
    setUnicodeValue(path, key, val = comment, HKEY_LOCAL_MACHINE)

setsrvcomment("呆瓜小贼 给我上来")
```

其中 registry 模块是目前nim中自带的，对应是 `nim的目录\lib\windows\registry.nim` ，
是一个非常好的学习例子。
python 3.6.5  を macbook にソースコードからインストール 

自分用の作業メモ

## environ
- MacBook (Retina, 12-inch, 2017)
- macOS 10.13.4

## download source code
```
$ mkdir -p ~/src
$ cd ~/src
$ curl -O https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz
```
## install
```
$ tar Jxvf Python-3.6.5.tar.xz
$ cd Python-3.6.5
$ ./configure --prefix=/opt/python/python-3.6.5
$ make
$ sudo make altinstall
```
## set venv
```
$ cd ~/.
$ /opt/python/python-3.6.5/bin/python3.6 -m venv `<vevn_name>`
$ source `<vevn_name>`/bin/activate
```
Apple Watchのコンプリケーションについてざっくりと紹介

## コンプリケーションとは

Apple Watchには、コンプリケーション（Complication）という機能があります。

コンプリケーションをつかうと、こちらの↓スクリーンショットのように、文字盤に画像やテキストを表示することができます。

![コンプリケーション01.PNG](https://qiita-image-store.s3.amazonaws.com/0/38924/4539c075-fdce-eacd-9271-5c9178c5759d.png)

アップルの [watchOSプログラミングガイド：コンプリケーションに関する要点](https://developer.apple.com/jp/documentation/General/Conceptual/WatchKitProgrammingGuide/ComplicationEssentials.html#//apple_ref/doc/uid/TP40014969-CH27-SW1) によると、

> コンプリケーションは文字盤に現れる小さなUI要素で、頻繁に使うデータを、ひと目で確認できるようにする働きがあります。多くの文字盤はカスタマイズ可能であり、好みのコンプリケーションをインストールすることが可能です。
> コンプリケーションの大きさや配置は、選択されている文字盤における空きスペースに応じてwatchOSが判断します。

<img width="566" alt="コンプリケーション02.png" src="https://qiita-image-store.s3.amazonaws.com/0/38924/8cc259d2-e6d6-8369-4fbd-3c840b6a46fc.png">


とあります。

上記のように、コンプリケーションは文字盤によって形や大きさが異なります。
たとえば、こちらの↓ユーティリティ文字盤の場合は、画面左上と右上には小さい四角い枠があり、画面下には横長な枠があります。

![コンプリケーション03.PNG](https://qiita-image-store.s3.amazonaws.com/0/38924/f5cf123b-d682-7982-1f74-7ac728ce1523.png)


コンプリケーションに表示する画像やテキストは、（制限はありますが）左上の温度のように動的に変更することもできます。

## コンプリケーションのタイムラインエントリ

[watchOSプログラミングガイド：コンプリケーションに関する要点](https://developer.apple.com/jp/documentation/General/Conceptual/WatchKitProgrammingGuide/ComplicationEssentials.html#//apple_ref/doc/uid/TP40014969-CH27-SW1) で紹介されているように、コンプリケーションはタイムラインを設定できます。

<img width="697" alt="コンプリケーションタイムライン.png" src="https://qiita-image-store.s3.amazonaws.com/0/38924/e6572f0f-752f-5579-8f57-29fa0f042a35.png">


上の図のように、時間ごとのデータをタイムラインエントリとして登録することで、現在時刻に応じたデータをコンプリケーションに表示することができます。

タイムラインは便利ですが、アプリの特性や連携するデータの内容をよく考える必要があります。

## コンプリケーションの役割

コンプリケーションの役割は、アップルの [watchOSプログラミングガイド：コンプリケーションに関する要点](https://developer.apple.com/jp/documentation/General/Conceptual/WatchKitProgrammingGuide/ComplicationEssentials.html#//apple_ref/doc/uid/TP40014969-CH27-SW1) によると、以下のように書かれています。

> アプリケーションにコンプリケーションを実装することは必須ではありませんが、コンプリケーションが単にアプリケーションのランチャとして機能するにすぎない場合であっても、実装することを強く推奨します。アクティブな文字盤にコンプリケーションを配置することには、以下の利点があります。
> ・ユーザがApple Watchに目を向けるたびに、重要な情報をアプリケーションから提供できます。
> ・アプリケーションは、メモリ内で一時停止したままの状態です。したがって、ユーザがコンプリケーションをタップしたとき、アプリケーションを即座に「起こす」ことができます。
> ・アプリケーションでは、より多くのリソースをバックグラウンドのタスクに割り当てられるようになります。

コンプリケーションに対応するためには、アセットに画像を追加したり、プログラムを書く必要があります。しかし、アップルが推奨しているように、アプリケーションのランチャとして機能するだけだとしても対応することがオススメです。

コンプリケーションはiPhoneのDockのような感じなので、アプリをワンタップで起動できます。せっかく開発したアプリをたくさん使ってもらうためにも、ぜひコンプリケーションに対応しましょう。