OmniAICreator/Qiita-1.07M huggingface dataset:
日本語pathのファイルをopenCVが読んでくれないのでPILで読んでから渡した

python環境の画像処理にopenCVを使っているんですが、cv2.imread()は日本語パスのファイルを開いてくれません。そこでPILで読んできてopenCVで扱えるように並べ替えることにしました。

## 実行環境
python 3.6.4
opencv-python == 4.0.0.21
Pillow == 5.0.0

## openCVで読んだ場合
まずopenCVで読んだらどうなるか確認しておきます。

```python:python
import cv2
import matplotlib.pyplot as plt
img_cv = cv2.imread('./tomato.jpg')
plt.imshow(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB))
plt.show()
```
<img src="https://qiita-image-store.s3.amazonaws.com/0/277233/6cc5e1eb-8d46-7f5e-5a0b-f03597e6e3dd.jpeg", width=50%>
読めました。

cv2.imread()で読むとnumpy.ndarrayになっているので、そのままで値が見えます。

```python:python
img_cv[0][:5]
```
```python:out
array([[53, 67, 19],
       [53, 69, 16],
       [47, 64,  7],
       [48, 66,  5],
       [53, 74, 11]], dtype=uint8)
```
これが再現できればOKです。

## PILで読み込み
PILで同じファイルを開いてみます。

```python:python
from PIL import Image
img = Image.open('./tomato.jpg')
img
```
<img src="https://qiita-image-store.s3.amazonaws.com/0/277233/6cc5e1eb-8d46-7f5e-5a0b-f03597e6e3dd.jpeg", width=50%>
PILの方が読むのは簡単ですね。

これをnumpy.arrayに変換します。

```python:python
img_arr = np.array(img)
img_arr
```
```python:out
array([[19, 67, 53],
       [16, 69, 53],
       [ 7, 64, 47],
       [ 5, 66, 48],
       [11, 74, 53]], dtype=uint8)
```
numpy.arrayにはできましたが、先ほどcv2.imreadで読んだものとは順番が違います。PIL.Image.open()はRGB、cv2.imread()はBGRの順で読んできますので、並べ替えてやる必要があります。

```python:python
img_arr2 = img_arr[:,:,::-1]
img_arr2[0][:5]
```
```python:out
array([[53, 67, 19],
       [53, 69, 16],
       [47, 64,  7],
       [48, 66,  5],
       [53, 74, 11]], dtype=uint8)
```
同じになりました。

## まとめ
openCVで読む場合

```python:python
import cv2
img = cv2.imread('./tomato.jpg')
img
```
PILで読んで並べ替える場合

```python:python
from PIL import Image
img = Image.open('./tomato.jpg')
img_arr = np.array(img)
img_arr = img_arr[:,:,::-1]
img_arr
```
処理時間も大差ないようなのでこれで良さそうです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/277233/b283e5c9-5626-481c-e5f7-b407e0f23954.png)

おしまい
parted コマンドについて

初めて知ったコマンド、初めて使ったコマンドを、意味もわからずにコピペで実行するのも怖いので、備忘録を残しておく。

## parted コマンド

MBR (Master Boot Record) と GPT (GUID Partition Table) の両形式に対応した、パーティションの作成や削除などに使うコマンド。

<dl>
<dt>MBR</dt>
<dd>最大サイズ 2TB のパーティションを管理する方式</dd>
<dt>GPT</dt>
<dd>最大サイズ 8.5ZB のパーティションを管理する方式<br>OS が 64bit で、パーティーションの分割が 4 つ以上の場合は GPT 一択</dd>
</dl>


