OmniAICreator/Qiita-1.07M huggingface dataset:
SQLServer　日付の扱い（SELECT,CASE）

# **はじめに**
仕事でSQLServerを扱っており、SELECTやプロシージャを作成する時に日付型を使うことが多いのですが、よく忘れて調べ直すことが多いので、まとめてみました。

# **YYYYMMDDの形式で表示**

まずGETDATE()で**2018-04-10 19:00:00.000**のように表示されます。

これを**2018-04-10**にするためには、、

```SQL:
/* INT型の変数定義 */
DECLARE @TODAY AS INT;
/* -を置換して変数に代入 */
SET @TODAY = REPLACE(CONVERT(date,GETDATE()),'-','');
```
**→　20180410 と今日の日付が表示される**

それでは、これを一緒にSELECTしてみます。

```SQL:
/* 変数定義 */
DECLARE @TODAY AS INT;
SET @TODAY = REPLACE(CONVERT(date,GETDATE()),'-','');

SELECT 
	@TODAY [YYYYMMDD],   --YYYYMMDD形式
	GETDATE() [現在時刻] --変換前
```

▼実行結果

|     | YYYYMMDD | 現在時刻                   |
|:----|:--------:|:-------------------------:|
| 1   | 20180410 | 2018-04-10 19:54:32.290   |

今回は一度変数に入れていますが、直接SELECT文に書いても大丈夫です。

# **様々な形式で表示**

Salesforceに取り込む時は、この型で取り込むので個人的によく使います。

```SQL:
SELECT
FORMAT(CONVERT(date,getdate(),111),'yyyy-MM-ddT00:00:00.000Z') [好きな形式で]
```

▼実行結果

|     | 好きな形式で              |
|:----|:------------------------:|
| 1   | 2018-04-10T00:00:00.000Z |

#**数値かどうかを判断する（数値だったら1を返す）**

**◾️ISNUMIC(値)**
値が数値の場合１、数値でない場合0を返します。
個人的には、プロシージャで数値以外を入れてはいけない時、CASE文で数値以外の場合ブランクにする、といったような使い方をしています。


```SQL:
SELECT
CASE ISNUMERIC(1) 
	WHEN '1' THEN '数値です'
	ELSE '数値ではないです'
END [TEST1]
,CASE ISNUMERIC('a') 
	WHEN '1' THEN '数値です'
	ELSE '数値ではないです'
END [TEST2]
```

▼実行結果

|     | TEST1 | TEST2               |
|:----|:-------:|:-----------------:|
| 1   | 数値です | 数値ではないです   |


ちなみにSQLServerのCASE文はこのようなイメージです。

```SQL:
CASE 対象の項目、値
  WHEN この値のとき THEN こう表示する
  ELSE 当てはまらなかったらここを表示
END [項目名]
```
03: Raspberry Piでリレーを制御する - 移植編

