OmniAICreator/Qiita-1.07M huggingface dataset:
【Laravel】ビューコンポーザって何？

#ビューコンポーザとは
ビューをレンダリングする際に自動的に実行される処理を用意するための部品のこと。
ServiceProviderクラスのbootメソッドだけ覚えとけば、とりあえずニューコンポーザは使用できる。
#サービスプロバイダ
サービスプロバイダはServiceProviderクラスを継承して作成される。ビューコンポーザを利用するならサービスプロバイダは重要。
##サービスプロバイダの基本形

```
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\ServiceProvider;

class プロバイダクラス extends ServiceProvider
{
   public function boot()
   {
    //コンポーザの設定(ブートストラップ処理)
   }
}
```
#サービスプロバイダ作成方法
ターミナルで作成できます。

```
php artisan make:provider プロバイダー名
```
app/providersフォルダのなかにスクリプトが指定したプロバイダー名で自動生成される。
##ビューコンポーザの用意
ビューコンポーザの用意方法は2つある。
1.無名クラスでコンポーザ処理
2.bootで設定

###1.無名クラスでコンポーザ処理
先ほど作成したサービスプロバイダのboot内に無名クラスでビューコンポーザの処理を組み込む。
ビューコンポーザーを設定するView::composerメソッド

```
View::composer(ビュー名 , 関数orクラス)
```
- 第一引数にビューコンポーザを割り当てるビューを指定
- 第二引数に実行する処理

次にサービスプロバイダをアプリケーションに登録する
config/app.phpにあるprovidersという名前の配列が、アプリケーションに登録されているプロバイダ一覧
この配列にプロバイダクラスを追記すればアプリケーション使用時にそれを使用することができる。

```
App\Providers\HelloService\プロバイダー名::Class
```
###2.bootで設定
コンポーザを作成しHttpフォルダ内に配置。
先ほど作成したサービスプロバイダのboot内のView::composerメソッドの第二引数にコンポーザを設定する。

※ 備忘録目的の記事です
3分でできる！WebVRの自作サンプルをOculus Quest上で動かす

# 完成図

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/62c8216c-cc47-d337-3180-1d87b1892eec.gif)

部屋が狭いので分かりづらいかもしれませんが、VR空間を6DoF（顔の向きだけでなく、体の移動や高さもトラッキング）で動き回れているのが分かるかと思います。

# 必要なもの

* PC（OS問わず）
  * Webブラウザ
* Googleアカウント
* VR機器
  * スマホでもOK。できればOculus Questのように、6DoF対応機器推奨

以上！

# 3分ステップ

