OmniAICreator/Qiita-1.07M huggingface dataset:
yarnとは？【フロントエンドパッケージ管理】



#概要
・npm互換のフロントエンドパッケージマネージャー
・facebookが開発した
・npmと同じことをできる
・npmとコマンドがちょっと違う（結構似てる）

※npmが分からない人はこちらの記事を先にチェック
[npmとは？](https://qiita.com/minato-naka/items/fc74f6c9439ab59cec63)

## npmと比べたメリット
・パッケージインストールが早い
→キャッシュ利用したり、並行インストールしたりできる
・メンバー間での厳格なバージョン固定共有が可能
→yarn.lockファイルによってバージョン固定される

#使い方
・`yarn init`
→package.jsonが作られる

・`yarn install`（開発時はこうする）
[yarn.lockがすでにある場合]
→package.jsonのdependenciesとdevDependenciesに書かれているパッケージをインストールする
→各パッケージはyarn.lockに記載されているバージョンがインストールされる

[yarn.lockがない場合]
→package.jsonのdependenciesとdevDependenciesに書かれているパッケージをインストールする
→yarn.lockを作成し、インストールした各パッケージのバージョン情報を記述する

※省略して `yarn` だけでも実行できる

・`yarn install --production`（本番環境ではこうする）
→package.jsonのdependenciesに書かれているパッケージをインストールする
→各パッケージはyarn.lockに記載されているバージョンがインストールされる

・`yarn add {パッケージ名}`
→そのパッケージがpackage.jsonのdependenciesに追記される
→yarn.lockにインストールしたパッケージのバージョンが追記される
→本番環境だけで必要なパッケージはこうする

・`yarn add --dev {パッケージ名}`
→そのパッケージがpackage.jsonのdevDependenciesに追記される
→yarn.lockにインストールしたパッケージのバージョンが追記される
→開発時のみ必要なパッケージはこうする
→例えばテストツールやデバッグツールなど

・`yarn upgrade {パッケージ名}`
→package.jsonに記述されている範囲でそのパッケージが更新される
→更新したバージョンがyarn.lockに記載される
→パッケージ名を省略すれば全パッケージが更新される


# 開発時の流れ
## 最初にプロジェクト作成する人
・`yarn init` でpackage.jsonを作成
・`yarn add {パッケージ名}`で本番用パッケージをpackage.jsonに追加&yarn.lockにバージョン情報追加
・`yarn add --dev {パッケージ名}`で開発用パッケージをpackage.jsonに追加&yarn.lockにバージョン情報追加
・package.jsonとyarn.lockをプッシュして共有

## プロジェクトに参加したメンバーたち
・`yarn intall` でみんなと同じパッケージをインストール
※この時、各パッケージはyarn.lockに記述されているバージョンがインストールされるため、チームメンバーと同一バージョンをインストール可能

## 新しいパッケージを入れるとき
・`yarn add {パッケージ名}` でインストールしてローカルで動作確認
・package.jsonとyarn.lockをプッシュして共有


# タスクランナーとして利用
npmと同様に、yarnもタスクランナーとして利用可能。

`package.json` の `scripts` にコマンドを記述。

```js
"scripts": {
    "{呼び出しキーワード}": "{実行されるシェルコマンド}"
}
```

そして、
`yarn run {呼び出しキーワード}`
のように実行すれば、package.jsに記述したシェルコマンドが実行される。

例えば
babel変換やwebpackのバインド処理など
長くてオプションが複雑なコマンドを、
`build` のような短いキーワードで登録しておき
`yarn run build` だけで実行できるようにしたりする。



# yarn自体のインストール
## windows、mac
公式サイトからインストーラダウンロード
https://yarnpkg.com/en/docs/install#windows-stable

##linux
###debian
```shell
sudo apt update && sudo apt install yarn
```

###centos
```shell
sudo yum install yarn
```


#参考
https://ics.media/entry/13838/
https://qiita.com/senou/items/d939601e32c0005ebfe3
https://yarnpkg.com/ja/
https://yuta-yamamoto.hatenablog.com/entry/2018/11/12/222001
【学習ノート】AWS SAA取得に向けて(VPC)

# VPC(Virtual Private Cloud)
利用者ごとにプライベートなネットワークをAWS内に作成するサービス。
ただし、***S3、CloudWatch,DyanamoDBなどVPC内に入らないサービスも多数存在する。***

## IPアドレス
- CIDRブロックは***/16から/28の範囲***で作成可能
    - あとから拡張するのは困難なので大き目に作成することが推奨されている

## サブネット
VPCに設定したCIDRブロックの範囲に収まる小さなCIDRブロックをアサインする機能。
サブネット作成時のポイントとしては、***同一の役割を持ったサブネットを複数のAZにそれぞれ作成する***[^1]こと。

- 個々のサブネットは1つの仮想ルータを持つ
    - この仮想ルータがルートテーブル、ネットワークACLを持つ
    - またサブネット内のEC2インスタンスのデフォルトゲートウェイになる

## ルートテーブル
- 個々のサブネットに1つずつ設定する
- 1つのルートテーブルを複数のサブネットで共有することができる
    - 但し、1つのサブネットに複数のルートテーブルは適用できない
- 宛先アドレスとターゲットゲートウェイ(ネクストホップのアドレス)を指定する
- VPCにはメインルートテーブルが存在する
    - サブネット作成時にルートテーブルを作成しない場合、デフォルトのルートテーブルとして利用される

## セキュリティグループ
EC2、ELB、RDSなど***インスタンス単位のイン/アウトバウンド通信制御***を行う

- ステートフルな通信
    - 応答トラフィックはルールに関係なく通信が許可される
- 制御項目
    - プロトコル
    - ポート範囲
    - 送受信先のCIDR/セキュリティグループの指定
        - セキュリティグループはデフォルトでアクセス拒否設定(ホワイトリスト方式)

## ネットワークACL
***サブネットごとにイン/アウトバウンド通信の制御***を行う

- ステートレス
    - 応答トラフィックであろうと明示的許可設定がなければ通信を遮断する
- 制御項目
    - プロトコル
    - ポート範囲
    - 送受信先のCIDRの指定
        - セキュリティグループによる通信先の指定はできない
        - セキュリティグループと異なりデフォルトでアクセス許可設定(ブラックリスト方式)

## GW(ゲートウェイ)
VPCの内部/外部でやり取りする出入り口

### IGW(インターネットゲートウェイ)
インターネットと接続するためのゲートウェイ
ルートテーブルでIGWをターゲットに指定するとインターネットへの通信になる
また、インターネット上のAWSサービスに接続する方法としては、VPCエンドポイントを利用する方法がある

- マネージドサービス
- EC2インスタンスがインターネット通信をするためには、以下のいずれかの対応が必要になる
    1. インスタンスにパブリックIPを設定する
    2. NATゲートウェイでアドレス変換する

### VGW(仮想プライベートゲートウェイ)
オンプレ拠点とつなげるためのゲートウェイ
ルートテーブルでVGWを設定すると、宛先アドレスとの通信は

- 接続には以下のようなサービスを利用する
    - VPN
    - Direct Connect
- オンプレミスネットワークの宛先を指定する方法
    - 各ルートテーブルに静的に設定する
    - ルート伝搬(プロパゲーション)機能で同的に反映する

### VPCエンドポイント
インターネット上のAWSサービスに接続する方法のひとつ

- ゲートウェイエンドポイント
    - ***S3,DynamoDB***と接続するために利用する
        - 他のサービスの接続には下記のインターフェイスエンドポイントを利用する必要がある
    - インターフェイスエンドポイント(AWS PrivateLink)
        - それ以外の大多数のサービスで利用する

## ピアリング接続
- 2つのVPC間をプライベートに接続する
- 異なるAWSアカウント間のVPCも接続可能
- 利用時の注意事項
    - VPCピアリング時の通信相手はEC2インスタンス等になる
        - IGW、VGWなどへ接続することはできない
        - 相手先のVPCがピアリングしている別のvpcへは推移できない
            1. AからBのVPCへピアリング
            2. AはBのVPCを踏み台にして、BとピアリングしているCのVPCへは推移できない

## VPCフローログ
- VPC内の通信解析を行う
- VPCフローログはENI(Elastic Network Interface)単位で記録される
- VPCフローログの記録項目
    - 送信先/元のアドレス
    - ポート番号
    - プロトコル番号
    - データ量
    - 許可/拒否の区別

[^1]: マルチAZ構成
npmとは？【フロントエンドパッケージ管理】

# 概要
・Node Package Managerの略
・フロントエンドで使用するパッケージの管理をする（依存解決、一括インストールなど）
→例えばCSSフレームワークのbootstrap、jsフレームワークのvue.js、
あとはよくあるちょっとしたjsモジュールのシャドーボックスとかスライダーとか
・パッケージ名がNodeだが、Node用のツールというわけではない
・package.jsonに必要なパッケージ、バージョンを記述して管理する
・node_modulesディレクトリ配下に、インストールしたパッケージのソースが配置されていく

※npmの改良版的なツールである【yarn】についても合わせて読むといい
[yarnとは？](https://qiita.com/minato-naka/items/94c8e76f8a440690d4b3)

# 使い方概要
・`npm init`
→package.jsonが作られる

・`npm install`
→package.jsonのdependenciesとdevDependenciesに書かれているパッケージをインストールする
→開発時はこうする

・`npm install --production`
→package.jsonのdependenciesに書かれているパッケージをインストールする
→本番環境ではこうする

・`npm install {パッケージ名}`
→そのパッケージがインストールされる
→自分の環境だけで試しにインストールしたいときに使う

・`npm install --save {パッケージ名}`
→そのパッケージがpackage.jsonのdependenciesに追記される
→本番環境だけで必要なパッケージはこうする

・`npm install --save-dev {パッケージ名}`
→そのパッケージがpackage.jsonのdevDependenciesに追記される
→開発時のみ必要なパッケージはこうする
→例えばテストツールやデバッグツールなど


# 開発時の流れ
## 最初にプロジェクト作成する人
・`npm init` でpackage.jsonを作成
・`npm install --save {パッケージ名}`で本番用パッケージをpackage.jsonに追加
・`npm install --save-dev {パッケージ名}`で開発用パッケージをpackage.jsonに追加
・package.jsonをプッシュして共有

## プロジェクトに参加したメンバーたち
・`npm intall` でみんなと同じパッケージをインストール
※この時、各パッケージはpackage.jsonに記述されているバージョンの範囲内で最新がインストールされるため、
完全にチームメンバーと同一バージョンがインストールされるわけではない
https://qiita.com/sotarok/items/4ebd4cfedab186355867

## 新しいパッケージを入れるとき
・`npm install {パッケージ名}` でインストールしてローカルで動作確認
・`npm install --save {パッケージ名}` でpackage.jsonに追記
・package.jsonをプッシュして共有


# その他コマンド
・インストール済みパッケージのバージョン確認
`npm list --depth=0`

・パッケージの更新
`npm update {パッケージ名}`
→package.jsonに記載したバージョンの範囲で更新する
→package.jsonに記載の範囲を超えてバージョンアップしたい場合はpackage.jsonを書き換える
→パッケージ名をスペース区切りで複数記述できる
→パッケージ名を省略すると全パッケージを一括更新する

・パッケージのアンインストール
`npm uninstall {パッケージ名}`
`npm uninstall --save {パッケージ名}`
`npm uninstall --save-dev {パッケージ名}`


# タスクランナーとして利用
npmのメイン機能はパッケージ管理だが、
タスクランナーとしての機能もある。

`package.json` の `scripts` にコマンドを記述。

```js
"scripts": {
    "{呼び出しキーワード}": "{実行されるシェルコマンド}"
}
```

そして、
`npm run {呼び出しキーワード}`
のように実行すれば、package.jsに記述したシェルコマンドが実行される。

例えば
babel変換やwebpackのバインド処理など
長くてオプションが複雑なコマンドを、
`build` のような短いキーワードで登録しておき
`npm run build` だけで実行できるようにしたりする。



# npm自体のインストール方法
※Node.jsをインストールすると、npmも一緒に使えるようになる
## windows, macの場合
https://nodejs.org/en/download/

## linux

### debian
```shell
sudo apt install nodejs
sudo apt install npm
```

### centos
```shell
sudo yum install nodejs
sudo yum install npm
```

## docker
https://hub.docker.com/_/node/
node.jsのimageでコンテナ作成

# 参考
https://qiita.com/maitake9116/items/7825d90c09f3e2f87dea
https://qiita.com/heyheyww/items/092fcbc490a249a2d05c
https://qiita.com/chihiro/items/ca1529f9b3d016af53ec
NuxtJS+TypeScriptの環境を爆速で作る

備忘録。以前nuxtjs + typescript環境の構築に非常に時間がかかった。 
 
が、[こちら](https://github.com/nuxt-community/typescript-template)のnuxtコミュニティが提供するテンプレートを使用すると爆速で開発のボイラーが出来上がる。


## Installation

```
$ npm install -g @vue/cli
$ npm install -g @vue/cli-init
```

```
$ vue init nuxt-community/typescript-template my-project
$ cd my-project
# install dependencies
$ npm install # Or yarn install
```

## Usage

###Development

```
$ npm run dev
```

http://localhost:3000  
にアクセス。

## Production

```
# build for production and launch the server
$ npm run build
$ npm start
```
Parallels 15.1.1でUbuntu 18.04が外部ネットワークに繋がらなくなった

# 環境
- Parallels 15.1.1
    - バーチャルマシンのネットワーク設定で「共有ネットワーク（推奨）」を選択している。(ネットワークの設定パネルへは、バーチャルマシンウインドウ右上の歯車アイコンをクリックして、Hardwareのアイコンをクリックすると辿り着ける)
- ゲストOSは、Ubuntu 18.04
- ホストOSは、MacOS 10.15.1 Catalina
- Window Managerは、[Maxx Interactive Desktop](https://www.facebook.com/maxxdesktop/)を使用。

<img width="500" alt="Screen Shot 2019-11-11 at 00.01.07.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145550/308b960f-469d-d674-b0fe-d2984588ea19.jpeg">
# 問題
ホストOSからゲストOSのUbuntu 18.04へssh接続できなくなった。また、ゲストOSのUbuntu 18.04からインターネットへ接続できなくなった。
# 解決策
```Reinstall Parallels Tools```をアップデートする。

注意点として、メニューバーの```Actions```から```Reinstall Parallels Tools```を選択しても、一向にアップデートまたはインストールが完了する気配すらない。

[こちらの方法](https://kb.parallels.com/121370)で手動でアップデートする必要があった。

補足ですが、マック本体のリスタートが必要です。再起動後、**linuxゲストOSのターミナル**で、`ip a`を打って、"10.211.55..."などの数字が出ていると、多分通ってます。
AmazonECRに学習済みモデルをデプロイする流れ（Docker利用）

# 学習済みモデルをデプロイ

DockerイメージのデプロイにはAmazon ECR を使う
[Amazon ECR（Docker イメージの保存と取得）| AWS](https://aws.amazon.com/jp/ecr/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33329/f9387986-3987-6187-3fb6-84db54b911d7.png)

これを見ておくと良さそう
**Amazon ECR における Docker の基本**
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/docker-basics.html

Dockerのセットアップが終わったら次をやる
[Amazon ECR の使用開始 - Amazon ECR](https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/ECR_GetStarted.html)
※そのまえに以下のセットアップを終わらせる
[Amazon ECR でのセットアップ - Amazon ECR](https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/get-set-up-for-amazon-ecr.html)


Dockerイメージの管理にはAmazon ECSを使う


# 参考
[Amazon SageMakerを使った学習済みモデルの流用　〜　ここどこサーチのデプロイまで - Qiita](https://qiita.com/nekia/items/f16af3dbbf2ce8beaafa)
CentOS6のLet'sEncryptのcertbot-autoが途中で止まる

# 現象

```
$ ./certbot-auto
...
Creating virtual environment...
Installing Python packages...
```
上記になるまでにすごい時間がかかる上、これ以降は動かない。

# IPv6が邪魔していた

wgetなどでも時間がかかっていた。
ので、無効化した。

参考：http://www.1x1.jp/blog/2013/03/disable_ipv6_on_centos6.html

```
$ vi /etc/sysctl.conf 
最後に追記
# ipv6 disable
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

$ /sbin/sysctl -p
```
cakephp2 DBに画像が保存されている場合、カラムを更新しない

# DBにデータがある場合にカラムを更新しない
## 前提
ユーザーページで”コメント”と”ユーザー画像”を編集が可能になっている

## やりたいこと
DBに画像ファイルが保存されていて空のまま更新ボタンを押した時に空の値を更新するのではなく、そのまま画像を表示させたい。

##　方法①
現在DBに入っているデータを取得して更新する。

```UsersController.php
if ($this->request->is('post') || $this->request->is('put')) {
     $img = $this->request->data['User']['image_name']['tmp_name'];//一時保存パス
     $image_name = $this->request->data['User']['image_name']['name'];//ファイル名
     if ($image_name) { //ファイルが選択されていればimgディレクトリに移動
          $this->request->data['User']['image_name'] = $image_name; 
          move_uploaded_file($img, '../webroot/img/' . $image_name);
     } else {//ファイルが選択されなければテーブルデータのファイル名取得
          //該当するidのimage_nameカラムの値を取得
          $image_name = $this->User->find('first', array('conditions' => array('id' => $id), 'fields' => 'image_name'));
          $this->request->data['User']['image_name'] = $image_name['User']['image_name'];
     }
     if ($this->User->save($this->request->data)) {//postされたデータをデータテーブルに保存
          $this->Flash->success(__('ユーザー情報を編集しました'));
          return $this->redirect(array('action' => 'view', $id));
     }
     $this->Flash->error(__('ユーザーを登録できませんでした。やり直してください。'));
} else {
     $this->request->data = $this->User->findById($id);
     unset($this->request->data['User']['password']);
}

```

## 方法②
ファイルが選択されていない場合はimage_nameカラムを更新しない

```UsersController.php
	if ($this->request->is('post') || $this->request->is('put')) {//postもしくはputのリクエストが行われた場合
			$img = $this->request->data['User']['image_name']['tmp_name'];//image_name配列の一時保存パスを代入
			$image_name = $this->request->data['User']['image_name']['name'];//image_name配列のファイル名を代入
			if ($image_name) {//ファイルが選択されていればimgディレクトリに移動
				$this->request->data['User']['image_name'] = $image_name;//DBに保存するファイル名
				move_uploaded_file($img, '../webroot/img/' . $image_name);//imgディレクトリにファイルを保存
				$this->User->save($this->request->data);//リクエストされたデータを保存
				$this->Flash->success(__('ユーザー情報を編集しました'));
				return $this->redirect(array('action' => 'view', $id));
			} else {//ファイルが選択されていない場合
				$this->User->save($this->request->data, false, array('comment', 'id'));//コメントとIDを保存
				$this->Flash->success(__('ユーザー情報を編集しました'));
				return $this->redirect(array('action' => 'view', $id));
			}
			$this->Flash->error(__('ユーザーを登録できませんでした。やり直してください。'));
     } else {
			$this->request->data = $this->User->findById($id);
			unset($this->request->data['User']['password']);
     }

```
下記同じ処理を2回行なっているため一回で行う方法はないか？

```
$this->Flash->success(__('ユーザー情報を編集しました'));
return $this->redirect(array('action' => 'view', $id));
```
【AfterEffects, Premiereエラー対処】 avconvert completed with error:1650549857.

#エラー
macで画面収録した動画(.mov)をPremire ProおよびAfter Effectsにインポート（取り込む）際に起きたエラー。備忘録

 avconvert completed with error:1650549857.
premiere pro ディスク上のファイルを読み込むことができません


#動作環境
macOS Mojave, After Effects CC, Premiere Pro CC, QuickTime Player

#問題
画面収録した動画ファイルが壊れている可能性があります。
なお、QuickTIme Playerでは再生できる。

#対処
.movをQuickTime Playerで同じファイル形式で再変換する（書き出す）。
画質はやや下がる。（感覚的）

#気をつけること
低スペックならば、画面収録後は保存が完了するまで、しばらく待った方がいいと思います。
保存直後にMacのクイックルックで動画ファイルを再生するなど。（スペースキーでの動画再生を避ける）
部分テンプレートでスッキリ！！ ❏Rails❏

#部分テンプレートとは
複数のビューファイルで共通する部分をテンプレート化する。そのまま！
例えば、ヘッダーやサイドバーなどはいくつかのビューで使い回せる可能性が高い。

#つくりかた
```_form.html.erb
<%= form_with model: thing do |form| %>
  <%= form.text_field :name %>
  <%= form.submit %>
<% end %>
```
①ファイル名を_から始める。
②共通する部分のみを記述。

#呼び出し方
```new.html.erb
<%= render partial: "form", locals: { thing: @thing } %>
```

```edit.html.erb
<%= render partial: "form", locals: { thing: @thing } %>
```

新規登録画面と編集画面です。
form_withさんが自動的にcreateアクションかupdateアクションへ振り分けてくれるおかげで、どちらも同じ記述です。

注意点としては
①partial: のあとに部分テンプレート名を記述。その際は_を除く。
_form.html.erb → partial: "form"

②locals: のあとに部分テンプレート内で使う変数を定義する。
この場合、部分テンプレート内でthingを使っていることから、コントローラーから渡された@thingをthingに変更。
locals: { thing: @thing }

---
ちなみに、呼び出す際に部分テンプレートが同じフォルダ内にある時は①の記述で構いません。以下。

```
・ views
  ・ things
    ・ _form.html.erb
    ・ new.html.erb
    ・ edit.html.erb
```

```
<%= render partial: "form", locals: { thing: @thing } %>
```

<br>
しかし、以下のように部分テンプレートが別のフォルダに存在する場合は、

```
・ views
  ・ layouts
    ・ _form.html.erb
    ・ application.html.erb 
  ・ things
    ・ new.html.erb
    ・ edit.html.erb
```

```
<%= render partial: "form/layouts", locals: { thing: @thing } %>
```

フォルダ名を/のあとに記述します。

<br>
また、partial,localsの省略も可能です。

```
<%= render "form/layouts", thing: @thing %>
```

<br>
<br>
ではまた！
日付フォームの差分計算

日付フォームの差分計算についてのメモ。もっと上手いやり方があるかもしれません。

## 作ったきっかけ

弊社で運営している自動見積書発行システム[「マイ見積」](https://my-mitsu.com/)で、ホームページ上で期間設定できたら便利だろう、ということで、フォームに日付（開始日と終了日）を設定できるようにしました。　

### html部分

html5 の、input type="date"機能を使いました。以下のようなhtmlです。

```html
<input type="date" id="Dates1_start" name="Dates1_start" value="2019-11-16" min="2019-11-16" max="2020-01-10" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
```

モダンなブラウザなら、カレンダー表示して日付を選べるようになっています。

![date-form.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31643/69b68706-86e3-e329-6154-f0f73ae58cc0.png)

### 日付の差分計算

原始的な方法ですが、「日付をマイクロ秒に変換して、86400000で割る」で実装しました。

```javascript
var Dates1_start = new Date( Dates1_startval );
var Dates1_end = new Date( Dates1_endval );
var Dates1_day = Math.floor((Dates1_end - Dates1_start + 86400000)/86400000);
```

86400000を足しているのは、開始日と終了日が同じだった場合に日数を1にしたいからです。

### サンプルページ

実際に動いている例は、[広告掲載期間設定して見積書発行](https://my-mitsu.com/sample/advertisement)をごらんください。
閉包テーブル(Closure Table)で子ノードを取得してみる

# やったこと
RDBでツリー構造を表現する手法の１つである閉包テーブルで
特定のノードに隣接する子ノードの一覧を取得する方法を模索してみた。

# 前提条件

以下の前提条件を設定

- 親ノードは１つまでとする  
※閉包テーブルのデータ構造は、複数の親ノードを持つこともできるみたいだが今回なし

上記前提がないと問い合わせ結果が正しく得られない

__ツリー構造のイメージ__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514634/89354742-765d-8486-86a3-fa7688e74fbd.png)

# 特定のノードと子孫ノードの距離を算出する

特定のノードを基準としたとき、関連する子孫のノードが特定のノードと
どのぐらいの位置関係にあるかを算出する。

__登録するデータ__
閉包テーブルでは子孫、祖先という形で対象ノードの関係性をすべて登録しておく
矢印の向かう元が子孫ノード、矢印の向かう先が祖先ノードを指す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514634/db1f1d47-ed5e-2a97-61bf-2ff26c575401.png)

__テーブルとカラム__
- `tree`・・・閉包テーブル
- `descendent` ・・・子孫ノード
- `ancestor`・・・祖先ノード

```sql
SELECT t0.descendent
      ,count(*) as depth
  FROM tree t0 
  WHERE EXISTS ( 
      SELECT 1 
        FROM tree t1 
       WHERE t1.ancestor   = 'B(対象ノード)'
	     AND t1.descendent = t0.ancestor
    )
 GROUP BY descendent
```
1. 祖先ノードが対象ノード(B)のデータを取得する
ノードBに向かって矢印が伸びているもの 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514634/436210be-87ef-6284-95d8-52931df3c740.png)  
 

2. 1.で該当したデータの子孫ノードを祖先ノードとするデータを取得する
BDEFGに向かって矢印が伸びているもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514634/d9b7fa22-7d90-e2ec-6668-dc2db3292af2.png)  

3. 2.で該当したデータを子孫ノードでデータ数を集計する
子孫ノードから出ている緑の矢印を数える
親ノードが1つである前提があることで、対象ノードまでの距離とすることができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514634/66aa6fdb-f2b8-3e23-3aa5-4e6ff07c3566.png)  

# 特定のノードの子ノードを取得する
特定のノードからの距離の算出が上記でできるので距離が2のものを取得する
距離を変えることで孫を取得できるが親が複数あるときにどの親の孫であるかはわからない

```sql
SELECT t0.descendent
      ,count(*) as depth
  FROM tree t0 
  WHERE EXISTS ( 
      SELECT 1 
        FROM tree t1 
       WHERE t1.ancestor   = 'B(対象ノード)'
	     AND t1.descendent = t0.ancestor
    )
 GROUP BY descendent
HAVING depth = 2
```
Rubyでオブジェクト指向を使った簡単なRPG風の戦闘画面をターミナル上で作ってみた

# Rubyで勉強がてら、オブジェクト指向を使った簡単なRPG風の戦闘画面をターミナル上で作ってみた

## 前置き
Qitta初投稿です。不慣れなところもしばしばあるとおもいますが、ご了承ください。
最近Railsばかり触っていたもので、たまには原点に立ち返って素のままのRubyをいじってみたいと思い作ってみました。

## ソースコード

```ruby:character.rb
class Character

  attr_accessor :name, :hp, :power

  def initialize(name, hp, power)
    @name = name
    @hp = hp
    @power = power
  end

  def attack(target)
    puts "#{@name}が#{target.name}に#{@power}のダメージを与えた!"
    target.hp -= @power
  end

  def killed(target)
    return target.hp <= 0
  end

end

```

actorとenemyの**親クラス（継承元）**
基本ここにactorとenemyがもっている共通の属性と振る舞いを記述することで
継承先はCharacterクラスと同じ振る舞いを持ったそれぞれの独立したクラスになる

```ruby:actor.rb
require "./character"

class Actor < Character

  def victory(target)
    puts "#{self.name}は#{target.name}を倒した！"
  end

  def lose
    puts "#{self.name}は死んでしまった"
  end

end

```
 **子クラス**であるactorには勝利したときのメソッドと敗北したときのメソッドを独自に定義

```ruby:enemy.rb
require "./character"

class Enemy < Character

  def attack(target)
    if self.name == "スライム"
      self.power = rand(30)
    elsif self.name == "ゴーレム"
      self.power = rand(20..50)
    end
    super
  end

  def show
    puts "#{self.name}が現れた!"
  end
  
end

```

同じく**子クラス**であるenemyにも、showメソッドを定義し、attackメソッドは親クラスから**オーバーライド**し、メソッドの中身を上書き

```ruby:game.rb
require "./actor"
require "./enemy"

class Game

  @@level = 0

  def self.start
    case @@level
    when 0
      name = "スライム"
    when 1
      name = "ゴーレム"
    else
    end
    actor = Actor.new("主人公", 100, 30)
    enemy = Enemy.new(name, 100, 5)
    enemy.show
    while true
      puts "--------------"
      puts "コマンドを選択してください。"
      puts "--------------"
      puts "[1]: たたかう"
      puts "[2]: にげる"
      puts "--------------"
      input = gets.to_i
      case input
      when 1
        actor.attack(enemy)
        if actor.killed(enemy)
          actor.victory(enemy)
          @@level += 1
          if @@level == 2
            puts "ゲームクリア！おめでとう！"
            exit
          end
          self.continue
        end
        enemy.attack(actor)
        if enemy.killed(actor)
          actor.lose
          self.continue
        end

      when 2
        puts "にげました。"
        exit
      else
        puts "そんなコマンドないよ"
      end
    end
  end

  def self.end
    puts "終了しました！"
    exit
  end

  def self.continue
    puts "もう一度プレイしますか？"
    puts "[1]: Yes"
    puts "[2]: No"
    input = gets.to_i
    if input == 1
      self.start
    elsif input == 2
      exit
    end
  end

end

while true
  puts "ゲームを開始しますか？"
  puts "[0]: start"
  puts "[1]: end"
  input = gets.to_i
  case input
  when 0
    Game.start
  when 1
    Game.end
  else
    puts "値が不正です！"
  end
end
```

最後にGameクラスでactorとenemyを呼び出して、それぞれのクラスのインスタンス変数とインスタンスメソッドを使い、戦闘画面を実装（ここらへんのコードは結構冗長になってしまいました^^;）

## まとめ

現段階では、コマンドの種類が「たたかう」、「にげる」しかなく、「どうぐ」や「まほう」とかもないのでそういった機能を追加するなど、まだまだやれることはあると思います。

まだまだ知識不十分ですが、これからも温かい目で見ていただければと思います^^;

ここが間違ってる、こうした方が良い、という意見がございましたらどしどしコメントしてください（語彙力なくてすいません）。
プログラミングスクールの就活に関する実態

#初めに
今回ある転職保証タイプのプログラミングスクールで転職活動を行ってきたので、その実態を報告したいと思います。
プログラミングスクールについて調べて方は薄々感づいているかも知れませんが、ほとんどが良い事しか書かれていませんよね？
なので、ここでは良かった点と悪かった点を含め感じた事を書いていきます。
**プログラミングスクールでの学習については以前にレポートしていますので、[こちら](https://qiita.com/mailok1212/items/be69d9558a42583ed238)をご覧ください。**

#スクール入学前の話
スクールに入学する前に必ず面談を行わなければいけません。
そこで、面談担当者に以下のような質問をしました。
##Q1.転職先として提案できる企業はどのような所がありますか？
A.提携企業な200社ほどあり、ほとんどがWeb系の企業です。割合は、自社開発６割、受託開発２割、SES２割です。
##転職活動などのように行いますか？
A.数ある企業の中から、専属の担当者と相談しながらワンツーマンで企業選び〜転職活動をしていく。

#転職活動前準備
転職活動の前準備として、履歴書、職務経歴書の添削や面接対策などを行います。

##良かった点
履歴書、職務経歴書の添削や面接対策として質問される傾向の高い質問に対する深堀りをするので、面接時にあたふたすることはありません。
##悪かった点
専属のキャリアサポーターと面談形式で実施するするのですが、受講生30名×3ヶ月分の人数をたった2人で対応する為、待ち時間が非常に長いです。
1週間近く待たされることはざらのようにあります。
面談では基本的に話を聞いているだけでなのですが、くだらない話が大半なので非常に退屈でした（個人差はあると思います）

#転職活動の条件
転職活動を始める直前に転職についての条件を聞かれます。
例えば、年収〇〇〇万円以上とか、正社員なのか非正規なのかなどです。
その希望条件に合った企業案内されます。

##私が提示した条件
1.正社員であること
2.Ruby,PHP,Pythonを扱う開発の仕事をしたい（そこのスクールでRubyについて学習したので）
3.SESはNGで、自社開発もしくは受託開発企業
以上のような条件を提示した結果、3番については濁されました。
その場で理由を聞くと有耶無耶にされましたが、転職活動を開始してすぐに理由はわかりました。
その理由は、後ほど、、、

##具体的な転職活動について
事前の面談では、専属の担当者と相談しながらワンツーマンで企業選び〜転職活動をしていくとの事でしたが実際は全く異なりました。
実際には、転職活動前に提示した条件とマッチする企業にスクール側が書類を提出し、書類審査に通過した企業の面接案内が送られてくるというものでした。
（書類審査が通った企業しか案内が来ない為、どこに提出しているかは全く分かりません。また、教えてもくれません）

#転職活動開始
基本的には書類審査通過のお知らせが来るまで待機です。
書類審査が通過すると、面接の日程を聞かれるので希望を言えば後はセッテングしてくれます。

##良かった点
・書類の提出を向こうでやってくれるので楽。
・面接のセッテングも適当な希望日を言うだけで、セッテイングしてもらえる。
・面接の日程が決まると、メールが来て以前行った人が面接で聞かれた質問が記入されているので前準備に役立つ。

##悪かった点
・どこの企業に書類を提出しているか分からない（聞いても教えてもらえない）
・書類審査が通った企業の面接を蹴ることは出来ません。（内定の拒否は出来る）

#転職活動をしていて思った事
恐らくプログラミングスクールで、転職を考えている方は下記の事を知っておいた方が後々後悔しないかもしれません！
##良かった点
・1ヶ月で14社の面接をセッテングしてもらえた。
・実務未経験だがスクールの働きかけで、未経験以上の給料を確約してくれている

##悪かった点
・マッチする企業に書類を提出するといっていたのですが、全くの嘘で全く提示した条件にマッチしていない企業からの書類審査通過の案内がありました。
例えば、開発を希望していたのにインフラのみの企業や業務で一切プログラミングを扱わずExcelしか扱わない企業などです。
しかもタチの悪いことに、面接での事業説明でそれを知ることも１度や２度ではありません。
・面接に行った企業の約7割がSES企業でした。
事前にSESは２割と言っていましたが、あれは嘘で実際は8割近いと思います。
自社開発、受託開発は少ないから、私が提示した条件の３番は濁されたのだと思います。
・Rubyでの開発が第１条件と言ったのですが、Rubyでの開発をしている企業は０で、全部Javaでの開発でした。

#転職保証について
私の行っていたスクールは転職保証がついていたので、転職が成功しないと全額返金されます。
しかし、内定と蹴った場合は返金の対象外となります。

#最後に
プログラミングスクールについて良い事を書いている記事は山ほどありますが、逆はなかったので今回体験談を書きました。
恐らくどこのスクールも事前の面談を設けているいると思いますので、この記事を頭に入れてから面談で質問してみると入学後に後悔しないかもしれませんね！
集中力の低下して中書いた記事なので、かなり読みにくい記事だったと思いますが長々とお付き合いありがとうございました。
Rails jQueryでイベントを発火させるまでの流れ

# まえがき
今回初投稿です。間違っている点や、修正点がありましたら指摘してくださると嬉しいです。
#きっかけ
インクリメンタルサーチを実装したいと思い、ajaxを触ってみたものの、イベントを発火させる（keyup,submitなどの操作をjsに反応させること）ところでつまずいてしまったので備忘録として書きます。同じところでつまずいた人の参考になれば幸いです。
#目次
・gemfileに追加
・application.jsに追加
・javascriptファイルを作成
・jQueryで記述
・動作確認

## gemfileに追加
それでは実際にやっていきます。
今回はjqueryで書いていくのでGemfileに**'jquery-rails'**というgemを追加してjQueryを使用できるようにします。

```ruby:Gemfile
  ...
 （中略）
  ...
# Use jquery as the JavaScript library
gem 'jquery-rails'
  ...
 （中略）
  ...
```

忘れずに **bundle install** をしましょう。
しっかりと、gemlockにjqueryの記述があることを確認します。

## application.jsに追加
今回はこのアプリケーション全体にjsを効かせたいのでapplication.jsに記述していきます。
記述するものは以下の通りです。


```application.js
  ...
  （中略）
  ...
//= require jquery
//= require rails-ujs 
  ...
  （中略）
  ...
```

requireという表記はCommonJSに基づいた書き方で、jsを適用させるという意味合いです。
各JSファイルをモジュール化しておいて、使うときはrequire()で読み込むやりかたをアプリケーション全体に効かせたいときにこのような表記をします。
ちなみにコメントアウトされているような表示方法ですがこれは**sprockets**というgemファイルの仕様です。
同じjavascriptファイルの中にsample.cofeeというようなファイルが入っていることがありますが、jsファイルと同じ名前だとjsファイルを読み込まないことがあるので使わないなら削除しておきましょう。

## jsファイルを作成
ではイベントを指定するjsファイルを作ってみましょう。
jsファイルは **assets / javascript** のディレクトリに入っています。
javasqriptファイルがない場合は作りましょう。


**app / assets / javascript / sample.js**

この位置に追加しましょう。

## jQuery記述
これからどんなイベントが発生したときに発火させたいのかを設定していきます。
記述方法は以下です。

```sample.js
$(function(){
  $('#action-form').on('keyup', function(){
    var input = $("#action-button").val();
      console.log (input)
  })
})
```
**keyup**はキーボードのキーを上げたときという意味になります。
**'#action-form'**はどこでkeyupしたときに発火させたいかということを指定しています。
まとめると、この記述は、**'#action-form'**に文字を入力したときに.val()で値を取得し、inputに代入している、というふうになります。
そしてそのinputをconsole.log()を使ってデバッグしていきます。
console.log()で値が取れているかどうかを確認するにはブラウザ上でプロパティーツールを開いて、consoleという欄を開くと確認できると思います。

もし、inputに代入した文字がconsoleで出力できていたなら発火できているという証拠です。

#まとめ
今回はjqueryを使って発火させるまでを書きました。
発火させることはjavascriptを使う上で一番最初のアクションになります。今回はkeyupを使って発火させましたが、submitやscrollなどたくさんの種類があり、以下のリンクが参考になります。是非確認してみてください。
[jQuery on() イベントの種類](https://qiita.com/temori1919/items/bcbfc4a93301ef902d1d)
では、また！！！！
Cubism SDK for Webをubuntuで動かしてみた

# 注意事項
- Cubism SDK for Webの対応OSはWindowsやMacOSであり，ubuntuは公式ではサポートされていません．
- 仮に以下の手順で進めても，うまく出来ない場合もあると思いますので，そこは自己責任でお願いします．

# Cubism SDK for Webとは
- WebGLで実装されたSDK.
- Live2DのモデルをWeb上で表示できたりする.
- 主要なWebブラウザに対応している.
- ソースコードはTypeScriptで書かれている.

（引用：[Cubism SDK](https://www.live2d.com/download/cubism-sdk/)）

# Cubism SDK for Webを使ってみよう（概要）
以下の手順で進めていきます．

1. Cubism SDK for Webを使うまでのインストール作業
2. Webサンプルのビルド&実行

今回試した環境は以下の通りです．
OS: Ubuntu 18.04 LTS
CPU: i3-4130 3.40GHz
メモリ: 16GB

# 1. Cubism SDK for Webを使うまでのインストール作業
基本的には[Live2D Cubism/SDKチュートリアル](https://docs.live2d.com/cubism-sdk-tutorials/sample-build-web/#)を参考にしています．
上記のものをより詳しく説明していければいいなと思っています．

## 1.1 Visual Studio Code(VSCode)のインストール
[UbuntuにVSCodeをインストールする3つの方法](https://qiita.com/yoshiyasu1111/items/e21a77ed68b52cb5f7c8)の記事がわかりやすいと思います。
3通りのインストール方法を紹介されていますが，私は3番目がとてもわかりやすかったです．
インストールを行い，バージョンの確認が出来ればおｋです．

```
$ code --version
1.38.1
b37e54c98e1a74ba89e03073e5a3761284e3ffb0
x64
```
次にインストールしたVSCodeを起動します．

```
$ code
```
実行をして，左側のブックマークのExtensionsをクリックして検索枠に以下の2つを入力します．

- Debugger for Chrome
- Live Server

以下の図のようにそれぞれをinstallしてください．
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472706/287cad2d-4677-47d8-da32-f4bb33c0f687.jpeg)
![無題2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472706/f4b0cfc3-b082-a06e-8fa2-b33e8e1b0c34.jpeg)

installが終わり，VScodeを再起動したらこの設定は終了です．


## 1.2 Node.jsのインストール
[Ubuntuに最新のNode.jsを難なくインストールする](https://qiita.com/seibe/items/36cef7df85fe2cefa3ea)の記事がわかりやすいと思います。
こちらもインストールを行い，nodeとnpmのバージョンの確認が出来ればおｋです．

```
$ node -v
v12.13.0
$ npm --version
6.12.0
```
## 1.3 TypeScriptのインストール
以下のコードを実行してインストールを行い，バージョンの確認が出来ればおｋです．

```
$ npm install -g typescript
$ tsc --version
Version 3.7.2
```

## 1.4 ビルドに必要な各パッケージのインストール
まず[Cubism SDK for Web ダウンロード](https://www.live2d.com/download/cubism-sdk/download-web/)から使用許諾契約に同意して，Cubism SDK for Webをダウンロードします．
ダウンロードしたzipファイルを解凍し，解凍したファイルに移動します．

```
$ unzip CubismSdkForWeb-4-beta.1.zip
$ cd CubismSdkForWeb-4-beta.1
```
移動してlsコマンドで「package.json」があることを確認します．

```
$ ls
CHANGELOG.md  README.md        framework.webpack.config.js  sample.webpack.config.js
Core          Sample           package-lock.json
Framework     cubism-info.yml  package.json
```
確認できれば，以下のコードを実行します．

```
$ npm install
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.9 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.9: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
```
上記のwarningが出ると思いますが、スルーしておkです．
ここまでが必要なインストール作業になります．

# 2. Webサンプルのビルド&実行
こちらの操作は直接[Live2D Cubism/SDKチュートリアル](https://docs.live2d.com/cubism-sdk-tutorials/sample-build-web/#)を参考に進めて貰えれば問題ないと思います．
上記のリンクの「ビルド」と「実行」を順に進めれば以下のようにブラウザが起動し，画面にモデルが表示されます．![Screenshot from 2019-11-11 00-47-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472706/e41aca71-69ca-9697-687c-7d88935e7218.png)

# まとめ
- ubuntuでLive2Dのモデルをweb上に表示した．
- 正直いつ不具合が出てくるかはわからないので，あまり期待はしない方が良い．
- 今後この続きを書くかは不明．
THREE.Geometry()でverticesを更新するときにverticesNeedUpdateの使い方がわからず困った

# やりたかったこと
`THREE.Geometry()`で形状データを作成するときに,ランダムに3D空間上に点を置いていく実装をしていた。このランダムに置いた点を、動かすことでパーティクルの表現をしたかった

## サンプル(動くもの)
https://marina1017.github.io/2019-creative-code-sketch/src/03-particle/


# 問題点
サンプルコードのように、作成した`geometry`の`vertex`の中にあるy軸のどのへんの位置にそんざいしているかという値を変更しても、なぜかかわらない。

```js
mesh.geometry.vertices.forEach(vertex => {
      vertex.setY(vertex.y + vertex.velocity.y);
});
```

# 解決方法

[参考文献](https://stackoverflow.com/questions/24531109/three-js-vertices-does-not-update)によると、「geometry.verticesNeedUpdate」はレンダリング後に毎回falseになるらしいので
`mesh.geometry.verticesNeedUpdate = true;`を毎回レンダリングで呼ぶ関数の中に設置することで、解決した

```js
// レンダリング---------------------
  function render(){
    requestAnimationFrame(render);
    //particle system自体をまわす
    mesh.rotation.y += 0.001;

    // meshに設定したgeometryの中に入っている点のy軸をランダムに動かすようにする
    mesh.geometry.vertices.forEach(vertex => {
      vertex.setY(vertex.y + vertex.velocity.y);
    });
    // geometryの「geometry.verticesNeedUpdate」はレンダリング後に毎回falseになるらしいのでtrueをここで設定している。
    // https://stackoverflow.com/questions/24531109/three-js-vertices-does-not-update
    mesh.geometry.verticesNeedUpdate = true;
    
    // マウスでカメラを操作するため
    controls.update();

    //シーンとカメラをいれる。
    renderer.render(scene,camera);
  }
```

### ちなみに
ドキュメントには、verticesを更新する場合は、`verticesNeedUpdate`を`true`にする必要があると書いてあるが、レンダリング後に毎回falseになるとは書いていないので、どなたかそれがドキュメントのここに書いてあるということをご存じの方は教えて下さい
![1573392352606.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176479/b0eec594-7221-e292-bb22-4ad248de4b1e.jpeg)



## サンプルコード
https://github.com/marina1017/2019-creative-code-sketch/tree/master/src/03-particle

## 参考文献
https://stackoverflow.com/questions/24531109/three-js-vertices-does-not-update
マイグレーションでcsvファイルをimportするときに気をつけること

# 概要

- **何をしたの？**

次の手順でテーブルにcsvデータをimportするマイグレーションファイルを書いて実行した。

    1. foobarテーブルにfooフィールドとbarフィールドを追加する

    2. foobarテーブルのfooフィールドとbarフィールドにcsvファイルのデータをimportする

- **何が起きた？**

  そのテーブルにそんなフィールドは無い旨のエラーが吐かれた。

  ```
  ActiveModel::UnknownAttributeError: unknown attribute 'foo' for Foobar.
  ```

  

# 結論

マイグレーションの中で複数フィールドを追加してcsvファイルのデータをimportするときは、

フィールド追加のマイグレーションファイルを分けましょう。

# 環境

```
Ruby 2.2.2p95
Rails 4.2.2
mysql 5.7.12
```

# 修正後コード

1.

``` ruby:add_foo_to_foobar.rb
class AddFooToFoobar < ActiveRecord::Migration
  def change
    add_column :foobar, :foo, :text
    Foobar.reset_column_information
  end
end
```

2.

```ruby:add_bar_to_foobar.rb
class AddBarToFoobar < ActiveRecord::Migration
  def change
    add_column :foobar, :bar, :text
    Foobar.reset_column_information
  end
end
```

3.

```ruby:add_data_to_foobar.rb
class AddDataToFoobar < ActiveRecord::Migration
  def change
    csv_data = []
    CSV.read('./rawdata/foobar.csv', headers: true).each do |record|
      csv_data << Foobar.new({
        foo: record[0],
        bar: record[1]
      })
    end
    Foobar.import csv_data
  end
end
```

1~3のファイルの順番でマイグレーションを行い、無事フィールドの追加・データのimportをすることができました。

# 修正前コード

以下の3パターンでコードを書いてマイグレーションを実行したところ、いずれも`ActiveModel::UnknownAttributeError:~`が発生し、正常にマイグレーションができませんでした。

①`add_column`を2行続けて、`.reset_column_information`を1回する

```ruby
class AddColumnToFoobar < ActiveRecord::Migration
  def change
    add_column :foobar, :foo, :text
    add_column :foobar, :bar, :text
    Foobar.reset_column_information
  end
end
```

②1ファイルの中で`add_column` `.reset_column_information`を交互にする

```ruby
class AddColumnToFoobar < ActiveRecord::Migration
  def change
    add_column :foobar, :foo, :text
    Foobar.reset_column_information
    add_column :foobar, :bar, :text
    Foobar.reset_column_information
  end
end
```

③`change_table~`でカラムを2行追加したあとに`.reset_column_information`を1回する

```ruby
class AddColumnToFoobar < ActiveRecord::Migration
  def change
    change_table :foobar, bulk: true do |t|
      t.string :foo
      t.string :bar
    end
    Foobar.reset_column_information
  end
end
```



- `.reset_column_information`が直前の追加したフィールドにしか作用していない
- `.reset_column_information`は1ファイルの中で一度しか動作しない

という予測を立ててみましたが、はっきりとした原因はわかりませんでした。

# 参考記事

1. [migration の中で model を触ったら必ず reset_column_information する](https://blog.onk.ninja/2017/10/18/use_reset_column_information)
Jupyter Notebookの導入

本命であるデータ分析に手を出して見ようと思い
とりあえず、前提である環境設定を投稿しようと思いまs。

## anacondaからの導入

このページから使いたいpythonをダウンロードします。
https://www.anaconda.com/distribution/

OSはページが合わせてくれるので心配はいらず
あとは手順通りにダウンロードして

enviromentで開発環境を作成

homeよりjupiternoteをinstallすれば完了です。

ただしなぜか開発環境が作成されない謎現象が起きたので
ターミナルで直接作るという手間が必要でしたが

## ターミナルからの導入

とうやらこの方法からも導入できるそうです。

```bash:ターミナル
　　$ pip install --upgrade setuptools
　　$ pip install --upgrade pip
　　pipを最新の状態へ更新します。

　　$ pip install numpy
　　$ pip install scipy
　　$ pip install matplotlib
　　$ pip install Pillow
　　$ pip install ipython[all]
　　必要なパッケージをインストールします。

　　$ pip install jupyter
　　Jupyter Notebookをインストールします。

　　$ jupyter notebook
　　実行しブラウザで確認
```
基本情報4週目(11/11週)

# 目標と結果
### 目標
- 16項目まで参考書の演習問題を正解する。
- できない部分を見つけ、そのままにしない。
- 基礎理論とアルゴリズムを勉強を続ける。
- [基本情報技術者試験ドットコム](https://www.fe-siken.com/)を使う。
- セキュリティのテストを合格する。

### 項目

独習ゼミの項目で言うとFE74まで

13．ソフトウェア開発管理技術
(開発プロセス手法・知的財産適用管理・開発環境管理・構成管理・変更管理)
14．プロジェクトマネジメント
(プロジェクトマネジメント・統合マネジメント・ステークホルダマネジメント・スコープマネジメント・タイムマネジメント・コストマネジメント・品質マネジメント・資源マネジメント・コミュニケーションマネジメント・リスクマネジメント・調達マネジメント)
15．サービスマネジメント
(サービスマネジメント・サービスの設計/移行・サービスマネジメントプロセス・サービスの運用・ファシリティマネジメント)
16．システム監査
(システム監査・内部統制)

### 結果

- FE74まで勉強できた。
    - 時間計算管理や工数管理などが苦手だと感じた。
        - 暗記問題はできていると思う。 

- セキュリティのテストに合格した。
    - 基本情報技術者試験ドットコムのセキュリティの項目を何周かすれば解けるようになったので、他の項目でも同じようにしてみようと思います。
        - 公開鍵暗号の項目が特にややこしい。
   
- Markdownのチャレンジした点
    - 箇条書きの段を下げて構造的にした。
        - (めっちゃ小さいことですいません。)


# 振り返り
### Keep

- 過去問道場を使う。
- 項目別の過去問題を周回する。

### Problem

- 時間計算や工数管理が苦手。
    - 計算が絡むと正答率が下がる。
- 基礎理論や二進数、伝送速度なども同じことが言える。

### Try

- 苦手な部分は繰り返しで覚える。
- 電子版の参考書を買ったので活用する。
- ネットワークとデータベースのテストに合格する。
クエリで Project Euler Problem 4

## 【お題】
[Problem 4](http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%204 "Problem 4 - PukiWiki")。
> Problem 4 「最大の回文積」 †
> 左右どちらから読んでも同じ値になる数を回文数という. 2桁の数の積で表される回文数のうち, 最大のものは 9009 = 91 × 99 である.
> 
> では, 3桁の数の積で表される回文数の最大値を求めよ.

## 【環境】
| SQLServer | SQLCMD |
| ---- | ---- |
| 2017 | 14.0.1000.169 |
設定はデフォルト。その他の環境は以下。

| OS | CPU | ストレージ |
| ---- | ---- | ---- |
| Windows10 64bit | Corei7 | SSD 250G |

## 【クエリ 1】
馬鹿正直に実装すると以下。

```SQL
;WITH [CTE_Val]([Val]) AS (                         -- 100 ～ 999 列挙CTE
    SELECT 100
    UNION ALL
    SELECT [Val] + 1 FROM [CTE_Val] WHERE [Val] < 999
)
, [CTE_Join]([Val], [ValStr]) AS (                  -- 100 ～ 999 × 100 ～ 999 列挙CTE
    SELECT
          [Val]
        , CONVERT(VARCHAR(6), [Val])                -- 文字列に変換
    FROM (
        SELECT
              [Src].[Val] * [Dst].[Val]
        FROM [CTE_Val] [Src], [CTE_Val][Dst]
    )t(Val)
)
SELECT MAX([Val]) FROM [CTE_Join]
WHERE   [ValStr] = REVERSE([ValStr])                -- 回文数判定
OPTION (MAXRECURSION 0)
;
GO

-----------
     906609

(1 行処理されました)
```
二つの3桁の数の全ての組み合わせの積を列挙。
数値を文字列に変換、`REVERSE` した結果と一致すれば回文数。
処理時間を計測したら約0.6秒だった。

結果はかなり大きな数値であることが予想されるので、最初の CTE を `SELECT 900` として 900始まりとしたら約0.001秒だったけど、それは反則か。

## 【クエリ 2】
二つの3桁の数の積の最大値は 999 × 999 = 998001。この最大値から降順に調べた方が速いか？ ということで実装例は以下。

```SQL
;WITH [CTE_Mul]([Mul]) AS (                         -- 100 ～ 999 列挙CTE(除数用)
    SELECT 100
    UNION ALL
    SELECT [Mul] + 1 FROM [CTE_Mul] WHERE [Mul] < 999
)
, [CTE_Val]([Val]) AS (                             -- 999 × 999 以下列挙CTE
    SELECT 999 * 999
    UNION ALL
    SELECT [Val] - 1 FROM [CTE_Val]
    WHERE   NOT EXISTS (
                SELECT 1 FROM [CTE_Mul]
                WHERE   [Val] % [Mul] = 0
                    AND [Val] / [Mul] < 1000
            )
        OR  CONVERT(VARCHAR(6), [Val]) <> REVERSE(CONVERT(VARCHAR(6), [Val]))
)
SELECT MIN([Val]) FROM [CTE_Val]
OPTION (MAXRECURSION 0)
;
GO

-----------
     906609

(1 行処理されました)
```
実行時間は約1秒。うーん、逆に遅いがな。
998001、998000、997999、……と調べる場合、問題はそれが回文数であるかの判定だけではなく、二つの3桁の数の積であるかの判定も必要なこと。
これって中々な難しいよね。（実はそれがこの問題のポイント？）

普通に考えたら、まず素因数分解。分解した素数群を二つのグループに分け、両グループの積が 1000未満だったらビンゴだけど、それをクエリで書くのはしんどい。
もっと単純でクエリに適したアルゴリズムは……とぐるぐる考えた末に出てきたのが上記の単純な試し割法。
100～999の除数テーブルを用意し、そのいずれかで割り切れ且つ割った結果が 1000未満であるか、という判定方法。しかし遅い。

結果論になってしまうけど、998001 から降順で調べる場合、約9万回ループすることになるので、それなりに高速に判定できないと遅い。
二つの3桁の数の積の降順で調べる単純な方法があれば、ループ数はずっと少なくなるんだろうけど。
二つの3桁の数の積の全てを列挙して……では最初のクエリで良いし。
イマイチ釈然としない結果。
cakephpでユーザー情報ページ作成

# cakephpでユーザー情報ページを作成する

cakephpのブログチュートリアルで作成したものから発展させて投稿したユーザーの個別のページを作る。
【ユーザー情報】
・ユーザー名
・登録メールアドレス
・ユーザー画像
・一言コメント

## Model
```php:User.php
public $validate = array(
		'username' => array(
			'required' => array(
				'rule' => 'notBlank',
				'message' => 'ユーザー名は必要です'
			)
		),
		'email' => array(
			'email' => array(
				'rule' => 'email',
				'message' => 'メールアドレスを入力してください',
			),
			'required' => array(
				'rule' => 'notBlank',
				'message' => 'メールアドレスは必要です'
			),
			'check' => array(
				'rule' => 'isUnique',
				'message' => 'すでに登録されているメールアドレスです'
			)
		),
		'password' => array(
			'required' => array(
				'rule' => 'notBlank',
				'message' => 'パスワードは必要です'
			)
		),
		'image_name' => array(
			//拡張子の指定
			'rule1' => array(
				'rule' => array('extension', array('jpg', 'jpeg', 'gif', 'png')),
				'message' => '画像ではありません',
:				'allowEmpty' => true,//空でも可
			),
			//画像サイズの制限
			'rule2' => array(
				'rule' => array('filesize', '<=', '5000000'),
				'message' => '画像サイズは5MB以下でお願いします',
			),
		),

```
`isUnique`は特定カラムの一意性を検証してくれるメソッド（重複チェック）
`'allowEmpty' => true`にすることで空欄であっても許可をする(必須ではない)

## Controller
```UsersController.php
//ログインしているかによって行える作業を分ける
	public function isAuthorized($user) {
//誰でもview（ユーザー情報を見る）だけは可能
		if ($this->action === 'view') {
			return true;
		}
//ログインユーザーであれば編集が可能
		if ($this->Auth->user('id') === $user['id']) {
			if ($this->action === 'edit') {
				return true;
			}
		}
		return parent::isAuthorized($user);
	}
```
## View
```php:view.ctp
<h1>ユーザー名：<?php echo $user['User']['username']; ?></h1>
<h1>メールアドレス：<?php echo h($user['User']['email']); ?></h1>
<h4>ユーザー画像</h4>
<?php
if ($user['User']['image_name']) {//DBにファイル名が保存されているかチェック
	echo $this->Html->image($user['User']['image_name'], array('width'=>'200','height'=>'200'));
} else {
	echo '未登録';
}
?>
<p>【一言コメント】</p>
<p><?php echo h($user['User']['comment']); ?></p>
<?php
if ($auth['id'] === $user['User']['id']) {//ログインユーザーと同じであれば編集が可能
	echo $this->Html->link(
		'ユーザー情報編集',
		array('controller' => 'users', 'action' => 'edit', $user['User']['id']));
}
echo '<br>';
echo $this->Html->link(
	'ホーム', array('controller' => 'posts', 'action' => 'index'));
?>

```
Blackbox Exporter で死活監視



「[Prometheus/GrafanaでCatalystのトラフィックを収集してみる](https://qiita.com/Yohichi_Hayashi/items/d712ce8db8e3fc2a11a8)」の続きで、死活監視をします。

参考にしたのは、「[PrometheusとBlackbox Exporterでサーバ死活監視](https://qiita.com/mmorita44/items/8eca5e6fae9fd40807ce)」です。

`docker-compose.yml`にblackbox-exporterを追加します。

```YML:docker-compose.yml
  blackbox_exporter:
    image: prom/blackbox-exporter:latest
    volumes:
      - ./blackbox_exporter/config.yml:/etc/blackbox_exporter/config.yml
```

blackbox-exportの設定ファイルは`config.yml`
死活監視のみなので、icmpだけ記述します。

```YML:config.yml
modules:
  icmp:
    prober: icmp
```

`prometheus.yml`にも以下の如く追記します。

```YML:prometheus.yml
  - job_name: 'blackbox_icmp'
    scrape_interval: 10s
    metrics_path: /probe
    params:
      module: [icmp]
    static_configs:
      - targets:
        - '192.168.0.110'
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: blackbox_exporter:9115
```

動かすとこんな感じです。
1がup、0がdown。
![スクリーンショット 2019-11-11 0.06.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116134/30ecd9c6-6df6-a65b-6263-d69e1b3ad0b0.png)

次はAlartManagerか。
以上。
Macのsystem_profilerコマンドについて

## 背景

別記事でこのコマンドを利用した、簡単なシステムレポートの仕組みを作成したので、その際行った調査を整理してみました。

## 利用方法

以下のコマンドを打つとコールできるデータタイプのリストが取得できます。

```

$system_profiler -listDataTypes
```

詳細のリストに記載したパラメーターを必要に応じて呼び出します。
例えば、中古でMacを購入検討時に、スペックを調査したい場合は、HW Checkの欄に丸が付いている項目を実行すれば、ハードウェア状態が確認できます。

また以下のコマンドでXML出力が可能です。

```

system_profiler -xml >MySystem.spx
```

このコマンドを叩いてなにが嬉しいかというと、出力した結果を自動処理しやすい、というところがポイントです。

## 詳細

それぞれのパラメーターに関しては以下を参照
設定によってはパラメーターが帰ってこない場合もあるので、不明な点も多いです。

|Available Datatypes |Discription  |HW Check|Response  |
|---|---|:-:|:-:|
|SPParallelATADataType|ParallelATAの状態|○|×|
|SPUniversalAccessDataType|ユニバーサルアクセスの設定状態||○|
|SPSecureElementDataType|セキュアエレメントの状態||○|
|SPApplicationsDataType|インストールされているアプリケーションのリスト||○|
|SPAudioDataType|オーディオ設定の状態||○|
|SPBluetoothDataType|Bluetooth設定の状態||○|
|SPCameraDataType|カメラのデバイス情報|○|○|
|SPCardReaderDataType|カードリーダーのデバイス情報|○|×|
|SPComponentDataType|Libralyフォルダ内のコンポーネント状態||○|
|SPiBridgeDataType|チップセットのデバイス情報|○|○|
|SPDeveloperToolsDataType|インストールされているXCodeのバージョン||○|
|SPDiagnosticsDataType|診断結果||○|
|SPDisabledSoftwareDataType|使用不可のソフトウェア情報||○|
|SPDiscBurningDataType|DiscBurningの情報|○|×|
|SPEthernetDataType|有線Lanの情報|○|×|
|SPExtensionsDataType|ハードウェア拡張のファームウェア情報||○|
|SPFibreChannelDataType|FibreChannelの情報||×|
|SPFireWireDataType|FireWireの情報||×|
|SPFirewallDataType|ファイアウォールの設定情報||○|
|SPFontsDataType|フォントの情報||○|
|SPFrameworksDataType|インストール済みフレームワークの情報||○|
|SPDisplaysDataType|ディスプレイ情報|○|○|
|SPHardwareDataType|ハードウェア情報|○|○|
|SPHardwareRAIDDataType|RAIDコントローラー情報||×|
|SPInstallHistoryDataType|インストール履歴||○|
|SPLegacySoftwareDataType|レガシーソフトウェア情報||○|
|SPNetworkLocationDataType|ネットワークのロケーション設定情報一覧||○|
|SPLogsDataType|システムログ||○|
|SPManagedClientDataType|不明||×|
|SPMemoryDataType|システムメモリ情報|○|○|
|SPNVMeDataType|SSDコントローラーの情報|○|○|
|SPNetworkDataType|ネットワーク機器の情報|○|○|
|SPPCIDataType|PCIバス情報|○|×|
|SPParallelSCSIDataType|ParallelSCSIの情報|○|×|
|SPPowerDataType|バッテリーと電源情報|○|○|
|SPPrefPaneDataType|Prefarence Panesの情報||○|
|SPPrintersSoftwareDataType|プリンタソフトウェアの情報||○|
|SPPrintersDataType|設定済みプリンタの情報||○|
|SPConfigurationProfileDataType|コンフィグデータ？？||×|
|SPRawCameraDataType|Raw形式をサポートしているカメラのリスト||○|
|SPSASDataType|SAS（シリアルSCSI）の情報|○|×|
|SPSerialATADataType|S-ATAの情報|○|×|
|SPSPIDataType|SCSI Parallel Interfaceの情報|○|×|
|SPSmartCardsDataType|Keychain絡みのセキュリティデバイス情報|○|○|
|SPSoftwareDataType|OS情報|○|○|
|SPStartupItemDataType|スタートアップの設定情報||×|
|SPStorageDataType|ストレージ情報|○|○|
|SPSyncServicesDataType|同期サービス情報||○|
|SPThunderboltDataType|サンダーボルトのデバイス情報|○|○|
|SPUSBDataType|USBのデバイス情報|○|○|
|SPNetworkVolumeDataType|ネットワークドライブの情報||○|
|SPWWANDataType|WWANの情報||×|
|SPAirPortDataType|AirPortの情報、WIFIの検知情報||○|

※Responseの項目はMacBook Proで叩いてみた際にレスポンスが帰ってこなかったものに×をつけています。
年末まで毎日webサイトを作り続ける大学生 〜23日目 3column layoutでサイトを作る〜

##はじめに
こんにちは！最近週末は温泉に通っている@70days_jsです！
webサイト制作でお金を稼ぐために年末まで毎日webサイトを作っております。
昨日2カラムレイアウトのサイトを作ったので、今日は3カラムレイアウトのサイトを作ってみました。
何かを参考にしようか迷いましたが、とりあえず最初は自分でということで何もみないで作りました。レスポンシブには対応していません。
扱う技術レベルは低いですが、同じように悩んでる初心者の方を勇気付けられれば幸いです。
今日は23日目。(2019/11/10)
よろしくお願いします。

##サイトURL
https://sin2cos21.github.io/day23.html

##やったこと
3 column layoutでサイトを作りました。

まずは構想を作ります。↓
![スクリーンショット 2019-11-10 23.52.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/dd748955-e8f3-8d38-34ca-83dd580cf62e.png)


次に手書きでイメージ図を描きます。↓
![IMG_1119.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/92a55870-00a9-17c4-0c31-9b4c547d18d9.jpeg)



最後に実際にコーディングして完成です。↓(gif、重くてみられないかも。サイトURLへGO!)
![test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/fa08e920-a425-95b8-e36b-59598768002d.gif)



特に見せ場はないのですが、とりあえず今回はheader,main,footerの構成で、mainの中を右、真ん中、左で分けて、それをflex boxで処理しました。

```css
body {
    margin: 0;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

main {
    display: flex;
}
```

あとのところは今までに習ったことで都合をつけました。

##感想
なんやかんやで1時間近くコーディングしていました。やっぱりcssって時間かかりますね・・・。ただ、デザインは考えるのが楽しいです。


最後までお読みいただきありがとうございます。明日も投稿しますのでよろしくお願い致します。

##参考
1. 太陽を一面に浴びる雪山の斜面｜無料の写真素材はフリー素材のぱくたそ (https://pakutaso.com/20191127311post-20952.html)

画像をお借りしました。ありがとうございます！
vimのコマンドと設定のメモ

>勉強中の関連記事まとめ
>[自分用の勉強記事をまとめた目次　~擬似知識体系~](https://qiita.com/oekaki-hoho-ron/items/3194f560efc461ec03b0)

ターミナルだけで完結したいときに便利だから覚えとこう。
基本的にノーマルモード状態からのコマンド入力となる。

#起動
`vim`　vimを起動
`vim ファイル名`　ファイルを作成してvimを起動（パス/ファイル名）

#モード選択
`esc`　各種モードを離脱してノーマルモードに戻る
`i`　入力モード
`:`　コマンドモード
`v`　ビジュアルモード（選択モード）

#ヘルプ
`:h operator`　ヘルプ
``

#保存・終了・ファイル開く
`:w`　上書き保存
`:w ファイル名`　名前をつけて新規保存

`:q`　終了
`:q!`　強制終了

`:wq` or `:x` or `ZZ`　保存して終了
`:xa`変更があるタブを保存して全てのタブを閉じる

`:e ファイル名`　ファイルを開く

#アンドゥ・リドゥ
`u`　アンドゥ
`ctrl + r`　リドゥ
`.`　直前の操作を繰り返す

#カーソル移動
`h`　←
`j`　↓
`k`　↑
`l`　→
覚え方は、デフォルトポジションのチョキが上下、そのサイドキーが左右。

`gg`　ファイルの最初へ
`G`　ファイルの最後へ

`H`　表示画面の最上行へ
`M`　表示画面の中央行へ
`L`　表示画面の最下行へ

`ctrl + b`　前ページへ
`ctrl + f`　次ページへ

`w`　次の単語へ（熟語単位）
`b`　前の単語へ（熟語単位）

`e`　次の単語へ（単語単位）
`ge`　前の単語へ（単語単位）

`^`　行頭へ
`$`　行末へ

`:3`　3行目へ（行数指定）
`%`　カーソル位置のカッコと対になるカッコへ

`f?`　現在の行で?と一致する最初の文字へ
`f? + ;`　現在の行で?と一致する次の文字へ

`m + アルファベット`　カーソル位置の行をマーク
`｀ + アルファベット`　マークした行へ

#範囲選択
`v`　一文字選択（ビジュアルモード）
`V`　行選択
`ctrl + v`　矩形選択
`ggVG`　全選択

#編集
`i`　インサート入力（カーソルの左側から）
`a`　アフター入力（カーソルの右側から）
`c`　選択範囲を削除して入力モードに移行

`I`　行の最初の非空白文字から入力
`A`　行末から入力

`o`　下に行を追加してから入力
`O`　上に行を追加してから入力
`J`　カーソル位置の行と下の行を連結

`短径選択 + I + 挿入文字列 + esc`　一括で同じ編集を加える（ちょっと複雑）

`>>`　右にインデント
`<<`　左にインデント
`=`　カーソル位置の行のインデントを自動整列

`~`　カーソル位置の文字の小文字・大文字を切替え
`U`　選択範囲の文字の小文字・大文字を切替え

#テキストオブジェクト編集
`c,d,y`　操作選択（置換・削除・コピー）
`i,a`　範囲選択（内容・全体）
`w,s,t,",),]`　オブジェクト選択（単語・文・htmlタグ・クォーテーション・カッコ）

例）`cit`　タグの内容のみを置換
例）`cat`　タグ全体を置換
例）`ci"`　" "の内容のみを置換
例）`diw`　一単語の内容のみ削除
例）`dw`　カーソル位置より右側の単語範囲を削除
例）`daw`　カーソル位置の単語を削除
例）`viw`　一単語選択

#削除
`x`　一文字削除
`dd`　一行削除
`3dd`　3行削除（行数指定）
`短径選択 + x`　一括削除
`D` or `d$`　カーソル位置から行末まで削除
`S`　カーソル位置の一行を削除して入力モードに移行

#コピペ
`yy`　コピー
`3yy`　3行コピー行数指定）

`p`　ペースト（削除やコピーした際のクリップボードから）

#検索
`/???`　キーワード検索
`/??? + n`　次の該当ワードへ
`/??? + N`　前の該当ワードへ

`*`　カーソル位置の単語と同じ単語へ（順）
`#`　カーソル位置の単語と同じ単語へ（逆）

`ctrl + n`　入力中の文字列をファイル内を参照して予測変換

#置換
`:s/文字列1/文字列2/`　カーソルに近い最初の文字列1を文字列2に置換
`:s/文字列1/文字列2/g`　行内の該当する全文字列を置換
`:%/文字列1/文字列2/g`　ファイル全体の全文字列を置換
`:%s/文字列1/文字列2/gc`　実行前に確認を求められる

#画面分割
`:sp`　水平分割
`:vs`　垂直分割
`ctrl + w`　画面選択
`:close`　画面を閉じる

#コマンドによる一時的な拡張機能
`:set tabstop=3`　Tabスペースの文字数を指定
`:syntax on`　テキストに色をつける
`:syntax off`　つけない

`:set ignorecase`    // キーワード検索で小文字・大文字を含める
`:set noignorecase`    // 含めない

#vim設定ファイルによる拡張機能
```.zsh
$ vim ~/.vimrc
```
```~/.vimrc
syntax on    // テキストに色を付ける
syntax off    // テキストに色を付けない

set number    // 行番号を表示
set title    // ファイル名を表示

set ignorecase    // キーワード検索で小文字・大文字を含める
set noignorecase    // 含めない
```
asciidoctor の csv のテーブル表示でセンタリング・右寄せ・左寄せを制御する

## 概要
csv でも、右寄せ、左寄せ、センタリングとか align 相当の指定はできる。
ただ、行単位の指定はできない。今更だけど、苦肉の策を思いついたので紹介してみる。

**参考**

[Asciidocで作る請求書 - Qiita](https://qiita.com/arachan@github/items/ebe49b3fba7dba30c46f)
> 右揃え左揃えはできない。
> だから上から順番に書くデザインにする。

## 環境

* Asciidoctor 2.0.10
* ruby 2.6.4
* Ubuntu 18.04 LTS

## 前知識
* `cols` を使うと、列単位には右寄せ(`<`)、左寄せ(`>`)、センタリング(`^`)などの指定は **できる**。  
  → 詳細は、参考を見てください。

## 問題点を整理する

* cols は **列単位** に制御できないので、ヘッダとヘッダ行以外とで寄せ方を変えたい場合はどうにもならない  
  → 本当？ヘッダ自体は大抵は固定文字列だから、何とかなるんじゃね？

## サンプルデータと実験結果

**asciidoc_tables_sample.csv**
全角空白でたっぷり詰め物をしたcsvです。
ヘッダーとフッターは、データ行のalignに影響されないように同じ幅でたっぷり詰めております。最終行は(無効にもできるが)asciidocとして解釈されることを前提に、左から、斜体、太字、マクロ展開(改行)を入れております。(良くも悪くも無効化できない)

```csv
"ID　　　　","金額　　　　　","　　　　　　備考"
1,"$100",Foo
2,"$20",Bar
"　　　　__ID__","　　　　　〇**〇**","　　　　　　　たpass:p[ +]　　　　　　　て"
```

**asciidoctor_tables_csv_align_sample.adoc**

* cols では、3列の指定でセンタリング(`^`)、左寄せ(`>`)、右寄せ(`<`)の指定をしております
* 先頭の1行目は、ヘッダ行として太字にしております
* 1列目に関しては、すべて下寄せの指定となります

```asciidoc
[format="csv" cols="^.>,>,<" options="header,autowidth"]
,===
include::asciidoc_tables_sample.csv[]
,===
```


**出力結果**
苦肉の策の出力結果でございます。
![asciidoctor_tables_csv_align.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326797/0a41d14d-e8e2-af79-5b8f-a419d1b4c82a.png)

## まとめ

csv自体の前処理・加工処理がなんらか存在するなら、別に csv に拘らなくてもよい気はする。
そういう意味で、割り切った状況下で、ヘッダを少し工夫すれば見栄えは変えられる程度の話です。

妥協したくなくて、csvに対して何等かのフィルターがあるなら、 `|===` の形式に変換するほうが良いと思います。
`|===` の形式なら、データを弄るような無駄なパディングをせずとも、`>| aaa ` みたいにセル単位に配置を調整ができます。
(`,` → ` | ` とかの変換は文字列置換のツールに慣れた人なら難しい処理ではない)

## 参考
* [Awesome Asciidoctor: Table Column and Cell Alignment - Messages from mrhaki](https://mrhaki.blogspot.com/2014/11/awesome-asciidoctor-table-column-and.html)