OmniAICreator/Qiita-1.07M huggingface dataset:
Terraformでインフラのコード化を体験してみよう ~ その④SNSを作ってみる


## 前提知識

### [SNS](https://aws.amazon.com/jp/sns/)とは・・？

> Amazon Simple Notification Service (SNS) は柔軟なフルマネージド型の pub/sub メッセージング/モバイル通知サービスで、登録中のエンドポイントやクライアントに配信するメッセージを調整できます。SNS を使用すると、分散システムやサービス、モバイルデバイスなど、多数の受信者にメッセージをファンアウトすることができます。 任意の規模のすべてのエンドポイントで通知をセットアップ、操作、および確実に送信できます。 AWS マネジメントコンソール、AWS コマンドラインインターフェイス、または AWS SDK のわずか 3 つのシンプルな API を使用して、ほんの数分で SNS を使い始めることができます。 SNS を使用することにより、専用メッセージングソフトウェアやインフラストラクチャの管理や運用に関連した複雑さやオーバーヘッドが排除されます。
>> AWSのSNS解説部より引用

端的に2つのサービスがあります。

- 1. pub/subメッセージング
	- 特定の通知先を登録しとくと、SNSに通知が来たときにそこへ通知する機能
- 2. モバイル通知
	- SNSに通知が来たときに、iosやAndroid等のモバイル端末へPush通知出来る機能

### どんな時に使われるのか

例えば、ユーザから問い合わせが来た時に、SNSに通知するようにしていて、
その通知先としてEmailを選択しておけば自分のメールアドレスに通知する。

とかも可能です。

**いきなり通知すれば良いじゃん？**

と思うかもしれませんが、SNSを挟んでおくと、Subscriptionといって通知先を複数登録することが出来るので、例えば急に「やっぱメールも良いんだけど、その場でDBに登録もしてくんね？」等の要望が出てきた場合、SNSなら通知先をLambaやSQSにすることも可能なので、そこへ通知することで、メール通知と同時に登録等も簡単に出来ます。

つまり、**イベント起きた後にxxする**部分を抽象化出来る訳ですので、
使う側(SNSに通知を送る人)としては、通知先と通知方法さえ知っとけば、その先に何が行われるか知ってる必要も無ければ、要件が変わったときにこちら側を修正する必要もない。

## 早速SNSのTopicを作ってみる