* PC
  * [A-Frameのサンプル](https://aframe.io/docs/0.9.0/introduction/)をコピーしてsample1.html（ファイル名適当でOK）として保存
  * Googleドライブにsample1.htmlをアップロード
  * アップロードしたsample1.htmlを右クリックし、アプリで開く→HTML Viewerを選択
  * HTML Viewerを使ったことがない場合、アクセス許可が出るので許可を選択
    * これでGoogleドライブにアップしたhtmlファイルが、テキストファイルではなくhtmlとして再生できます
* Oculus Quest
  * ブラウザを開く
  * Googleに移動し、Googleアカウントにログインする
    * 左メニューを開き、「パソコン版」を選ぶ
    * ![pc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/8df37f66-80de-6a7f-4f3e-485b05c66220.jpeg)
      * ※Oculus Questのブラウザだと右クリックができず「HTML Viewer」で開くことができないため
    * sample1.htmlをダブルクリックで開き、アプリでHTML Viewerを選択
    * ![viewer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/1ed48236-e9fe-89dd-160e-02a0e4221e11.jpeg)
    * ![browser.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/07739664-4666-0eca-e1ab-ffac67fd03ab.jpeg)
    * 右下のVRマークをクリック
    * ![vr.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/895cbf67-85ae-aaeb-aed4-b7d5acd056ed.jpeg)
    * 終わり！

# それ以外の方法

herokuやAWS S3にアップする方法でも当然ながらOKです。
今回の方法だとOculusの開発者登録やミラーリング設定等をせず、自分でコーディングしたWebVRアプリを完全無料で使うことができます。

# 終わりに

数年前にthree.jsでWebVRアプリを作ったのですが、その際はVR用のライブラリを別途読み込んだ上でシーン設定・カメラ設定・コントロール設定等を手動でゴリゴリ書いていく必要があり、かなり時間がかかるのでハードルが高く感じました。

A-Frameはthree.jsを元に作られたWebVRフレームワークですが、シーンを宣言するだけでVR対応・非対応機器問わずコントロールできる機能が付いてくるので非常に便利です。

A-Frameに関してあまり詳しくないので、いろいろ触って知見が溜まったらまたQiitaに投稿するかもしれません。
三項演算子とは？？？

最近暑さが増してきましたね、、、
個人的にはアロハシャツが着れる夏は大好きです:relaxed:

(そんなことは置いといて...)

アプリケーション開発を進めていく中で、三項演算子という便利なツールを見つけたので、分かりやすくまとめていきます！

## 三項演算子とは？？？
一言でまとめると、条件分岐を行うための演算子です！

(もっと分かりやすく説明して...):joy:

図を見ながら説明すると理解しやすいと思います！

```ruby:sample.rb
条件式 ? 真の時の値 : 偽の時の値
```
条件式を判定して、trueだった時は「真の時の値」を、falseだった時は「偽の時の値」を返します。
条件や返り値がシンプルな場合、***if分よりも簡潔に記述できる!***

(なるほど！分かりやすい！）:relieved:

## if文と三項演算子を比較してみましょう！

if文を使った場合

```ruby:sample.rb
var = "文字列"

if var.class == String
  "varはStringです"
else
  "varはStringではありません"
end
```

三項演算子を使った場合

```ruby:sample.rb
var = "文字列"

var.class == String? "varはStringです" : "varはStringではありません"
```

どちらが簡潔で見やすいかは見比べれば一目瞭然ですよね！！！

これが三項演算子のパワーでございます...

積極的に使っていきたいですね:relaxed:

##おまけ（便利な使い方）
値を代入し、三項演算子のメソッドを返り値にしたい場合！

```ruby:sample.rb
numbers = [5,6,7,8,9,10]
sum = 0

numbers.each do |n|
  sum_value = n.even? ? n * 10 : n
  sum += sum_value
end

puts sum #=> 261
```

***条件式の後に？を付け足すのがポイントです！***

---

以上となります！

ご質問等ございましたら、コメントお気軽にしてください！

ご静聴ありがとうございました！
Leetcode #152: Maximum Product Subarray

```swift
func maxProduct(_ nums: [Int]) -> Int {
    if nums.isEmpty {
        return 0
    }
    var answer = nums[0]
    var currentMax = nums[0]
    var currentMin = nums[0]
    for i in stride(from: 1, to: nums.count, by: 1) {
        let tmp = currentMax
        currentMax = max(nums[i], currentMin * nums[i], tmp * nums[i])
        currentMin = min(nums[i], currentMin * nums[i], tmp * nums[i])
        answer = max(answer, currentMax)
    }
    return answer
}
```
Qiita　Markdown記法メモ

### 折りたたみ

~~~
<details></details>で囲む

タイトルを入れる時は、
<details><summary>詳細</summary>
</details>

スペースやコードがある場合は、
<details><summary>詳細</summary><div>　
</div></details>

~~~


<details><summary>タイトル</summary><div>
内容

~~~
print("test")
~~~

</div></details>



### 画像埋め込みリンク
![alt](https://youngjump.jp/kingdom/character/images/shin/09.jpg)

<img width="200" alt="ファイル名" src="https://youngjump.jp/kingdom/character/images/shin/09.jpg">

~~~
![ファイル名](URL)
![alt](https://youngjump.jp/kingdom/character/images/shin/09.jpg)
　　↓
<img width="400" alt="ファイル名" src="URL">
<img width="400" src="https://youngjump.jp/kingdom/character/images/shin/09.jpg">
~~~

##  見出し H2　アンダーラインがつく
### 見出しh3　
### 　見出しh3
  全角スペースを前に入れると目次の階層が進む
### #　見出し h4
### ##見出し h5
### ###  見出し h6

**太字**

~~~
##  見出し H2　アンダーラインがつく
### 見出しh3　
### 　見出しh3全角スペースを前に入れると目次の階層が進む
### #　見出し h4
### ##見出し h5
### ###  見出し h6
**太字**
~~~

### ページ内リンク
[テーブル](# テーブル)

~~~
[テーブル](# テーブル)
~~~


### リンク
[title](https://youngjump.jp/kingdom/character/index3.html)

~~~
[title](https://youngjump.jp/kingdom/character/index3.html)
~~~

### コード
上下に空行を挿入しないと正しく表示されないことがある
'~~~'の後にPythonを入れるとシンタックスハイライトされる
又、その後に':'を入れると以降がヘッダとなる

```Python:qiita.rb
puts 'code with syntax'
```

### 改行する方法
3つの方法がある

・文末に半角空白スペースを2つつける
・1行空白の行を入れる
・brタグを使う

### ノート

~~~
:::note
インフォメーション
:::

:::note warn
警告
○○に注意
:::

:::note alert
強い警告
○○するな
:::
~~~

:::note
インフォメーション
:::

:::note warn
警告
○○に注意
:::

:::note alert
強い警告
○○するな
:::

### テーブル
手前で改行しないと表示されない

|  TH  |  TH  |
| ---- | ---- |
|  TD  |  セル内で<br>改行  |

~~~
|  TH  |  TH  |
| ---- | ---- |
|  TD  |  セル内で<br>改行  |
~~~

上にくっつけると２列になってしまう

| TH 左寄せ | TH 中央寄せ | TH 右寄せ |
| :--- | :---: | ---: |
| TD | TD | TD |
| TD | TD | TD |

~~~
| TH 左寄せ | TH 中央寄せ | TH 右寄せ |
| :--- | :---: | ---: |
| TD | TD | TD |
| TD | TD | TD |
~~~

### イコール(＝)を揃える
begin{align}とend{align}と&を用いることによってブロック内で改行前後の位置を揃える

### 改行(\\)
数式の行末に\\(バックスラッシュ２つ)をつけることによって改行をすることができます。

```math
\begin{align}
f(x) &= x^2+3x+2 \\
&= (x+1)(x+2)
\end{align}
```

ドルマークだと改行されない
$\begin{align}
f(x) &= x^2+3x+2 \\
&= (x+1)(x+2)
\end{align}$

~~~
```math
\begin{align}
f(x) &= x^2+3x+2 \\
&= (x+1)(x+2)
\end{align}
```

~~~
ドルマークだと改行されない
$\begin{align}
f(x) &= x^2+3x+2 \\
&= (x+1)(x+2)
\end{align}$
~~~

### 行列
これもドルマークだとできない

```math
\begin{matrix}
a & b \\
c & d 
\end{matrix}
```

~~~
```math
\begin{matrix}
a & b \\
c & d 
\end{matrix}
```

### 場合分け

```math
f(x) = \left\{
\begin{array}{ll}
1 & (x \geq 0) \\
0 & (x \lt 0)
\end{array}
\right.
```

~~~
```math
f(x) = \left\{
\begin{array}{ll}
1 & (x \geq 0) \\
0 & (x \lt 0)
\end{array}
\right.
```

# Tex
$w_n$
$w_{n+1}$

~~~
$w_n$
$w_{n+1}$
~~~

**分数**
$\frac{分子}{分母}$

~~~
$\frac{分子}{分母}$
~~~

**べき数**
$a^2$

~~~
$a^2$
~~~

**総和**
$f(x) = \sum_{i=0}^n x_i$
$C_v=\sum_{j=0}^{N-v}a_ja_{j+v}$

~~~~
$f(x) = \sum_{i=0}^n x_i$
$C_v=\sum_{j=0}^{N-v}a_ja_{j+v}$
~~~

***平方根
\sqrt{a^2+b^2} \\
\sqrt[3]{a}

```math
\sqrt{a^2+b^2} \\
\sqrt[3]{a}
```

### 引用
> text
>> text

~~~
> text
>> text
~~~
storeを実装してJavaScriptへの理解を深める

es6 の module import/export の仕様を再確認したかったのが出発点。

## 準備

手軽なのでcreate-react-appを利用する。

```
create-react-app mystore
cd mystore
```

## store実装

```js:store.js
export let globalState = { count: 1 }
export const increment = () => {
  globalState = { count: globalState.count + 1 }
}
```

変数とその変更方法を提供してるだけ
これを複数箇所からimportして利用する。

```jsx:App.js
import React from 'react';
import './App.css';
import { globalState, increment } from './store'
import Counter from './Counter'

class App extends React.Component {
  state = { count: globalState.count }

  increment = () => {
    increment()
    this.setState({ count: globalState.count })
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <h2>Parent counter</h2>
          <p>{globalState.count}</p>
          <button onClick={this.increment}>increment</button>
          <Counter />
        </header>
      </div>
    );
  }
}

export default App;
```

component の stateを利用してないのはご愛嬌。
（値を直接見たかったので。再描画用のsetState）。

```jsx:Counter.js

import React from 'react'
import { globalState, increment } from './store'

class Counter extends React.Component {
  state = { count: globalState.count }

  increment = () => {
    increment()
    this.setState({ count: globalState.count })
  }

  render() {
    return (
      <div>
        <h2>Child counter</h2>
        <p>{globalState.count}</p>
        <button onClick={this.increment}>increment</button>
      </div>
    )
  }
}

export default Counter
```

ポイント：

- export されている値が変更されたら、その変更はimport先のファイルをまたいで維持される（この例でも、リアルタイムに描画されるかはともかく、親と子で最終的には値が同期されている）
  - 調べると ES6 export では binding がエクスポートされるとか書かれてるがよくわからない
  - その具体例と思われる[シングルインスタンスのエクスポート](https://k94n.com/es6-modules-single-instance-pattern)と関連づけた方が理解しやすい
- リアルタイムに再描画されない場合がある
  - この例では子での変更は親に反映されない
  - 親の方のボタンをクリックしたら同期される

## subscription 機能を実装
値をリアルタイムに同期させたいなら起点となるイベントが必要だということだろう。
subscription用のコールバックを格納する配列を作って変更のたびに全て実行する。

```js:store.js
const subscriptions = []
export const addSubscription = (callback) => {
  subscriptions.push(callback)
}
export let globalState = { count: 1 }

export const subscribedIncrement = () => {
  globalState = { count: globalState.count + 1 }
  subscriptions.forEach(callback => callback(globalState))
  // console.log(subscriptions)
}
```

コンポーネントのコンストラクタあたりでコールバック追加すれば良い。

```js:App.js
// ...

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { count: globalState.count }
    addSubscription(this.onGlobalStateChange)
  }

  increment = () => {
    subscribedIncrement()
    this.setState({ count: globalState.count })
  }

  onGlobalStateChange = (globalState) => {
    this.setState(globalState)
  }
// ...
```

解除方法は知らぬ。

## 結論

- Reduxで良い
- ただし、React Reduxは何が嬉しいのだったか頭を整理中
    - propsに渡すパターン？
    - コンテナコンポーネント作るならいらん？
SSHポートフォワードを使ってリモートから自宅LANのWindows PCにRDP接続してみた

#背景
実家に帰ったときとか，出張に行ったときに気軽に自宅の環境にアクセスして遊んだり，データ持ってきたりしたいと思ったから

#sshポートフォワードとは
sshトンネルを利用して，安全に遠隔地の端末にアクセスできる機能．一種のVPN的な機能だと思っている．

#概要
自宅LANに安全にアクセスできるようにするため，公開鍵認証を採用した．もちろん，rootログインは禁止した．
sshサーバには最近購入したRaspberry Piを使用した．Raspberry Piはインターネット公開に利用されることが多いからか，<b>ハニーポットでデフォルトと思われるユーザ名とパスワードが観測されているので，公開サーバとして利用する際は要注意！</b>

概要図は以下の通り：
![ssh_port_forward.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438083/e37bc64b-7638-0050-4c77-facafe5d3b96.png)

実行したコマンドは以下の通り：
[]は，各々の環境に合った値を入れてください．私の環境の値は伏せておきます．

```sh:実行コマンド
ssh -g -i [秘密鍵のファイルパス] -L 3389:[RDP接続先PCのIPアドレス]:3389 -p [sshサーバのポート番号] [ユーザ名]@[sshサーバのIPアドレス]
```

#コマンドの説明
- g: ローカル以外からsshトンネルにアクセスする場合に付加するオプション
- i: 公開鍵認証を使用する際に指定する自分の秘密鍵のファイルパス
- L: ssh接続元のポート番号．ここで指定したポートに手元のPCからアクセスすることで，本来接続したい端末のポート番号にアクセスできる．今回は，ポート番号を変更するのが面倒くさかったため3389を指定．
- p: sshサーバのポート番号を指定するオプション．デフォルトの22番なら本オプションは不要

#結果
<b>ちゃんとRDPでアクセスできました．ものすごく重いうえに，すぐに切断されましたけど...</b>

#まとめ
- 本などで読んで理論的にできることは知っていたが，実際にできると感動した
- <b>ものすごく動作が重い！実家に帰ったときに利用しようかと思っていたが，全然そのレベルに達していない！無駄に中継しているせい？それとも，家の回線が脆いせいなのか...</b>

ということで，ほかにいい方法や改善点が思いつく方はぜひコメント等で教えてください．

#参考文献
- まんがでわかるLinux シス管系女子 3巻 -ネットワーク & セキュリティ入門-    
https://www.amazon.co.jp/%E3%81%BE%E3%82%93%E3%81%8C%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8BLinux-%E3%82%B7%E3%82%B9%E7%AE%A1%E7%B3%BB%E5%A5%B3%E5%AD%902-%E6%97%A5%E7%B5%8CBP%E3%83%91%E3%82%BD%E3%82%B3%E3%83%B3%E3%83%99%E3%82%B9%E3%83%88%E3%83%A0%E3%83%83%E3%82%AF-Piro-%E7%B5%90%E5%9F%8E%E6%B4%8B%E5%BF%97/dp/4822236072/ref=sr_1_fkmr0_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E3%81%BE%E3%82%93%E3%81%8C%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8BLinux+%E3%82%B7%E3%82%B9%E7%AE%A1%E7%B3%BB%E5%A5%B3%E5%AD%90+3%E5%B7%BB&qid=1560769477&s=gateway&sr=8-1-fkmr0
AWSで踏み台を経由したサーバ構築

## やりたいこと

* どのサーバへも踏み台サーバを経由すればすぐにログインできるようにしたい
* 上記にプラスして踏み台サーバを活用してアプリケーションサーバへのログイン経路を限定したい
* SSHの際も一々IPアドレスで指定しないでパスなしの名前でシュッとログインしたい

↓こんな感じのイメージ
![BastionServer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181414/f94247d8-f9e4-923c-d497-f5b36eab2889.png)

#### インスタンスの作成

細かい手順は省くが、アベイラビリティゾーンは同一に合わせた適当なインスタンスと、
セキュリティグループでSSHを許可したものを作成する。

**踏み台サーバ側**

* AWSの管理ページ上で専用のセキュリティグループを作成する
* どのサーバからでもSSHできる設定にしておく
* SSH-Keyを作成して秘密鍵を保持(パスフレーズは設定しない)

```
ssh-keygen
```

* ~/.ssh/configに下記の様にアプリケーション側のサーバ情報を書き加えておく

```
Host <サーバのホスト名>
  HostName <IPアドレス>
  User <ユーザ名>
  Port <SSHポート>
  IdentityFile <秘密鍵の場所>
```

**アプリケーションサーバ側**

* "~/.ssh/authorized_keys"に作成した公開鍵を登録

* AWSの管理ページ上でセキュリティ設定でグループID指定で踏み台サーバのセキュリティグループからしかアクセス出来ないようにする


これだけで踏み台サーバからしかアクセス出来ないかつ

```
ssh <.ssh/configで指定したサーバのホスト名>
```

上記のコマンドでシュッとアプリケーションサーバ側にログインできる
resourcesとresourceの違いについて！

アプリケーション開発でルーティングを設定していく上で、両者の違いについて気になったので、備忘録含めてまとめていきたいと思います:relaxed:

## resourcesメソッド
Railsの基本となるコントローラの7つのアクション名に対してのルーティングを自動で生成するメソッド！

（なんと便利な！）:astonished:

postsテーブルにとっての１ツイート、usersテーブルにとっての１ユーザー、つまり、テーブルに保存されるレコード１つの情報のことを***リソース***と呼びます！

以下の例のような記述では、postsというリソースに対して、基本となる7つのアクションをリクエストするルーティングが設定されます。

```config/routes.rb
Rails.application.routes.draw do
 resources :posts
end
```
ターミナルにて***rake routes***コマンドを実行すると以下のように7つのルーティングが設定されているのが確認できます。

```terminal
Prefix Verb         URI Pattern            Controller#Action
    posts GET    /posts(.:format)          posts#index
          POST   /posts(.:format)          posts#create
 new_post GET    /posts/new(.:format)      posts#new
edit_post GET    /posts/:id/edit(.:format) posts#edit
     post GET    /posts/:id(.:format)      posts#show
          PATCH  /posts/:id(.:format)      posts#update
          PUT    /posts/:id(.:format)      posts#update
          DELETE /posts/:id(.:format)      posts#destroy
```

## resourceメソッド

resourceメソッドは、コントローラの７つのアクションに対して、***indexとid付きのパスが生成されません！***
show, editアクションの実行に、idが必要ない場合に有効です！

以下の例のような記述では、postsというリソースに対して、indexとidつきパスを外した残りのアクションをリクエストするルーティングが設定されます。

```config/routes.rb
Rails.application.routes.draw do
 resource :posts
end
```

ターミナルにて***rake routes***コマンドを実行すると以下のように7つのルーティングが設定されているのが確認できます。

```terminal
Prefix Verb         URI Pattern         Controller#Action
new_posts  GET    /posts/new(.:format)  posts#new
edit_posts GET    /posts/edit(.:format) posts#edit
     posts GET    /posts(.:format)      posts#show
           PATCH  /posts(.:format)      posts#update
           PUT    /posts(.:format)      posts#update
           DELETE /posts(.:format)      posts#destroy
           POST   /posts(.:format)      posts#create

```

---

以上となります！

場面場面によってしっかり使い分ければ、とても便利ですね！

何か気になる点等、ございましたらお気軽にコメントお願いします！

ご静聴ありがとうございました:relaxed:
raspberrypi pigpio


ICカードで施錠 https://qiita.com/carpenders/items/94d29098127faaffe1fc

```
pi@raspberrypi:~ $ sudo apt-get -y install pigpio

pi@raspberrypi:~ $ sudo pip install -U pigpio

pi@raspberrypi:~ $ sudo pigpiod
```
ラジコンサーボ　配線　茶色GND、橙色+V、黄色SIGNAL
![pi-pinout-diagram-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436333/92170f84-ccdf-2566-8e4a-46ddec44f0f4.png)

### 参考
本家
http://abyz.me.uk/rpi/pigpio/
基本的な使い方
https://karaage.hatenadiary.jp/entry/2017/02/10/073000
pigpio全般の解説
https://decafish.blog.so-net.ne.jp/2016-10-15
pi.set_PWM_dutycycle()
https://tomosoft.jp/design/?p=8768
PHP：配列から重複した値を削除するために array_unique を検証する

## はじめに
* 配列から重複した値を削除するために array_unique を検証する

## 背景
* PHPのマニュアルでは、多次元配列での使用を想定したものではないとの記載があったため、特定の多次元配列を用意してテストコードで問題ないかどうかの検証を行う
    * https://www.php.net/manual/ja/function.array-unique.php
    * array_uniqueの第２引数sort_flagsに、SORT_REGULARを指定すれば上手くいくであろうという記述もあったためテストコードにより確認する

## プロダクションコード

~~~php
    /**
     * 重複する配列データを削除する
     *
     * @param array $itemList
     * @return array
     */
    public function arrayUnique($arrayList)
    {
        return array_unique($arrayList, SORT_REGULAR);
    }
~~~

## テストコード

~~~php
    /**
     * 重複する配列データが削除されるどうか確認する
     *
     * @test
     */
    public function 重複する配列データが削除されるどうか確認する()
    {
        $テスト配列重複除外結果 = $this->CI->arrayUnique($this->テスト配列重複データ());

        // 結果配列が空でない
        $this->assertNotEmpty($テスト配列重複除外結果);
        // 結果配列の数が2である
        $this->assertCount(2, $テスト配列重複除外結果);
        // 結果配列の順番が一致しているかどうか確認
        $this->assertEquals(22222, $テスト配列重複除外結果[0]['id']);
        $this->assertEquals(11111, $テスト配列重複除外結果[1]['id']);
        // 結果配列の型も含めて等しいかどうか
        $this->assertSame($this->期待値配列データ(), $テスト配列重複除外結果);
    }

    /**
     * @return array
     */
    public function テスト配列重複データ()
    {
        return array(
            array(
                'id' => 22222,
                'name' => 'テスト名前２',
                'data' => 'テストデータ２',
                'start_date' => '2019-06-17 12:00:00',
                'end_date' => '0000-00-00 00:00:00'
            ),
            array(
                'id' => 11111,
                'name' => 'テスト名前１',
                'data' => 'テストデータ１',
                'start_date' => '2019-06-11 12:00:00',
                'end_date' => '0000-00-00 00:00:00'
            ),
            array(
                'id' => 22222,
                'name' => 'テスト名前２',
                'data' => 'テストデータ２',
                'start_date' => '2019-06-17 12:00:00',
                'end_date' => '0000-00-00 00:00:00'
            ),
            array(
                'id' => 11111,
                'name' => 'テスト名前１',
                'data' => 'テストデータ１',
                'start_date' => '2019-06-11 12:00:00',
                'end_date' => '0000-00-00 00:00:00'
            )
        );
    }

    /**
     * @return array
     */
    public function 期待値配列データ()
    {
        return array(
            array(
                'id' => 22222,
                'name' => 'テスト名前２',
                'data' => 'テストデータ２',
                'start_date' => '2019-06-17 12:00:00',
                'end_date' => '0000-00-00 00:00:00'
            ),
            array(
                'id' => 11111,
                'name' => 'テスト名前１',
                'data' => 'テストデータ１',
                'start_date' => '2019-06-11 12:00:00',
                'end_date' => '0000-00-00 00:00:00'
            )
        );
    }
~~~

## UT結果
<img width="367" alt="スクリーンショット 2019-06-17 20.13.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87218/fd8be3a7-560f-54a8-3b31-01d40d7e81b1.png">

上記パターンの配列では問題なく重複データが削除されました。
別の多次元配列パターンなど一度テストコードにより検証を行うと安心かと思います。
Pythonの配列に関する便利なメソッドをご紹介！

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンをしている田島一毅です。プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

2週間前くらいにPythonの学習を始め、最近``__init__``というメソッドに出会いました。

学習を進めているうちに、

「Pythonって、多くの場面で使われている言語だし、さぞかし便利なメソッドが用意されているんだろうなあ」

という気持ちになったので、調べてみました。

今回は、配列に関するメソッドに絞って紹介します。

他のメソッドも順次公開するので、そちらも是非ご覧ください。


#Pythonの便利なメソッド

##appendメソッド

appendメソッドは、配列の末尾に要素を追加するメソッドで、例えば、

```
list = [1,4,6]
list.append(2,9)
print(list)
```

のようにappendメソッドを使うと、

```
[1,4,6,2,9]
```

のように簡単に要素を追加できるのが便利です。

##insertメソッド

appendメソッドが配列の末尾に要素を追加するのに対して、insertメソッドは、要素を、自分の選んだ位置に追加できるメソッドです。

書き方は、以下のように、第1引数には追加したい位置のインデックスを指定し、第2引数には
追加したい値を指定します。



```
list = [1,3,5,7,8]
list.insert(2,9)
print(list)
```
この場合は、第1引数が2、第2引数が9なので、

```
[1,3,9,5,7,8]
```

といったように要素が追加されます。

##popメソッド

popメソッドでは、第1引数でインデックスを指定することで、指定のインデックスの要素を削除することができます。

例えば、

```
list = [1,3,5,7,9]
list.pop(2)
print(list)
```

とすると、第1引数は2であるため、インデックスが2の要素5が削除され、

```
[1,3,7,9]
```

といった出力結果となります。

##removeメソッド

popメソッドが指定のインデックスの要素を削除するのに対し、removeメソッドは指定の値を削除するメソッドです。

例えば、

```
list = [2,4,2,5,2,6,8,10]
list.remove(2)
print(2)
```

とすると、値2が指定されたので、

```
[4,5,6,8,10]
```

といった出力結果になります。

##extendメソッド

extendメソッドでは、配列同士を結合することができます。

例えば、

```
list1 = [2,4,6]
list2 = [1,3,5]
list1.extend(list2)
print(list1)
```

といったようにすると、list1にlist2が追加されて、

```
[2,4,6,1,3,5]
```

という出力結果となります。

##indexメソッド

indexメソッドでは、指定した値が配列に含まれているか調べることができます。

指定した値が配列に含まれている場合は、その値の最初のインデックスが結果として返されます。

指定した値が配列に含まれていない場合は、エラーが表示されます。

例えば、

```
list = [2,4,6,7]
print(list.index(2))
```
とすると、2が含まれているため、そのインデックスの0が表示され、

```
0
```

といった出力結果となりますが、

```
list = [2,4,6,7]
print(list.index(5))
```

とすると、配列には5は含まれないので、

```
ValueError: 5 is not in list
```

という出力結果となります。


##countメソッド

countメソッドでは、指定した値がいくつ配列に含まれているか調べることができます。

例えば、

```
list = [2,4,5,7,5,4,8,2,2,4,2]
print(list.count(2))
```

とすると、値2は配列に4つ含まれているので、

```
4
```

という出力結果となります。

##reverseメソッド

reverseメソッドでは、配列の要素の順番を並び替えることができます。

```
list = [2,4,5,7,8]
print(list.reverse())
```

とすると、

```
[8,7,5,4,2]
```

という出力結果となります。

#まとめ

今回は、Pythonの配列に関する便利なメソッドを紹介しました。

その他のメソッドも今後紹介していくので、そちらも是非ご覧ください。
【ターミナル】簡単にファイル作成と、書き込みを同時にする方法

# hello.txtに、helloと書き込みたい場合

このコマンドひとつで出来ます。

```terminal:terminal
$ echo hello > hello.txt
```

改行したい場合はこのようにすればokです。

```terminal:terminal
$ echo -e hello\\nhow are you?\\ni am doing fine > hello.txt
```

以上
俺でもわかるElasticsearch(5.0) sprit brainからのザオラル

俺です。
Elasticsearch(ES5.0)でsprit brainな状況に遭遇したので遺書を残します。
ES古いとか言わず。

人生もsprit brainです。


# ESクラスタが突然の死

- node1が高負荷になり9200portへの接続ができなくなってしまったのでEC2をstop/startした
- node2がmasterになるも高負荷のため9200portへ接続受け付けない状態になった
- node1復帰後にnode2へ接続しようとするが接続できない
- node2のElasticSearchをkill -9して停止した

ESクラスタのノードが全て停止してしまった

```
[YYYY-MM-DDTHH24:MI:SS][INFO ][o.e.n.Node               ] [node1] started
[YYYY-MM-DDTHH24:MI:SS][DEBUG][o.e.a.a.c.s.TransportClusterStateAction] [node1] no known master node, scheduling a retry
[YYYY-MM-DDTHH24:MI:SS][INFO ][o.e.d.z.ZenDiscovery     ] [node1] failed to send join request to master [{node2}{XXXXXXXXXXXXXX}{YYYYYYYYYYYY}{XX.XX.XX.XX}{XX.XX.XX.XX:9300}]
```

- node1復帰後に接続エラーを繰り返している状態のときのクラスタ(`master_not_discoverd_exception`)


```
$ curl localhost:9200/_cat/nodes
{"error":{"root_cause":[{"type":"master_not_discovered_exception","reason":null}],"type":"master_not_discovered_exception","reason":null},"status":503}
```

# ESクラスタノードの起動と絶望

- node1を最初に起動する
- node1がmasterになる
- node2を起動するとすでにmasterへjoinされているノードとして認識されてしまう絶望

```
[YYYY-MM-DDTHH24:MI:SS][INFO ][o.e.d.z.ZenDiscovery     ] [node2] failed to send join request to master [{node1}[internal:discovery/zen/join]]; nested: IllegalArgumentException[can't add node {node2}, found existing node {node2} with the same id but is a different node instance]; ]
[YYYY-MM-DDTHH24:MI:SS][WARN ][o.e.g.MetaStateService   ] [node2] [_global]: failed to write global state
```

- clusterの状態
- node1(masterノード)だけ起動している
- node2は接続されているけども正しい状態を保持していない


```
$ curl localhost:9200/_cat/nodes
node1  XX YY M XXX XXX XXXX      mdi * node1
node2  **ココにナニも状態が描かれない** mdi - node2
```

# masterへ接続できなくなったノードのnode.lockファイルを消す

- node.lock が `/var/lib/elasticsearch/nodes/<node_number>/node.lock` につくられている
- masterへ接続できないnodeで該当ファイルをrmする
- データディレクトリやindexディレクトリ・ファイルは削除しなくてOK


```
$ ps -ef|grep elastic
<ESプロセスが止まっていること. monitなどでディスカバリしてる場合は止める>
$ rm -f /var/lib/elasticsearch/nodes/0/node.lock
$ sudo service elasticsearch start
$ curl localhost:9200/_cat/nodes
以下のようにclusterのmaster/memberが見えていればOK
node1  XX YY M XXX XXX XXXX      mdi * node1
node2  XX YY M XXX XXX XXXX      mdi - node2
```
 
おわり
Rails コールバックのbefore_createについて

以下のような、Railsのコールバックを用いた処理の流れについて解説する。
(処理の内容は、ユーザーが投稿を行ったら、textカラムに保存されるデータの最後に「！」を自動で追加するというもの。)


#1.Railsのコールバックとは何か？
オブジェクトが生成(create)、更新(update)、破壊(delete)される時や、バリデーションを実行する時の前後に共通の処理を追加する仕組みをいう。これは**モデル層**で指定でき、処理を共通化することによって、モデルの一貫性を保て、またコード量を減らすことができるメリットがある。

以下のコードでは、Railsのコールバックのbefore_createを用いる。これは、オブジェクトがDBに新規保存(create)される直前で実行されるものである。

Rails コールバックのについては、以下の記事を参照。
https://morizyun.github.io/ruby/active-record-callback.html


#2.処理の流れについて
tweet.rb (ツイーツ モデル)

```ruby
class Tweet < ApplicationRecord

  before_create :change_tweet

   def change_tweet
     self.text = text + "！"
   end

 end
```
処理に流れとしては、
before_createが作動して、それに紐づいたchange_tweetメソッドが呼び出される。
そして、change_tweetメソッドの中に定義してあるself.textの処理がなされる。ここでは、self.textの中には、text + "！"という処理が代入されている。textとは、Tweetクラスのインスタンスである。つまり、ユーザーが投稿した個別・具体的なツイート内容のことを意味している。さらに、text の最後に"！"を加える処理が加えて行われる。


＜参考記事＞
・https://morizyun.github.io/ruby/active-record-callback.html
・http://beck23.hatenablog.com/entry/2014/10/02/020200
・https://tech.kitchhike.com/entry/2018/06/30/232400
Chandra衛星のデータを描画する

# 概要
X線衛星チャンドラの画像を描画したいと思います。使うツールはPython, astropy, numpy, matplotlibです。

# 使用するデータ
[チャンドラ衛星のデータ配布ページ](http://chandra.harvard.edu/photo/openFITS/multiwavelength_data.html)の"Kepler's Supernova Remnant"のデータを使用します。High Energy, Low Energyの両方と、スピッツァーのInfra-Redのデータを用います。

# スクリプト
```python
#!/usr/bin/env python

from astropy.io import fits
from matplotlib import pyplot as plt
import numpy as np


# load from the data files
header = fits.getheader('kepler_xray_he.fits')
high = fits.getdata('kepler_xray_he.fits')
low = fits.getdata('kepler_xray_le.fits')
ir = fits.getdata('kepler_ir.fits')
# merge data
data = np.dstack([ir, low, high])
# stack the data
plt.imshow(data, origin='lower', interpolation='nearest')
plt.show()
plt.clf()
```

# 結果図
結果は以下のようになります。綺麗な3色合成図が出来上がります。

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335400/7f57dd12-ce96-2388-d2ba-f0dd1ee2a500.png)

#スクリプト詳細
## fits.getdata

```python
high = fits.getdata('kepler_xray_he.fits')
low = fits.getdata('kepler_xray_le.fits')
ir = fits.getdata('kepler_ir.fits')
```

の行で、上からそれぞれHigh Energy(4-6keV), Low Energy(0.3-1.4keV), Infra-Redのデータを取得しています。

## np.dstack
```python
data = np.dstack([ir, low, high])
```
で、1pixelに3色のデータ、というようにデータをひとまとめにしています。irをRed, lowをGreen, highをBlueに対応づけてデータセットを作成しています。dstackの挙動についての詳細は[こちらのページ](https://docs.scipy.org/doc/numpy/reference/generated/numpy.dstack.html)をご覧ください。
試しに

```python
data = np.dstack([low, high, ir])
```
としてみましょう。すると結果は以下のように色合いが変化します。

![Figure_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335400/deb5e435-12a7-c4cf-e807-1d6822ddbc55.png)

## plt.imshow
```python
plt.imshow(data, origin='lower', interpolation='nearest')
```
この行で、先ほどひとまとめにしたデータを描画しています。`origin='lower'`で左下を原点にしています。`interpolation='nearest'`でピクセルの補間方法を決定しています。詳しくは[こちらのページ](https://matplotlib.org/3.1.0/gallery/images_contours_and_fields/interpolation_methods.html)をご覧ください。

## 注意点
ちなみにですが

```python
data = np.dstack([low, high])
```
として純粋にチャンドラのデータのみを描画しようとしても`plt.imshow`でエラーとなります。これはimage dataがRGBの3色でなければならないからです。試しに

```python
data = np.dstack([ir, low, high, high])
```
とするとこれはRGBAを指定していることになり、結果は以下のようになります。

![Figure_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335400/241590c5-a2f4-4464-1851-63276c084b41.png)

## 

# 結言
他にもまだまだ方法はありそうです。皆さんもRGBの綺麗な画像作成にぜひチャレンジしてみてください。
CentOSでtarしたらThis does not look like a tar archiveとなったときの対応方法

- 環境:CentOS Linux release 7.6.1810 (Core)

# 事象 : 解凍しようとして`tar`したら怒られた
```bash
$ tar -xvf hoge.zip
tar: This does not look like a tar archive
tar: Skipping to next header
tar: Exiting with failure status due to previous errors
```

# 原因 : ZIPファイルだから
解凍したいからといってなんでも`tar`すればいいわけではない
[一度はちゃんと確認しておきたいデータ圧縮形式 - Qiita](https://qiita.com/1coin178/items/caacb46d630c4c98ce0f)

## 対応方法 : `unzip`を使う

```bash
$ unzip hoge.zip
Archive:  a.zip
  inflating: nikki/20190601.md
  inflating: nikki/20190602.md
```
Dockerコンテナの内部IPアドレスを確認する方法

- 環境
    - Dockerホスト:
        - CentOS Linux release 7.6.1810 (Core)
        - Docker version 18.09.6, build 481bc77156
    - Dockerコンテナ
        - CentOS Linux release 7.6.1810 (Core)

# 1.ホスト側でコンテナIDを確認する
```bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
{コンテナID}        1a83763d4bd9        "/usr/sbin/init"    2 days ago          Up About an hour    0.0.0.0:8082->8080/tcp   {コンテナ名}
```

# 2.実行中のコンテナに入る
```bash
$ docker exec -it {コンテナID} /bin/bash
```

# 3.コンテナ内でIPアドレスを確認する
```bash
$ hostname -i
123.45.0.3
```

# 参考
- [Dockerでコンテナの内部IPを調べる - Qiita](https://qiita.com/miyatahirotaka/items/a44e2ae0bac53a4a5feb)
powershellでクリップボードを使って単純作業を楽にしてみた

#経緯
- windowsPCで単純作業を行う中で楽がしたいと思った。
- 入力した値を元に自動で文章を作成して、それをクリップボードに入れたかった。
- クリップボードに入れる文章は一度の入力に対して2回行う必要があったのでpauseコマンドで止めてみた。

##実際使った使い方
(1) コマンドプロンプトにURLを入力する
(2) 文字列がクリップボードに入るので、ブラウザ上の入力フォームにカーソルを合わせてペースト
(3) 再度コマンドプロンプトをアクティブウィンドウにして、Enterキーを押して文章をクリップボードに入れる
(4) ブラウザ上の入力フォーム２にカーソルを合わせてペースト
(5) 繰り返し...の単純作業

##用途
- 任意の文字を元に文章を作って文字列をクリップボードに入ることで便利になる作業


#作成したファイル

バッチファイル

```test.bat
Powershell -NoProfile -ExecutionPolicy Unrestricted .\test.ps1
```

pawershellファイル

```test.ps1
$outputencoding=[console]::outputencoding
for(){

    $input1 = Read-Host "URLを入力してください"
    $input = $input1.replace("`n","")

    $Name1 = "[URL] "
    $Name2 = " は私のマイページに飛びます。"
    $Message1 = "閲覧者方々 お世話になっております。

※本メッセージは自動で送信しています。

概要： [URL] "  

    $Message2 = " は私のマイページに飛びます。

--------下記は管理の情報になります-------- 

作成者のqiitaIDはこちら「su-pleiades」"


    echo ■Name■■■■■■■■■■■
    $Copyname = "$Name1 $input $Name2"
    echo $Copyname 
    $Copyname | clip
    pause

    echo ■Message■■■■■■■■■
    $CopyMessage = "$Message1 $input $Message2"
    echo $CopyMessage
    $CopyMessage | clip
    echo ■■■■■■■■■■■■■■

}
```



#コマンド結果

```

C:\Users\user\Desktop>Powershell -NoProfile -ExecutionPolicy Unrestricted .\test.ps1
URLを入力してください: https://qiita.com/su-pleiades
■Name■■■■■■■■■■■
[URL]  https://qiita.com/su-pleiades  は私のマイページに飛びます。
続行するには、Enter キーを押してください...:
■Message■■■■■■■■■
閲覧者方々 お世話になっております。

※本メッセージは自動で送信しています。

概要： [URL]  https://qiita.com/su-pleiades  は私のマイページに飛びます。

--------下記は管理の情報になります--------

作成者のqiitaIDはこちら「su-pleiades」
■■■■■■■■■■■■■■
URLを入力してください:

```

##1度目でクリップボードに入る文字列
[URL]  https://qiita.com/su-pleiades  は私のマイページに飛びます。

##2度目でクリップボードに入る文字列
閲覧者方々 お世話になっております。

※本メッセージは自動で送信しています。

概要： [URL]  https://qiita.com/su-pleiades  は私のマイページに飛びます。

--------下記は管理の情報になります--------

作成者のqiitaIDはこちら「su-pleiades」


#最後に
powershellで何かを作成することは今回で3度目になる若輩者です。
思いついたときに時間かけずにさっと作れるようになりたいですが、そうなるにはまだまだ時間がかかりそうです。

このコマンドがどなたかの役に立ちましたら幸いです。
powershellについて勉強するのに最適な本やサイトがありましたら、教えていただけると嬉しいです。
以上ありがとうございました。
誰でもできるGit導入方法

# 誰でもできるGit導入方法



今回はエンジニア以外の人もgitが手軽に使えるという、SourcetreeというGitクライアントソフトの導入方法を紹介したいと思います。


### 導入手順

1. [Sourcetree](http://qiita.com/)にアクセス
2. [windows向けダウンロード] or [Mac向けも利用可能]を選択
3. インストールし終えたら、[Bitbucket]を選択し、ログイン作業を終了させる（googleアカウントで可）
4. GitとMercurialを選ぶことができるので、Gitだけを選択
5. helpほげほげはチェック入れて次へ
6. SSHキーを読み込みますかは「いいえ」を選択

これで終了です。YouTubeに詳しく解説している方がいらっしゃるので、そちらも参考に

https://www.youtube.com/watch?v=_PyuylNk64o&list=LLqQTu93zeIPRrQC9OHxwFyw&index=3&t=0s
Rubyのシンボルについて

#1.シンボルとは何か？
シンボルとは、任意のシンボル名の前にコロン（:）を置くことでSymbol 型と認識されるものである。
Symbol 型と認識させることで、Ruby の方では、文字列と同じ認識をさせることができる。通常、文字列を認識させるためには、ダブルクォーテーション（”）で囲むことが必要である。このような型をString 型という。
つまり、シンボルは、ダブルクォーテーション（”）を使わずして、文字列としての認識をさせることができる。


入力事項

```ruby

str = "名前"
sym = :name

p str.class
p sym.class
```

実行結果

```
String
Symbol
```


シンボルがよく使われる場面としては、ハッシュが挙げられる。

```ruby
boy = {name: "Kendrick Lamar", age: 3, origin: "Miami"}
```

#2.ジンボルを使うことのメリット

1.メモリ消費が少ない
シンボルは一度生成されると同じ領域をずっと使うことになるため、メモリを節約することができる。また、文字列は使用するたびに違う領域を使用するため、毎回メモリ領域が必要になる。

2.可読性が上がる
ハッシュを記載するときに、ハッシュロケットを使用するよりも、シンボルを使用した方がコードが短くなり、読み易くなる。

```ruby
baby = {"name" => "Rick Ross", "age" => 1, "origin" => "Compton"}
```

```ruby
dog = {name: "pochi", kind: "shibaken" } 
```

3.処理が高速になる
メモリの消費と同様、シンボルは一度生成されると同じ領域をずっと使うことになるため、処理が高速になる。

　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　以上

＜参考記事＞
・https://qiita.com/Kta-M/items/53a13ef60e14fcb41193
・http://snagimo.com/what-is-symbol-on-ruby
・https://www.sejuku.net/blog/13094#i
CloudFrontで手動キャッシュ無効化の怖さ

# 何があったか
久々CloudFront設定をしたら３年前のエピソードを思い出した。
リクエスト増加でCloudFrontを導入したが、コストがかかっても更新時にすぐ確認したいとの要望。[Invalidation]でキャッシュの無効化はできるが・・・

コンテンツが更新されたら動く。そうLambdaの登場。以下が自分資料より分かりやすかったのでそのままリンク。
[静的コンテンツを更新したときに即時反映されるようにCloudFrontのInvalidationを走らせるLambda関数](http://bit.ly/2Xl1Ml1)

ある日偶然、テストアカウントの請求ダッシュボードを見ると、60万円を超えている。月変わって10日しか経てないのに。（偶然見なかったらその月どうなっただろう・・・）

#### リミッターとか警告はデフォルト装置で必要ではないか
Invalidationはプレミアム的な料金に気をつけよ。CF導入は新プロジェクトの新しい試みだったし、故意ではないので注意だけで終わりとなったけど、65万はそれでよかったとは思えない。検索すると似たようなAWS魔と出会ってしまった苦労人がいた。
AWSさん、小銭稼ぎ（AWSにとっては）はやめましょう。上司に叱られAWSが嫌になったエンジニアって意外といると思いますよ。

CloudWatchかなにかで料金監視すること

# 前に進むしかない
キャッシュはどうしても導入したい。無効化は必要。

テスターに下記で納得していただいた。
URLの後ろに処理に影響のないパラメータをつける！
CFが新しいページと認識するのでキャッシュークリアの効果がある。
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html#invalidation-specifying-objects-paths

```php
.../sample.php?1906171634
```

# メモ
登録フォームなどキャッシュがジャマになるページはBehaviorsでキャッシュスルー設定
Visual Studio Code でインデント幅の初期設定（Mac）

初期設定のスペース幅だと、コードが長くなった際に端が途切れてしまうので
インデント幅の初期値を2に変更。

１．`command + ,`で設定画面を開く。
<img width="611" alt="スクリーンショット 2019-06-17 19.13.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314346/77cf22ed-61cf-2f8a-92c2-4a9138607227.png">

２．右上の`{}`をクリックすると、JSONファイルが開きます。
<img width="708" alt="スクリーンショット 2019-06-17 19.14.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314346/38d0b03a-dfd1-d6c8-53b6-e8aacac16fec.png">

３．下記のコードを追記

```settings.json
"editor.tabSize": 2
```

最終的に下記のようなセッティング画面になればOK。
<img width="713" alt="スクリーンショット 2019-06-17 19.18.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314346/b934fd79-9f67-1674-727d-34a30d997708.png">

最後に`command + s`で保存を忘れずに。。
わかりやすいコードを書くための方法[まとめ2]

学習用の投稿です。



分かりやすいコードに仕上げるためには、制御文を減らすことが重要であるとされています。

Because 条件分岐やループが多いと、処理を追うのが大変。

鉄則　＝　if文,for文は極力使わないようにする。


今回if文を削減する方法を紹介します・・・

◎1.メソッドを使う。
e.g 10を最大値として、10より大きい値を受け付けたくないとき
×

```Java
if ( x > 10){
	x = 10;
}
```

〇

```Java
x = min(x,10);
```

◎2.早めにリターンする。

-ネストが深くなるのを予防。
-ガード節を使うとも言う。
>ガード節について　参考
https://qiita.com/kouyan/items/7b8b456b626447a1e24e

◎3.配列を使う
×

```Java
int id_to_num(int id)
{
	if(id == 0) return 10;
	if(id == 1) return 15;
	if(id == 2) return 30;
	if(id == 3) return 50;
	return 0
}
 ```

○

 ```Java
	int id_to_num(int id)
	{
		final int table[] = {10,15,30,50};
		assert 0 <=id && id <= 3 ;
		return table[id];
	}
```

◎4.データ構造を使う
配列と似ていますが、対応表を作っておくことで、ifの使用を防ぐことができる場合がある。
こちらの記事が参考になります。
http://atomiyama.com/linux/page/ketteihyou-if-sakugen-01/

```Java
if(myHand == opponentHand) {return draw}
if(myHand == Rock && opponentHand == Scissors) return victory; 
if(myScissors == Rock && opponentHand == Paper) return victory;
//略
return...;
````


```Java
result [3][3]=
//グー,チョキ.パー
{Draw,Lose,Win },//グー
{Win,Draw,lose },//チョキ
{Lose,Win,Draw },//パー
return result[myHand][oppnentHand]
```

決定表をつくることで、ノーif文で結果を返すことができます。

まとめ
if文が多いコードは可読性を下げる。
if文の多様を防ぐには
メソッド・Return・配列を活用する。
StreamControllerのsink.add,add,addStreamの違い

# StreamControllerとは


> 
・制御するストリームを持つコントローラ。
・このコントローラは、そのストリーム上でデータ、エラー、および終了イベントを送信することを可能にします。このクラスは、他の人が待機できる単純なストリームを作成したり、そのストリームにイベントをプッシュしたりするために使用できます。
 ・ストリームが一時停止されているかどうか、そしてそれがサブスクライバを持っているかどうか、そしてこれらのどちらかが変わったときにコールバックを受けるかどうかをチェックすることが可能です。

要するに、
非同期処理を行うものである。


## addがたくさんある。
StreamControllerのapiにはaddがたくさんある。

* StreamController.sink.add
* StreamController.add
* StreamController.addStream


それぞれの違いを説明する
## StreamController.add
addメソッドの引数に値を入れると、StreamControllerに持たすことができる。

## StreamController.addStream
Stream型の値を入れることができる。

## StreamController.sink.add
` StreamController<T>.sink => StreamSink<T>` 
StreamController.addと同じことをやっているのだが、StreamSinkは入力のみを受け付けるメソッドしかもたない。
よって、初期化されたStreamControllerクラスは、データが入っていたとしても、StreamSink型になるとstreamを受け取ることができないので、誤った値の購読を防ぐことができる。
KibanaでUnix timestampを使う方法

# 概要

Kibana(Elasticsearch)なログ基盤にFirehose経由で脳直にUnix timestampを投げ込んだら、見事に `Date` 型として認識してくれなかったのでメモ。 `number` になっちゃうんだよなぁ…

Autoindexが良い感じに処理してくれるようにテンプレートを書く感じ。


# 下準備

すでに存在しているindexは消しておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133666/b9e91305-c5ff-7502-9243-338db353a600.png)


# テンプレート設定

`type` と `index` が分かれば設定できる。

## indexについて

特に気にする必要はなくて、 `hoge-*` とか `hoge-error-*` とか `hoge-error-log-*` とかで良さそう。

## typeについて

typeが把握できていない場合は `Kinesis` の設定画面を見れば良さそう。

「 `Amazon Kinesis` -> `Data Firehose` -> 該当するストリーム名 」で辿り着くページの `Amazon Elasticsearch Service destination` を見ればわかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133666/72237653-187b-c9c4-7d6f-47cf35b065fc.png)


## 以上を踏まえた設定値

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133666/2ad3ed1f-b41a-bc53-4ae2-3ba2cc633d8a.png)



```
PUT _template/hoge_template
{
  "template": "hoge-error-log-*",
  "mappings": {
    "log": {
      "properties":{
        "timestamp": {
          "type": "date",
          "format": "epoch_second"
        }
      }
    }
  }
}
```

# データを投げ込む

適当に。例えばこんなデータ。

```

{
    "host": "ip.ap-northeast-1.compute.internal",
    "message": "test",
    "level": "err",
    "timestamp": 1560762549
}
```

# 動作確認(Create index patternをしてみる)

わーい！ちゃんと `date` として認識しているぞー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133666/3d1eeaa8-8ce1-cde8-b149-73a0a0d52582.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133666/68c3bbf5-cd83-c312-382e-76e02d951ca2.png)



# 補足

浮動小数点なデータ( `date +%s.%3N` コマンドで取れるようなミリ秒付きの値)でも動作はするが、内部処理系で整数型に丸められているみたい。

なので、解析にミリ秒が必要なときは、ちゃんとミリ秒単位なunix epoch(13桁)を投げ込むようにして、 `format` に `epoch_millis` を指定すると良さそう。

利用できる `format` 情報については下記を参照。

[format | Elasticsearch Reference [7.1] | Elastic](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html)


ちなみに `epoch_millis||basic_ordinal_date_time_no_millis` みたいな指定もできるらしい。試してないけど。



# 参考文献

[SORACOM Funnel の `timestamp` を Elasticsearch で自動mappingする方法 - Qiita](https://qiita.com/ma2shita/items/85954a361d373ca01172)
[Elasticsearchの自動マッピングの一部を上書きする方法 - Qiita](https://qiita.com/ma2shita/items/f534d8fafbd285570efd)
fastai/course-v3をdocker環境でやってみる

# 概要
機械学習の学習用にfastaiが公開しているチュートリアルをやってみました。ローカルで実行する際細々ハマったのでメモ

# クローン
なにはともあれgit clone

```
$ git clone https://github.com/fastai/course-v3
```

# Dockerfile docker-compose.ymlを追加
Dockerfile

```Dockerfile
FROM jupyter/base-notebook                                                                                                                                                                                          
USER root
RUN apt update
RUN apt install -y build-essential
USER $NB_UID
RUN pip install fastai
```

docker-compose.yml

```yml
version: '3'
services:
  jupyter:
    build: .
    volumes:
      - ./:/home/jovyan
    shm_size: 4G # これ重要。デフォルト64MBらしくメモリが足りなくて計算中に落ちる。
    ports:
      - 8888:8888
```

# 起動

```bash
$ docker-compose build
$ docker-compose up
Creating network "course-v3_default" with the default driver
Creating course-v3_jupyter_1 ... done
Attaching to course-v3_jupyter_1
jupyter_1  | Executing the command: jupyter notebook
~~中略
jupyter_1  |     Or copy and paste one of these URLs:
jupyter_1  |         http://(bc3f81290f54 or 127.0.0.1):8888/?token=xxxxxxxxx
```

token付きのURLが出力されるのでそこへアクセス

以上でとりあえずlessen1は実行できます。
限界までメモリ増やしてもエラーでエラーが起きる場合は、バッチサイズを小さくするなどして対応します（ものすごく時間はかかる。やはりGPUがいい。。。）
Alibaba CloudのVPN-Gatewayを使ってみる [SSL-VPN編]

# まずはじめに
もし気に入っていただけたり、役に立ったらぜひ　”いいね！”　お待ちしております！
投稿のモチベーションに繋がります^^¥

## この記事の目的
Alibaba CloudにVPN-Gatewayなるプロダクトがあったので、クライアントPCからSSL-VPNでさくっと接続してみたいと思う。

- 検証環境：MacOS X

ゴールイメージ↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/84a751c9-8e1e-e2ce-61b8-60a0214e0180.png)



## 兎にも角にもVPN-Gatewayを買ってみる
コンソールからVPN-Gatewayを選択します。
ざっくり構築手順としては、以下でいけそう。

- VPN-Gatewayインスタンスの購入
- SSL-Serverの作成
- 証明書作成
- 証明書インストール


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/b7e1787e-eca4-cb14-6e2b-7f2c4b283160.png)

## VPN−Gatewayインスタンスを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/62156dd9-f124-1d33-4550-1fbf58a34cc5.png)

- VPCを選択
- トラフィックはとりあえず10M
- SSLVPNの有効化（IPsecは使わないのでOffでOK）
- リージョンはちゃんと日本を間違えず選択
- 接続数はとりあえず5

時間あたり約16円。従量課金しか選択できないので、コネクションがあるときだけの課金になるみたいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/6dff87ed-893d-1cc8-f2c1-2bbdc0ed5113.png)

SLAと規約に同意し、購入！
インスタンス作成まで、3-4分かかるのでコーヒータイムとしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/01144311-1020-d234-2391-964a9f7b01dc.png)


## SSL-Serverの作成

インスタンスの購入ができたら、SSL-Serverを作っていきます。

- 名前：適当に（ただし英語で）
- ローカルネットワーク：vSwitchのサブネット
- クライアントサブネット：任意（ここでは192.168のクラスCとします。）

問題なければ、下部の作成を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/43f42769-647e-f63f-b749-b1459652e039.png)

## SSL証明書の作成
次にSSL証明書を作成していきます。
先ほど作成したSSL-Serverを選択しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/1344a9c2-2a91-ad56-3ace-1278806ae35b.png)

SSL証明書をローカルにダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/9ef205b2-1820-fdc1-022a-bef968657de0.png)

## クライアント側の設定
別サイトを引用させていただきます。
とりあえず、証明書をクライントソフトへ読み込ませれば、SSL-Serverを認識できます。

### Windows
OpenVPNを利用します。

>OpenVPN.JP
>https://www.openvpn.jp/document/openvpn-gui-for-windows/


### MacOS X
Tunnelblickを利用します。
>Mac OSでOpenVPNが使えるソフト「TunnelBlick」の設定方法（Neverまとめ）
>https://matome.naver.jp/odai/2143512841677670101

Macの場合、下図のようにD&Dで接続先エリアにファイルをインポートできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/7bfa151f-452a-f7b6-de28-fb48c4112cdd.png)


## 接続確認
さて、Configファイルを読み込めたらVPNを張りましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/9f05326b-c78f-4118-5a13-ef4299e84368.png)

SSL-Serverに接続できたことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/83f59d4a-8332-ba40-1a5a-90a92a8802be.png)

