OmniAICreator/Qiita-1.07M huggingface dataset:
【PageMenu】コードからタブインデックスを元にページをスクロールさせる【Swift3.0】

便利な[PageMenu](https://github.com/uacaps/PageMenu)ですが、タブのインデックスを元にページをスクロールさせるメソッドがないようなので(2016.12.18時点)、自分でCAPSPageMenu.swiftに追加して使ってます。

### scrollViewByTabIndex

```swift
    // swift 3.0

    // MARK: - Scroll view by Tab index

    func scrollViewByTabIndex(_ itemIndex:Int) {
        if itemIndex >= 0 && itemIndex < controllerArray.count {
            // Update page if changed
            if itemIndex != currentPageIndex {
                startingPageForScroll = itemIndex
                lastPageIndex = currentPageIndex
                currentPageIndex = itemIndex
                didTapMenuItemToScroll = true
                
                // Add pages in between current and tapped page if necessary
                let smallerIndex : Int = lastPageIndex < currentPageIndex ? lastPageIndex : currentPageIndex
                let largerIndex : Int = lastPageIndex > currentPageIndex ? lastPageIndex : currentPageIndex
                
                if smallerIndex + 1 != largerIndex {
                    for index in (smallerIndex + 1)...(largerIndex - 1) {
                        if pagesAddedDictionary[index] != index {
                            addPageAtIndex(index)
                            pagesAddedDictionary[index] = index
                        }
                    }
                }
                
                addPageAtIndex(itemIndex)
                
                // Add page from which tap is initiated so it can be removed after tap is done
                pagesAddedDictionary[lastPageIndex] = lastPageIndex
            }
            
            // Move controller scroll view when tapping menu item
            let duration : Double = Double(scrollAnimationDurationOnMenuItemTap) / Double(1000)
            
            UIView.animate(withDuration: duration, animations: { () -> Void in
                let xOffset : CGFloat = CGFloat(itemIndex) * self.controllerScrollView.frame.width
                self.controllerScrollView.setContentOffset(CGPoint(x: xOffset, y: self.controllerScrollView.contentOffset.y), animated: false)
            })
            
            if tapTimer != nil {
                tapTimer!.invalidate()
            }
            
            let timerInterval : TimeInterval = Double(scrollAnimationDurationOnMenuItemTap) * 0.001
            tapTimer = Timer.scheduledTimer(timeInterval: timerInterval, target: self, selector: #selector(CAPSPageMenu.scrollViewDidEndTapScrollingAnimation), userInfo: nil, repeats: false)
        }

    }
```

### 呼び出し
たとえば左から２番目のページをスクロールさせるにはこのようにします。

```swift
pageMenu?.scrollViewByTabIndex(1) 
```

ちなみにuacaps/PageMenuさんへはプルリク済みです。
初投稿で戸惑う「Payload Too Large」への説明がない

##概要
記事に画像を貼り付けた時にPayload Too Largeと表示され画像が追加されないことがあるが、(2017/01/01現在)この動作はQiitaの仕様である。
[初めてQiitaに投稿すると1ヶ月の画像アップロード制限が2MB→100MBにアップします(blog.qiita.com)](http://blog.qiita.com/post/75674629515/image-capacity-expansion)
##原因
スパム避けと思われる。各アカウントの1件目の記事に貼り付けられる画像ファイルサイズに制限がある。

##（投稿者による）対策
画像なしの状態で記事を登録する→画像を後から貼り付ける

##（運営側による）対策
- スパム避けであれば、本文中に日本語が含まれているか確認する
- ユーザー登録時に日本語の入力を強制させる
- きちんと告知する

[](http://qiita.com/MasahikoEbisuda/items/cbe61de91cf4bb1b3bbc)[](http://qiita.com/keroppi0_0/items/31863410490aff13e90a)[](http://qiita.com/genshun9/items/9e54325bf2dd3de2f99f)[](http://qiita.com/yamashin/items/8f40ba5bfcbfa74a77e8)

##メモ
初投稿時に画像の大きさ制限に引っかかる件については、
その説明の記事がたびたびアップされていることから、
これ、説明不足なんじゃないかなって思っています。

> Payload Too Large: [http://qiita.com/FAQ/PayloadTooLarge](http://blog.qiita.com/post/75674629515/image-capacity-expansion) をご確認ください

とかにすればいいのに。
React コンポーネントのレンダリング結果をテストする

enzyme を使うと具体的な HTML を気にせず、あるコンポーネントが含まれているかなどを検証する変更に強いテストが書けます。一方で、テストが通らない時などには実際にどういう HTML が出力されるかがわかると便利です。

enzyme でのテストと HTML 文字列でのテストは次のように書くことができます。

```js
import React from "react"
import Markdown from "./Markdown"
import { shallow } from "enzyme"
import { renderToStaticMarkup } from "react-dom/server"

describe("Markdown", () => {

  // HTML文字列でテスト
  it("should renders headers", () => {
    const html = renderToStaticMarkup(<Markdown markdown="# hello" />)
    expect(html).toEqual(`<div class="Markdown"><div><h1>hello</h1></div></div>`)
  })

  // enzyme でテスト
  it("should renders emphasis", () => {
    const wrapper = shallow(<Markdown markdown="*bold*" />)
    expect(wrapper.contains(<em>bold</em>)).toEqual(true)
  })
})
```
PHPでドメイン名とサブドメインを分離する

# PHPでドメイン名とサブドメインを分離する

## 経緯
 - AccessLog内のあくせすさきURLから、ドメイン名だけ抜き出したかった
 - 正規表現で ドメイン名とサブドメインを分離できるだろうと思ったけど、よくよく考えたら無理だった  
   - サードレベルまで考えるか、セカンドレベルまででいいかとか
   - 最近大量に使用できるドメイン名が増えてきた
   - など


## 解決策
 - Domain parser を使う ([php-domain-parser](https://github.com/jeremykendall/php-domain-parser))
 - Sourceはこんな感じで書く

```php
$pslManager = new Pdp\PublicSuffixListManager();
$parser = new Pdp\Parser($pslManager->getList());

$url = 'www.domainname.net';
$subdomain = $parser->getSubdomain($url);
$domainName = $parser->getRegisterableDomain($url);

/** $subdomain = 'www' */
/** $domainName = 'domainname.net' */
```

以上です
PDFドキュメント内から画像を抽出する（iTextSharp を使用）

#概要
[iTextSharp](https://ja.osdn.net/projects/sfnet_itextsharp/) を使用して、PDFドキュメント内にある画像を抽出するサンプルです。
Visual Studio で [NuGet パッケージ(nia_tn1012さん)](http://qiita.com/nia_tn1012/items/77c3c1b006f7c69d30ac) から  5 系（投稿時の最新版）を取り込み、下記のようなコードで連番の画像ファイル（デスクトップ宛）に抜き出してみました。

※iTextSharp のライセンス形態に注意。

さまざまな方法があるようですが、iTextSharp.text.pdf.parser.PdfReaderContentParser クラスの ProcessContent メソッドを利用するとだいぶ楽にコーディングできるようです。
iTextSharp は、Java 用に作られている iText を .NET 向けに移植したもののようで、Java っぽくリスナークラスを使用するところがいかにもといった感じです。

#サンプルコード
```csharp
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace SampleNS
{
    public class SampleClass
    {
        public void SampleMethod()
        {
            using (var reader = new iTextSharp.text.pdf.PdfReader(@"sample.pdf"))
            {
                var images = new System.Collections.Generic.List<iTextSharp.text.pdf.parser.PdfImageObject>(); // リスナーからパーサーが返してきた結果を受け取るための入れ物

                var parser = new iTextSharp.text.pdf.parser.PdfReaderContentParser(reader);
                for (int pageNumber = 1; pageNumber < reader.NumberOfPages; pageNumber++)
                {
                    parser.ProcessContent<ImageRenderListener>(pageNumber, new ImageRenderListener(images));
                }
                var index = 1; // 1 からの連番
                images.ForEach(q => q.GetDrawingImage().Save(System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory), (index++).ToString() + "." + q.GetFileType())));
            }
        }
    }

    internal class ImageRenderListener : iTextSharp.text.pdf.parser.IRenderListener
    {
        private System.Collections.Generic.List<iTextSharp.text.pdf.parser.PdfImageObject> _list;

        public ImageRenderListener(System.Collections.Generic.List<iTextSharp.text.pdf.parser.PdfImageObject> list)
        {
            _list = list;
        }

        public void BeginTextBlock()
        {
            // 今回なにもする必要なし
        }

        public void EndTextBlock()
        {
            // 今回なにもする必要なし
        }

        public void RenderImage(iTextSharp.text.pdf.parser.ImageRenderInfo renderInfo)
        {
            var img = renderInfo.GetImage();
            _list.Add(img);
        }

        public void RenderText(iTextSharp.text.pdf.parser.TextRenderInfo renderInfo)
        {
            // 今回なにもする必要なし
        }
    }
}
```

#ご参考
- [How to extract images from PDF files using c# and itextsharp](https://psycodedeveloper.wordpress.com/2013/01/10/how-to-extract-images-from-pdf-files-using-c-and-itextsharp/) - [psyCodeDeveloper](https://psycodedeveloper.wordpress.com/) Thank you so much!
最新のstableブランチ名をgitコマンドのみで取得する方法

GitLab flowを運用していて、最新のstableブランチを取得する場合、
今までgrepやheadやsortを使って取得していたのですが、`git for-each-ref`コマンドで取得できたのでメモとして残しておきます。

```
git for-each-ref --format='%(refname:short)' --sort=-authordate --count 1 "refs/remotes/origin/stable"
```

参考
https://git-scm.com/docs/git-for-each-ref
Windows8.1 > 画面表示 1024x768(汎用非PnPモニター)からの復帰対応

```txt:動作環境
Windows 8.1 pro(64bit)
```

### 症状

以下の報告を受けた。

- Windows Updateがかかった
- 画面の解像度が1024 x 768しか選択できない
- 外部モニタ 2台が拡張表示でない 
   - クローン表示(同じ内容が表示される)になっている
   - RGB, DVI接続の2台

### 対処

以下の対処をした。

- ビデオ関連のデバイスドライバ削除
- 再起動
- 管理者権限でログイン
- ビデオ関連のドライバを最新版にしようとした
  - 汎用非PnPモニターという認識で「最新版です」となった

よく分からないので、他のPCで情報を調べに行った。

5分後に該当のPCに戻ってきたら、**ドライバの状態が自動で回復してモニタ2台(拡張表示)でそれぞれ1920x1200表示になっていた。**

似たような状況(勝手に回復する)は他のWindows 8.1 PCでもあったという報告も1件受けている。
macOS SierraにNokogiriをインストールするときはlibxml2の別途インストールが必要

macOS SierraでNokogiriをインストールしようとしたらlibxml2がらみのエラーが出て失敗しました。

```bash
Note, however, that nokogiri is not fully compatible with arbitrary
versions of libxml2 provided by OS/package vendors.
************************************************************************
Extracting libxml2-2.9.4.tar.gz into tmp/x86_64-apple-darwin16/ports/libxml2/2.9.4... OK
Running 'configure' for libxml2 2.9.4... OK
Running 'compile' for libxml2 2.9.4... ERROR, review '/Library/Ruby/Gems/2.0.0/gems/nokogiri-1.6.8.1/ext/nokogiri/tmp/x86_64-apple-darwin16/ports/libxml2/2.9.4/compile.log' to see what happened. Last lines are:
========================================================================
```

brewでlibxml2をインストールし、それを使うようにしたらインストールに成功しました。

```bash
brew install libxml2
bundle config build.nokogiri --use-system-libraries --with-xml2-include=/usr/local/opt/libxml2/include/libxml2
bundle update
```

[Fix Nokogiri v1.6.8.1 Installation Failure on macOS Sierra](https://www.fdp.io/blog/2016/10/13/fix-nokogiri-v1-6-8-1-installation-failure-on-macOS-sierra/)
「MBAでスクリプトを書き、リモートサーバ上で実行する」をGitで実現する

MBA上のnon-bareリポジトリ、リモートサーバ上のbareリポジトリとnon-bareリポジトリ、で実現します。図にするとこんな感じ。

![git_mba_server.png](https://qiita-image-store.s3.amazonaws.com/0/101824/a4edb078-17f1-0e69-2e08-924ed07c50f5.png)

1. MBA上のCodaでスクリプトを書き、MBA上のnon-bareリポジトリにcommit
2. MBA上のnon-bareリポジトリからリモートサーバ上のbareリポジトリにpush
3. リモートサーバ上のbareリポジトリからリモートサーバ上のnon-bareリポジトリにpull
4. リモートサーバ上でスクリプトを実行

# MBA上にnon-bareリポジトリ作成
作成中のスクリプトがあるディレクトリに移動し、リポジトリを作成します。

```bash
$ cd ~/security-tweet-bot
$ git init
```

作成中のスクリプトをaddし、commitします。

```bash
$ git add tweet-bot.rb
$ git commit -m "initial commit"
```

# リモートサーバ上にbareリポジトリ作成
リモートサーバ上のbareリポジトリ用のディレクトリを作成、bareリポジトリを作成します。

```bash
$ mkdir ~/git/security-tweet-bot.git
$ cd ~/git/security-tweet-bot.git
$ git --bare init
```

MBA上のnon-bareリポジトリのディレクトリに移動し、リモートサーバ上のbareリポジトリにpushします。

```bash
$ cd ~/security-tweet-bot
$ git remote add origin [リモートサーバのユーザ名]@[リモートサーバのアドレス]:git/security-tweet-bot.git
$ git push origin master
```

これで、リモートサーバ上のbareリポジトリにpushされました。

# リモートサーバ上のbareリポジトリをcloneして、リモートサーバ上にnon-bareリポジトリ作成
リモートサーバ上のnon-bareリポジトリ用のディレクトリに移動し、cloneします。
ローカルホストにSSH接続できるようにしておく必要があります。

```bash
$ cd  ~/security-tweet-bot
$ git clone localhost:/Users/nekotricolor/git/security-tweet-bot.git/
```

# リモートサーバ上のbareリポジトリからリモートサーバ上のnon-bareリポジトリにpull
これで、Codaで変更したスクリプトをcommit→リモートサーバのbareリポジトリにpush→リモートサーバ上のnon-bareリポジトリでpullすれば、目標達成です。

MBA上で：

```bash
$ git commit
$ git push origin master
```

リモートサーバ上のnon-bareリポジトリ用のディレクトリで：

```bash
$ git pull
```

# 参考記事
- [Macにgitサーバーを構築してgit://（gitプロトコル）でアクセスできるようにする方法](http://tukaikta.blog135.fc2.com/blog-entry-206.html)
- [いまさら聞けないgitの使い方](http://qiita.com/mountcedar/items/682743c95fd3b8fc274b)
teeコマンドでMySQLの操作を記録する

チームでWEBアプリケーションを開発する場合、どうしてもMySQLを直接操作しなければならない場合があります。
チームに若手がいたりすると、操作時のエラーメッセージを記録せずに先輩社員に質問したりする場合もあり、トラブルシューティングが困難になるケースもあります。
そんなときにMySQLのteeコマンドを使うと、実行時の出力をファイルにも書き出してくれるので便利です。

## 実行例

```mysql
-- user_console.logファイルに操作を記録開始
mysql> tee /tmp/user_console.log
Logging to file '/tmp/user_console.log'
-- 何かのコマンドを実行する
mysql> use db
Database changed
mysql> show tables;
+----------------------------------------------+
| Tables_in_db                                 |
+----------------------------------------------+
| test_db                                      |
+----------------------------------------------+
1 rows in set (0.01 sec)

-- ファイルへの出力を終了
mysql> notee
Outfile disabled.
mysql> quit
Bye
```

少ない手順で操作ログを記録できるので、チームで徹底するのも良いと思います。
B2Bのユーザを相手にするという事

[Classi Advent Calendar 2016](http://qiita.com/advent-calendar/2016/classi) 18日目です。
元々のネタが準備不足のため、日々の仕事で気付いた事を書きたいと思います。

### 〇書いてあること
B2Bのシステムでは、導入を決めたのは組織であって個人ではない。
よって、「そもそも使う気がないユーザ」に対峙する事が多々ある。
効果が見えて自発的に使ってくれるようになるまで、
システム導入と並行して、現場で働く人の意識や仕事の仕方を変えてもらう必要がある。


## はじめに
僕は今、対組織向け（所謂B2B）のシステムを作っている。
今までやってきた事は対個人向け（所謂B2C）のWebサービスがほとんどで、
B2Bのシステムは、新卒で入った会社で少し経験しただけで随分と久しぶりだ。

新卒で入った会社のはじめの現場で、導入期のコツとして以下のような事を聞いた。

「単にシステムを導入しても、お客さんの業務改善には繋がらず、うまくはいかない。
だから、お客さんの意識/業務の改革を行うコンサルタントと一緒にシステムを導入するのだ」

それを聞いた時は、その真意がわからなくて、とりあえず頭に入れて置いたんだけど、
最近、B2Bのシステムに戻ってきて、ようやくその意味がわかった。

## システムの導入を決めたのは組織であって個人ではない
B2Cの、例えばWebサービスとかだと、
PCやタブレットやスマートフォンを扱うのに抵抗があるユーザをターゲットとしている事は少ないし、
そもそもWebページに訪れたユーザは、そのサービスに興味を持って訪れたユーザだ。

だけどB2Bのシステムだと、導入を決めたのは組織で、個々のユーザではない。
だから、前提とするスキルがなかったりするユーザや、そもそも使う意欲がないユーザと、多々対峙する事になる。

彼らを放って置く事はマズイ。
個々に浸透しないと本当の意味で組織は変わらないし、
データが蓄積され効果が見えるまで継続的に使ってもらう必要があるからだ。

## どうするか?
いざ、ディスプレイの前に来てもらえば、そこから先はシステムのUI/UX改善の領域だ。
だけど、それ以前の、日々の業務で使おうとしてもらうところや、
ICT機器に慣れてもらうところは、前段階として整えておかないといけない。

これは非常にタフな仕事だと思う。

新しい業務フローを考えて、廻りを説得して、浸透させないといけない。
スキルを補完する講習会のようなものも企画しないといけないかもしれない。
現場の人に対して「今までの慣れた業務のやり方を変えてください」というのを納得してもらう必要がある。
人に行動を変えてもらうという事は何よりも難しい。

## 誰がやるのか?
お客さんの組織の中に業務改革できる方がいれば最高だ。
だけど難しい仕事だし、そういう状況は稀だと思う。

冒頭の会社は、そこら辺を専任のコンサルタントを付けるという形で解決していた。
ただ、そういうスキルを持っている人は往々にして単価が高く、お客さんにコストが跳ね返ってくる。

我々の場合、業務改革が難しい場合は、
今のコストのままで、できる限りサポートしている...というところか。
あるいは、お客さんに必要性を訴えて、割高だが業務改革専任の人間を付ける事もできるかもしれない。

## 最後に
我々が要望を頂いて改修してシステムを変えていっているように、
お客さんも業務を変えていっている。(それが求められる)

「お互い変わっていきましょう」という事で。
ではでは。
Firebase経由でiPhoneアプリにPush通知するときDATAだけだと通知が表示されなかった

# Firebase経由でiPhoneアプリにPush通知するときDATAだけだと通知が表示されなかった

## 経緯
 - Androidアプリが最初にあり、Firebaseを使用したPush通知を実装していた
 - サーバーから GCM を使って Push通知を送信していた
 - サーバからは以下のようなデータを送信していた  

```json
{
  "to" : "DEVICE TOKEN",
  "data" : {
    "message" : "Push Message"
  }
}
```

 - 同じ内容でiOSアプリへPushを実行した場合、アプリが Foreground にないとき、Push通知のEventがアプリ内で取得できなかった


## 解決策
 - iOS でアプリが Foreground にない場合、アプリまでイベントが上がらない（OS側で処理される）らしい
 - 送信するデータを以下のように変更する

```json
{
  "to" : "DEVICE TOKEN",
  "priority" : "high",
  "content_available" : true,
  "data" : {
    "message" : "Push Message"
  },
  "notification" : {
    "title" : "Push Title",
    "body" : "Push Message"
  }
}
```

 - notification を指定すれば、OS側がキャッチして、Pushメッセージを表示してくた
 - priority を high に指定すると Push通知が画面の上から表示される

以上です
権限を委譲したい/してほしいときに便利なデリゲーションポーカー

デリゲーションポーカーの[出典はこのあたり](http://www.slideshare.net/jurgenappelo/agile-management-authority-delegation/31)です。

仕事は、あらゆる場面で、様々な決定をしながら進める必要があります。
ですが、何を誰が決めるかでモメることはありませんか？
チームメンバーは「私はどこまで決めていいのか」と思うときがあるでしょう。
また、偉い人も「私はどれほど決定していいのか、又は委ねていいのか」と思う時があるでしょう。

そんな時に便利なのが「デリゲーションポーカー」です。

権限委譲は「する/しない」といった2値の問題ではなく、7段階のステップに分かれています。
7段階のステップは以下です
※私=偉い人、彼ら＝チームメンバー

1. 命令する(私が彼らに決定を伝える)
2. 説得する(私が彼らに売り込む)
3. 相談する(彼らに相談し私が決める)
4. 同意する(私と彼らが合意して決める)
5. 助言する(私は助言するが彼らが決める)
6. 尋ねる(彼らが決めた後で私が尋ねる)
7. 委任する(私は彼らに完全に委ねる)

例えば「スクラムではプロダクトバックログの優先順位をプロダクトオーナーが決定する」とあります。
しかし、プロダクトオーナーとして決定を下すという行為にも、実は1〜3までの温度差があることがわかります。
もし、プロダクトバックログの優先順位について、プロダクトオーナーは1の認識をしていて、チームメンバーは3の認識をしていたとすると、この認識のズレを解消しないかぎりお互い不幸な思いをすることになります。

このような認識の相違、ズレをあぶり出し、解消していくツールがデリゲーションポーカーです。

# デリゲーションポーカーの進め方

| 項目 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| プロダクトバックログの優先順位  |   |   |  |   |   |   |   |
| タスクの見積もり  |   |   |   |   |   |   |   |
| スケジュール、リリース日  |   |   |   |   |   |  |   |
| ほげ  |   |  |   |   |   |  |   |
| ふが  |   |  |   |   |   |  |   |
| ぴよ  |   |  |   |   |   |  |   |

1. 上記のような表を作ります。
1. 検討したい項目をリストアップします。
1. 偉い人と各メンバーがそれぞれ1から7までのカードを持ちます。
1. 項目名を読み上げた後、プランニングポーカーの要領で一斉にカードを出し、数字のズレがあった場合は対話によってズレを解消していきます。
1. 収束した結果を表にプロットしていきます。
1. 4〜5を繰り返し、項目すべてについて検討できたら終了です。

# 結果の使い方

この表は書いたら終わりではありません。毎月、3ヶ月、半年などの期間でふりかえりましょう。
状況に応じて新たな項目を加えたりするのも良いでしょう。
また、この表をうまく活用することでチームの成長(自己組織化)を導くことも可能です。各項目の数値を徐々に上げることができれば、現場への権限委譲が進んでいるということになります。
`MyProject/lib`に置いたファイルが読み込まれない時の対処法

ちょっとハマったのでメモ。

まず`lib/foo.rb`という名前で`Foo`クラスを作っておいといて

```.rb
Dir[File.join(Rails.root, 'lib', '*.rb')].each { |l| require l }
```

で正常に読み込めて使えてるのに、また別の時に`bar.rb`で`Bar`クラスを定義して`bundle exec rails console`しても`Bar #=> NameError: uninitialized constant Bar`と返してきて困った。

### 解決策

`spring`が原因だったようで`bundle exec spring stop`でなおりました。
LaravelでX-Frame-Optionsを設定する


やり方が悪かったのか、.htaccessに`Header always append X-Frame-Options DENY`ってやっても効かなくて焦ったのでメモ。

## 1. Middlewareでサイト全体にかける

```bash
$ php artisan make:middleware ResponseHeader
```

```php:app/Http/Middleware/ResponseHeader.php
  public function handle($request, Closure $next)
  {
    $response = $next($request);
    
    $response->header('X-Frame-Options', 'DENY');
    
    return $response;
  }
```

Kernelの`$middleware`に登録

```php:app/Http/Kernel.php
    protected $middleware = [
        \App\Http\Middleware\ResponseHeader::class,
    ];
```


## 2. アクションごとに設定する

```php
return response()->view('hoge.index')->header('X-Frame-Options', 'DENY');

```

## 3. Middlewareで設定してコントローラで有効無効を出し分ける
Kernelの`$routeMiddleware`に登録して、各コントローラのコンストラクタでコントロールする。（未検証）
祝日をプログラムで判定する

[PEAR::Date_Holidays_Japan](http://pear.php.net/package/Date_Holidays_Japan/) を使う。

Date_Holidays_Japan の前に依存する2つのパッケージをインストールする。
`# pear install channel://pear.php.net/XML_Serializer-0.21.0 XML_Serializer`
`# pear install channel://pear.php.net/Date_Holidays-0.21.8 Date_Holidays`
`# pear install channel://pear.php.net/Date_Holidays_Japan-0.1.3 Date_Holidays_Japan`

```php
<?php
require_once 'Date/Holidays.php';

// 第2引数で年を指定
$date_holidays = DateHolidays::factory('Japan', date('Y'), 'ja-JP');
// 休日名を日本語化
$date_holidays->addTranslationFile('/usr/share/pear/data/Date_Holidays_Japan/lang/Japan/ja_JP.xml', 'ja_JP');

foreach ($date_holidays->getHolidays() as $holiday) {
  echo '<pre>';
  var_dump($holiday);
  echo '</pre><hr>';
}
```

$holiday->getDate()->format('%Y-%m-%d') で指定書式で取り出せるのでそいつとdate()の結果を比較すればOK

--
追記

isHoliday()なんてのがあった。わざわざdate()したのと引っ張る必要もなかった

```php
<?php
require_once 'Date.php';
require_once 'Date/Holidays.php';

$date_holidays = DateHolidays::factory('Japan');

// 当日が休日かどうか
$date = new Date();
var_dump($date_holidays->isHoliday($date));

// 指定した日が休日かどうか
$date->setDate('2016-12-23');
var_dump($date_holidays->isHoliday($date));
```
拡張iso8601形式の日付をDataframeのindexに設定する方法

なんだか苦労したのでメモしときます。

```Python:dt.ipynb
import pandas as pd

# JSTのサンプルデータ
data = [
    {"count":224, "time":"2016-01-01T09:00:00+0900"},
    {"count":198, "time":"2016-01-01T12:00:00+0900"},
    {"count":312, "time":"2016-01-01T20:00:00+0900"},
]
df = pd.DataFrame(data)
df

```

当然まだ文字列。

|   |count|                      time|
|:--|:----|:-------------------------|
|0  |  224|  2016-01-01T09:00:00+0900|
|1  |  198|  2016-01-01T12:00:00+0900|
|2  |  312|  2016-01-01T20:00:00+0900|


```Python:dt.ipynb
# iso8601をto_datetime()に渡すとUTC時刻が返ってくるので、JSTに変換
dt = pd.to_datetime(df["time"].tolist()).tz_localize("UTC").tz_convert("Asia/Tokyo")
df.set_index(dt, inplace=True)
df.drop(["time"], axis=1, inplace=True)
df
```

|                           |count|
|:--------------------------|----:|
|2016-01-01 09:00:00+09:00  |  224|
|2016-01-01 12:00:00+09:00  |  198|
|2016-01-01 20:00:00+09:00  |  312|

```Python:dt.ipynb
type(df.index)
```

pandas.tseries.index.DatetimeIndex

なんかもっとスマートな方法あれば知りたいなぁ･･･
Xamarin"超"初心者によるXamarin"超"初心者のためのアプリネタ

このエントリーは、[[学生さん・初心者さん大歓迎！]Xamarin Advent Calendar 2016](http://qiita.com/advent-calendar/2016/xamarin-student)の19日目です。

## はじめに
タイトルの通り、Xamarinの超初心者です。
未だにPCLとSharedの違いがイマイチ理解できていません。。。
鋭意勉強中です！

そんな私がXamarinを勉強し始めた時に作ったアプリ（と言っていいものかはさておき）に題材とした「ライフゲーム」を紹介します。

## ライフゲームとは
Wikipedia先生によると***生命の誕生、進化、淘汰などのプロセスを簡易的なモデルで再現したシミュレーションゲーム***とのことです。

詳しくは、[ライフゲーム](https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0)を見てもらえるとわかると思います。

## なぜライフゲームなのか？
一番の理由は、私の大学の時の卒論の専攻が**複雑系工学**と言うものだったからです。
複雑系とは、個々がそれぞれの役割を担い関係しあうことで全体的に本来の機能を実現するもので、川の流れや交通渋滞などがそれに当てはまります。
その入り口の勉強として**ライフゲーム**を扱っていて、そのシミュレータをJavaのSwing（10年以上も前なので許して）で作って、JavaやSwingについて学ぶことができたので、Xamarinを勉強する時にも同様に用いました。

## コード
ちょっと前に作ったきりメンテしないものをGithubに上げています。
 
* [xamain lifegame](https://github.com/ijufumi/xamarin-lifegame)

Xamarin.Formsを使っているものの、XAMLは使っていなく、また[nuits.jpさん](http://www.nuits.jp/)や[かずきさん](http://blog.okazuki.jp/)が紹介されているXamarinいいぞ!を実感できるネタは一切使っていなくて、Xamarin超初心者な感じ満載です。
あと、画面切れていたりでレイアウトもダメダメです。

今後、PrismやXAMLを勉強しながら改良していこうと思っています。

![lifegame.gif](https://qiita-image-store.s3.amazonaws.com/0/44959/33a17bbb-c763-f829-9d66-8dd80b41ebd5.gif)

## ライフゲームを用いてよかったこと
### グリッドレイアウトを使うことができる
初心者からするとグリッドレイアウトはあまり馴染みがないけど、一定数のパネルを碁盤状に配置する必要があるので、グリッドレイアウトは必須です。
最初からレイアウトを意識することでレイアウトに対する知識を自然と身に付けることができるので良いなと思っています。

### ボタン以外のクリックイベントを制御する方法を知ることができる
ライフゲームの中心である**生と死**をLabelを用いて表現しています。ライフゲームは最初のパターンによって終わりが異なるため、アプリを起動しながらパターンを変更できることが必要で、そのためにはLabelを直接クリックすることにより白と黒を入れ替えることができなければなりません。
そのために、否が応でもでもボタン以外のクリックイベントのやり方を学ぶことができます。

### スレッド（非同期）について学ぶことができる
ライフゲームに限った話ではなく、画面からのイベントで裏の処理を制御する時は基本的に（というか絶対）非同期処理を用います。なぜなら、処理を行なっているスレッドがそのスレッドを止めるという処理を実行することができないからです。SwingだとWorker Threadを使ったりします。
処理の制御だけではなく、裏で動いてる処理が画面の更新を行うときも処理とは別スレッド（Xamarinはメインスレッドじゃないとダメみたい）で行う必要があるため、このようなアプリを作成する時はスレッドによる非同期処理は必須です。
必須なので、こちらも否が応でも学ぶことができます。

### 今後オセロを作れる
完全に見た目トリガーな選択肢です。。。
「碁盤状に何かが配置されていてクリックイベントで色が変わり、裏の処理で画面の更新をする」というほとんど共通していて「同じじゃね？」って言われても反論できません。。。
しかも、ライフゲームのロジックの中にある「周りのセルである状態のものを計算する」というロジックまでほぼ一緒。。。
ですが、オセロは世間一般的に名の知れたゲームで、ほとんどの人がルールを知っているので、アプリを作ってしまえば誰かと遊ぶことができます。
Azure使ってサーバ用意すれば、ネットワーク対戦も夢じゃないし、今流行りのAIとの対戦もできる!

とか、ちょっと無理矢理な感じ醸し出していますが、プログラミングやその他関連ツールは、使い倒した時間に比例してスキルはアップしていくものだと思いますので、
その一つとして、ライフゲームからのオセロはアリなのかなと思います。

## 最後に
色んな方々が「Xamarinはいいぞ!!」って言うのを聞いて、「自分もやりたいな。でも何作ろう？」って感じている人は少なくないと思っています。（私自身そうでした。。。）
このエントリーが、そう言う人たちの役に少しでも立つことができたら幸いです。

あと、記述内容に間違いなどありましたら適宜ご指摘いただけると幸いです。

## 追記（2017/03/16）
`Prism.Fomrs` や `XAML` を使ってリメイクしてみました。
あと、前回は `Java` っぽい書き方でしたが、`C#` に近づいた気がします。

* [xamarin-lifegame-xaml](https://github.com/ijufumi/xamarin-lifegame-xaml)

まだまだ勉強中なので、PRとまではいかなくても「こうした方がいいよ」なことがありましたら、コメント頂けると幸いです。
DNSでバランシングしていたら辛くなった話

この記事は Retty Advent Calendar 19日目です。
昨日は@bokenekoの[character-level CNNでクリスマスを生き抜く](http://qiita.com/bokeneko/items/c0f0ce60a998304400c8)でした。


DNSで一部バランシングを行っていたら、なんと半分が死んでいる！！
あー辛い！ってなったので、DNSのお話から代替案についても書いていこうかと思います。

# DNSについて
そもそも、DNSとはどういった仕組みの物かを紹介してから問題点について書きます。

## DNSの仕組み
私達がweb検索等で利用するDNSは「分散環境」と「ドメイン・ツリー」という仕組みから成り立っている。
この仕組によりDNSサーバー自身の負荷分散も行えているため、世界中からweb検索を行っていても落ちること無く動作している。

普段使用しているドメインex.[retty.me, xxxx.co.jp]は「.」(ピリオド)により複数の階層に区切られます。
DNSは、「.」で区切られた階層以下のドメイン名やホスト名毎にしか管理しない、「分散型サービス」となっております。
具体的にはどういった仕組みかは以下の図の様になっています。
![無題のプレゼンテーション-3.png](https://qiita-image-store.s3.amazonaws.com/0/137186/11949782-76e9-8aeb-abb0-01a71fa25a10.png)

DNSサーバーは決まった仕事しかしない仕組みになっており、それにより負荷が軽減されている。
また、このツリー構造になっているDNSの構図をドメイン・ツリーと呼びます。

## DNSの反映時間について
ここまではDNSの仕組みについて書いて来ましたが、ここから本題に入って行きます。
DNSではレコードと呼ばれる設定を追加することにより、名前解決を可能にしています。
その設定の際に、TTL(Time To Live)と呼ばれるパケットの有効時間も設定します。
（TTLはrouterを通過する度に値が減っていく仕組みになっており、本来パケットが行き先を見失った際にrouter内で無限ループが走らないように設定されています。）

自分たちのPCにはDNSキャッシュという仕組みがあり、TTLで設定された時間はDNSサーバーに接続先を検索することなく接続が可能となっている。
そのため、DNSレコードの設定を変更したところで反映には時間がかかってしまう。

# DNSのバランシングについて
ここまではDNSの仕組みについて書いてきたため、バランシングについても書いていきたいと思います。
DNSでは、レコードを登録してIPやドメインとの紐付けを行っています。また、このレコードは1つのドメインに対して複数書くことができ、紐付けた値に対して重み付けをすることも出来ます。
そのため、レコードを複数登録してバランシングすることも可能になっています。

## DNSのバランシングによるデメリット
- 障害時にもバランシングがされてしまう。  
- サーバーの切り離しに時間がかかってしまう。  
- インスタンスのIPが再起動の度に変わるインスタンスに対しては、都度の設定変更が必要。
- 設定変更に時間がかかってしまう。

# 解決方法
このデメリットを解決する方法としては幾つかありますが、今回はAWSで環境を作っているため、
ELBによるバランシング方法を選択します。
また、これと並行してmonitとというプロセス監視を行い、停止した場合に再起動をかけるツールを併用します。

## ELBのメリット
- ポートに対するヘルスチェック機能があるため、障害時にサーバーの切り離しがされる。
- インスタンスIDでELBとの紐付けを行うため、再起動が発生した場合も設定変更が不要。
- 設定変更に時間がかからず、即時反映される。

## monitを導入する理由
プロセスの監視を行い、問題が発生した場合は再起動を実行することにより、ダウンタイムを短くできる。
これは、再起動で復旧するものに対しては有効だが、設定ファイルのミス等の再起動では解決出来ないものもあるため、その時はアラートを飛ばす事が可能になっている。
弊社では、slackに障害発生時と復旧時に通知する様になっています。
![f8187894-680f-d8af-d569-596013cac004.png](https://qiita-image-store.s3.amazonaws.com/0/137186/bf9c85e0-85a7-9fe8-eae3-8e4cf4731ba3.png)


では皆様も良いmonit Lifeを
trixbox(asterisk)連携で役立つコマンド一覧

コールセンターのシステム担当の人ならtrixboxまたはasteriskという言葉を一度は聞いていると思います。
自社システムと連携したくてもtrixboxとasteriskの日本語の参考資料が少なく、
やる前は正直何が出来るかすらわかりませんでした。
今回は弊社で実装した機能とシステム連携のときに使ったコマンドを紹介したいと思います。

# 自社システム⇔trixbox
trixboxとのシステム連携で弊社で実装したのは受電の振分けシステムです。
受電時にtrixboxを介して自社システムにアクセスし、データのステータスによって受電先を分けるシステムを実装しました。
流れは

ユーザーが電話をかけてくる
↓
まずはtrixboxでどの番号に受電させるか振り分ける
↓
振分け先でスクリプトから自社システムにアクセスする
↓
自社システムでユーザー情報を取得し、
ユーザーのステータスによって特定の人に受電させるか、
特定のグループに受電させるか振り分けて結果をtrixboxに返す
↓
スクリプトで受電させる

流れの中で一番厄介なのがスクリプトで受電させる事
スクリプトで受電の設定をしたり実際に受電させるコマンドを
見つけるのに苦労したので一覧化してみました。

# 連携で役立つコマンド一覧
| 内容 | コマンド | AGIの書き方 |
|:-:|:-:|:-:|
| 受電時のタイトルを設定する | CALLERID(name) | set_variable("CALLERID(name)",  “タイトル”) |
|  特定の1人に受電させたい時  |  DIAL SIP/ソフトフォンNO |  exec("DIAL SIP/ソフトフォンNO|6|rt") |
| 受電した時の結果を返す（ANSWER、NOANSWER、BUSY等） | DIALSTATUS | get_variable("DIALSTATUS") |
| 指定したキュー（グループ）に受電をさせる | QUEUE | exec('QUEUE',  ‘キュー名') |
| 指定したサブメニューに受電をさせる | Goto | exec('GOTO SUBMENU｜s｜1') |

# まとめ
上記4つのコマンドがあれば
特定の1人に受電させたけど、対応中で出られなかったのでグループに受電させる事ができます。
つまり、受電を振り分けることができます。
windowsでファイルの行数を取得する方法

# コマンド
```cmd
find /v /c "" a.txt > b.txt
```

**a.txt**内の""か含まれない行[^1]の行数[^2]を**b.txt**に保存します。

ただし、最終行が改行だけの場合はカウントされないので注意です。

オプションは`find /?`に乗っています。

[^1]: `/v`オプション
[^2]: `/c`オプション

詳しくは`find /?`で、わかります。

# 参考
http://win.just4fun.biz/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AE%E8%A1%8C%E6%95%B0%E3%82%92%E8%AA%BF%E3%81%B9%E3%82%8B%E6%96%B9%E6%B3%95%E3%83%BBfind.html
プロ生ちゃんを日焼けさせるやつ

# はじめに
とあるスライドとイラストを共有します。
スライドは、Arduinoの説明、軽い電気回路の説明、
[Adafruit SI1145](https://www.adafruit.com/products/1777)というパーツを使った実験についてです。
イラストは、かわいらしい暮井慧ちゃんを日焼けさせたやつです。
ピンときた方は全力でヌルーしてください。ただの供養ですので。

# とあるイラストとスライドです
https://www.dropbox.com/sh/bhttbdeis05fvfk/AAAz-HHTHfH5IfyOe7imvdYQa?dl=0
都合上、編集・トリミングをしておりますが、
元イラストは[こちら](http://pronama.azurewebsites.net/pronama/download/)の「画像データ＞イラスト」のOneDriveにあったものをお借りしています。
本当にありがとうございます。

# C#側のポイント
ネットに転がっていたBitmapオブジェクトの透明度をいじるサンプルソースを流用して作っていたため、
まるまるは公開できませんが、軽い仕組みをポイントとなるコードを書きます。

## 日焼けの流れ
1.プロ生ちゃんの画像をリソースとして登録しておく
2.日焼けしていない画像をPictureBoxのBackgroundImageとして表示させておく
3.currentImageとして日焼けした画像のリソースを指定してImageオブジェクトを生成する

```csharp
Image currentImage = Properties.Resources.hiyake_resize;
```

4.TrackBarの値が変更されたら、currentImageのAlphaを再設定してPictureBoxのImageにcurrentImageを設定する

これで、背景の上に半透明の日焼けイラストが重なるので、徐々に日焼けしていくように見えます。

## UVの取得
Arduino側からAdafruit SI1145で取得したUVの強さが改行文字区切りで逐一送られてきます。

```csharp
        private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                string data = serialPort1.ReadLine();
                if (!string.IsNullOrEmpty(data))
                {
                    Invoke((MethodInvoker)(() => AddSuntan(data)));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
```

こんな感じで、ReadLine()で改行毎にデータを取得して、
その値をAddSuntanに入れています。
AddSuntanは取得した値を計算して表示している日焼け画像のAlphaを更新していきます。

# Arduinoのポイント
こちらも、当時書き込んだプログラムがノートPC死亡と共に消えてしまいましたので、
当時を再現したもので説明します。

## 処理の流れ
1. void setup()でSerial.begin(9600)を使ってシリアル通信の準備をする
2. loopでSerial.println(uv.readProx());する

基本的にはAdafruit SI1145のサンプルコードを更にシンプルにした感じです。

## キモとなるコード
特に無いです。

```cpp
#include <Wire.h>
#include "Adafruit_SI1145.h"

Adafruit_SI1145 uv = Adafruit_SI1145();

void setup() {
  Serial.begin(9600);
}

void loop() {
  float UVindex = uv.readUV();
  UVindex /= 100.0;
  Serial.println(UVindex);

  // 当時はUVだとあんまり反応がよくないのでIRの値を使っていた
  // Serial.println(uv.readIR());

  delay(1000);
}
```
こんな感じのコードだったと思います。

# さいごに
アドベントカレンダーの締め切りを過ぎてしまい申し訳ありませんでした。
また、関係者の方々ありがとうございました。
ちなみに、日焼けのイラストはどうやって作ったのか、という質問がありましたが、
技術が無いので愛と気合で作りました。
やり方を忘れてしまいましたが、Photoshopの介護を受けながら作業していたと思います。
VNCサーバ専用機の導入メモ

# 背景

開発環境が遠い遠いデータセンター（時差８時間程度の場所）にあるのだが、データセンター内にVNCサーバを立てたのでは応答が悪すぎて、作業できない。ローカルに常時稼働のVNCサーバを立てて、そこからデータセンターにIPSecのVPN接続を張っておくことが必要。

なお、Windowsは、Windows Updateによって勝手にリブートされたりするので、何らかのLinuxディストリビューションを用いることは既定路線。

これまで、古いThinkPadにUbuntu14を入れてその用途に使っていたのだが、回転体（ファンかHDDか）が異音を発しまくっていて不快なので、ファンレスかつ非回転体ストレージ（SSDなど）のマシンを導入することを決意した。

# 導入したマシン

似たようなスペックの候補機種の中から、**ZOTAC ZBOX PI330**というマシンを入手した。主な決め手は見た目。

![zbox_pi330_image05.jpg](https://qiita-image-store.s3.amazonaws.com/0/126349/807bc207-80ea-c983-f6e1-8f1dfc242fc0.jpeg)

詳細は省くが、Intel Atom x5-Z8500（クアッドコア）、2GBメモリ、32GBのeMMCといったところ。Windows 10 Home Editionがプリインストールされている。

# 最初のトラブル : OSインストール

とりあえずUbuntu16を入れよう、と、DVD-RにUbuntu 16.04.1 Desktopのインストーラを焼くが、BIOSに認識されない。

外付けのDVDドライブに問題があるのかと思って、PC付属のリカバリーディスクを入れてみると、ちゃんと認識される。

いろいろなディストリビューションのインストーラを試してみた結果、CentOS7-64bitのインストーラが認識されることが判明。原因は未だにわからないが、まあ、それはそれとして、CentOS7で行くことにする。具体的には**CentOS-7-x86_64-DVD-1611.iso**というISOイメージである。これを、8GBのUSBメモリに入れて使った。

# 最初にやったこと

yumのリポジトリリストにEPELを追加して、vpncパッケージをインストールした。これが動くことを確認できないと先に進めないので。

```
# wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-8.noarch.rpm
# rpm -Uvh epel-release-7-8.noarch.rpm
# yum install vpnc
```

そしてVPNCの設定を済ませ、データセンターのマシンに接続できることを確認。

# 次のトラブル : gnome-terminal

特にターミナルにこだわりはなかったのだが、最近使ってたのがgnome-terminalだから今回もこれでよかろうと思っていた。デフォルトで入っているし。

ところが！

[こんなバグ](https://bugzilla.gnome.org/show_bug.cgi?id=730632#c33)のせいで、gnome-terminalがマウスも使う開発者にとって非常にやばい状態になっていることが図らずも判明してしまった。というか、忘れていたのを思い出した。（詳しくは"gnome terminal select-by-word"で検索されたし）

ダブルクリックした時の文字列選択の区切り単位をユーザが設定できなくなっているのである。僕はvimでコーディングするので、しかもマウスも使うので、これは致命的欠陥と言える。

一応ワークアラウンドがあるのだが、これがどういうわけか効かない。こないだまでThinkPadに入れてたUbuntuでのgnomeバージョンではワークアラウンドが機能していたのだけれど…。

いっそ古いLinuxディストリビューションをインストールするか、とか考えてもみたのだが、そういえば、そもそも大抵のインストーラが動かないという問題があるのだった。

# 落ち着いたところ

というわけで、OSはCentOS7のままで、別のターミナルアプリを試してみよう、となった。

そのついでもあって、MATEというウィンドウマネージャを導入してみた。

MATEは、クラシックな見た目で、ウィンドウマネージャとしては非常に好感が持てる。

しかし、MATE Terminalもまた、求めているものではないことが判明した。select-by-word設定がないのだ。

そこで、エイヤッと試してみたのが、Xfce Terminal（特に理由もなく選んだのだが）。これは、ウィンドウごとのフォントサイズ（＝ウィンドウサイズ）変更ができないのを除けば、特に不満点がなく、日常の用途に便利に使えそうだ。

![terminal pref.png](https://qiita-image-store.s3.amazonaws.com/0/126349/47793f9f-28e9-25c1-f94a-7ed4d4470b12.png)

当面、これで行こうと思う。ウィンドウマネージャはMATEのまま。
String?をアンラップせずに空文字か判定できるようにしてみた


## 空文字判定の前にnull判定

文字列の空判定ってどの言語でも出て来ると思うんだけど、大体null判定した後に中身が空文字かどうかを精査しないといけない。


## 特にSwiftだと
型が`String`なら

```
if !str.isEmpty {
	// 処理
}
```

で済む話なんだけど、`String?`だと

```
if str != nil && !str!.isEmpty {
	// 処理
}
```

ってやって ***Force Unwrap*** が出てくるのが気に食わない。(っていうか **Java** かよ←

## if letを使って


```
if let str = str, !str.isEmpty {
	// 処理
}
```

って書くこともできて、アンラップした値を中の処理で使うなら良いんだけど使わない場合なんかもにょる。

## そこで

(´-\`).｡oO(`Optional`の`extension`作ってやればよくね？

<details><summary>ってことでできたコードがこちら</summary><div>

```swift:StringExtension.swift
protocol StringOptionalProtocol {}
extension String: StringOptionalProtocol {}

extension Optional where Wrapped: StringOptionalProtocol {
    
    /// nilまたは空文字の場合trueを返す
    var isEmpty: Bool {
        if let str = self as? String {
            // アンラップに成功したので空文字か判定
            return str.isEmpty
        }
        
        // アンラップに失敗してるのでnilと判定
        return true
    }
    
    /// nilまたは空文字の場合falseを返す
    var isNotEmpty: Bool {
        guard let str = self as? String else {
            // アンラップに失敗しているのでnilと判定
            return false
        }
        
        // アンラップに成功したので空文字でないか判定
        return !str.isEmpty
    }
}
```

`String`に専用のプロトコルを用意してジェネリクスの型引数(`Wrapped`)に制約をかけているのがミソ。
こうすることで`String?`に対してだけこの中のメソッドを許可できる。
後は中で`isEmpty`と`isNotEmpty`を実装してやればOK
</div></details>

## ※2019/7/30追記
ずっと放置していて忘れてたんですが、Swift4くらいのタイミングから`where`で直接型を指定できるようになっていました。
<details><summary>それに基づいて書き直したのがこちら</summary><div>

```swift:StringExtension.swift
extension Optional where Wrapped == String {
    /// nilまたは空文字の場合trueを返す
    var isEmpty: Bool {
        guard let str = self else {
            // アンラップに失敗してるのでnilと判定
            return true
        }

        // アンラップに成功したので空文字か判定
        return str.isEmpty
    }

    /// nilまたは空文字の場合falseを返す
    var isNotEmpty: Bool {
        guard let str = self else {
            // アンラップに失敗しているのでnilと判定
            return false
        }

        // アンラップに成功したので空文字でないか判定
        return !str.isEmpty
    }
}
```
</div></details>

## 呼び出し例はこんな感じ

```
func hoge(_ str: String?) {
	if str.isEmpty {
		print("empty string")	
	}
}

hoge("hoge")	// 何も出力されない
hoge("")		// "empty string"が出力される
hoge(nil)		// "empty string"が出力される

```

## 注意

- 変数が`nil`の時と`""`の時で処理が変わる場合はこの方法は無意味なので用法用量を守って正しく使いましょう(
静的サイトジェネレーター「Movable Type」について、誤解されている4つの事柄

これは、[静的サイトジェネレーター Advent Calendar 2016](http://qiita.com/advent-calendar/2016/static-site-generator) 20日目の記事です。

Movable Type (ムーバブルタイプ) は、2001年に生まれたブログソフトであり、CMSソフトです。そして、強力な機能を持つ静的サイトジェネレーターでもあります。

再構築と呼ばれる処理を行うことで、階層構造を持ったサイトデータに加え、月別・年別・著者別・カテゴリ別など、アーカイブごとにデータをまとめて出力できます。その特性から、ウェブ用CMSとして、小規模から大規模までの企業サイト、そしてブログなどに広く使われています。

一方で、15年の長い歴史を持つソフトでもあるため、数々の誤解も存在します。今回は、静的サイトジェネレーター Movable Type についてよく言われている誤解を解いておこうと思います。

## Movable Type は無料で使えない、高い

無償で使えるライセンスがあります。個人で使うなら、個人無償ライセンス。開発・評価で使うなら、開発者ライセンスがあります。

https://www.sixapart.jp/movabletype/license/

さらに、AWSにも、無料で使えるメニューが存在します。Movable Type のAMIを利用して、nanoおよびmicroインスタンスを立ち上げた場合、Movable Typeのライセンス費用はかかりません。

https://www.sixapart.jp/movabletype/aws/


## Movable Type はPerlで書かれているため、とっつきづらい

Ver.6から、REST APIである [Data API] が実装されています。エンドポイントを叩くことで、php、Ruby、Java、JavaScript など、さまざまな言語でデータ操作が可能です。

https://www.movabletype.jp/developers/data-api/
https://www.sixapart.jp/movabletype/data-api/

## Movable Type は昔流行ったソフト。もう誰も使ってないのでは？

全国に10以上のユーザーグループが存在して、個別に活動を行っています。
https://www.movabletype.jp/mtug/

2016年は2つの大きなイベント「MTDDC Meetup」が開催され、とても盛り上がりました。
http://mtddc2016.mt-tohoku.net/
http://mtddc2016.mt-tokyo.net/

コミュニティは活気があります。

実際に使っているエンドユーザーもたくさんいまして、日本国内では継続的に、企業や大学、官公庁のサイトのCMSとして多く使われております。

## Movable Typeを作っていたシックス・アパートは、買収されてなくなったんじゃなかったけ？

アメリカで設立された Six Apart は 最終的に [Say Media](https://www.saymedia.com/) に統合されましたが、[日本のシックス・アパート](https://www.sixapart.jp/) がMovable Type のライセンスを引き継ぎ、日本国内を中心として開発を続けています。

IT、インターネットに関するプロダクトやサービスは、どうしても海外で生まれ、盛んになったものが主流になりがちです。日本で流行っているプロダクトやサービスも、海外産が多くを占めています。

その一方で、日本で作ったサービスを、世界に向けて発信したい、と頑張っている開発チームもたくさんあります。Movable Type も、実は「日本から世界中のユーザーに届けたい」と頑張っているサービスの一つです。

静的サイトジェネレーター「Movable Type」が使ってみたくなった方は、ぜひ開発者ライセンスに登録していじってみるか、AWSでインスタンスを立ち上げて、いろいろ触ってみてはどうでしょうか。

## AWSで Movable Type を触ってみる

AWSを利用して、Movable Type を触る方法について、以下にマニュアル的なものがありますので、参考になれば幸いです。

https://www.sixapart.jp/movabletype/aws/how-to-use.html
http://www.slideshare.net/tosanai/20161219-aws-handsonpublicpptx


※ Disclaimer

本記事を書いたのは、Movable Type を開発している会社・シックス・アパートの中の人間です。ただし、記述した内容には嘘や誇張は存在しません。
(なにかお気づきの点がありましたら優しくお知らせください、謹んで訂正いたします。m(__)m)
SSHログインスクリーンを2分でかっこよくする

# なにこれ
SSHのログイン画面、デフォルトだといつも無機質で愛が無いですよね。
ちょっと気分転換したいときに、やってみるといいかもしれません。
所要時間：３分
想定環境: ubuntu (14.04で動作確認ずみ)


# screenfetch導入

```bash
$ wget https://raw.githubusercontent.com/KittyKatt/screenFetch/master/screenfetch-dev
$ sudo cp screenfetch-dev /usr/local/bin/screenfetch
$ sudo chmod 755 /usr/local/bin/screenfetch
```

# motdの書き換え
.bashrcに書いちゃうと、コンソール開く度に出てきて悲惨なので、こちらへ。

```bash

$ vi /etc/update-motd.d/00-header
printf "=========================================================\n"
printf "Welcome to %s (%s %s %s)\n" "$DISTRIB_DESCRIPTION" "$(uname -o)" "$(uname -r)" "$(uname -m)"
printf "\n"
screenfetch
printf "=========================================================\n"
```

# sshサーバーのリロード
motdの反映にsshサーバーをリロードさせます。
(あまりよくないかもしれません......)

```bash
sudo service ssh restart
```

# 完成

<img width="794" alt="スクリーンショット 2016-12-19 10.58.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/128123/8ad7ac25-0815-8312-4383-f8a94d1fb101.png">
ぬくぬくReact学習記(3)


## Game コンポーネント
Gameコンポーネントを作り、Boardコンポーネントで行っていた処理をGameへ移す。BoardはSquareをrenderするだけになり、状態の保持・winnerの計算・クリックイベントハンドラはGameが担当する。
これで、Game <-> Board <-> Squareとデータが直線的に流れることになる。**ここでやっとReactのデータフローの特徴が実感できた。**

## 複数のアイテムをrenderするとき
- 複数のアイテムをrenderしたいときは、アイテムを配列にしてからrenderする。
- それぞれのアイテムには、ユニークなkeyを設定する必要がある。Reactはkeyを使ってそれぞれのアイテムを区別する。keyはアイテムの配列の中でユニークであれば良い。
- keyを変更した場合、アイテムはdestroyされてから再createされる。

## 気になったコード
```
  const squares = this.state.squares.slice();
  squares[i] = this.state.xIsNext ? 'X' : 'O';
```
squaresにはconst修飾子がついているが、インデックスを指定して`squares[i] = 1`のような代入はOK。もちろん、`squares = 1`はダメ。

## 気になったコード 2
```const moves = history.map((step, move) => {```
引数は、stepが配列内の要素・moveが要素のインデックス。順番を逆にして覚えていた、、
ゲームってなに？

ゲームデザイナーの岡田です。

2年ぶりの登場でちょっと役職が変わりました（笑）。
で、2年前の「ゲームってなに？」というブログの続きで、「ゲームデザインの作り方」を書こうと思っていたのですが、すでに4日も遅れているという体たらく＆そもそも2年前のそのブログ、誰も読んでないでしょ…、ということで、続編ではなく、改訂版のご案内を…。
「ゲームデザインの作り方」は、会社ブログの方にでも気が向いたら寄稿します。

＝＝以下引用＝＝

ズバリ本題ですが、初めてゲームを作ろう！、となった7～8年前、「そもそもゲームってなに？」という当たり前だけど、踏み込むと哲学的な迷路に飛び込みました。
で、wikiを調べる等の安易な解決策に走ったわけですが、いくつかの高尚な理論を理解もできずに、右往左往していると、 「乱数による揺らぎを分かりやすく楽しめるものにすること」というような自分でも理解できて、かつ形に落としやすいシンプルな記述があって、「ああ、これだな」と、自分の中のゲームの定義にしました。
ここでいう乱数は、プログラム生成される数値だけじゃなくて、相手の思考とかも含めた「結果が予測できないもの」、位な感じです。


じゃんけんの例

一例を出すと、究極的にシンプルなゲームは仮に「じゃんけん」とします。

A君とBさん、初対面の2人がじゃんけんを10000回戦した場合、最初の1戦の勝率はやはり5割でしょう。
そして、2人とも何も考えずに10000回じゃんけんをした場合、やっぱり5000勝5000敗近辺になると思います。
ただ、A君だけが「勝ち越そう」という目的意識を持って、

Bさんの心理パターンを読む
Bさんに「俺、次パーだすから」等の陽動をかける
Bさんの癖を見抜く
動体視力を鍛える
等々、さまざまな努力を欠かさなければ、おそらくは5200勝4800敗位で勝ち越せると思います。
勝ち越せなかったら、努力の方向性や量が間違えていた、ということで。。。

ただ、じゃんけんは「分かりやすい」、ということに異論はなくとも、「楽しみつづけられるか」という点では、やはりシンプルすぎて物足りません。
乱数による揺らぎを楽しむにしても、じゃんけんほどにシンプルすぎると、どんなに分かり易くてもやっぱり飽きます。


現実世界とゲーム内のリソース

飽きがきずらい、ある程度複雑なやりとりをゲームとして形作っていくには、さまざまなルールを加えていくことが必要で、そのルールを構築するうえで、ゲーム内リソースが必要になります。
そこで、ゲーム内リソースと引き換えるために持ち込んでいただく現実世界のリソースが必要になるのですが、これは「時間・お金・運」の3つに大別できると思っています。
もうひとつ、プレイヤースキルというものもありますが、これは求めすぎると敷居が高くなるうえに、スマホゲームの特色である空き時間にストレスなく楽しめる、と相反する部分もあるので、「時間」の範疇に入れておきます。

この3要素のバランスが悪いと、「張り付きげー」や「課金ゲー」になったり、「運ゲー」になるのかと思います。
この3要素のバランスがとれていると、いろんなプレイスタイルのユーザーさんが自分なりの楽しみ方で楽しめる懐の深いゲームになるので、バランスのいいゲームと言えるのではないでしょうか。

この点、どうしても「課金」が重視されがちですが、「時間＝人生」です。
時間を使って遊んでいただけること、これってとても大切ですよね。

「運」に関しては、これってもうどうしようもないです。
ただ、これこそ本当に「乱数による揺らぎ」のストレートな在り方なので、単体でゲームとよべなくもない、というちょっと苦しい擁護をしておきます。

で、この3要素と引き換えに手に入れたゲーム内リソースを使って、「乱数による揺らぎ」を攻略していくのが、私が思うゲームの定義です。


ゲームコンテンツ

次いで、この「乱数による揺らぎ」を生成するのが狭義の「ゲームコンテンツ」と言われるものかと思ってます。

ここには、「パズル」が当てはまったり、「ひっぱり」が当てはまったり、「コマンドアクション」が当てはまったり、「クイズ」が当てはまったりといろいろとあります。
ここを省略してしまったり、魅力がないとそもそも面白くない、という話になるので、一番大切なところですが、ここはもう閃き頼りなところも大きいので、絶対に面白いゲームなんて誰にも作れない、と言われる所以なのかと思ってます。
ただ、逆説的ですが、ここ以外はある程度の確度を持って組み上げられてしかるべきだし、ここをきちんと組み上げるのが「ゲームデザイナー」という「本当に必要なの？」といわれがちな職種の存在意義かと思います。

ゲームデザイナーは想定しているターゲットユーザーが各々のプレイスタイルに応じて幅広く楽しめるものであるように、乱数の揺らぎの幅やら、レベルデザインやら、ゲーム内リソースの獲得・交換・消費やら、協力や対戦のあり方やら、色々と多岐にわたって積み上げていかないといけないので、経験が必要な職種かとは思いますが、先人の知恵の「手順ではなく仕組み」を見つめつつ、「製作者自身が現実世界のリソース消費を我慢できなくなるように」組み上げていければ、面白いゲームになるのではないかと思います。

加えて、コンシューマとして成功しているゲームは、この「ゲームコンテンツ」の面白さは立証されているわけなので、業界内で言われているほど博打ではなく、ある程度の確度で成功事例は出せると思いますし、その意気込みがある方、ぜひ、一緒に仕事しましょう（笑）。


まとめ

で、長くなってきたのでまとめますと、


乱数による揺らぎを分かりやすく楽しめるものがゲーム
   ↓
シンプルすぎると飽きるので、ルールを作る
   ↓
ルール作りに必要なゲーム内のリソースは現実世界のものを持ち込む
   ↓
現実世界から持ち込むものは「時間・お金・運」
   ↓
現実世界から持ち込むものがプレイスタイル
   ↓
乱数による揺らぎの生成法が「ゲームコンテンツ」
   ↓
「ゲームコンテンツ」を覆うのがゲームデザイン
   ↓
「ゲームコンテンツ」はまだまだ沢山眠っている

という感じでしょうか。

ブログネタを…、ということで徒然と書いてみましたが、なんだか当たり前のことしか書いてないみたいな気がして、色々と恐縮です。

＝＝＝＝＝

削っただけで終わってしまいました。。。

「ゲームデザインの作り方」以外にも「メルクストーリアが目指したもの」、「ソーシャルゲーム概論」、「ソーシャルゲーム運用論」、「ソーシャルゲーム業界の展望」などなど、いくらでも語りたいことあるんですが、なかなかどうして時間って余らないですね。

とはいえ、こういう語りは嫌いじゃないので、時間みつけて上記のタイトルを出したもの位は書いていきたいと思います。

自己満足でしかないでしょうが、自己満足を追及しないで何を追及するのか、と、いう話でもありますしね。
PhpStormでSilexのコード補完(3)

以前、[PhpStormでSilexのコード補完(2)](http://qiita.com/chihiro-adachi/items/50a59d379eb5b1b9d7df)に続き、3回めの記事です。
前回、前々回で、

- $appのキー補完
- FormTypeやQueryBuilderの補完

が出来るようになりました。

今回は、PhpStormのAdvanced Metadata という補完の仕組みを使って、EC-CUBEのフックポイントで引数として渡ってくる`$event`を補完してみようと思います。

## 環境

PhpStorm 2016.3 を使ってます。

# Advanced Metadataとは

https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata

いわゆるサービスロケータなメソッドに対し、引数の文字列に応じて返却する型を指定できる仕組みです。これにより、`/** @var XXX $var */`としなくてもコード補完が効くようになります。

## 設定を書いてみる

プロジェクトのルートディレクトリに、`.phpstorm.meta.php`というファイルを作成します。
ここでは、`$event->getArgument('Product');`が呼び出されたときに, 戻り値の方が`Eccube\Entity\Product`になるように指定しています。

```php
<?php

namespace PHPSTORM_META {

    // \Eccube\Event\EventArgs::getArgument()メソッドを指定
    override(\Eccube\Event\EventArgs::getArgument(0), // (0)は固定
        map([
            // getArgumentの引数が`Product`のときはProductのエンティティである、と指定
            'Product' => \Eccube\Entity\Product::class,
        ]));
}
```

`.phpstorm.meta.php`を作成すると、以下のようなコードで、コード補完が行われるようになります。

![ok.png](https://qiita-image-store.s3.amazonaws.com/0/72858/0b071135-55f6-936a-27b1-32f8547b804c.png)


## .phpstorm.meta.phpのサンプル

フックポイントでよく出てくる引数をまとめてみました。よければ使ってみて下さい。

```php
<?php

namespace PHPSTORM_META {

    override(\Eccube\Event\EventArgs::getArgument(0),
        map([
            'Product' => \Eccube\Entity\Product::class,
            'ProductClass' => \Eccube\Entity\ProductClass::class,
            'Parent' => \Eccube\Entity\Category::class,
            'TargetCategory' => \Eccube\Entity\Category::class,
            'Order' => Eccube\Entity\Order::class,
            'OriginOrder' => \Eccube\Entity\Order::class,
            'TargetOrder' => \Eccube\Entity\Order::class,
            'Shipping' => \Eccube\Entity\Shipping::class,
            'Customer' => \Eccube\Entity\Customer::class,
            'CustomerAddress' => \Eccube\Entity\CustomerAddress::class,
            'form' => \Symfony\Component\Form\FormInterface::class,
            'builder' => \Symfony\Component\Form\FormBuilderInterface::class,
            'qb' => \Doctrine\ORM\QueryBuilder::class
        ]));
}
```
Powershellでスクリプトファイル.ps1の位置を実行ディレクトリにする

いっつも忘れるのでメモ。

```
Set-Location (Split-Path $MyInvocation.MyCommand.Path -parent)
```

やってることは簡単で、 ``$MyInvocation.MyCommand.Path`` でスクリプトファイルのパスを取得して、 ``Split-Path`` でパスを分解、 ``-parent`` で親パス（つまりディレクトリ）を取得して、そのパスを ``Set-Location`` で実行ディレクトリにする、です。
バンドルされたJSファイルのサイズを分析する

webpack/Browserifyで複数JSファイルをバンドルした際、バンドル後のファイルサイズが気になることがあると思います。実は不要なファイルが含まれていたりするかもしれません。そんな時、バンドルJS中に占める各プログラムのサイズを調べることができます。

source-map-explorer を使います。
https://www.npmjs.com/package/source-map-explorer
以下のように分かりやすく可視化してくれます。
![screencapture-file-var-folders-qj-zxppfzhj7vgfp_tc47lq7hl40000gn-T-1161118-49184-t77o11-l298d50zfr-html-1482071275666.png](https://qiita-image-store.s3.amazonaws.com/0/15528/dcdc0b78-6341-62fc-20eb-b3e316542cdb.png)

## 使い方

### 1. インストール

```bash
npm install -g source-map-explorer
```

### 2. source mapを生成

webpackの設定例です。

```webpack.config.js
module.exports = {
  ...
  output: {
    path: '.',
    filename: '[name].js',
    sourceMapFilename: '[file].map'
  },
  devtool: 'source-map'
};
```

```bash
$ ls
bundle.js  bundle.js.map
```

### 3. グラフ生成

```bash
$ source-map-explorer bundle.js
```

ブラウザでグラフが表示されます。
teraterm マクロで複数のSSH転送設定を組み込む

###自端末から踏み台サーバを経由して複数台のWEBサーバを表示したい場合
（teraterm version 4.92）
Teratermのssh転送を毎回設定したりサーバごとにいちいち設定変更操作をするのは面倒です。そこで以下のマクロで一気に設定します。（と言っても4台ですが。）
１台単位では他のサイトでも紹介されてましたが複数やりたかったので、記入方法も工夫して見やすくしてみました。

環境はこんなのです。
![terasample1.png](https://qiita-image-store.s3.amazonaws.com/0/155688/e47437a4-e8d0-5bbb-bd9b-4ef341f9f424.png)

んで肝心のマクロ本文。

```teraterm:setuzoku.ttl
;;踏み台サーバへの接続情報（鍵認証の場合）
username = 'hogeuser'
hostname = '192.168.1.10'
keyfile = 'C:\Users\hogeuser\Documents\humidai.key'

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;SSH転送設定(4台のwebサーバ）
svr1 = '9999:10.1.1.10:https'
svr2 = '9998:10.1.1.11:https'
svr3 = '9997:10.1.1.12:https'
svr4 = '9996:10.1.1.13:https'

sprintf2 svr '%s,%s,%s,%s' svr1 svr2 svr3 svr4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;踏み台サーバへの接続
msg = hostname
strconcat msg ':22 /ssh2 /auth=publickey /user='
strconcat msg username
strconcat msg ' /keyfile='
strconcat msg keyfile

;;SSH転送組み込み
strconcat msg ' /ssh-L'
strconcat msg svr

connect msg
```
踏み台への接続までは付属のサンプルを改造するなどで各自環境へ合わせてください。
sprintf2の%sの個数と後に続くsvrの個数は一致させる必要があります。連結して文字列変数のsvrに固めてます。teratermバージョンによっては（～%s,%s～）の部分はカンマ区切りじゃないかもです。

後は自端末ブラウザにアドレスを打つだけです。
https://localhost:9999/
こんな感じで。

大分楽になったー。
CentOSにIDCFのcloudstack-apiをansibleでセットアップ

#前提
- CentOS6.8 (IDCFクラウドテンプレート)
- Ansibleタスクはroleとして作成してPlaybookから読み込む形とした
- IDCFクラウドのリージョンは東日本 
- Ansibleのinventoryファイルは適当に用意

#ファイル構成
┣ files
┃&nbsp;┗ .idcfrc
┣ roles
┃&nbsp;┗ install-cloudstack-api
┃&nbsp;&nbsp;&nbsp;&nbsp;┗ tasks
┃&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;┗ main.yml
┣ hosts
┗ playbook.yml

#files/.idcfrc
```text:.idcfrc
[account]
host=https://compute.jp-east.idcfcloud.com/client/api
api_key=[IDCFクラウド管理画面からコピペ]
secret_key=[IDCFクラウド管理画面からコピペ]
```

#roles/install-cloudstack-api/tasks/main.yml
```yaml:main.yml
- name: "cloudstack-apiインストール状態確認"
  stat: path=/usr/bin/cloudstack-api
  register: installed

- name: "cloudstack-apiインストール要否判定"
  set_fact:
    need_to_install: "{{ installed.stat.exists == False }}"

- name: "pythonz インストール"
  shell: "curl -kL https://raw.github.com/saghul/pythonz/master/pythonz-install | bash"
  when: need_to_install

- name: "ez_setup インストール"
  shell: "wget https://github.com/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | sudo python"
  when: need_to_install

- name: "setuptools 更新"
  shell: "pip install setuptools --upgrade"
  when: need_to_install

- name: "pip インストール"
  shell: "easy_install pip"
  when: need_to_install

- name: "関連パッケージ インストール"
  yum: 
    name={{ item }}
    state=present
  with_items:
    - python-devel
    - gcc
    - libxslt-devel
  when: need_to_install

- name: "IDCF cloudstack-api インストール（数分かかります）"
  shell: "pip install git+https://github.com/idcf/cloudstack-api"
  when: need_to_install

- name: "API設定ファイル を設置"
  copy: src=.idcfrc dest=/root/.idcfrc owner=root group=root
```

#playbook.yml
```
- hosts: ciservers
  roles:
    - install-cloudstack-api
```

#実行
> ansible-playbook -i hosts playbook.yml
SVGでドロップシャドーの色を変えたい時


ガウシアンフィルタの色自体を指定します。

サンプル↓

```test.svg

<svg>
    <filter xmlns="http://www.w3.org/2000/svg" id="drop-shadow" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
        <feComponentTransfer in="SourceAlpha">
            <feFuncR type="discrete" tableValues="1"/>
            <feFuncG type="discrete" tableValues="0"/>
            <feFuncB type="discrete" tableValues="0"/>
        </feComponentTransfer>
        <feGaussianBlur stdDeviation="2"/>
        <feOffset dx="0" dy="0" result="shadow"/>
        <feComposite in="SourceGraphic" in2="shadow" operator="over"/>
    </filter>
    
    <rect width="50" height="50" fill="red" filter="url(#drop-shadow)" />
</svg>
            

```

feComponentTransferってやつでRGB値を指定しつつfilterにcolor-interpolation-filtersを付与しましょう。
よく使うアセット関連の設定項目まとめ

## はじめに
必要になったときにいつも忘れているので、Railsのアセット関連の設定項目をまとめてみました。

### public以下のファイルを公開するかどうか
```ruby
config.serve_static_assets = true # Rails4以前
config.public_file_server.enabled = true # Rails5以降
```
Rails5から書き方が変わったので、Rails5の移行作業で触った人も多いはず。falseだと、public以下のファイルは公開されず、他の配信用サーバーから配信する必要がある。パフォーマンス面から言えば、静的なファイルはRailsからではなく、CDNなどで配信する方が良い。

### assetsをコンパイルするときに、圧縮するかどうか
```
config.assets.js_compressor = :uglifier
config.assets.css_compressor = :sass
```
JSとCSSのコンプレッサを指定する。指定がなければ、圧縮しない。コンプレッサを指定したら、対応するgemをインストールする必要がある。

### アセットが見つからないとき、コンパイルを実行するかどうか
```ruby
config.assets.compile = false
```
trueにすると、アセットが見つからないときに自動でコンパイルを試みてくれる。

###プリコンパイルするアセットを設定する
```ruby
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
Rails.application.config.assets.precompile += %w( search.js )
```
application.js・application.css以外でプリコンパイルしたいJSやCSSファイルがある場合は、追加する。

###プリコンパイルを実行するrakeコマンド
```bash
$ bundle exec rake assets:precompile
$ bundle exec rake assets:precompile assets:clean
```
`assets:clean`をつけると、古いプリコンパイルされたファイルを削除してくれる。ただし直近３バージョンまでは削除せず、保持しておく模様。プリコンパイルの度に新しいファイル名をつけてくれるので、ブラウザキャッシュのせいで起こる問題を回避できる。