OmniAICreator/Qiita-1.07M huggingface dataset:
theshellレビュー

## 目次
1. 概要
2. インストール
3. 使ってみて
4. 総評


## 1. 概要

### theshell
> 出来る限りユーザーの邪魔をしないように設計されたデスクトップ環境です。ウィジェットツールキットとして Qt 5 を、ウィンドウマネージャとして KWin を使用します。パーソナルアシスタントが組み込まれています。
>> ArchWiki デスクトップ環境より引用
>> https://0e0.pw/vtjP

公式サイト
https://vicr123.com/theshell/

githubリポジトリ
https://github.com/vicr123/theshell

#### ※日本語対応がされておりません
公式サイトにて翻訳スタッフを募集しております
是非ご参加を！

## 2. インストール

※ArchLinuxにインストールすることが推奨です

#### 1. AURからインストール(ビルド作業有)

```bash
git clone https://aur.archlinux.org/theshell.git
cd theshell
makepkg -si
cd ../
rm -rf theshell
```

AURヘルパーを利用する場合は各種ヘルパーの使い方に沿ってインストールしてください。
ここではyayの場合を紹介します。

```bash
yay -Syu theshell
```


#### 2. 作者様リポジトリからインストール(ビルド作業無)

/etc/pacman.confに追加

```
[theapps]
SigLevel = Optional TrustAll
Server = https://vicr123.github.io/repo/arch/$arch/
```
追加後に

```bash
sudo pacman -Syu theshell
```

#### 共通の作業
ウィンドウマネージャの再起動をします
Xサーバーが再起動するのでCtrl + Alt + F1~6を押してコンソールに移動してから作業することをオススメします。

```
# Lightdm(GNOME, Plasma以外)の場合
  sudo systemctl restart lightdm
# sddm(Plasma)の場合
  sudo systemctl restart sddm
# gdm(GNOME)の場合
  sudo systemctl restart gdm

# 起動時のスプラッシュ画面(plymouth)が有効な場合はそれぞれの最後に-plymouthと付けてください。
# (例) lightdm-plymouth
```

各種ウィンドウマネージャでtheshellを選択しログインしてください。

初回起動時は短いセットアップが有ります。

はじめに言語を選択しますが、残念ながら日本語はまだ未実装なので自分が得意な外国語を選択してください。

その後は画面の指示に従ってください。
## 3. 使ってみて

Good :thumbsup:

- 動作が軽快
   + 無駄な機能が少ないので古いマシンでも快適に使えました。
- 美しいUI
   + Plasma5と同じQtツールキットが使われています。
   + アニメーションも多く使われており滑らかに動きます。

- 使いやすいタスクバー
  + 音楽の再生・停止やウィンドウの切り替えがスムーズに行なえます。


Bad :thumbsdown:

- 日本語未対応
   + 日本語対応済みのGUIアプリケーションも標準では外国語表記となります
- タブレット向けのUI
  + 設定画面などが全画面表示のみでシングルウィンドウだと設定が大変です。
  + 普通のウィンドウも全画面表示推奨です。

### 4. 総評
theshellは
- ノートパソコンやタブレット端末向け
- 日本語非対応な点に注意
- メインマシンには不向き
- 美しく軽快、さらに使いやすいいいデスクトップ環境
ぜひどうぞ！
vue.js [ vuetify ] 行と列の対応

# vue.js [ vuetify ] 行と列の対応

不用意にdevとか混在させても上手くいくだろうと思ってコーディングしてたらどんどんはまっていったので、最低限のテンプレートを備忘録として記す。
SPAを作成したかったので、App.vueからいろんなvueを呼び出し、router-viewで表示する。

## 基本構成
最初にmain.jsから呼ばれるvue

``` vue:App.vue
<template> <!-- vueの決まり -->
  <v-app> <!-- 最初に呼ばれるApp.vueの決まり -->
      <v-content>
        <v-container>
          <v-layout>
              <router-view></router-view>
          </v-layout>
        </v-container>
      </v-content>
  </v-app>
</template>

<script>
export default {
  name: 'App'
};
</script>
```

routerに呼ばれるvue

``` vue:About.vue
<template>
  <div class="about">
    <v-contaienr>
      <v-layout> <!-- row -->
        <v-flex></v-flex> <!-- column1 -->
          <p></p> <!-- row1 -->
          <p></p> <!-- row2 -->
        <v-flex></v-flex> <!-- column2 -->
      </v-layout>
    </v-contaienr>
  </div>
</template>
```

## 行と列の対応
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545043/e10cced5-28dc-17a1-61df-9cf794e25a01.png)

About.vueの画面上をグリッドで分割して見たとき、v-containerの子要素であるv-layoutが「行(row)」になる。以下、階層を下るたびに入れ替わる。
PCパーツとベンチマークテストについて

#はじめに
この記事は[RUNTEQ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/runteq) 8日目の記事です。
PCパーツと、その性能測定について書いていきたいと思います。
ベンチマークテスト用のフリーソフトの中からも、定番といわれているモノをピックアップしてみました。
Qiitaの記事としてはあまり適切ではないかもしれませんが、これなら内容がかぶらないかも？と思い書いていきます。

※ベンチマークは性能やスペックを表す指標。