VPC内にいる、ECSのプライベートアドレス（10.0.0.240）にpingすると、無事pingが通りました。
（ECSのセキュリティグループで、ICMPはオンにしておいてください）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274358/708eba5c-8651-fb38-9bfe-8949466f6487.png)


## 最後に
VPCのリソースへセキュアにアクセスする際など、活用範囲は色々とありそう。
クライアント側の設定だけなので、楽でした！
Laravel Nova使ってみた

#Laravel Novaとは
Laravelの開発者であるTaylor Otwellが発表した公式の管理画面作成用のパッケージ。
優れたデザイン性を持った管理画面を構築することができます。 
既存のLaravelアプリケーションに簡単に導入することが可能で、その他にもいろいろな機能を持っており、
簡単な操作でカスタマイズができる。
####Laravel adminとの違い
- OSSではなく、ライセンスを買う必要がある。
- jQueryベースの「Laravel-admin」と、Vue.jsベースの「Laravel Nova」。実装コード量が少なく済む。
- 新機能を簡単に追加することが出来る。（Cards機能、Metrics機能等）

#導入手順
ファイルを直接ダウンロードする方法とcomposer経由でダウンロードする方法の２つ方法があるが、
今回はcomposer経由で行う。
#####使用するツール
- PhpStorm
- phpMyAdmin
- Git