- 参照: [MBR と GPTの違い、相互変換及び初期化方法‐どっちがよい](https://jp.minitool.com/partition-disk/mbr-vs-gpt-guide.html)

## 基本的な使い方

```shell-session
# parted [パーティーションの操作をするディバイス名]
```

例えば、`# parted /dev/xvdg` と実行すると、対話モードになり、パーティーションの各設定をしていく。

### オプションを指定

例えば、`# parted -l` とオプションを指定すると、現在のパーティーションの情報を表示する。

```shell-session
# parted -l
Model: NVMe Device (nvme)
Disk /dev/nvme0n1: 107GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name                 Flags
128     1049kB  2097kB  1049kB               BIOS Boot Partition  bios_grub
 1      2097kB  107GB   107GB   xfs          Linux
```

## 使用例

```shell-session
# parted /dev/xvdg --script 'mklabel msdos mkpart primary 1M -1s print quit'
```

- `parted /dev/xvdg` デバイス /dev/xvdg のパーティーションを操作する
- `--script` 対話モードは使用しない<br>'mklabel...' 内の設定を実行する
- `mklabel msdos` パーティーション形式を指定する
  - msdos - MBR 形式を指定する
  - gpt - GPT 形式を指定する
- `mkpart`
  - mklabel で msdos を指定した場合 - mklabel [パーティーションタイプ(primary/extend/logical)] [ファイルフォーマット(省略可能)] [開始位置/1M] [終了位置(相対指定可)]
  - mklabel で gpt を指定した場合 - mklabel [パーティーション名(例: untitled)] [ファイルフォーマット(省略可能)] [開始位置/1M] [終了位置]
- `print` パーティーション情報を表示
- `quit` parted を終了する

上記の `-1s` は最後の 1セクタ までを指す (すべて使い切るのではなく、1 セクタ未使用で残す)。

- [Parted User&rsquo;s Manual](https://www.gnu.org/software/parted/manual/parted.html)
- [【 parted 】コマンド――GPT対応のパーティションを作成、削除する：Linux基本コマンドTips（189） - ＠IT](https://www.atmarkit.co.jp/ait/articles/1803/08/news017.html)
情報セキュリティ 応用情報技術者試験 対策日記@15

# 情報セキュリティの要求事項
**機密性(Confidentiality)**
認可されていない情報を使用不可または非公開にする特性。

**完全性(Integrity)**
資産の正確さ、完全さを保護する特性

**可用性(Availability)**
要求時にアクセス及び使用が可能である特性

**真正性(Authenticity)**
内容が主張通りである特性

責任追及性(Accountability)
動作を一意に追求できる特性

否認防止(Non-Repudiation)
ある事象を後になって否認されない様に証明する能力

信頼性(Reliability)
意図した動作及び結果に一致する特性

#攻撃者の種類や動機による分類
**スクリプトキディ**
インターネットで公開されているクラッキングツールを利用して不正アクセスを試みる攻撃者

**ボットハーダー**
ボットを利用することでサイバー攻撃を実行する

**ハクティビズム**
政治的・社会的活動としてのハッキング活動

#暗号化技術とその応用
セキュリティ事故などが起こった際に、デジタル証明書の信頼性が損なわれた場合、CAに連絡して**CRL(Certificate Revocation List)**に登録してもらう。また、デジタル証明書の失効情報を問い合わせるためのプロトコルに**OCSP(Online Certificate Status Protocol)**があり、CRLの代替として提案されている。

### SSL/TLS
セキュリティを要求される通信のためのプロトコル。認証、暗号化、改竄検出の3機能を提供する。サーバがサーバ証明書をクライアントに送り、クライアントがその正当性を確認する。

### IPsec
IPパケット単位でのデータ改ざん防止や秘匿機能を提供するプロトコル。AH(Authentication Header)では完全性確保と認証、ESP(Encapsulated Security Payload)ではAHの機能に加えて暗号化をサポートする。また、IKE(Internet Key Exchange Protocol)により、共通鍵の鍵交換を行う。

### S/MIME
**MIME**とはテキストしか使用できなかった電子メール規格を拡張したもので、画像や音声などを利用することができる。S/MIMEはMIME形式の電子メールを暗号化するための標準規格。

### SSH
公開鍵暗号方式によって共通鍵の交換を行うハイブリッド暗号方式を使用し、ネットワークを通じて別のコンピュータにログインしたりファイルを移動させたりするプロトコル。
React Hooksでformもuseして型安全なフォーム生活

https://github.com/hachibeeDI/mayoiga

はい。

## とくちょう

簡単な例です。

```typescript
import * as React from 'react';
import {FC} from 'react';

import {useForm, createFormScope} from 'mayoiga';
import {Input, NumberInput} from 'mayoiga/lib/forms';

const required = (target: string) => (target.length === 0 ? 'required' : undefined);

const between = (min: number, max: number) => (target: number) => {
  if (target < min) {
    return `more than ${min}`;
  }
  if (target > max) {
    return `less than ${max}`;
  }
};

const choice = function<T>(...candidates: Array<T>) {
  return (target: T) => (candidates.includes(target) ? undefined : 'You should choose from the candidates.');
};

const INITIAL_FORM_STATE = {
  name: '',
  age: 13,
  seed: 'fish',
};

const {context, scope} = createFormScope<typeof INITIAL_FORM_STATE>();

const DemoForm = scope(props => {
  const {Form, Field} = useForm(context);
  return (
    <Form onSubmit={value => console.log(value)}>
      <Field name="name" component={Input} validations={[required]} />
      <Field name="age" component={NumberInput} validations={[between(5, 20)]} />
      <Field name="seed" component={Input} validations={[choice('fish', 'squid', 'octopus')]} />

      <button disabled={!props.touched || Object.values(props.errors).some(e => !!e.length)}>submit</button>
    </Form>
  );
});

export default function DemoApp() {
  return <DemoForm initialState={INITIAL_FORM_STATE} onSubmit={value => alert(`submit ${JSON.stringify(value)}`)} />;
}
```

一番重要なのは

```typescript
const {context, scope} = createFormScope<typeof INITIAL_FORM_STATE>();

const DemoForm = scope(props => {
  const {Form, Field} = useForm(context);
  return (
    <Form onSubmit={value => console.log(value)}>
      <Field name="name" component={Input} validations={[required]} />
      <Field name="age" component={NumberInput} validations={[between(5, 20)]} />
      <Field name="seed" component={Input} validations={[choice('fish', 'squid', 'octopus')]} />

      <button disabled={!props.touched || Object.values(props.errors).some(e => !!e.length)}>submit</button>
    </Form>
  );
});

export default function DemoApp() {
  return <DemoForm initialState={INITIAL_FORM_STATE} onSubmit={value => alert(`submit ${JSON.stringify(value)}`)} />;
}
```

のくだりですね。
`useForm` できます。え、すごーい！ キャッシュも結構きかせてるからパフォーマンスも悪くないっぽいよ！（たぶん）

そしてこのライブラリは型を頑張ってるので `<Field />` に渡すnameが `createFormScope` で渡した型引数のkeyに存在しない値である場合はTypeScriptがエラーを出してくれます。これでageと間違えてsageても問題ありませんね。
さらに`component=`で渡しているコンポーネントの `value` と `onChange` が `State[Name]`（たとえばageであれば`INITIAL_FORM_STATE['age']`の型と互換であるかどうか。つまりこの場合は`number`である必要がある）もチェックしてくれるんだって！

ちなみに`<Form />`レベルのonSubmitはoptionalです。

特徴を簡単にまとめると

- 型がかなり効く
- `useForm`できるので最新版を使っているという気持ちになれる。ボイラープレートコードが少ない
- ちょっとしたグルーを書けばantdやbootstrapやmaterialやらwhateverと簡単に連携できる

です。


[こちら](https://dev.to/hachibeedi/react-use-form-type-safe-react-hooks-based-form-utility-4k5h) にもうちょっと詳しい説明があります。

-----

最後にこの動画が面白い、役に立つと思った方は高評価とチャンネル登録、リポジトリにスターをお願いします。またね！
面倒なことはshellになんとかしてもらおう



エンジニアたるもの怠惰であれ、と神は言った。

## 人生は面倒に溢れている
生活を送るに当たって面倒なことは多々あります。わけのわからない講義やわけのわからないコンパイル、クソつまんねぇ行事やクソつまんねぇ一連のコマンド操作。はい、毎回やる一連の動作なんてものは一発でできるようにしてしまいましょう。

## shellってなに？
コマンドうつ時のあれ、つまりコマンド作ろうぜってお話ですね。
今回は3つのコマンド作成について説明します

## コマンドを作ろう
では、本題です、これから何回も打つコマンドや長いコマンドを短くしていく方法を3つ紹介していきましょう。

### ailiasを設定しよう
alias (別名,偽名)をコマンドに設定してあげましょう。
~/.bash_profile というfileに書き込んでいきましょう。
zshに変えている人は
~/.zshrc に書き込みましょう。

```
nano ~/.bash_profile
```

を実行してfileに書き込みましょう。
書き込みが終わったら control + o で保存して control + x　でエディタを閉じましょう。CUIエディタに興味がある人は調べてみても面白いかもしれません。

早速実例を見ながら説明していきましょう。
- ll
まずはlsコマンドの -l オプションです。これ1日に100回くらい使います
1日100回もこんなの打つと鬱になりますね。

```
alias ll='ls -l'
```
ついでに
- la

```
alias la='ls -al'
```
これも設定しちゃいましょう。
~/.bash_profileを書き換えたら実際に動きを確認してみたいですよね、今llコマンドを打っても反応はしてくれません、焦らずに

```
source ~/.bash_profile
```

としてあげましょう、せっかちはダメですよ。
そうするとあら不思議、llとコマンドを打つとls -l が実行されたではありませんか。では、このままaliasを使って面倒なコマンドを短くしていきましょう。興味があるのは追加してみてください。

- sshl
 
```
alias sshl='ssh 接続するサーバー'
```
決まったサーバーにsshする場合はsshコマンドを簡潔にしましょう。lはlocalの意です。
僕はraslというコマンドで自宅のラズベリーパイにlocal sshをし、rasgというコマンドでglobal sshをしています。


- nn

```
alias nn='nano -k -w -i -S'
```
nanoのオプションを毎回打つのは面倒なので簡略化します。
- bi

```
alias bi='brew install'
```
何気にしょっちゅう打つ、brewを使ってパッケージをインストールする際に毎回brew installを打つのは面倒なのでbiで済ませます。

と、まあこんな感じにいくつか紹介しましたが、このコマンド何回も打つなって思ったらaliasに登録して短くしてやりましょう。

### shファイルを作ろう
aliasには変数は使えません。なので変数を使う場合などはcommandName.shのようなfileに書き込み、aliasに登録してあげましょう。
まずは.shファイルをまとめるディレクトリを作り、そ子に移動しましょう。

```
mkdir ~/Tools
cd ~/Tools
```
以下はcommandNameというshファイルを作り、commandというaliasを設定する場合です。

```
alias command='sh ~/Tools/commandName.sh'
```

- mkcd

mkdirをしたあとはさっきのように続けてcdしましたよね、これ面倒ですよね、コマンドにしてあげましょう。

```mkcd.sh
#!/bin/sh

command='mkdir $1 && cd $1'
eval $command
```
少し説明します、*$1*とは

```
cd hogehoge
```
このhogehogeの部分のことです。スペース区切りで入力した文字が\$1,\$2と変数に格納されます。
eval とは以降のコマンドを実行するという命令です。
aliasに登録してあげましょう。

```
alias mkcd='source ~/Tools/mkcd.sh'
```
- cl

もう一例示してみましょう、cdした後にはそのディレクトリになにがあるか知りたいですよね、先ほど登録したllを使いましょう。

```cdll.sh
#!/bin/sh

command='cd $1 && ll'
eval $command
```
これで、cdしたディレクトリでll (ls -l)コマンドを自動で行ってくれます。

```
alias cl='source ~/Tools/cdll.sh'
```
alias登録を忘れずに。

### functionをつくろう
先ほど作ったclコマンドをfunctionで実装してみましょう。

```
function cl () {
  cd $1;
  ls -l;
}
```
こうやって作ることで、aliasに登録せずに、clと入力することでcl関数を実行することも可能です。

##　おわりに

こんな感じで少しでも面倒に感じたら自分なりにショートカットできるコマンドを作ってみるといいと思います。c言語やtexのコンパイル作業とか、面倒なのでshellになんとかしてもらいましょう。
Laravelでなるべく楽にcsvを扱う

# 前提
- csv扱うの面倒なのでなるべく楽したい(SJISとか特に)
- Laravel5.5(PHP7.2)の環境が構築済み

## 操作
[usmanhalalit/laracsv](https://github.com/usmanhalalit/laracsv)を使う。
このままだとUTF-8しか対応していなので、継承して少し修正する。

まず

```
composer require usmanhalalit/laracsv:^2.0
```

完了したらば下記のクラス・コードを適当なところに追加する

```php

<?php

namespace App\HogeService;

use SplTempFileObject;
use Laracsv\Export;
use League\Csv\Writer;
use League\Csv\CharsetConverter;

/**
 * 
 */
class HogeCsvExport extends Export
{

    /**
     *
     * @return void
     */
    public function __construct()
    {
        $encoder = (new CharsetConverter())->outputEncoding('SJIS');

        $writerObject = Writer::createFromFileObject(new SplTempFileObject)->setNewline("\r\n");

        $this->csv = $writerObject->addFormatter($encoder);
    }

}

```

`namespace App\HogeService`と`HogeCsvExport`
は任意の名称で。

`(new CharsetConverter())->outputEncoding('SJIS');`と
`Writer::createFromFileObject(new SplTempFileObject)->setNewline("\r\n")`
で任意の文字コードと改行コードを設定する。

柔軟性をもたせるなら、`__construct`の引数に文字コードと改行コードを設定すれば良いかな？

```php

    /**
     *
     * @return void
     */
    public function __construct(string $encoding, string $newLine)
    {
        $encoder = (new CharsetConverter())->outputEncoding($encoding);

        $writerObject = Writer::createFromFileObject(new SplTempFileObject)->setNewline($newLine);

        $this->csv = $writerObject->addFormatter($encoder);
    }
```

入力の文字コードも変更したい場合は`inputEncoding`を使えば良い。
詳しくは[usmanhalalit/laracsv](https://github.com/usmanhalalit/laracsv)の関連ソースコードを参照ください。

```php
$encoder = (new CharsetConverter())->inputEncoding('SJIS');
```


## 参照
[usmanhalalit/laracsv](https://github.com/usmanhalalit/laracsv)
[League\Csv](https://csv.thephpleague.com/9.0/converter/charset/)
Rails eachの代わりにrender partial collectionでコレクションのデータを取り出す

#はじめに
ネットで調べた情報で分かりづらかった所があったので、まとめてみました。
eachで書くよりもスッキリするのでいいですね。
#eachでの書き方
`@data`には何かしらのデータが入っているとします。
`@data = User.all`的な。

```index.html.erb
<% @data.each do |data| %>
※省略
<% end %>
```
ふつうですね。
次にpartialを使った書き方を。
#renderでpartialのcollectionな書き方
```index.html.erb
<%= render partial:'hoge', collection:@data %>
```
この一行でOKです。スッキリですね。
後はpartialで呼び出す部分テンプレートを用意しておく必要があります。
この場合ならファイル名は `_hoge.html.erb`　になりますね。

#取り出した値はどこへいった？？
自分で変数を用意する必要はないらしいです。
部分テンプレートの名前で自動生成されるようです。ありがたいですね。

```_hoge.html.erb
<%= hoge.name %>
<%= hoge.age %>

<%= hoge_counter %>
```
こんな具合ですね。
`hoge.`でアクセスできます。
また、`hoge.counter`でcollectionの何番目かを取得できます。
取得できる値は0~のカウントになるので注意が必要ですね。

#おわり
初めてqiitaに投稿してみました。
用語があやふやな部分があり(ActiveRecord_Relationってなんぞ・・・？みたいな・・・)
ふわっとしてますので、指摘のコメントお待ちしてます。
meldでフォルダ同士の比較が遅い時はnode_moduleなどでひっかかってる

ファイル比較ソフトのmeld便利ですよね。

あるとき、プロジェクトのフォルダ同士の比較で奥の階層のフォルダの比較ができませんでした。

あれ？と思ってるとしばらくたって折りたたみマークがでました。

そう、node_module部分の比較をしようとして時間がかかってたのでした。

今はnode_module部の比較は不要なので比較対象から外して軽量化を計ります。

## node_moduleを比較対象外する。

設定からFile Filtersの項目を開きます。

設定ダイアログ下部の＋ボタンを押してnode_moduleを除外する設定を追加してください。

名称のアンダースコアは無視されるようでハイフンにしましたが名前はなんでもかまいません。

<img width="642" alt="pref.png" src="https://qiita-image-store.s3.amazonaws.com/0/51116/334288b8-30d4-bf23-ff73-3b47b9cd54d1.png">

activeにもチェックしておいてください。設定が初めから有効になります。

## meldのフィルタで、node_moduleを指定します。

メインウインドウツールバーのFilterからさきほど作成したnode-moduleを有効になってるのを確認してみてください。

<img width="1252" alt="meld.png" src="https://qiita-image-store.s3.amazonaws.com/0/51116/c04e08d8-cc35-128e-40e0-a5739a024478.png">

爆速(?)でフォルダ比較ができるようになりました。

今回はnode_moduleを除外しましたがライブラリ系などで比較対象が重くなってる場合には流用できますね。
KSZ8995MAの使い方

@SRCHACKさんからわけてもらってコードを書いたKSZ8995MAのetherswitchの使い方のメモです。

# VLANの設定

port4をCPUポートにしてport0とVLANを組んでみます。

```
# etherswitchcfg config vlan_mode DOT1Q
# etherswitchcfg port0 pvid 2
# etherswitchcfg port0 striptag
# etherswitchcfg port4 pvid 2
# etherswitchcfg port4 addtag
# etherswitchcfg vlangroup2 vlan 2
# etherswitchcfg vlangroup2 members 0,4
# ifconfig vlan2 create vlan 2 vlandev arge0
# ifconfig vlan2 inet 10.10.10.111/24
```

vlangroupはどれでもよいです。


通常のSwitchの場合とDot1Q+VLANでのpingのping 100回の応答速度を2回確認したところなぜか処理が多いはずのDot1Qの方が早かったです。謎です。

通常のSwitch

```
round-trip min/avg/max/stddev = 1.069/4.698/77.992/13.074 ms
round-trip min/avg/max/stddev = 1.085/4.604/76.116/13.094 ms
```

Dot1Q+VLAN

```
round-trip min/avg/max/stddev = 0.997/3.877/70.568/10.973 ms
round-trip min/avg/max/stddev = 1.039/3.469/59.865/9.355 ms
```

# Mirroringの設定

port0の送受信をport4でモニターします。下記がデータシートのレジスタです。portは1始まりになっています。

![スクリーンショット（2019-04-02 14.36.37）.png](https://qiita-image-store.s3.amazonaws.com/0/104066/25da5387-a295-b8a2-677d-06dae477d7ec.png)

```
# etherswitchcfg config vlan_mode NONE
# etherswitchcfg reg 17=0x7f
# etherswitchcfg reg 81=0x9f
```

![Mirror.png](https://qiita-image-store.s3.amazonaws.com/0/104066/45f2e0b2-e5c5-0117-eda4-604813fd3382.png)

port4のinterfaceでtcpdumpするとport0の通信が確認できます。

etherswitchはVLANなどの最低限の機能はコマンドでサポートするけど、チップによって機能が様々なので個別の機能はレジスタ叩いてねって、ポリシーのようです。

スイッチへの接続はSPIやMDIO,I2Cなどですが、etherswitchcfgで全て同じように読み書きできるのは現実的な実装だと思います。


# MIB

mruby-etherswitchを使ってMIBを拾ってみました。

```ruby:ks.rb
mib = ARGV[0].to_i

t = EtherSwitch.new(0)

port = 0

while port < 5 do

  t.writereg(110, 0x1c)
  t.writereg(111, (0x20 * port) | mib)
  c = (t.readreg(117) << 24) | (t.readreg(118) << 16)
  c = c | (t.readreg(119) << 8) | t.readreg(120)
  c = c & 0x3fffffff
  if port != 0 then
    print ","
  end

  print c.to_s
  port = port + 1
end
```

実行してみます。

```
# /usr/local/bin/mruby ks.rb 14
413,0,0,0,0
```

困ったことにこのMIBはアクセスした時点でリセットされるようです。bsnmp-ucdでは定期的に呼ばれて、最後の値が読み取れるので、この仕様だと、そのままは使えません。:(
AWSの機械学習エンジニアの認定試験


AWSの認定資格に新しく機械学習向けのものが出来たそうなので、その概要メモ

# 概要

>The AWS Certified Machine Learning - Specialty certification is intended for individuals who perform a Development or Data Science role. It validates a candidate's ability to design, implement, deploy, and maintain machine learning solutions for given business problems.

![](https://d1.awsstatic.com/training-and-certification/machinelearning/path_ml-exam-preparation.0849ffc65449f465503b5d3b92410677a2ca62b3.png)


- [機械学習 – 試験準備コース](https://aws.amazon.com/jp/training/learning-paths/machine-learning/exam-preparation/)
- [新しい認定資格「AWS Certified Machine Learning – Specialty」で認定機械学習開発者になる | Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/become-a-certified-machine-learning-developer-with-the-new-aws-certified-machine-learning-specialty-certification/)

# 必要知識

- AWS上での1-2年の実務経験（開発、設計、ML運用）
- 機械学習アルゴリズムの基礎を説明できること
- ハイパーパラメータの最適化の経験があること
- ML/DNNフレームワークの経験があること
- モデル訓練のベストプラクティスに従えること
- デプロイ・運用のベストプラクティスに従えること

# 試験の注意点
- 選択式（択一回答・複数回答）
- 未回答の問題は不正解扱い
- 統計調査用の問題が混じっている（採点されないし、試験の合否に影響しない）
- 750/1000点で合格

# 試験内容
- データの取り扱い(Data Engineering)
    - データリポジトリ作成
    - データ統合の判断と実装
    - データ転送の判断と実装
- 探索的データ分析(EDA)
    - データクリーニングと準備
    - 特徴量エンジニアリング
    - データ分析・可視化
- モデリング
    - 機械学習のビジネス課題への当てはめ
    - 課題に対するモデル選択
    - モデル学習
    - ハイパーパラメータ最適化
    - モデル評価
- ML実装・運用
    - 機械学習ソリューションの構築（性能・可用性・スケーラビリティ・復旧・耐障害性）
    - 課題に対する適切な機械学習サービスの推薦と実装
    - 機械学習に対するAWSのセキュリティプラクティス適用
    - デプロイと運用


# 出そうなサービス

- EMR
- DyanamoDB
- Redshift
- QuickSight
- Athena
- Kinesis
- Glue
- SageMaker
Amazon SESでの拒否イベント用EICAR テストファイルの保存

Amazon CloudWatchにてSESの拒否のメトリクスを確認したく、
拒否イベントを発生させるのに苦労したEICAR テストファイルの保存についてをメモいたします。
#Amazon SESでの拒否イベント

Amazon SESにて、拒否イベントを発生させるには、送信した内容（メッセージ）にて
**ウイルスを検出した**と判断させる必要があります。

Amazon SES にはメールボックスシミュレーターが用意されており、
架空の E メールアドレスを作成せずに E メール送信アプリケーションをテストしたり、
1 日あたりの送信クォータに影響を与えずにシステムの最大スループットを確認することができますが、
拒否イベントをテストするためのアドレスは、現時点では含まれていません。

その為、ウイルスを検知させるためのEICARテストファイルをEメールに添付することで
拒否イベントのテストを行う必要があります。

【参考】 [Amazon SES開発者ガイド](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/mailbox-simulator.html)

###EICARテストファイルとは
ウイルス対策ソフトの動作確認を目的に作成された、無害なテストファイルです。
ウイルス対策ソフトはこのファイルをウイルスとして取扱います。

##問題点
ウイルス対策ソフトが導入されているローカルPCやWorkSpace上に
EICARテストファイルを作成保存した時点でウイルス対策ソフトで検知され、
駆除（削除）されてしまうのでEメールに添付以前にファイル保存ができませんでした。

※他にやる方法があったのかもしれませんが・・・。

##対処方法
以下のようにEICARテストファイルをLambdaで一度S3上に作成し、
S3の作成したファイルを読込んで添付しSESにて送信する方法で対応いたしました。
![qiita_20190401-1-構成図.PNG](https://qiita-image-store.s3.amazonaws.com/0/390199/14cfc8a7-44e7-9669-9010-99e2f8c4273e.png)
この投稿では、LamdbaにてS3上にEICARテストファイル生成する部分（①）の
実装を記述したいと思います。

###Lambdaの処理
AWSにログインし、サービスからLambdaを選択 > 関数の作成を押下します。
「一から作成」を選択し、基本的な情報を入力します。（詳細は、割愛します。）
ランタイムは「***Python3.6***」を選択しております。

```python:
import boto3

def lambda_handler(event, context):
    # オブジェクトを取得
    s3 = boto3.resource('s3')
    
    # バケット名を指定
    bucket = 'your_backet_name'
    # S3に保管するEICARテストファイル名（パス）
    fileName = 'reject.txt'
    # EICARテストファイルの内容
    fileContents = 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*'
    
    obj = s3.Object(bucket,fileName)
    obj.put(Body=fileContents)

    return
```

上記の関数コードを記述し、右上の「保存」ボタン押下後、テスト実行すると
S3の指定バケットにEICARテストファイルが作成されます。

##まとめ
ローカル上に保存できなくとも、S3に保存することで対応できます。
次の投稿では、実際にSESで拒否するまでの工程（②～③）を投稿したいと思います。
Laravelのバリデーションエラーメッセージが文字化けした場合の解決方法

#バリデーションエラー時の日本語メッセージが文字化けする

適当にバリデーションを実装し、取得したエラーメッセージをChromeのコンソールログに出力してみます。

```php

$validator = Validator::make($request, [
            'id' => 'require|integer',
            'name' => 'require|string',
        ], [
            'id.integer' => '不正なidです。',
            'name.string' => '不正な名前です。'
        ]);

if ($validator->fails()) {
  return Response::json(
    [
      'code' => 'ERROR_***'
      'errors' => $validator->getMessageBag()->toArray()
    ], 
    400,
  );
}

```

すると、下のように、エラーメッセージが文字化けしてしまいます。

```

# console.log
{
  "code" : "ERROR_***"
  "errors" : "\u5165\u529b\u5024\u304c\u4e0d\u6b63\u3067\u3059\u3002"
}

```

## もう解決策

Response::json()の第4引数に、`JSON_UNESCAPED_UNICODE`を設定。

```php

return Response::json(
    [
      'code' => 'ERROR_***'
      'errors' => $validator->getMessageBag()->toArray()
    ], 
    400,
    [],
    JSON_UNESCAPED_UNICODE,
  );

```

上記のように、[定義済み定数(https://www.php.net/manual/ja/json.constants.php)](https://www.php.net/manual/ja/json.constants.php)を渡すことで、
unicodeで日本語をエスケープせずにそのまま返してくれるようです。

```

# console.log
{
  "code" : "ERROR_***"
  "errors" : "不正な名前です。"
}
```

## まとめ
バリデーションとは関係なく、`Response::json`の仕様であった。
ちなみに、バリデーションエラーメッセージを

```php

$validator->errors()->all(),
```

で取得して渡すと文字化けしない。
時間があるときに調べてみよう。
RubyのメソッドやRuby周りの知識[メモ用]

#はじめに
　メモ用

#配列の中に入っているハッシュを指定する時に起きたエラー

hoges = [{name: "taro", age: 18},{name: "hanako", age: 38}]
こんなデーター入っていたとする。

```:
 `buy_program': no implicit conversion of Symbol into Integer (TypeError)
```

正しい指定
"hanako"を取り出したい
hoges[１][:name]


#比較演算子

http://www.tohoho-web.com/ruby/operators.html

#代入
（大元）　　　　　<< 　(入れたい要素)
　hero_datas 　<< 　hero_data



#ハッシュの要素をeachで取り出す

```ruby:
hoge.each　do |key, value|

puts"key: #{key} value: #{value}"

```
###よくやっている事
datas = [{name: "yujiro", age: 29},{name: "taro", age: 180}]
配列の中にあるハッシュのname要素だけ取り出したい時。

```
datas.each do |name|
```


#each_with　メソッド


```ruby:
hoges.each_with_index do |hoge, i|

puts"#{i}番目の要素は#{item}です。"

```




#文字列の連結

```
"A" "B" "C"

"A" + "B" + "C"

実行結果
"ABC"
```

#splitメソッド

文字列を切り離し、配列に返すメソッド

```ruby:
s = "hello,world,ruby"
p s.split(",")

#実行結果
["hello", "world", "ruby"]
```


#reverseメソッド
文字列の順番を入れ替えるメソッド。

```ruby:
s = "hello"
puts s.reverse
olleh
```
#lengthメソッド

レングスメゾット（長さ）とは文字列の数を数えるメゾット
スペースも数える

 ```Ruby:
irb(main):002:0> "Hello World".length
=> 11
```
#定数とは

定数
一度オブジェクトを代入したら再代入しない。
定数は名前をすべて英大文字。

```Ruby:
NUMBER
```

#スラッシュ記法とは
オプションと￥マークで＜\＞表記される

改行する時に使う


| 記法 | 意味 |
|:--|:--|
| \n | 改行 |
| \t | タブ |
| \b | バックスペース |
| \\ | バックスラッシュ |


#chompメソッド
getsの後につけているイメージあるが、
これは文字列が改行しない為につけている

```ruby:
name = "名前".chomp
```
#ハッシュの際のキーの指定について

この３通りあるよね。結論　name2とname3は同じ。name3の書き方が多い

```ruby:

name1 = {"name" => "taro"}
name2 = {:name => "taro"}
name3 = {name: "taro"}
```

ここでの違いは name1はキーを文字列としている
name2,3はキーをシンボルとしている事。
シンボルとは、文字列の皮を被った数値であり、実行速度を見ると、シンボルでキーを指定した方が早い。

#writeメソッド
ファイルを扱うには、Fileクラスを使う。
ファイルを作成するためには、Fileクラスのwriteメソッを使う。
指定した場所に指定のファイルを作成する事ができるよ。

 ```Ruby:
File.write(ファイルの場所, ファイルの中身) 
```



#to_iメソッド

paramsで取得できるのは文字列。それを数値として認識させるのに使用する


 ```ruby: 
params: [:id].to_i
```
#ヒュアドキュメント

```ruby:
puts <<~TEXT
おはよう
田中
太郎
くん


TEXT
```
#defメソッド
プログラムは上から順に処理していく。
ただ、defメゾットがある場合、呼び出されるまで無視する。
メソッドの外で定義した変数を「メソッドの中」で使えるようにするには引数を使う。

```
  def hoge(name) ＃仮引数はわかりやすい名前にする
  ③ puts "Mr.#{name}"
  end

  ①add_name = "taro"
  ②hoge(add_name)　＃仮引数と名前が違っても伝わる

```

実行結果

```
Mr.taro
```

実行順番

```
①taroがadd_nameに代入される
②代入されたadd_nameの情報を持った状態でhogeメソッドを呼び出す。
③仮引数の値に本引数の情報が加えられる
④実行される
```
脱AWS初心者！AWSのCloudTrailとCloudWatchを使って他リージョンの異常なイベントを監視・通知する

# やりたいこと
国内向けのサービスをAWS上で運営しているが東京リージョンしか使っていない。
そこで、何かの拍子に他のリージョンにec2が大量に作られるなどした場合に検知できるようにしておきたい。

# 概要
[調べたところ](https://dev.classmethod.jp/cloud/cloudtrail-cloudwatch-logs-sns/) 以下のような手順でできそう・・

1. Cloudtrailでイベントのログを取る
2. CloudWatch LogでログのフィルターとSNSをトリガー
3. SNSで通知する

# 手順
## Cloudtrailでイベントのログを取る
Cloudtrailの設定については調べれば出てくるので割愛します。

## CloudWatch Logのフィルター
[フィルターをかけるところまでいったら](https://dev.classmethod.jp/cloud/cloudtrail-cloudwatch-logs-sns/)ここからが本題です。

今回の要件/実装方針は
1. 東京リージョン以外のイベントを検知したい
2. ログインは発生するのでそれらは除く
3. 他にもログなどの書き込みなどありそうだがそこは少しずつフィルターを育てて改善する

の2つです。

仕様に落とし込むと
1. regionは `ap-northeast-1` 以外で絞る
2. `"invokedBy": "signin.amazonaws.com"` かつ `"userName": "someUser"` を弾く

## 実装

### 1. ロググループ選択
`OtherRegionLogGroup` という名前でグループを作りましたのでそれをクリックする。

<img width="1426" alt="1.ロググループ.png" src="https://qiita-image-store.s3.amazonaws.com/0/35480/87e88b50-16f6-f4da-98a2-1187e8a06c44.png">

### 2. イベント一覧
イベントの一覧です。リストの中身を見ればイベントの詳細情報がわかります。
ここでフィルターをいろいろ試しながら自分が使いたいフィルターを決めます。

[CloudWatch フィルターとパターンの構文一覧はこちら](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html#matching-terms-events)

<img width="1425" alt="2フィルターテスト.png" src="https://qiita-image-store.s3.amazonaws.com/0/35480/8da8a2ff-9636-c3f3-0085-72a192d84296.png">


条件としては下記の形になりました。

```
{
  ($.awsRegion != "ap-northeast-1") && (
    ($.userIdentity.invokedBy != "signin.amazonaws.com") &&
    ($.userIdentity.invokedBy != "cloudtrail.amazonaws.com")
  )
}
```

`ap-northeast-1` 以外かつ発火ユーザーが `signin`, `cloudtrail` 以外としています。

### 2.5 json filterのネストの書き方
少しだけ詰まったので補足説明です。
例: `{ $.requestParameters.instanceId = "some-instance-id" `

> SELECTOR
どのJSON プロパティを確認するかを指定します。プロパティセレクタは常に、JSON のルートを示すドル記号 ($) から始まります。
プロパティセレクタは英数字の文字列であり「-」および「_」をサポートします。
配列要素は [NUMBER] 構文で示され、プロパティに従う必要があります。
例は次のとおりです。$.eventId、$.users[0]、$.users[0].id、$.requestParameters.instanceId。

### 3 メトリクスフィルタの作成
フィルターが決まったらそれを適用させます。
ロググループ一覧に戻り、グループを選んだ状態でメトリクスフィルタの作成を押します。
<img width="1426" alt="1.ロググループ.png" src="https://qiita-image-store.s3.amazonaws.com/0/35480/622f2733-c4cb-8c7c-05c1-b2efddd30fc7.png">

そこにフィルタパターンを入れて「メトリクスの割り当て」を押します。
<img width="1427" alt="4.フィルタ定義.png" src="https://qiita-image-store.s3.amazonaws.com/0/35480/c63170fa-108b-9876-e0f6-9ecc03114e3a.png">

そうしたらこんな画面になるかと。
### <img width="1412" alt="5.フィルタ定義後.png" src="https://qiita-image-store.s3.amazonaws.com/0/35480/6b7c3ac8-189c-3359-108c-6b3874908e0c.png">

### 4. アラームの設定
上図の「アラームの作成」を押してアラームを作成しましょう。
今回は1度でもイベントがあるとアラームがくるようにしています。

<img width="1432" alt="6. アラート作成.png" src="https://qiita-image-store.s3.amazonaws.com/0/35480/4ccf6e35-5345-fe7b-af86-97e309391ef1.png">

### 5. アラームのチェック
試しにus-east-1リージョンでec2を作成してアラームが来るか検証してみましょう。来ていたら成功です :tada: 
<img width="1428" alt="7アラームきた.png" src="https://qiita-image-store.s3.amazonaws.com/0/35480/9cd74915-7c4b-b089-30c4-0869456722b6.png">

## 最後に
以外と後回しにしがちですが、1時間ほどあればとりあえずの設定はできるのでおすすめです！
もし何かありましたらコメントお願いします :bow:
Serverless Frameworkで知っておくと便利な設定

## はじめに

Serverlessを本番に組み込むにあたりこの設定いいなーというものを書いていきます。

## 環境

* Serverless Framework 1.36.1
* Node 6.9.0
* ランタイム（Ruby 2.5.0）

## CloudWatch Logsの保存期間を指定する

`provider`に`logRetentionInDays`で保持日数を指定してあげればOKです。
これを指定しないと、保持期間が無制限となるので、特にずっと保持しておく必要がなければ、指定しておきましょう
> 以下の設定では10日保持するとしています。

```yaml

provider:
  logRetentionInDays: 10
```


## デプロイバージョン管理指定を変更する

Serverless Frameworkでは`sls deploy`を行うごとに、バージョン管理されたフォルダをS3に保存します。
こちらもCloudWatch Logs同様に無制限にフォルダがS3に格納されていってしまうので、古いバージョンをいくつまで保存するのか設定を行いましょう。

[serverless-prune-plugin](https://github.com/claygregory/serverless-prune-plugin)のプラグインを使うことで簡単に設定できます。
`package.json`のある階層で以下を実行します。

```
$ npm install --save-dev serverless-prune-plugin
```

以上を実行したら、`serverless.yml`に以下を追加します。

```yaml
plugins:
  - serverless-prune-plugin
```

デプロイ後に自動で実行させたいので、以下のように`serverless.yml`に追記をします。

```yaml
custom:
  prune:
    automatic: true
    number: 5
```

上記のように設定することで、デプロイを行なうと過去5つのバージョンまでが保存されているかと思います。

## DynamoDBのオンデマンド（リクエスト数課金）設定

DynamoDBではリクエスト数に応じて課金となるオンデマンド設定が用意されています。
それをServerless Frameworkで使うには、以下のように`Resource`を変更します。

```yaml
Resources:
  DynamoDbTestTable:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
      - AttributeName: id
        AttributeType: S
      KeySchema:
      - AttributeName: id
        KeyType: HASH
      # BillingModeを変更
      BillingMode: PAY_PER_REQUEST
      TableName: test-tables
```

上記のように、`BillingMode`を`PAY_PER_REQUEST`にすることで設定が可能です。

## DynamoDBのレコードに有効期限を設定する

大量のトランザクションデータを保存するときなどにレコードの有効期限を設定したかったりします。
この設定を知る前はLambdaでバッチ処理を書いてレコードを削除していましたが、以下の設定でそれらを行うことなく実現が出来ます。

[serverless-dynamodb-ttl](https://github.com/Jimdo/serverless-dynamodb-ttl)　このプラグインを使うことで簡単に設定が出来るので、使用します。

```
$ npm install serverless-dynamodb-ttl --save
```

次に`serverless.yml`を編集します。
`plugins`セクションにプラグイン名を追記し、`custom`セクションに設定をするテーブル名と有効期限を格納したカラム名を指定します。

```yaml
plugins:
  - serverless-dynamodb-ttl

custom:
  dynamodb:
    ttl:
      - table: test-table # テーブル名
        field: expiration_date # カラム名
```

`expiration_date`には`unixtime`で有効期限を設定する必要があります。

<img width="134" alt="スクリーンショット 2019-04-02 13.20.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/19716/3faae1b5-6870-bd2c-2b8b-6a1e2f401b4f.png">

## Serverlessのタイムゾーンを日本時間に変更する

日本時間に変更するには、`serverless.yml`の`provider`セクションに環境変数`TZ: Azia/Tokyo`を設定してあげれば変更が出来ます。

```yaml
provider:
  environment:
    TZ: Asia/Tokyo
```


## 終わりに

今後も便利な設定があれば追記予定ですので、こんな便利な設定があるよなど教えていただけますと幸いです。
backoffの確認


```plaian:pipfile
requests = "*"
backoff = "*"
flask = "*"
flask-limiter = "*"
```

```python:my_backoff.py
import backoff
import logging
import requests

logging.getLogger('backoff').addHandler(logging.StreamHandler())
logging.getLogger('backoff').setLevel(logging.DEBUG)

def fatal_code(e):
    return 400 <= e.response.status_code < 500

@backoff.on_exception(backoff.expo, requests.exceptions.RequestException, jitter=backoff.full_jitter, max_time=60, giveup=fatal_code) 
def sample(): 
    r = requests.get("http://localhost:5000")
    r.raise_for_status()
    return r.text 

```


```python:my_flask.py
from flask import Flask
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)
limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=['100 per day', '10 per hour']
)


@app.route('/')
@limiter.limit('5/minute')
def root():
    return '1分に5回しかアクセス出来ないぞ'


def main():
    app.run()

if __name__ == '__main__':
    main()
```
git cloneで役に立つエイリアス

全世界のgitユーザー待望のエイリアス作りました。
GitリポジトリのURLをコピペしたと思ったら```git clone git clone```になってしまったときにもgit cloneできるようにするエイリアスです。

```text:~/.alias
alias git='history 1|sed -r "s/ *[0-9]+ *//;s/^ *git *clone *git/git/"|sh #'
```
上記コマンドをエイリアスに登録するか、実行してください。
![git_clone_alias.gif](https://qiita-image-store.s3.amazonaws.com/0/155890/faa16017-f05c-1a17-3114-ee96e093932e.gif)

間違って```git clonegit clone```になっても大丈夫です。

他のコマンドには影響を与えないので、便利便利

## 動かした環境

- Git bash for Windows
- Ubuntu 18.04

のBashでは動きます。

Macでは試してないので誰か試していただけると幸いです。

## 追記

### 本気で使いたい人向け
git 自体をエイリアスにしているので、gitに他のエイリアス(例えば```alias gs='git status'```)を登録していた場合は影響を与えます。
本当に使いたい場合は、gitコマンドを拡張すると幸せになれます。

```bash
# gitコマンドを拡張
$ echo 'git clone $(echo "$*"|sed -r "s/^ *git *clone//")' | sudo tee -a /usr/bin/git-get
$ sudo chmod +x /usr/bin/git-get

## 使うとき
$ git get https://github.com/amanoese/splash-julia
## or
$ git get git clone https://github.com/amanoese/splash-julia
```
ZorinOS Ultimate 12.4をインストールして設定したこと

※ Zorin 12.4はUbuntu16.04ベースであり、Ubuntu16.04のバグがそのまま残っています（Bluetoothキーボードがうまく使えないなど）
次回リリースからはUbuntu18.04ベースとなるようなので、しばらく待った方がよいかも？

---

ZorinOS Ultimate 12.4を購入しました。
paypalを通して2,470JPY。

Linuxにしては珍しい有料OSですが、別にサポートが手厚いとかそういうわけではありません。
Liteに比べて多少の機能追加とデフォルトで入っているアプリケーションが多いくらいで、正直そこまでしてUltimateを導入する理由はありません。
（私はUltimateの付加価値というよりはカンパのつもりで課金しました。）


ZorinOSはUbuntuベース&&GNOMEベースなので、そのへんの知見がわりとそのまま通用します。
逆に言うと、この記事の内容も他のUbuntuベースのディストリやGNOMEに通用すると思います。

HW: Thinkpad X1 Yoga 3rd Gen

---

## CPUファンが動くようにする: Thinkpad X1Yoga3特有
一部のThinkpadでは標準でCPUファンが回転しない問題を抱えています。
CPU側で温度制御がかかるので壊れるようなことはないのですが、その分クロックが落ちてまともに設定作業もできないので、まずこれを解決します

### パッケージリストの更新
今upgradeまでするとCPU温度がとんでもないことになって大変なのでupdateだけ

```bash

$ sudo apt update
```

### ファン制御の有効化
```bash=
$ sudo vi /etc/modprobe.d/thinkpad_acpi.conf
options thinkpad_acpi fan_control=1

# 一度再起動する

$ sudo su
$ echo level 7 > /proc/acpi/ibm/fan
```
とりあえずこれでファンが全開で回り始める

### thinkfanのインストール
```bash=
$ sudo apt install thinkfan
$ sudo vi /etc/thinkfan.conf
# 上の方に下記を追記
hwmon /sys/devices/virtual/thermal/thermal_zone0/temp

$ sudo systemctl start thinkfan
# ファンの制御が始まればOK エラーが出れば設定ファイルが間違えている

# 自動起動の設定
$ sudo systemctl enable thinkfan
```


## 英語環境での日本語フォントが中華になる問題
たとえ日本人でもOSは英語で使いたいという場合が多いと思いますが、（要出典）
英語設定になっていると読みに行くフォントセットが英語向けになるので日本語フォントが気持ち悪くなります。

Fontconfigは`$FC_LANG`を見てフォントセットを決定しているようなので、これをjaにすることで日本語向けのフォントセットを使うことができます。

```bash
$ vim ~/.profile

# 最下行に追記
export FC_LANG=ja
```
設定後一旦ログアウト。


## 日本語入力の設定
```bash
$ sudo apt install fcitx fcitx-mozc
$ im-config -n fcitx

# logout => login
```

## CAPSをCtrlにする: GNOME特有
```bash
$ gsettings set org.gnome.desktop.input-sources xkb-options "['ctrl:nocaps']"
```


## スケーリングを無効化する（等倍で表示する）: GNOME特有
```bash
$ gsettings set org.gnome.desktop.interface scaling-factor 1
```



# アプリケーション
今は結構な数のアプリがsnapで入れられるようになっている模様。とても楽。

## docker
```bash
$ sudo snap install docker
```

## visual studio code
```bash
$ sudo snap vscode --classic
```

## discord
```bash
$ sudo snap install discord
```

## slack
```bash
$ sudo snap install slack --classic
```


# おわりに
先述の通りUbuntu16.04のバグが残っており、Bluetoothキーボードが使えない問題が発生しました。
私にとってこの問題は非常に深刻なので、結局違うディストリに乗り換えています。

課金したときにユーザー登録の類が皆無だったからすでに新しくZorin12.4すら落とせないし（むしろURLさえわかれば誰でも落とせる）、次回リリース時もまた課金しないといけないんだろうなあ...
AWS/ECSでタスク定義をする際のネットワークモードとFargate

初投稿です。

ECS + EC2 で動いているサービスをECS + Fargate に変える際に
ネットワークモードとFargateについて覚えることがあり、備忘録も兼ねて書き残します。


## この記事で書く事
1. ネットワークモードはどこで設定するか？
2. ネットワークモードの種類とそれぞれの説明
3. Fargateとは？awsvpcしか選べない理由

## この記事で書かない事
1. ECS/ECR/Docker周りの詳しい記述
2. タスク定義を完了させるまでの全フロー

---------------

## ネットワークモードはどこで設定するか？
2019/3/29現在、ECSで新規タスク定義を作ろうとすると、
コンテナの起動させる場所としてFargateかEC2にするかを選ぶ画面が出現します。

![スクリーンショット 2019-03-29 17.51.34.png](https://qiita-image-store.s3.amazonaws.com/0/58193/be7da376-0776-761b-45d8-c54efc6dd27d.png)

**「EC2」** を選択して次に進むと、ネットワークモードを選択するセレクターが出てきます。

![スクリーンショット 2019-03-29 17.52.43.png](https://qiita-image-store.s3.amazonaws.com/0/58193/a8edd500-649a-250e-72c7-c6f11049b253.png)

**< default >** は **bridge** と同じですので、実質４つの選択肢となります。

-----------------

## ネットワークモードの種類とそれぞれの説明

### bridge（ブリッジ）

bridgeはDockerコンテナと外のネットワークを繋ぐ最もオーソドックスな手段です。
DockerコンテナがEC2インスタンスの中にある時、ネットワークはまずEC2インスタンスに接続し、
その後、宛先のDockerコンテナのポートを探して接続します。

DockerコンテナがEC2インスタンスに１つだけなら、そう難しく考える必要はありませんが
複数のDockerコンテナがEC2インスタンスの中で動く場合、ポートの管理（ポートマッピング）が発生します。

例えば２つのWebサーバDockerコンテナを同じEC2インスタンス内で動かそうとすると、
両方をDockerコンテナに80番ポートと設定(エクスポート)したとしても、
EC2インスタンス側で片方を8080番ポートで繋ぐ等の工夫をしなければいけません。

### host（ホスト）

hostはDockerで設定(エクスポート)したポート番号とEC2インスタンス側のポートを番号を同じにします。

ゆえに、２つのWebサーバDockerコンテナを同じEC2インスタンス内で動かそうとする場合、
両方に「同じポート」と設定することはできません。
つまり、両方を「80番ポート」にすることができないということです。

ですから片方のDockerコンテナを8080番等の別のポートにする変更が必要になります。
そして、外部ネットワークから接続する時も8080番ポートに接続することで
そのDockerコンテナにアクセスできるようになります。

bridgeに比べるとポート管理(ポートマッピング)が必要ありませんが、
コンテナを作る時からポートを考えなければいけないため、使い分けが必要と言えます。

### awsvpc
awsvpcはDockerコンテナ自体にENIという、AWS内のネットワークインターフェイス（IPアドレスやMACアドレス）を与えます。
これにより、bridgeやhostで抱えていた「Dockerコンテナ間のポートの競合」問題が無くなります。

このネットワークモードはタスク定義をする際、
「起動タイプの互換性の選択」時に **「Fargate」** を選ぶと、
このネットワークモードが **自動的** に選択されます。これに関しては後に説明いたします。

### なし
外部のネットワークと接続できなくなります。

--------------------------------

## Fargateとは？awsvpcしか選べない理由

Fargateは、これまでのDockerコンテナがEC2インスタンスの中で動いていたのに対し、
**EC2インスタンスを省いて、Dockerコンテナだけ** でサービスが動くようにしたものです。

したがって、これまでENIを保持していたEC2インスタンスが無くなった為、
Dockerコンテナ自身でENIを持たなくてはいけません。

これが理由によりFargateを選ぶとawsvpcのネットワークモードが自動的に選ばれる事になります。



## まとめ

awsvpcはポート管理がいらない魅力的なネットワークモードです。
また、それを使用するFargateも魅力的なサービスです。

新規でECSでサービスを作ろうと考えている方がいらっしゃれば
こちらのネットワークモードやサービスの使用を検討される事をおすすめします。

------------

参考：
Amazon EC2 Container Service(ECS)の概念整理
（この記事では「Task=Dockerコンテナ」と致しましたので、こちらをお読みになられる事をおすすめします）
https://qiita.com/NewGyu/items/9597ed2eda763bd504d7

Amazon ECS(EC2 Container Service)についての簡単なメモ
（上の記事より簡単に概念がわかります）
https://qiita.com/mokemokechicken/items/d45144dcd1979c10e336

Elastic Network Interface（ENI）
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_ElasticNetworkInterfaces.html

ECSでEC2インスタンスを利用する際のネットワークモードについて調べてみた
（こちらの記事の方がネットワークモードについて専門用語などが正しく使われています。一読される事をおすすめします）
https://dev.classmethod.jp/etc/ecs-networking-mode/
Docker networkについて簡単にまとめた



#Docker networkとは
Dockerコンテナ同士を連携できる。

例えば、以下のような用途になります。

 - WordPressコンテナとMySQLコンテナ同士を連携させ、WordPressをインストールできるようにする
 - RubyコンテナとMySQLコンテナ同士を連携させ、Ruby on Railsをインストールできるようにする




#どのようにして連携させるか(※docker-composeを使用する場合)
今回はDocker-composeを利用したネットワーク構築方法をまとめます。

## docker-compose.ymlでコンテナ設定を記述
以下はWordPressコンテナとMySQLコンテナを連携させる例です。

```docker-compose.yml


version: '3'
services:

  wordpress:
    image: wordpress
    container_name: 'wordpress'
    restart: always
    expose:
      - 80
    ports:
      - "80:80"
    volumes:
      - ./www/html/:/var/www/html
    external_links:
      - mysql
    environment:
      VIRTUAL_HOST: 'ホスト名'
      WORDPRESS_DB_HOST: 'mysql:3306'
      WORDPRESS_DB_NAME: 'DB名'
      WORDPRESS_TABLE_PREFIX: '接頭辞'
      WORDPRESS_DB_USER: 'DBユーザー名'
      WORDPRESS_DB_PASSWORD: 'DBユーザーのパスワード'
    depends_on:
      - mysql

  mysql:
    image: mysql:5.7
    container_name: 'mysql'
    restart: always
    environment:
      MYSQL_ROOT_USER : 'root'
      MYSQL_ROOT_PASSWORD: 'DBrootユーザーのパスワード'
      MYSQL_DATABASE: 'DB名'
      MYSQL_USER: 'DBユーザー名'
      MYSQL_PASSWORD: 'DBユーザーのパスワード'
    ports:
      - "3306:3306"
    volumes:
      - ./sql:/docker-entrypoint-initdb.d
      - ./mysql/:/var/lib/mysql
```

## docker-compose upコンテナを立ち上げ

```terminal
#docker-compose upコンテナを立ち上げ
$ docker-compose up -d
```
※この時点でコンテナ同士を連携させるネットワークが一つ設定されます。

##設定されたネットワークを確認

```terminal


#設定されたネットワークを確認
$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
2618f1800ddf        bridge              bridge              local
365733c9a465        host                host                local
8683de83529d        none                null                local
ca080878c135        wordpress_default   bridge              local

```
※「wordpress_default」というネットワークが生成されいるのが確認できる。
※bridge、host、noneのデフォルトで生成されているものらしい。

#さいごに
私個人のお話ですが、1つのVPSでDockerを使って、マルチホストでサイトを複数立ち上げたいと考えており、
その作業の過程でDocker networkって何だと躓いたので、今回自分なりにまとめました。

また、Docker netoworkについてなにか学習したものがあれば、随時追記します。

#参考
【Docker コンテナ・ネットワークの理解 — Docker-docs-ja 17.06.Beta ドキュメント】
http://docs.docker.jp/engine/userguide/networking/dockernetworks.html

【Compose のネットワーク機能 — Docker-docs-ja 1.12.RC2 ドキュメント】
http://docs.docker.jp/v1.12/compose/networking.html
Visual Studio Codeで日本語化する方法[Windows]

#簡単に日本語化ができるので備忘録として



>###2019/11/21更新
>新しいパソコンにVScode入れたら、日本語化がさらに簡単になっていました。一応記事の更新しておきます



Visual Studio Code（VScode）を使うときに日本語化したのですがいろいろと情報が錯綜していたので自分の環境で成功した方法を書きます。

OSはWindows10です。

1. Visual Studio Codeを開く
2. メニューバーからviewを選択
3. command palette を選択
4. configure display languageを選択
5. install additional laugageを選択
6. 左に拡張言語パックが出てくるのでJapanese Language Pack for Visual Studio Codeを探してインストール
7. すべてが終わったらVScodeを再起動する（普通にポップアップが出てくるのでそれに従ってVScodeを再起動すればいい）

これで完了です。

ページによっては拡張機能の説明がなかったりほかのファイルをインストールしているものもありましたが、自分の環境ではこの状態で日本語化しました。
(R15)LINE Clova FriendsをLチカ信号でWake

#■はじめに
LINE Clova Friendsを、音声の「ねぇClova」ではなく***Lチカ信号でWake***かけられるようにしてみました。Clovaって、音声起動以外に鼻を押して起動することもできるんですよね。この***鼻のスイッチをハックして、外部に引き出し***ました。**これで何がしたかったのかは、自分でもよくわかりません**。こんな特殊なニーズがあるとはまつたく思えないのですが、自己満でとりあえず公開しますね。大胆な分解を伴う改造なのでR15指定入ります。
#■仕組み
**分解して鼻のスイッチ端子から線を引き出し**て、念のためフォトカプラを経由して**Lチカ信号でON/OFF**します。**フォトカプラごとCloavの底面に埋め込み**、外部からコンパクトに直接Lチカ信号を送れるようにしました。Clovaの外部への端子引き出しは、**ピンソケット2本を背面に埋め込む**形にしのした。都合よくCloavの胴体には小さい穴がたくさん開いているので、そこにいい感じにこっそり忍ばせました。

#■こんな感じの仕上がり
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/985b33b3-5f64-07ee-aa33-2a6de2b9b4cd.png)


#■これで何ができるのか
アイディア次第で、あんなことやこなんことが色々できるのですが、2つほど活用事例を上げておきます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/obniz?src=hash&amp;ref_src=twsrc%5Etfw">#obniz</a> <a href="https://twitter.com/hashtag/Clova?src=hash&amp;ref_src=twsrc%5Etfw">#Clova</a><br>距離センサー(GP2Y0A21YK0F)で、バーチャルClovaの鼻を押せたらリアルClovaをWake。 <a href="https://t.co/Z0fbB5ra53">pic.twitter.com/Z0fbB5ra53</a></p>&mdash; Google Homer (@google_homer_) <a href="https://twitter.com/google_homer_/status/1081575855711604736?ref_src=twsrc%5Etfw">January 5, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/obniz?src=hash&amp;ref_src=twsrc%5Etfw">#obniz</a><br>obnizのブロックプログラミングの新版がAI機能なんかも搭載して、とてつもなくすごいことになっている。<br>スマホカメラが顔を認識したらLINE ClovaをWakeするやつがこのブロックプログラミングで一瞬でできてしまった。LINE Clovaを目くばせでWake、ここに完成か。 <a href="https://t.co/tgXldkNhsj">pic.twitter.com/tgXldkNhsj</a></p>&mdash; Google Homer (@google_homer_) <a href="https://twitter.com/google_homer_/status/1072109802124271619?ref_src=twsrc%5Etfw">December 10, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
#■改造手順
ほぼほぼプラスドライバーのみで行けます。そんなに集積度高くないので、分解の難易度は低い方だと思います、、、、
###が、私はClova一人失いました。
###それでは、お気をつけて行ってらっしゃいませ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/23f9f985-4729-7e26-b1d0-47be12d911ac.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/d4f388c3-fdd2-4112-b7e5-3cd4b4099f30.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/207f5fab-3ff7-3e9f-fd5f-00c17325c977.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/70c31401-95c6-c010-884d-d6fef0bd6381.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/94044e74-6e4f-63f3-5c17-8bcd601c2a6d.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/cb3c93c6-cd03-4d42-0a1f-b759d1241988.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/df559c5c-17d6-02ac-8240-e8565942766a.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/fe55146a-992b-0d04-69bc-a7bf590a3b70.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/d835b86a-26d3-d0fb-4594-108ba635006c.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234533/5958f1d8-0b72-466b-7a00-71806408cf84.png)
##以上です。
dockerインストールメモ


https://hub.docker.com/editions/community/docker-ce-desktop-windows

の
Please　ログイン　to　インストール

みたいなところで
登録するとメールが飛んできて
そのURLに
インストーラーのURLがあるので
それで保存し
Docker for Windows Installer.exe
を実行すればインストール出来ると思うけど
うんともすんとも言わない……

再起動かな？？？
developからdevelopにPushできないような設定方法

コードレビューがなし、直接developブランチに反映するのは危険ので、
直接"develop"ブランチへのpushを検知して止めるような方法を紹介します


### マージの正しいルート：
リモートのdevelopブランチから新しいブランチを切る
↓
先程作った新しいブランチで改修を行う
↓
リモートのdevelopブランチにマージリクエストを投げる
↓
レビューを行う
↓
リモートのdevelopブランチにマージする。

### 開発途中で、ブランチを切るのは忘れて、直接developブランチにpushしてしまったルート
ローカルのdevelopブランチで改修を行う
↓
リモートのdevelopブランチにマージ

#クライアント側で設定方法
1、git管理配下に下記のファイルを追加する

```bash
#!/bin/sh
# project_root/.git/hooks/pre-push
not_allowed_branchies="develop"

read local_ref local_sha remote_ref remote_sha

remote_branch=`echo ${remote_ref} | awk -F "/" '{ print $NF }'`
for branch in `echo ${not_allowed_branchies}`
do
  if [[ "${remote_branch}" = "${branch}" ]]; then
    echo "***************************************************************"
    echo "Gitのクライアント側で、リモートのdevelopヘの直接pushを禁止されていました。"
    echo "リモートの${branch}ブランチへpushしようとしたので中断しました！"
    echo "***************************************************************"
    exit 1
  fi
done

```
2、ファイルの実行権限を与える

```
$ chmod 755 project_root/.git/hooks/pre-push
```

#リモート側での設定方法
gitlabの場合、プロジェクトのsetting画面で設定ができるので、詳細の設定方法は略します。

#参考先
http://www.denet.ad.jp/technology/2017/11/gitmasterdeveloppush.html
LaravelでAmazon ElasticCache(Redis)を使う

## 概要
Laravelのキャッシュの保存先にRedisを使いたかった。
クラスターモードを有効にして、Redis AUTHを使った時にLaravelでRedisの設定をググりながらやってたら、つまづいたのでメモとして残しておくこととする。

## 環境
- php7.1.16
- Amazon Linux 2
- Redis 5.0.3
- Laravel 5.6

## 手順
1. AWSのElastiCacheコンソールからRedisを作成する
2. ノードのタイプとか用途に応じて設定する  
        今回だと「クラスターモードが有効」かつ送信中の暗号化とRedis AUTHを使う  
3. 作成したRedisに適切なセキュリティグループを設定する
4. composerでpredisをインストール
5. envとconfigのdatabaseをredisを使うように変更する

### 作成したRedisに適切なセキュリティグループを設定する
今回はLaravelがあるEC2とRedisは同一のVPCにいる前提
インバウンドにRedis作成時に指定したポートと443を開ける(ソースはVPCのCIDRに絞る)
アウトバンドはすべてのトラフィックを許可

### envとconfigについて

```env
REDIS_HOST=設定エンドポイント
REDIS_PASSWORD=REDIS AUTHで指定したパスワード
REDIS_SCHEME=tls
REDIS_PORT=Redis作成時に指定したポート
```

```php:config/database.php
'redis' => [
    'client' => 'predis',

    'options' => [
        'cluster' => 'redis',
        'parameters' => [
            'password' => env('REDIS_PASSWORD', null),
            'scheme' => env('REDIS_SCHEME', 'tcp'),
            'port' => env('REDIS_PORT', 6379),
        ],
        'ssl' => [
            'verify_peer' => false,
        ],
    ],

    'clusters' => [
        'default'=> [
            // NOTE: これでないとError while reading line from the serve が出る
            'host' => env('REDIS_SCHEME', 'tcp')  . '://' .  env('REDIS_HOST', '127.0.0.1'),
        ],
        'options' => [
            'cluster' => 'redis',
        ]
    ],
],
```

## つまづいた時の検証方法等

### 設定エンドポイントにpingできるか
EC2にssh接続して`ping 設定エンドポイント`でpingできるか

### redisに接続できるか
今回は暗号化してるのでopensslコマンドでRedisに接続できるかを試す
[とても参考になった記事](https://access-jp.co.jp/blogs/development/161)

### predisを使ってLaravelプロジェクトからRedisに接続できるかどうか
app/Console配下に適当なコマンド作って、コマンド実行してRedisに接続できるかどうか

```php
// もうちょっと必要な情報もあったような・・・
$parameters = ['tls://設定エンドポイント'];
$options    = ['cluster' => 'redis'];

$client = new Predis\Client($parameters, $options);

$client->set('key', 'value');
$value = $client->get('key');
$client->del('key');
logger($value);

// もしくはopensslでredis接続しといて、MONITORとかで確認しててもよい
```

### キャッシュの保存先をRedisに変更してから
opensslでredis接続しといて、[MONITOR](https://redis.io/commands/MONITOR)で確認してキャッシュが保存されているかを確認する

## その他
今回はREDIS AUTH使ってたのでopensslでRedisに接続してましたが、
使ってなかったら普通にredis-cliで接続もできやす
[インストール方法](https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/red-ug/GettingStarted.ConnectToCacheNode.html#GettingStarted.ConnectToCacheNode.Redis)
HTML,CSSの知識（基本コード）


#はじめに

ただのcssメモ

#便利なcalc

（）で計算ができる。

```css:
.hoge{
height: calc(100% - 180px);
}
```

#要素の概念

参考文献
https://www.attend.jp/%E8%A6%AA%E8%A6%81%E7%B4%A0%E3%83%BB%E5%AD%90%E8%A6%81%E7%B4%A0%E3%83%BB%E5%85%84%E5%BC%9F%E8%A6%81%E7%B4%A0

<img width="829" alt="スクリーンショット 2019-05-13 16.04.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385774/40eaf247-892d-c837-0ca8-58c4858ea9f7.png">

<img width="823" alt="スクリーンショット 2019-05-13 16.04.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385774/abd5aa83-c2b9-d0ee-3171-2c0826252baf.png">



# インライン要素をインラインブロック要素に変更

要素を横並びにした上で横幅と高さを指定
aタグには、そのままでは大きさの指定ができない。


```css:
.hoge{
display: inline-block;
}
```
# ヘッダーとフッターの高さに合わせて隙間を合わせる。

```css:
.hoge{
padding: 70px 0px 45px;
}
```



#ボックスの角に丸みをつけたい場合

border-radiusは四角形の角を丸くするためのプロパティ
今回のように4pxと指定.半径4pxの円に相当する丸みになります。

```css:
.hoge{
border-radius: 4px;
}
```

#ボックス全体の大きさを変えたくない場合
全体に対して適用なので、*を使う。

```css:
*{
box-sizing: border-box;
}
```

#文字の間隔を調整

コメント

```css:
.hoge{
letter-spacing: 1px;
}
```

#背景画像の大きさ

| auto | サイズは自動的に決まる |
|:--|:--|
| contain | 縦横比を保ったまま、範囲内に全ての画像が入るように配置（縦か横に空白ができる） |
| cover | 縦横比を保ったまま、対象範囲を全て埋めるように配置（画像の縦かよこが切れる） |
| 長さ（例：980px） | 縦横を長さで指定 |
| パーセンテージ（例：60%） | 縦横を親要素に対する比率で指定 |コメント

```css:
.hoge{
background-size: cover;
}
```

#文字の行間広げる

行の高さを指定するプロパティで、ここでは行間を広げる

```css:
.hoge{
line-height: 2.5;
}
```

#要素の周りに線を引く


| none | なし（何も指定しないとnoneになる） |
| solid | １本線 |
| dashed | 破線 |
| dotted | 点線 |コメント

```css:
.hoge{
border: 2px solid #fff;
}
```

#親要素と同じ色にする指定

親要素と同じ色にするという意味で、透過しているような見た目になります。

```css:
.hoge{
background-color: transparent;
}
```

#マウスカーソルを指定するプロパティ

ボタンの上にカーソルが来ると形が変わるようになる。

```css:
.hoge{
cursor: pointer;
}
```

#要素の重なりを決める

ヘッダーが上に行くようにするのに使うよね。

```css:
.hoge{
z-index: 1;
}
```

#文字の太さを指定

この場合は、太字にしている


```css:
.hoge{
 font-weight: bold;
}
```
#、中央よせができないとき
ブロックの幅がコンテンツエリアいっぱいに広がっていると中央にならないよね

```html:
.hoge{
margin: 0 auto;
}
```

#position: relativeについて

現在の表示位置から相対的に要素の位置を動かしたいときに使います。

```css:
#relative {
  position: relative;
  top: 10px;
  left: 10px;
```


# position: absoluteについて

親要素を基準に、絶対的な位置を指定。
この「絶対的な位置」というのは、要素がどんな形であろうと、間に他の要素や余白が入っていようと、その位置に配置してくれるということ意味する。

>親要素はrelativeにしておく
absoluteを使って位置調整するときは、親要素にposition:relative（もしくはfixed）を指定する。これを忘れると基準位置がずれて思ったように表示されません。absoluteを使うときは、おまじないのように親要素もセットで変えるようにしましょう。

```css:
.hoge{
 position:  absolute;        /* 要素の配置方法を指定 */
    background-color: #ccc;     /* 背景色指定 */
    padding:  0;             /* 余白指定 */
    left:  0p;                /* 右からの位置指定 */
    top: 0;   
    bottom:  o;
}
```

# リセットCSS
```css:
body, html {
  height: 100%;
  background-color: white;
}

h1, h2, h3, h4, h5, h6, p, body {
  line-height: 1.77;
  font-size: 18px;
  color: #4a4a4a;
  font-family: sans-serif;
  margin: 0;
  padding: 0;
}
```

# ヘッダー固定.下段に張り付く形で設定する時に使用する。

```css:
.hoge{
bottom: 0;
}
```

# 位置を固定させる

```css:
.hoge{
position: fixed;
}
```