OmniAICreator/Qiita-1.07M huggingface dataset:
Bitbucket Pipelinesでとりあえずユニットテストを動かす


初投稿になります。

# Bitbucket pilelinesって？
Atlassian製のCIツールです。
BitbucketへのアクションをトリガーとしてDockerコンテナ上でタスクを実行してくれます。
当然ながらBitbucketをリポジトリとして利用していないと意味ないです。

# 元々の悩み
- Bitbucketでプルリク送ったけど、これテスト通ってんの？とかいちいち確認したくない
- developにマージしてから確認だとプルリク閉じちゃっている場合あるし、そもそもテスト通ってからプルリク送れや( ﾟдﾟ )とか荒ぶることになってしまう。

# やりたいこと
タイトルの通り、Bitbucket Pilelines使ってbranchへpushした時にユニットテストを動かしてしまおう作戦

# 問題
- push単位だとジョブが割と頻繁に動作してしまう
 → とりあえずpipelinesは今の所タダだし良いか( ´∀｀)

# 設定
Bitbucket Pipelinesを開始するには、まず以下の手順で有効にする必要があります。

リポジトリの設定 > PIPELINESのSettings > Enable Pipelinesをクリック

これで有効になるので、プロジェクトのルートにbitbucket-pipelines.ymlを設置することでタスクを実行させることが出来ます。

# bitbucket-pipelines.yml

とりあえず、今回やった対応を載せちゃいます。

```
image: ruby:2.3.0

pipelines:
  default: # ブランチの指定。defaultの場合は全てのブランチが対象になります。
    - step: # 実行単位
        script: # 実行するコマンドを登録していきます。
          # expect install
          - apt-get update
          - apt-get install -y expect
          # mysql install
          - wget -O mysql-apt-config.deb http://dev.mysql.com/get/mysql-apt-config_0.3.5-1debian8_all.deb
          - expect -c "set timeout -1; spawn dpkg -i mysql-apt-config.deb; expect \"Which MySQL product do you wish to configure?\"; send \"2\n\"; expect \"$\""
          - apt-get update
          - expect -c "set timeout -1; spawn apt-get install -y mysql-server-5.6 -y --force-yes; expect \"Enter root password:\"; send \"\n\"; expect \"$\""
          - cp -p deployment/etc/mysql/test.cnf /etc/mysql/conf.d/
          - chmod 644 /etc/mysql/conf.d/test.cnf
          - /etc/init.d/mysql start
          - mysql -uroot -e 'create database sample_test DEFAULT CHARACTER SET utf8mb4'
          # project setting & exec rspec
          - bundle install
          - bundle exec rake db:migrate RAILS_ENV=test
          - bundle exec rspec spec
```

全てのbranchでpushしたらテストコードを実行するので、対象はdefaultにします。
もしbranch名で対象を広げたいのであれば、defaultと記述している箇所をブランチ名に変更します。
stepは配列ですが、現状は1つしか登録出来ないようです。
scriptに実際に実行するコマンドを記述していくことになります。

今回はテストだけ実行させるので、RubyのコンテナイメージにMySQLをインストールしてrspecを実行します。
Ruby + MySQLのコンテナイメージもあったのですが、MySQLのバージョンが利用したいものとは違ったので、仕方なく手動で導入することにしました。
自分でコンテナイメージ作って、Docker Hubに上げればいいのですが、今回は検証も兼ねてpipelines上のコマンドでインストールしていきます。

ちなみに rubyのコンテナイメージのOSはdebian8でした。