###Laravelインストール
① インストーラーをダウンロード
 
```
composer global require "laravel/installer"
```
② Laravelインストーラにパス通す（環境変数の追加）

```
PATH=$PATH:~/.composer/vendor/bin
```

③ 環境変数の更新

```
export PATH
```

④ プロジェクトのディレクトリに移動して、laravel設置

```
laravel new src
```

⑤.envを編集
データベース名を変更（任意）

```
DB_DATABASE=laravel-nova
```


おまけ　PhpStormの機能をGitに置く必要はないのでちょこっとイジる
プロジェクト名と同じ階層に新規ファイル「.gitignore」を作成
中身

```
/.idea
```
コミット一覧から削除する

```
git rm -r --cached .idea/
```
rm 削除
-r ディレクトリを指定
--cached オプションを付けることにより、ファイルを残したまま管理対象から外すことができる。
.idea/ 対象ディレクトリ

###phpMyAdminでデータベース作成
データベース名　laravel-nova （.envと一致させる）
charset　utf8mb4_unicode_ci


###Laravel Novaインストール
①compser.jsonに追記

```php

  "license": "MIT",
  "require": {
    "php": "^7.1.3",
    "fideloper/proxy": "^4.0",
    "laravel/framework": "5.8.*",
    "laravel/tinker": "^1.0",
    "laravel/nova": "*" //ココを追記
  },　
  "repositories": [ //ココを追記
    { //ココを追記
      "type": "composer", //ココを追記
      "url": "https://nova.laravel.com" //ココを追記
    } //ココを追記
  ], //ココを追記
```