作り方は、これも[公式](https://www.terraform.io/docs/providers/aws/r/sns_topic.html)みれば書いてあるので参考にしてみます。

snsのtopicを作る時には`name`だけが必須で、他はオプションとなってます。
policyの設定方法は、これも[公式](https://www.terraform.io/docs/providers/aws/r/sns_topic_policy.html)を参照すると分かりやすいです。

さらに、[sns_topic_subscription](https://www.terraform.io/docs/providers/aws/r/sns_topic_subscription.html)で、SNSの通知先も設定出来ます。


[サポートされてるプロトコル](https://www.terraform.io/docs/providers/aws/r/sns_topic_subscription.html#protocols-supported)を見るとわかりますが、ここでは、`email`, `email-json`, `sms`は未サポートでした。
(これらをsubscriptionにしたい場合は、コンソール上から設定する必要があります)

なので今回は、**SQSをsubscriptionに設定したSNS Topic**を作ります。

```
# SNS
resource "aws_sns_topic" "test_sns" {
  name = "test_sns_topic"
}

# SQS
resource "aws_sqs_queue" "test-sqs" {
  name     = "test_sqs"
}

# 全ての権限のpolicyを与える
resource "aws_sqs_queue_policy" "sqs_queue_polycy" {
  queue_url = "${aws_sqs_queue.test-sqs.id}"

  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Id": "sqspolicy",
  "Statement": [
    {
      "Sid": "First",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "sqs:*",
      "Resource": "${aws_sqs_queue.test-sqs.arn}"
    }
  ]
}
POLICY
}

# SNSのsubscriptionにSQSを登録
resource "aws_sns_topic_subscription" "sub_to_sqs" {
  topic_arn = "${aws_sns_topic.test_sns.arn}"
  protocol  = "sqs"
  endpoint  = "${aws_sqs_queue.test-sqs.arn}"
}```

簡単にやるとこんな感じですね。

## 実際にSNSに通知して、SQSにキューが貯まるかチェック

```
$ aws sns publish --target-arn "arn:aws:sns:ap-northeast-1:138710906407:test_sns_topic" --message "hello world"
{
    "MessageId": "39995d19-8000-5e5d-ab10-0f3eb8c4dabc"
}
```

![スクリーンショット 2017-09-04 20.19.28.png](https://qiita-image-store.s3.amazonaws.com/0/23276/6e3f1cec-5d5a-b4e7-e90b-f978b30a5e31.png "スクリーンショット 2017-09-04 20.19.28.png")

良い感じです。
このように、SNSやSQSもterraformを使えば簡単に作成や設定が可能です。
Go言語とAngularの習作として対戦シミュレーションRPG作ってみた

初めてAngularを触ったとき、「これゲーム作るのに向いているのでは？」と思い勉強と実験を兼ねて作ってみました。
その中で得た色々な気付きを書きたいと思います。

#まずは成果物について

The Dragon Throne CROSS
http://srpg.laineus.com

![Screenshot from 2017-09-04 20-00-00.png](https://qiita-image-store.s3.amazonaws.com/0/151137/97dbf0b8-15d7-6dd7-88ca-81fd6fef2d0a.png)

二人対戦専用のシミュレーションRPG（ブラウザゲーム）です。
canvasなどは使わず、全てDOMでできています。

実際に遊んでいる様子の動画はこちらです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ブラウザ動くでちょっとした対戦シミュレーションRPG作りました。<a href="https://t.co/2UuWmHRYa3">https://t.co/2UuWmHRYa3</a> <a href="https://t.co/qI6uZq5Hft">pic.twitter.com/qI6uZq5Hft</a></p>&mdash; らいね (@Laineus) <a href="https://twitter.com/Laineus/status/904666195676217344">2017年9月4日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

（おともだちが居ない人は違う種類のブラウザを2つ立ち上げて遊ぼう！）

#ゲームとして成り立たせるのは無理でした…

以前「[絵しりとり](https://eshiritori.net/)」というブラウザゲームを作ったんですが、こちらは今も色んな人が遊んでくれています。
こんな感じでオンライン交流コンテンツとして定着することを目指していたんですが、、無理でした…。

主な原因は以下二点、

1.対戦相手がほぼ見つからない
2.シミュレーションRPGとしてつまらない

1ですが、絵しりとりは「BBS」のように時間帯をまたいでも成立する仕組みですが、
このゲームは「チャット」のように同時に操作していないとゲームになりません。

なので、あらかじめ知人と約束して始めるか、偶然誰かが訪れるのを待つしかありません…。

2ですが、ある程度完成した段階で身内と対戦してみて気づきました。
全然面白くない…。これはじゃんけん程度の戦略性しか無い…。

2は戦略性が出るようにもっと作りこんだりすれば、ある程度は改善できそうではありますが、
大変すぎて心が折れてしまったので、「習作」という大盾を構えて公開することにしました。

そんな経緯で、他にも実装しようと思っていた制限時間機能、ランキング機能など様々な機能がお蔵入りしました。

#仕組み

構成はタイトルの通り、Go+Angularで、DBはMySQLです。

ごく普通のSPAで、サーバーはapiのみ、htmlはフロントで吐き出しています。

ユーザー間のデータ同期は、シンプルにapiを数秒ごとに叩きに行っています。

#Go言語

「サーバーサイドで使えるPHP以外の言語を使えるようになりたい」
と思い、なんとなくイマドキな雰囲気漂うGo言語を選びました。

WAFはGin、ORMはgormを使っています。

PHPよりも厳格な分、書いていて安心感が強いです。
バグも減るんじゃないでしょうか。

速さについてですが、もちろんGo言語自体は速いと思います。
ただ、最終的に完成したapiの処理速度はどうなのかというと、特に速くはなさそうです。
詳しいことは分からないですが、多分ORMを導入したことの負担がかなり大きい気がしています。

あまりに遅いところは、生のSQL文に置き換えて対応しました。

#Angular
裏がGoなら表もGoogleで統一しようということでAngularにしました。

完成した今時点では、他のライブラリにも手を出しているんですが、その中だとRiotが一番気に入っております。

##Angularをはじめ、流行りのVDOMやSPAはゲームを作るのに向いている！

実は、半年ほど前にもjQueryで作ったゲームを公開したんですが、
→『[PHP+HTML+JSでレスポンシブ対応のロールプレイングゲーム作ってみた](http://qiita.com/laineus/items/e879dd7e1a9436dce46a)』
正直すごく大変でした。

ゲームはボタンを押すたびにどんどん状態が変化していきますが、
そのためにDOMのステートとボタンイベントを相互に管理していくのは中々骨が折れます。

しかし、AngularなどのViewを持つフレームワークやライブラリを使うことで、
Viewテンプレートに変数がどう展開されるかだけ定義しておき、
あとはひたすらjs側で変数の中身を動かしていくだけでよくなります。

これは非常に感動しました。
フロント界隈で色々なライブラリが流行るのも納得です。

ページ遷移のストレスがない「SPA」もゲームに向いている要素と言えます。

ただ、結局のところDOM要素でゲームを作るのは曲芸みたいなものだと思っています。
その上で、どうしてもDOMでブラウザゲーを作らなきゃいけない人がいたら、Viewライブラリの導入はおすすめです。

##Angularと他のライブラリを比べて

Angularは、他のライブラリより厳格さが強い印象を受けました。
大規模なサイトを大人数で作るときに、破綻しづらいんじゃないかと思います。
一方、VueやRiotのようなシンプルなライブラリは、フリーダムに書ける分、無茶苦茶なコードも出来やすい気がします。

ただ、僕個人で使うにはAngularレベルのがっつり系フレームワークをフロントに導入するのは…。
朝食にカツ丼を食べるようで胃がもたれる気分です。

##まだ良くわからないこと

コンポーネント！
どの粒度で分割すればいいんだろう…。

今回のゲームでいうと、「タイトル画面」「ゲーム一覧」「ゲーム内」の3画面をそれぞれ一つのコンポーネントとして実装しました。

その他、「ゲーム一覧」と「ゲーム内」で重複するヘッダー部分をコンポーネント化したりしてみたんですが、
面倒なデータのやりとりを行ってまで分割するメリットが分からずに辞めてしまいました。

#デプロイ
僕は、gitのリリース用ブランチにプッシュしたら勝手に本番反映してほしい人なんですが、
今回はangularもgoも要コンパイルということでひと手間ありました。

goはsupervisorというアプリで常駐させ、apacheからはリバプロで流しています。
プッシュがあったら、Goで作ったapiを再コンパイルし、supervisorでapiを再起動させます。

angularも同じくプッシュ時にサーバー側で再ビルドします。
node-jt400を試してみた（IFS write）

#IFS write
今回でコーディング例は終わりになります。

```IfsWrite.JS
var jt400 = require("node-jt400");
var express = require("express");
var iconv = require('iconv-lite');
var app = express();

var pool = jt400.pool({ host: '192.168.X.XXX', user: 'MYUSER', password: 'MYPASS' });

var server = app.listen(8888, function () {
  console.log("curl http://localhost:" + server.address().port + '/~');
});

app.get("/ifsWrite", function (req, res, next) {
    var sqlReadableStream = pool.createReadStream("select * from member");
    var ifs = pool.ifs();
    var writer = ifs.createWriteStream("/myIfsFolder/node-write.txt", { append: true });
    
    var buffer = "";
    sqlReadableStream.on("data", function (chunk) {
        buffer += chunk;
    });
    sqlReadableStream.on('end', function () {
        writer.write(iconv.encode(buffer, "UTF-8"));
        writer.end();
        res.send(iconv.encode(buffer, "UTF-8"));
    });
});
```
SQLの結果をIFSに書き出してみました。

![nodejt26.png](https://qiita-image-store.s3.amazonaws.com/0/146069/0a155db9-23bb-f24b-a460-0de6f8e98ed6.png)

コンソールには正しく文字を返却しましたが、IFSのファイルでは文字が化けました。

![nodejt27.png](https://qiita-image-store.s3.amazonaws.com/0/146069/73141c43-5c68-8177-c963-93efc00adeab.png)

#node-jt400のJavaソース改修（文字化け対応）
改修するソースは、\java\src\nodejt400\IfsWriteStream.javaです。
29行目に以下のコードがあります。

```IfsWriteStream.java
fos = new IFSFileOutputStream(file, IFSFileOutputStream.SHARE_ALL, append);
```

コードページを指定します。（今回はUTF-8）

```IfsWriteStream.java
fos = new IFSFileOutputStream(file, IFSFileOutputStream.SHARE_ALL, append, 1208);
```

ビルドが成功したら、jt400wrap.jarを置き換えて再度実行してみます。

![nodejt28.png](https://qiita-image-store.s3.amazonaws.com/0/146069/9372e283-49c5-89f4-d686-c22f71e1a67c.png)

本当はパラメータ化できれば良いのですが、まだそこまで知識がありません・・。

なお、ソース改修における一切の責任を投稿者は負いません。自己責任でお願い致します。

2017年12月28日追記
ビルド済みのjt400wrap.jarを[ここ](https://github.com/ymurata1967/node-jt400/releases/)に置きました。
Laravel + Vue.jsアプリをHerokuで動かしたら読み込みがやたら遅かった件への対応(原因調査〜対策〜結果)

###■問題
Laravel + Vue.jsでWebサービスを作成して、Herokuにデプロイ。
HerokuからOpenAppでページを開いたのですが、
めちゃくちゃ重い。。。
１ページ読み込む毎に10秒〜15秒くらい待たされます。。

###■原因調査
とりあえずどのファイルの読み込みがこんなに遅いのか見るために、GoogleChromeのデベロッパーツールを使いました。
ツールの「Network」タブを開くとどのリソースの読み込み時間や読み込みのタイミングを見ることが出来ます。
<img width="781" alt="スクリーンショット 2017-09-04 2.22.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/121811/bd2f796a-fabe-c903-61c7-86c9f660fbef.png">

これを見ると、
`app.css`と`app.js`の読み込み時間がやたら長いことが分かります。

`app.css`、`app.js`、、、、LaravelMixか???
と思い、本番環境でのアセットコンパイルについて調べたところ以下の記事が出てきました。
http://qiita.com/llhrkll/items/513c23008b2596089a00

なるほど、本番環境でもアセットコンパイルが必要なのか。。(←当然？)

###■対策
記事にある通りに`webpack.mix.js`、`package.json`、`app.blade.php`を編集しました。

その後、

```
heroku run bash
```

```
npm run production
```

でHeroku上のリソースをコンパイルしました。


###■結果
だいぶ速くなったw

<img width="780" alt="スクリーンショット 2017-09-04 19.09.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/121811/95988f53-be65-21d6-b662-de9f4481e99b.png">

10~17sくらいかかっていた読み込み時間が1~2sまで短縮しました。
もっと短くできるのかもしれないけど一旦ここまで。
今は手動で`npm run production`やってるけどHerokuCI使って自動化もして行きたいですね。

こうやって問題解決して行く中で色々新しい知識が入ってくるのは楽しいです^^
ご指摘あれば宜しくお願いします！
rcloneを使ってみた（GoogleDrive連携 on CentOS）

[前回](http://qiita.com/tksnino/items/c33e526af1428fabb7fa)の続編。サーバーサイドです。

### **其の二：CentOSサーバーへ転送**
##### **1.準備**
インストール、confファイル作成までしておく。
https://rclone.org/install/#linux-installation-from-precompiled-binary

##### **2.同期**
rclone rsync を使ってGoogleDrive→サーバーへファイル同期。
cronで3分ごとに実行してみる。
※プロセスが重複起動しないようにした。

```
*/3 * * * * if [ "$$" = "`pgrep -fo /usr/sbin/rclone`" ]; then /usr/sbin/rclone sync DRIVE:/hogefrom /var/www/html/hogeto/ >> /var/log/rclone.log 2>&1; fi
```

##### **3.PHPバッチで処理**
同期したファイルをPHPアプリケーションでごにょごにょする必要があったため、色々処理。
そして処理済みのファイルはGoogleDrive上も別フォルダに移動させたい。
そこでPHP上からrcloneを呼ぶことにする。

まず、Apacheから起動できるようにvisudoを変更。
（参考）http://www.dahlbeck.net/works/posix/50-2014012304

```
Defaults   requiretty
# 追記
Defaults:apache   !requiretty
...
Defaults   !visiblepw
# 追記
Defaults:apache   visiblepw
...
root    ALL=(ALL)       ALL
# 追記
apache  ALL=(ALL)  NOPASSWD: ALL
```

そしてPHPからrcloneを実行。

```rclone.php
$src_path = 'DRIVE:/hogefrom/';
$dest_path = 'DRIVE:/hogeto/';
$rc_conf = '/home/hogehoge/.rclone.conf';
...
$file = ループ回しながらファイル名を取得;
$subdir = ファイル名で階層をつくったり;
exec('sudo /usr/sbin/rclone --config="' . $rc_conf . '" move ' . $src_path . $file . ' ' . $dest_path . $subdir . ' 2>&1', $output, $res);
```

こんな感じで、GoogleDrive上のファイルを取り込み、何らかの処理後、GoogleDrive上のファイルも移動するというバッチができました。
Cognos TM1Webログイン画面のメッセージカスタマイズ

#概要
Cognos TM1 10.2.2で、TM1Webのログイン画面の、下記の赤枠のメッセージをカスタマイズする手順のメモです。
![001.PNG](https://qiita-image-store.s3.amazonaws.com/0/147246/77e310da-49f3-acc1-3ca0-29b1b6c6bc90.png)

同じ様なネタを、Cognos BIで投稿しているのもありますので、こちらもご興味あればご参照下さい。
http://qiita.com/shinyama/items/8c0d05d2ca6893f1cd18

#手順
まずは表示する文言を変えてみます。
文言自体は、以下のファイルに入っています。
C:\Program Files\ibm\cognos\tm1_64\webapps\tm1web\scripts\tm1web\common\nls\ja\CommonMessages.js

ファイルを編集で開き、ファイル内で「しばらくアイドル状態～」の文言を検索して、任意のメッセージに変更します。

    WILL_TIMEOUT_AFTER_INACTIVITY_STR:"しばらくアイドル状態が続くと、システムは自動的にログアウトし再度サインインするように要求します。"
以下に変換します。

    WILL_TIMEOUT_AFTER_INACTIVITY_STR:"アクセスしたいTM1サーバーを選択し、ユーザー名、パスワードを入力後、ログオンボタンを選択してください。"

![003.PNG](https://qiita-image-store.s3.amazonaws.com/0/147246/6c3e8ea1-b0c4-8ec2-add5-d878436cacbe.png)



ブラウザのキャッシュをクリアーして、再度TM1Webに接続すると、さっそく表示が変わっています。
![002.PNG](https://qiita-image-store.s3.amazonaws.com/0/147246/1124a147-9bd9-7075-9974-45b89d860019.png)

次に、メッセージを太字にしてみます。
これは別のJSファイルで、以下となります。

C:\Program Files\ibm\cognos\tm1_64\webapps\tm1web\scripts\tm1web\standalone\TM1WebApp.js
先ほどのCommonMessages.jsに記載のあった、「WILL_TIMEOUT_AFTER_INACTIVITY_STR」を探して、以下のように置き換えます。

    _407.getMessage("WILL_TIMEOUT_AFTER_INACTIVITY_STR")
以下の様に .bold() を追記します。

    _407.getMessage("WILL_TIMEOUT_AFTER_INACTIVITY_STR").bold()

この様に、無事に太字になりました。
![004.PNG](https://qiita-image-store.s3.amazonaws.com/0/147246/b0a881c5-03ff-3f88-641a-90963086a406.png)

もちろん非正規な実装になりますが、これが必要という環境は多くあると思いますので、ご活用頂ければと思います。
Spring Bootでapplication.xmlという名前のBean定義ファイルを使って嵌った

## 背景
- Spring MVCをwar packagingで使っていて、そのBean定義ファイルをapplication.xmlという名前にしていた。
- Spring Bootで動かしたくなったので、まずは`@ImportResource`でapplication.xmlを読み込めるか試した。
- classpathに含まれるように、src/main/resources直下にapplication.xmlを置いた

## 現象
以下のようなエラーが出る。

```
java.lang.IllegalStateException: Failed to load property source from location 'classpath:/application.xml'

... stack trace ...

Caused by: java.util.InvalidPropertiesFormatException: org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 87; Document root element "beans", must match DOCTYPE root "null".

... stack trace ...

```

## 原因
Spring BootのConfigFileApplicationListenerが、xmlをBean定義ファイルではなく設定ファイル（application.properties相当）として読み込もうとしてエラーになる。

デフォルトの設定ファイル名がapplicationで、PropertiesPropertySourceLoaderが対応している拡張子に`xml`が含まれるため、application.xmlが読み込み候補のファイル名になる。また、設定ファイルのデフォルトのlocationにはclasspath直下が含まれるので、`classpath:/application.xml`が読み込まれる。結果として、`@ImportResource`しようがしまいが関係なく、`src/main/resources`直下にapplication.xmlを置いた時点で悲しい選択だった。

## 回避策
- ファイル名を変える  
そもそもapplication.xmlという名前をなんとなくで使ってたのが良くない。
Spring Frameworkのドキュメント通りに作ればおそらく `applicationConfig.xml` になるので、普通の人は遭遇することは無さそう。
- Java化する  
これを期に`@Configuration`化するのも良いタイミングなのかも。
RDSでDBをスナップショットから復元する

こんにちはみなさん

サービスを更新するとき、ときには現時点でのデータベースのデータ構造に手を入れる必要が出てくるかもしれませんが、そんなときは必ずバックアップをとっておくものです。
随分前であれば、`mysqldump`とかを使って生のダンプファイルを取っておいて、復旧時はそのダンプファイルを入れ直すというふうにやっていたと思うのですが、AWSのRDSではスナップショットを定期的に、もしくは能動的に取得することができ、このスナップショットからDBを復元するという手段があるので、それを頼りにする場合があるでしょう。

私の場合は、コンテナ運用時にはそもそもRDSへ直接アクセスする手段を封じていますので、スナップショットによる復元以外には (セキュリティグループの設定を変えたりしない限り) 方法がありません。 

そんなわけで、RDSでスナップショットからDBを復元するときに、引っかかりそうになった部分を、実際のシナリオを元にしてピックアップしていきましょう。

# シナリオ: DBに大きな変更が入る
## メンテナンス作業
実際にDBに大きな変更を入れる場合、コンテナ運用でブルーグリーンデプロイができる状況であっても、データの動きが発生しないようメンテナンスを入れるべきでしょう。
今回は以下のような手順でメンテを実施したとします。

1. アプリケーションをメンテIN
2. **RDSのスナップショットを取得する**
3. バッチでデータを改変する
4. デプロイの成否判定をする
5. 成功したらメンテOUT

まず、スナップショットはメンテに入ってからデータ改変するまでの間にとっておきます。
こうすることで、データ改変前の最新の状態を保存しておくことができます。
操作方法はマネジメントコンソールであれば、

RDS -> インスタンス -> (対象のインスタンスを選択) -> インスタンスの操作 -> スナップショットの取得

で実施できます。

<img width="309" alt="snapshot.png" src="https://qiita-image-store.s3.amazonaws.com/0/102182/042e11e9-426e-e435-f557-591527ab0d46.png">


そして、デプロイの成否判定で、成功しなかった場合に、スナップショットからRDSを復元する作業が入ります。

## 復元作業
復元するときは次の手順に従います。

1. メンテは継続
2. **現在のRDSインスタンスの識別子を変更する**(アプリケーションからのDB接続ができなくなる)
3. スナップショットから復元する。**復元時に元のインスタンスの識別子を指定する**
4. インスタンスが起動する
5. **インスタンスのパラメータグループとセキュリティグループを変更する**(変更適用後、アプリケーションからの接続が可能になる)
6. 復元したRDSを再起動する
7. メンテOUT

意外と手順が多いですね。
もう少し簡単になってくれないかなぁって思いますが、こんなもんなんでしょう。
スナップショットから復元するためには以下のようにします。

RDS -> スナップショット -> (直前に保存したスナップショットを選択) -> スナップショットのアクション -> スナップショットの復元

<img width="299" alt="restore.png" src="https://qiita-image-store.s3.amazonaws.com/0/102182/940c9df9-047d-308f-681a-08740a3be5eb.png">

このあと、RDSインスタンスを生成するためのウィザードが立ち上がります。

# 注意点
## スナップショットからの復元は、インスタンスを生成することである
これ知らなかったんですが、スナップショットからの復元って、既存のDBをロールバックするんじゃなくて、新しくインスタンスを立ち上げることなんですね。
なので、現行DBが残った状態で復旧DBを立ち上げることになります。

復元手順において、はじめに現行のDBの識別子を変更しているのは、復旧DBに現行のDBの識別子を付けさせることで、アプリケーションから接続できるようにするためです。
あとで変えればいいかもですが、この段階で変えておいたほうが早いんじゃないかと。

## セキュリティグループとパラメータグループが初期化される
> 指定した時刻のソース DB インスタンスから新しい DB インスタンスを作成します。この新しい DB インスタンスにはデフォルトの DB セキュリティグループと DB パラメータグループが関連付けられます。 この機能は現在、 InnoDB ストレージエンジンでのみサポートされています . MyISAM テーブルを使用している場合、詳細については以下を参照してください こちら .

ここが面倒なところなのですが、復元されたインスタンスのセキュリティグループとパラメータグループは、何故か元のインスタンスのそれを引き継いでくれません。
つまり、一旦復元が完了してインスタンスが起動した状態で、あらためてセキュリティグループとパラメータグループを変更する必要があります。

パラメータグループは、日本語を含むデータを格納する場合はcharacter_setをutf8にしておく必要があるのですが、デフォルトを適用されてしまい、latin1とかいうクソみたいなcharacter_setになっているので、このままデータを格納してしまうと、文字コードがずれるというかなりまずい状態が発生するかもしれません。

さらに、パラメータグループの変更には再起動が必要なので、ダウンタイムが発生します。
なので、再起動が住んでからメンテを開けるようにする必要があります。

## 古いインスタンスも少しの間だけ残しておくべき
スナップショットからDBを復元した後、データ改変に失敗した古いインスタンスはさっさと消したいところですが、上述したように、いくつか完全に復元できていない部分が出てしまいます。
そのため、メンテ中の確認はメンテ明け後しばらくは古いインスタンスを残しておき、異常が発生した際に復元DBのパラメータに誤りがないかを確認するようにした方がいいです。

# まとめ
というわけで、RDSをスナップショットから復元する際に、発生する微妙な注意点をまとめました。
スナップショットを取っておいて、問題があったらワンクリックでロールバック！なんて都合の良い機能はないんだなぁって思うと、もう少し便利に使えないかなぁって思います(チラッチラッ
え？AWS CLI?そんなものありましたっけ？

今回はこんなところです。

# 参考
[DB スナップショットからの復元](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_RestoreFromSnapshot.html)
macOS Sierra に Homebrew で PHP5.6 と 7.1 入れて、Symfony3.3 と Laravel5.5 をインストールするまでのメモ

# すぐ忘れちゃうから自分用のメモです

## Install Homebrew
```
# 最初にXcodeをApp storeから落としてから、下のコマンドを叩く
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

## Install PHP
```
# 諸々入れとく
brew tap homebrew/dupes
brew tap homebrew/versions
brew tap homebrew/homebrew-php

# 先に5.6入れてUnlinkしてから7.1を入れる
brew install php56
brew unlink php56
brew install php71

# 5.6に戻したい時
brew unlink php71
brew link php56
```

## Install Symfony（https://symfony.com/doc/current/setup.html）
```
# 入れないと、最後の動作チェックで怒られるから入れとく
brew install php56-intl
brew install php71-intl
 
# PHP Accelerator を有効化
brew install php56-opcache
brew install php71-opcache
  
# Install Symfony
sudo curl -LsS https://symfony.com/installer -o /usr/local/bin/symfony
sudo chmod a+x /usr/local/bin/symfony
 
# 今のところは3.3のプロジェクトができる
symfony new my_project_name
 
# 動作チェック
php my_project_name/bin/console server:run
 
ブラウザで http://localhost:8000/config.php を開いて
All checks passed successfully. Your system is ready to run Symfony applications.
ってなったらOK
```

## Install Laravel（https://laravel.com/docs/5.5）
```
brew install homebrew/php/composer
 
composer global require "laravel/installer"
 
# パス通しとく
export PATH=$PATH:$HOME/.composer/vendor/bin
 
laravel new my_project_name
 
# 動作チェック
php my_project_name/artisan serve
 
ブラウザで http://localhost:8000/config.php を開いてLaravelって表示されていればOK
```

ざっつおーる
jq でsubstrみたいに文字列を取得する

# jq
jq 便利ですね。ってもう枯れた話題ですが、いまさらです。
でもちょっとやりたかったことでハマったのでそのメモ。

# substrみたいに文字列を取得したかった
マニュアル嫁ってことで、３０分位格闘しましたｗ。そしてやりたいことが簡単にできることを再確認しました。

## こんなこと
具体的には、下記のjsonの日付(dateTime)文字列を分解して日付書式にしたかっただけ。まあやり方は、色々あるんですがシンプルにしたかったなということで格闘してました。

```text:test.json
{
  "dateTime": "20170904152510701",
  "tempoCode": "Y123456"
}
```

を、下記のように。

```text
2017/09/04      Y123456
```

sed使ったちょっとえぐい感じｗ

```bash:cmd
jq -r '[.dateTime, .tempoCode] | @tsv' | sed 's/^\(.\{4\}\)\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)\(.\{3\}\)/\1\/\2\/\3/g'
```

かっこ悪いｗ。なので

```bash:cmd
jq -r '[ .dateTime[:4] + "/" + .dateTime[4:6] + "/" + .dateTime[6:8], .tempoCode ] | @tsv '
```

できたーｗ

# 便利やわ
json データを加工するために php やら perl で書いていたことを思うとコマンドでできて非常に便利、しかももっと高度なこともできる。

# 参考にさせて頂いたサイト
>+ [jq コマンドを使う日常のご紹介](http://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af)
>+ [jqでcsvをjsonに変換する](http://qiita.com/shobyshoby/items/68204f8567efbd32d705)
>+ [jqでREST APIの結果を整形する](http://qiita.com/niwashun/items/48ad5d55ff76c4a0cdce)
>+ [軽量JSONパーサー『jq』のドキュメント：『jq Manual』をざっくり日本語訳してみました](http://dev.classmethod.jp/tool/jq-manual-japanese-translation-roughly/)
>+ [jqで複数の日付・時刻形式でstrptimeを試みる方法](http://qiita.com/mumoshu/items/9d9fc23efe95a4b34e97)
>+ [JSON Tools: Jq](http://hyperpolyglot.org/json)
pythonメモ：enumerate() -リストのインデックス、要素を同時に取得してfor文を回す

#動機
[前回の記事]()の続きで、[「詳解 ディープラーニング Tensorflfow・Kerasによる時系列データ処理」](https://www.amazon.co.jp/dp/4839962510)を読んでいたところ、kerasでのモデル構造定義の際に、for文でenumerate()という関数が用いられていたのですが、中身が分からなかったので調べてみました。


#enumerate():リストのインデックスと要素を一気に取得
こちらを参考にさせていただきました。
http://www.gesource.jp/programming/python/code/0022.html

```Python:enumerate_check.py
a = [(i+1)*10 for i in range(10)]

for index, element in enumerate(a):
  print(index, '-', element)
```

実行結果
0 - 10
1 - 20
2 - 30
3 - 40
4 - 50
5 - 60
6 - 70
7 - 80
8 - 90
9 - 100

#どういうときに役立つんだろう？
```Python:enumerate_check2.py
a = [(i+1)*10 for i in range(10)]

for i in range(len(a)):
  print(i, '-', a[i])
```
これでも同様の結果でした。
enumerate()の方がいいのでしょうか？単に可読性の問題でしょうか。
PHP の cookie secure 属性で勘違いしてたはずかしい話。。。

お恥ずかしい話ですが、PHP の cookie secure 属性の取り扱いに関して、大きな勘違いをしていたため、なぜ勘違いしたかと念のため行った検証結果を自戒の意味も込めて記述しておきます。

# 勘違いした内容
php.ini に`session.cookie_secure = 1`を設定すれば、session 用の cookie だけでなく、全cookie に secure 属性が付く!?と思ってました。

# なぜ勘違いしたのか？
[session.cookie_secure](http://jp2.php.net/manual/en/session.configuration.php#ini.session.cookie-secure)
> session.cookie_secure specifies whether cookies should only be sent over secure connections. Defaults to off. This setting was added in PHP 4.0.4. See also session_get_cookie_params() and session_set_cookie_params().

google 翻訳
> session.cookie_secureは、クッキーをセキュアな接続を介して送信するかどうかを指定します。 デフォルトではオフになっています。 この設定はPHP 4.0.4で追加されました。 session_get_cookie_params（）およびsession_set_cookie_params（）も参照してください。

前後ちゃんと読めよ。。。って感じですが、session 関連のみの記述になっていることを認識していませんでした。残念なことに、この文章を読んで、setcookie の $secure のデフォルト値が切り替わると飛躍した理解をしてしまった訳です。。。

# 検証
まず、通常の secure 属性付与の様子を確認。
cookie として保存された場合を ○、保存されなかった場合を ☓ とします。

|設定|httpサイト|httpsサイト|
|:--|:--:|:--:|
|setcookie $secure = 0 |○|○|
|setcookie $secure = 1 |☓|○|

まぁ当然の結果です。

次にphp.ini に session.cookie_secure を設定した場合としなかった場合を確認しました。
cookie の発行は、`setcookie('test','hogehoge', time()+36000)`とし、setcookie の $secure のデフォルト値が切り替わるか確認。

|設定|httpサイト|httpsサイト|
|:--|:--:|:--:|
|session.cookie_secure = 0 |○|○|
|session.cookie_secure = 1 |○|○|

切り替わるわけ無いですよね＾＾；

# 結論
全 cookie の secure 属性付与は、
・ラップする関数を用意するして一括制御する
・web サーバで secure 属性を付与する
あたりで対応する必要があります。
php.ini では対応できません。。。

# おまけ １
今回、調査している時に、私と同じ勘違いをしているサイトをたくさん見かけました＾＾；WordPress のサイトを SSL 対応にするぜ！ってサイトが多かったので、大量の犠牲者が出ているものと推測されます。南無。。。

# おまけ ２
実はもう一つ大きな勘違いをしていました＾＾；
cookie って secure 属性付けると、http でのアクセスに対しては、cookie を送信しないと思っていたのですが、secure 属性付きの cookie を発行するんですね＾＾；
**発行はされるけど、ブラウザ側で保存しない**っていう挙動となります。

マニュアルにもヒントが書いてあるんですが、さらっと読み飛ばしていました。

> [setcookie secure](http://php.net/manual/ja/function.setcookie.php)
クライアントからのセキュアな HTTPS 接続の場合にのみクッキーが送信されるようにします。 TRUE を設定すると、セキュアな接続が存在する場合にのみクッキーを設定します。 サーバー側では、このようにセキュアな接続の場合にのみクッキーを送信するという処理は プログラマの責任で行うことになります (たとえば $_SERVER["HTTPS"] の内容を使用します)。

これも勘違いを早めに気がつけて良かったです。
クッキー怖いｗ
Selenium2でダウンロード処理をさせてみる

tsuttieです(*'▽')
今回はSelenium2を使ってのダウンロード処理についてお話していきます。


#1. Selenium2を使ってみて
Webアプリのテスト自動化を目的としてSelenium2を使ったので詰まった点を数回に分けてまとめて行きたいと思います。
#2. 使用したSelenium
・Selenium IDE
・Selenium Webdriver (Java 3.5.0)
※導入方法についてはわかりやすくまとめていらっしゃる方が多くおりますので、そのあたりのお話は省きます。
#3. 【本題】Selenium2にダウンロード処理をさせてみよう
　今回は前回の予告通りということでSelenium2にDownload処理をさせてみたいと思います。
※環境はFirefox(54.0.1)64ビットです。

　まず普通にダウンロード処理を命令するとどういった問題があるのかというところからご説明させていただきます。(^^ゞ


ダウンロードボタンを押してからダウンロードが行われるまでは簡単に以下のような手順を踏むかと思います。


**ダウンロード処理をするまでの手順**
1. ファイルをダウンロードするリンクを選択する
2. ブラウザよりダイアログが発生する
3. ダイアログよりダウンロード場所を指定する
4. ダウンロードを許可
5. 無事ダウンロード開始・終了

大まかに説明するとこんな感じですよね！

と、そこでここで問題が発生します。

**こいつです。**
![download_test.PNG](https://qiita-image-store.s3.amazonaws.com/0/198205/37ce6cf6-15ee-7d42-94bc-4fa2659a6e44.png)


ダイアログ・・・
Selenium2では現状、ダイアログに対して細かい操作を指定できません。
そこで、このダイアログを発生しないようにしなければならないと・・・(・_・;)
（発生した時点でその後の処理は全く操作できなくなってしまいます）

とりあえずFirefoxブラウザを開き
[オプション]-[一般]-[ダウンロード]より
ダウンロード先を指定しましたが、そんな簡単なはずもなく・・・
そもそもwebドライバーを使っていますので、プログラムから開いた場合と普通に開いた時とで設定が異なってしまう状況でした。

そうなればJavaでwebドライバを準備しているときについでに設定してしまおう！
ということですね。
【参考】[Selenium 2.x Web Driverでファイルをダウンロードをする](http://design-ambience.com/blog/?p=114)
以上のURLを参考に書き進めていくと

以下の処理で解決することが出来ました。

```java:Download2017.java

package ~;

import java.io.IOException;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;

public class Download2017 {

	private WebDriver driver;

	@Before
	public void setUp() throws Exception {

		FirefoxProfile profile = new FirefoxProfile();
		//1.ダウンロード場所を指定する0：デスクトップ 1：ダウンロードフォルダ 2：ダウンロードに指定された最後のフォルダ
		profile.setPreference("browser.download.folderList", 0);
		//2.ダウンロード先が指定してあればそれを使う
		profile.setPreference("browser.download.useDownloadDir", true);
		//3.zipファイルは有無を言わさずにダウンロードを行う
		profile.setPreference("browser.helperApps.neverAsk.saveToDisk", "application/zip");
		//4.webdriverの設定(設定したprofileを読み込む)
		System.setProperty("webdriver.gecko.driver", "./driver/geckodriver.exe");
		driver = new FirefoxDriver(profile);

	}

	@After
	public void tearDown() throws Exception {

		driver.quit();

	}

	@Test
	public void test() throws InterruptedException {

		try {

			driver.get("URL");
            driver.findElement(By.id("ダウンロード")).click();
            //ダウンロードリンクをクリック

		}catch(IOException e){

			System.out.println(e);

		}

	}

}


```
簡単にまとめると
1.ダウンロード場所を指定。
2.ダウンロード先を固定
3.ダイアログを出さないように設定
4.その設定をしたprofileを読み込む
といった手順となりました。

おそらく場所指定の方法とかもう少しいい書き方があるのかも・・・
とは思いますが、ひとまずダウンロードはこの方法で何とかなりそうです(^_^)/



#4. まとめ
Firefoxのバージョンがどうだとか、Driverのバージョンがどうとか
エラーもかなり出たので正直そこそこ苦戦しました。
現状はダウンロードすることはできるけどFirefoxのバージョンが上がるとまた対応できなくなるかも・・・とかなり怖い妄想がはかどりました。:skull:

次回はIEで接続してみようかと思います
よろしくお願いします( ˘•ω•˘ )！！
ChromiumOS M59以降でCaps LockをCtrlキーに変更

## 方法

**一般的に、**JP106キーボードを使う時には`Caps Lock`キーを`Ctrl`キーへリマップすると思いますが、Chromebook(ChromiumOS)で下記のように設定画面に表示されていない場合、

![Screenshot 2017-09-03 at 20.19.34.png](https://qiita-image-store.s3.amazonaws.com/0/90678/992473b7-f4f9-8c11-c977-620e554d80bb.png)

1. ｢キーボード｣あたりで右クリックして｢検証｣を選び、デベロッパッパーツールを起動
2. 数行下の`<settings-keyboard>`というタグを探して右クリック、｢Add Attribute｣を選び、`show-caps-lock_`(最後のアンダーバーに注意) という属性を追加

![Screenshot 2017-09-03 at 20.40.58.png](https://qiita-image-store.s3.amazonaws.com/0/90678/8b64fad1-d2ab-27a6-843a-70baa1bb5ad7.png)
3. `Caps Lock`のリマップ設定が表示されました! :tada: 一時的な設定ではなくずっと使えます。

![ink.png](https://qiita-image-store.s3.amazonaws.com/0/90678/f6338f8d-8f2e-37ef-e9e6-780652683dc4.png)

M59以前は[ここ](https://superuser.com/questions/741328/how-do-i-remap-the-caps-lock-key-in-chrome-os/741329#741329)を見て変更していましたが、設定画面が[Polymer](https://www.polymer-project.org/)で一新されてからは同じ方法が使えませんでした。

```html:settings/keyboard-overlay
    <template is="dom-if" if="[[showCapsLock_]]">
      <div class="settings-box" id="capsLockKey">
        <div class="start">CapsLock</div>
        <settings-dropdown-menu label="CapsLock" pref="{{prefs.settings.language.remap_caps_lock_key_to}}" menu-options="[[keyMapTargets_]]">
        </settings-dropdown-menu>
      </div>
    </template>
```

ただ、、、ソース上は設定が入っているみたいなので無事変更できました。

## まとめ

<img src="https://www.polymer-project.org/images/logos/p-logo.png" height="26"> [Polymer](https://www.polymer-project.org/) を知っておくと便利ですよ!

以上
IDDD読んだ感想メモ１

# １．DDDへの誘い

## ユビキタス言語の実現方法

### 用語集を作るという考え方はあながち間違っていない
* チームは用語集に従うことで強制的にユビキタス言語を使用することになる
* 良くも悪くも、言語が統一される

### ただし、用語集はいつでも捨てられるようにしておくこと
* 開発当初は用語集を作るとしても、ある程度軌道に乗ったら不要になると考えるべし。
    * チームの会話やコードが、ユビキタス言語の正である。ユビキタス言語は時間の経過により変わっていくものである。
    * 結果的に、用語集とチームの会話やコードが必ず同期するというのは非現実的。

## DDDを取り入れるということ

### ドメインエキスパート（＝業務知識のある人）との頻繁な仕様確認ミーティング
* つまり、境界付けられたコンテキスト（＝一つの業務単位と思ってよい）ごとに、仕様を確認する（小規模レビューを高頻度で開く）
    * その際に、ユビキタス言語の定義も行う
        * 「この業務／処理は、〇〇〇と呼んでいいですか？」
* めんどくさいかもしれないが、こうすることで、よりドメインに対する理解を得ることができるし、よいドメインモデルを構築することができる
* イテレーティブに、小粒度で打ち合わせをしていくことが大事なのかなと思う
Hyper-Vを使ったdocker-machineでフォルダ共有、マウントを行う

#DockerホストをHyper-Vで作成するとフォルダの共有が難しい
zshの補完が優秀なためBash on Windows(BoW)上でdockerを使うために、docker-machineでWindowsのホスト上でDockerホストを立ち上げて、そこからTLSでBoWからアクセスしています。
そのままの状態で```docker run -v マウントしたいフォルダ:/マウント先```でマウントしようとしても、このコマンドはDockerホスト上のフォルダをマウントしようとするため、BoW上でもWindows上でもなく、Dockerホスト(boot2docker)上のフォルダをマウントしようとします。
VirtualBoxでは共有フォルダ機能を使用してどうにかこうにかできますが、Hyper-V上では一筋縄では行きません。

#作業の流れ
作業の流れとしては、以下の流れになります。

 * Windows上で対象のフォルダを共有フォルダにする
 * boot2docker上で共有フォルダをマウントする
 * dockerのコンテナを起動するときに、boot2dockerでマウントしたパスを指定して、マウントする
 
##1.Windows上で対象のフォルダを共有フォルダにする
方法は色々ありますが、まずは対象のフォルダを共有フォルダにしましょう。
私は、対象のフォルダを右クリックしてフォルダのプロパティから、共有タブで共有フォルダに設定しました。
##2.boot2docker上で共有フォルダをマウントする
boot2docker上でWindowsの共有フォルダをマウントしましょう。
しかしboot2dockerにはWindowsの共有フォルダをマウントするモジュールが標準で入っていないため、入れる必要があります。
必要なのは、cifs-utilsです。
###2.1失敗したモジュールの入れ方
boot2dockerはTinyCoreLinuxをベースに作られているため、各種パッケージを入れるコマンドは、```tce-load```になります。
Hyper-Vマネージャから対象のDockerホスト名のVMに接続しましょう。
パッケージをダウンロードしてインストールするオプションは`-wi`のため、`tce-load -wi cifs-utils`を実行すると、ルートで実行しないでね、と怒られるため、ユーザを作成するなりなんとかします。
既にdockerというユーザが作成されていたため、私はそれを流用しました。
dockerでログインして先ほどのtce-loadを叩くと、途中でコケます。
ログを見ると、
>Downloading filesystems-4.4.84-boot2docker.tcz

のように、boot2docker専用のパッケージを途中で探しにいくようで、存在しないがために404 Not Foundを吐き出します。
ではどうするかというと、boot2dockerはTinyCoreLinuxのカスタムのため、ベースのTinyCoreLinuxのパッケージを入れます。
###2.2成功したモジュールの入れ方
まず、ベースのTinyCoreLinuxのバージョンを調べます。
boot2dockerに接続したdockerから`docker info`を叩きましょう。
色々情報が出力されますが、次の行に注目します。
>Operating System: Boot2Docker 17.07.0-ce (TCL 7.2); HEAD : 24e9d2f - Wed Aug 30 00:04:56 UTC 2017
OSType: linux
Architecture: x86_64

このTCL 7.2というのがTinyCoreLinuxのバージョンになります。アーキテクチャとバージョンだけ覚えましょう。
このバージョンとアーキテクチャから対象のパッケージを探します。
7.2のx86_64の場合次のURLにパッケージ一覧があります。
違うバージョンの場合URLを適宜置き換えてください。

* [Index of /tinycorelinux/7.x/x86_64/tcz/](http://distro.ibiblio.org/tinycorelinux/7.x/x86_64/tcz/)

ここからパッケージを探します。
cifs-utils.tcz.depに依存関係が書かれています。
最終的に、依存関係含めて2つのファイルをboot2docker上でダウンロードします。

* http://distro.ibiblio.org/tinycorelinux/7.x/x86_64/tcz/samba-libs.tcz
* http://distro.ibiblio.org/tinycorelinux/7.x/x86_64/tcz/cifs-utils.tcz

boot2docker上でroot以外のユーザーになったあと、wgetやcurlなどで上記の2つのファイルをダウンロードします。
そのあと、次のコマンドを叩きます。
`tce-load -i samba-libs.tcz`
`tce-load -i cifs-utils.tcz`
これで、boot2docker上でWindowsの共有フォルダをマウントできるようになりました。
そして、WindowsとDockerが所属しているネットワークの、Windows側のIPを調べておきます。
boot2dockerのrootで次のコマンドで共有フォルダをマウントしましょう。
`mount -t cifs //Windows側のIP/共有フォルダのパス /マウント先のパス -o user=共有フォルダの許可したユーザー名,iocharset=utf8`
この`iocharset=utf8`を忘れるともれなく日本語が文字化けします。

##3.dockerのコンテナを起動するときに、boot2dockerでマウントしたパスを指定して、マウントする
コンテナを起動するときに先ほどのマウント先のパスを指定します。
例:boot2docker上で/mnt/shareにマウントして、docker上で/windowsShareにマウントする場合
`docker run  -v /mnt/share:/workspace イメージ名`

以上の流れで共有可能です。
VirtualBoxよりも複雑で難しいですね。
Ubuntu 16.04 でWebサーバー構築するまでのフローとさくらVPSの罠

OSインストールするたびにコマンドとか調べるのは非効率なのでまとめておく。

## 構築する環境

1. 鍵認証でSSHできるようにする
2. Firewallの設定（UFW）
3. Apache でバーチャルホスト
4. PHPなどもいれて WordpressとMediaWikiを使えるように
5. MySQL

## 鍵認証
1. scp で公開鍵をサーバーの ~/.ssh/authorized_keys にコピー
2. クライアント側でパーミッションを 700（rwx全部可）に、サーバー側で600（x以外可）にする。
3. パスワード認証の禁止をする（/etc/ssh/sshd_config でPasswordAuthentication no に）
4. ```$ sudo /etc/init.d/sshd restart ```

## Firewall の設定
1. ```$ sudo ufw allow ssh```
2. ```$ sudo ufw enable```
3. ```$ sudo ufw allow http && sudo ufw allow https```

## Apache
``` $ sudo apt update && sudo apt install -y apache2 libapache2-mod-php ```

## PHP
``` $ sudo apt install -y php ```

## MySQL
### インストール
``` $ sudo apt install -y mysql-server php-mysql ```

rootのパスワードを入力しろと言われるので設定する

### MySQL dump から復元
dumpファイルを復元したい場合は、まず復元するための空のDBを作成
``` $ mysql -u root -p ```
でログインして
``` > create database DB_NAME; ```
一旦mysql抜ける
``` > exit ```
そして次のコマンドでdumpファイルから復元
``` $ mysql -u root -p DB_NAME < DUMP_FILE.dump ```


## よし、Webサーバーにアクセスしよう
ひととおり設定し終えたのでブラウザからサーバーにアクセスしてみようとしたところ、なんどやっても Connection refused. になってしまいます。。。ufw は activeなのに。。。なにがいけないんだ。。。

結論としては、さくらVPSのデフォルトのファイアーウォールが設定されていて、UFWなどでどんなにファイアーウォールの設定をしても無駄だったということです。そのにっくき設定ファイルは ```/etc/iptables/iptables.rules ``` にあります。したがってこれをぶっとばせばUFWの設定が反映される。

``` $ sudo mv /etc/iptables/iptables.rules /var/tmp ```
で、reboot.


## 追記
さくらVPSでは新たにスタートアップスクリプトというサービスを提供してくれました。その中にOSインストール時にデフォルトのファイアーウォールを無効化してUFWを有効化してくれるスクリプトがあったので、それを使うのが良さそうです。
Drupal7の設定方法

# 手順
### 下記URLにアクセス後、Drupalをダウンロードする。
http://drupal.jp/core_download

scriptsディレクトリと同階層のrobots.txt以外のtxtファイルを削除する。
※	Drupalの動作には不要であり、セキュリティ上好ましくない為。

下記URLにアクセス後、[Pick a language: ]で「Japanese」を選択し、[Go There]ボタンを押下する。
https://localize.drupal.org/

手順1でダウンロードしたバージョンに合わせ、drupal-X.XX.ja.poを/profiles/standard/translationsへダウンロードする。

対象hostへアップロードする。
※	/www配下に格納。

sites/default直下のdefault.settings.phpをコピー後、settings.phpへ名称変更、属性変更(666)する。
sites/default直下にfilesディレクトリを作成後、属性変更(777)する。

ブラウザから、ホスト名/手順2/にアクセスする。
※	例：http://xxxxx.com/

[Standard]を選択後、[Save and contitue]を押下する。

[Japanese]を選択後、[Save and contitue]を押下する。

[データベース名]などを設定後、[保存して次へ]を押下する。

サイト名などを設定後、[保存して次へ]を押下する。

画面が表示されたら、正常にインストール終了です。

注意点
エラーが表示された場合、sites/default/settings.phpの属性変更(644)する。
「ファイル sites/default/settings.php は変更に対して保護されていないため、セキュリティー上の危険性があります。
ファイルのパーミッションを書き込み禁止に変更してください。」
rcloneを使ってみた（GoogleDrive連携 on WindowsPC）

### **rclone**
GoogleDriveとかDropBoxとかWEBストレージサービスとファイルのやり取りができるすごいやつ。
https://rclone.org/

どうやって、どんなことをしたのか備忘までに。

### **其の一：Windowsローカルからファイル転送**
##### **1.準備**
ファイルをGoogleDriveに転送するので、まずは設定。
https://rclone.org/drive/
これに従い、コマンドプロンプトで転送先を設定しておく。

なお、デフォルトだとC:\Users:\自分のアカウント 直下に.rclone.confがつくられる。
（confファイル指定オプションもあるので、移動・コピー可）

##### **2.実験**
コマンドプロンプトで転送実験

```
rclone --config .rclone.conf copy "C:\path\to\hogehoge.mp4" drive:hogehoge
```

##### **3.ツリー構造の複数ファイルを転送する**
今回は、フォルダ分けして整理したファイルを、フォルダツリーの名前をファイルに付与して転送する必要があった。

---
1_hoge
　└11_hogehoge
　　└hogehoge1.mp4
　　└hogehoge2.mp4
　└12_hogefuga
　　└xyz.txt
2_fuga
　└21_fugafuga
　　└fuga.mp4

↓こうやって転送したい

hoge_hogehoge_hogehoge1.mp4
hoge_hogehoge_hogehoge2.mp4
hoge_hogefuga_xyz.txt
fuga_fugafuga_fuga.mp4

---

リネームとか処理が必要なので、pythonを使うことに。（こちらも経験浅）
最終的にはこんなものを書いた。
コマンドプロンプトから引数にルートフォルダ渡す形で実行。

```rclone.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import random
import sys
import time
import logging
import datetime
import re
import shutil
import subprocess

DRIVE = "drive:hogehoge"
RCCONF = ".rclone.conf"

def decode_windows(str_p):
  return str_p.decode('cp932', errors='replace')

def encode_windows(str_u):
  return str_u.encode('cp932', errors='replace')

if __name__ == '__main__':
  pdir = sys.argv[1]

  try:
    target = os.path.join(os.pardir, pdir)
    for root, dirs, files in os.walk(decode_windows(target)):
      dirname = re.sub(r'^.*' + decode_windows(pdir), '', root) #ルートフォルダ除去
      dirname = re.sub(r'\\[^\\_]*_', ' ', dirname).replace('\\', ' ') #「_」以前の除去、区切りの空白化
      dirname = re.sub(r'^ ', '', dirname) #先頭空白除去
      dirname = re.sub(r' ', '_', dirname) #空白->アンダーバー

      for f in files:
        if f.endswith('.lnk'): #リンクは除外
          continue

        if f.startswith(dirname):
          renamed = f
        else:
          renamed = dirname + '_' + f
        os.rename(encode_windows(os.path.join(root, f)), encode_windows(os.path.join(root, renamed)))

        #GoogleDriveにpush
        cmd = 'rclone --config "' + encode_windows(os.path.join(os.pardir, RCCONF)) + '" copy "' + encode_windows(os.path.join(root, renamed)) + '" ' + DRIVE
        print 'Do Copy To GoogleDrive.'
        subprocess.call(cmd, shell=True)

  except Exception as ex:
    print '\n'
    print ex
    print '\n'
    sys.exit(1)
```

文字化けとかハマりましたね。。。

##### **次回**
[LinuxサーバーとGoogleDriveの連携](http://qiita.com/tksnino/items/52d618b115e5af8e25cb)
SoapUIでJava8を利用する

# SoapUIでJava8を利用する

## 導入
SoapUI 5.3.0(Installer版)で使われているJAVA Verが7のため、
デフォルトではTLSv1.2がDisableとなっている。
引数、環境変数等でTLSv1.2を許可してもいいが今回はJAVA8を利用したいと思う。


## インストール
SoapUIのアーキテクチャ x86 か x64か
JAVAのアーキテクチャ x86 か x64か
を統一する

SoapUIx64はLatestReleaseからDLできる
https://www.soapui.org/downloads/latest-release.html

例
JAVAx64を利用する場合SoapUIx64
JAVAx86を利用する場合SoapUIx86

## 環境
### 環境変数
JAVAに対し
PATH、JAVA_HOMEを設定

最近のWindows版のインストーラーでは
Pathに対し
C:\ProgramData\Oracle\Java\javapath
が追加されjavaコマンドが動くようになっている

### 動作環境
%SOAPUI_HOME%..\jreをリネームする

例
C:\Program Files\SmartBear\SoapUI-5.3.0\jre
↓
C:\Program Files\SmartBear\SoapUI-5.3.0\jre~

## 起動

SoapUIを起動する

SoapUI画面下部のSoapUI logを開き

Used java version: 1.8.0_xxx

の表記が出ていれば成功。

# 解説
付属のjreが存在しない場合
システムにインストールされているjreを利用する構造を利用したもの。
javaコマンドへパスが通っていれば実行できるようになる。

それっぽいコードがbin\soapui.batに書かれているため参考にした。

# 問題点
JAVAとSoapUIのアーキテクチャが一致しないと「SoapUI.exe」は動かない。
bin\soapui.batからの実行はアーキテクチャが一致しなくとも動いた。

# その他仕様
SoapUI 5.3.0の話。

SoapUI.exe内部でJAVAのx86 x64の差異をチェックしている。
zip版soapui-5.3.0.jar及びlib内のバイナリに関してはx86 x64の差異が無かったため
SoapUIx64 zip版を利用するとjreがx86であろうとx64であろうと実行できる上、
SoapUIx64パッケージがx86のWindows上でも実行可能と思われる。

むしろjre無しzip版はx64と記載しなくてもよいのでは…？

このため
JAVAがすでにインストールされている場合
100MB以上のjre同梱版をDLするより40,50MB程度のzip版を利用することで
従量課金制回線の通信費節約や、低速回線の時短に寄与できるかと思う。
composerのlaravel/installerがいつしか動かなくなっていた


いつも通り、`composer global require "laravel/installer"`と打つと下記のエラーが。

```bash
$ composer global require "laravel/installer"
Changed current directory to /root/.composer
Using version ^1.4 for laravel/installer
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - laravel/installer v1.4.1 requires ext-zip * -> the requested PHP extension zip is missing from your system.
    - laravel/installer v1.4.0 requires ext-zip * -> the requested PHP extension zip is missing from your system.
    - Installation request for laravel/installer ^1.4 -> satisfiable by laravel/installer[v1.4.0, v1.4.1].

  To enable extensions, verify that they are enabled in your .ini files:
    - /etc/php.ini
    - /etc/php.d/10-opcache.ini
    - /etc/php.d/20-bz2.ini
    - /etc/php.d/20-calendar.ini
    - /etc/php.d/20-ctype.ini
    - /etc/php.d/20-curl.ini
    - /etc/php.d/20-dom.ini
    - /etc/php.d/20-exif.ini
    - /etc/php.d/20-fileinfo.ini
    - /etc/php.d/20-ftp.ini
    - /etc/php.d/20-gd.ini
    - /etc/php.d/20-gettext.ini
    - /etc/php.d/20-iconv.ini
    - /etc/php.d/20-intl.ini
    - /etc/php.d/20-json.ini
    - /etc/php.d/20-mbstring.ini
    - /etc/php.d/20-mcrypt.ini
    - /etc/php.d/20-mysqlnd.ini
    - /etc/php.d/20-pdo.ini
    - /etc/php.d/20-phar.ini
    - /etc/php.d/20-simplexml.ini
    - /etc/php.d/20-sockets.ini
    - /etc/php.d/20-sqlite3.ini
    - /etc/php.d/20-tokenizer.ini
    - /etc/php.d/20-xml.ini
    - /etc/php.d/20-xmlwriter.ini
    - /etc/php.d/20-xsl.ini
    - /etc/php.d/30-mysqli.ini
    - /etc/php.d/30-pdo_mysql.ini
    - /etc/php.d/30-pdo_sqlite.ini
    - /etc/php.d/30-wddx.ini
    - /etc/php.d/30-xmlreader.ini
  You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.
```

## 解決策
`php-zip`をインストールすればOKです。

```bash
# yum-config-manager --enable remi-php71をしている状態です
$ yum -y install php-zip
```
root権限なしでGraphvizをインストールする．

root権限がない環境でGraphviz[^1]をインストールする方法です．

## 作業手順

```
mkdir ~/usr
wget http://www.graphviz.org/pub/graphviz/stable/SOURCES/graphviz-2.40.1.tar.gz
tar xvzf graphviz-2.40.1.tar.gz
cd graphviz-2.40.1
./configure --prefix=$HOME/usr
make
make install
```


## 動作検証

hello.dotとしてdotファイルを作成する．

```
graph g {
    "hello world"
}
```

下記コマンドでグラフを作成する．

```
~/usr/bin/dot -T png hell.dot -o hello.png
```

無事hello.pngができていれば成功です．

![image.png](https://qiita-image-store.s3.amazonaws.com/0/107399/68405a07-1aaa-b65f-682d-3e141b7d3dd0.png)

## References

[^1]: [Graphviz - Graph Visualization Software](http://www.graphviz.org/Home.php)
phina.jsでbase64形式で画像を使う

使える。


![2017-09-04_16h35_31.png](https://qiita-image-store.s3.amazonaws.com/0/62354/10c45220-4da9-448a-5066-06d3305e858d.png)


```js
phina.define('MainScene', {
  superClass: 'DisplayScene',
  init: function() {
    this.superInit(); 
    const player = Sprite('player').addChildTo(this);
    player.x = this.gridX.center();
    player.y = this.gridY.center();
  }
});


const ASSETS = {image: {
  player : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAABACAYAAAB7jnWuAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwwAADsMBx2+oZAAAA1pJREFUaEPtlSGoFFEUhl9+ebFr0GJ4YFBQLCIbBcEoD9Ri0WLWIIJFRDFZXnpVBZuI3WAQkyAGwWQQbKZxv4v/8O+ZM/fNzKogzIGPe++595z/v7Ozu1tzzDHHHHPMMUfTNJNYLBZNJJ4ZQprsw8XuXLnUwfdjbR9pMlITdV4+vldgPtREmnRo9P7Vi7ZxhoQ552eHmEiTggZ9zZX3Pd+H3XMnDzSRJsHF1dAbQ8w7OjPJAEUUZ+Kw3Dla0Dozwz55xpqJNKnbq5kLFGO7O62A5yXIWvswyoBu743VVI2/PdoteF5iymnOONqAmgJNuLE3dQPkdI65C/vYZ6KTcAMqRszNsH6wPFwgx96nVatn29sdYc1HG1CRBN2MgyjiUVjjZAMUMpeQGzh75FALa4lgxEV9PsqAipkz8qj15iOox//m85cyknNxx41kJtYWQsKMLkKOcf/dh5L7+P1H2dce/Hz9tKD1RgYkwqOmKUKMevwE+zKgMzonYTHYAHDYDTRf35amjJkBzrKvl1YGdJlJBiiSaB/sg27eZyATh05CTDWgNbWTDegwo5pGYfLRALenJopqzEiTQs3cBPM+cd6DIaJOmhTejOYyEoX1ufP1vLW33z4F9amRJjPUFCMOwkBg4Myp4y1DTKTJCI3UFBFCwlpL/Pq1i4W/YoDGesyE5lH8ycPbg02kScfF1bh8zveXZQTf01zrP24AuPGx51fbJ+CC/qS0XzORJh2K400JDBCZAYQ9WPeZ6CQciesmbkDBnouDQnUw2QBNQM0R8sgMkFOofpIBoJAfmpoBcm6AGn1N9fO8irR/mnTUTOI1AzJBjf9aTjbgN5EBRg8MuDk3waj9PhOdhCMD+gjcAI01ai8zIEYboMD/cNRQ34oT50+XEcixJwNF7Pe/pddHDegkRGzCGlFx4eblzrh221Wt6icbcPcSubF3tzpyTgYQ9wtEDegkHIqEmg8dvRZib5EmM2jCTfypRIbcOJImMw4SKGv73P+5AZ0ZayJNRmikN7x9yzc456TJCI30lws1A0POOWkyQqOhNxtzFtJk5L81wHwjA9aghH77a039vKJ2Pk0CRYgpJF4zoJqsrq+mkxAU+BsNa/92PTXsZ3WTDNSI5yE758TzTdNs/QIWqxL7Ezfl1gAAAABJRU5ErkJggg==',
}}

// Main
phina.main(function() {
  const app = GameApp({
    startLabel: 'main',
    assets: ASSETS,
  });
  app.run();
});

```

http://runstant.com/runstataccount/projects/38f617ed


変換は
[Base64エンコーダー (画像を簡単に変換)]

ただし、普通は使う必要はなくて、runstantがファイルアップロードできないから。

全画像をbase64化するのも別の場所確保も辛いので…どうするべきか。
jsdo.itはファイルアップロードできるのでそっちの方が良いか。


# 前回

[phina.jsでグリッドに四角形を敷き詰める - Qiita]

[phina.jsでグリッドに四角形を敷き詰める - Qiita]:http://qiita.com/khsk/items/1bec0a7fa6cc58b2356c


[Base64エンコーダー (画像を簡単に変換)]:https://lab.syncer.jp/Tool/Base64-encode/
[Fusion360]休憩時間にfusion360と遊ぶ その3。

今日はYouTubeみながら、ARDUINOのケースを作り方を学びました。

[作ったリンク](http://a360.co/2iN1gt6) < - 

![ard01.JPG](https://qiita-image-store.s3.amazonaws.com/0/137182/73b5e36e-3226-07b7-bdc4-f1272321bfa4.jpeg)

![ard02.JPG](https://qiita-image-store.s3.amazonaws.com/0/137182/61d50036-2c12-d6da-9030-b857c4aea692.jpeg)



#参考になった。
1．[Designing an Arduino Uno Enclosure with Fusion 360](https://www.youtube.com/watch?v=E0bhdr84FNU)
2. [Arduino UNO in Fusion 360 Format.](https://gallery.autodesk.com/fusion360/projects/22415/arduino-uno-1?searched=)
LambdaでAWSの料金を毎日Slackに通知した結果課金されてしまった

# はじめに
[ブログにも書いてます](https://toshi.click/aws-0001/)
請求アラートは設定していますが、それとは別に[AWSの料金をLambdaのcronで定期チェックしてSlackに通知する](http://qiita.com/saku/items/fc6b70a420a5c510de2b)を設定して１ヶ月間運用してみました。  
毎日金額がわかるとやっぱり安心できますよね。

# 推移
![2017-09-04 (4).png](https://qiita-image-store.s3.amazonaws.com/0/128244/35668df6-7401-f9ae-20ca-fc45ff517a8c.png)
![2017-09-04 (5).png](https://qiita-image-store.s3.amazonaws.com/0/128244/0bf22333-6802-50f6-ef4e-f3860ff28ae0.png)
![2017-09-04 (6).png](https://qiita-image-store.s3.amazonaws.com/0/128244/52fb9d21-4a22-1ef5-3089-11614e09267c.png)
![2017-09-04 (7).png](https://qiita-image-store.s3.amazonaws.com/0/128244/65275b81-1b70-0a27-eecf-9d760abfd459.png)
![2017-09-04 (8).png](https://qiita-image-store.s3.amazonaws.com/0/128244/325deb3d-8555-b38e-02ea-fb0698471f5d.png)
![2017-09-04 (9).png](https://qiita-image-store.s3.amazonaws.com/0/128244/c457c540-2685-70ff-2fce-8d442302b653.png)


# おわりに
安心のために2円(2017/09/01のレート)支払うことになった。
悲しい。
「明日・やろうは・バカ・やろう」をランダムに表示し「明日やろうはバカやろう」が完成したら煽ってくるプログラム


http://qiita.com/sanonosa/items/d619c7f88e69ab205241

こちらの記事を見たので真似してノリで書いてみました。
言語はRubyです、かなりシンプルになってます。


## プログラム
```
# 明日やろうはバカやろう　で煽るプログラム

ary = ["明日", "やろうは", "バカ", "やろう"]
moji = ""
loop do
  word = ary.sample
  moji << word
  print word

  break if moji =~ /明日やろうはバカやろう/
end

puts <<EOT
"#{moji.length}文字で煽られました。"
"＿人人人人人人人人人人人＿"
"＞明日やろうはバカやろう＜"
"￣Y^Y^Y^Y^Y^Y^Y^Y^Y^Y￣"
EOT
```

特筆することはないです。。。
Rubyの基本を使って簡単にかけます。

おかしなところがあればコメントお願いします

※ コメントいただいた修正をいたしました。 @scivola さんありがとうございます！
[CEDEC2017]本格スマホRPG『アナザーエデン』開発の裏側を包み隠さずお話します　〜コード資産も無く、チームとしての経験も豊富ではない中エンジニアはどう挑んだのか〜

#本格スマホRPG『アナザーエデン』開発の裏側を包み隠さずお話します　〜コード資産も無く、チームとしての経験も豊富ではない中エンジニアはどう挑んだのか〜

##講演者
阿部 智司　さん（グリー株式会社）
井田 勝　さん（グリー株式会社）

##講演内容

###アナザーエデンの概要
- 2017年4月12日にリリース
- 現時点で300万DL
- 開発開始は2015年4月
- 現在は2~3週間の頻度でバージョンアップを行っている

###開発環境
- Mac
- git
- Jenkins
- Cocos2d-x
- Spine
- LWF([Lightweight SWF](https://github.com/gree/lwf))
- Cricret Audio
- CRI Sofdec

###開発人員
約60名でアート職が一番多かった。
リリース時期までのコンシューマ開発経験者が6名程度しかいなかった

###開発中の課題解決と現在
- 開発開始時 

10名程度の人員で開発を開始し、まず初めに目指すゴールの共有を行った。
1ヶ月間で2DライクなRPGを作成し、飛び出す絵本のような表現を目指して開発を行った。


- トライアルアンドエラーを効率よく

動作確認→データ入力→長いアセットビルド→アプリビルド→インストール
このPDCAサイクルを効率よく回す必要がある。

- Furutyを使用

MacOS上でネイティブに動作するゲームクライアント
実機/MacのSchemaを切り替えて動作するようにしている。

通常ゲームモードとマップ編集モードの2種類で動作するように行っている。

- 通常ゲームモード

・製品版と同様の動作を行う
・各種デバッグ機能を搭載しており、デバッグ関連だけでも100カテゴリに及ぶデバッグ項目を用意
・約300ファイルに上るデバッグ用コードが存在
・mac上で動作するため各種キーボードのショートカットを用意

- マップ編集モード

・通常モードに編集用UIを被せ、移動経路の設定やオブジェクト配置などのエディット機能
・配置情報などのデータは開発中はjsonで出力し、最終的にはFlatBuffersで出力を行っている

- イベントスクリプト

・各種イベント（フィールドやクエストなど）をLuaスクリプトを使用して作成
・約450命令に上るC++の命令処理が存在している。

- マップ作成

・上記のマップ編集モードを用いてデータを作成している。
・壁と床の種類はそれぞれ4種類ずつ
・一番重いマップではオブジェクトが1900個ほど配置されているとのこと


###ゲーム開発未経験者の苦悩と闘い
- バトル部分を担当

バトル部分のコード資産が無い状態で始めたため、スクラッチで実際に触るところまでとにかく
実装、仕様や演出のブラッシュアップを行っていた。
レベルデザインを行えばいずれは面白くなるはずを計5回繰り返して完成。

最初はアクションゲームとして実装を行っていたが、2016年にある事件が発生し、
ユーザーにアクション制かターン制かのアンケートを行い、ターン制ゲームとして作ることとなった。

###その他の課題
エリア切り替えなどをシームレスで実装することとなったため、
切り替わるときのカクツキの対策を念入りに行っていた。

- 原因

・膨大な量のアセットをロードする際にcocos2d-xのI/O処理がブロッキング処理だった。
・JSON形式のファイルのパース処理が重い

- 対策

・独自スレッドを立ててロード処理を非同期で行うように対応
・パース処理が重たいのでバイナリ形式のファイルに変更

- さらなる課題

非同期処理に切り替えたことにより、クラッシュが頻発するようになってしまった。
そこでXcodeのAddressSanitizerを使用して原因の特定修正を行った。

###作業の効率化
作業の効率化を行うために以下ものを実装

####Hubotで実装したchatbot
- 定型業務のサポート
- アプリのビルド
- デプロイ
- ビルド
- 各種検索

これらをチャットベースで行えるように対応


####マスターデータの入力ミス
マスターデータはエクセルベースで作成を行っている。
また、バージョン管理システムがgitを使用しているためロックすることが出来ずに
巻き戻りやコンフリクトが発生してしまっていた。
Excelの差分なので修正差分を表示することが出来ないため、
ロックや差分ができるようなものを作成して運用を行っている。

##まとめ
コード資産が無い状態で開発を行った際の問題点や
コードではない部分の問題点のお話を聞くことが出来、
非常にためになりました。開発環境が無いなら作るという
チーム全体の意思やゴールを明確化していた
部分などどのような開発でも応用が利くものと思っています。
gitリポジトリ単位で バックアップ、アーカイブ、リカバリ

# やりたい事
- リモートで管理しているgitリポジトリを丸ごとバックアップ、アーカイブ、リカバリしたかったのでメモ
 
# 実現するには…
- バックアップ : `--mirror` オプションを付けて clone する
- アーカイブ化 : clone したリポジトリをtarなどでアーカイブ化して保管
- リカバリ方法 : `--mirror=push` オプションを付けて リモートリポジトリを作成

# リモートリポジトリのバックアップ
- `--mirror` オプションを付けてリモートリポジトリをclone

```
git clone --mirror "git@github/path/to/repo/repo.git" "/path/to/repo.git"
```

- 通常のcloneとは異なり対象リポジトリの .git ディレクトリのみがCloneされる。

```
ls -al "/path/to/clone/repo.git"
```

# アーカイブ化
- `--mirror` でcloneしたディレクトリを丸ごと圧縮、保存してあれば後のリカバリに使える
- tar.gz でアーカイブ化するなど...

``` 
tar -zcf "/path/to/archive.tar.gz" "/path/to/repo.git"
```

# リポジトリをリモートリポジトリへ復元する
- Clone済みの `/path/to/repo.git` ディレクトリへ移動してから作業する

```
cd "/path/to/repo.git"
```
- `--mirror` オプションを付与して Pushする

```
git remote add --mirror=push origin "git@path.to.repo"
git push origin
```

- Pushしたリポジトリを別名でCloneしなおすなどで過去のコミットログの反映状況を確認する

# その他
- gitホスティングのサービス間でリポジトリを移動させたい場合に利用できる。
- リポジトリ単位でバックアップ、アーカイブ化する用途に使える。

# 参考
- http://qiita.com/ngyuki/items/35e369812588c2aebcc7
- https://techacademy.jp/magazine/10268
Contact Form 7とWP-Mail-SMTPプラグインの組み合わせでメール(2)が送信できない

以下の環境で確認

+ PHP 5.6.22
+ WordPress 4.7.2
+ Contact Form 7プラグイン 4.9
+ Contact Form 7 add confirmプラグイン 4.8
+ WP-Mail-SMTPプラグイン 0.10.1

WP-Mail-SMTPプラグインの「メーラー」設定で「WordPressの全てのメールをSMTP経由で送信する」を選択し、SMTP設定でメールを送信した場合、Contact Form 7プラグインで「メール(2)」を設定していても送信できませんでした。（最初に設定した「メール」の方は送信されます）

※「PHP mail()関数を使用してメールを送信する」を選択すれば2通とも送信されます。
Google APIで特定のファイルを出力する

## ログインの権限で、ドライブを触れるようにする。

```
https://accounts.google.com/o/oauth2/auth?client_id=[client_id]&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/drive&response_type=code&approval_prompt=force&access_type=offline
```

## アクセストークンを取得する。
```
curl -k -d client_id=[client_id] -d client_secret=[client_secret] -d redirect_uri=urn:ietf:wg:oauth:2.0:oob -d grant_type=authorization_code -d code=[ブラウザで取得したコード] https://accounts.google.com/o/oauth2/token
```

## ファイルのリビジョン情報を取得する。

```
curl -sSLG \
    -H 'Authorization: Bearer [access_token]’ \
    'https://www.googleapis.com/drive/v3/files/[file_id]/revisions?fields=revisions(id%2CmodifiedTime)'
```

※もし、reasonがaccessNotConfiguredとなった場合、Drive APIが向こうになっているので有効にする。
https://console.developers.google.com/apis/api/drive.googleapis.com/overview?project=[プロジェクトID]

## 出力形式を指定してファイルを出力する。
```
curl -sSLG \
    -d "mimeType=application/zip" \
    -H 'Authorization: Bearer [access_token]' \
    "https://www.googleapis.com/drive/v3/files/[file_id]/export?revisions=[revision番号]“\
    -o [出力するファイル名]
```

他のmimeTypeは、下記URLに記述してある。
https://developers.google.com/drive/v3/web/manage-downloads

----
APIを利用するには下記設定が必要。
OAuth2の設定をする。
https://console.developers.google.com/apis/credentials

google api+を有効にする 
https://console.developers.google.com/apis/api/plus/overview
mysqlでsqlを外部ファイルから実行する

```
mysql -u ユーザ -D スキーマ -pパスワード < sql_0904.txt
```

### sql_0904.txtの中身
insert into test_table(test_clm, created)values('test1',CURRENT_TIMESTAMP);
insert into test_table(test_clm, created)values('test2',CURRENT_TIMESTAMP);
insert into test_table(test_clm, created)values('test3',CURRENT_TIMESTAMP);
insert into test_table(test_clm, created)values('test4',CURRENT_TIMESTAMP);
insert into test_table(test_clm, created)values('test5',CURRENT_TIMESTAMP);