# はじめに
こちらは
[Arduino と Raspberry Pi の違いのまとめ](https://qiita.com/KZ2/items/5e0e79f84e4dd26bd373)の3つ目の個別記事で、Raspberry Pi で relay を制御する。

# 目的
Raspberry Pi3 で Relay の制御を行う。

## 課題
Arduinoで動作していたRelayを持ってきてGPIOを出力にして接続すると、Relayのカチッという動作音はするのだが音がArduinoのときと比べて小さい。

## 問題点
Relayの出力をテスターで調べるとカチッと音は鳴るが、Relayとしての動作をしてくれていない。

## 原因
なんかおかしいと思い、調べたところ Raspberry Pi3 の GPIO出力の電圧は3.3Vだそうで、5Vリレーの直接駆動はできないということが分かった。

下記に詳しい。
[AN INTRODUCTION TO GPIO AND PHYSICAL COMPUTING ON THE RASPBERRY PI](https://www.raspberrypi.org/documentation/usage/gpio/README.md)

## 解決策
解決策としては、少なくとも三つ考えられる。
1. 5V動作のリレーから3V動作のリレーに交換する
2. Transistorを追加して、Switchとして用い、リレーへの電源供給を5Vとなるようにする
3. Raspberry Pi対応の Relay moduleを利用する

1. が簡単だが、手元に3V動作のリレーはなく、新規に買うと3V動作のリレーの2回路用は500円近くするので、#2を選択した。Transistor によるリレードライブの詳細説明はこちらを参考とした。

[電子回路におけるリレー使用上のご注意](https://www3.panasonic.biz/ac/j/control/relay/app_circuits/index.jsp)

ちなみに市販のリレーモジュールは、見た感じでは#2の実装になっている様子である。

### リレードライブの回路図
指で書くのは厳しい。。

[回路図]
![E9F83867-7B65-441E-BE5B-66A8CD2454C0.jpg](https://qiita-image-store.s3.amazonaws.com/0/162341/dcbe8d57-e65b-db5b-33f8-ff84d1fbedc2.jpeg)


[写真 not yet.]()

### 市販のRelay module
動作の状況が分かるようにLEDがついており、Relayがoffのときには、LEDが点灯している。つまり、LEDが消えたときには、RelayがOnになっている。もちろんRelayの出力側の配線を逆にすれば、LEDの点灯と動作を合わせることもできる。

[リレーモジュール](https://www.amazon.co.jp/gp/product/B00L11KL10/ref=oh_aui_detailpage_o05_s00?ie=UTF8&psc=1)

価格は大きく変動するようなのでebay.comとかいろいろ探すとよいかもしれない。

```python
05_RELAY2_GPIO21.py 
import RPi.GPIO as GPIO
from time import sleep

RELAY2_GPIO = 21 # GPIO number for relay or relay module 

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(RELAY2_GPIO, GPIO.OUT)

try:
    while True:
        GPIO.output(RELAY2_GPIO,GPIO.HIGH)
        sleep(1)
        GPIO.output(RELAY2_GPIO, GPIO.LOW)
        sleep(1)
except KeyboardInterrupt:
        # pass
        GPIO.cleanup()
```


# まとめ
これでRaspberry Pi3でリレーが動作するようになった。


# 親記事
[Arduino と Raspberry Pi の違い](https://qiita.com/KZ2/items/5e0e79f84e4dd26bd373)
riot.js 自明な設定をtag無しで設定する。

### 全体を括れば、変数のように使える。有っても無くてもエラーにならない。
```html
<script src="//gnjo.github.io/riot.js"></script>
<system>
<header>{today}</header>
<aricle>xxx</aricle>
<footer>{copyright}{owner}</footer>
</system> 
```
```js
riot.tag('system', false, function(opts) {
  this.copyright = new Date().toISOString().slice(0,'YYYY'.length)
  this.today=new Date().toISOString();
  this.owner='gnjo'
})
riot.mount('*')
;
```
MacのChromeで証明書失効リスト(CRL)をダウンロードしてopensslで見てみる方法

勉強をしていて証明書失効リストなるものを見てみたいと思いました。

## 1 証明書失効リストをダウンロードする。
### 1.1 サイトを開いて鍵マークあたりを押下して、[証明書]の下にあるリンクを押下する。
![スクリーンショット 2018-04-11 20.37.58.png](https://qiita-image-store.s3.amazonaws.com/0/159761/80cc0820-21fe-a0ee-3b48-3d6f482945bb.png)

### 1.2 [詳細な情報]欄を広げる。
![スクリーンショット 2018-04-11 20.39.34.png](https://qiita-image-store.s3.amazonaws.com/0/159761/b54730e6-7658-8fc0-af23-4fa111769063.png)

### 1.3 [CRL配布ポイント]にある[URI]を押下して証明書失効リストをダウンロードする。
![スクリーンショット 2018-04-11 20.42.22.png](https://qiita-image-store.s3.amazonaws.com/0/159761/21c6764a-db9d-4456-1718-5cd1e73abb95.png)

## 2 証明書失効リストを開いてみる
### 2.1 ターミナルを起動してopensslで開く
```sh:crl拡張子の開き方
openssl crl -inform der -in [証明書失効リスト] -text
# ex)
openssl crl -inform der -in sca1b.crl -text
```

### 2.2 見てみる
```sh:証明書失効リストの中身
Certificate Revocation List (CRL):
        Version 2 (0x1)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: /C=US/O=Amazon/OU=Server CA 1B/CN=Amazon
        Last Update: Apr  8 17:04:08 2018 GMT
        Next Update: Apr 15 17:00:00 2018 GMT
        CRL extensions:
            X509v3 Authority Key Identifier: 
                keyid:59:A4:66:06:52:A0:7B:95:92:3C:A3:94:07:27:96:74:5B:F9:3D:D0

            X509v3 CRL Number: 
                886
Revoked Certificates:
    Serial Number: 0CD11D8D8691FED7501A20E114F37BA8 #<<< 電子証明書のシリアル番号
        Revocation Date: Mar 22 15:26:17 2017 GMT   #<<< 失効日
    Serial Number: 0BE6061F7EF760225030B79E41A0F553
        Revocation Date: Jun  1 06:00:52 2017 GMT
    Serial Number: 0E3A14D4980F4DBCF3CABB5D0BD28725
        Revocation Date: Jun  1 06:01:45 2017 GMT
 <省略>
    Serial Number: 0BADA0E3D760F6F9A64DE74E647A618B
        Revocation Date: Apr  8 16:30:52 2018 GMT
    Signature Algorithm: sha256WithRSAEncryption
         b7:56:51:66:89:ce:11:2a:a1:b5:b1:53:42:c8:41:6c:bc:f1:
         e2:87:03:51:1e:fb:e2:87:86:2d:3f:6c:3f:f1:2b:16:1d:3a:
         9e:2f:2b:f4:e7:80:34:e5:be:61:8c:18:3b:19:d0:32:fc:53:
 <省略>
         ea:c0:59:06
-----BEGIN X509 CRL----- #<<< PEM形式の鍵っぽいもの・・・認証局の電子署名かしら？CRLの仕様は、X.509の規格で決められているからその関係なのか？
MIK1bDCCtFQCAQEwDQYJKoZIhvcNAQELBQAwRjELMAkGA1UEBhMCVVMxDzANBgNV
BAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDFCMQ8wDQYDVQQDEwZBbWF6
 <省略>
LZpBaTzONFw5xPfRLftpr7SWOU0jmxLTLyshpurAWQY=
-----END X509 CRL-----
```

## 出典
- [証明書の失効：CRL(Certificate Revocation Lists) とOCSP](https://rms-digicert.ne.jp/howto/basis/revoked_ssl_certificates_ocsp_crl.html)
- [CRLの中身ってどうやってみるの？ &#8211; 遊戯三昧](https://letticiablog.wordpress.com/2015/10/25/crl%E3%81%AE%E4%B8%AD%E8%BA%AB%E3%81%A3%E3%81%A6%E3%81%A9%E3%81%86%E3%82%84%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B%E3%81%AE%EF%BC%9F/)
Gitのブランチ名を返すエイリアスを設定したら地味に捗った

# 設定したalias
まず設定したaliasはこちらです。.zshrcやら.bashrcに設定します。

```zsh:.zshrc
alias brname='git symbolic-ref --short HEAD'
```

![2018-04-11 17_01_23.gif](https://qiita-image-store.s3.amazonaws.com/0/73446/e367cc11-0cbf-c0e1-708b-2ae80626ef25.gif)


すると、```brname``` で今のリポジトリのブランチ名を標準出力で返すようになりました。

## コマンドと組み合わせる
**追記**
こちらのaliasを使った例ですが、aliasを使わなくてもできる方法をコメントにて指摘頂いており、
[Gitのブランチ名を返すエイリアスを設定しなくても地味に捗った](https://qiita.com/kmszk/items/6000bf8cf26ef0d2e442)
にまとめましたので、こちらも併せてご参考下さい。

### git push 
ブランチをローカルで作ってリモートに初めてpushする時に使えます。

```bash
git push -u origin $(brname)
```

毎回ブランチ名をコピペしてpushしていた作業がコピペ不要になります。

**追記：**コメントにて push -u については ```git push -u origin HEAD```がこれと同じ意味になるとの指摘をいただきました。確かにこちらだとaliasも不要ですね…！

## git pull
自分の今いるブランチのみpullすると、余計なものをpullせずにすむのでブランチ名で指定したい時に使えます。

```bash
git pull origin $(brname)
```

毎回ブランチ名をコピペしてpullしていた作業が(ry

## git diff 
今いるブランチのリモートとローカルの差が知りたい時に使えます。

```bash
git diff $(brname) origin/$(brname) --stat
```
※ オプションはお好みで

毎回ブランチ名をコピペして(ry

## git reset 
今いるブランチのリモートの状態にresetしたい時に使えます。

```bash
git reset --hard origin/$(brname)
```

毎回ブラン(ry

### 他にもいろいろありそうですが
とりあえず、自分が日常で使っているのはこんな感じでした。
他にもブランチ名を入れたいところに使うことができるので、いろいろな使い道がありそうです。

## 補完で呼び出す (fish、zsh)
```$(brname)``` を使ってgit操作をしていると、今いるブランチに対して使うコマンドが、すべて同じコマンドになってくることが分かるかと思います。

そうなると、fishのような補完を使える場合には、コマンドを打っている途中に過去のコマンドの履歴からいつものコマンドを補完してくれるのでかなり楽になります。

自分はfishを一時期使ってはいましたが今はzshに戻ってきてまして、zshで同じことが出来るように[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) を使っています。
(下記のGIFの途中まで打っていてグレーになっているのがそうです。)

[zshの入力をfishっぽくする。(CLIのハイライトと予測補完](https://qiita.com/kmszk/items/203583935ed1cced5174)

![2018-04-11 14_06_29.gif](https://qiita-image-store.s3.amazonaws.com/0/73446/64fed031-ffc0-b277-c793-d58a0846929a.gif)

## まとめ
地味なエイリアスですが

- 無駄なTypoを防ぐ
- コピペの手間削減
- 補完を使うことによりタイプ数も減る

効果が期待できますので、結果~~地味に捗りました。~~ → 続きの記事書きました。
[Gitのブランチ名を返すエイリアスを設定しなくても地味に捗った](https://qiita.com/kmszk/items/6000bf8cf26ef0d2e442)
PDFKit で https が表示できない

Macには以前からあったようですが、iOSではiOS11から PDFKit が追加されました。

PDFKit の細かな話は自分で調べてもらうとして、今回は `https://...` のPDFが表示されず、対応策がネット上に英語の情報しか見つからなかったので書いておきます。

# 前提

|Xcode|Swift|iOS|
|:--:|:--:|:--:|
|9.3|4.1|11.3|


# コード (結論)

```swift
let url = URL(string: "https://www.apple.com/business/docs/iOS_Security_Guide.pdf")!
let data = try! Data(contentsOf: url)
pdfView.document = PDFDocument(data: data)
```

## 注意
- 便宜上 force unwrap してますが良くないので適宜修正して下さい
- `pdfView` は `PDFView` のインスタンス

#  原因

PDFDocument のイニシャライズ時は通常 `PDFDocument.init?(url:)` を使うと思いますが、この時 `https://` のurlの場合nilが返されます。

```swift
PDFDocument(url: URL(string: "http://...")!)  // PDFDocument instance returned
PDFDocument(url: URL(string: "https://...")!) // nil returned
```

さらに `PDFView` の `document` プロパティが `PDFDocument?` というようにnilを許容しているので、なにも表示されない原因に気付きにくいです。

```swift
// nothing happens
pdfView.document = PDFDocument(url: URL(string: "https://...")!)
```

詳しい事などは **参考** を参考にしてください。

# 参考

- https://stackoverflow.com/questions/45717813/pdfkits-pdfdocument-initurl-url-does-not-work-with-https
- https://developer.apple.com/documentation/pdfkit
- https://dev.classmethod.jp/smartphone/iphone/ios-11-pdfkit/
ドローンの姿勢推定

# 目的
ドローンの姿勢制御がしたい
だが姿勢が分からない

# 姿勢推定手法
 - 加速度センサの傾き等からオイラー角計算＆カルマンフィルタ
 - マドウィックフィルタ
    - Quaternionで記述するので特異点に陥らない

# 参考文献
いつも参考にさせて頂いている[Enigmaブログ](http://myenigma.hatenablog.com/entry/2016/04/10/211919)です
[スマホの姿勢推定](https://www.nxp.com/docs/en/application-note/AN4248.pdf)

# オイラー角度の計算
## センサーの向き
**全てのセンサの向きをそろえること**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146448/b8a34e16-0e6c-16f8-be12-c1bfae1b6a10.png)
### 加速度センサの正方向
+1gを読んでいる方向が正方向
x, y, z で繰り返す

### 地磁気センサ
北半球では北＆下方向に１軸を向けて最大値になる方が正，逆に向けて最小値になる方向が負
x, y, z軸周りで繰り返す

## 角度算出
### roll
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146448/d4fe9beb-d3ad-a6ea-647c-c1b51fed0838.png)

### pitch
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146448/0c512279-dff4-3d93-48b9-4369d123716d.png)

### yaw
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146448/2d5611db-deb3-7afe-0123-f8b459db2ff6.png)


# カルマンフィルタ
```math
A = 
\begin{bmatrix}
1 & 0 & 0 & Ts & 0 & 0 \\
0 & 1 & 0 & 0 & Ts & 0  \\
0 & 0 & 1 & 0 & 0 & Ts  \\
0 & 0 & 0 & 1 & 0 & 0  \\
0 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 0 & 0 & 0 & 1  \\ 
\end{bmatrix}
```
```math
状態量x=
\begin{bmatrix}
phi \\
theta \\
psi \\
p \\
q \\ 
r \\
\end{bmatrix}
```

パラメータは
Ts = 1/400
Q = 0.01^2*eye(6)
R = diag([2 2 10 1 1 10])

観測できるのは
角度は先ほど求めた式から，角速度はGyroから得られる．
そのため観測行列は
C = eye(6)
riot.js animate.css と合わせる

### vueのように細かにはないので、animate.cssを使ってクラス操作をすることに成る。
```html
<script src="//gnjo.github.io/riot.js"></script>
<link rel="stylesheet" href="//gnjo.github.io/animate.css"></link>
<anim></anim>
<style>
label{
 display:inline-block;
 padding:0.1rem;margin:0.1rem;
 background-color:whitesmoke;
}
label:hover{background-color:orange}
.orange{ color:orange} 
</style>
```
```js
let data=`bounce	flash	pulse	rubberBand
shake	headShake	swing	tada
wobble	jello	bounceIn	bounceInDown
bounceInLeft	bounceInRight	bounceInUp	bounceOut
bounceOutDown	bounceOutLeft	bounceOutRight	bounceOutUp
fadeIn	fadeInDown	fadeInDownBig	fadeInLeft
fadeInLeftBig	fadeInRight	fadeInRightBig	fadeInUp
fadeInUpBig	fadeOut	fadeOutDown	fadeOutDownBig
fadeOutLeft	fadeOutLeftBig	fadeOutRight	fadeOutRightBig
fadeOutUp	fadeOutUpBig	flipInX	flipInY
flipOutX	flipOutY	lightSpeedIn	lightSpeedOut
rotateIn	rotateInDownLeft	rotateInDownRight	rotateInUpLeft
rotateInUpRight	rotateOut	rotateOutDownLeft	rotateOutDownRight
rotateOutUpLeft	rotateOutUpRight	hinge	jackInTheBox
rollIn	rollOut	zoomIn	zoomInDown
zoomInLeft	zoomInRight	zoomInUp	zoomOut
zoomOutDown	zoomOutLeft	zoomOutRight	zoomOutUp
slideInDown	slideInLeft	slideInRight	slideInUp
slideOutDown	slideOutLeft	slideOutRight	slideOutUp`
 .replace(/\n| |\t/g,',').split(',').filter(d=>d.length!=0)
;

riot.tag(
`anim`
,`<div><div class="{nowanim}" animationend={aniend}>test</div></div>
<label each="{item in opts.data}" onclick={click}>{item}</label>
`
,function(opts){
 let self=this,f=(d)=>{return 'animated '+d}
 self.nowanim=f('hinge')
 this.aniend=function(ev){ self.nowanim='orange' }
 this.click=function(ev){ self.nowanim=f(this.item)}
})
riot.mount('anim',{data:data})
;
```
PHPのDateTimeで日付差分を得る時は、dではなくdaysを使う。

最初、以下のように、日数を算出していた。

```php:sample1.php
$day = new DateTime('2018-04-05');
$day2 = new DateTime('2018-04-11');
$diff = $day->diff($day2);
echo diff->d;
```
結果： **6**

が、この場合だと、日だけを見て差分を見ているので、月が変わっても結果は同じになってしまう。

```php:sample2.php
$day = new DateTime('2018-03-05');
$day2 = new DateTime('2018-04-11');
$diff = $day->diff($day2);
echo diff->d;
```
結果： **6** ← 本来なら37日が正しい

年月を含めて日数を見るなら

```php:sample3.php
$day = new DateTime('2018-03-05');
$day2 = new DateTime('2018-04-11');
$diff = $day->diff($day2);
echo diff->days;
```
結果： **37**

日数を算出する場合は、**d**ではなく、**days**を使う。
メールを機能実装する際に気を付けること

以前sendmailから送信したメール（送信元偽装をしていました。）が迷惑メールに入ってしまったり届かないことが本番環境で発覚したのでメモしておきます。（届かない場合はプロバイダで止めらたり？）

多分[こちら](https://qiita.com/clustfe/items/370e201270c873684489)の方と同じかな？

わたしもインフラの方は偉大だと常々思っています。

DNSへの対応が必要になるので直接メールを送信するのではなく既に運用中のメールサーバーを使うのが楽。

![送信元認証](https://image.slidesharecdn.com/20130205aws-140207023745-phpapp01/95/aws-16-638.jpg?cb=1465284236)

[IPによる認証 SPF](http://salt.iajapan.org/wpmu/anti_spam/admin/tech/explanation/spf/
http://salt.iajapan.org/wpmu/anti_spam/admin/operation/implement/spf_sid-milter_solaris10/)（送信元認証するならこれが楽そう　自分の組織のDNSで送信するメールサーバを宣言するだけ？）

[署名による認証](http://salt.iajapan.org/wpmu/anti_spam/admin/operation/implement/sendmail-milter/)

[AWSからのEメール送信](https://www.slideshare.net/AmazonWebServicesJapan/aws-30934799)
![AWSからのEメール送信の選択肢](https://image.slidesharecdn.com/20130205aws-140207023745-phpapp01/95/aws-21-638.jpg?cb=1465284236)

# GmailのSMTPの注意点

GmailのSMTPはXOAuthの認証があるのでホストとユーザーとパスワードだけでは接続できない。

安全性の低いアプリからのログインを許可する
https://support.google.com/accounts/answer/6010255

2段階認証が有効の場合はみつからないのでアプリパスワードを発行して使用する。
https://support.google.com/mail/answer/185833
7年間連れ添ったmacに「Wi-Fi：ハードウェアなし」の文字

# 問題
Wi-Fiが繋がらなくなった．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146448/99718bb2-0fb4-caa5-5483-d024e01d0f17.png)

# 試した解決策
 - NVRAM のリセット
 - SMC のリセット
どれもダメ．

# 原因
macのバッテリーやHDDを交換したときにWi-Fiモジュールのワイヤーを少し動かしてしまった．

# 解決策
下記の画像中の赤い円で囲った銀の部分がしっかりmacの筐体に接触していること
多分だが，ここが全体のグランドの役割しているのかな？？
とりあえず直ったので参考にしてください．


![image.png](https://qiita-image-store.s3.amazonaws.com/0/146448/e8f03bad-2383-deba-e8c9-36edac0d564a.png)
iOS開発環境を整えるチートシート

## はじめに
ドキュメントを読みながらexampleを試したいなと思った時に環境構築どうしたらいいんだっけ・・？といつも迷うのでメモ
Cocoapodsをプロジェクトごとにバージョン管理しなきゃとか、根元の方にgemを入れてしまわないか不安な人向け

### 例 TextureGroup/Textureでやってみる
git cloneをしてさてworkspaceを開いて実行するぞと意気込むものpodfileに乗ってるライブラリを入れなきゃビルドできない
<img width="808" alt="screenshot.png" src="https://qiita-image-store.s3.amazonaws.com/0/176479/c2e3eeb0-5ede-30ab-e71c-fa4fc503d291.png">



# 環境構築方法
### １このリポジトリをクローンする このファイルを入れたいディレクトリに移動してから下記コマンドを実行する

```
$ git clone git@github.com:TextureGroup/Texture.git
```
### 2.rbenvをインストール 
複数バージョンを管理することができるrbenvを入れます。

```
$ brew install rbenv ruby-build
```
入ったことを確認したらrbenvのどのバージョンが入ったのか確認

```
rbenv --version
```
### 3.今回使うrubyの指定バージョンを入れる

```
$ rbenv install 2.3.1
```

一応入ってきたかチェックする(いまPC内で使えるrubyバージョン一覧が出てくる)

```
$ rbenv versions
```
こんな感じで出てきたらOK

```
system
* 2.3.1 (set by...........)
```

### 4.このリポジトリ内で利用するrubyのバージョンを設定する
/Texture/examples/Swiftの中に移動しておく

```
$ rbenv local 2.3.1
```
`.ruby-version`というファイルができる

### 5.リハッシュする
```
$ rbenv rehash
```
### 6.gemのバージョン管理をおこなうbundlerをいれる （PCのグローバルにgemをいれるとバージョン管理ができなくなるためこのリポジトリ内にgemを入れるようにする）
```
gem install bundler
```

### 7.gemを管理するgemfileをつくる
```
$ bundle init
```
ここでコマンドを打った、ディレクトリに`Gemfile`が作られる

### 8.Gemfileの中身を記入 Gemfileを開く
```
$ vi Gemfile
```
cocoapodsを管理するためGemfileに以下を書きこむ vimはiを一度押すと記入できるようになる。以下をかきこみ終わったら:wqを入れてエンターを押す (wは書き込みqは終了です)
Gemfileの中身

```
source "https://rubygems.org"

gem "cocoapods", "1.2.0"
```

### 9.gemfileを参照して、必要なgem(ここではcocoapods)を入れる

```
$ bundle install --path Vendor/Bundler
```

### 10.ios開発のためのライブラリ管理ツールpodの準備をする
まずはPodfileの作成(TextureのexampleではPodfileがすでに存在しているのでこれを使う)

```
$ vi Podfile
```

Podfileの中身

```
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'

use_frameworks!

target 'Sample' do
	pod 'Texture', :path => '../..'
end
```

### 11.Podfileに登録したライブラリをおとしてくる (bundlerでcocoapodを管理しているためpodのコマンドを使うときはbundle execを前につける必要がある)
```
$ bundle exec pod install
```

### 12.gitignore編集
```
$vi .gitignore
```

```
### Mac ###
.DS_Store

### CocoaPods ###
Pods/*

### Xcode ###
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.xcuserstate

### AppCode ###
.idea/

### App ###
*.mobileprovision
*.ipa
*.zip

### Carthage ###
Carthage/*

### Bundler ###
.bundle/*
bundle/*

### bundler ###
Vendor/Bundler
```

### 12.プロジェクトファイルを開く
```
$open Sample.xcworkspace
```

間違い、もっとこうした方がいいなどありましたら教えてください

#参考
https://qiita.com/ikuwow/items/4fae81a099bf82f44749
https://github.com/github/gitignore
[Xcode] シミュレータがデフォルトiPhone8 Plusで起動するのが嫌なとき

実機がiPhone8なので、デフォルトで選択されているデバイスを変更したかった。
テスト用のプロジェクトをばんばん作るので、毎回選択するのはめんどくさい。

ぐぐると、デフォルトであるデバイスにする設定画面はないらしい。（あったら教えてください）

# 結論
シミュレータ一覧からPlusを削除しちゃえばおｋ

## Add Additional Simulators...を選択
<img width="449" alt="スクリーンショット 2018-04-11 19.26.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/60209/c6600906-0ef2-36d2-aa87-5abe8de1cb2e.png">

## Show as run destinationのチェックを外す
<img width="790" alt="スクリーンショット 2018-04-11 19.18.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/60209/b39d3e4c-ee16-7c6c-bf7a-0a8d9bea6dc1.png">

以上。

## でも、たまにはPlusで動かしたいあなたへ
Xcodeのデバイス一覧からは消えますが、シミュレータのHardwareには残っているのでPlusで動かせなくなるわけではありません(^o^)
<img width="742" alt="スクリーンショット 2018-04-11 19.22.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/60209/f0bccb7d-9c04-364b-b295-7b2ed848be2d.png">
【swift】オーバーライドとオーバーロードの違い

オーバーライドとオーバーロード、言葉は似ていますが全く違うものです。

#オーバーライド
継承したスーパークラスのメソッドを上書きすること

```swift
class SuperClass{
    func sayHello(){
        print("Hello")
    }
}

class SubClass: SuperClass{
    override func seyHello(){
        print("こんにちは")
    }
}

let superClass = SuperClass()
let subClass = SubClass()
superClass.sayHello() //Hello
subClass.sayHello() //こんにちは
```

#オーバーロード
同じクラスの中に名前は同じだが、引数や戻り値が違うメソッドを定義すること

```swift
class SomeClass{
    func sayHello(){
        print("こんにちは")
    }

    func sayHello(name: String){
        print("こんにちは" + name + "さん")
    }
}

let someClass = SomeClass()
someClass.sayHello() //こんにちは
someClass.sayHello(name: "花子") //こんにちは花子さん
ワンライナーでJSON APIの結果を整形して出力するスクリプト

`curl`の結果を

```python
python3 -c "import sys, json;dict=json.loads(input());print(json.dumps(dict, indent=4, separators=(',', ': '), ensure_ascii=False))"
```

にパイプで渡す

# 例

```shell 
curl "https://api.ipify.org/?format=json" | python3 -c "import sys, json;dict=json.loads(input());print(json.dumps(dict, indent=4, separators=(',', ': '), ensure_ascii=False))"
```
Git リポジトリを分割する

以下のようなディレクトリ構造のリポジトリを分割する方法を場合分けしてまとめます。

```
repo1/
 ├─ subdir/
 ├─ aaa
 ├─ bbb
 ├─ ccc
 └─ ddd
```

## ケース1：サブディレクトリを切り出す

リポジトリ repo1 のサブディレクトリ subdir を別のリポジトリ（のルートディレクトリ）として切り出したい場合：

```
git filter-branch --subdirectory-filter subdir HEAD
```

## ケース2：ディレクトリ構造を保持して一部を切り出す

リポジトリ repo1 から aaa, bbb を切り出したい場合，ccc, ddd, subdir を削除して**歴史修正**します。

```
git filter-branch --tree-filter 'rm -rf ccc ddd subdir' --prune-empty
git gc
```

`git filter-branch` での変更を複数回しようとすると，以下のエラーが出るので，`-f` オプションを付けます。

```
Cannot create a new backup.
A previous backup already exists in refs/original/
Force overwriting the backup with -f
```

## 補足：リモートリポジトリを追加して push する

```
git remote add new_origin {URL}
git push new_origin
```

## 参考ページ

- [Gitリポジトリのディレクトリ構成を変えて別リポジトリにする](http://gozuk16.hatenablog.com/entry/2015/04/24/145714)
- [gitのリポジトリを分割したい](http://www.nakajimadevnakajima.info/2017/02/24/post-30/)
- [Git で複数のリポジトリをまとめたり、逆に切り出したりする](https://qiita.com/uasi/items/77d41698630fef012f82)
Nuxt.jsでのリンク備忘録

`pages/about.vue`ファイルを作成。

```pages/index.vue
<template>
  <nuxt-link to="/about">ABOUTへ</nuxt-link>
</template>
```

```pages/about.vue
<template>
  <nuxt-link to="/">トップへ</nuxt-link>
</template>
```

ブラウザで見てみると、`<nuxt-link>`タグは`<a>`タグに置き換えられている。
【ruby】rack/testでdbを切り替えてtestする

[Docker-composeでSinatra + Nginx + MySQL を動かす時のハマりポイント - Qiita](https://qiita.com/koyo-miyamura/items/54bbde546db07ef64bf3)

sinatraで[画像投稿サービス](https://github.com/koyo-miyamura/latestgram)を作ってテストをしようとした時に、MySQLの接続先をテスト用とdokcer用で切り替えてテストする必要があったのでその時のメモ。

ActiveRecord使わない方法を見つけるのが難しかったので書いておきます！

# 簡単なディレクトリ構成
.
├── myapp.rb
├── test
│   └── test_myapp.rb

# 解決策
`ENV['RACK_ENV']`を使いましょう。

testコードの冒頭で`ENV['RACK_ENV'] = "test"`を設定して、rubyのmysql接続部分で参照してhostを振り分ければOKです。

### myapp.rb
* docker-composeを使う時
    * ENV['RACK_ENV'] は nil
* testするとき
    * ENV['RACK_ENV'] は test
* ローカルのmysqlで動かしたいとき
    * `sudo RACK_ENV=development bundle exec ruby myapp.rb` というようにRACK_ENVを設定
    * ENV['RACK_ENV'] は development

```ruby
    def db_connect()
      if ENV['RACK_ENV'] == "test" || ENV['RACK_ENV'] == "development"
        host = 'localhost'
      else
        host = 'db'
      end

      client = Mysql2::Client.new(
        :host     => host,
        :port     => '3306',
        :username => 'root',
        :password => '',
        :database => 'latestgram',
        :encoding => 'utf8mb4',
        :datatbase_timezone => :local
      )
      return client
    end
```

### test_myapp.rb
```ruby
ENV['RACK_ENV'] = 'test'

require_relative '../myapp'
require 'minitest/autorun'
require 'rack/test'

class MyAppTest < Minitest::Test
  include Rack::Test::Methods

  def app
    MyApp
  end

  def test_my_default
    get '/'
    assert last_response.ok?

    get '/signin'
    assert last_response.ok?

    get '/signup'
    assert last_response.ok?    
  end
end
```

### 参考
[Sinatraで環境変数(environment)のセット - Qiita](https://qiita.com/Esfahan/items/3e5f08880e14ade264e7#rake-tasks)
Nuxt.jsを始める

まずは、Nuxt.jsってなんなのかを知る。
https://www.slideshare.net/rararagi/nuxtjs-20180202-vuejs
https://html5experts.jp/potato4d/24346/

公式サイトはしっかり抑える。
https://ja.nuxtjs.org/

## Nuxt.jsとは

Vue.jsベースのフレームワーク。

## 始めるには

vue-cliをインストールしていない場合はインストールする。
https://github.com/vuejs/vue-cli

このボイラープレートを使えばすぐにサーバが起動するとこまでもっていける。
https://github.com/nuxt-community/starter-template



```
$ vue init nuxt-community/starter-template my-project  
```
シェルスクリプトで firewalld と iptables とどちらを使っているか調べて切り替える

#モチベーション
RHEL7になって標準でインストールされるパッケージが iptables から firewalld になりましたが、iptables パッケージがなくなったわけではなく、追加インストールすることにより引き続き iptables で運用することも可能です。また、旧バージョンを使用している場合やわざわざパッケージをアンインストールした場合など、firewalld が存在していないこともあるでしょう。シェルスクリプトで実際にどちらを使用しているかをチェックして処理を切り替えたい時の方法を考えました。

#実現方法
以下の2点をチェックしてどちらも真である場合はfirewalld を使用しているものとします。

- firewalld がインストールされている
- firewalld が実行中である

firewalldへの操作はfirewalldを直接実行するのではなく、パッケージに含まれるfirewall-cmdを使用します。なお、firewall-cmd の実行は root 権限が必要で、権限がない場合は firewall-cmd の終了コードが必ずエラーとなります。ここでは省略しますが、事前に $EUID が 0 であるかどうかで root 権限があるかどうかを確認し、root権限がない場合はここに入らないようにする必要があります。
firewalld が実行中であるかどうかは 

```shell:
$ firewall-cmd --state
```

を実行して終了コードを確認します。

ということで、以下のようなスクリプトとなります。

```shell:check-firewalld.bash
#!/bin/bash

if which firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
  echo You are using firewalld.
  # ここにfirewalld使用時のコード
else
  echo You are using iptables.
  # ここにiptables使用時のコード
fi
```

#結果

```shell:
$ sudo ./check-firewalld.bash
You are using iptables.
$
```
プログラムをインストールしたHDDのデータを別のHDDに移す方法

# この記事の内容
- プログラムをインストールしているドライブ（システムドライブではない）のデータを物理的に移動します。
- 移動先のドライブを使っても、エラーとかもなく、ちゃんと移動前と同じ動作をすることを目指します。

# 問題解決前
## ダイナミックディスク
　ここにうかつにもダイナミックディスクにしてしまったHDDがある。
　![2018-03-30 23.17.08 ディスクの管理.png](https://qiita-image-store.s3.amazonaws.com/0/227200/24516c46-1d58-3866-9364-99cba0769dbb.png)

　ダイナミックディスクは色々と利点もあるようだが、**他の環境から中身を見ることができない**という欠点も持ち合わせている。
　だからベーシックディスクに戻したかった。

　でもダイナミックディスクからベーシックディスクに戻すのは大変だ。
　一度そのHDDからデータを抜いて、ダイナミックなHDDをリセットしなければならない。
　巷には便利なソフトがあるようだが、狙ったみたいに全部有料。

## どうするか
　じゃあもうHDDをコピーすればいいんでしょ！！

　でも対象のHDDは、プログラムのインストール先として利用している。
　それをそっくりそのまま移し替えるには……よし、ドライブレターも変えてみよう。

　ということで、手順はこちら。
　**1. 高速コピーソフトを用意
　2. セーフモードで起動
　3. ソフトで丸ごとファイルコピー
　4. ドライブレターの変更**

　ちなみに僕の実行環境はWindows8.1 Embeddedです。
　~~貧乏根性はこの辺にも表れている~~。
　
# 手順
## 高速コピーソフト
　『FastCopy』を利用させてもらった。
　ググれば出る。一応リンクは→[こちら](https://ipmsg.org/tools/fastcopy.html)
　使い方は特に調べなかったが、ぱっと見でだいたい分かるのでよい。

## セーフモードで起動
　起動方法は他のサイト参照。
　例えば→[こちら](http://121ware.com/qasearch/1007/app/servlet/relatedqa?QID=015917)
　今回はネット接続もいらないのでなるべく最小限の構成に抑える。

## ソフトで丸ごとファイルコピー
　以下の画像ではQドライブが元々のドライブ。
　Pドライブが新しく用意したドライブで、Qドライブのデータ量より大きな容量を持っている。

　![2018-03-30 23.44.45 FastCopy ver3.41.png](https://qiita-image-store.s3.amazonaws.com/0/227200/3c072d6b-5be0-1b13-90dd-fde1a8959724.png)

　これで『実行』をクリックすれば実行可能。
　普通にコピーするよりは断然早いと思う。おおむね100MB/sくらいでコピーしていた気がする。
　ちなみに僕の場合、
　　**データ量：1.39TB(1,472,402MB)
　　総経過時間：4時間12分25秒**
　だったので、平均 **97.22MB/s** だった。

## ドライブレターの変更
　セーフモードのまま、ディスクの管理からドライブレターを変更する。
　ドライブレターは「Cドライブ」とか「Qドライブ」とかの文字のことだ。
　ここができるか一番不安だったのだが、使用中のドライブの場合は再起動後に適用されるようで、普通に変えたい放題（）だった。
　ここで **Q→Oドライブ**、**P→Qドライブ** に変更。

　ちなみに「パラメータが間違っています」みたいなエラーが出た場合は、ページファイルを削除すればよい。
　この方法も他サイトを参照してほしい。例えば→[こちら](http://ch.nicovideo.jp/muk/blomaga/ar361043)

　（もしかすると、これはセーフモードである必要はないかも……）

## 結果
　![2018-03-31 00.25.38 ディスクの管理.png](https://qiita-image-store.s3.amazonaws.com/0/227200/b49568d6-c95d-c111-1cb1-ab16b5bd38c5.png)


　Qドライブの移動に成功。
　ディスク2のボリュームもすべて削除した。
　削除するとき「使用中ですが～」のような警告が出たが、何事もなくうまく動いているみたいなので良かった。

# 結論
　プログラムをインストールしたドライブであっても、ドライブレターを変えてしまえば普通に動く。
　なのでがりがりコピーするのが一番楽。
　知っている人にとっては当たり前のことだったかも。
Elasticsearchのaggregationsのサンプル

---

あるtypeの月ごとの件数をカウントする必要があり、
頑張って調べたのでメモ。

### リクエストのサンプル

```
GET index_name/type_name/_search
{
  "size": 0, 
  "query": {
    "filtered": {
      "filter": {
        "range": {
          "{{ sample_time }}": {
            "gte": xxxxxxxxxxx
          }
        }
      }
    }
  },
  "aggs": {
    "{{ monthly_count }}": {
      "date_histogram": {
        "field": "{{ sample_time }}",
        "interval": "month",
        "time_zone": "+9:00",
        "order": {
          "_key": "desc"
        }
      }
    }
  }
}
```
- sizeは、条件にヒットするドキュメントが出力されるのが邪魔なので0にした
- queryで集計するドキュメントの条件を絞れる(例はsample_timeがある日付以降)
- aggsからが集計の条件

### aggsの各パラメータの意味
```
"aggs": {
	"{{ 適当な名前をつける }}": {
	  "date_histogram": {             # date_histgramを指定すると日付の間隔でbucketを作れるらしい
	    "field": "{{ sample_time }}", # 集計するキーとなるフィールド
	    "interval": "month",          # 月ごとに集計したいのでmonth
	    "time_zone": "+9:00",         # タイムゾーンを調整できる(utcだったので+9時間した)
	    "order": {
	      "_key": "desc"              # 集計結果をソート可能
	    }
	  }
	}
}
```

### レスポンスのサンプル

```
{
   "took": xxx,
   "timed_out": false,
   "_shards": {
      "total": xxx,
      "successful": xxx,
      "failed": 0
   },
   "hits": {
      "total": xxx,
      "max_score": 0,
      "hits": []
   },
   "aggregations": {
      "{{ 適当につけた名前 }}": {
         "buckets": [
            {
               "key": 1522540800,  # 降順で月ごとの件数が集計された
               "doc_count": 300    # 対象月の件数
            },
            {
               "key": 1519862400,
               "doc_count": 400
            },
            {
               "key": 1517443200,
               "doc_count": 100
            }
         ]
      }
   }
}
```
- 例は2018/02 ~ 2018/04の月ごとの集計結果、件数は適当です
Windows10のChocolateyでNeoVimをインストール

# 注意(追記)

Scoopを利用してインストールすることを推奨します。Chocolateyを利用してインストールするとNeoVimにパスが通りませんが、Scoopを利用すると通るからです。

# Chocolateyのインストール
Win+X→Aで管理者PowerShellを開き、次のコマンドを打ち込みます。

```
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
```

# PowerShell標準のPackageManagementでChocolateyを使えるようにする (Win10)

Windows10では、PowerShellにパッケージマネージャが付きました。こちらを使ってもよいでしょう。

```powershell
Install-PackageProvider ChocolateyGet
```

# NeoVimのインストール
Chocolateyをインストールしてしまえば一発です。次のコマンドを入力します。

```powershell
cinst -y neovim
```

PackageManagementを利用している場合は、次のコマンドを利用します。

```powershell
Install-Package -Name neovim -Provider ChocolateyGet
```


# NeoVimのエイリアスを作成
NeoVimの実行ファイルは`C:\tools\neovim\Neovim\bin\nvim.exe`です。また、GUI版が同ディレクトリの中に`nvim-qt.exe`という名前であります。PowerShellのエイリアスを作成して、「`vim`」「`gvim`」で起動できるようにしましょう。

```powershell
code $PROFILE
C:\tools\neovim\Neovim\bin\nvim.exe $PROFILE
```

などのコマンドで`$PROFILE`を開き、次の内容を追加して保存します。

```powershell
Set-Alias nvim C:\tools\neovim\Neovim\bin\nvim.exe
Set-Alias vim nvim
Set-Alias vi nvim
Set-Alias nvim-qt C:\tools\neovim\Neovim\bin\nvim-qt.exe
Set-Alias gvim nvim-qt
```

これでPowerShellでNeoVimを使うことができます。
riot.js contenteditable

### contenteditable は valueのようにはいかない。ハウリングしてしまう。
dummyをriotにwatchして貰って、それを更新する。更新を回避する事もできるが、each要素をストアデータとして利用したい場合には、やはりdummyに保存しておいたほうが良い。

```html
<li each="{item in items}" oninput={input} contenteditable="plaintext-only" dummy={item.text} ref='ed'></li>
```
### ただ、this.one mountでelement.textContentに初期値を入れ込む処理が入る。
```js
 this.one('mount',function(){
  this.refs.ed.forEach((el,i)=>{ el.textContent=this.items[i].text; })
 })
```

### 全部
左はテキストデータ、右はテキストデータのアナライズ

```html
<script src="//gnjo.github.io/riot.js"></script>
<loop></loop>
<style>
 body{margin:0;width:100vw;height:100vh;}
.f{
 display:flex;flex-direction:row;
 width:80%;height:100%;justify-content:center;
 margin:auto;
}
.f>ul{margin:0;padding:0;width:100%;height:100%;}
.f>ul li{
 list-style:none;
 min-height:1rem;min-width:100%;
 margin:0.1rem;
}
.left li{background-color:skyblue}
.right li{background-color:pink}
</style> 
```
```js
let fn={};
fn.jpTime=(timestamp=Date.now())=>{
 return new Date(timestamp+1000*60*60*9)
  .toISOString().replace(/-/g,'/').replace('T',' ').slice(0,'YYYY/MM/DD hh:mm:ss'.length)
} 
fn.lex=(d)=>{ return {head:d.match(/#{1,6} .+/),count:d.length,time:fn.jpTime(),text:d} }
;
riot.tag(
`loop`
,`<div class="f">
<ul class="left"><li each="{item in items}" oninput={input} contenteditable="plaintext-only" dummy={item.text} ref='ed'></li> </ul>
<ul class="right"> <li each="{item in items}">{item.count}:{item.head} :{item.time}</li> </ul>
</div>
`
,function(opts){
 this.items =['# xyz','# xxx','# yyy'].map(d=>fn.lex(d))
 this.one('mount',function(){ this.refs.ed.forEach((el,i)=>{ el.textContent=this.items[i].text; }) })
 this.input=function(ev){ Object.assign(this.item,fn.lex(ev.target.textContent)) }
})
riot.mount('loop',{})
;
```
Android Emulatorの設定アプリがクラッシュするときにやること

* 一旦エミュレータを終了する
* Android StudioのAndroid Virtual Device Managerで対象のエミュレータでWipe dataする
![image.png](https://qiita-image-store.s3.amazonaws.com/0/94/f5d91650-f45e-d4e1-e843-a877e28dace4.png)

* 起動し直す。
開いているページのある文字列をファイルに保存するブックマークレット

普段、自分の金融資産の時価総額をチェックしているのですが、最近老眼がきつくなってきて目で見て書き写すのはしんどくなってきました。

Web APIみたいなのが提供されておればよいのですが、なかなかそんなサービスは少ないのでcurlとかでスクレイピングしたいところなのですが、ログインまでのプロセスがややこしい上に定期的なパスワード変更を強制されたり、2FAを突破したりしないといけないこともあり、なかなか難しい。それにセキュリティ的にもスクレイピングするスクリプトを置いておくのもちょっと危険な感じもします。

そこで今開いているページのある部分を取り出してファイルに保存できたら、あとでそのファイルをスクリプトで処理してグラフを書いたりと色々と応用が効くかと思いました。

ということで以下のようなブックマークレットを作成しました。

```javascript
javascript:((d,nm,id)=>{
var a = d.createElement('A');
a.download=nm+'-'+(new Date()).toISOString()+'.txt';
var x=d.getElementById(id).innerHTML;
a.href='data:text/plain,'+x.replace(/,/g,'');
d.body.appendChild(a);
a.click();
d.body.removeChild(a);
})(document, '401k', 'D_Header1_lblKigyoBalanceAssets');
```

これはとある確定拠出年金サービスの時価を抜き出してファイルに保存するものです。

数値を見やすくするカンマは扱いにくいので取り除いています。
ファイル名は現在時刻を含むようにしていますので、日時が分かるだけでなく、毎回名前が変わりますので扱いやすいかと思います。

引数を適当に変えてやればファイル名のprefixと抜き出すべきタグのIDが変えられますので、他のサービスでもほとんどそのまま使えるのではないかと思います。
振り返り手法のサーベイ

# 振り返り手法のサーベイ
背景: 
* レトロスペクティブの時KPTで振り返りを行なっている
* しかしチームでうまくスプリントを回せてないと感じている人が多い
* そこで振り返り手法にどのような種類があるのか調べ、まとめる事にした

まとめて思った事
* KPTは万能じゃない！ 課題の洗い出しに特化してたフレームワーク
* 根本対応を行いたいなら別のフレームワークを選定しなければならない
* KPT以外のほとんどが、プラグマティズムの思想の派生フレームワークに見えてくる
* トヨタ強い

## YWT
ストーリー形式で振り返る方法

### 手法
* Y:やったこと
* W:わかったこと
* T:(わかったことを活かして)次にやること(の候補)
* (M:次にやることをやる) Tをやることが乗り気でないときにやる

## KPT
Keep:続けること、Problem:問題点、Try:試みること、の頭文字を名称としている。

### 提唱者
アリスター コーバーン 

### 手法
* 活動経過および結果を対象に、この 3 つの観点にてブレインストーミングを行う

### メリット
以降の活動にて取り組むべきポイントを洗い出すことができる。

### デメリット
* 『案件』の絞り込みと深掘りが難しいという弱点も持ち合わせている。 

## なぜなぜ分析

### 手法
* 特定の問題に対し、その問題を引き起こす原因となる事象(なぜ)を提示する事を木構造で分解していく事により『真因』を特定する
* 真因に対して対策を立案する。
 
### メリット
* 問題と対策の間の因果関係の繋がりを検証できる手法である。
* 特定の問題に対する原因の深堀りに適している


### デメリット
* 問題設定の適切さを確認するプロセスに欠けている。 
* 理想状態に繋がらず問題が回帰してしまう問題もある。(ギャップ分析とは違い、問題を最初に上げているため)


## ギャップ分析
### 手法
* あるべき姿(理想状態)を上げる
* それを実現するためにはどうすべきかを木構造で分解していく
* 最後に現在とのギャップを判断し、対処していく

### メリット
* 問題と対策の間の因果関係の繋がりを検証できる手法である。
* 特定の問題に対する原因の深堀りに適している

### デメリット
* 問題設定の適切さを確認するプロセスに欠けている。 

## KWS
* KPTとなぜなぜ分析、Solution(対策のベストプラクティスが研究されきれていない)のいいとこ取り

### 構成要素
* K: KPT
* W: Why(なぜ分析)
* S: Solution(対策)

### メリット
* 洗い出しから、深掘り、対策まで既存手法の良い所を集めて行えるため充分に振り返ることができる

### デメリット
* 時間がかかる

## 経験学習モデル
学習 = 経験を概念化したもの という理論(プラグマティズムの思想)を元に作られたモデル

### 手法
* 経験:具体的な経験をすること。
* 観察:経験を多様な観点から振り返ること。
* 概念化:他でも応用できるよう概念化し自分の未来や、他の人が使えるように教訓にすること。 (KPTと違う点)
* 試行:新しい場面で実際に試してみる。

### メリット
* プラグマティズムの思想を正とするなら最も効果的な振り返り手法


## 4行日記
経験学習モデルと似ているが、 `宣言` に心理効果を持たせたもの

### 手法
* 事実: 今日合った出来事を振り返り、一番印象に残っていることやアンテナに触れたものを一つ選んで書き出す。
 - 4行日記を始めた。
* 気づき: 事実から得られた発見や感想などを書く。あまり深く考えすぎず自分が直感的に思ったことを書く。
 - 日記を書き続けることで成長することができる。
* 教訓: 気づきからどのようなことを学んだのかを3行目に書く。自分に起こった出来事から学んだこと般化、抽象化するとどうなるかが教訓だ。
 - 継続は力なり。
* 宣言: 最後に自分がありたい姿を宣言して日記は終わりだ。ここでの書き方としては、自分がなりたい姿を現在進行形でなれていると仮定して断定することがポイントだ。
 - 私は計画性を持った人間です。

## PDCA
概念
* P 計画
* D 実行
* C 点検・評価⇒学習（振り返りと概念化）
* A 処置改善

## LAMDA
PDCAサイクルの発展版

トヨタ製品開発の「リーン生産方式」をアレンウォード博士によって体系化されたもの
* Look (実際に現場をみる)
* Ask (やる)
* Model (結果を抽象化)
* Discuss (フィードバックしてもらう)
* Act (やる)




## 参考文献
* 「KPT」と「なぜなぜ分析」を応用した KWS 振り返りの研究 
 - https://www.juse.or.jp/sqip/workshop/report/attachs/2011/SQiP1-B.pdf
* アジャイルアンチパターン 〜私がアジャイルの1周目で学んだこととXPの次の10年〜
 - https://www.slideshare.net/fkino/1xp10?next_slideshow=1
* 経験学習の理論的系譜と研究動向
 - http://www.jil.go.jp/institute/zassi/backnumber/2013/10/pdf/004-014.pdf
* 2018年の目標設定にも使える！ “振り返り”に役立つ5つのフレームワーク
 - https://ferret-plus.com/9262
【CakePHP】CSSが反映されない場合の対処法まとめ

##概要
CakePHPでビューを作っている時に、CSSが反映されなくなった場合の対策法まとめです。ちなみに筆者は下記の対策を全部しましたが、結局反映できず嫌になってしばらく放置して戻ってきたら直ってました。何が原因だったのはわからないのでやったこと全部リストにしましたので参考にしてください。

##原因
ブラウザにキャッシュが残っているから

##対策
###①ブラウザのキャッシュを削除する
アプリを確認するのに使うブラウザのキャッシュを削除します。Chromeでは履歴削除でキャッシュが消せます。

###②app/Config/core.phpの編集
下記、コメントアウトされているはずなのでコメントアウトを外します。

```php

Configure::write('debug', 2);
Configure::write('Asset.timestamp', true);

//debug = 0 の時
Configure::write('Asset.timestamp', 'force');
```

###③Apacheの設定を変える
```php
cd /etc/httpd/conf
sudo vi httpd.conf
```
でファイルを開き、

```php
EnableMMAP off        //これでも解決しなかったらさらに
EnableSendfile off
```
というのがコメントアウトされてるので有効にしましょう。また、

```php
<Directory "/var/www/html">
    Options FollowSymLinks
    AllowOverride All
</Directory>
```
該当箇所が上記のようになっていなければ直しましょう。

```
sudo service httpd reload
```
で再起動してくださいね。

###④アプリに蓄積されるキャッシュを消す
`/app/tmp/cache/`以下のディレクトリ(modelsとかviewとか)にキャッシュが入っているので、全て削除してしまいましょう。

###⑤コントローラーのbeforeFilterを編集
コントローラの中に、

```php
public function beforeFilter()
{
     parent::beforeFilter();
     $this->response->disableCache();
}

```

と追加しましょう。

##最後に
一回サーバーをシャットダウンして、また立ち上げてみるのもありだと思います。
これだけ対策があるのでハマっている方は試してみてください。
Postgresでdistinct onしながらcountしようとしたらハマった

##やろうとしたこと
あるサービスのアクセスユーザー数をセッション単位で数えたかった

**table名:user_browsing_log**

|列名|Type|note|
|:-----------|:-------------|:----------|
|session_id|text|セッションid| 
|browsing_at|timestamp without time zone|アクセス日時|


**最初に作ったSQL**

```sql:first.sql
select distinct on(session_id) count(*) from user_browsing_log;
```

**実行結果**

```
ERROR: column "user_browsing_log.session_id" must appear in the GROUP BY clause or be used in an aggregate function
```

session_idをgroup byせよとのこと

**2番目に作ったSQL**

```sql:second.sql
select distinct on(session_id) count(*) from user_browsing_log group by session_id;
```

でもこうするとあるsession_idが何回アクセスしたか、になってしまう、、、、

#####正解

```sql:correct.sql
select count(distinct session_id) from user_browsing_log;
```

めっちゃ単純だしsqlにしてみると当たり前も当たり前な感じだった

ある列だけを基準にdistinctして他の列も取得するときのdistinct onを使う場合が固定概念になってしまってハマっていた
書いてみようカーネルモジュール。仮想環境を作ってカーネルモジュールでHello Worldまで。

# 仮想環境の準備
## Vagrant上にLinuxを用意する
```
% vagrant box add debian-8-jessie https://github.com/holms/vagrant-jessie-box/releases/download/Jessie-v0.1/Debian-jessie-amd64-netboot.box
% vagrant box list
% vagrant init debian-8-jessie

% vagrant up
% vagrant ssh
```


# 必要ファイルの準備


カーネルパッケージのインストール

```
# apt-get install kernel-package
```

# カーネルモジュールでhello world
まず、insmod/rmmodでロード/アンロードするだけの簡単なモジュールを作成する。

```
% mkdir helloworld
% cd helloworld
```

モジュールのコード

```c:helloworld.c
#include <linux/module.h> // カーネルモジュールを作成するときは必ずlinux/module.hをinclude
#include <linux/kernel.h>

// モジュール初期化（insmod時に呼ばれる）
static int __init helloworld_module_init( void )
{
    printk( KERN_INFO "Hello World!\n" ); // カーネルランド版のprintf
    return 0;
}

//  モジュール解放（rmmod時に呼ばれる）
static void __exit helloworld_module_exit( void )
{
    printk( KERN_INFO "Goodby World!\n" );
}

module_init( helloworld_module_init );
module_exit( helloworld_module_exit );

MODULE_DESCRIPTION( "helloworld" ); // modinfoで見れる
MODULE_LICENSE( "GPL2" );
MODULE_AUTHOR("takish");
```

## コンパイルのための準備

バージョン名を確認

```
% uname -rn
% jessie 3.16.0-4-amd64
```

コンパイル時に/lib/modules/build以下にheadersが必要なのでインストールする


```
% sudo apt-get install linux-headers-3.16.0-4-amd64
```

インストール先を確認

```
# dpkg -L linux-headers-3.16.0-4-amd64
```

/lib/modules以下にヘッダ群が入っていることを確認できます。

続いて、コンパイルするためにMakefileを用意

```c:Makefile
KERNEL_DIR = /lib/modules/$(shell uname -r)/build 
BUILD_DIR := $(shell pwd)
VERBOSE := 0 

obj-m := helloworld.o 

all: 
    make -C $(KERNEL_DIR) SUBDIRS=$(BUILD_DIR) KBUILD_VERBOSE=$(VERBOSE) modules 
clean: 
    rm -rf *.o *.ko *.mod.c *.symvers *.order .tmp_versions .helloworld.*
```

modinfoにてモジュールの情報を確認

```
vagrant@jessie:~/helloworld$ /sbin/modinfo helloworld.ko
filename:       /home/vagrant/helloworld/helloworld.ko
author:         takish
license:        GPL2
description:    helloworld
depends:
vermagic:       3.16.0-4-amd64 SMP mod_unload modversions
```

insmod/rmmodにてモジュールのロード、アンロードを確認する

```
$ sudo /sbin/insmod helloworld.ko
$ lsmod
$ sudo /sbin/rmmod helloworld
```

dmesgにてprintkでの出力がされていることも確認して見てください。
物置：気になる物事

__とりあえず箇条書きにしておくだけ。__
___

####マージツール

[KDiff3とP4Merge比較記事]　https://tokibito.hatenablog.com/entry/20160209/1454955700



####Semantic Merge
* 頭のいいマージツールらしい。今使うか？将来スタンダードになるか？
* 三方向マージ（3 way merge）
https://www.semanticmerge.com/
http://www.softantenna.com/wp/software/senmantic-merge/
Visual Studio2012の使い方

#学習した内容　
・ソリューションとプロジェクトの作成
・ツールボックス使い方
・ツールボックスからButtonコントロールをWPFウィンドウに配置
##新しいソリューションとプロジェクトの作成
・(ファイル)→(新規作成)→(プロジェクト)
 ![WS000000.JPG](https://qiita-image-store.s3.amazonaws.com/0/249277/519dc6ed-55bc-75c7-68a2-db389272c08e.jpeg)
・(WPFアプリケーション)をクリック→(名前)＝(ソリューション名)→(場所)→(保存)
　　*(ソリューションのディレクトリを作成)チェックボックスがオンになっていることを確認する。
![WS000001.JPG](https://qiita-image-store.s3.amazonaws.com/0/249277/d70df8a2-5325-19a4-17f0-0452385ee5df.jpeg)
##ツールボックスの表示
(表示)メニュー→(ツールボックス)
*(Shift+F7)
![WS000002.JPG](https://qiita-image-store.s3.amazonaws.com/0/249277/93bd6c1a-4824-dcfb-7dfc-65fed2ed0e64.jpeg)
ツールボックスが右にでていることを確認
![WS000003.JPG](https://qiita-image-store.s3.amazonaws.com/0/249277/b0ac8ecc-e43a-2400-1206-16e1b2b02093.jpeg)
###ButtonコントロールをWPFウィンドウに配置
ツールボックスの(Button)をクリック→WPFウィンドウをクリック
![WS000004.JPG](https://qiita-image-store.s3.amazonaws.com/0/249277/6d54c95b-ade2-4815-bbfd-d751cb234170.jpeg)
WPFウィンドウに配置されているかを確認
Pandas でExcelを読む時のカラム指定

#目的
pandas でExcelファイルを解析したいが、パラメータエラーと怒られ、調べて解決したが、その過程を備忘録とする
#環境
Windows7+Anaconda3(4.3.30)
#試したソース
```python
sheet1 = Excel.parse(sheetname='2004', index_col=None,
                     na_values=['NA'], usecols='A,C:AA')
```
#問題
上記のコードを実施すると、”, is not in the list" 旨のメッセージが出た。
usecolsがdeprected parse_cols で試しても、一向に改善されません。
#解決

いろいろ調べた結果、なんと最新のAnaconda3なのに、Pandasは最新ではないと...
pip install pandas --upgrade 
を実施すると、解決！
mht形式で保存されたCognosのActive ReportをFireFoxで実行するにはUnMHTアドオンが必要

Cognosで作成したActive Reportをダウンロードして配布して使用することができますが、
ただ、ダウンロードされたmht形式のActive ReportはそのままではFireFoxで稼動させることができません。

どうすればよいかと言うと、
FireFoxに「UnMHT」アドオンを追加することで実行できるようになります。



[UnMHTアドオンへのリンク](https://addons.mozilla.org/ja/firefox/addon/unmht/)


アドオンを追加すると、FireFoxの再起動も必要なく、mht形式のActive Reportを実行できるようになります。
![WS000003.JPG](https://qiita-image-store.s3.amazonaws.com/0/146283/06d386b6-9bae-4656-8cff-cc294f97c949.jpeg)
ExcelVBAで他のアプリを起動したあとに、マクロ動かしてるExcelを手前にもってきたい件

#ExcelVBAでツール作って関連付けから他のアプリをキックしたらアクティブウインドウが取られちゃう(当たり前)

なんちゃってExcelマクロまん16年目に突入したふーれむです。
ググっても最適解が出なかったので備忘として書き残しておきます。

##そもそもの話
ExcelVBAでマクロを作った時、Excel内だけで処理が完結するものは
別に面倒なWindow制御とか要らんのですが、外部アプリをキックしたあとに「おわったよ」ダイアログとか出したい時、外部アプリが上にくると永久に終わりがわからなくなるという…　ね…　(´・ω:;.:...

で、ググったわけだが最適解が乗ってなかったわけですよ。

###結論
以下のコードを確認ダイアログとか出したい直前にサクッと差し込んでおく。

```
    AppActivate Application.Caption
```

たぶんバージョン差異などがあっても今のExcelのウインドウタイトル名称を動的に引っ張ってきてくれて動くので、今後も無修正で動いてくれる（と信じている）。

(注：例外があるとすると、Excel起動してる状態で、更に「コマンド名を指定して実行」とかで別プロセスのExcelを起動し、それぞれで同じファイル名のファイルを開いて…とかすると名前が衝突しててアレなのかな と思ったのだけれど、どうも「完全同一名称のExcelファイルは同時に開けない」という制約があるのかもしれない。(私の環境では起動したら蹴られたので…)　Excel自身が何らかの古いソースコードの中でPIDではなくウインドウハンドラの名前ベースの制御をしてるのかもしれませんね。)

おわり。

###以下細かい話
AppActivate関数は引数に名称ないしWindowsのPIDを渡してやるとそのアプリケーションを最前面にもってきてくれる関数なわけですが、
ググったところ

〇ファイル名と " - Excel" を結合して食わせよう
とか、

〇以下みたいな形でPIDをもらってきてAppActivate関数の引数に入れよう

```
    Dim l_PID As Long
    l_PID = Shell("ほげほげ", 1)
    AppActivate l_PID
```

といった情報は出てくるんですが、決定版みたいな情報が見当たりませんでした。

###まとめ

結局のところ、基本的に起動したExcel自身でのウインドウアクティブ化対応が必要な場合は

```
    AppActivate Application.Caption
```

Excelマクロから起動した何かのウインドウアクティブ化対応が必要な場合は

```
    Dim l_PID As Long
    l_PID = Shell("ほげほげ", 1)
    AppActivate l_PID
```

というコードになりそうです。
ログインパスワードの伏せ字を表示するブックマークレット


```js
// Form の パスワードを表示する
javascript: (() => {
  const elems = Array.from(document.querySelectorAll('[type=password]'));
  elems.forEach((e) => e.setAttribute('type', 'text'));
})();
```



関連: [ブックマークレット活用・すばやい登録と呼び出し \- Qiita](https://qiita.com/elzup/items/1698767d77af39d8dd19)
tensorflow.jsで手書き分類

#概要
tensorflow.jsで手書き分類、やってみた。

#以下から、モデルお借りした。

https://github.com/CreativeGP/tensorflowjs-mnist 

#サンプルコード


```
var canvas = $("#canvas").get(0);
var touchableDevice = ('ontouchstart' in window);
if (canvas.getContext)
{
	var context = canvas.getContext('2d');
	var drawing = false;
	var prev = {};
	canvas.width = 2 * $("#canvas").width();
	canvas.height = 2 * $("#canvas").height();
	context.scale(2.0, 2.0);
	context.lineJoin = "round";
	context.lineCap = "round";
	context.lineWidth = 20;
	context.strokeStyle = 'rgb(0, 0, 0)';
	$("#canvas").bind('touchstart mousedown', function(e) {
		e.preventDefault();
		prev = getPointOnCanvas(this, event, e);
		drawing = true;
	});
	$("#canvas").bind('touchmove mousemove', function(e) {
		if (drawing == false) return;
		e.preventDefault();
		curr = getPointOnCanvas(this, event, e);
		context.beginPath();
		context.moveTo(prev.x, prev.y);
		context.lineTo(curr.x, curr.y);
		context.stroke();
		prev = curr;
	});
	$("#canvas").bind('touchend mouseup mouseleave', function(e) {
		drawing = false;
	});
	var getPointOnCanvas = function(elem, windowEvent, touchEvent) {
		return {
			x : (touchableDevice ? windowEvent.changedTouches[0].clientX : touchEvent.clientX) - $(elem).offset().left,
			y : (touchableDevice ? windowEvent.changedTouches[0].clientY : touchEvent.clientY) - $(elem).offset().top
		};
	};
	$("#run_button").click(function() {
		test_predict();
	});
	$("#delete_button").click(function() {
		context.clearRect(0, 0, 280, 280);
	});
	var getImageBuffer = function(context, width, height) {
		var tmpCanvas = $('<canvas>').get(0);
		tmpCanvas.width = width;
		tmpCanvas.height = height;
		var tmpContext = tmpCanvas.getContext('2d');
		tmpContext.drawImage(context.canvas, 0, 0, width, height);
		var image = tmpContext.getImageData(0, 0, width, height);
		var buffer = []
		for (var i = 0; i < image.data.length; i += 4)
		{
			var sum = image.data[i + 0] + image.data[i + 1] + image.data[i + 2] + image.data[i + 3];
			buffer.push(Math.min(sum, 255));
		}
		return buffer;
	};
}
var test_predict;
tf.loadModel('https://rawgit.com/CreativeGP/tensorflowjs-mnist/master/model/model.json').then((model) => {
    test_predict = function() {
	    var p = getImageBuffer(context, 28, 28);
        const buffer = tf.buffer([1, 28, 28, 1]);
        for (var i = 0; i < 28; i++) 
        {
            for (var j = 0; j < 28; j++)
            {
                var s = i * 28 + j;
                var v = p[s] / 255.0;
                buffer.set(v, 0, i, j, 0);
            }
        }
        const input = buffer.toTensor();
        const predict = model.predict(input).argMax().dataSync();
        alert(predict);
    }
});

```


#成果物

http://jsdo.it/ohisama1/UrzR

#モデルを変更した。

https://github.com/yukagil/tfjs-mnist-cnn-demo 

#成果物

http://jsdo.it/ohisama1/SUxj


以上。
VMware FusionにHigh Sierraをインストールしようとして“インストールメディアを作成できません”でつまずいた時の対処

App Storeから【macOS High Sierraインストール】をダウンロードすると最初に自動実行されるのだけど、インストーラを終了しても勝手にマウントされたディスクイメージが裏に残っているのが原因(デスクトップに表示されない)。

ディスクユティリティーを起動してこのイメージをアンマウントすると、無事にインストールできるようになる。

![名称未設定.png](https://qiita-image-store.s3.amazonaws.com/0/48588/3cd453a3-15fb-5dd4-4bf3-f4a888378f04.png)
Linux mintでVNC接続するときの方法

http://kimamanilife.com/archives/459
こちらの記事を参考にさせていただきました。

# Linux mint端末でVNCを接続するときはGUIで設定できる
vinoと言われている標準で入っているソフトウェアを用います。
![スクリーンショット_2018-04-11_17-22-12.png](https://qiita-image-store.s3.amazonaws.com/0/174910/8b437b0d-a4ed-b138-916b-fde514a8f5d2.png)

パスワードの入力要求はデフォルトでは無効になってるので注意です。

最初はこれでVNC接続できると思っていたのですが、これだけでは出来ず...。
Googleさんに聞くと、
「vinoではLinux端末同士ではこれでいいけど、windowsとかIOSだとできないよ」
とのこと。
しんどい〜〜〜。

でもう少し調べて上記の記事を見つけました。
このコマンドを打って、暗号化を無効にしないといけないらしい。
```
$ gsettings set org.gnome.Vino require-encryption false
```

![IMG_0095.PNG](https://qiita-image-store.s3.amazonaws.com/0/174910/ad27cc81-2362-5e5c-c19e-43bdb718386e.png)

Ipadから繋いだけど出来てるっぽい。

なお、一度再起動しないと設定が反映されませんのでご注意下さい。
Deployerを使ってLaravelのenvファイルをデプロイする

# はじめに

- Deployerを使ってLaravelアプリケーションをデプロイする際に.envファイルの扱いに工夫が必要だったので内容をまとめておきます。
- [Deployer](https://deployer.org/)とはphp製のデプロイツールになります(capistranoのようなものです)

# やりたいこと

- デプロイ環境ごとに.envファイルを以下のようにつくっておき、デプロイ環境にあわせてそれぞれ有効になるようにします。

```
.env.development     # 開発環境
.env.staging         # 検証環境
.env.production      # 本番環境
```

# 問題点

- Deployerにあらかじめ用意されているlaravelのrecipeを使ってデプロイする場合、以下の設定がされているので、プロジェクト内の.envファイルがsharedディレクトリにコピーされ、.envファイルとリンクされます。

    ```php
      set('shared_files', [
        '.env',
      ])
    ```

- ただし、**はじめからプロジェクト内に.envファイルが存在しない場合、空の.envファイルが生成され、それがリンクされます**
- このため、sharedディレクトリにファイルがコピーされる前に環境にあわせた.envをファイルをプロジェクトディレクトリに生成しておく必要があります。

# 解決策

- 上記の処理をDeployerのtaskとして定義して、sharedの処理が実行される前に実行されるように設定します
    - ただし、デプロイするごとに.envファイルが更新されないように、デプロイ実行時のオプションとして指定できるようにします
- はじめにオプションの引数を定義します。
    - `env-update=true` のようにして指定します

```php
option('env-update', null, InputOption::VALUE_OPTIONAL, 'update env file.');
```

- taskを定義します

```php

task('copy:env', function () {
    if (input()->hasOption('env-update')){
        $update = input()->getOption('env-update');
        if($update == 'true'){
            $stage = get('stage');
            $src = ".env.${stage}";
            $path = get('deploy_path');
            $shared_path = "${path}/shared";
            run("if [ -e $(echo ${shared_path}/.env ) ]; then cp {{release_path}}/${src} ${shared_path}/.env; fi");
            run("cp {{release_path}}/${src} {{release_path}}/.env");
        }
    }
});
```

- deploy_pathは `set('deploy_path', '/var/www/html')`のように設定されていることを前提としています
- 以下のようして `recipe/laravel.php` の `deploy:shared` が実行される前に上記のタスクが実行されるようにしておきます

```php
before('deploy:shared','copy:env');
```

- あとは以下のようにしてデプロイを実行します

```bash
dep deploy production --env-update=true
```

# 最後に

- Deployerには予めLaravel用のデプロイrecipeが用意されているので、簡単にデプロイ環境を構築出来てとても便利です！