②追記したらコマンド実行

```
composer update
```
③ユーザー名とパスワードを聞かれる
登録した情報を入れても「資格情報が無効です」って言われたら、
④APIトークン認証を聞かれる（Laravel Novaのマイページで確認）
それでもダメなら
⑤composer.jsonと同じ階層に新規ファイル「auth.json」を作成
中身

```
{
  " http-basic ":{
  " nova.laravel.com ":{
  "ユーザー名":"○☓△□",
  "パスワード":"○☓△□"
}
}
}
```

⑦ここでようやく

```
php artisan nova:install
```

導入完了

#Auth機能を導入

コマンド実行

```
composer require laravel/ui
php artisan ui vue --auth
php artisan migrate
npm install
npm run dev
```
npmコマンドを使用するためにはNode.jsをインストールしておく必要があります。
[Node.jsインストール手順](https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09)

#ユーザー登録
/registerでユーザー登録ページに飛びます。

#####フロント画面からユーザー登録が不要な場合
routes/web.phpを修正

```web.php
Auth::routes(['register' => false]);
```

src/app/Http/Auth/RegisterController.phpを削除

#管理画面にログインしてみる

/novaでログインページへ

ログイン完了
![スクリーンショット 2019-06-17 14.50.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286794/885635aa-5ec2-ac47-4e09-4547f6fea79a.png)
LARAVELの設定はどこを変更すべきなのか

