OmniAICreator/Qiita-1.07M huggingface dataset:
【WordPress】アフィリエイトリンクをショートコード化する方法【プラグインなし】

WordPressでWebサイトを運営していると、アフィリエイトリンクを貼り替えなければいけないことがあります。

 

このとき、アフィリエイトリンクを複数のページに貼っていると非常に面倒です。

 

1ページ1ページ貼り替えなきゃいけないので、

- 時間がかかる
- 貼り替えを忘れてしまう
などのデメリットがあります。

 

そんな時にやりたいのが、アフィリエイトリンクのショートコード化。

ショートコードにすると、とにかく管理が楽になります。

 

ショートコード化するプラグインもありますが、「わざわざプラグインを入れたくない」という人もいると思うので、この記事ではプラグインなしでショートコード化する方法についてまとめてみました。


##アフィリエイトリンクはショートコードにして管理しよう

アフィリエイトリンクはショートコードにして管理するのが楽です。

###そもそもショートコードとは？
ショートコードとは、自分で作った関数を短いコードで呼び出せる機能です。


例えば、

**Nintendo Switchの購入はこちら**

というアフィリエイトリンクを作りたいとします。



そして、ショートコードの名前をswitchとしましょう。

 

この時、[switch]と記述すると、[switch]と記述した場所にNintendo Switchの購入はこちらというリンクが出力されます。

 

これがショートコードです。


###アフィリエイトリンクをショートコードにすると管理が楽すぎる

アフィリエイトリンクをショートコード化するメリットは

- アフィリエイトリンクの管理が楽になる

ということです。

例えば、複数の記事にアフィリエイトリンクを直接貼っていたとしましょう。

 

この場合、アフィリエイトリンクを貼り替える必要がでてきたとき、「1ページずつ貼り直す」という面倒な作業が発生してしまいます。

 

しかし、アフィリエイトリンクをショートコード化する場合は、面倒な作業は発生しません。

 

ショートコードの内容を書き換えるだけで、全ての記事のアフィリエイトリンクを一括で変更できる

のでとにかく楽。

 
- 時間を節約できる
- 貼り替えを忘れもない
などメリットがとにかく大きいです。


##【コピペOK】WordPressでショートコードを作る方法
ショートコードを作るには、PHPというプログラミング言語を書く必要があります。

けど、コピペでOKなので心配無用です。

###アフィリエイトリンクを出力するショートコードの書き方

WorPressテーマのfunctions.phpに、以下のコードを書き込みましょう。（太字は各自設定する必要がある箇所）
 

```functions.php
function 関数の名前() {
 return 'アフィリエイトリンク';
}
add_shortcode('ショートコード名', '関数の名前');
```

ちなみに、functions.phpは

1.外観
2.テーマエディター
3.function.php

の順番で進んでいくとファイルがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266250/6ed8de63-af5e-0344-87d3-5c99eadb422d.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266250/b83e1858-149c-bb38-aa15-7ff8602a7eb9.png)


下の写真の”//以下に子テーマ用の関数を書く”の下に、先ほどのショートコードを貼ってください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266250/5d2a6071-98e2-5f79-bd22-ecdc3a8e5b30.png)


##アフィリエイトリンクをショートコード化する具体例
具体例として、Nintendo SwitchのAmazonアフィリエイトのリンクをショートコード化してみます。

###ステップ1：関数名を決める
まずは関数名を決めます。

関数名はパッと見で分かるようにするのがオススメです。

 

今回は、”switch”という関数名にしましょう。

そうすると以下のようになります。


```functions.php
function switch() {
 return 'アフィリエイトリンク';
}
add_shortcode('ショートコード名', 'switch');
```

##ステップ2：アフィリエイトリンクの挿入
次にアフィリエイトリンクを挿入します。

 

ここでは“https://switch-amazon”という架空のURLを挿入された“Nintendo SwitchをAmazonでチェックする”という文字列を出力するショートコードを作ってみましょう。

 

以下のように書けばOK。

```functions.php
function switch() {
 return '<a href="https://switch-amazon">Nintendo SwitchをAmazonでチェックする</a>';
}
add_shortcode('ショートコード名', 'switch');
```


###ステップ3：ショートコード名を決める
次にショートコード名を決定します。

ショートコード名も分かりやすくするのがオススメです。

 

僕は基本的に関数名と同じにしています。

なので、今回もswitchというショートコード名にしてみました。

```functions.php
function switch() {
 return '<a href="https://switch-amazon">Nintendo SwitchをAmazonでチェックする</a>';
}
add_shortcode('switch', 'switch');
```

これで完成。

[switch]と記事中に書いてみて、Nintendo SwitchをAmazonでチェックするというリンクが出力されていたら成功です。


##WordPressでショートコードを作る時の注意点
最後に注意点について、簡単に書いておきます。

 

ショートコードを書くfunctions.phpというファイルは、けっこう重要なファイルです。

 

なので、バックアップを取った上でコードを書きましょう。

ショートコードは便利ですが、自己責任でお願いします。


##まとめ
アフィリエイトリンクをショートコード化すると便利なので、個人的にはオススメ。

 

貼り替えが発生したとき、とにかく楽です。
gofeedを使って、パースできないUnicode文字を除去してパースする方法

# 背景
gofeedのParseURLメソッドでwebページをパースしようとしたところ、以下のエラーが発生。
不正文字(パースできないUnicode文字)がXML上に含まれているとのこと。

```
  XML syntax error on line 650: illegal character code U+0008
  panic: runtime error: invalid memory address or nil pointer dereference
  exit status 2
```

エラーが起きるたびに不正文字を置換で除くのは大変なので、不正文字を除去してパースする仕組みにしたい。

# 環境
- Golang 1.11.0
- gofeed v1.0.0-beta2