### MySQLインストール & DB作成
MySQL自体はOracleからリポジトリ情報取得して、aptでインストールすることになるのですが、その際に対話式で設定を行います。
そこで、expectで自動入力させることにしました。
コマンドが見難いので、ファイルに移してシェルスクリプトで実行した方が良いかもしれません。
もし、apt-get installでこの対話式の設定を行わないやり方知っている人教えてください(´・ω・`)

DBの作成はmysqlコマンドで行っています。
テスト実行のみなので、DBのユーザーはrootにしちゃっています。

### テスト実行
Gemfileが更新されている可能性があるのでbundle installを実行し、db:migrateでDBを作成してからrspecを実行します。

この状態でbitbucket-pipelines.ymlファイルをプロジェクトルートに設置した状態で、Bitbucketにpushすると自動的にpipelinesが起動します。
rspecまで無事完了すればpipelinesのステータスがSuccessfulになります。

# 今後の課題
* テストだけじゃなくてデプロイもしたいので、AWSのcodedeploy + capistranoで実現する
* ジョブの成功可否をチャットで通知する
* 静的解析やカバレッジレポートのアップロードをする

とかですかね。

プルリクエストを送る前にユニットテストの実行可否を確認出来るので、テスト通った？とか自分の環境にpullしてきてテスト動かしてみるとかしなくて良いのは素晴らしいです。
コンテナでgitからソースを持ってくる必要もないので、gitの認証情報の管理もしなくていいですし、そもそも動かすの簡単なので割とおすすめですよ。
HTTP認証

#HTTP認証
##BAISIC認証
http_basic_authenticate_with

```ruby:
class AdminsController < ApplicationController
  http_basic_authenticate_with name: "humbaba", password: "5baa61e4"
end
```

##ダイジェスト認証
authenticate_or_request_with_http_digestメソッド

```ruby:
class AdminsController < ApplicationController
  USERS = { "lifo" => "world" }
 
  before_action :authenticate
 
  private
 
    def authenticate
      authenticate_or_request_with_http_digest do |username|
        USERS[username]
      end
    end
end
```
Travis CI で phantomjs 2.5.0 beta を使う

```
sudo: required
```

を設定する。

before_install に

```
  - sudo apt-get -qq update
  - sudo apt-get install -y phantomjs libicu52 libxml2 libxslt1.1 libhyphen0 libwebp5 software-properties-common
  - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && sudo apt-get -qq update && sudo apt-get install -y gcc-4.9 g++-4.9
  - wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.5.0-beta-linux-ubuntu-trusty-x86_64.tar.gz && tar xvf phantomjs-2.5.0-beta-linux-ubuntu-trusty-x86_64.tar.gz && chmod +x phantomjs-2.5.0-beta-ubuntu-trusty/bin/phantomjs && sudo cp phantomjs-2.5.0-beta-ubuntu-trusty/bin/phantomjs /usr/local/bin && rm -rf phantomjs* && phantomjs --version
```

のように書く。するととりあえず動くは動く。
ただ phantomjs 2.5.0 beta の品質が今のところ実用品ではないので、本当にとりあえず動くというだけ。
Sublime Text 2 > bug > 複数選択の誤動作

```txt:動作環境
Sublime Text 2
Windows 7 pro (32bit)
```

<kbd>Ctrl</kbd>+<kbd>D</kbd>による複数選択において、以下のようなファイルで`22`を複数選択するときに失敗する。

```
220, some text
221, some text
222, some text <<-- (3)
223, some text

220, some text <<-- (1) ここからCtrl+Dにて`22`を複数選択
221, some text
222, some text <<-- (2) ここから誤動作
223, some text
```

上記において、(1)の地点から`22`で選択していくと、(2)の地点で`222`が選択される。
すると、それ以降の<kbd>Ctrl</kbd>+<kbd>D</kbd>は`22`ではなく`222`を探してしまい、(3)の地点が選択される。

文字選択イベントが発生するたびに検索対象文字列が更新されるように実装していて、<kbd>Ctrl</kbd>+<kbd>D</kbd>押下時の文字選択もそのイベントとしてカウントされているのだろう。
ASPIRE Edge-Gatewayへの IPsec VPN接続手順

オンプレミスのネットワークから ホワイトクラウドASPIRE(以下ASPIRE) Edge-Gatewayへの
IPsec 接続については、サポート対象にはなっていませんが、参考資料をご紹介します。

|ASPIRE Edge-Gatewayへの IPsec VPN接続イメージ|
|---|
|![SnapCrab_NoName_2017-2-27_20-7-54_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/143230/7e2bf1fb-b582-93bc-c45a-b1f715a3a33a.png)


IPsec VPN(Internet VPN)については、利用者それぞれに通信回線環境が異なるため、
ASPIREでは、IPsecによるVPN接続は、サポート対象外となりますのでご注意ください。
VPNについて、接続の一切を保証するものではありません。また、以下資料は、参考資料の
扱いのため、サポートにご質問いただいてもお答えすることができません。


具体的な接続手順については以下をご参照ください。

（１）VPN接続構成ガイド_01-ASA5515X版　
　　　　IPsec VPNをご利用するための、ASA5515X機器のセッティングの参考情報となります。

（２）VPN接続構成ガイド_02-RTX1210版
	IPsec VPNをご利用するための、RTX1210機器のセッティングの参考情報となります。
Vagrantのvmdkファイルが肥大化してたので圧縮したら容量が10分の1になった！


NetCommons3の開発に使ってるVagrantのvmdkファイルがいつのまにか84.5GBまで肥大化してたので圧縮することに。

結論からいうと84.5GBまで肥大化してたのが6.9GBまで圧縮できたので、肥大化してきたらまた圧縮かけた方が良さそうです。


## 圧縮手順

http://satorumpen.blogspot.jp/2014/03/vagrant.html
の手順を参考にやったが、最後に圧縮したストレージを取り付けるところでこけました。

試しにvagrant upしてもエラーなのでGUIで起動。

GUIで起動したらこんなエラーでてました。

![スクリーンショット 2017-02-27 19.27.50.png](https://qiita-image-store.s3.amazonaws.com/0/9845/dd01a6e3-8edb-efb9-222c-a51ac6eebcbc.png "スクリーンショット 2017-02-27 19.27.50.png")


>UUID {60e04f2c-4bf2-4d3f-ac64-13a07d7931b6} of the medium '/Users/ryuji/VirtualBox VMs/NetCommons3_default_1412849439256_19966/box-disk1.vmdk' does not match the value {9073c8c6-d5c6-4374-acf6-faf665860c8f} stored in the media registry ('/Users/ryuji/Library/VirtualBox/VirtualBox.xml').

ちゃんと英語の意味理解してないですが、なんとなくストレージのUUIDがこのマシン用のUUIDは __9073c8c6-d5c6-4374-acf6-faf665860c8f__ なのに __60e04f2c-4bf2-4d3f-ac64-13a07d7931b6__ になってるよーってことなんでしょうな。

ってことでUUIDを変更したら大丈夫なんじゃない？ってことでぐぐる。
ストレージのUUID変更にVBoxManageコマンドが使えることを確認。


## VMDKファイルのUUID変更方法

```VBoxManage internalcommands sethduuid <対象のvidファイル> <設定するUUID>```

ってことで

```
$ VBoxManage internalcommands sethduuid box-disk1.vmdk 9073c8c6-d5c6-4374-acf6-faf665860c8f
```

って正しいと思われるUUIDに変更したらちゃんと仮想マシンに取り付けられて無事にvagrant upできることも確認できました。

結果、84.5GBまで肥大化してたvmdkファイルを6.9GBまで圧縮完了(^^)
WordPress Popular Postsのメッセージカスタマイズ

# 概要
WordPress Popular Postsで人気記事がないときのメッセージが
「ごめん。すでにメッセージがありません。」というのが表示され、ちょっとかっこ悪い。。。
直そうと思ったけど、参考になりそうなサイトがあまり出てこなかったのでメモ。

## 方法
WordPress Popular Postsプラグインの中にある翻訳ファイルを編集します。
プラグインフォルダは```wp-content/plugins/```にあります。

### 翻訳ファイルが格納されているフォルダに移動
```zsh
$ cd plugins/wordpress-popular-posts/lang
```
### 翻訳ファイル(.po)を翻訳ファイル編集ツールで開く
[PoEdit](https://poedit.net/)で``` wordpress-popular-posts-ja.po ```を開きます。

### 翻訳テキストを修正
ソーステキスト（翻訳元）の言語と、翻訳テキストが表示されるので
編集したいテキストを書き換え、保存します。

### ブラウザで表示して、メッセージが書き換わってるか確認
書き換わってたら完了です。簡単！
!functionと書いてよかったこと

JavaScriptで即時実行の関数を書くにはいろいろな方法がありますが、`!`で始める、ということに、ほかの手法にはないメリットがあると感じたのでまとめてみました。

# 即時実行の関数、とは
（少なくともES5の段階では）スコープを切るなどの目的で、ときおり「関数リテラルを作ってその場で実行する」ということが必要となります。これが即時実行関数式、Immediately Invoked Function Expression（IIFE）です。

# 素直に書こうとするとエラーに
ところが、素直に「関数リテラルを作ってその場で実行」しようとすると、文法エラーになってしまいます。

```エラー.js
function(){ /* コード */ }();
```

というのも、文を`function`で始めてしまうと、関数リテラルではなく**関数宣言**とみなされてしまって、関数宣言に必要な名前がないためにエラーとなってしまいます。ということで、式に持ち込むために、何か別なもので書き始める必要が出てきます。

# いくつもある書き方
式の一部にしてしまえるならなんでもかまわないのですが、いくつか書き方があります。

0. カッコを付ける（`(function(){...})()`、`(function(){...}())`）
1. 単項演算子を使う（`!function(){...}()`、`+function(){...}()`、`void function(){...}()`など）

このうち、カッコを使う方法は、あとから結果全体をそのまま式に受けられることもあってか、よく使われます。

# カッコでハマるけど、!なら大丈夫
そして、あるとき元のソースコードが「セミコロンを打たない」流儀になっているコードに手を入れる場面が出てきて、そんな中にIIFEを書く場面がありました。

```js
// BAD
var foo = bar()
(function(){...})()

// Good
var foo = bar()
!function(){...}()
```

ここで上の方ですと、外側のカッコが`bar()`の結果に対する**関数呼び出し**とみなされてしまって、想定したようには動かなくなります。一方、`!`を使った下のコードの場合、`!`に2項演算子の用法はないため、`bar() !`というものは文法上つながれません。そのため、`bar()`と`!`の間にセミコロンが自動挿入されて、想定通りに動作します。

`!`のほうがカッコより1バイト少ないですし、返り値が不要な場面ならカッコよりいいのではないかと思いました。
オンプレミス環境からASPIREへの移行方法

オンプレミス環境からホワイトクラウドASPIRE（以下ASPIRE）への移行方法について、以下３パターンにまとめています。

|オンプレミス環境からASPIREへの移行方法|
|---|
|![SnapCrab_NoName_2017-2-27_19-49-17_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/143230/adf4d7a8-7cf4-066b-214e-ebf0e5be439b.png)

（１）バックアップソフトを用いる場合
　　　 サードパーティ製のバックアップソフトを利用して移行する方法です。移行元のVMの電源をオンにしたままバックアップを実行し、
　　　　移行させることが可能です。通信断が許容されないシステムなどで向く移行方法です。
　　　　よくある移行方法　 i  初回はフルバックアップを取得し、クラウド側にリストアを実行
			ii  クラウド側に環境切替を行う直前に、前回のバックアップ以降に更新されたファイルのバックアップを行い、
　　　　　　　　　　　　　　 　差分をクラウド側に反映し切替を実施。

（２）OVA Export / Importを用いる場合
　　　仮想マシンの標準フォーマットである　OVAファイルを用いることで、仮想環境上で仮想マシンをイメージファイルとして
　　　扱うことが可能です。OVA ExportにはVM停止が伴うため、VMサイズや、ネットワーク環境により停止時間は前後します。
　　　OVAファイルを用いた仮想マシンのインポート方法については、別に詳細説明をいたします。

（３）物理HDDをデータセンターに持ち込みする場合
　　　大容量の仮想マシンを移行させたいケース
　　　この方法については、別に詳細説明をいたします。
物理HDDを利用して仮想マシンをインポート

ホワイトクラウドASPIRE（以下ASPIRE）では、仮想マシンをインポートするオプションを提供しています。
名称　：　VMインポートサービスオプション


|利用イメージ：USB HDDを直接データセンタへ持ち込みしてインポート|
|---|
|![SnapCrab_NoName_2017-2-27_19-46-26_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/143230/00bbff9b-c6e9-7eb2-4ef6-ca957fad652c.png)


|契約単位|1作業 単位  (※1回の作業につき合計 10VM までの対応)|
|---|---|
|本オプションの提供条件|お客様にてUSB-HDDをご用意いただき、お客様作業にて VM イメージをUSB-HDDに格納実施。その後、ソフトバンクに VM を格納したUSB-HDDメディアを引き渡し。
費用|ゲスト OS の種類 （計 2パターン） や、VM数、VMサイズにより異なります。
データの受け渡しについて|VMware vCenter Converter を用いて、VMイメージデータのコンバートをお客様作業にて実施。作業予定日の７営業日前までにソフトバンクへ調整した方法にて受け渡し。


※　VMware vCenter Converter は、Windows および Linux ベースの物理マシンを VMware の仮想マシン形式に
　　変換するツールです。vCenter Converterを利用することで、物理サーバからクラウドへのマイグレーション（P2V2V）が
　　可能になります。vCenter Converterの詳細については、以下参考リンクをご覧ください。
　　参考リンク　http://www.vmware.com/products/converter
　　ダウンロードには、VMware アカウントが必要です。
[AzureDataFactory] パイプラインの推奨設定 – リトライ

[Azure Data Factory] パイプラインの推奨設定 – リトライ
https://blogs.msdn.microsoft.com/jpsql/2017/02/27/azure-data-factory-pipeline-retry/

MSDN のサイトが削除されたため 2017年2月に投稿した記事も消えました。手元に保存していた過去の記事を再度投稿します。
- Azure Data Factory とは？
=============================
SQL Server では、データを移行を行う際 SQL Server Integration Services (SSIS) を利用することで、CSV ファイルを SQL Server へコピーや、データ加工後の移行ができました。
これを Azure のクラウドで実現したものが Azure Data Factory となります。
Azure Data Factory を利用すれば、例えばローカルにある CSV ファイルや SQL Server にあるデータを Azure SQL Database や Blob Storage にコピーしたり、データ変更後の移行ができます。
サポートされる移行元のデータは、ローカルのファイル、On-Premise の SQL Server や Oracle のデータ、Azure 上の SQL Database や Data Lake Store のデータ、その他 Salesforce などさまざまで、それらを Azure 上の SQL Database, BLOB Storage や DocumentDB などへのデータ移行もしくはデータ変換し保存することができます。詳細は クラウドによるデータ統合サービスである Azure Data Factory サービスの概要 を参照ください。
 
- Azure Data Factory で行われる処理とは？
=========================================
Azure Data Factory で行われる処理はアクティビティと呼ばれ、主に 2 種類あります。一つは、データをコピーするコピーアクティビティ。もう一つは、データを変換もしくは分析する、データ変換アクティビティです。
これらのアクティビティは、Azure Data Factory で設定する JSON 形式の パイプラインで指定できます。
 
- コピーアクティビティの参考情報  コピー アクティビティを使用したデータの移動
https://docs.microsoft.com/ja-jp/azure/data-factory/v1/data-factory-data-movement-activities

- データ変換アクティビティの参考情報  Azure Data Factory でデータを変換する
https://docs.microsoft.com/ja-jp/azure/data-factory/v1/data-factory-data-transformation-activities
 
- パイプラインの推奨設定 - リトライ
=========================================
Azure Data Factory は Azure クラウドの Web のサービスであるため、高可用性を実現しているサービスではあるものの、データセンター側でのサーバーの障害によるフェールーバー（サーバーの切り替え）や、ネットワークの問題による瞬断などが発生します。
そのため、上記の予期せぬ問題を回避するため、パイプラインの activities の項目にある policy にてリトライの設定を行います。詳細は Azure Data Factory のパイプラインとアクティビティ を参照ください。リトライの設定例は以下となります。
 
(例) スライス (パイプラインで指定した間隔) のデータ処理が失敗した場合、最初に 3 回リトライを行い ("retry": 3)、それでも失敗する場合は 25 分待って (
"longRetryInterval": "00:25:00")、2回目のロングリトライ ("longRetry": 2) により、3 回のリトライが実施される設定の例です。

"policy": {
    "timeout": "01:00:00",
    "delay": "00:07:00",
    "concurrency": 1,
    "executionPriorityOrder": "NewestFirst",
    "retry": 3,
    "longRetry": 2,
    "longRetryInterval": "00:25:00"
},

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163237/23b4e791-6302-a3d3-05b9-c7cf066f3919.png)

 
以上、Azure Data Factory の紹介と、パイプラインのリトライの設定についてお伝えしました。お役に立てたら幸いです。
UIButtonのAutolayoutがtitleEdgeInsetsを考慮していないので対応した

# 便利にしたい点
InterfaceBuilder上のUIButtonにtitleEdgeInsetsを設定し、
ボタンの文言のみをプログラム上で設定（変更）すると文言の長さによって
ボタンのサイズが変更されるが、そのサイズにtitleEdgeInsetsが反映されていないため
表示が崩れてしまう。

![名称未設定.png](https://qiita-image-store.s3.amazonaws.com/0/46404/9ea6841a-94c9-aa43-f6f9-a7a59b76a1c0.png)
**収まってくんない**

タイトルを変更した事をAutolayoutに明示的に通知する必要があるのかと思い、
以下のコードを実行してみました。

```swift
botton.setTitle("収めて収めて収めて収めて収めて", forState: .Normal)
// AutolayoutにintrinsicContentSizeが変更された事を伝える
button.invalidateIntrinsicContentSize()
```
![名称未設定.png](https://qiita-image-store.s3.amazonaws.com/0/46404/9ea6841a-94c9-aa43-f6f9-a7a59b76a1c0.png)
**収まってくんない**
# 対応
調べてみた結果、intrinsicContentSizeがそもそもtitleEdgeInsetsを考慮していないということが判明したので以下のようなUIButtonのextensionを実装

```swift
extension UIButton {
    public override func intrinsicContentSize() -> CGSize {
        let originalContentSize = super.intrinsicContentSize()
        let adjustedWidth = originalContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = originalContentSize.width + titleEdgeInsets.top + titleEdgeInsets.bottom
        return CGSize(width: adjustedWidth, height: adjustedHeight)
    }
}
```
返り値のCGSizeに対してそれぞれ、edgeInsetsの値を足してあげる。
すると・・・・・

![収めて.png](https://qiita-image-store.s3.amazonaws.com/0/46404/32a0a58e-1149-be07-5603-de0dceeb01e4.png)
**収まってくれた**

# 感想
ちょっとした気の利かない部分にイラッとしちゃいました:man_with_gua_pi_mao:
UIButtonにはこれとは別にimageEdgeInsetsも存在しているので、imageEdgeInsetsでイラッとした方は同じ手順で改善されるかと思います。
SSL/TLS についてざっくりまとめた

HTTPS や OpenVPN を利用する上で SSL/TLS についての理解がないと大変だったため、調べたことをざっくりとまとめた。

# 公開鍵暗号と共通鍵暗号
まずはじめに、SSL/TLS で使われる公開鍵暗号と共通鍵暗号について。

|  | 公開鍵暗号 | 共通鍵暗号 |
| --- | --- | --- |
| 暗号化 | 公開鍵を使う | 共通鍵を使う |
| 復号化 | 秘密鍵を使う | 共通鍵を使う |
| メリット | 秘密鍵が漏れない限り安全 | 処理速度が速い |
| デメリット | 処理速度が遅い | 共通鍵を安全に共有する必要がある |

それぞれメリット・デメリットがあるが、SSL/TLS ではそれぞれのデメリットをカバーし合うように両方の暗号化方式が用いられている。

# SSL/TLS とは
暗号化通信を行うためのプロトコル。
Web (HTTPS) や OpenVPN など、さまざまな用途で暗号化通信をするのに SSL/TLS が用いられている。

TLS と呼ぶのがより正確[^wiki]だが、SSL/TLS または単に SSL と呼ぶことも多い。
今回は SSL で統一する。

[^wiki]: [Transport Layer Security - Wikipedia](https://ja.wikipedia.org/wiki/Transport_Layer_Security)

# SSL 通信における登場人物
SSL 通信を行う際には「クライアント」「サーバ」「認証局 (CA)」の三者を考える必要がある。

※ 中間認証局については割愛

## クライアント
- SSL 通信をしたい端末
- サーバから証明書を提示された際に、あらかじめインストールしてある CA 証明書と署名が一致するかどうかでサーバの信頼性を検証する
- CA 証明書とサーバ証明書から公開鍵を複合し、その公開鍵でデータを暗号化してサーバに送信する

## サーバ
- SSL 通信を受け入れる端末
- あらかじめ認証局 (CA) に署名された証明書を保持しておき、クライアントから SSL 接続要求があった際に証明書を提示する
- 証明書の署名要求に使った秘密鍵を利用して、クライアントから受信した暗号化されたデータを復号化できる

## 認証局 (CA)
- 署名要求に対して、署名された証明書を発行することができる
- クライアントがある認証局を信頼する (CA 証明書をインストールする) ということは、クライアントは「その認証局が署名した証明書を持つすべてのサーバ」を信頼することを意味する
- 公的に認められた認証局を「パブリック認証局」、そうでない認証局を「プライベート認証局」という
    - 有名なパブリック認証局としては Symantec とか GeoTrust とか
    - ブラウザなどにプリインストールされている CA 証明書はパブリック認証局のもの

# SSL に関わるファイル
SSL を扱うときは様々な種類/形式のファイルがあってややこしい。
ここでは概要だけまとめるが、以下の記事がより詳細でわかりやすい。

http://qiita.com/kunichiko/items/12cbccaadcbf41c72735

## ファイルの種類
| 略語 | 意味 | 用途 |
| --- | --- | --- |
| KEY | 秘密鍵 (Private Key) | クライアントが公開鍵で暗号化して送ってくるデータを復号化するのに必要。絶対に外部に漏らしてはいけないやつ。 |
| CRT | 証明書 (Certificate) | 認証局が発行し、サーバが保持するもの。クライアントから SSL 接続要求が来た際に提示する。 |
| CSR | 証明書署名要求 (Certificate Signing Request) | サーバが認証局に証明書の署名を要求するために、秘密鍵から CSR を作成して認証局に送りつける。 |
| CRL | 証明書失効リスト (Certification Revocation List) | 認証局が発行し、クライアントが保持するもの。サーバから提示された証明書が失効していないかどうかを確認するのに利用する。 |

## ファイル形式
| 略語 | フォーマット名 | 用途 |
| --- | --- | --- |
| DER | Distinguished Encoding Rules | ASN.1 というデータ構造をバイナリデータとしてエンコードした形式。 |
| PEM | Privacy Enhanced Mail | DER を Base64 でテキストとしてエンコードした形式。パスフレーズを設定することもできる。 |

# SSL 通信の手順
SSL 通信では、公開鍵暗号を利用して共通鍵を共有し、共通鍵暗号で通信を行う。

公開鍵暗号を利用するためには、事前に秘密鍵を生成したり署名された証明書を配置したりしておく必要がある。

## 事前にやること
### サーバ
0. SSL 通信に使用するサーバ秘密鍵を用意する
0. サーバ秘密鍵から証明書署名要求 (CSR) を作成する
0. 証明書署名要求 (CSR) を認証局に送信する
0. 認証局から署名されたサーバ証明書が送られてくる
0. サーバ秘密鍵とサーバ証明書をサーバに設置する
    - Web サーバであれば、Apache や Nginx などの設定ファイルに秘密鍵/証明書のパスを記述する

### クライアント
0. 認証局の CA 証明書をインストールする
    - Web ブラウザであれば、既にパブリック認証局の CA 証明書はインストールされている

## 通信する
### サーバの信頼性を検証する
0. クライアントからサーバに SSL 接続要求を送る
0. サーバはサーバ証明書をクライアントに提示する
0. クライアントは、受け取ったサーバ証明書の署名が CA 証明書の署名と一致するかどうかを検証する

### 共通鍵を共有する
0. クライアントは、CA 証明書から CA 公開鍵を取得する
0. クライアントは、CA 公開鍵とサーバ証明書からサーバ公開鍵を取得する
0. クライアントは、共通鍵を作成する
0. クライアントは、作成した共通鍵をサーバ公開鍵を使って暗号化し、サーバに送信する
0. サーバは、暗号化された共通鍵を受け取り、サーバ秘密鍵を使って復号化する

### 暗号化通信を行う
0. クライアント - サーバ 間は共通鍵暗号を利用して通信を行う

# 参考文献
- [SSL 認証 の仕組みと OpenVPN の認証の仕組み](http://server-setting.info/blog/ssl-openvpn-authentication.html)
- [SSL/TLSをはじめから](http://www.infraexpert.com/study/study44.html)
Convert certificate and key to .pem format


I had issues getting the .p12 file working, so we are going to convert them to .pem. Follow the following commands to get the .pem files. cert.cer is probably named by default as aps_development.cer.

`$ openssl x509 -in cert.cer -inform DER -outform PEM -out cert.pem`
`$ openssl pkcs12 -in key.p12 -out key.pem -nodes`

Test the certificate and key .pem files
Next, let’s test our .pem files to see if they are working. Follow the appropriate step for development and production certificates and keys.

For Development (sandbox) certificate and key

`$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert cert.pem -key key.pem`

For Production certificate and key

`$ openssl s_client -connect gateway.push.apple.com:2195 -cert cert.pem -key key.pem
`


https://medium.com/@liheyse/a-step-by-step-guide-on-how-to-setup-apple-push-notifications-apn-on-meteor-and-react-native-aa90c8d4bb72#.rk6ca96cu

http://stackoverflow.com/questions/16055756/how-can-i-generate-pem-file-for-push-notifications-in-iphone
laravelで tinyInteger の auto increments のカラムを作る

Laravel 5.4 にて確認。

下記メソッドで auto increments のカラムを作ることができます。

```
$table->increments('id');
$table->mediumIncrements('id');
$table->smallIncrements('id');
```

tinyint ではこのような記載になります。（コメントにてご教授ありがとうございます）

```
$table->tinyInteger('id', true, true);
```


laravel4 では下記のように書く必要があります。5.4でも下記で動作確認できました。ただ上記のほうがスマートです。

```
$table->tinyInteger('id')->unsigned()->autoIncrement();
```

参考
http://stackoverflow.com/questions/19711783/is-it-possible-add-tinyinteger-or-smallinteger-to-increments-on-laravel-orm
dict同士を合体させた新しいdictを作る

リストのように

```py
dict_a + dict_b
```

と書いても辞書の合体はできないので自分でループを書いて合体させる処理を組まなければいけないかと思いきや、これで一発。

```py
{**dict_a, **dict_b}
```

（コメントで教えてもらったのでさらに）

```py
dict_a += dict_b
```

的なことがやりたければ

```py
dict_a.update(dict_b)
```

とあいなります。
どっちも+, +=演算子でいーじゃねーかと思うんですけどね。
CardViewでpaddingが効かなくて若干ハマった

普通のpaddingは効かないので

```xml
<android.support.v7.widget.CardView
            style="@style/CardView.Light"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:padding="10dp">
```





app:contentPaddingを使うと効く

```xml
<android.support.v7.widget.CardView
            style="@style/CardView.Light"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            app:contentPadding="10dp">
```
人工知能はラーメン二郎を識別するか

はじめに
===

* [LINE BOT AWARDS](https://botawards.line.me/ja/)向けにレコーディングダイエットのサービスを作ってみました
* 料理の画像を上げるとAIが自動的に識別してカロリー情報を返却してくれるというものです
* 要するにこの記事はそのサービスのステマなので早速BotのQRコードを貼っておきます！

![qrcode.png](https://qiita-image-store.s3.amazonaws.com/0/27361/a5b89870-ddb3-c9d4-c8e0-9bfbc176ca92.png)

技術的には
===

Qiitaなので技術面をご紹介。

* [Tensorflow](https://www.tensorflow.org/)上の[Inception-v3](https://github.com/tensorflow/models/tree/master/inception)で料理の判定(Gunicorn + flaskでWebAPI化）
* LINE Messaging APIとのやりとり部分は[Hubot](https://github.com/github/hubot)上で動作
  * [アダプタはこちら](https://github.com/shouta-dev/hubot-line-message-api)
* 管理画面はRuby on Railsでさらっと
* ランタイム入り乱れてて、マイクロサービスアーキテクチャって感じです

後日このあたりの詳細は別の記事にしたいなと思っています。
＃特にInception-v3でオリジナル画像でトレーニングするのは結構大変だったのでそのへんとか。

__2017/08/07追記__

[別の記事](http://qiita.com/shouta-dev/items/26cb1ace8c11c196f86e)で技術面書きました。

分類させてみる
===

んで、実験してみましょう。

ちょっとした居酒屋メニュー
---

![IMG_5647.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/7f8c9b05-8248-dd38-a281-399ce8cc15fe.png) ![IMG_5648.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/6f026b26-bfbf-07f1-3fdb-457d47a292fd.png) ![IMG_5649.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/87d106c5-d41c-caed-402e-4d96af90b45b.png)

おおー！ばっちりじゃないですか。

洋食的な
---

![IMG_5650.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/b29d333c-b552-f23d-f21e-a369c5c64a2a.png)

うむうむ。

塩ラーメン
---

![IMG_5651.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/d7436427-7f80-c105-8b25-2f3c1dbe768d.png)

いいね！

二郎
---

![IMG_5656.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/6054c32c-dc19-0c9c-191c-97227ecbcf1f.png)

うおー！すげえ！

ちゃんぽん
---

![IMG_5662.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/325672de-9a1b-2453-4923-21ac3d2a945b.png)

ソムタムってなに？

二郎
---

![IMG_5658.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/6e341060-0eae-576c-3f42-b25d4c0eb08f.png)

もやしラーメンw

野菜ラーメン
---

![IMG_5663.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/d14604af-7aef-81f1-e0bd-b09911040fa3.png)

野菜のかさが低いのをみて二郎フラグを落としてるのか・・・？！

二郎
--

![IMG_5659.PNG](https://qiita-image-store.s3.amazonaws.com/0/27361/b677cd49-5671-6d74-4a23-ce6a1a9db434.png)

よっ！ジロリアン！

すげえなAI！
---

AIジロリアンが現われる日も近そうですね！完飲。
cakephp3でのphpunitの備忘録

自動テストをしてくれと頼まれてcakephp3&phpunitでコードを書いていたのですが、備忘録的に小ネタを。

**セッションの引き継ぎ**

```php:HogeControllerTest.php
$this->post ( url1 );
$this->post ( url2 );
```
と書くとurl1で作ったセッションがurl2に渡らない、そんなときは

```php:HogeControllerTest.php
$this->post ( url1 );
$this->session ( $this->_requestSession->read () );
$this->post ( url2 );
```

**セッションに値を渡したい**

```HogeControllerTest.php
$this->session(['aaa'=>'bbb']);
```

**セッションの検証**

```HogeControllerTest.php
$this->assertSession ( ['エラー'], 'errors');
```

**セッションの取得**

```php:HogeControllerTest.php
$hoge = $this->_requestSession->read ('aaa');
```

**set()された値の取得**

```HogeControllerTest.php
$hoge = $this->viewVariable ( 'aa' );
```

これで一通りのテストコードを書くことができます
Go言語で画像ファイルか確認してみる

# Go言語で画像ファイルか確認する
Go言語で書かれたサーバーサイドで
アップロードされたファイルが画像ファイルか確認する必要があったため今後の備忘録として記載します。

## imageパッケージを使用する

[imageパッケージ](https://golang.org/pkg/image/)を使用することで簡単にできます。

```go:main.go
import(
  "image"
  _ "image/gif"
  _ "image/jpeg"
  _ "image/png"
  "os"
)

func main(){
  f, _ := os.Open("path/to/image")
  defer f.Close()
  _, format, err := image.DecodeConfig(f)
  if err != nil {
    // 画像フォーマットではない場合はエラーが発生する
    fmt.Println(err)
    return
  }
  // pngファイルの場合はformatがpng
  // jpegファイルの場合はformatがjpg
  // gifファイルの場合はformatがgif
  fmt.Println(format)
}
```

## 拡張

下記パッケージを使用することにより、より広い範囲で画像判定を行うことができます。

https://golang.org/x/image

importする箇所で下記のように追加することでbitmapやtiff形式の画像ファイルにも対応できます。

```go:
import(
  "image"
  _ "golang.org/x/image/bmp"
  _ "golang.org/x/image/tiff"
)
```

現状ではこれで十分なため、これ以上の調査は行っていませんが、
もし新たに画像フォーマットの対応が必要になれば根性出して自分でコードを
書けば拡張できるようになっているのが[imageパッケージ](https://golang.org/pkg/image/)のいいとこかなと思います。

追記
@matsumatsu20 さんから編集依頼をいただいたためコードを修正しました。
ありがとうございます！

```go:
// f, _ := f.Open("path/to/image")
f, _ := os.Open("path/to/image")
```
deviseでストロングパラメータを追加する (Rails5を受けての変更点)

# はじめに

devise3からdevise4へのアップデートに伴い、ストロングパラメータの追加の仕方が変わっていたのでメモしておきます。

[Remove `ParametersSanitizer` inheritance.](https://github.com/plataformatec/devise/pull/3856)

`devise_parameter_sanitizer.for` から `devise_parameter_sanitizer.permit` に変わったようです。

`for`のままだとこんな感じのエラーになりました。

```
NoMethodError (undefined method 'for' for # Did you mean? fork)
```

`for`よりも`permit`のほうがわかりやすいと個人的に思ったのでなかなかよいのではないでしょうか。

# 具体例

## devise3

```rb:app/controllers/application_controller.rb
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

    def configure_permitted_parameters
      devise_parameter_sanitizer.for(:sign_up) << :username
      devise_parameter_sanitizer.for(:sign_in) << :username
      devise_parameter_sanitizer.for(:account_update) << :username
    end
```

## devise4

```rb:app/controllers/application_controller.rb
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
    devise_parameter_sanitizer.permit(:sign_in, keys: [:username])
    devise_parameter_sanitizer.permit(:account_update, keys: [:username])
  end
brew updateをしたらError: /usr/local must be writable!が出た

#はじめに#
Homebrewのアップデートのためにターミナルから`brew update`を実行すると`Error: /usr/local must be writable!`というエラーが出ました。

#解決策#
`sudo chgrp -R admin /usr/local`
/usr/local ディレクトリと中身のグループをグループ名adminに再帰的に変更します。

`sudo chmod -R g+w /usr/local`

/usr/localディレクトリのアクセス権限を変更します。ディレクトリとその中身のアクセス権限を再帰的に変更するために-Rオプションをつけます。グループの権限として書き込み権を与えます。

#確認方法#
`brew doctor`
を実行して`Your system is ready to brew.`になれば正常終了です。

#おまけ#
私が初めに実行したときには、"You may wish to `brew unlink` these brews:
  readline"という警告が出ました。

そこで、`brew unlink readline`した後で、`brew install readline`を実行しました。`brew doctor`で`Your system is ready to brew.`が無事表示されるようになりました。

#参考文献#
[Homebrew の update が失敗する問題](http://pc.tokuvin.net/homebrew-error/)
[【chgrp】Linuxでファイルやディレクトリのグループを変更するコマンド](http://uxmilk.jp/52207)
[【Mac】Homebrewアップデート時のコマンド一式](http://mzgkworks.hateblo.jp/entry/homebrew-update-flow)
SHA-1、破られる！で、TLSへの影響は？

2017年2月23日、ついに机上の理論ではなく実際に、SHA-1が破られました。具体的には、SHA-1ハッシュ値が全く同じ値を取る２つのPDFファイルが公開されました。詳細については[SHAttered](https://shattered.it/)の公式サイトを見ていただくとして、ここでは一般論としてハッシュ関数が破られるとTLSに何が起きるかという観点で考察したいと思います。

# ハッシュ関数が破られても直ちに危険とは言えない、か？

## デジタル署名で使う場合は危険

署名関数（RSAやDSA）と組み合わせてデジタル署名に使われるハッシュ関数で衝突に成功するということは、署名と辻褄が合うような偽造電文を作られてしまう可能性があることになりますので、基本的には、その署名は安全ではありません。もっとも、実際に攻撃が可能かどうかは、標的電文のファイルフォーマットなど複雑な要因が作用します。

## HMACの中で使う場合は微妙

ハッシュ関数はHMACの中で使われますが、ハッシュ関数が脆弱ならHMACも脆弱か？というと、ちょっと古いですが2011年の[RFC6151](https://tools.ietf.org/html/rfc6151) ([Google翻訳](https://rfcs.web.fc2.com/rfc6151.html)) にMD5ベース、[RFC6194](https://tools.ietf.org/html/rfc6194) ([Google翻訳](https://rfcs.web.fc2.com/rfc6194.html)) にSHA-1ベースの考察が記載されています。これによると、

- HMACをMACとして（通信改ざん検出に）利用する場合は、直ちに脆弱ではない。
- HMACを利用するPRF関数については、影響はよくわからない。

というわけで、何だかモヤッとするところですが、直ちにHMAC-MD5、HMAC-SHAを危険と扱う必要はないと考えてよさそうです。

# 具体的には。。。

## X.509証明書

TLSサーバ証明書などの証明書は、各認証局でSHA-2への移行が順次進んでいるはずですが、古いSHA-1の仕様がまだ残っている場合は引っかかる可能性があります。[SHAttered](https://shattered.it/)の公式サイトによると、FirefoxはSHA-1の廃止を当初予定より前倒しして2017年2月24日に実施したとのことです。

ちなみに、誤解されやすいのが証明書のfingerprint （拇印）ですが、証明書の中に拇印というフィールドがあるわけではありません。例えばSHA-256拇印とは、単にその証明書データのSHA-256ハッシュ値です。ですから、もしブラウザの画面にSHA-1拇印しか出てこないとしてもそれは証明書を見ているあなたのブラウザにSHA-1拇印機能しかないという話ですから、やるべきことは、あなたのブラウザをアップデートすることであり、証明書そのものを手直しする必要はありません。

## TLS1.0, TLS1.1

拙稿[SSL3.0, TLS1.0～1.2の微妙な違いのまとめ](https://qiita.com/n-i-e/items/0cbe004ad8a2e800b90d)で説明しましたが、TLS1.0とTLS1.1は、プロトコルの中にSHA-1とMD5がハードコードされています。SHA-1が破られたとすれば、TLS1.0や1.1に影響が出るのか気になるところですが、結論としては、直ちに危険ではないようです。

### PRF
PRFはTLSのいろいろなところに出て来る縁の下の力持ち的な多用途の関数です。定義は[こちら](https://qiita.com/n-i-e/items/0cbe004ad8a2e800b90d#prfsecret-label-seed)。

使われ方としては、上述のHMACをPRFの中で使うケースですので、一応、直ちにSHA-1を廃止必須とするほど重大ではないと考えてよさそうです。

### ServerKeyExchangeの署名

拙稿 [SSL/TLS（SSL3.0～TLS1.2）のハンドシェイクを復習する](https://qiita.com/n-i-e/items/41673fd16d7bd1189a29#%E9%8D%B5%E4%BA%A4%E6%8F%9B) の鍵交換のところで説明しましたが、ServerKeyExchangeは、鍵交換方式がDHEやECDHEの場合に現れるメッセージです。RSAの場合は使われません。

定義は[こちら](https://qiita.com/n-i-e/items/0cbe004ad8a2e800b90d#serverkeyexchange-clientverify%E3%81%AE%E7%BD%B2%E5%90%8D%E9%96%A2%E6%95%B0)にありますが、署名に使うハッシュですので、その意味では危険度は高いということになります。もっとも、既存の署名と辻褄の合うような偽のDiffie-Hellman公開鍵（と、対応する秘密鍵）を作り上げるというのは、ちょっと高難度すぎる気がしますので、いまのところ、これが実際の脅威とは扱われていないようです。とはいえ、Forward Secrecyと呼ばれ、安全とされ、使うことが推奨される、DHEとECDHEが対象というのは、ちょっと気になるところではあります。

### CertificateVerifyの署名

これはクライアント証明書を使う場合に送出されるメッセージです。これも署名に使うハッシュではありますが、CertifateVerifyは平文の正しさを証明するのではなく、証明書の正しさを証明するための署名ですので、偽の平文ではなく「偽の証明書」を作る攻撃ができないと、脅威にはなりません。SHAtteredでは、そこまで実現してはいないようです。

というわけで、結論としては、TLS1.0とTLS1.1がSHAtteredの影響を受けて非推奨と扱われることは、今のところなさそうです。もっとも、TLS1.2のほうが安全度は高く、可能であればTLS1.2に移行するほうが無難ではあります。

以上！SHAtteredに関しては今後も続報が出るかも知れませんので、開発者、運用者の皆様におかれては、ニュースに注意するようにして下さい。幸運を祈る。
Office365とDirSyncしている環境において配布グループ（ML)に外部アドレスのメンバーを追加する方法

厳密にはOffice365は直接関係ないのですが、多くの環境では、ADFSやDirSyncなどを使っていると思います。
下記の参考先では、AD環境とDirSync等で同期している場合には直接Office365上から登録することができないので、同じ手法が使えません。そのため、代替手段を考えました。
ポイントは2点です。

- ローカルのADサーバ上で作成すること。
- 連絡先（Contact)のオブジェクトの作成と属性の変更はそれぞれコマンドを実行すること。

■環境
ADサーバ　Windows Server2012

■前提条件
登録先のMLグループはあらかじめ作成しておきます。（ここではabcml@sample.comとします。）
一括登録用に以下のような読み込み用ファイルを作成します。タブ区切りのテキストファイルです。

--------
Name	Email	givenName	SurName	dn	Description
"鈴木　一郎"	hoge@gmail.com	一郎	鈴木	"cn=鈴木　一郎,ou=abc,dc=sample,dc=local"	abcML

--------

以下のコマンドを実行します。

````PowerShell:sample.ps1

import-CSV C:\temp\abcml.txt -delimiter "`t" -Encoding Default | 
  ForEach-Object{ 
    New-ADObject -Name $_.Name -Type contact -Path "ou=abc,dc=sample,dc=local";
    Set-ADObject -Identity $_.dn -replace @{msExchHideFromAddressLists=$True;mail=$_.Email;DisplayName=$_.Name;givenName=$_.givenName;sn=$_.SurName;Description=$_.Description};
    Set-ADGroup -Identity "abcML" -Add @{'member'=$_.dn};
}

````
■補足
- New-ADObjectで指定している-Path属性ですが、ファイル内にも指定しているのですがうまく読み込めなかったので直接記述しています。ここでは連絡先オブジェクトがabcというOUの中に作成されます。
- Set-ADObjectで指定しているmsExchHideFromAddressListsはグローバルアドレス帳に非表示にするための指定です。
- Set-ADGroup でMLにメンバーを登録しています。

■参考
[Office365でメーリングリストにgmailなどのアドレスをメンバに追加する]
(http://meganehunter.hatenablog.com/entry/2014/05/17/103606 "Office365でメーリングリストにgmailなどのアドレスをメンバに追加する")
ReDoSがPythonでも可能か調べてみた

# ReDoSとは
https://blog.ohgaki.net/redos-must-review-mail-address-validation

なにこれこわい

# 検証
## ipythonでやってみる

```py
import re
from datetime import datetime


n = 5
while n < 12:
    s = "username@host{}.".format(".abcde" * n)
    start = datetime.now()
    print(re.match(r"\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z", s, flags=re.IGNORECASE))
    print('{}: {}'.format(len(s), (datetime.now() - start).total_seconds()))
    n += 1
```

実行結果

```
None
44: 0.085964
None
50: 0.41799
None
56: 2.106463
None
62: 10.319476
None
68: 57.825968
None
74: 269.451777
None
80: 1400.865988
```

まじで指数関数的に増えてる。こえー

## Django の EmailValidator でもやってみる

```py
from datetime import datetime
from django.core.exceptions import ValidationError
from django.core.validators import EmailValidator


validator = EmailValidator()
n = 5
while n < 12:
    s = "username@host{}.".format(".abcde" * n)
    start = datetime.now()
    try:
        validator(s)
        print(True)
    except ValidationError:
        print(False)

    print('{}: {}'.format(len(s), (datetime.now() - start).total_seconds()))
    n += 1
```

実行結果

```
False
44: 0.015296
False
50: 0.000116
False
56: 9.3e-05
False
62: 0.000127
False
68: 0.00016
False
74: 0.000122
False
80: 0.000125
```

お、大丈夫そう。

## ついでに自作のValidatorもやってみる

```py
import re
from datetime import datetime
from django.core.exceptions import ValidationError
from django.core.validators import EmailValidator


class JapaneseEmailValidator(EmailValidator):
    user_regex = re.compile(
        r"(^[-.!#$%&'*+/=?^_`{}|~0-9A-Z]+$"  # dot-atom
        r"|^\"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*\"$)",  # quoted-string
        re.IGNORECASE
    )


validator = JapaneseEmailValidator()
n = 5
while n < 12:
    s = "username@host{}.".format(".abcde" * n)
    start = datetime.now()
    try:
        validator(s)
        print(True)
    except ValidationError:
        print(False)

    print('{}: {}'.format(len(s), (datetime.now() - start).total_seconds()))
    n += 1
```

実行結果

```
False
44: 0.00613
False
50: 9.8e-05
False
56: 8.6e-05
False
62: 9.9e-05
False
68: 0.000127
False
74: 0.000145
False
80: 0.000105
```

# まとめ
セキュアプログラミングとか気をつけないとね
よくわからないときは、Django公式のvalidatorとかにしておけばいいんじゃね
８０文字で１４００sec(23min２０sec)とかないわー
cake php3 で$ _SERVERの値を取得する場合

POST GETのどちらが呼ばれたのかを調べるため、コントローラーで
`if ($_SERVER ["REQUEST_METHOD"] == 'POST') {`
と使って順調ですねーと思ったら、単体テストのphpunitで動かない
「Notice: Undefined variable:」
と怒られちゃいました。

何故に！と思ってググってみたのですが解決方法が見つからず、どうしたもんかと思っていたら、公式にちゃっかり載ってました。
[リクエストとレスポンスオブジェクト](https://book.cakephp.org/3.0/ja/controllers/request-response.html#server-env)

確かに
`if ($this->request->env('REQUEST_METHOD') == 'POST')`
と書いたところ、phpunitでも上手く実行されたのですが、分かりづらいですよ公式さん。

いっそ、\$_SERVERを使わず$this->request->envを使えと言って欲しかった・・
内閣府の「国民の祝日ネ申CSV」をRubyでパースしてみた

http://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html

このネ申CSVをパースします。
![スクリーンショット 2017-02-27 11.42.04.png](https://qiita-image-store.s3.amazonaws.com/0/3345/0252f675-9e77-2acb-04bd-8f6c5e817785.png)

```
$ruby -v
ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin14]
```

```ruby
require 'open-uri'
require 'csv'
require 'pp'

# http://okzk.org/blog/openuri_treat_under_10kb
# Don't allow downloaded files to be created as StringIO.
# Force a tempfile to be created.
if OpenURI::Buffer.const_defined?('StringMax')
  OpenURI::Buffer.send :remove_const, 'StringMax'
end
OpenURI::Buffer.const_set 'StringMax', 0

URL = 'http://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv'.freeze

open(URL) do |io|
  pp(CSV.read(io, encoding: 'CP932:UTF-8').flat_map do |row|
    row.each_slice(2).flat_map do |name, date|
      if date && Date._parse(date).key?(:mday)
        [{ name: name, date: Date.parse(date) }]
      else
        []
      end
    end
  end)
end

```

出力結果の先頭

```
[{:name=>"元日", :date=>#<Date: 2016-01-01 ((2457389j,0s,0n),+0s,2299161j)>},
 {:name=>"元日", :date=>#<Date: 2017-01-01 ((2457755j,0s,0n),+0s,2299161j)>},
 {:name=>"元日", :date=>#<Date: 2018-01-01 ((2458120j,0s,0n),+0s,2299161j)>},
 {:name=>"成人の日", :date=>#<Date: 2016-01-11 ((2457399j,0s,0n),+0s,2299161j)>},
 {:name=>"成人の日", :date=>#<Date: 2017-01-09 ((2457763j,0s,0n),+0s,2299161j)>},
 {:name=>"成人の日", :date=>#<Date: 2018-01-08 ((2458127j,0s,0n),+0s,2299161j)>},
 {:name=>"建国記念の日", :date=>#<Date: 2016-02-11 ((2457430j,0s,0n),+0s,2299161j)>},
 {:name=>"建国記念の日", :date=>#<Date: 2017-02-11 ((2457796j,0s,0n),+0s,2299161j)>},
 {:name=>"建国記念の日", :date=>#<Date: 2018-02-11 ((2458161j,0s,0n),+0s,2299161j)>},
 {:name=>"春分の日", :date=>#<Date: 2016-03-20 ((2457468j,0s,0n),+0s,2299161j)>},
```
PhpStormのTask機能を使ってみよう

PhpStorm、Task機能の基本的な利用方法です。

まだ情報の少ない機能ですが、
この機能を使い始めてからPhpStormでの作業がよりスムーズになったので共有したいと思います。

## 環境
Windows7
PhpStorm 2016.3.2

## この記事のゴール

以下のような内容を記載しています。

- Taskの作成、切り替えができる
- gitのブランチとTaskを連動させることができる
- GitHubのIssueからTaskを作成できる

## Task機能とは

PhpStorm内でのアクティビティ(作業活動)を管理する機能です。
作業ごとにTaskを作成しておけば、作業をスムーズに切り替えながらコーディングを進めることができます。

Taskごとに以下のような情報が関連付けられます。

- gitブランチ
- Changelist
- 開いているファイル

## Taskを作成してみる

ウィンドウの右上にあるTask一覧から「+ Open Task...」を選択。
（もしくはショートカット`Ctrl + Alt + T`でタスク一覧を表示）
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/b1bf62ad-0934-9ff8-42bc-06943d7591b0.png)

検索フォームに新規作成したいTask名を入力して、「Create New Task」を選択します。
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/d3cb910d-58bb-66dd-d607-34846468a678.png)

OKを押せばタスクができあがります。
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/269f5e37-cef7-baf5-fd63-8499f8a47943.png)

Task一覧が「MyTask」に切り替わっているのを確認。
リストから選んで、Taskを切り替えたり削除したりすることができます。
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/674aa895-1d2e-6010-2603-19b7bc07deb3.png)

## gitのブランチと連動させる

プロジェクトがgitリポジトリで管理されている場合は、Task作成時のダイアログが下記のようになります。
(git以外のVCSでも同じだと思います)
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/30315e25-b512-b7de-c13d-9671b92564eb.png)

Taskを切り替えるとブランチも切り替わるようになります。
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/2d4fe065-b63a-13e5-91e5-c5d556b3c337.png) ⇔ ![image](https://qiita-image-store.s3.amazonaws.com/0/113212/3724522d-31ba-e8ec-b60e-55edab7fdaa7.png)

ChangelistもTaskごとに作成されるので、どのタスクで行った変更かも把握しやすくなります。
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/4f3072d3-1e76-d2ef-c08f-55d7a446b197.png)

## GitHubのIssueからTaskを作成する
`Settings > Tools > tasks > Servers`で、様々なチケット管理システムを連携することができます。
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/f8e4eada-29be-f9a2-6fac-7446a7184133.png)

連携した状態でTaskを開くと、以下のようにチケット一覧が表示されるので、すぐに新しいブランチで作業を開始できます。
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/afd9277c-2f45-f88e-b5cb-6fe3fb4bf990.png)
　　↓
![image](https://qiita-image-store.s3.amazonaws.com/0/113212/c718e5b0-96c9-a58d-3b42-19fa697579b0.png)

## 参考
Managing Tasks and Context
https://www.jetbrains.com/help/phpstorm/2016.3/managing-tasks-and-context.html
pandocをCentOS7にインストール

[過去に書いた記事](http://qiita.com/fk_2000/items/d9ba2984349728bb5609)でpandocのことを書いたのに、近頃CentOS7にpandocが簡単にインストールできなくなったので、ソースからコンパイルする方法を書いておきます。

#Pandocとは

Pandocは Haskell製のライブラリおよびコマンドラインツールであり、 あるマークアップ形式で書かれた文書を別の形式へ変換するツールです。


#Stackとは
Stackは、Haskellのパッケージをビルドしたりインストールしたりするツールです。

http://qiita.com/tanakh/items/6866d0f570d0547df026


#事前準備

`$ sudo yum -y install zlib-devel`

#Stackのインストール

petersen-stack-epel-7.repoファイルを作成して、yumインストールする

```
$ sudo vi /etc/yum.repos.d/petersen-stack-epel-7.repo
[petersen-stack]
name=Copr repo for stack owned by petersen
baseurl=https://copr-be.cloud.fedoraproject.org/results/petersen/stack/epel-7-$basearch/
type=rpm-md
skip_if_unavailable=True
gpgcheck=1
gpgkey=https://copr-be.cloud.fedoraproject.org/results/petersen/stack/pubkey.gpg
repo_gpgcheck=0
enabled=1
enabled_metadata=1

$ sudo yum -y install stack
```


#Pandocのインストール

pandocの最新版のソースをダウンロードして解凍する

最新版は[こちら](https://github.com/jgm/pandoc/releases/tag/1.19.2.1)


```
$ wget https://github.com/jgm/pandoc/archive/1.19.2.1.tar.gz
$ tar xf 1.19.2.1.tar.gz
$ cd pandoc-1.19.2.1/
```

事前にテンプレートをダウンロードして、pandocパッケージのフォルダに格納する

```
$ git clone https://github.com/jgm/pandoc-templates.git
$ cp -p pandoc-templates/default.* pandoc-1.19.2.1/data/templates/

```

default.html、default.docbook、default.epubをリネームする。

```
$ mv data/templates/default.html4 data/templates/default.html
$ mv data/templates/default.docbook4 data/templates/default.docbook
$ mv data/templates/default.epub2 data/templates/default.epub
```

stackコマンドでセットアップを実行し、インストールを実行する

```
$ stack setup

Downloaded lts-7.14 build plan.
Preparing to install GHC to an isolated location.
This will not interfere with any system-level installation.
Downloaded ghc-8.0.1.
Installed GHC.
stack will use a sandboxed GHC it installed
For more information on paths, see 'stack path' and 'stack exec env'
To use this GHC and packages outside of a project, consider using:
stack ghc, stack ghci, stack runghc, or stack exec

$ stack install --test
```
少々時間がかかります。

完成すると、pandoc-1.19.2.1/.stack-work/install/x86_64-linux/lts-7.14/8.0.1/bin配下に「pandoc」モジュールが作成されるので、/usr/local/binあたりにコピーする。

```
$ cd .stack-work/install/x86_64-linux/lts-7.14/8.0.1/bin
$ sudo cp -p pandoc /usr/local/bin/
```

バージョンを確認する

```
$ pandoc -v
pandoc 1.19.2.1
Compiled with pandoc-types 1.17.0.4, texmath 0.9, skylighting 0.1.1.4
Default user data directory: /home/fk2000/.pandoc
Copyright (C) 2006-2016 John MacFarlane
Web:  http://pandoc.org
This is free software; see the source for copying conditions.
There is no warranty, not even for merchantability or fitness
for a particular purpose.
```

インストール完了です。

#CSSを指定してMarkdownからHTMLを生成する

`pandoc -c style.css input.md -o output.html`

#宣伝
イレブンナイン株式会社では、エンジニア採用に力を入れています。本稿以外のノウハウも弊社は有しており、日々向上を是として取り組んでおります。自社サービスの開発もその一つです。

弊社のサイトです。
http://www.elevennines.co.jp

弊社のサイトにも採用に向けた応募フォームがありますが、採用強化週間としてIndeed.comに求人広告を載せています。

[Indeed.com - イレブンナイン株式会社の求人広告](http://jp.indeed.com/%E6%B1%82%E4%BA%BA?q=%E3%82%A4%E3%83%AC%E3%83%96%E3%83%B3%E3%83%8A%E3%82%A4%E3%83%B3%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BE&l=&rq=1)

ご興味がありましたらぜひコンタクトをいただければ幸いです。
cloud_sql_proxyで接続しようとするとERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

## 背景

cloud_sql_proxy経由でcloud_sqlに接続する設定をドキュメント見ながらやろうとしたらハマった。
https://cloud.google.com/sql/docs/mysql-connect-proxy?hl=ja


```
mysql -u user -p -host 127.0.0.1
```


で接続しようとするとこんなエラーが出る。

```
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0
```

## 解決策
コンソールのGoogle Cloud SQL APIを有効にする。

コンソールだと

```
API Manager -> ダッシュボード -> APIを有効にする -> 「cloud sql api」 で検索 -> 有効にするをクリック
```

もしくは、

```
https://console.developers.google.com/apis/api/sqladmin/overview?project=<project_id> 
のページにいって「APIを有効にする」をポチる。
```

有効にしてから数分後アクセスできるようになる。

以上。

バックグラウンドで起動していて、以下のログを見逃していたのがハマった原因。

```
2017/02/22 08:53:40 couldn't connect to "project_id:asia-northeast1:xxxxx": ensure that the account has access to "project_id:asia-northeast1:xxxxx" (and make sure there's no typo in that name). Error during createEphemeral for project_id:asia-northeast1:xxxxx: googleapi: Error 403: Access Not Configured. Cloud SQL Administration API has not been used in project 297993258130 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/sqladmin/overview?project=xxxxx then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry., accessNotConfigured
```
[バッドノウハウ]angular-cliのテンプレートファイルを書き換える

angular-cliで作成されるテンプレートが気に入らないという声がありました。シングルクォーテーションが嫌だとか、ここの空白が気に入らないなど。私は長いものに巻かれる主義なので基本的には作成されたテンプレートで作りますが、こだわりの強い人のためにテンプレートを変更する方法を考えました。

# 準備
1. angular-cliをプロジェクトにインストールする。バージョンによってフォルダ構成が変わる可能性があるのでバージョンは固定で入れる。

    ```コマンド
    npm install @angular/cli@1.0.0-beta.32.3  —save-dev
    ```   
1. ファイルコピペするためのプラグインをインストールする。

    ```コマンド
    npm install cpx —save-dev
    ```
1. テンプレを任意のディレクトリ（ここでは`cli-template`）にコピーする

    ```コマンド
    cp -r ./node_modules/@angular/cli/blueprints cli-template      
    ```

1. `cli-template`内のテンプレを自分の好きなテンプレートに書き換える。

1. `package.json`ファイルの`scripts`に次のコマンドを追加する。`postinstall`コマンドは、`npm install`コマンドが実行された後に実行されるコマンドで、`node_modules`以下のテンプレートフォルダを`cli-template`フォルダで上書きするコードです。
    

    ```package.json
  "scripts": {
    "ng": "ng",
    "postinstall": "cpx 'cli-template/**/*.*' node_modules/@angular/cli/blueprints"
  },
    ...略...
    ```

# その後

ngコマンドを使うときはnpm scripts経由で実行します。

```
npm run ng g component piyopiyo    
```

# あとがき
こだわりを持つことも大事ですが、バージョンの変更で構成が変わったりがありますし、チームへの周知も必須です。危険なので出来る限りやめた方が良いです。

# 参考
[Angular-CLIチートシート#独自のテンプレートで出力したいとき - Qiita](http://qiita.com/armorik83/items/5ad850b78e5893d41570#独自のテンプレートで出力したいとき)
iPhoneでセレクトボックスのスタイルを設定する方法

-webkit-appearance:none;をスタイルをリセットしてからcssを適用していく

```css
.select-box01 select {
	-webkit-appearance: none;
	-moz-appearance: none;
	appearance: none;
}
```


参考
https://edge.sincar.jp/web/selectbox-appearance-customize/
Macにpythonとanacondaの環境を構築してみる（pyenv,condaにて）


pythonの勉強でメモ的に

pyenv-virtualenvは使いません。（というか使おうとしましたがうまくいきませんでした）
condaで環境を切り替える方向で書きます。
activateはpyenvとかぶるらしいので、anacondaのほうのactivateをフルパスで指定して行う方向で書きます。

こちらを参考にさせてもらいました。
http://qiita.com/y__sama/items/f732bb7bec2bff355b69

## 環境
Mac OS X El Capitan
python 3.5.2
anaconda 4.3


## 1.pyenvとanacondaのインストール

### ・pyenvのインストール
(1)homebrewかgitで

```bash
brew install pyenv
```

or

```bash
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
```

(2).bash_profile（.bashrc）に設定を追加

```bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
```

(3)読み直し

```bash
source .bash_profile
```

### ・anacondaのインストール
(1)anacondaのインストールできるバージョンの確認

```bash
pyenv install -l
```

(2)anacondaインストール

3系の場合

```bash
pyenv install anaconda3-4.2.0
```

2系の場合

```bash
pyenv install anaconda2-4.2.0
```

## 2.condaで仮想環境を構築し、activateで環境を切り替える
(1)anacondaの環境をglobalに切り替え

```bash
pyenv global anaconda3-4.2.0
```

(2)condaで仮想環境作成

```bash
conda create --name py3.5 python=3.5 anaconda
```
自分のところではpythonのバージョンを指定しないとうまくできませんでした。
また、anacondaの環境も含める場合は後ろに「anaconda」が必要です。

(3)作業フォルダへ移動し、pyenv localを実行

```bash
cd anaconda_sample
pyenv local anaconda3-4.2.0/envs/py3.5
```

(4)一応globalをsystemへ戻しておく（任意）

```bash
pyenv global system
```

(5)activateし、環境を切り替える

```bash
source $PYENV_ROOT/versions/anaconda3-4.2.0/bin/activate py3.5
```

pythonとanacondaのバージョンを確認

```bash
python -V
Python 3.5.2 :: Anaconda 4.3.0 (x86_64)
```

jupyter notebookを起動してみる（任意）

```bash
jupyter notebook
```
ブラウザでjupyterが起動できればOK（anacondaも一緒にいれたから起動できるはず）

(6)deactivateで環境を解除

```bash
source $PYENV_ROOT/versions/anaconda3-4.2.0/bin/deactivate py3.5
```

(7)再度、環境を切り替えるときは作業フォルダに入って、activate

```bash
cd anaconda_sample
source $PYENV_ROOT/versions/anaconda3-4.2.0/bin/activate py3.5
```

## 3.（おまけ）ansibleのインストール
自分はansibleにて開発環境を構築しているので、そこまでインストール
環境は以下です。
Python 2.7.13
Anaconda 4.3.0
ansible 2.2.1.0

(1)anacondaインストール（2系）

```bash
pyenv install anaconda2-4.2.0
```

(2)anacondaの環境をglobalに切り替え

```bash
pyenv global anaconda2-4.2.0
```

(3)condaで仮想環境作成

```bash
conda create --name ansible python=2.7 anaconda
```
一番後ろの「anaconda」はansibleで使うだけならいらないかもです。一応自分はつけてしました。

(4)作業フォルダへ移動し、pyenv localを実行

```bash
cd anaconda_ansible
pyenv local anaconda2-4.2.0/envs/ansible
```

(5)activate

```bash
source $PYENV_ROOT/versions/anaconda2-4.2.0/bin/activate ansible
```

pythonとanacondaのバージョンを確認

```bash
python -V
Python 2.7.13 :: Anaconda 4.3.0 (x86_64)
```

(6)pipでansibleのインストール

```bash
pip install ansible
```

ansibleをcondaで管理したい方は下記のURLを参考
http://stangler.hatenablog.com/entry/2016/10/11/171115

ansibleのバージョン確認

```bash
ansible --version
ansible 2.2.1.0
```

※上記でCentOS、Apache、PHP、MySQLのansible環境を作ってみましたが大丈夫でした。

## 感想
activateの構文がちょっと長いので、何かもっといい方法があれば教えてください。（aliasをつけるといいのかな。。）
しばらくこれで色々勉強ですね！
Azure Storage  アカウント キーの漏洩対策

#注意
本記事の内容は、[Azure Key Vault ストレージ アカウント キー](https://docs.microsoft.com/ja-jp/azure/key-vault/key-vault-ovw-storage-keys)機能により網羅されており古い情報となります。以下は参考情報として残してあります。

#概要
[Azure Storage](https://azure.microsoft.com/ja-jp/services/storage/) アカウントは  512 ビットの文字列からなる 2 つのキー（Primary Key, Secondary Key）で管理されていてます。ストレージ アカウント名と、これらいずれか 1 つのキーを利用して、ストレージ アカウントに保存されているデータ オブジェクト (BLOB、テーブル内のエンティティ、キュー メッセージ、Azure ファイル共有上のファイルなど) へアクセスできます。

#Key の漏えいと再生成
アカウント キーが判れば Azure Storage の全データにアクセスが可能となり、キーの漏洩は深刻なデータ漏えいにつながる可能性があります。このためアカウント キーには柔軟な再生成機能が備わっています。以下のようなキーの漏洩に関する事案が疑われる場合には、ストレージ管理者はキーの再生成を実施しデータの漏洩を防ぐ事が可能です。

 - キー情報を知っている運用・開発チームのメンバーがチームから外れた場合
 - ハッキングなどによりキー情報の漏洩が疑われる場合

#Key が 2 つある理由
管理用のキーが 2 つある理由は、キーの再生成を実施する際に既存アプリケーション（Primary Key を利用）への影響を最小限にするためです。キーの再生成は、Storage サービス全体に同期されるまで最大 10 分程度かかる可能性があります。このためキーの再生成は次のプロセスで実施する事をお勧めします。

	1. Azure ポータルで Secondary Key を再生成します。
	2. Primary Key を利用している既存アプリケーションのキーを Secondary Key に変更します。アプリケーションをテストし発行します。
	3. Azure ポータルで Primary Key を再生成します。
上記のステップにて、アプリケーションのダウンタイムを最小限に抑えながら 2 つのキーの再生成が実施できますが、これにはアプリケーションの改修と再発行などの手間を要します。[Azure Key Vault](https://azure.microsoft.com/ja-jp/services/key-vault/) を利用する事で、よりセキュアにこれらの漏洩対策を実施する事が可能です。

#Azure Key Vault による Key の漏洩対策
Azure Storage アカウント キーの漏洩対策として、Key をシークレットとして Azure Key Vault に格納し、アプリケーションではキーを保持せず格納されたキーを必要に応じて取得する方法があります。この方法ではキーを再生成した場合でも、アプリケーションで必要になるたびにキーを読み取るか、メモリにキャッシュし、使用に失敗した場合に、Azure Key Vault からキーを取得し直すことができます。

Azure Key Vault を使用する事で、[Azure Active Directory](https://azure.microsoft.com/ja-jp/services/active-directory/) を使用してキーへのアクセス権を制御することが可能になります。次の図では、Azure Key Vault に格納されたキーを参照権限のあるユーザーのサービスが読み取り、読み取ったキーを利用してストレージへアクセスしている流れとなります。またこのケースでは、[Azure Automation](https://azure.microsoft.com/ja-jp/services/automation/) により、１時間毎にキーの再生成をすることで、キーの漏洩を防ぐ仕組みを取り入れています。

![Secure-Azure-Storage-Using-Azure-Key-Vault-and-Azure-AD.png](https://qiita-image-store.s3.amazonaws.com/0/166732/142ed193-cc10-02e6-37c9-1f6eba9e3fc5.png)
参考資料：[Say goodbye to key management – manage access to Azure Storage data using Azure AD](http://www.dushyantgill.com/blog/2015/04/26/say-goodbye-to-key-management-manage-access-to-azure-storage-data-using-azure-ad/)