# はじめに
LARAVELをインストールしたまではよかったのですが、いざPostgreSQLを使おうとした際にデフォルト設定では接続できないらしい、設定を変更する必要がある、とのこと。
そこで公式ドキュメントを読んでみたところ、どこをいじってよいのかよくわからないので、自分なりに調べてまとめてみました。
# 設定のある場所
1. [root]/.env
2. [root]config/*.php
3. 'php artisan config:cache' コマンドで作成された設定

### [root]/.env について
LARAVELをインストールすると作ってくれる、インストール時の環境に応じた環境設定。
これそのものは何もしない（と思うのだが…。）

### [root]/config/*.phpについて
設定ファイル群。キャッシュファイルを作らない限りここから設定を読み込む。

### 'php artisan config:cache' コマンドで作成された設定 について
上記設定ファイル群から読み込んだ設定をまとめたもの。これを作成するとアプリが早くなるらしい。
そして**この設定キャッシュファイルの存在が確認できた場合には、/.envファイルは読み込まれなくなる。**

#それぞれの関係について
[root]/config/\*.php を開いてみると、ところどころで'env()'関数を使っている。ではこの関数はなんぞやというと、
**env([** *パラメータ1* **],[** *パラメータ2* **]);**
パラメータ1の環境設定値を返す。
パラメータ1の環境設定値がない場合には、パラメータ2の値を返す。
パラメータ1のみでパラメータ1の環境設定値がないときにはnullを返す。

つまり、

```:/.env
HOGE=hogehoge
```

のとき、

```:/config/fuga.php
'fuga' => env('HOGE');
```

で ```fuga = 'hogehoge'``` となる。また、

```:/config/fuga.php
'fuga' => env('PIYO');
```

であれば、PIYOという値の設定はないので、
```fuga = null``` となるし、

```:/config/fuga.php
'fuga' => env('PIYO','piyopiyo');
```
であれば
```fuga = 'piyopiyo'``` となる。

#つまりなんなんだよ
結論としては、
1. /config/\*.php の内容を確認する
2. 環境設定でいじれるものは/.envでいじる
3. env()関数を使ってなさそうなものは/config/\*php を直接編集する(カスタムのconfigファイルを作る方法もあるらしいですが、ここでは触れません。)
4. いよいよ設定も固まってきたぞといったところで 'php artisan config:cache' で設定キャッシュファイルを作成する。これによって設定は固定化され、~~/.envに依存する設定はnullとなる。~~ /.envはロードされなくなり、env()関数は全てnullを返す。

だから公式ドキュメントでは「アプリケーションの開発期間中は設定が頻繁に変更されることも多いので、ローカルでの開発中にこのコマンドを実行してはいけません。」と書かれているのでしょう。

#参考
[Laravelのデータベース設定（config/database.php）の意味](https://teratail.com/questions/130419)
[Laravel 5.8 設定](https://readouble.com/laravel/5.8/ja/configuration.html#introduction)
[Laravel の .env の値は config() 経由で使う。](https://hiroto-k.hatenablog.com/entry/2018/03/28/213000)
2019-06-26 追記
[Laravelヘルパ envメソッド](https://readouble.com/laravel/5.8/ja/helpers.html#method-env)

ありがとうございます。
jsで文字列の重複を削除する

jsで文字列の重複を削除したい。
配列の重複はやり方が見つかったのですが、文字列のが見つからなかったので、こんな感じでやってみました。

メソッドチェーン一回したのですが、なぜなエラーになるのと、チェーンつなぎすぎて読みづらいのでやめました。

```javascript
let tmp = '123123123';

tmp = tmp.split('');
tmp = tmp.filter(function (x, i, self) {
  return self.indexOf(x) === i;
});

tmp = tmp.join(',');
tmp = tmp.replace(/,/g, '');

console.log(tmp);
// 123
```

参考ページ

配列の重複をはじく、もしくは重複を取り出す
https://qiita.com/cocottejs/items/7afe6d5f27ee7c36c61f
AWS Innovate Online Conference 「試験対策セッション5：運用上の優秀性（オペレーショナル・エクセレンス）を備えたアーキテクチャを定義する」をまとめてみた

# 参考文献
[AWS Innovate Online Conference](https://aws.amazon.com/jp/about-aws/events/aws-innovate/) 
AWS 認定 - 試験対策 「ソリューションアーキテクト - アソシエイト」
セッション5：運用上の優秀性（オペレーショナル・エクセレンス）を備えたアーキテクチャを定義する
を視聴して、まとめた内容を記載しています。

# 運用上の優秀性を実現するそソリューションの設計特性を選択する

## クラウド上の運用上の優秀性を実現するためのベスト・プラクティス
- 準備
    - 運用上の優秀性を実現するためには効果的な準備が必要
- 運用
    - 技術的なメトリクスに終始せずに、ビジネスの成果とお客様の成果の達成度によって運用を評価するという考え方
- 進化
    - 運用上の優秀性を維持するために運用を進化し続けようとする考え方

ビジネスの人数と、お客様のニーズを理解し、ビジネスの成果を得られるように効果的かつ効率的にサポートする必要がある  
目的となるビジネスの成果の達成度を評価するために使用するメトリクスを収集する  
ビジネスの状況、優先事項、ニーズの変化に対応して、長期的にサポートする運用を設計し、運用から学んだ教訓を取り入れることが重要  

## 運用上の優秀性を向上させるための原則

- コードを使用して運用する
    - 運用コードとして実行することで、ヒューマンエラーを抑制し、様々なイベントに対する一貫性のある応答を実現できる
- ドキュメントに注釈を付ける
    - AWSを運用していくと、ドキュメントが自動化のために用意したスクリプトなどで構成されるようになる
- 定期的に、小規模な、元に戻すことができる変更を適用する
    - コンポーネントを定期的に更新するように、設計し、失敗した場合に元に戻すことができるように少しずつ変更する
- 運用手順を定期的に改良する
    - 運用手順を実行するとき、改善の機会を探す
    - システムのワークロード進化させるときに手順も進化させる
- 障害を予想する
    - 障害シナリオをテストし、その影響を検証する
    - 定期的なゲームデーを計画し、ワークロードとシュミレートされたイベントに対するチームの応答をテストする
- 運用上のすべての障害から学ぶ
    - 運用上の全てのイベントと障害から教訓を学び、改善する


# 運用上の優秀性をサポートするAWSサービス
- AWS Config
    - EBSやEC2などのリソースを追跡して、リソースの追加／更新があらかじめ設定したconfigルールにしたがって自動検証
- AWS CloudFormation
    - JSON YAMLなどのテンプレートからインフラストラクチャーおよびリソースを自動構築
- AWS Trusted Advisor
    - セキュリティ、信頼性、パフォーマンス、コストサービスの制限におけるベスト・プラクティスに基づいてアカウント内のリソースをチェックし、ベストプラクティスに沿っているかアドバイスしてくれる
- AWS Inspector
    - EC2のセキュリティ脆弱性をチェック
    - 脆弱性が見つかった場合は、詳細な改善手順を載せたレポートを出力する
- VPCフローログ
    - VPC内のネットワークトラフィックをログに出力
    - ネットワークに問題があった場合のトラブルシューティングやインシデントが起きた場合の情報収集に利用できる
- AWS CloudTrail
    - APIコールをログに記録
- CloudWatch
    - メトリクスを収集/追跡して、メトリクスが閾値を超過している場合は、アラームをトリガーにすることができる
    - CloudWatchログはログを収集して保存する
    - EC2インスタンス内で生成されたログやCloudTrailのログ、lambda関数内の出力されたログなどを収集できる
    - メトリクスフィルター機能を利用すれば、パターンマッチしたログから新しいメトリクスを生成することも可能