# 対応
[ParseURL](https://godoc.org/github.com/mmcdole/gofeed#Parser.ParseURL)メソッドだと、webページに不正文字が存在する時点でエラーになってしまうため、以下の手順を踏むことで対応する。
1. webページをstring型で取得
2. [unicode.IsPrint](https://golang.org/pkg/unicode/#IsPrint)と[strings.Map](https://golang.org/pkg/strings/#Map)を利用し、不正文字を除去
3. [ParseString](https://godoc.org/github.com/mmcdole/gofeed#Parser.ParseString)メソッドでパース

#### 修正前
```go:main.go
  func main() {
      fp := gofeed.NewParser()
      feed, _ := fp.ParseURL(パース対象のwebページのURL) // ParseURLでエラー
      items := feed.Items
      ...
  }
```

####修正後
```go:main.go
  func main() {
      resp, _ := http.Get(blog.URL)
      defer resp.Body.Close()
      body, _ := ioutil.ReadAll(resp.Body)
      xmlData := strings.Map(printOnly, string(body))

      fp := gofeed.NewParser()
      feed, _ := fp.ParseString(xmlData)
      items := feed.Items
      ...
  }

  func printOnly(r rune) rune {
      if unicode.IsPrint(r) {
          return r
      }
      return -1
  }
```

※エラーハンドリングは省略

## 参考
https://blog.zikes.me/post/cleaning-xml-files-before-unmarshaling-in-go/
Kafka in Docker のチュートリアル

## 内容
公式のチュートリアルにはバージョンなどが原因で不備があるので、それを修正して解説したものを書きました。

[公式チュートリアル](http://wurstmeister.github.io/kafka-docker/)

## Install
dockerのインストールは前提とし、kafka-dockerをインストールします。

```bash
$ git clone git@github.com:wurstmeister/kafka-docker.git
```

## docker-compose.ymlの修正
zookeeperのホストのポートは2181に制限したままだと接続できないので削除します。
`KAFKA_ADVERTISED_HOST_NAME`はDockerホストのIPアドレスに変更します。

```yml:docker-compose.yml
version: '2'
services:
  zookeeper:
    image: wurstmeister/zookeeper
    ports:
      - "2181"
  kafka:
    build: .
    ports:
      - "9092"
    environment:
      KAFKA_ADVERTISED_HOST_NAME: 192.168.100.93
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
```

## 起動と確認


```bash
$ docker-compose up -d
$ docker-compose ps
      Name                     Command               State                          Ports
----------------------------------------------------------------------------------------------------------------
kafka_kafka_1       start-kafka.sh                   Up      0.0.0.0:32768->9092/tcp
kafka_zookeeper_1   /bin/sh -c /usr/sbin/sshd  ...   Up      0.0.0.0:32769->2181/tcp, 22/tcp, 2888/tcp, 3888/tcp
```

## Topicを作成し、Producerでメッセージを送る
Kafka shell を起動。
`ZK_HOST`には`KAFKA_ADVERTISED_HOST_NAME`で設定したIPを入れます。
`ZK_PORT`にはzookeeperのコンテナのポートを入れます。


```bash

$ ./start-kafka-shell.sh <DOCKER_HOST_IP> <ZK_HOST:ZK_PORT>
```

Topicを作成。
`test`というTopic名でPartitionは4に設定します。
`$ZK`には<`KAFKA_ADVERTISED_HOST_NAME`で設定したIP:zookeeperのホストのポート>を入れます。

```bash
$ $KAFKA_HOME/bin/kafka-topics.sh --create --topic test --partitions 4 --zookeeper $ZK --replication-factor 1
```

作成されたTopicを確認。
ちゃんと４つありますね。

```bash
$ $KAFKA_HOME/bin/kafka-topics.sh --describe --topic test --zookeeper $ZK
Topic:test	PartitionCount:4	ReplicationFactor:1	Configs:
	Topic: test	Partition: 0	Leader: 1001	Replicas: 1001	Isr: 1001
	Topic: test	Partition: 1	Leader: 1001	Replicas: 1001	Isr: 1001
	Topic: test	Partition: 2	Leader: 1001	Replicas: 1001	Isr: 1001
	Topic: test	Partition: 3	Leader: 1001	Replicas: 1001	Isr: 1001
```

Producerを起動し、適当なメッセージを送る

```bash
$KAFKA_HOME/bin/kafka-console-producer.sh --topic=test --broker-list=`broker-list.sh`
>test1
>test2
>test3
>test4
```
## Consumerを起動し、メッセージを受け取る

Producerは起動したまま、別のshellからconsumerを起動し、メッセージを受け取ります。
ちゃんと全て受け取れてますね

```bash
./start-kafka-shell.sh <DOCKER_HOST_IP> <ZK_HOST:ZK_PORT>
$KAFKA_HOME/bin/kafka-console-consumer.sh --bootstrap-server=`broker-list.sh` --topic=test --from-beginning
test2
test3
test4
test1
```

## 参考
[公式チュートリアル](http://wurstmeister.github.io/kafka-docker/)
[Kafka を試してみる](https://blog.chocolapod.net/momokan/entry/106)
CentOS 8

##CentOS 8 が2019.09.24にリリース予定。

本のミラーサーバにはまだミラーされていないようだが、海外のサーバにはミラーされているところもあるよう。

リポジトリのライフサイクルが少し変わっているらしい。

例によって、epelはインストールしたいので、
$ wget https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/e/epel-release-8-5.el8.noarch.rpm
$ yum install -y ./epel-release-8-5.el8.noarch.rpm
Stitch Fix: 変化し続けるファッション界のレコメンドAIは、人間とAIの協業の仕組みが成功の鍵

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124978/92eb557e-eb85-395e-ce7f-9486bc5452b7.png)


以前にも何度か取り上げてきたサンフランシスコのファッション系のスタートアップであるStitch FixがShop Your Looksという新しい機能をリリースしたのにともない、「[Need Some Fashion Advice? Just Ask the Algorithm](https://www.wired.com/story/stitch-fix-shop-your-looks/)」という記事がWeirdの方に出てました。

これは、すでにスタイリストが手作業で一つずつ作って顧客に送っていた着こなしを提案するカードをデータに落としこみ、それをもとに作った予測モデルによるレコメンドのサービスに関する話ですが、人間（顧客とスタイリスト）とAIの協業によって、よいサービスができていく話としてもおもしろいと思いました。

もともとスタイリストが手作業で一つずつ作っていた情報を大量に効率的に入力していくことができる、アウトフィット・ピッカーと呼ばれるツールを作って、現在Stitch Fixの3000人ほどいるスタイリストやクリエイティブチームの人達は着こなしに関する情報をデータベースに入れていっているとのことです。

こうした服装の組み合わせの候補は、その時その時の在庫、新しいデータ、新しいスタイルによって変わってくるので絶えずアップデートし続ける必要があるとのことです。

さらにユーザーからのフィードバックを効率的に集めるために、Tinderという出会い系のアプリのようにユーザーがスワイプして簡単によいか悪いかを入力することができるUIを提供しているとのことです。

機械学習による予測モデルは入力データの精度と量が重要なので、こうした精度の高いデータをうまく集めてくるフィードバックの仕組みがしっかり作っているのが参考になります。

## AIは人間が絶えず更新し続けなくてはいけない

ところで、この手の話があると、ファッション・エディターやスタイリストがAIに置き換わると思われがちですが、彼女たちはそんなことはないといい切ります。

今回のShop Your Looksの開発をリードしたデータサイエンティストのHilary Parkerのコメントは興味深いです。

「データを収集してこれが最高のアウトフィットだ！と宣言して終わることはない。着こなしに関する問題を解決する日は永遠に来ないでしょう。私達は複雑なアートの形式であるものをモデルしようとしているのです。ファッションは絶えず進化し、人間も進化し続けるので、専門家やスタイリストからの入力を絶えず必要とします。つまり、これは私達がずっとやり続けることになるタスクなのです。」

この記事は、Stitch Fixの新しいサービスのラウンチにともなうPR的なものがありますが、それでもおもしろいなと思ったのは、このサービスを開発した現場のデータサイエンティストへ直接インタビューした記事だからです。よくある、マーケティングの人間が有る事無い事、適当に言っているようなただのPR記事とは一線を画しています。

やはりこういう記事をしっかりと出せるのも、この会社ではCEO直属のチーフ・アルゴリズム・オフィサーがデータサイエンス部門のトップだからでしょう。つまり、チーフ・マーケティング・オフィサーと同じレベルなわけですから、基本的にはデータサイエンス部門がPRを主導することができるし、しっかりと地に足の着いた情報を出していくことができるのでしょう。

これは、IBMのWatsonがWatsonヘルスケアというサービスで、患者の診断を勝手にAIがやってくれるという触れ込みで売り切ったあとで、実は医者や看護師が絶えずデータを入力し続けなくてはいけないということが後でわかり、訴訟問題になってたのと比べると大きな違いです。IBMのPRというのは、もちろんマーケティングから出てくるのでほとんど詐欺みたいな話ばっかりです。

## レコメンドエンジンに関わっているのは100人のデータサイエンティストのうちたったの6人

ところで、Stitch Fixは顧客それぞれのスタイルに合わせて服をレコメンドして配送してくれるサービスですが、その際の服のレコメンドには、100人いるデータサイエンティストのうちたったの6人しか関わってないとのことです。他の人達は例えば、在庫の予想だったり、これからのトレンドの予想であったりと、他の様々なアルゴリズムに関する仕事をしているとのことです。

* ファッション業界もデータを使ってトレンドを理解する時代 - [Link](https://exploratory.io/note/kanaugust/zNW2PxP2Ho)

3000人ほどいるスタイリストがレコメンデーションのアルゴリズムを使ってそれぞれの顧客へどの服を送るかを決めているようですが、この品質はどんどん上昇しているようで、今では90％の顧客のリターン率を達成しているとのことです。すごいですね。


# データサイエンス・ブートキャンプ、11月開催！

次回の[データサイエンス・ブートキャンプ](https://ja.exploratory.io/training-jp?utm_campaign=stitchfix_shopyourlook&utm_medium=blog&utm_source=qiita)は11月です！

データサイエンス、データ分析の手法を１から体系的に学び、現場で使える知識とスキルを身につけたいという方は、ぜひこの機会に参加をご検討ください！

詳細は[こちらのページ](https://ja.exploratory.io/training-jp?utm_campaign=stitchfix_shopyourlook&utm_medium=blog&utm_source=qiita)にあります。
ステーキを食べて腹八分目だったときに満腹かつ完食できるグラム数を表示するRuby

ステーキ屋さんに行って好きなグラムを指定していざ実食！
すると不思議、結構多めに頼んだはずなのに腹八分目だった。

一体自分はどのくらいの量を食べれるのだろうか？
挑戦したいが、残すのはもったいない。

いくらのグラムを注文すれば、満腹で完食できるのだろうか？
それはRubyが教えてくれます。

```ruby:staek.rb
def stomach_limit(steak) #ステーキ食っても腹八分目関数
  stomach_capacity = 20/100.0 #腹八分目定義（あと２０％入る）
  completed_food_theory = steak+steak*stomach_capacity
  #今回食したステーキに20%を足した数値を出す
  end
  
  puts "何グラム食べましたか？"
  steak = gets.to_i #今回食したグラム数を入力する
  puts "あなたが完食できて、かつ満腹になれる理論値#{stomach_limit(steak)}グラムです。"
```


- 腹八分目の定義は８０％ではなく、あと２０％入るという解釈にしている
- 食べたグラム数に上記の２０％を足すことで、腹十分目とする
- 腹の状態も入力させて、計算できるようにすることが今後の課題


[参考]Rubyで指定の確率でtrueを返すメソッドはありますか?
https://ja.stackoverflow.com/questions/33416/ruby%e3%81%a7%e6%8c%87%e5%ae%9a%e3%81%ae%e7%a2%ba%e7%8e%87%e3%81%a7true%e3%82%92%e8%bf%94%e3%81%99%e3%83%a1%e3%82%bd%e3%83%83%e3%83%89%e3%81%af%e3%81%82%e3%82%8a%e3%81%be%e3%81%99%e3%81%8b
【初心者向け】Gitでブランチ/コミット/マージする一連の流れ

##この記事の対象者
・Gitというバージョン管理システムがあることは勉強して、gitの仕組み、addやcommitの使い方はなんとなく理解した初心者の方
・実際にgitを使ってアプリケーション開発を進める上で使用するコマンドがよくわからないという初心者の方

簡素にまとめてあるので、備忘録としてお使いください。

##一連の流れ
①ブランチを作成し、作成したブランチに移動する
②作成したブランチ上で作業を行いコミット&プッシュをする
③ファイル編集後、masterブランチに作成したブランチの編集内容を取り込む

##①ブランチを切る
まずはブランチを切りましょう。
ブランチというのは英語で「branch」と書き、「枝/分岐する」などの意味を持ちます。
一つのプロジェクトから枝分かれさせて作業を分担して行うために用いられます。

ここでは「sample-branch」という名前でブランチを切ります。

```
$ git checkout sample-branch
```
###※ブランチを作成すると同時にそのブランチに移動する場合
「-b」オプションを使用する。

```
$ git checkout -b sample-branch
```
###※間違えていらないブランチを作った場合
一旦他のブランチに移動してから、いらないブランチを削除しましょう。

```
$ git checkout sample-branch
$ git checkout -d 削除したいブランチ名
```

###現在のブランチを確認する

```
$ git branch
  master
※ sample-branch
```

「※」マークが付いているものが現在いるブランチを示しています。

##作成したブランチ上で作業を行いコミット&プッシュをする
ファイルを編集後、現在のディレクトリ配下の全てのファイルをトラッキング状態にして、ローカルリポジトリにコミットします。

```
$ git add .
$ git commit -m "commit message"
$ git push origin 
```
※コミットしたファイルや履歴を確認するには以下のコマンドを使用します。

```
$ git log
```

##masterへマージする
作成したブランチにて作業の区切りがついたら、いよいよ本体にマージしましょう！
まずは作成したブランチからmasterに移動しましょう。

```
$ git checkout master
```

そしてsampleブランチの内容をmasterにマージしましょう

```
$ git merge sample-branch
```

###※マージを元に戻す方法
間違えてマージしてしまって元に戻したいという時は以下のコマンドから状態を元に戻すことができます。

・マージした後でまだコミットしていない時
$ git reset --hard HEAD
・マージした後で既にコミットしている場合
$ git reset --hard ORIG_HEAD
phpで文字列や数値を昇順と降順にするソートボタンを作ってみた

#近況報告

エンジニア転職成功しました。YouTubeでエンジニア転職したい方向けに情報発信しています。

https://www.youtube.com/channel/UCcXQG8lu_EdyP2Cbhtz1bcA




独習php5.3に載っていたスタックとキューの概念と、配列の内容を並び替えるsort関数を用いて、
簡単に文字列をソートさせるプログラムを組んでみました。

入力フォームに文字を打って各ボタンを押すと値がソートされます。

phpの実行環境をお持ちの方は
コピペで使えますので参考までにどうぞ。

```php:practicesort.php
<!-- 練習問題5.3を元にスタックとキューの概念と配列のソートを用いて値をソートさせる -->
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<form action="" method="POST">
    <?php echo "ソートさせたい文字列を入れてください(1024文字まで)"; ?>
    <br>
    <!-- 入力フォームとボタンを作成 -->
    <input type="text" name="content">
    <input type="submit" name="昇順" value="昇順ソート">
    <input type="submit" name="降順" value="降順ソート">
</form>
</body>
</html>

<?php
    // 入力文字を受け取る
    $content = htmlspecialchars($_POST["content"], ENT_QUOTES, "UTF-8");
    $contentCnt = 0;

    // 入力文字を受け取った場合
    if(isset($content)){
        // 文字数を数える
        $contentCnt = mb_strlen($content);
        // 文字数が有効範囲の場合
        if(1 <= $contentCnt && $contentCnt <= 1024){
            // 文字数分カンマで区切る
            for($i = 0; $i <= $contentCnt; $i++){
                $contentStr .= mb_substr($content,$i,1).',';
            };
            // カンマの位置で配列に分割
            $contentStr = explode(',',$contentStr);
            // 昇順/降順ソートボタンを押した時
            if("昇順ソート" === $_POST['昇順']){
                // 昇順ソートする
                sort($contentStr, SORT_STRING);
                $check = "asc";
            }elseif("降順ソート" === $_POST['降順']){
                // 降順ソートする
                rsort($contentStr, SORT_STRING);
                $check = "desc";
            };
            // 配列の要素値をresultに全て格納
            foreach($contentStr as $contentSort){
                $result .= $contentSort;
            };
             // 昇順/降順ソートボタンを押した時
            switch($check){
                case "asc" :
                    print $result."　<b>左記文字を昇順ソートしました</b>";
                    break;

                case "desc" :
                    print $result."　<b>左記文字を降順ソートしました</b>";
                    break;
            };
        }elseif($contentCnt > 1024){
            echo "1024文字以内で入力してください。";
        }elseif($contentCnt == 0){
            echo "文字を入力してください";
        }
    }
?>
```
アンジャッシュとエンジニア～コミュニケーションの桃源郷を目指して～

## この記事の概要
- エンジニアにおいてコミュニケーション能力が大切だというポエムです
- アンジャッシュアンチやエンジニアアンチの記事ではありません
- 上司や同僚とのコミュニケーションについて悩んでいる方の助けになれば幸いです

## アンジャッシュとは
### 概要
> アンジャッシュは、児嶋一哉と渡部建によるお笑いコンビ。プロダクション人力舎に所属。1994年デビュー。略称は「アンジャ」。爆笑オンエアバトル第5代目チャンピオン。ともに東京都八王子市出身。

([Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%B3%E3%82%B8%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5)より引用)

### アンジャッシュの芸風
彼らの代表的なネタに「すれ違いコント」というものが存在する。
これはどういう内容かと言うと、児嶋さんと渡部さんが会話をしていくうちに、両者の知識や勝手に想像していた話の前提から生まれる勘違いが（悪い方向に）噛み合ってしまい、お互いに変な人だなぁ…と思いこんでしまうというものである。（全部のネタがこの構成であるという意味ではないのであしからず）

### 芸風のポイント
前述した短い文でのポイントは以下のとおりである。

1. 会話中に**知識や話の前提から勘違い(齟齬)**が起こる
1. そしてそれが**(悪い方向に)噛み合う**
1. お互いに**「何を言っているんだろう？」**となる

お笑いネタとしては非常に秀逸で面白いものである。

## アンジャッシュのネタがエンジニアリングの世界で起こったら
こうなる→[顧客が本当に必要だったもの](https://s-jsd.com/entry/1422.html)

これはあくまで一例で由々しき事態だが、これは顧客との間だけで発生するものではない。
上司と部下、同僚同士、マシンと人間の間でも発生する。

エンジニアはこのような事態を未然に防ぐ必要がある。

## 優しい世界を目指して
### 優しい世界とは…
コミュニケーションをしている人・モノたちが、齟齬なく効率的な意思伝達ができる桃源郷のことである。~~僕と契約して魔法ｓ~~

### 齟齬の回避策
「芸風のポイント」セクションで述べた3つのポイントは、すべて**相手に質問する・自分の考えや知識を述べる**ことで解決することが可能である。
言い換えれば、「相手の知識・認識」と「自分の知識・認識」を同じレベルにすれば齟齬を回避できる、ということである（文章が長くなってしまうので、以下では「知識・認識」のことを単に「知識量」と書くことにする）。
さらに言えばこの齟齬は、相手と自分の知識量のギャップが開けば開くほど発生しやすくなる。

### 素早く知識量のギャップを埋める
相手に質問することと、自分の考えや知識を述べることで、両者の知識量のギャップを埋めることが可能となる。このギャップを埋める作業は、どちらか一方が欠けると非常に難航し、作業効率が悪くなる。

例えば、コンパイル言語でコンパイルエラーが出たときに人間はデバッグ（質問）し、正しいコードを書く（知識を述べる）。この際マシンと人間の知識量が合致すればコンパイルが成功する。（そのコードが顧客が本当に必要だったものかはわからないが。）
この際デバッグ（質問）ができない状況であれば人間側は青ざめた表情になるかもしれない。

はたまた人間同士の会話において、「このエラーはどういう意味ですか？」とだけ訊かれても答える側は、「どのような環境で出たのだろう」「どういう操作をしたのだろう」となり途端に答えにくくなる。（この場合は、答える側がそれを質問をすることで解消できる場合があるが、時間的ロスが発生する。）

ちなみに不要な質問や、相手が必要としていない（自分の）知識量を露呈すると、相手に嫌われるかもしれないので注意が必要である。

### 優しい世界に存在しない概念
「感情」はこの桃源郷には存在しない。（感情という概念が存在しないのに優しいとはこれいかに。）
例えば、「私はあなたを好いておりません故、質問は受け付けられませぬ」などである。
そもそもこれはコミュニケーションが成立していないので、この桃源郷では扱うことができない。

## まとめ
- エンジニアの世界においてコミュニケーション能力は必須である
- コミュニケーションでは齟齬が発生する可能性があり、その齟齬は「**相手に質問する・自分の考えや知識を述べる**」ことで充分対処可能であることを記した

---
#### 言い訳とか
「顧客が本当に必要だったもの」はあくまで一例です。この記事は、円滑なコミュニケーションを取るためのノウハウを記したものですので、お間違いなきようお願いいたします。

当記事の内容については普段私も心がけておりますが、やはり議論する時間が足りない・これを質問したら失礼かな？など、桃源郷には程遠い場面も多々存在します。
gitコマンド実行時にライセンス同意(Xcode/iOS)を要求された場合の対処法

# 概要
個人的メモ。
gitコマンドを叩いた時にXcode/iOS関連のライセンスに同意するよう言われたので対応した。
※実行環境は```MacOS Mojave```

# 事象
```Terminal
$ git status

Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.
```
こんな感じでライセンスに同意してねと言われる。

# 対応手順
## xcodebuildコマンドを実行
```Terminal
$ sudo xcodebuild -license
```

## Enter押下でライセンス情報を表示
```
You have not agreed to the Xcode license agreements. You must agree to both license agreements below in order to use Xcode.

Hit the Enter key to view the license agreements at '/Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf'
```

## ライセンス情報を確認する
```Terminal
Xcode and Apple SDKs Agreement

PLEASE SCROLL DOWN AND READ ALL OF THE FOLLOWING TERMS AND CONDITIONS 

〜〜

Software License Agreements Press 'space' for more, or 'q' to quit
```
SpaceかEnter押下で読み進める。
q押下だとライセンス情報を閉じてしまうので注意。

## ライセンスに同意する
ライセンス情報を最後まで表示すると確認メッセージが表示される。
```agree```を入力し、Enter押下。

```Terminal
By typing 'agree' you are agreeing to the terms of the software license agreements. Type 'print' to print them or anything else to cancel, [agree, print, cancel] 
```

同意が完了すると以下のメッセージが表示される。

```Terminal
You can view the license agreements in Xcode's About Box, or at /Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf
```

## 動作確認
```Terminal
$ git status
```
正常にコマンド実行できたら、全行程完了。
【Realm】Could Not Build Objective-C Module 'RealmSwift' というエラーが出る

RealmSwiftはちゃんとinstallされているのに***「Could Not Build Objective-C Module 'RealmSwift' 」*** というエラーが出たので、対処法をメモしておきます

#### 1.Product > Scheme > New Scheme の順に開く
#### 2.‘RealmSwift’をドロップダウンから選択
#### 3.'OK' を押す

かなりシンプルですが...
以上で自分の場合は解決出来ました。
[漏洞预警]CVE-2019-8451/Jira未授权SSRF漏洞

### 漏洞描述
近日Atlassian公开了一个Jira未授权SSRF漏洞.Jira中的`/plugins/servlet/gadgets/makeRequest`类允许远程攻击者通过服务器端请求伪造(SSRF)漏洞来访问内网资源.此漏洞加上某一特定请求头,无需登陆即可触发.
### CVE编号
CVE-2019-8451
### 漏洞威胁等级
高危
### 影响范围
Jira < 8.4.0
### 漏洞验证
使用payload在未授权的情况下进行SSRF成功访问亚信安全官网首页

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/5db9db68-c7d2-7e86-16fd-e667b047b81e.png)


### 修复建议
升级至8.4.0或其以后版本
### Reference
https://nvd.nist.gov/vuln/detail/CVE-2019-8451
https://jira.atlassian.com/browse/JRASERVER-69793
macでphpenvで7.3.9をインストールする（phpenvがインストールされている前提です。）

# はじめに
一部時間がかかった部分があったのでまとめ。

## 前提
* mac mojave
* anyenv, phpenv インストール済み
* php 7.2.x系 インストール済み


## 手順
### install可能なバージョンを確認する。

```
$ phpenv install list
  7.2.0
  7.2.10
  7.2.11
  7.2.12
  7.2.13
  7.2.14
  7.2.15
  7.2.16
  7.2.17
  7.2.18
  7.2.1
  7.2.2
  7.2.3
  7.2.4
  7.2.5
  7.2.6
  7.2.7
  7.2.8
  7.2.9
```

インストール可能なバージョンに7.3.x系がない。
→ ないので、phpenvのアップデートを行う

```
$ phpenv update
```

再度、バージョン確認すると増えているはず。

### 7.3.9をインストールする。

```
$ php install 7.3.9

-----------------
|  BUILD ERROR  |
-----------------
 
Here are the last 10 lines from the log:
 
-----------------------------------------
configure: WARNING: This bison version is not supported for regeneration of the Zend/PHP parsers (found: 2.3, min: 204, excluded: ).
configure: WARNING: You will need re2c 0.13.4 or later if you want to regenerate PHP parsers.
configure: error: Cannot find OpenSSL's <evp.h>
-----------------------------------------
```

bisonのバージョンが古い。。。

```
$ brew install bison
```

インストール後、最新のbisonを通るようにパスの変更が必要みたいなので、下記を実行しバージョンを変更する。

```
$ brew link bison --force
```

再度、インストールを実行する。

```
$ phpenv install 7.3.9
-----------------
|  BUILD ERROR  |
-----------------
 
Here are the last 10 lines from the log:
 
-----------------------------------------
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/signal.h:106:48: note: insert '_Nullable' if the pointer may be null
int     sigvec(int, struct sigvec *, struct sigvec *);
                                                   ^
                                                    _Nullable
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/signal.h:106:48: note: insert '_Nonnull' if the pointer should never be null
int     sigvec(int, struct sigvec *, struct sigvec *);
                                                   ^
                                                    _Nonnull
211 warnings generated.
PEAR package PHP_Archive not installed: generated phar will require PHP's phar extension be enabled.
-----------------------------------------
```

とよく分からないエラーが出現。。。
調べてみると、Xcodeが悪さをしているらしい。

下記のコマンドで、

```
sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
```

けど失敗。。。
なので、developerサイトからダウンロードする。
https://developer.apple.com/download/more/?name=Xcode
`Command Line Tools (macOS 10.14) for Xcode 10.3` をダウンロード

それで、再度インストールを実行

```
$ phpenv install 7.3.9
[Success]: Built 7.3.9 successfully.
```

やっと成功。
インストール、バージョンアップの度に、なんか色々なものインストールしてる気がする。
fastlane matchで正しいpassphraseを入力しているのにエラーが出る

# 問題
一度cloneしたことのあるrepositoryを消して、再cloneした後fastlaneでcertificatesをダウンロードしようとしていたら、

```
Enter the passphrase that should be used to encrypt/decrypt your certificates
```

というのでpassphraseを入力すると

```
security: SecKeychainAddInternetPassword <NULL>: The user name or passphrase you entered is not correct.
```

と表示される。



# 状況

- OSをMojaveにアップデートしたばかり
- XCode 10からXCode 11にアップデートしたばかり

## 解決策

1. MacのKeychain Accessを開く
2. 左のメニューから「ログイン」を右クリック
3. キーチェーン"ログイン"をロック
4. キーチェーン"ログイン"のロックを解除
5. `fastlane match`を走らせる
6. passphraseを入力

同じpassphraseのはずなのに今度は上手く行った。
OS Updateの後に起きる現象らしい。
エラー文が紛らわしかった。
AWSで特定のページだけ「The page you were looking for doesn't exist...」の表示が出る

## ページが存在しない？

AWSでやっとこさデプロイし、トップページを開くと

>The page you were looking for doesn't exist.
>You may have mistyped the address or the page may have moved.
>
>If you are the application owner check the logs for more information.

と、「ページが存在しませんよ。」というエラーが出てページが見られない問題に直面しました。

## テーブル内の存在しないレコードを参照しようとしていた

原因はコントローラで

```ruby:posts_controller.rb
def index
@fuga = Post.find(2)
end
```

と、postsテーブル内の（まだ存在しない）id 2のレコードを引っ張ってくるインスタンス変数を定義し、ビュー（トップページ）で

```ruby:posts/index.html.haml
= image_tag (@fuga.image.url)
```

と記述していたからでした。

postsテーブルはユーザーによって投稿されたコンテンツを保存するためのテーブルであり、デプロイ完了時点でのpostsテーブル内のデータは当然空っぽです。その状態でid 2のレコードを引っ張ってこようとすると冒頭のエラーページが出てくるようです。（ローカルでは当該レコードは存在していて、ビューの表示は正常にできていたので盲点でした...）

@fugaを参照していないビューであれば普通に表示できたので、

会員登録ページからユーザーの新規登録
↓
postsテーブルのid 2のレコードにデータが入るよう、投稿ページからコンテンツを2回投稿

で、ちゃんとトップページが表示されるようになりました。
【Rails】audiojs-railsの導入からオーディオファイル再生までの手順

# はじめに

HTML5にはオーディオファイルを埋め込む専用のタグが用意されています。

```html
<audio src="sample/sample.ogg" controls>
<p>音声を再生するには、audioタグをサポートしたブラウザが必要です。</p>
</audio>
```

このaudioタグをより便利にしたJavaScriptライブラリ「audio.js」を使えば、見た目のカスタマイズやプレイリストの追加が簡単に行えるようになります。
Railsアプリでは「audiojs-rails」というRuby gemsが提供されているので使います。
また、Railsにはaudioタグのヘルパーメソッドが用意されているのでこれも使います。

```html
<%= audio_tag 'sample.mp3' %>
```


# audiojs-railsの導入

Gemfileに以下を追加して`bundle install`を行います。
※rails serverを起動している場合は再起動してください。

```ruby
gem 'audiojs-rails'
```


# audiojsの読み込み

`app/assets/javascripts/application.js`に以下を追加します。

```javascript
//= require audiojs
```


# audiojsの初期化・再生プレイヤー設置

Viewに以下を追加します。

```html
<!-- 再生プレイヤー -->
<%= audio_tag 'sample.mp3' %>

<!-- audiojsの初期化 -->
<script>
  audiojs.events.ready(function() {
    var as = audiojs.createAll();
  });
</script>
```


# assetsパスの追加

上記で設置した再生プレイヤーで読み込んでいる「sample.mp3」は、`app/assets/audios/`に配置することにしましょう。
しかし、このままではアセットパイプラインで配信されないので、assetsパスを追加する必要があります。
`config/initializers/assets.rb`に以下を追加します。

```ruby
Rails.application.config.assets.paths << Rails.root.join("app", "assets", "audios")
```

以下のコマンドでassetsパスが追加されたかを確認します。

```
$ rails c
> Rails.application.config.assets.paths
=> ["Your Rails app path/app/assets/audios/", ...]
> exit
```

# 再生プレイヤーのカスタマイズ（おまけ）

audio.jsで使用しているクラスを上書きすることで、再生プレイヤーの見た目を変更することができます。

```css
/*　プレイヤー（再生バー）の高さ、幅、背景色の指定　*/
.audiojs { ... }
/*　再生・停止ボタンの高さ、幅、パディングの指定　*/
.audiojs .play-pause { ... }
/*　再生・停止ボタンなどの p 要素　*/
.audiojs p { ... }
/*　進行状態・ロードの状態を表示する部分　*/
.audiojs .scrubber { ... }
/*　進行状態を表示するバーの部分　*/
.audiojs .progress { ... }
/*　ロード状態を表示するバーの部分　*/
.audiojs .loaded { ... }
/*　再生時間の部分　*/
.audiojs .time { ... }
.audiojs .error-message { ... }
 /*　再生している曲の情報　*/
.track-details { ... }
.track-details:before { ... }
```


# 参考

- [audio.js](http://kolber.github.io/audiojs/)
- [audiojs-rails](https://github.com/subosito/audiojs-rails)
- [Railsでhtml5で追加されたaudioタグを使う](https://qiita.com/NishidaRyu416/items/c244aeeaacab1d9bb0c1)
- [Rails Asset Pipelineがうまくいかないときの問題の切り分けかた](https://qiita.com/metheglin/items/c5c756246b7afbd34ae2)
- [audio.js を使ってみる](http://www.webdesignleaves.com/wp/jquery/490/)


# 宣伝

[AUTOVICE](https://autovice.herokuapp.com/)

私のポートフォリオサイト（仮）です。
こちらでも技術情報を発信していますので、よろしければご覧ください😉
Carthageがどうやっても終わらない・・・

# Carthageがどうやっても終わらないようになってしまった

carhage実行するとファンがぶんぶん回ってこっから先に進まない。

```
carthage update --platform iOS
*** Cloning SwiftyJSON
*** Cloning TOCropViewController
*** Cloning Alamofire
*** Cloning ObjectMapper
*** Cloning IQKeyboardManager
*** Cloning PopupDialog
*** Cloning TableViewDragger
*** Cloning SVProgressHUD
*** Cloning AlamofireImage
*** Cloning DynamicBlurView
*** Cloning RxSwift
```

[sshの鍵問題](https://qiita.com/nakagawa1017/items/4a61fabdaf65de1c1c0a)も参考にしてみたが解決せず。

## Githubのissueは1年前から放置されてる？

Carthageのgithubを見ると同様のバグは今現在（2019/9/24）でもまだ解決されていない模様。約1年前のissueなんですが。うーん。
https://github.com/Carthage/Carthage/issues/2615

## Carthageのフォークでうまく行きました

上記issueの[コメント](https://github.com/Carthage/Carthage/issues/2615#issuecomment-521570252)にある、werner77さんのフォークだとうまく行きました。ありがたや！

```
brew uninstall --force carthage
brew tap nsoperations/formulas
brew install -s nsoperations/formulas/carthage
```

issueが解決するまでは当面はこちらで運用していこうと思う。
carthage updateが終わらない人はぜひ試してみてください！
プログラミングの"ベストプラクティス"は機能外の人のなすべきこと

# ベストプラクティスとは機能不足を人が補填するもの

　自分は、いろいろな言語やツールを使うとき、それらが標準で提供する機能について学習すると次に、ベストプラクティスを学ぶ。
　プログラミング言語なら文法やビルドの方法を覚えると、サードパーティライブラリを調べて、ベストプラクティスを最後に学ぶ。

　ベストプラクティスとは、言語の文法やビルドでは強制されないけど、問題を起こしにくい、処理を速くするための手法。
　そしてそれは、言語そのものが機能として持っていいない、人が行うもの。
　
　ツールもマニュアルを超えて、こうつかった方がいいよという自由裁量の部分。

# 言語やツールには限界がある

　言語やツールは、開発をするのにリソースの制約があったり、利用シーンが汎用的すぎて特定化できない側面もある。
　なので、ある局面では便利だけど、機能化されていない部分もある。
　それは人間側で補わざるを得ない。ベストプラクティスとは、そうした人がニーズに合わせて行う手法の集大成とも言える。

　言語やツールを使いこなすにはどうしても、こうしたベストプラクティスの習得が欠かせない。

　そもそも、言語やツールそれだけでは不足があるから。
UnuboでDiscordBotを動かす

# Unuboって 

https://unubo.com/

HerokuのようなPaaS 
最近こんな[記事](https://paiza.hatenablog.com/entry/2019/09/11/Node_js%2CPython%2CRubyなどのWebアプリを完全無料でホスティング可)もありました。
まだまだ知名度も低いみたいで今日(2019/09/24)現在、[公式twitter](https://twitter.com/UnuboHQ)のフォロワーも200人ちょい(Herokuは10万人ぐらい)

1GBのRAMと500MBのストレージがずっと無料で使える(HerokuのfreeはRAMが512MB)上に、24h毎のリセットも無し

## DiscordBotのデプロイ
- 1ntegrale9さんの[記事](https://qiita.com/1ntegrale9/items/aa4b373e8895273875a8)を参考にレポジトリを拝借して、アカウント作って、GitHubへのアクセスを許可して、ゴニョゴニョしたら完成 

- Herokuより断然UIが良くて分かりやすい！(ダークモードもあるし)(SPAにも対応していて私のようなスマホオンリープログラマにも親切) 

- ハマりポイントとしては、下のCommandsへのスクリプト起動に`python3 hoge.py`ってするとビルドは難なく通りますが、デプロイでエラーになります
 
<img width="414" alt="F78784F3-0F5A-49F4-B736-F228023F868A.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282918/3ff58103-3eae-3726-b15d-f1925b3e36db.png">

## その他の小細工
alpineで動いてるので、voiceオプション付きのdiscord.pyを動かすために適当なライブラリをapk addしましょう。buildが終わったら不要になった分はapk delで消して問題ありません
`ctypes.util.find_library`でopusをなぜか拾って貰えなかったので適当にモンキーパッチしましょう。

## 感想
Herokuの使い方が全然理解できないって人もなんかいるみたいですが、UnuboはProcfileもruntime.txtも要らないし、requirements.txtはあったら使ってくれるけど無くても良いみたいですし、シンプルで使いやすいですね。
Rubyのゲッター、セッター、selfについて

# はじめに
- この記事はゲッターとセッターの記述について書いています（ほぼ自分用の備忘録
- ついで、ゲッターとselfを利用したインスタンス変数の参照についても記載します

# サンプルコード

- クラス部分

```rb
class Test

  def initialize(name)
    @name = name
  end

#getNameは、ゲッターとして定義
  def getName
    return @name
  end

#changeNameは、セッターとして定義  
  def changeName=(name)
    @name = name
  end

#selfを使って、getNameを呼んでみる
  def show
    num = 1
    self.getName.each do |name|
      puts "#{num}個目の要素は#{name}"
      num += 1
    end
  end
end
```

- 実行結果の検証

```rb
#１つ目の検証
 test1 = Test.new("kazuki")
 puts test1.getName
 =>kazuki
#インスタンスにゲッターとして定義した「getName」を使うと、インスタンス変数の@nameが取り出せる

#2つ目の検証
 test1.changeName = ["apple", "orange", "peach"]
 puts test1.getName
 =>apple
   orange
   peach
*インスタンスにセッターとして定義した「changeName」を使うと、@nameに直接代入可能

#3つ目の検証
 test1.show
 =>1個目の要素はapple
   2個目の要素はorange
   3個目の要素はpeach
*self.getNameで指定してeach文を実行してみた
　結果、無事に出力
　ちなみに、この場合だとselfを使わずgetNameのみで、直接@nameを指定しても同じ結果だった
```
【vsftpd】FTPをSSL/TLSで暗号化する設定

# はじめに

## FTPのSSL/TLS方式
FTPでSSL/TLSを利用する方法には大きく2種類あり、vsftpdとしては、どちらとも利用可能なため、接続するFTPクライアントによって使い分けることが良いと思われる。
※ ftpをTLSで暗号化するプロトコルは下記２種類どちらとも**ftps**と呼ばれ、SSHでファイル転送を行う**sftp**とは異なる。

### explicit(明示的な)方式
平文のFTPのポート(TCP/21)で接続、平文でコネクションを張った後、FTPのAUTHメソッドでTLSへ移行する方法。いわゆるSTARTTLS方式。

httpで例えれば、平文のHTTPのポート(TCP/80)で接続し、GETやPOST等のメソッドを呼ぶ前にTLSへ移行するためのメソッドを呼び、暗号化通信を開始した後にGET等のリクエストを開始するようなイメージ。

vsftpdでのSSL/TLS通信のデフォルトで、RFCで正式に採用されている方式。

### implicit(暗黙的な)方式
平文のFTPのポート(TCP/21)とは別にTLS(ftps)用のポート(一般にTCP/990)を使用し、コネクションを張る時点からTLSで暗号化する方式。httpsで利用されているTLSに近い。

RFCとして正式な記載はないが、vsftpdではimplicitモードも利用することができる。

# vsftpdでSSL/TLSを利用する設定

## 環境
- CentOS 7.6
- vsftpd 3.0


## 用意するもの

### サーバ証明書

SSL/TLSを利用するため、httpsのWebサーバと同様にサーバ証明書が必要となる。
使用する証明書はhttpsのSSL/TLSで使用するサーバ証明書と同じもので、自己証明書で作成してもよいし、一般の認証局やLet's encrypt等で発行したサーバ証明書でもよい。

中間証明書が必要となる場合は、サーバ証明書と中間証明書を1つのファイルに連結した証明書ファイルを作成しておく必要がある。(WebサーバのApache 2.4やnginxで使用する方法と同様)

## 設定
vsftpdの設定ファイル`/etc/vsftpd/vsftpd.conf`へ設定を行っていく。
※ Ubuntu等のパッケージでは場所が異なり、`/etc/vsftpd.conf`となっている。

vsftpdの設定ファイルには初期で設定項目が存在していない場合もあるので、無い場合はファイルの末尾などに手動で追記する必要がある。

### 基本的な設定

```sh
# TLSを有効化
ssl_enable=YES

# 使用プロトコル (必要なプロトコルをYESに設定する)
ssl_sslv2=NO
ssl_sslv3=NO
ssl_tlsv1=NO
ssl_tlsv1_1=NO
ssl_tlsv1_2=YES

# 暗号化方式
ssl_ciphers=kEECDH+AESGCM+AES128:kEECDH+AESGCM:kEECDH+AES128:kEECDH+AES:!aNULL:!eNULL:!LOW:!EXP

# サーバ証明書、秘密鍵
rsa_cert_file=/etc/vsftpd/server.crt
rsa_private_key_file=/etc/vsftpd/server.key
```

各設定値の意味はそれぞれ下記の通り。

|設定項目名|設定値|意味|
|:--|:--|:--|
|ssl_enable|YES/NO|SSL/TLSによる接続を有効化する|
|ssl_sslv2|YES/NO|SSL 2.0 を利用可能とする|
|ssl_sslv3|YES/NO|SSL 3.0 を利用可能とする|
|ssl_tlsv1|YES/NO|TLS 1.0 を利用可能とする|
|ssl_tlsv1_1|YES/NO|TLS 1.1 を利用可能とする|
|ssl_tlsv1_2|YES/NO|TLS 1.2 を利用可能とする|
|ssl_ciphers|文字列|通信で利用可能とする暗号化スイート(OpenSSL方式で指定)|
|rsa_cert_file|文字列|サーバ証明書(+中間証明書)のファイル名|
|rsa_private_key_file|文字列|証明書の秘密鍵ファイル名|

`ssL_ciphers`でDHE方式の暗号化スイートを利用する場合は、[DH鍵交換パラメータ設定](#補足:DH鍵交換パラメータ設定)により任意の鍵長のDH鍵交換パラメータを利用することもできる。

### implicitモードを使用する場合
implicitモードでのftpsを利用する場合は、上記に加えて`implicit_ssl`を有効化し、`listen_port`に通信に使用するポート(TCP/990 など)を設定する。

```sh
# implicit モード有効化
implicit_ssl=YES
listen_port=990
```

## SSLログの有効化
`debug_ssl`を有効化することで、クライアントからの接続時にsyslogへSSL/TLSのプロトコルや暗号化方式などの情報を出力させることも可能。
※`syslog_enable`が有効となっていないとsyslogへのログ出力自体がされないので注意。

```sh
# ロギング設定
syslog_enable=YES
debug_ssl=YES
```

ログを有効化した場合、SSL/TLSでの接続時にsyslogへ下記のようなログが出力されるようになる。

```
vsftpd[1279]: DEBUG: Client "127.0.0.1", "SSL version: TLSv1/SSLv3, SSL cipher: ECDHE-RSA-AES256-GCM-SHA384, not reused, no cert"
```

## 稼働確認

SSL/TLS周りの接続確認はOpenSSLのコマンドで確認が可能。
OpenSSLの場合、implicitモードでの接続になるため、explicitモードで接続の場合は`-starttls`オプションを利用する必要がある。

```sh
# explicitモードの場合
openssl s_client -connect localhost:21 -starttls ftp

# implicitモードの場合
openssl s_client -connect localhost:990
```

## 補足:DH鍵交換パラメータ設定
SSL/TLSのCipherSuitesにDHE系の鍵交換を使用する場合は、
nginx等と同様に任意の長さのDHパラメータを生成して設定することも可能。

### DHパラメータファイル設定
vsftpdの設定ファイルには`dh_param_file`に生成したDHパラメータファイルを指定することで任意のパラメータを使用することができる。

```sh
# DH鍵交換パラメータ
dh_param_file=/etc/vsftpd/dhparam.pem
```
AWS Certified Solutions Architect - Associate(SAA)を合格した話

2019年9月22日に AWS Certified Solutions Architect - Associate(SAA)に合格したので、自分がやっことを書き留めたいと思います。
これから受験される方に少しでも役に立てれば幸いです。

# 対策本は１つあればOK

対策本だけでは試験問題をカバーできませんでした。しかし、AWSサービスの概要を調べる時に、すぐに調べられるように１冊あると便利です。

# 模擬試験をこなす

模擬試験は、無料で学習できる[WEB問題集](https://aws.koiwaclub.com/)と、Udemyの[AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（5回分325問）](https://www.udemy.com/share/101rfMB0oeeFxXRXw=/)をやりました。Udemyについては、キャンペーンを行なっている時に購入します。**更にお得に受講するために、Udemyはポイントサイトを経由して購入しましょう。**

Udemyの[AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（5回分325問）](https://www.udemy.com/share/101rfMB0oeeFxXRXw=/)は5回分の模擬試験を行えますので、こちらを購入すれば、AWSの模擬試験は受けなくても良いと思います。**Udemyのキャンペーン価格などにより、1回分のAWSの模擬試験2000円よりも、費用対効果は高いです。**

# 少し学習してから、Black beltのスライドを見る

SAAの学習を少ししてからBlack beltのスライドを見ることにより、覚えたことがより明確になりました。AWSのホワイトペーパーなどは資料が多すぎるので、要点を説明してくれるBlack beltは手っ取り早く学習できます。試験ではサービスの細かい点について問われることもありますので、スライドに記載されているメリット・デメリットなどについて押さえておくと良いです。

# 試験の24時間前までに合格する可能性がないと感じたら、諦める
本番の試験の24時間前までなら、無料で試験の変更、キャンセルが可能です。24時間前までに、Udemyの[AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（5回分325問）](https://www.udemy.com/share/101rfMB0oeeFxXRXw=/)のうち、１つも合格できない場合は試験を延期しましょう。

# 重点的に学習すべき分野

模擬試験などをこなしていると新サービスに関して学習しなければいけないと思うことがあります。しかし、SAAにおける試験の比重は、下記の通りであり**「高可用性」に関する問題が最も多く出題されます。**新しいサービスを詳細に学習するよりも、比重の高い分野について、重点的に学習しておいたほうが良いでしょう。

<img width="619" alt="スクリーンショット 2019-09-23 22.58.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/af93cd40-791b-11fd-c483-62525c74ee3a.png">

# 解答に迷ったら、消去法で解答を導く

問題でわからないキーワードが出た時は、消去法で解答を導きました。例えば、次のようなケースです。

Q.　Aについて述べているものはどれか？

| No|       選択肢 |
|-----------------|------------------|
| 1           |インスタンス作成時にBを選択することにより、ディスク性能を高速化することができる|  
| 2            |Cを使って、データ分析を行うサービスを提供する |        
| 3              |高可用性で、スケーラビリティのあるNoSQLデータベースを提供する|         
|4|D方式の暗号化を使用してデータを暗号化する|

選択肢1の「B」が初めて見るキーワードであり解答に迷ってしまう場合、選択肢2,3,4はAについての記述ではないことが分かれば解答から除外し、正解の可能性が高いであろう選択肢1を選択します。

# 落として良い問題を22問以内にする
本番試験では、ホワイトボードとペンが渡されますので、解答した問題を自信がある、自信がない、分からない、の３つに分けて番号をボードに記載していきました。最低合格スコアは100-1000の間で720、正答率は65%くらいと言われているので、**65問中、43問くらいは「自信がある」に該当しないと合格できません。落として良い問題は22問です。**問題を解きながら「自信がない」「分からない」を試験画面の「後で見直す」を使いチェックします。時間が限られているため、２週目で見直す問題は「後で見直す」に限定し、その中で正解が導き出せた問題は「後で見直す」チェックを外します。**最終的に「後で見直す」の問題が22問以内になるようにします。**
アクセス修飾子と命名規則（private/protectedは1単語、publicは2単語）：シンプルな処理とシンプルな名前

# privateやprotectedの処理は単語は１つ、publicなものは単語２つ

　命名において、長さをどうするかは悩みどころ。
　Goなどは、１文字変数名が多かったりする。変数の宣言で型がわかって、スコープが短ければ、それが何を表すかはわかるので、それでもいいところはある。けど、1文字変数はよほど明確でないと命名しにくい。

　Pythonのモジュール名をつける時、基本はアンダースコアは使わない。使うなら階層を作る。だから、１単語で命名する。

　翻って、Javaなどで冗長なものはやたらと単語をつなげる。その結果、いろいろな役割をクラスや関数が担ってしまう。
　Pythonのように単語を一つに絞ることで、各モジュール（パッケージ）の役割が絞られて、自ずと一つのクラスやソースがシンプルになっていく。

　原則、１単語でモジュール（パッケージ）名、クラス名、メソッド名をつくれば、ソースの内容がシンプルになっていく。

　だが、実際、処理の実行部分では、いろいろなメソッドを呼び出し、どうしても単語１つでは衝突が起こる。その場合を考えて、2単語でつくると衝突の可能性が半減する。それでも駄目な場合は、asをつかったエイリアスや、JavaならFQDN(Fully Qualified Domain Name)で、名前空有間をつける。

　経験的に、モジュールの役割を独立化していけばあまりFQDNを使う局面は少ない。できるだけパッケージ全体で一つの機能を作っていく。
　基本は、パッケージ内で完結するもの、すなわち、private/protectedのものは１単語で命名して、パッケージ外から使うpublicなものは２単語でつくると効率的だと思う。

　名前が衝突するのは、そもそも一つのクラスやメソッドの役割が混在している。それをばらして独立化することで、衝突の確率が下がっていく。

# 名前が冗長なものはソースも冗長になる

　仕事では、大手企業のJava案件を見ることが多いが、Javaは冗長な名前が多く、それと比例して、FatClassが多い。つまり、名は体を表すで、助長な名前のクラスやメソッドは、処理がやたら長い。

　逆に、PythonとかGoでコーディングすると、Lintに従っているコードは名前が短いので、それにあわせて処理を分割してシンプルになっている。

　プロジェクトのアーキテクトの方針もあるだろうが、基本はprivateやprotectedの処理は単語は１つ、publicは2つの単語で作ると名前だけでなく、処理もシンプルになるように思う。
AWS SAA試験記 (試験会場は事前によく調べておくこと)

## AWS Certified Solutions Architect - Associate


この度、2019/08にAWSのSAA試験に合格しましたので試験記録として記事を残すことにしました。
試験体験記はたくさんあればあるほど、今後試験を受験する方たちの不安を払拭できるかと思います。
少しでも誰かの参考になりますように。

### 筆者のAWS経歴

- 新卒でIT企業(Web系)に入社してから約5年半
- AWSを本格的に触ったのは2018/12頃
  - 試験合格が2019/08なので約8ヶ月の業務経験
  - それまではEC2,S3,RDSなどの基本サービスの理解はあったが、具体的にどう設計するかの知識は無い状態
- 業務経験でVPCの作成からサーバー(EC2)の立ち上げ、サービスリリースまでの一通りの流れを経験済み

### 勉強時間

約30時間です。

- 対策本 10時間
- 動画(Udemy) 10時間
- 模擬試験(対策本+Udemy) 10時間

### 対策本

いくつか立ち読みをして比較しましたが、以下を購入しました。
対策本の中では圧倒的にオススメです。
この本だけで試験範囲をほぼ網羅でき、内容も質が良いと思います。

> この１冊で合格！ AWS認定ソリューションアーキテクト - アソシエイト テキスト&問題集
https://www.kadokawa.co.jp/product/321811001165/

### 動画(Udemy)

> これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座（初心者向け21時間完全コース）
https://www.udemy.com/aws-associate/

タイトル通りこれだけでOKです。むしろ対策本より質が良いので、金銭面で節約したい方はこれだけ買いましょう。
期間限定で1000円代まで値引きされることがあるので、その期間が狙い目です。
AWSに慣れていれば倍速程度でも十分に知識を吸収できます。

### 模擬試験

Udemyの模擬試験(全3回分)が非常に優秀です。
各回を2回やりました。間違えた問題は理解するまで見直しましょう。

## 当日について

### キオスク端末は英語でリモートチャットする可能性あり

試験は試験会場で行ないます。事前に予約するのですが、予約前に会場について調べたほうがいいです。
私が受けた会場は海外の試験官とリモートチャットでやり取りを行ないました。
このとき、試験官とのやり取りが **英語である可能性** があります。
私は英語力がないので、英語でチャットが来た場合は日本語にしてもらうようにお願いするつもりでした。
（幸い、私が試験したときは日本語でのチャットでした。ただし英語を直訳したような日本語でした。）

以前、LPICやOracle Masterの試験を受けたことがあるのですが、[ピアソンVUE](https://www.pearsonvue.co.jp/) による申し込みで
試験当日も受付スタッフにより試験の受付、サポートを行なっていただきました。
今回は受付スタッフによるサポートはなく(席までの誘導のみ)、**キオスク端末** と呼ばれる席で自身で受付することになりました。

着席後は免許証をスキャンし、クレジットカードをディスプレイ上部に取り付けられたカメラに向けて見せるように指示されます。
（このときクレジットカードを「もっと近づけてください」「揺らさないでください」と指示がされたのですが、ディスプレイ上部にカメラがあるため腕が震えて無理難題でした、、。先方の確認が終わるまで５〜10分くらいかかりました。筋肉との戦いで試験前にヘロヘロに。）

### 試験会場の選定をしっかりと

試験の申し込みはPSIで行なったのですが、[ピアソンVUE](https://www.pearsonvue.co.jp/)でも行えるようですので
そちらの選択も検討するとよいかもしれません。
また、試験会場は横浜が一番近かったのですが受けたい日に空いてなかったので武蔵小杉にしました。
あとでよく調べてみると、会場によってキオスク端末とそうではない端末があります。
キオスクではないほうがサポートが厚い可能性がありますのでよく検討してください。
神奈川県民は横浜の会場が圧倒的にキレイでオススメらしいです（私は行ったことはありません）
今度受けるときは横浜にします、、。

![スクリーンショット 2019-09-23 23.52.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466431/838260fb-5fb9-bc64-f14c-b0742884cf7d.png)

こちらの銀座の試験会場のブログも参考になります。
https://ameblo.jp/mochizuki108desu/entry-12406491373.html

受験前に調べておいたほうがよかったなぁと反省。

以上
docker-composeでwordpressをサクッと作る

(今更ながら）さくっとdocker-composeでworpdressを作ったので忘備録。
ubuntu18.04で書いてるけど、CentOSでもcomposeの操作は全く同じ。

##dokcerとdocker-composeをインストール
dockerは公式の情報そのまんま入れます。
composeも最後に一緒に入れます。


・関連パッケージインストールとGPGキーの追加

```
sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
```

・フィンガープリント確認
9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
と表示されていることを確認する

```
sudo apt-key fingerprint 0EBFCD88
```

・リポジトリ追加

```
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
```

・dockerとdocker-composeのインストール

```
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
```
↑ここで一緒にdocker-composeも入れてOKだけど、ubuntu16.04などでは古いバージョンが入って
下記のymlファイルが上手く読み込めないので最新を取ってきます。
(2019/09/24時点での最新は1.24.1)

・docker-composeのインストール
インストールと言うより直接実行ファイルをダウンロードして実行権限をつけるだけ

```
curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```

---
#docker-compose.ymlを作る

下記の内容で~/workなど適当なディレクトリにdocker-compose.ymlという名前で保存する

```docker-compose.yml
version: '3.1'

services:

  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wordpress:/var/www/html

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql

volumes:
  wordpress:
  db:
```
・設定で気になるところを直す

例えば
 ・ ports: 待ち受けポート 8080じゃなくて80にしてもよい 
 ・ DB_USER / DB_PASSWORD / DB_NAME : DB接続情報。好きな値に変更してOK
変更した場合は下のMYSQL_DATABASE/MYSQL_USER/MYSQL_PASSWORD も同じ内容に変更する

#起動
root以外でも使いたい場合は下記コマンドで使用ユーザを指定してログインしなおす

```
sudo usermod -aG docker ユーザ名
```
※dokcerが使える=サーバを色々操作できる強力な権限を与える為、必要無いならこのコマンド入れずに下記コマンドの頭にsudoつける方法でもよい。

docker-compose.ymlがあるディレクトリに移動して

```
docker-compose up -d
```
これで起動完了。
サーバ落とすなどで起動を一旦停止する場合は

```
docker-compose stop
```

再度動かす場合は

```
docker-compose start
```

コンテナ自体を削除する場合は

```
docker-compose down
```
でOK

あとは http://自分のサーバIP(or ドメイン）:指定したポート
でアクセスできる。
wordpressのインストール画面が出てきたら完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266161/e33a5316-f515-3a14-59e5-dd30cb37147d.png)



dockerのrunコマンドでパラメータ指定するよりdocker-compose.ymlで設定するほうが見やすのでcomposeオススメ。
複数コンテナもまとめて書けるので管理がしやすい。

---
参考：
docker 公式ページ(インストール方法など)：https://docs.docker.com/install/linux/docker-ce/ubuntu/
Docker Hub - wordpress ： https://hub.docker.com/_/wordpress
グローバルip取得コマンド


忘れがちなのでメモ

Linux

```bash
$ curl ifconfig.io
```

Powershell

```powershell
(Invoke-WebRequest -Uri "inet-ip.info/ip").Content
```

最近グローバル ip 取得して処理するスクリプト書くことが多く、毎度忘れるのでメモ。
Kotlin+fuel-coroutinesを使ってHTTP通信

fuel-coroutinesを使った非同期HTTP通信がとても簡単だったのでメモ。

Fuel自体はKotlin全般で利用できますが、今回はAndroidアプリ開発を想定しています。

## Fuelとは
KotlinでHTTP通信できるライブラリです。[こちら](https://oldbigbuddha.dev/post/android-about-fluel/)にわかりやすく使い方がまとまっています。

[FuelのGitHubリポジトリ](https://github.com/kittinunf/fuel)を見るとわかると思うのですが、いろんなパッケージの集合体という形をとっています。今回利用するfuel-coroutinesはその中の一つです。

### なぜfuel-coroutinesなのか
Fuelの特徴として「同期でも非同期でも書ける」というものがありますが、fuelのみだと非同期まわりの融通があまり効きません。結局「自前のコルーチンに同期処理を書く」ということになります。

fuel-coroutinesはKotlinのコルーチンライブラリであるKotlinX Coroutinesを利用しているため、コルーチンが扱いやすいです。

また、KotlinX Coroutinesと同じ書き方(というか同じものですが)でコルーチン制御できるため、検索しやすいです。(Kotlinのコルーチンについては[こちら](https://qiita.com/kawmra/items/ee4acb7db61f70dec9a8)がわかりやすいです。)

AndroidはメインスレッドでWebリクエストが送れないので、素直にfuel-coroutinesを使ったほうが色々楽です。

## 依存関係を書く
Build.gradleに依存関係を書きます

```Build.gradle
dependencies {
    implementation "com.github.kittinunf.fuel:fuel:2.2.1"
    implementation "com.github.kittinunf.fuel:fuel-android:2.2.1"
    implementation "com.github.kittinunf.fuel:fuel-coroutines:2.2.1"
}
```
fuelは様々なパッケージの集合体ですが、今回使うのは`fuel` `fuel-android` `fuel-coroutines`です。3つともgradleに書きましょう。

## 使ってみる
まずは[サンプル](https://github.com/kittinunf/fuel/tree/master/fuel-coroutines)を少し変えたものを。

```sample.kt
val url = "https://hoge.con"
val tag = "hoge"
runBlocking {
    val (request, response, result) = url.httpGet().awaitStringResponseResult()

    result.fold(
        { data -> Log.d(tag, data)},
        { error -> Log.e(tag, "An error of type ${error.exception} happened: ${error.message}") }
    )
}
```
見ての通りWebリクエストに成功したときは`result.fold`の第一引数の関数が、失敗のときは第二引数の関数が実行されます。

リクエストパラメータを追加したいときは`httpGet`の引数に`listOf(key to value)`を受け渡しましょう。

### 画像をダウンロードする
```image_download.kt
// imageにrunBlockingの計算結果を代入
val image = runBlocking {
            val (_, _, result) = url.httpGet().awaitByteArrayResponseResult()

            // http通信に成功した場合Bitmap、失敗した場合nullがdataに入る
            val data = result.fold(
                {res-> res},
                {error->
                    Log.e(tag, "An error of type ${error.exception} happened: ${error.message}")
                    null
                }
            )
            //ここでダウンロードした画像をBitmap形式に変換する。
            BitmapFactory.decodeByteArray(data, 0, data!!.size)!!
        }
```
敢えてさっきとは色々違う書き方をしましたが、基本的な違いは`awaitStringResponseResult`が`awaitByteArrayResponseResult`に変わっただけです。

## 参考
- https://oldbigbuddha.dev/post/android-about-fluel/
- https://qiita.com/kawmra/items/ee4acb7db61f70dec9a8
- https://qiita.com/pljp/items/a1f3e8d1d13c88a94907
Azure Kubernetes Service (AKS) を使いこなす : 目次

Microsoft のマネージド Kubernetes である Azure Kubernetes Service (AKS) を使いこなすための情報をまとめます。基本的には [AKS 公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/aks/) の情報に対して、より詳細な情報を自分なりに付加しながらまとめる予定です。

本目次は色々記事を書いた後にまとめる予定です。

# AKS チュートリアルの深堀

このセクションでは公式ドキュメントで紹介されているチュートリアルについて、付加情報をつけながら深堀します。

[Kubernetes と AKS 概要](https://qiita.com/kenakamu/items/8f43163d1a42aca62fb7)
[アプリケーションの準備](https://qiita.com/kenakamu/items/50193c1b642cb3339b46)
[コンテナレジストリを作成する](https://qiita.com/kenakamu/items/bb876f17e4f6ecaf370b)
[AKS クラスターのデプロイ](https://qiita.com/kenakamu/items/fb8adae1c5ddb906e0f2)
[アプリケーションの実行](https://qiita.com/kenakamu/items/cac80a548b0b43a270fa)
[アプリケーションのスケーリング](https://qiita.com/kenakamu/items/af537527d4d899a8f80e)
[アプリケーションの更新](https://qiita.com/kenakamu/items/f6b2de045b76cc05b809)

# SQL Server 2017 を AKS で使う 

このセクションでは [AKS に SQL Server コンテナーを配置する](https://docs.microsoft.com/ja-jp/sql/linux/tutorial-sql-server-containers-kubernetes?view=sql-server-2017) に付加情報をつけながら深堀します。

[ストレージの準備](https://qiita.com/kenakamu/items/8d584e6da3e93929b1d9)
[SQL のインストールと障害復旧の検証](https://qiita.com/kenakamu/items/a05843d8e5efd13eb009)

# SQL Server 2019 ビッグデータクラスター を AKS で使う 

このセクションでは SQL Server 2019 ビッグデータクラスターを AKS にインストールする方法や管理などを見ていきます。SQL Server 2019 自体の機能は別のシリーズを書くかもしれません。

[azdata 既定の構成でインストール](https://qiita.com/kenakamu/items/fd7834f07e391b90337a)
[サンプルデータを試す](https://qiita.com/kenakamu/items/9d113deb1dcec2c5a058)
[azdata を使ったカスタムインストール](https://qiita.com/kenakamu/items/56d30f66ddf90414e752)
[azdata を使った高可用性インストール](https://qiita.com/kenakamu/items/805373a964b4fe74d659)
[クラスターの管理方法](https://qiita.com/kenakamu/items/3e8bc0ddcbc91c4e77ff)
[HDFS の階層化](https://qiita.com/kenakamu/items/eee6280ba7303842deec)
[アプリケーションの展開](https://qiita.com/kenakamu/items/3dacf60e5764c586d6af)
[データ仮想化で Azure SQL をクエリする](https://qiita.com/kenakamu/items/7a4d7fd5505b58ad48b9)
[Spark ジョブでデータを取り込む](https://qiita.com/kenakamu/items/e122c5782d9a4a4bf35b)

# AKS で asp.net core アプリケーション

このセクションでは Microsoft SQL Server 2017 バックエンドの asp.net core Web アプリを AKS にデプロイしていきます。

[事前準備](https://qiita.com/kenakamu/items/20194ace476d873b2949)
[ローカルで開発する](https://qiita.com/kenakamu/items/f61ed635a77b673e8164)
[アプリをデプロイ](https://qiita.com/kenakamu/items/c1ff282992bfc778000d)
[イングレスとアプリ複数ポッド構成](https://qiita.com/kenakamu/items/19b5eb067c9d40e47b0b)
[複数ノードプールの構成](https://qiita.com/kenakamu/items/aee6748b6d15b8aab34f)
[Azure CNI ネットワーク と Application Gateway](https://qiita.com/kenakamu/items/f4c0fabea8044a6b28cb)
[Application Gateway と Application Gateway Ingress Controller](https://qiita.com/kenakamu/items/6997c894e6cce58f2ea2)
[ラベル、セレクターと名前空間](https://qiita.com/kenakamu/items/7003b6013779f1a5bdb6)
[自動スケール概要とポッドの水平スケール](https://qiita.com/kenakamu/items/29acb5c79c6700eed814)
[自動スケール - クラスターのスケール](https://qiita.com/kenakamu/items/a4fe3769605795c23c24)
[自動スケール - Azure Container Instance との統合](https://qiita.com/kenakamu/items/6f3ed4be598d1c2ea8c2)
PHPで処理時間を測定する（microtime）

## microtime()
`microtime()` という関数があり、これでマイクロ秒まで取得できる。
[PHP マニュアル](https://www.php.net/manual/ja/function.microtime.php)

```php
<?php
// 引数を渡さないと、以下のように現時刻が取得できる。
// 0.26283300 1569114629 
microtime();

// 引数に true を渡すと float で現時刻が取得できる。
// 1569115527.2943 
microtime(true);
```

## 処理時間を測定する
`microtime()` でマイクロ秒の現時刻が取得できるので、後は測定したい処理の前後を比較すれば良い。

### 例
```php
<?php

class ClassName
{
	
	public function execute()
	{
		// 処理前の時刻を取得
		$start = microtime(true);

		// 測定したい処理
		$this->FunctionName();

		// 処理後の時刻を取得
		$end = microtime(true);

		// 差分を表示
		echo($end - $start);
	}

	public function FunctionName()
	{
		# code...
	}
}
```