#CPU編
CPUは制御装置、演算装置、レジスタ、クロックといった要素で構成されている高価な塊です。
そんなCPUを性能測定するのはコチラ[Cinebench](https://www.maxon.net/jp/%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88/%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89/)

試しにテストしてみました。 見た目はこんな感じです。左上にPCの構成。左下に自分のCPUとランキングがあります。
右側には…お洒落な写真がありますが、これはテスト時にパネルがモリモリめくれて写真が完成するような演出になっています。写真の完成速度＝CPUの性能といった感じです。
[![Image from Gyazo](https://i.gyazo.com/79a66f3e97108615cc98d8774cb049bf.jpg)](https://gyazo.com/79a66f3e97108615cc98d8774cb049bf)
core i7-8700k(6コア12スレッド)でテストした所、スコアは2822でした。

続いて、macbookproでも試してみました。CPUはcore i5-8257U(4コア8スレッド)、スコアは1630でした。

#メモリ編
データを一時的に保存しておくもの…です。
ベンチマークテストはあまりしないので、ここは割愛します。

#ストレージ編
SSDとかHDDと言われているモノ。
今回は、ベンチマークテストの機能はほぼ一緒ですが、windows用とmac用で別モノとなります。
windows用 [CrystalDiskMark](http://crystalmark.info/ja/download/#CrystalDiskMark)
mac用 [AmorphousDiskMark](http://www.katsurashareware.com/pgs/adm-j.html)

windows用で測定してみました。(Samsung SSD 960 EVO 500GB)
[![Image from Gyazo](https://i.gyazo.com/06e50a6788f858a437b8b9a296311849.png)](https://gyazo.com/06e50a6788f858a437b8b9a296311849)

とりあえず、一番上の欄を見てみます。
Read 2802 MB/s　Write 1773 MB/s　となりました。

#グラフィックボード編
最後に、グラフィックボード編。
基本的には映像を綺麗に出力するための部品ですが、最近はディープラーニング運用に適したモデルなども登場しています。

ベンチマークテストでは[3DMark](https://benchmarks.ul.com/3dmark)が有名です。

#まとめ
CPUをはじめ、PCパーツは世代やシリーズなどによって性能が変わります。
core i7なのに思ったほどサクサク動かない！といった事も起こりえます。
出来るだけ低コストで十分な開発環境を構築したい方や、スペックに悩みを抱えている方はこういったベンチマークテストの結果も参考にしてみると良いかもしれません。
Conoha で VPS を借りて SSH で公開鍵認証できるまで

Mac から VPS へ SSH で接続するまでの作業ログ。
大した作業じゃないけどすぐ忘れるので自分用にメモ

## 環境

[Conoha の VPS](https://www.conoha.jp/vps/?btn_id=header_vps)

Conoha コントロールパネルでサーバーを追加する。
今回は `アプリケーション：LAMP` を指定。
現時点では CentOS 8 らしい。

## 作業ユーザー作成

### クライアント環境から VPS にログインする

追加したサーバーの詳細画面から IP アドレスを確認し、root ユーザーでログイン

```
>>> ssh root@xxx.xxx.xxx.xxx -p 22
```

### VPS に作業用ユーザーを作成

```
# adduser tukanpo
# passwd tukanpo
```

### 作成したユーザーを wheel グループに追加

```
# gpasswd -a tukanpo wheel
```

>【追記】 
後で apache グループにも追加した

### sudo 設定ファイルを編集

```
# sudo visudo
```

２行目がコメントアウトされていたらコメントを外す

```
## Allows people in group wheel to run all commands
%wheel  ALL=(ALL)       ALL
```

## 秘密鍵・公開鍵の作成

### 作業ユーザーでサーバーにログインしなおす

VPS からログアウト

```
# exit
```

作業ユーザーでログイン

```
>>> ssh tukanpo@xxx.xxx.xxx.xxx -p 22
```

ユーザーの作業ディレクトリ直下に .ssh ディレクトリ作成

```
$ mkdir .ssh
$ chmod 700 .ssh
```

ログアウトして再びクライアントに切り替える

### クライアントで鍵を作成する

まだ未作成の場合は .ssh ディレクトリ作成

```
>>> cd ~
>>> mkdir .ssh
>>> chmod 700 .ssh
>>> cd .ssh
```

鍵を生成する (すでに存在していて使い回しでよければ不要)

```
>>> ssh-keygen -t rsa -b 2048
```

### クライアントの公開鍵をサーバーにコピーする

公開鍵をサーバー側の authorized_keys にコピーする

```
>>> scp id_rsa.pub tukanpo@xxx.xxx.xxx.xxx:~/.ssh/authorized_keys
```

### ホスト名で接続可能にする

.ssh ディレクトリの config ファイルを編集（なければ作成）

```
>>> vi config
```

下記を追加

```
Host tukanpo.net
  HostName xxx.xxx.xxx.xxx
  User tukanpo
  Port 22
  IdentityFile ~/.ssh/id_rsa
```

ホスト名で VPS に接続

```
>>> ssh tukanpo.net
```

おわり
EtherCAT開発方法    概要編



この記事は EtherCATについて語る Advent Calendar 2019 の7日目です。

昨日は@nonnoiseさんの [EtherCAT関連の名称まとめ](https://qiita.com/nonNoise/items/5a1b8c0b98f28cadda63) でした。

#はじめに

EtherCATを開発する上で、知っておくべき内容や開発手法について説明していきます。

シリーズものなので、以下にリンクをまとめる（予定）


#開発方法
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12499/74ba55db-0563-ee59-999b-da9d0b33ba13.png)

この図は、[EtherCATマスターブック 第1巻](https://www.switch-science.com/catalog/5919/)にて書き出した図で、最初に大きな分岐がある。

EtherCATには、二つの役割があり、

一括して集中管理を行う　＝＞　マスター

自分の機能や処理だけに集中する　＝＞　スレーブ

といった感じで、マスターとスレーブの２役がEtherCATを構成させる。

それぞれの開発方法やデバック方法が違うため、一般的には**どちらか一方**に集中して開発を行うが、
著者は研究者でマニアな事もあり、両方開発する事でEtherCATの理解を深めている。



#マスター開発

マスターとは、スレーブを一括して管理を行ったり、それぞれのスレーブに情報を伝達する**親**となる部分である。
マスターを開発する際は、最低限１台はスレーブが必要となる。

マスター側の開発は、主にデスクトップPCやノートPCなど、コンピュータで以下のような環境で開発する事が出来る。


- Windows 10 PC
    - TwinCAT（BECKHOFF）　有料ソフト
    - その他ベンダーの有料ソフト
    - [Simple Open EtherCAT Master SOEM](https://openethercatsociety.github.io/)

- Ubuntu PC (Linux)
    - [Simple Open EtherCAT Master SOEM](https://openethercatsociety.github.io/)
    - [PyEtherCAT](https://github.com/pyEtherCAT)

-  Raspberry Pi (Rasbian)
    - [Simple Open EtherCAT Master SOEM](https://openethercatsociety.github.io/)
    - [PyEtherCAT](https://github.com/pyEtherCAT)

自分は[PyEtherCAT](https://github.com/pyEtherCAT)の開発者で最も簡単な部分しか実装されていないが、EtherCATを理解するには最も適したシンプルなライブラリだと思っている。
（要するに高度な機能が実装できてなく、仕様通りの仕組みを丁寧に実装したまで）

また、大手ベンダーが手を出していないLinuxでの実装がよかったのかRaspberryPiでも動作するため、軽く試したい方は気にして見れいただければと思います。

PyEtherCATについての使い方は次回にご紹介いたします。


#スレーブ開発

さて、スレーブ側ですが、スレーブとは、**制御したいモータや機械**もしくは**制御に使うスイッチやセンサー**側を開発するという事です。

スレーブを開発するには以下の物を準備する必要があります。

- マスター機器
   - 上のマスターを構成するもの
   - マスター動作するシーケンサ
   - RaspberryPi + [PyEtherCAT](https://github.com/pyEtherCAT)
- スレーブIC
   - [EtherCATスレーブに使える半導体 (1)](https://qiita.com/nonNoise/items/8caacbaae9d31ffd63e4)
   - [EtherCATスレーブに使える半導体 (2)](https://qiita.com/nonNoise/items/6f6889fc8b30eb9cec1f)

- それらを使用したモジュール基板
    - [EtherCATスレーブ評価基板LAN9252使用](https://www.switch-science.com/catalog/5917/)
    - [EasyCAT](https://www.bausano.net/en/hardware/ethercat-e-arduino/easycat.html)
    - その他、各ベンダーが出すモジュール（使い方は各社に聞いて見て）

あぁ大変。

オススメは以下の機構で簡単に実験ができます。

##ArtifactNoiseモデル
- Raspberry Pi 3B+ (4Bでも)
- [PyEtherCAT](https://github.com/pyEtherCAT)
- [EtherCATスレーブ評価基板LAN9252使用](https://www.switch-science.com/catalog/5917/)
- [LED16モジュール](https://www.switch-science.com/catalog/5918/)

これらを組み合わせると、簡単なEtherCATについての理解する事ができる。


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

とりあえず、概要はこんな所で。

仕事でEtherCATを学ぶ方は、マスター側を攻めるのか、スレーブ側を攻めるのかを理解し、
ロボットや研究開発で使用する方は、両方を学ぶ必要があるんだなと覚悟をし、
マニアなのでどっちも触る！って方は、ぜひ次回も読んでいただければと思います！！

それでは、次回また！

北神 @nonNoise
AnsibleでCentOS7へJenkinsをインストールする

こちらは[Jenkins Advent Calendar](https://qiita.com/advent-calendar/2019/jenkins) 7日目の記事になります。

今回はJenkinsをCentOS7へAnsibleを使ってインストールするサンプル例について説明します。

# 利用するAnsible Playbook

* [ansible-playbooks-centos7/jenkins_install - GitHub](https://github.com/ansible-playbooks-centos7/jenkins_install)

# インストール手順

```shell
git clone https://github.com/ansible-playbooks-centos7/jenkins_install.git
cd jenkins_install
ansible-galaxy install -r roles/requirements.yml
ansible-playbook -i localhost, -c local install.yml
```

## Ansible変数ファイルの設定例

それぞれのAnsible Roleのページから確認します

### Boostrap
* [robertdebock/ansible-role-bootstrap: Prepare your system to be managed by Ansible. - GitHub](https://github.com/robertdebock/ansible-role-bootstrap)

### Docker
* [geerlingguy/ansible-role-docker - GitHub](https://github.com/geerlingguy/ansible-role-docker)

### Epel
* [robertdebock/ansible-role-epel: Install epel on your system. - GitHub](https://github.com/robertdebock/ansible-role-epel)

### Git
* [geerlingguy/ansible-role-git - GitHub](https://github.com/geerlingguy/ansible-role-git)

### Locale
* [robertdebock/ansible-role-locale: Configure locale on your system. - GitHub](https://github.com/robertdebock/ansible-role-locale)

### Java
* [geerlingguy/ansible-role-java - GitHub](https://github.com/geerlingguy/ansible-role-java)

### Jenkins
* [geerlingguy/ansible-role-jenkins - GitHub](https://github.com/geerlingguy/ansible-role-jenkins)

### Pip
* [geerlingguy/ansible-role-pip - GitHub](https://github.com/geerlingguy/ansible-role-pip)
JavaからMySQLにInsertした際、返り値にAuto_Increment_ID（自動採番値）を取得する

# はじめに
JDBCを利用して、JavaのコードからDBにレコードをインサートする際、Auto_Increment（オートインクリメント）される値を取得する方法を示す。

`SELECT LAST_INSERT_ID()`によって、最後に採番された値を取得することができるが、返り値として取得したい場合に利用できる。

# 使用環境
- MySQL 8.0
- Java 8

# 前提事項


まず、以下のようなデータベース／テーブルを作成する。
- データベース名　：　testdb
- テーブル名　　　：　test

ここで、testテーブルに`Auto_Incrementの設定を施した主キーであるidカラム`と`Char型のnameカラム`を用意する。

テーブルを作成するSQLは以下のとおりである。

``` 
CREATE TABLE test(
  id INT NOT NULL AUTO_INCREMENT,
  name CHAR(30) NOT NULL,
  PRIMARY KEY (id)
);
```

テーブルのカラム情報を確認すると（SHOW COLUMNS FROM テーブル名）、`主キーのidカラムにAuto_Incrementが設定されている`ことがわかる。

| Field | Type | Null | Key | Default | Extra |
|:-----:|:----:|:----:|:---:|:-------:|:-----:|
| id    | int  |  NO  | PRI | NULL    | auto_increment |
| name  | char |  NO  |     | NULL    |                |

# Auto_Increment_IDの取得方法
まず、Javaのソースを示す。

```Test.java
public class Test {

	public static void main(String[] args) {
		 int autoIncrementKey = 0;

	     try {
	     // ドライバロード
	     Class.forName("com.mysql.jdbc.Driver");

	     // MySQL に接続
	     Connection con = DriverManager.getConnection("jdbc:mysql://localhost/testdb?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC", "user", "password");
         
	     String sql = "insert into test(name) values (?)";
	     
         // ステートメント生成
         // ここでRETURN_GENERATED_KEYSを設定する
	     PreparedStatement stmt = con.prepareStatement(sql, java.sql.Statement.RETURN_GENERATED_KEYS);

	     stmt.setString(1, "XXX");
	     stmt.executeUpdate();

         // getGeneratedKeys()により、Auto_IncrementされたIDを取得する
	     ResultSet res = stmt.getGeneratedKeys();

	     if(res.next()){
	    	 autoIncrementKey = res.getInt(1);
	     }

	     System.out.println(autoIncrementKey);

	     res.close();
	     stmt.close();
	     con.close();

		} catch (Exception e){
			System.out.println(e);
		}
	}

}
```


PreparedStatementを生成する際、`第2引数にjava.sql.Statement.RETURN_GENERATED_KEYS`を設定する。

そして、stmt.exceuteUpdate()でInsert文を実行後、`stmt.getGeneratedKeys()`を実行することで、自動採番されたidを取得することができる。

# おわりに
生のJavaやSQLを利用する機会は少ないが、備忘録として。
get(key)等の引数に補完を利かせるTypeScript (メモ)

TypeScript でキー/バリューを与えたら、get(キー) のキーで補完が効く＆TSチェック入る、というクラスの作り方。具体的には、下記のようなことが可能なクラスをの作成方法。

```ts
    const a = new CompletionMap({
        aa: 1,
        bb: 2,
    })

    // 補完が効いて、'aa', 'bb' が選択可能になる
    a.get('aa')
    a.get('bb')

    // 値の書き換えも可能
    a.put('bb', 22)

    // 未知のキーはTS的に怒られる
    a.get('cc')
    a.put('cc', 3)

    // キー/バリューを加えることもできる
    const b = a.mergeValues({ cc: 3 })

    // 補完が効いて、'aa', 'bb', 'cc' が選択可能になる
    b.get('aa')
    b.get('bb')
    b.get('cc')

    // これは怒られる
    b.get('dd')
```

方法:



```ts
export declare type CMValue = any
export declare type CMKeyValues = { [key: string]: CMValue }

class CompletionMap<T extends CMKeyValues> {
    constructor (
        public _data: T = {} as T
    ) {
    }

    get (key: keyof T): CMValue {
        return this._data[key]
    }

    put (key: keyof T, value: CMValue) {
        this._data[key] = value
    }

    /**
     * 引数で追加のオブジェクトを受け取って、マージしたオブジェクトを返す
     */
    mergeValues<T2 extends CMKeyValues> (additions: T2): CompletionMap<T & T2> {
        return new CompletionMap<T & T2>({ ...this._data, ...additions })
    }

    /**
     * 引数でインスタンスを受け取る場合
     */
    static mergeInstance<U extends CompletionMap<CMValue>, T2 extends CMKeyValues> (
        instance: U,
        additions: T2
    ): CompletionMap<U['_data'] & T2> {
        return new CompletionMap<U['_data'] & T2>({ ...instance._data, ...additions })
    }
}

test('test', () => {
    const a = new CompletionMap({
        aa: 1,
        bb: 2,
    })
    expect(a.get('aa')).toBe(1)
    expect(a.get('bb')).toBe(2)
    // expect(a.get('cc')).toBe(3)
    a.put('bb', 22)
    expect(a.get('bb')).toBe(22)

    const b = a.mergeValues({ dd: 4 })
    expect(b.get('aa')).toBe(1)
    expect(b.get('bb')).toBe(22)
    // expect(b.get('cc')).toBe(3)
    expect(b.get('dd')).toBe(4)

    const c = new CompletionMap({
        ...a._data,
        cc: 3,
    })
    expect(c.get('aa')).toBe(1)
    expect(c.get('bb')).toBe(22)
    expect(c.get('cc')).toBe(3)
    // expect(c.get('dd')).toBe(4)

    const d = CompletionMap.mergeInstance(a, { dd: 4 })
    expect(d.get('aa')).toBe(1)
    expect(d.get('bb')).toBe(22)
    // expect(d.get('cc')).toBe(3)
    expect(d.get('dd')).toBe(4)
})
```
Nest.jsでSwagger (Open API) とバリデーション用のデコレータを記述する

@nestjs/swaggerが4.x（3.xと並行開発されていたnextブランチ）になり、Open API (Swagger 3.0) がサポートされるようになった。class-validatorを使ったバリデーションと組み合わせたときのデコレータの記述について、一般的なREST APIでの実装例を以下のサンプルプロジェクトにまとめた。

* Controllerクラス実装例：[todo.controller.ts](https://github.com/unhurried/fullstack-example/blob/v0.2.0/backend/src/controller/todo.controller.ts)
* Resourceクラス実装例：[todo.ts](https://github.com/unhurried/fullstack-example/blob/v0.2.0/backend/src/resource/todo.ts)
* Parameterクラス実装例：[list-query-param.ts](https://github.com/unhurried/fullstack-example/blob/v0.2.0/backend/src/param/list-qurey-param.ts)

以下では、サンプルプロジェクトを作成する際に気づいたことをまとめている。

##### クエリパラメータの記述方法

OpenAPI定義に利用する@ApiQuery（@nestjs/swagger）はMethod Decoratorのため、Controllerメソッドに設定する必要がある。一方でバリデーション定義（class-validator）ではProperty DecoratorをDTOクラスに設定する。それぞれ単純に設定すると似たような制約条件の記述場所が離れてしまうので、OpenAPIの制約条件をSchemaObjectに分離して、DTOクラスと同じファイルに記述するとよい。

my-controller.ts

```typescript
@Controller('path/to/controller')
class MyController {
  @ApiQuery({ 
    name: 'myParam',
    description: 'A query parameter',
    schema: MyParamSchema
  })
  @Get()
  get(@Query() query: MyQuery): MyBody { ... }
}
```

my-query.ts

```typescript
export class MyQuery {
  @MaxLength(32)
  myParam?: string;
}

const MyParamSchema: SchemaObject = {
  maxLength: 32,
  type: 'string',
}
export { MyParamSchema }
```

##### （参考）@ApiPropertyをクエリパラメータに使うときの問題点

単純にDTOクラスにOpenAPIの制約条件を記述する方法として、@ApiPropertyを使うことが考えられるが、このデコレータはリクエストボディに利用されることを想定しているようで、クエリパラメータに設定するとparameters直下に制約条件のプロパティが出力されて、OpenAPIの仕様違反となる。

```typescript
class MyQuery {
  @MaxLength(32)
  @ApiProperty({ maxLength: 32 })
  param?: string;
}
```

上記のDTOクラスから出力されるOpenAPIは下記のようになる。

```
parameters:
  - name: myQuery
    in: query
    maxLength: 100
```

（OpenAPI仕様上は下記のようにクエリパラメータの制約条件はschemaプロパティに指定する必要がある。）

```
parameters:
  - name: Offset
    in: query
    schema:
	  maxLength: 100
```

##### クエリパラメータで数値を受け取る

クエリパラメータには型を定義する方法がないため、Nest.jsではstring型として扱われる。数値用のバリデーションデコレータを利用できるようにclass-transformerを使ってnumber型で受け取るとよい。

```typescript
class QueryParam {
    @Type(() => Number)
    @Min(0)
    @ApiPropertyOptional({
      description: 'Offset',
      minimum: 0,
      example: 5,
    })
    offset?: number;
}
```

##### その他課題など

現時点では以下のような使いにくいポイントがある。（今後改善されていく？）

* @nestjs/commonで定義したリクエストは@nestjs/swaggerに反映されるが、レスポンスは反映されないため、別にOpenAPI用の定義を記述する必要がある。
  * 例えば、@HttpCode (common) でレスポンスのステータスコードを変更したとしても、Open APIドキュメントに反映するには別途@ApiResponse (swagger) を記述する必要がある。
* 別のライブラリのため当然だが、class-validatorと@nestjs/swaggerのアノテーションはそれぞれ設定する必要がある。
  * ドキュメントに記載する定義域と実際のバリデーションルールを分離したい場合は問題ないが、同じでよい場合は同じルールを2か所に記載することになる。
* Open APIドキュメントを出力するにはひと手間必要になる。（参考：[#158](https://github.com/nestjs/swagger/issues/158)）
ssh接続のセキュリティを高めたい

#sshのセキュリティを高めるために
今回もsshでログインする対象はUbuntu18.04です。
セキュリティを高めるためにやったこと

1. ポート番号変更
2. rootログイン禁止
3. aaa


##1. ポート番号変更

```
# vim /etc/ssh/sshd_config
```
でconfigファイルを開いて `Port 22`を探して任意のポートを入力しましょう
ウェルノウンポートなどがあるので考えて決めましょう。
ちなみに#は外さないとコメントアウトになっているので忘れずに外しましょう。
ただこれだけでは変更できないので、
SELinuxのポリシーに新たなポート番号を追加して、firewalldの設定も変えましょう。
この辺は調べたらすぐ出てきますね。

##2. rootログイン禁止

```
#PermitRootLogin no
```
同じように`PermitRootLogin`を探して`no`にしましょう

##3. 公開鍵を作成しよう
ここはのち書きますね
datetime_selectで年月日が「2000-01-01」になってしまった件

datetime_selectで年月日＋時刻を扱ったけれど、
年月日が「2000-01-01」になってしまった件。
自分の覚書として残します。
　
### バージョン
Ruby:2.6.3
Rails:5.2.3


### 状況
Scheduleモデルにdeadlineカラムを持たせただけ。

```ruby:views/schedules/_form.html.erb
<%= form_with(model: schedule, local: true) do |form| %>
  <div class="field">
    <%= form.label :deadline %>
    <%= form.datetime_select :deadline %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>
```
こんな入力画面。
![スクリーンショット 2019-12-07 18.56.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159704/e8d4747c-a78a-8804-5111-d4b1a4014891.png)

2019年12月25日 18:00で設定し、[Create Schedule]をクリック。
するとこうなる。
![スクリーンショット 2019-12-07 18.57.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159704/a01e7c0c-aa7f-48f1-c168-0f815f79397d.png)



### 原因
deadlineカラムがtime型だった orz

```ruby:db/schema.rb
  create_table "schedules", force: :cascade do |t|
    t.time "deadline"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
```
datetime型に直して解決！
![スクリーンショット 2019-12-07 18.56.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159704/59071a3b-bc57-b900-be8e-4da42261e72f.png)
Microsoft Learn 8日目

12月は、毎日 [Microsoft Learn](https://docs.microsoft.com/ja-jp/learn/) を受講していこうという記録。
※受講後に書き込むので公開に間に合わないこと多々あります(アドベントカレンダーの意味ｗ)

12/8 は
**Core Cloud Services - Azure アーキテクチャとサービスの保証**
 - Azure のリージョン ペアについて

を受講。以下、簡易メモ。

# Core Cloud Services - Azure アーキテクチャとサービスの保証
## Azure のリージョンペアについて
### リージョンペアとは
各 Azure リージョンは、同じ地域内の少なくとも300マイル離れている別のリージョンと組み合わされている。
この利点は、地域を超えてリソースをレプリケートして、自然災害、暴動、停電、または両方のリージョンに同時に影響を与える物理的なネットワーク障害などに起因する障害が発生する可能性を低減できる。
リージョンペアの例(画像は Microsoft Learn より拝借)
![5-region-pairs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141029/2eff084c-ffa9-4ec2-1e83-dd1b03ea0e23.png)
Twitterの呟き回数を可視化（期間ごとの行数を求める）

[前記事](https://qiita.com/KanikaniYou/items/ccebe7ff45c0fbd0698f)ではTwitterの用意している機能で保存した過去データをcsvに書き直しました。せっかく作ったcsvですので、これをもとに期間ごとにツイートした回数をグラフにしてみます。
以下の記事を参考にしています。

Pandas で時系列のデータを期間ごとに集計してまとめる https://qiita.com/ihgs/items/2aa5af86ae5c4a60b091

環境
Python3.6.5
Mac OS Mojave  10.14.4

matplotlib==2.2.2
pandas==0.23.0

```python:generate_timeplot.py
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

df = pd.read_csv('df_text_date.csv', parse_dates=[0], index_col=[0],encoding='utf16',engine='python',names=("date","text"))
```

csvを読み込む際に、engine = 'python'としないとエラーになりました。

Error in Reading a csv file in pandas[CParserError: Error tokenizing data. C error: Buffer overflow caught - possible malformed input file.]
https://stackoverflow.com/questions/33998740/error-in-reading-a-csv-file-in-pandascparsererror-error-tokenizing-data-c-err

期間内の行数の集計を、新しく追加したカラム'count'(デフォルト値=1)を合計することで行なっています。

```python:generate_timeplot.py
df['count'] = 1
df2 = df.resample('W').sum() 
fig, ax = plt.subplots(figsize=(250,8))

ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
ax.bar(df2.index, df2['count'])
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, fontsize=5);
df2.plot(kind='bar')
plt.show()
```
resampleメソッドの解説はこちらがわかりやすいです。

pandasで時系列データをリサンプリングするresample, asfreq https://note.nkmk.me/python-pandas-time-series-resample-asfreq/

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/c120e14b-c87b-a0f7-bbb7-58a217a93d12.png)


大学の授業期間中はツイート数が多い傾向などが読み取れそうです。今回はテキスト内容を全く使っていませんが、形態素解析+ネガポジ判定をうまく行えば気分の浮き沈みの可視化などもできそうですね。
今回のソースコードは以下にあります。
https://github.com/KanikaniYou/plot_tweet_graph
djangoのプロジェクトを作るシェル

Djangoのいろんなチュートリアル消化してるけど、はじめにプロジェクト作るところが飽きてきたー。のでシェル作成。プロジェクト名は「config」統一。

```shell-session:start_django.sh
#!/bin/sh

# 作業ディレクトリ作成＆移動
mkdir $1 && cd $1

# 仮想環境構築
python3 -m venv venv

# アクティベート
source venv/bin/activate

# djangoインストール
pip install django

# プロジェクト作成
django-admin startproject config .
```

実行権限を付与して、sourceで実行。※shで実行してもディレクトリを移動してくれないので注意。

```shell-session
$ chmod 755 django_start.sh
$ source ./django_start.sh <project_name>
```
Microsoft Learn 7日目

12月は、毎日 [Microsoft Learn](https://docs.microsoft.com/ja-jp/learn/) を受講していこうという記録。
※受講後に書き込むので公開に間に合わないこと多々あります(アドベントカレンダーの意味ｗ)

12/7 は
**Core Cloud Services - Azure アーキテクチャとサービスの保証**
 - Azure のデータセンターとリージョンについて
 - Azure の地域について
 - Azure の可用性ゾーンについて

を受講。以下、簡易メモ。

# Core Cloud Services - Azure アーキテクチャとサービスの保証
## Azure のデータセンターとリージョンについて
### リージョンとは
少なくとも 1 つのデータ センターを含む、また場合によっては待ち時間の短いネットワークでネットワーク構成された近隣の複数のデータ センターを含む地球上の地理的領域。
2018年12月時点で利用可能なリージョンは以下のようになっている。(画像は Microsoft Learn より拝借)
![2-regions-large.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141029/0b6f5c9f-3771-8998-8a63-7f17924a9871.png)

### 特殊な Azure リージョン
コンプライアンスまたは法的な目的に合致したアプリケーションを構築する場合に使用できる特別なリージョンがある。

## Azure の地域について
地政学的な境界または国境で定義する "地域" に世界が分割されている。
Azure の地域とは、データ所在地とコンプライアンスの境界を保持する2つ以上のリージョンを含む独立したマーケットを指す。
このような分割には利点があり
・データ所在地とコンプライアンスに関して特定の要件を持つお客様が、データとアプリケーションを近くの場所に維持できる
・データ所在地、主権、コンプライアンス、回復性に関する要件が地域の境界内で確実に遵守される
・大容量の専用ネットワークインフラストラクチャへの接続を通じて、リージョン全体の障害に耐えることができるフォールトトレランス性を備えている

## Azure の可用性ゾーンについて
### 可用ゾーンとは
Azure リージョン内の物理的に分離されたデータセンターのこと。
それぞれの可用性ゾーンは
・独立した電源
・冷却手段
・ネットワーク
を備えた1つまたは複数のデータセンターで構成されている。
可用性ゾーンを使用してミッションクリティカルなアプリケーションを実行できる。
可用性ゾーンをサポートしている Azure サービスは2つに分類されている。
・ゾーン サービス：リソースを特定のゾーン(仮想マシン、マネージド ディスク、IP アドレスなど) にピン留めする
・ゾーン冗長サービス：プラットフォームが複数のゾーンにわたって自動的にレプリケートされる(ゾーン冗長ストレージ、SQL Database など)
いつか使える(かもしれない) Laravel Tips

# TL;DR
[VALU Advent Calendar 2019](https://qiita.com/advent-calendar/2019/valu)の7日目の記事です。
今回はいつか使えるであろうLaravelの知見を列挙してみました。


## モデルとマイグレーションファイルとresourceのあるコントローラーを同時に生成する

いつも新しいファイルの生成時に使うそれぞれのコマンドたち

```bash
$ php artisan make:migration create_posts_table

$ php artisan make:model Post

$ php artisan make:controller Post
```

実はこれらは１つのコマンド実行できる

```
$ php artisan make:model Post -mcr
```

m : モデル
c : コントローラー
r : resource


新しい機能を作る時などに試して欲しい

## マイグレーションと同時にSeedingする
新しいマイグレーションファイルを作った時、ダミーデータでテストしたくなるのが常でしょう
しかし、dev環境などだとわざわざサーバーにssh接続してコマンドを打つのは面倒
そんな時、下記のようにマイグレーションファイルに追記すると、Seedingもできるようになります

```php
public function up()
{
    Schema::create('themes', function (Blueprint $table) {
        $table->increments('id');
        $table->text('name');
    });

    Artisan::call('db:seed', [
        '--class' => ThemesTableSeeder::class
    ]);
}
```

productionでは動かないようにするのも忘れずに

```php
public function up()
{
    Schema::create('themes', function (Blueprint $table) {
        $table->increments('id');
        $table->text('name');
    });

    if (app()->environment() != 'production') {
        Artisan::call('db:seed', [
            '--class' => ThemesTableSeeder::class
        ]);
    }
}
```


## `where`メソッドのTips

```php
$users = User::where('approved', 1)->get();
```

whereメソッドはカラム名とつなげることもできます

```php
$users = User::whereApproved(1)->get();
```


## リレーションにおけるN+1問題の解決
親レコードのものをこのようにforeach文などで回して表示したい場合があるとします

```php:index.blade.php
@foreach ($sessions as $session)
<tr>
  <td>{{ $session->created_at }}</td>
  <td>{{ $session->user->name }}</td>
</tr>
@endforeach
```
リレーション内容

```php:Session.php
public function user()
{
    return $this->belongsTo(User::class);
}
```

その時の間違ったコントローラーの書き方

```php
public function index()
{
    $sessions = Session::all();
    return view('sessions.index', compact('sessions');
}
```

これだと`Session`モデルのインスタンスを取得した後、ループが回るたびに`User`モデルのインスタンスを取得してしまい、表示数によっては負荷の大きい処理になってしまいます
そうならないための正しいコントローラーの書き方が以下になります

```php
public function index()
{
    $sessions = Session::with('user')->get();
    return view('sessions.index', compact('sessions');
}
```

`with`メソッドで事前にリレーション先のモデルのインスタンスを取得しておけば、ループで回したとしてもすでに取得したインスタンスを使うだけなので、処理がとても軽くなります
いわゆるEagerロードというやつですね

## リレーション先が空の場合の表示
ユーザーネームがない匿名ユーザーなどの処理に使えます
 bladeで処理する場合

```php
{{ $payment->user->name ?? 'Anonymous' }}
```

それより前にEloquentで処理する場合

```php
public function user()
{
    return $this->belongsTo(User::class)
      ->withDefault(['name' => 'Anonymous']);
}
```

```php
{{ $payment->user->name }}
```


## 簡略化した`Auth::user()->id`

ログイン中のユーザーIDが欲しい時にいつも使うであろう`Auth::user()->id`
しかし、こういう短い書き方もできます

```php
Auth::id()
```

`id`以外のプロパティも指定でき、ログアウト中は`null`になります

# 参考
[Laravel Daily](https://laraveldaily.com/)
シェルスクリプト exec コマンド

exec コマンドを使うと、同じプロセス内で外部コマンドが実行される。
用途として考えられるのは、もしラッパースクリプトを作って別のスクリプトを呼び出す必要がある場合、ラッパースクリプトから exec を使って別のスクリプトを呼び出すようにすれば、余分なプロセスを作成しないで済む。

##### exec コマンドを使わない場合
```bash:example1
$ ls
```
例えば、今のプロセスIDが500だとする。
何らかの外部コマンド（lsなど）を実行する前、まず新しいプロセスID（例えば、501）が生成される。
そして新しいプロセスID（501）で、ls コマンドが実行される。

##### exec コマンドを使う場合
```bash:example2
$ exec ls
```
例えば、今のプロセスIDが500だとする。
何らかの外部コマンド（lsなど）を exec コマンドを用いて実行すると、元のプロセスID 500 内で ls コマンドが実行される。

##### 標準出力をリダイレクトする
exec > output のように実行すると、それ以降実行されるコマンドの標準出力については、output ファイルにリダイレクトされる。
元に戻すためには、exec > /dev/tty を実行する。

```bash:example3
$ exec > output
$ pwd
$ exec > /dev/tty  # シェルの標準出力先を画面に戻す
$ pwd
/home/blueskyarea
cat output
/home/blueskyarea
```

##### 環境変数をすべて削除して実行する
exec env - scriptA で呼び出された scriptA はすべての環境変数が削除された状態で実行される。
※ bash では exec -c scriptA で同様の動きになる

```bash:example4
export MY_ENV=my-env
echo "${MY_ENV}" # my-env
echo "${LANGUAGE}" # en_US:
exec env - ./other-script.sh # "${MY_ENV}" や "${LANGUAGE}" などを参照しても空
```
Azureの基礎　その３

#コア Cloud Services - Azure アーキテクチャとサービスの保証
出展：https://docs.microsoft.com/ja-jp/learn/modules/explore-azure-infrastructure/index

##Azureのデータセンターとリージョンについて

###リージョンとは

・少なくとも1つのデータセンターを含む、または待ち時間の短いネットワークでネットワーク構成された近隣の複数のデータセンターを含む地球上の地理的領域

##Azureの地域

###Azureの地域とは
・データ所在地とコンプライアンスの境界を保持する 2 つ以上のリージョンを含む独立したマーケット
・各リージョンは1つの地域に属し、特定のサービスの可用性、コンプライアンス、データの保存場所/主権の規則が適用される

###地域に分割するメリット
・データ所在地とコンプライアンスに関して特定の要件を持つ利用者が、データとアプリケーションを近くの場所に維持できる
・データ所在地、主権、コンプライアンス、回復性に関する要件が地域の境界内で確実に遵守される
・大容量の専用ネットワークインフラストラクチャへの接続を通じて、リージョン全体の障害に耐えることができるフォールトトレランス性を備えている

##Azureの可用性ゾーン

###可用性ゾーンとは

・Azureリージョン内の物理的に分離されたデータ センター
・それぞれの可用性ゾーンは、独立した電源、冷却手段、ネットワークを備えた1つまたは複数のデータセンターで構成される（分離境界）
・1つのゾーンがダウンした場合、他のゾーンが動作を継続する
・可用性ゾーンは、高速なプライベート光ファイバーネットワークを介して接続される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/f7781bc8-65bb-52df-c447-83d872e1dd15.png)

##Azureのリージョンペア

###リージョンペアとは
・各Azureリージョンは、同じ地域内 (米国、ヨーロッパ、アジアなど) の少なくとも300マイル離れている別のリージョンと組み合わされている
・地域を超えて（仮想マシンのストレージなど）リソースをレプリケートして、自然災害、暴動、停電、または両方のリージョンに同時に影響を与える物理的なネットワーク障害などに起因する障害が発生する可能性を低減できる
・リージョンのペアは直接接続されており、地域の災害の影響は受けないよう十分に離れているため、これを使用すれば信頼できるサービスとデータの冗長性を提供することができる
・計画的なAzureの更新をペアになっているリージョンの1つずつにロールアウトすることで、ダウンタイムとアプリケーション停止のリスクを最小限に抑えることができる

##Azure 製品およびサービスのSLA

###パフォーマンスの目標

・SLAで定義されるパフォーマンスの目標は、各Azure製品およびサービスに固有

###アップタイムと接続性の保証

・一般的なSLAでは、対応するAzureの製品またはサービスごとに、99.9% (「スリーナイン」) から 99.999% (「ファイブナイン」) の範囲のパフォーマンスの目標のコミットメントを指定する

###サービスクレジット

・パフォーマンスの低いAzureの製品またはサービスに対する補償として、利用者へのAzureの請求に割引が適用される場合がある

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/00bf98f4-7625-fd7d-ca56-cf381bd8c1f5.png)

##Azureのアプリの信頼性を向上させる

###アプリの要件を理解する
・効率的で信頼性の高いAzureソリューションを構築するには、ワークロード要件を知る必要がある
・ソリューション内のAzure製品およびサービスのパフォーマンスの目標を定義するAzure SLAを理解しておくことが重要
・各Azure製品、サービスで障害が起きることを計画しておく必要がある

###回復性
・障害から回復して動作を続行するシステムの能力
・ダウンタイムまたはデータの損失を回避するように障害に対応すること
・回復性の目的は障害後にアプリケーションを完全に機能している状態に戻すこと

###コストおよび複雑さと高可用性
・可用性を高めると、ソリューションの複雑さとコストも増加する
・高可用性が要件に対してどの程度クリティカルであるかによって、アプリケーションのSLAに追加される複雑さとコストを処理する方法が決まる
枠外をクリックして閉じれるドロップダウンの実装

# 始めに
メニューなどでクリックしたらリストがドロップダウンで表示することがあると思いますが、その時関係のない場所をクリックしたら閉じるという機能をどう実装するかという話です。
（デザインが適当すぎるせいで伝わっているか不安・・・）
今回はVue.jsで実装する場合の説明をしたいと思います。

![ドロップダウン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187768/e5febd38-335a-a415-4a10-a8a0beda8fc9.png)

2020/04/16追記
色々記事を見ていたらどうやら`vue-click-outside`というライブラリがあるようで、これを使った場合は以下のような実装をしなくて良かったそうです＞＜
https://www.npmjs.com/package/vue-click-outside

なので、もし自前で実装する場合はどうするのかを知りたい方だけ続きを見てくださいm(_ _)m

# 実装方法
## 1. 全体をクリックしたときに閉じるようにする
まずは関係のない場所をクリックしてもイベントが拾えるようにwindowからイベントリスナーを拾います。
addEventListenerで登録してコンポーネント破棄時にイベントを消さないといけないので`this._onBlurHandler`という変数にメソッドを保存しています。

```javascript
new Vue.extend({
  mounted() {
    // windowにイベントリスナーをセットする
    window.addEventListener('click', this._onBlurHandler = (event) => {
      this.$data.isOpen = false; // 表示フラグをOFFにする
    });
  },
  beforeDestroy() {
    // コンポーネントが破棄されるタイミングにイベントリスナーも消す
    window.removeEventListener('click', this._onBlurHandler);
  }
});
```

## 2. 自分の要素に含まれない場所をクリックしたときだけ閉じる
上記のやり方でも閉じてはくれますが、ドロップダウンの中身をクリックしても閉じてしまいます。
ドロップダウンの中身をクリックしたときは何もせず、それ以外の場所をクリックしたときだけ閉じるようにする場合は、Elementにある`contains`メソッドを使ってチェックします。
具体的には`event.target`がイベントの元となったエレメントになっており、refで適当な場所を設定して、そのElementで`contains`メソッドを呼んで含まれているかのチェックをしています。

```javascript
window.addEventListener('click', this._onBlurHandler = (event) => {
  // targetがコンポーネントの中に含まれているものなら何もしない
  if (this.$refs.elRoot.contains(event.target)) {
    return;
  }
  this.$data.isOpen = false;
});
```

# 終わりに
関係のない場所をクリックしたときに閉じるという処理は意外とちゃんとやろうと思うと中々上手くいかなかったので記事にまとめました。
サンプルコードは以下に置きましたので興味がある方は確認してみてください。

<p class="codepen" data-height="370" data-theme-id="default" data-default-tab="js,result" data-user="wintyo" data-slug-hash="KKwpWag" style="height: 370px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="ドロップダウン">
  <span>See the Pen <a href="https://codepen.io/wintyo/pen/KKwpWag">
  ドロップダウン</a> by wintyo (<a href="https://codepen.io/wintyo">@wintyo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## 余談
ちなみにこのやり方をする前は閉じたくない要素に`stopPropagation`を呼んでwindowまでイベントが送られないようにしていました。ただこれすると他のドロップダウンをクリックしたときにそれ以外のドロップダウン要素が閉じてくれなかったりで色々難点がありました・・・。
【Rails】簡単に使える暗号化gem`attr-encrypted`を使ってみた

## はじめに
Railsアプリにおいて、ログインパスワードは**bcrypt**を使ってUserモデルに`has_secure_password`と記載すれば簡単に暗号化出来ます。

でも、それ以外にもトークンなど**そのまま保管したくない情報**が出たときどう処理するんだろう？と疑問が発生。

そこで調べたところ、**attr-encrypted**という便利なgemがあったので使い方をまとめました。

[こちらが公式のREADME](https://github.com/attr-encrypted/attr_encrypted)です。

## この記事が役に立つ方
- 暗号化は**bcrypt**の`has_secure_password`しか使ったことがない方

## この記事のメリット
- `attr-encrypted`を使って簡単に暗号化が出来るようになる

## 環境

```
macOS Catalina 10.15.1
zsh: 5.7.1
Ruby: 2.6.5
Rails: 5.2.4 
```

## 前提・目的

- 今回暗号化したいデータの**カラム名**：`hoge`
- **既存**の`Users`テーブルに`hoge`を暗号化して追加したい

## インストール方法

```ruby:Gemfile
gem "attr_encrypted"
```

```shell
bundle install
```
シンプルです。
## 使い方

### 1.マイグレーションファイルを作成
```shell
rails g migration AddAttrEncryptedToUsers
```

### 2.マイグレーションファイルを編集

```ruby:db/migrate/XXXXXXXXXXXXXX_add_attr_encrypted_to_users
class AddAttrEncryptedToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :encrypted_hoge, :string
    add_column :users, :encrypted_hoge_iv, :string
  end
end
```

`encrypted_カラム名`
`encrypted_カラム名_iv`
のように設定します。

### 3.`db:migrate`

```shell
rails db:migrate
```

### 4.Userモデルを編集

```ruby
class User
  attr_encrypted :hoge, key: 'This is a key that is 256 bits!!'
end
```

`attr_encryptes`の後に暗号化したい**カラム名**を記載します。

### 5.`rails s`

```shell
rails s
```
サーバーは再起動しておきます。

これで**準備は完了**です。

## 動作確認

`rails console`で確認します。

```ruby
user = User.new
=> #<User:XXXXXXXXXXXXXXXXX id: nil, created_at: nil, updated_at: nil, encrypted_hoge: nil, encrypted_hoge_iv: nil>
```
↓

```ruby
user.hoge = "foobar"
=> "foobar"
```
↓

```ruby
user
=> #<User:0x000055904fb92870
 id: nil,
 created_at: nil,
 updated_at: nil,
 encrypted_hoge: "暗号化された文字列",
 encrypted_hoge_iv: "暗号化された文字列">
```
↓

```ruby
user.hoge
=> "foobar"
```

`hoge`カラムはUsersテーブル上には存在しませんが、無事に暗号化されていて、呼び出しも出来ることが確認できました:v:

## 補足：生Rubyでの使用方法もREADMEに記載あり
READMEの**Usage**にはこんな風に書いてあります。

> If you're using an ORM like ActiveRecord, DataMapper, or Sequel, using attr_encrypted is easy:

ActiveRecordとかDataMapperとかSequelみたいな[ORM(Object-relational mapping)](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E9%96%A2%E4%BF%82%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0)を使うなら簡単に使えるよ！とのこと。

Railsアプリケーションであれば、普通**ActiveRecord**を使用していると思いますので、今回は**このパターン**のみ記載しました。

他に**PORO**(Plain Old Ruby Object：生Ruby)向けの使い方も掲載されていますので、ご興味のある方は[README](https://github.com/attr-encrypted/attr_encrypted)をご覧ください。


## おわりに
最後まで読んで頂きありがとうございました:bow_tone1:

こんなに簡単に使えると、かえって**「ホントに大丈夫なの？」**と考えてしまいますが、実際どうなんでしょう？:thinking:笑

## 参考にさせて頂いたサイト（いつもありがとうございます）
[GitHub - attr-encrypted/attr_encrypted: Generates attr_accessors that encrypt and decrypt attributes](https://github.com/attr-encrypted/attr_encrypted)
#Rails の FactoryBot + create_list で毎回ランダムに異なる値を 引数に与える方法は？

ないっぽいよ！ 愚直にeach  / map しよう。

```rb
%w(NYC Boston SF Austin).map do |tb_location|
  FactoryBot.create(:location, city: tb_location)
end
```

[create_list with different values for the same attribute · Issue #787 · thoughtbot/factory_bot](https://github.com/thoughtbot/factory_bot/issues/787)

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2816








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
【Twitter】ダウンロードした(自分のアカウントの)過去ツイートを綺麗なCSVにしたい

Twitterでは、「設定」>「アカウント」>「Twiterデータ」>「アーカイブをダウンロード」
に、自分の過去のツイートを全てダウンロードする機能が用意してあることはご承知の通りです。
<img width="494" alt="スクリーンショット 2019-12-07 17.53.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/56e85562-7c7d-2a58-3ecf-5086f18fe265.png">

ダウンロードしたファイルには過去のツイート、RTしたツイート、いいねしたツイートの情報、ダイレクトメッセージなどが含まれています。(通常は一緒にダウンロードされるindex.htmlを開くことで閲覧できるようですが、自分の場合にはindex.htmlがダウンロードされませんでした。なんでだろう)

____
#####2019/12/15 追記
#####index.html はそもそもダウンロードされない仕様に変更になっている模様です。
[BERTを理解しながら自分のツイートを可視化してみるハンズオン](https://qiita.com/yuki_uchida/items/09fda4c5c608a9f53d2f)
↑こちらの記事を読んでて気付きました。
↓(参考)
[【解決済】twitterの全ツイート履歴がダウンロードできない【方法】](https://www.spongy-pig.com/how-to-download-tweets)
____

テキストマイニングや何らかの分析を行いたい場合には tweet.json を読むことになると思います。本稿ではこちらのjsonファイルを、形態素解析などに使いやすいようなcsvに加工します。作成するcsvは「タイムスタンプ」と「テキスト本文」の2カラムです。

最終的にできるCSVのイメージ
<img width="500" alt="n5v579QliBDG6o51575723317_1575723341.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/2e251a4a-e2e3-26c5-b29d-33658173e545.png">


環境
Python 3.6.5
Mac OS Mojave 10.14.4

pandas==0.23.0

ダウンロードしたjsonを開くとこんな感じになっているとおもいます。
![tLvy3PlzlPJ2Khh1575731228_1575731416.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/1429600b-2249-7b6c-360e-45f4763019bb.jpeg)

赤いアンダーラインを引いた

```
window.YTD.tweet.part0 = 
```

は不要ですので消してください。そのうえで拡張子を .txt に変更し、作業するディレクトリに入れてください。


```python:read_dl_tweet.py
import pandas as pd
import json

tweets_file = open("tweet.txt", "r")
tweet = json.load(tweets_file)
```

上のスクリプトでpandasのdataframeとしてjsonを開きます。
カラムはたくさんあるのですが、必要なカラムだけを抜き出します。

```python:read_dl_tweet.py
df = tweet_data_frame.loc[:,["created_at","full_text"]]
```

csvにしていく際に改行やカンマなどの困った文字が入っているので、これらを除去します。
regex=Trueとしないとうまくいきませんでした。

```python:read_dl_tweet.py
df = df.replace(['\n',',','	','\r'],'',regex=True)
```

また、タイムスタンプの形式が、ソートに使えない形になっているので、これを読みやすい形に直します。pandasのto_datetimeメソッドで一発で変換できました。

```python:read_dl_tweet.py
df_date = pd.to_datetime(df["created_at"])
df["date_form"] = df_date
df_sorted = df.sort_values("date_form") 
df_text_date = df_sorted.loc[:,["date_form","full_text"]]
```

新しく作ったタイムスタンプでソートしています。

```python:read_dl_tweet.py
df_text_date.to_csv("df_text_date.csv", header=False, index=False,sep=',',encoding='utf-16')
```

csvを出力する際のオプションは適宜変更してください（区切りをタブにするなど）。

[次記事](https://qiita.com/KanikaniYou/items/166b847bacdf79e7422c)では作成したcsvから期間ごとのツイート数をグラフに出してみます。

今回のコード：　https://github.com/KanikaniYou/plot_tweet_graph
Golang 始めました

[Link-1]:https://github.com/ziutek/ftdi
[Link-2]:https://play.golang.org/
[Link-3]:https://www.codewars.com/
[slice-1]:https://qiita.com/mizukmb/items/b543f88bc37c9a75673f
[slice-2]:https://christina04.hatenablog.com/entry/2017/09/26/190000
[for-1]:https://qiita.com/high5/items/3fe34d2feeff2c11f5ca
[String-1]:http://knightso.hateblo.jp/entry/2014/06/24/090719
[String-2]:https://text.baldanders.info/golang/string-and-rune/
[play-1]:https://play.golang.org/p/X8E4i6V4ulG
[play-2]:https://play.golang.org/p/fsmQLy0TC3s
[play-3]:https://play.golang.org/p/8UEsr4yTXLu

#きっかけ
始めたきっかけはGolangの特徴である以下の特徴があったからです。

- コンパイラ言語
- オープンソース
- マルチプラットフォーム
- `C`ライブラリを使える(例えば、[`FTDI`のライブラリ][Link-1]など)

そして何より・・・
**流行ってる気がする事**

以前、トレンドになってると思ってたのですがその記事が見当たらなかったです

##やっている事
`Golang`を勉強するのに、以下のサイトを使っています。
>[The Go Playground][Link-2]
Web上でコンパイルと実行してくれる便利なやつ

>[codewars][Link-3]
この問題集を解いています。楽しい

##勉強した事
スライス、制御構文の書き方、文字列についてを勉強しました。

- スライスについては以下の記事を参考にしました。
    - [Go言語 スライスの確認][slice-1]
    - [
GolangのSliceを関数の引数に渡した時の挙動][slice-2]
- 制御構文に関しては、以下の記事を参考にしました。
    - [golangを基礎から学ぶ　制御構造編][for-1]
- 文字列については、以下の記事を参考にしました。
    - [Go言語のstring, runeの正体とは？ - golang][String-1]
    - [String と Rune][String-2]

##試してみて引っかかったところ
- [`for range`はスライスや配列をコピーして処理を行う][play-2] 
    - プレイグラウンドで試しています。`for range`で値を順番に取り出す場合はスライスや配列は取り出す様にコピーを行なっている様なので、コピー元となる配列の内容をいじっても取り出される順番は変わりません。
- [`String`を使わずに文字列の順序を逆順にする][play-2]
    - `String`から`for range`で一文字づつ抜き出す場合は、`rune`型としなければいけない

##作ってみたもの
>[素数間距離(prims gap)][play-1]
Codewarsの問題の一つ。素数判別に余剰計算を行なっている。正しく判定してくれはするが、処理回数が多すぎてランダムテストがパスできない

#最後に
Golangは楽しい
Laravel 5.8 + dockerで新規プロジェクトを作成する

dockerコンテナでlaravelのスタータープロジェクトを作成します。

# 手順

## 1. ベースイメージの作成

php７.２をベースに composer + laravel 5.8のイメージを作成する

```Dockerfile
FROM php:7.2-fpm
COPY php.ini /usr/local/etc/php/

RUN apt-get update && \
    apt-get install -y \
    libpq-dev \
    zlib1g-dev && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

RUN pecl install xdebug && docker-php-ext-enable xdebug
RUN docker-php-ext-install zip pdo

# install composer
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

# setup composer
ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME /composer
ENV PATH $PATH:/composer/vendor/bin
ENV PATH $PATH:/app/vendor/bin

# instal laravel
RUN composer global require "laravel/installer"
```

```bash
$ docker build . -t laravel-base
```

## 2. 作成したベースイメージでlaravelアプリケーションを生成する

```bash
$ docker run -w / -it laravel-base bash
(laravel-base) # laravel new app
$ docker cp <container id>:/app .
```

さっきビルドしたlaravel-baseを使って `laravel new app` コマンドを実行。
出力されたファイルをホストPCにコピーします。

## 3. 実行

```bash
$ docker run -v app:/app -w /app -p 8000:8000 -it laravel-app php artisan serve --port 8000
```
Twitterで任意の画像を一括ダウンロードするのに苦労した話

## 概要

諸事情で、ある有名人のTwitter上にあるファンアートを集めることになりました。

## 環境

- macOS Mojave 10.14.6
- PHP 7.3.12
- pip 19.3.1
- python 3.7

## 要件

- ある有名人のTwitter上にあるファンアートを集める
    - Twitterで特定のワードで検索した時に表示される画像を集める
    - 期間は2年以上前から現在まで

名前を出すことができないので、仮に「ハリネズミ」の画像を集めることとします。
集めるべき画像は、Twitterで「ハリネズミ」「Hedgehog」と検索したときに表示される画像です。

## 結論

google-images-downloadで「Twitterから『ハリネズミ』と検索したとき」に表示される画像を一括DLする。

```
googleimagesdownload -ri -cd "./chromedriver" -l 1000 -k "site:twitter.com ハリネズミ"
```

## 試したこと

以下の2つを試しました。

1. Twitter Search API
2. google-images-download

### Twitter Search API

Twitterの画像をDLするなら、TwitterのAPIを使おうというところで、「Twitter Search API」を使うことにしました。

#### Twitter開発者登録し、APIキー等を発行する

自分の場合は、数年前に開発者登録をしてテスト用のAPIキーを発行していたので、そのAPIキーを使いました。
初めてTwitter開発者登録をされる方はここら辺を見るとよいかもしれません。

https://qiita.com/kngsym2018/items/2524d21455aac111cdee

#### OAuth認証して、APIを叩く

コードはGitHubにあげておきます。READMEを見ればすぐに使うことができます。
https://github.com/ntask19/collect_twitter_image

#### APIの制限に引っかかる

しかしながら、無料で検索できる範囲が過去7日間ということが判明し、Twitter Search APIでは要件を満たすツールが作れないことが判明しました…。

![スクリーンショット 2019-12-09 18.16.32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36927/3e519f1e-82c9-8d47-b608-b546f1dde86e.jpeg)

https://developer.twitter.com/en/docs/tweets/search/overview


### google-images-download

そこで、機械学習の画像集めに使われる「google-images-download」を使うことにしました。

詳細はこの記事を見るのが早いです。

https://qiita.com/Ikko_Kojima/items/4d943c60ff5e886a0544

#### google-image-downloadのインストール

```
pip install google_images_download
```

#### chromedriverのダウンロード

画像を1000枚以上一括DLするにはchromedriverが必要になるので、[こちら](https://chromedriver.chromium.org/downloads)からDLします。現在使っているGoogle Chromeとバージョンが合わないと正常に作動しないので注意が必要です。

ダウンロード後は、zipファイルを解凍してコマンドを実行するディレクトリの直下に置きます。

![スクリーンショット 2019-12-13 23.17.20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36927/bc3fe67d-5dbf-c97f-8ee6-5f0b5e212ba7.jpeg)

コマンドをtmpディレクトリ上で行う場合の設置例。

#### google-image-downloadの実行

google-image-downloadの使い方は簡単で、以下のコマンドを実行すると、Googleで「ハリネズミ」と検索したときの画像を1000枚ダウンロードしてくれます。

```
googleimagesdownload -ri -cd "./chromedriver" -l 1000 -k "ハリネズミ"
```


普通に検索すると、Twitter以外の画像もDLしてしまうので、[高度な検索](https://support.google.com/websearch/answer/2466433)をつかって、Twitterに投稿された画像のみをDLするようにしています。

```
googleimagesdownload -ri -cd "./chromedriver" -l 1000 -k "site:twitter.com ハリネズミ"
```

## 最後に

Twitter Search APIの実装に結構時間を喰った結果、使えないことが分かったので、もっと早くgoogle-image-downloadの存在に気づけばよかった…。
macOSのアップデート通知を表示しない方法

# はじめに
基本的にOSは常に最新の状況を維持しましょう！

とは言いつつ、諸事情によりmacOSをアップデートしたくない方もいると思います。
そのような方のためのtipsです。

# 方法
1. アップデート通知を出さない方法

```shell:設定方法
softwareupdate --ignore "macOS Catalina"
```
```shell:解除方法
softwareupdate --reset-ignored
```
2. 「システム環境設定」のアイコンについているバッチを消す方法

```shell:設定方法
defaults write com.apple.systempreferences AttentionPrefBundleIDs 0
killall Dock
```
解除は、システム環境設定→ソフトウェアアップデート→「アップデートを確認」をOFF,ONとすると復活します。

##  参考
https://applech2.com/archives/20191014-softwareupdate-ignore-macos-catalina-in-system-pref.html
効率の悪い移動を繰り返すと自責の言葉を表示するVimプラグイン

アドベントカレンダー初参加です。

# はじめに
みなさんは効率の良い・素早い移動を心がけているでしょうか？

本記事で吊るし上げる「効率の悪い」移動とは、

**h/j/k/lを連打もしくは長押しすること**

です。

効率の悪い移動を控えるように矯正し、f/F、その他検索やジャンプなどを使う癖をつけたいものです。

# 動作例

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">悪い行いを自覚し改めなければならない <a href="https://t.co/gqGaiC6O0L">pic.twitter.com/gqGaiC6O0L</a></p>&mdash; まとるる (@_matoruru) <a href="https://twitter.com/_matoruru/status/1203225307437617152?ref_src=twsrc%5Etfw">December 7, 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://t.co/f4TlDl8Aqn">pic.twitter.com/f4TlDl8Aqn</a></p>&mdash; まとるる (@_matoruru) <a href="https://twitter.com/_matoruru/status/1203225982556966912?ref_src=twsrc%5Etfw">December 7, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

自責の言葉やフロートウインドウの大きさ、効率の悪い移動の許容範囲・回数は変更可能です。

# 「自責」[^1]
[^1]: [三省堂 大辞林 第三版](https://www.weblio.jp/content/%E8%87%AA%E8%B2%AC)

*自分で自分のあやまちを責めること。*

**似た言葉**
恥じる  恥じ入る  慙愧  悔いる  悔やむ

# 矯正方法の例

- h/j/k/lを無効化する
    - 突然なくなるのは苦しいかもしれません。
- h/j/k/lを押すと保存せずにVimを閉じる
    - どこかの記事でみた気がしますが、過激過ぎます。
- **h/j/k/lをある回数以上繰り返したときに自責の言葉を表示する**
    - 本記事で紹介する方法（プラグイン名: [vim-hjkl-warning](https://github.com/matoruru/vim-hjkl-warning)）です。

# 仕組み

移動する度に移動距離の測定と回数のカウントを行い、効率の悪い移動を繰り返し行った時に自責の言葉を表示するようにしています。

# 設定例1

```vimscript
let g:hjkl_warning_win_width    = 10
let g:hjkl_warning_win_height   = 3
let g:hjkl_warning_min_column   = 5
let g:hjkl_warning_min_line     = 2
let g:hjkl_warning_max_repeat   = 8
let g:hjkl_warning_message      = ["わたしには", "学習能力が", "ありません"]
let g:hjkl_warning_enable_title = v:false
```

横方向に5文字未満、もしくは縦方向に2文字未満の移動を8回を超えて連続で繰り返した時、以下のように表示されます。
<img width="156" alt="Screenshot 0001-12-07 at 5.58.47 PM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304979/73c21a7c-b923-580e-320d-92b690f1b33c.png">

設定例2

```vimscript
let g:hjkl_warning_win_width    = 2
let g:hjkl_warning_win_height   = 1
let g:hjkl_warning_min_column   = 3
let g:hjkl_warning_min_line     = 1
let g:hjkl_warning_max_repeat   = 5
let g:hjkl_warning_message      = ["😡"]
let g:hjkl_warning_enable_title = v:false
```

横方向に3文字未満、もしくは縦方向に1文字未満(つまり縦方向では判定されない)の移動を5回を超えて連続で繰り返した時、以下のように表示されます。
<img width="95" alt="Screenshot 0001-12-07 at 6.07.35 PM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304979/605e4317-3758-599e-0692-522ac1b62f39.png">


# リポジトリ

<a href="https://github.com/matoruru/vim-hjkl-warning"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/matoruru/vim-hjkl-warning.png?ver=1" width="460px"></a>

# おわり

記事を読んでくれてありがとうございます😊

プラグインを作ったのは初めてで、かつあまり時間を割けなかったため、作りが甘い・良くない可能性が高いと思っています。例えば、pluginディレクトリとautoloadディレクトリの違いをあまり理解せず、全てpluginディレクトリの1ファイルで済ませてしまっています(これを逆手にとり、「そんな感じでもプラグイン作れるんだ」という気軽な気持ちでプラグイン作成に挑戦してみても良いと思います🙂)。

ご意見やアドバイスなどあれば、ぜひコメントしてください。

ここまで読んでくださってありがとうございます！

Twitterフォローしていただけると嬉しいです！
https://twitter.com/_matoruru