OmniAICreator/Qiita-1.07M huggingface dataset:
IBM ILOG CPLEX Optimization Studio  とらぶるメモ


# はじめに
IBM ILOG CPLEX Optimazation Studio を使う事になり、チュートリアルを見ながら勉強していたところ、詰まってしまったことがありましたので、解決策とともにメモします。

## 環境
今回使用した環境は以下の通り。
Windows10 
IBM ILOG CPLEX Optimazatio Studio 12.9.0.0 ビルド ID: 201902191339

## No.1 エラーメッセージが表示されない問題
自力でサンプルプログラムを作成して実行したところ、エラーが発生。
発生したエラーを確認したところ、以下のメッセージが表示。

![cplex_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13492/c61dda46-57a4-df68-a3ba-cc044601c5e3.png)

左端のセルに赤色の「×」が表示されているだけで、説明が一切出てこない。:sweat_smile:

### 原因
メッセージが表示されないのは、言語環境に不具合が疑われます。
今回は、
[CPLEX Optimization Studio文字化けの回避](https://qiita.com/fred55/items/8aa6056effb52cddcfab)で紹介されている方法でCPLEXを再起動して、メッセージが表示されないかを確認しました。
![cplex_error_en.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13492/fa0c034e-2a05-9db5-1a8c-47e183bd4c2c.png)
まだ、一部に文字化けが残っていますが、先程より情報があります。
「構aeuu1」となっているので、似た箇所が無いか確認しました。

![cplex_view.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13492/a07d7264-653d-2f51-6e41-e762c673088d.png)
すると、"Run Configurations"の直下にある、「構成 1(default)」の名前で引っかかったようです。

### 解決策

"構成 1"を "Config1"に変更して実行すると無事実行できました。
![cplex_view_mod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13492/14905c75-a5a7-3024-2c2c-82dd0ea91540.png)

どうやら、日本語の名前で Configuration の名前を指定するのは避けた方が良さそうです。
Railsコンソールで日本語入力ができない現象【Docker】

#はじめに
Railsの参考書を読みながら勉強を進めているときに、

DockerのRailsコンテナ内で、Railsコンソールを起動し、日本語文章を入力しようとしたら、
入力はできるのに、エンターキーを押すとターミナルに表示されないという現象が起きたので、

その解決方法についてです。

エンターキーを押す前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534848/abdff03e-3126-6109-f6bb-c969b1471833.png)


押した後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534848/61e3d541-a77c-bcfe-4f70-5653cc58ddf4.png)


#解決方法
DockerFileに、

`ENV LANG C.UTF-8`

を記入して

`docker-compose up --build`で再起動

これでコンソールに日本語を入力できるようになります。

エンターキーを押す前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534848/d312c68b-1119-1a9c-6f6e-d5fc48edd80f.png)

押した後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534848/73724ed3-afd3-6dc7-b99e-784a219023f1.png)


参考にしたページ：Docker / rails console で日本語入力できない問題
https://gist.github.com/tasiyo7333/2163a09129ed36639645145a0146d8d3
Docker-composeを使ってみよう

# Docker-compose とは
ちょっと調べてみました。
複数のDockerコンテナをまとめて自動化・管理するツールらしい。
連携（コンテナ間のネットワーク連携）もできるらしい。

参考URL:
[Docker compose ことはじめハンズオン](https://qiita.com/TsutomuNakamura/items/7e90e5efb36601c5bc8a)

### Docker-compose インストール
Docker Desktop for Mac でDockerをinstallした場合は不要。(Windowsも同じく）
Linuxの場合は上記参考URLを参照。（丸投げ）

# Docker-compose.yml 作成

ディレクトリ構成は下記の通り

```
.（/yourlocal_dir）
├── .env
├── Dockerfile　
├── docker-compose.yml
├── input/     　　
├── output/  　　
└── script/   　　
```

### docker-compose.ymlの基本のき

**「見本のdocker-conpose.yml」**

```yaml:docker-conpose.yml
version: "3" # バージョン
services: # 起動するコンテナの定義
  ubuntu:
    image: ubuntu:16.04 # 使いたいイメージをinstall
    container_name: ubuntu # コンテナの名前
    volumes:
      - /yourlocal_dir:/tmp/wk #ｈｏｓｔとマウント
    working_dir: /tmp/wk #コンテナ内のワークディレクトリ
    command: touch test.txt # コマンド記入
```
・`image: `・・・使いたいイメージを指定する...ではなく作成したdockerfileを指定することもできる。`image: `のところを`build: .`に変更でおk。
・`command: `　デフォルトのコマンドを上書きしますので要注意。
　複数にコマンドを記入したい場合は下記の通り。

```yaml:
    command: >
      bash -c "touch test.txt &&
      mkdir output/test &&
      mv test.txt output/test/"
```

はい、できた。
さて、**「見本のdocker-conpose.yml」** を動かすと`/yourlocal_dir/`の中に test.txt ができます。

参考URL:[Docker Compose - docker-compose.yml リファレンス](https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa)

# これだけは覚えとけ！docker-composeコマンド
まず、docker-conpose.ymlのあるディレクトリに移動。
`cd /yourlocal_dir`

起動
イメージがない場合は自動でインストールしてくれます。
今回の場合、瞬殺でtest.txtが出来上がります。
`docker-compose up -d`

Dockerfileをbuildする場合はこちら。
``docker-compose up --build``

コンテナの一覧　
`docker-compose ps`

止める
`docker-compose stop`

再起動
`docker-compose restart`

logをみる。
`docker-compose logs`

コンテナの中に入ってみる。
`docker-compose exec [コンテナ名] /bin/bash`
 出るときは[control+C]


捨てる
お疲れ様でした。　
-f　は強制終了。つけない場合は　Are you sure? [yN]　と聞かれる。
`docker-compose rm -f`

複数のコンテナの内、１つだけ止めたい！という場合は下記の通り。
下記ルールは他docker-composeコマンドでも使えるようですよ。
`docker-compose stop [container_name]`

参考URL:[docker-compose コマンドまとめ](https://qiita.com/wasanx25/items/d47caf37b79e855af95f)

# ちょっと上級者編(筆者的に）
## 環境変数（.env）　について
スマートに書きたい。
バージョンなど変更する場合がある値。
同じ文字打つのめんどい。
という時に！

```terminal:command
#テキストエディタで開いて
nano .env
```

```text:.env
#環境変数を入力して保存
VER=16.04
DIR=/home/peta/ws
CMD=touch test_20191107.txt
```
docker-conpose.ymlはこんな感じ

```yaml=docker-conpose.yml
version: "3" # バージョン
services: # 起動するコンテナの定義
  ubuntu:
    image: ubuntu:${VER} # 使いたいイメージをinstall
    container_name: ubuntu # コンテナの名前
    volumes:
      - ${DIR}:/tmp/wk #ｈｏｓｔとマウント
    working_dir: /tmp/wk #コンテナ内のワークディレクトリ
    command: ${CMD} # コマンド記入
```

他のPCや仲間に共有したときに、`．env`を変更するだけでいいようにdocker-compose.ymlを書いといたらいいですね。
参考URL:[docker-compose.ymlで.envファイルに定義した環境変数を使う](https://kitigai.hatenablog.com/entry/2019/05/08/003000)
# 別にDockerだけでよくね？　という方へ
筆者の個人的感想です。
【利点】
・いろんなコンテナを同時に使える。組み合わせられる。
・docker-compose.ymlへ、コマンドや設定を書いているので、のちのち管理しやすい。
・ymlで書くのでわかりやすい（個人的見解）
　→後から見やすいかな？と思いました。
・docker-compose.ymlを渡すだけでまるまる共有できる！！！再現できる！！！（docker-composeコマンド使えたら）


【問題点】
・docker-compose.yml　書くのに時間かかりそう。（コンテナの組み合わせを考えたりも）
　→時間かかりますが、一度できたら流用しやすそう。

【まとめ】
共有・再現する際に非常に役立ちそう。

---
おわり。
gitを入れ子にする（submodule）

# gitを入れ子にする（submodule）

gitレポジトリを入れ子にするにはsubmoduleという機能を使う。

## 参考

- [Git submoduleの押さえておきたい理解ポイントのまとめ \- Qiita](https://qiita.com/kinpira/items/3309eb2e5a9a422199e9)
- [git remote set\-url origin git@github\.com:username/submodule\_to\_be\_split\.git](https://qiita.com/horiem/items/e740a69bd3fec5908ce4)


## やりたいこと

下記のツリー図において、以下の2点を実施したい

- module_Cをproj_Aと異なるレポジトリとして分離したい
- 分離したmodule_Cをproj_B内に追加したい


```
.
├── proj_A
│   ├── A.py
│   └── module_C ★これをproj_Aから分離したい
│       └── C.py
└── proj_B
    ├── B.py
    └── ★ここにmodule_Cを追加したい
```

## module_Cをproj_Aと異なるレポジトリとして分離する

module_Cをproj_A外のどこかにコピーする
分かりやすくするため、名前はレポジトリに格納する名称に変更しておく。

```
$ cd proj_A
$ cp -r module_C ../repos_C
```

githubにrepos_C格納用の空レポジトリ（仮名：repos_C）を作っておいて
コピーしたフォルダを通常の手順でgithubに登録する

```
$ cd ../repos_C
$ echo "# repos_C" >> README.md
$ git init
$ git add README.md
$ git commit -m "first commit"
$ git remote add origin https://github.com/username/repos_C.git
$ git push -u origin master
```

proj_Aのレポジトリからmodule_Cを削除

```
$ cd proj_A
$ rm -rf module_C
$ git add -A
$ git commit
```

repos_Cを改めてcloneする

```
$ git submodule add git@github.com:username/repos_C.git
```

`git@github.com:`は状況にあわせて`https://github.com/`とかに適宜変更する

あとは`git commit`して完了


## 分離したmodule_Cをproj_B内に追加したい

手順は先の`proj_A`に`repos_C`を追加したのと同じ手順でOK


```
$ cd proj_B
$ git submodule add git@github.com:username/repos_C.git
```

## 各ディレクトリが紐づいてるレポジトリを確認する

実際にどのレポジトリに紐づいているかを確認するには`git remote -v`を使う

proj_Aの確認（proj_Bも同様）

```
$ cd proj_A
$ git remote -v
origin  https://github.com/username/proj_A.git (fetch)
origin  https://github.com/username/proj_A.git (push)
```

その中のrepos_Cの確認

```
$ cd repos_C
$ git remote -v
origin  https://github.com/username/repos_C.git (fetch)
origin  https://github.com/username/repos_C.git (push)
```
Go エラーハンドリング

## エラー処理の基本
- Goにはtry〜catch〜finallyの例外処理は存在しない  
http://golang.jp/go_faq#exceptions
- エラーを処理するためにerrorインターフェースが用意されている

```go:main.go
type error interface {
  Error() string
}
```
実際には、返されたエラーがnilかどうかで条件分岐し、nilではない場合error.Error()でエラー内容を出力しるような使い方をする

## errro packageのよく使う4つの機能
### 1.func New(message string)erro  
エラーメッセージを文字列で指定して単純にエラーを生成する時に使う

```go:main.go
err := errors.New("エラー")
fmt.Println("output:", err)
// output:エラー
```
### 2.func Errorft(format string, args ...interface{})error
フォーマット形式とエラーメッセージ文字列を指定してエラーを生成

```go:main.go
err := errors.Errorf("output: %s", "エラー")
fmt.Printkn("%+v", err)
// output: エラー
```
### 3.func Wrap(err error, message string)error
エラーをラップする時に使う

```go:main.go
err := errors.New("repository err")
err = errors.Wrap(err, "service err")
err = errors.Wrap(err, "usecase err")
fmt.Pringln(err)
// usecase err: service err: repository err
```
### 4.func Cause(err error)error
一番最初に起きたエラーの原因を特定する際に有効

```go:main.go
err := errors.New("repository err")
err = errors.Wrap(err, "service err")
err = errors.Wrap(err, "usecase err")
fmt.Pringln(errors.Cause(err))
// repository err
```
## 参考
[【Golang Errro handling】エラーの種類によって処理を分けるBESTな方法](https://qiita.com/yoshinori_hisakawa/items/15bf0307245744deb4fc)
Linuxターミナルの便利な小技まとめ☆日々更新

##Linuxのターミナルであれできないの？とググりまくった記録を記事にしました

私はよくググっても結局忘れてしまったリンクなどが多くありググることを記録してまとめることの重要性を感じています。

そもそも「どんな単語でググったっけ？」と思い出せず履歴の中に埋没してしまった小技がびっしりつまったサイトの数々があったはず、私はそれを忘れないようにこうして記事にして共有しようと思います。

##小技の紹介

###ログファイルから指定の日時のログを取得

[元ネタはこちらです](https://unix.stackexchange.com/questions/220597/how-to-tail-a-log-file-by-time)

``` bash
$ awk '/2014-01-01 21:/' log.txt; tail -f log.txt
```

###グループにいるユーザーを一覧化する
[元ネタはこちらです](https://www.cyberciti.biz/faq/linux-list-all-members-of-a-group/)

``` bash
$ grep 'grpup-name-here' /etc/group
```

membersというモジュールをインストールすると便利

``` bash
$ members ftponly
```

### すべてのディレクトリをパースしてトップ10に重いファイルをリスト化する

``` bash
$ sudo ls -lhSR / | grep -v '^d' | head -10
```

###CSVのヘッダー行を飛ばし任意の列を一覧する

[参考にしたstackoverflow](https://stackoverflow.com/questions/14110223/how-to-read-file-from-line-x-to-the-end-of-a-file-in-bash)

**以下のようなCSVのname列を抽出する**

``` sample.csv
name,age
hoge,10
fuga,12
bar,14
```

``` bash
# tail -n +2 $1 最初の行をスキップして2行目から表示
$awk -F, '{ print $1 }' sample.csv | tail -n +2 $1
```

### ファイルの最初の10行だけ表示

[元ネタはこちらです](https://www.cyberciti.biz/faq/unix-linux-show-first-10-20-lines-of-file/)

``` bash
#10行
$ head -10 bar.txt
#20行
$ head -20 bar.txt
```
### 文字列をフォルダの中から再帰的に探す

``` bash
grep -r '【文字列】' /【フォルダ名】
```

### CSVから3フィールドを抽出し3番目のカラムの値をもとに降順に最初の10行を表示

``` bash
$ cut -d ',' -f 3,5,7 kawasaki_koukai.csv | sort -n -r -t ',' -k 3 | head -n 10
```

##更新履歴
- 2019/12/09 本記事を作成
- 2019/12/10 awkの小技を追加
- 2020/1/19 cutやgrepの小技を追加
若手のころやらかした話

この記事は[Digital Identity Creative Div. Advent Calendar](https://adventar.org/calendars/4714) 2019の7日目です。

**余裕と油断は紙一重**
とはよく言ったもので、人生の教訓や名言ってのはその身になってみて初めて理解が得られるものだなと。
子供の躾もいくら危険を注意して伝えたところで本人が理解しないと何も伝わらない。
時折「一度痛い目見ないとわかんないのよ」っていうのはある意味的を得ているものだ。

これは私がエンジニアとして駆け出しから一人立ちして少し経った時の大失敗の話。
なおこの時の失敗はそこから中堅シニアと経験を重ねた今でも身についているものである。


# とある案件を初めて一人で任される

新卒で入社してCGIスクリプトをせこせこ構築する日々が続いたある日上司からとある案件のメンテナンス作業を任されることになった。
任されるサーバと設置ファイル階層の特質上操作はSSHで操作する必要がある。
それまでサーバアップロードはFTPのみだった私にとっては初のSSH操作の解禁を示すことになる。
SSH操作は入社した際初めて任された社内Webサーバ構築時以来の操作となる。
しかもその時はコマンド操作を事前に確認して行なっていたためファイル操作や削除など特定処理は行なっていなかった。
当時の社内ではSSHの解禁は以降プロジェクトを単体で任され出す予兆とされていた。
正直震えた、ついにきたかと。
ただ私は上司の「SSH操作は気をつけないと簡単にサーバ飛ばせるからねw」っていう軽く警告を受けていたことを忘れてはいない。
基本のコマンド操作には最新の注意を払い作業を進める、漆黒のターミナル画面での操作はより慎重さを覚えると共に
自ら入力したコマンドによって動作する様をみると単なるファイル移動でさえ心が踊ったものだ。

# 急変は突然に
そんな作業を半年以上行なっていたあくる日、SSH操作も慣れてきてrootの危機感も少し薄れてきていた。
本プロジェクト以外にも複数サーバ対応を任され慣れてきたからだ。
最初はコマンドを入力し間違いかないか確認していたものだが、上司のキー操作よろしくタブ置換操作よろしくエンターキーをッッターーーンとしていた。
気がつけば社内でキータイプの速さが１、２を争うレベルになっており、どっちの方が環境構築を早く仕上げられるかみたいなよくわからん話まで聞こえる始末。
別段それにあぐらをかいていたわけではないが少なくとも成長したんだなという実感を覚えて少しだけ鼻は高くなっていた気がする。

そんなおり日々のシステムメンテナンスで作業差分ファイルをアップロードする時間になった。
当時はgitからデータ取得するものではなく、サーバにファイルをアップロードして該当ディレクトリへコピー処理を行っていた。
そう、それこそ何100回と行なってきた行為である。
ただその日はシステムのバックアップ作業も依頼されていた、ファイル容量はそれなりに膨大だったため並行して作業をすることに。
バックアップファイルを圧縮しダウンロードさせつつ、いつものようにファイルをアップロードする、、ドキュメントルートへコピー作業を行おうとした際にふとディレクトリ内のファイル群を見る。
・・・なんかわちゃわちゃしてるな。。
私以外にも作業したものがいるのだろうか、アップロードディレクトリは以前のパッチファイルや不明な画像ファイルなどが溢れてごちゃごちゃしていた。
汚いな。。整理しよう。。
別段HDD容量を圧迫していたわけではないが、万が一違うファイルを展開してしまっては問題だ。
またアップロードファイルの銘名規約があったため、日付以外は途中までファイル名が似ているのでタブキー置換がめんどすかかった。
もちろん他メンバーが行なったタスクと比較し上司にも確認した上でファイルの削除を行いディレクトリを一掃、スッキリ！
さぁ満を辞してアップロードとファイルコピーを行い動作確認のためブラウザアクセスした時目の前に広がっていた光景は


**404 not found**

# そこは真っ白な雪国のような何かでした

404 not found 

中に誰もいませんよ？
おっと、トラウマを思い出すところだったぜ、それよりもどちらかといえば自宅マンション上からスーパースローモーションで落下したあとにﾋｬｯﾊｰしたほうが目が冴えてしまってねむれなかったじゃないk・・いやいや、正気を保て、時系列が違いすぎる。

そう、ファイルがかき消えていたのである。
え、なんで？コピーしただけなのになんでなくなってるの？？
アップロード先のドキュメントルートを見ると中身完全にからっぽ。は？？

何が起きたかわからず復旧しようにもそもそもファイル自体が存在していない。
そう、バックアップはアップロードするファイルのみの差分ファイルしかとっていなかったのである。
システム全部は取っていない。
テンパった挙句自力復旧も不可能。。大人しく上司に報告に行く。
普段温厚な上司が顔を歪めて即あれこれ駆け回り、デイリーバックアップからデータを復旧させてくれてことなきを得たものの、その事件はシコリとなって数日ひきづる羽目となる。

なんで消えたか、そこが問題である。
上司と共に自分がやった作業を見返すためコマンド履歴を追っていく。
すると一つのコマンドにて手が止まる。

`rm -rf ./up_YYYYMMDD/* /var/www/html/*`

そう、コピーコマンドを実行する前にディレクトリ内の掃除を行なったのであった。
その時コピー元と先のディレクトリ階層を入力するのを端折って履歴から辿ろうとした際にcpコマンドとrmコマンドがごっちゃになってしまったのである。

ありえないミス…！普通に考えたらあり得ない致命的ミス…！だが発生…！
立木文彦さんのナレーションが響き渡った気がした。

そのあと強めだが短くお説教を受け、当分の間コマンド操作時は事前にコマンドリストをまとめチェックしてもらってからコピペで実行するお達しを受けトボトボ帰路に帰ることとなるのであった。


# 最後に

以降現在に至るまでSSHコマンド操作を行う際はエンターを押す時必ず一旦止まる癖が今でも残っている。
人生最大にして最高のミス。
余談だが、その時の凹みっぷりから別の先輩上司に「いやー、凹むなって、まだマシだよ。俺なんて**お客のサーバ吹っ飛ばして300万円の損害賠償支払うことになった**ものwwそれに比べたら軽いよww」とか言われたけど、当時の私にはピンとこなすぎて一ミリの救いにもならなかったことを添えておく。
みんなもサーバの扱いは気をつけようね。
12月13日資料

バルーントリップ風のゲームをUnity PlayGroundで作る演習です。これまでの演習内容を参考に、ゲームを完成させてください。
https://qiita.com/kono3478/items/913387e7694b4c247d7c
https://qiita.com/kono3478/items/bc7971ebe7a9c0cbf2e2
https://qiita.com/kono3478/items/ed7199f56b0e4e460b24
https://qiita.com/kono3478/items/ae9cb117aa3c411deba8

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166666/296c5020-cda4-15ac-e9b4-caa8d21d74c0.png)
https://youtu.be/m5RAKAXL9Jw
1：はじめに課題となる「バルーントリップ」のプレイ動画を観察してください

2：ゲームの仕様を決定します。Unity PlayGroundで実現できない部分は無視してかまいません。下記は一例です。他にアイディアがあれば、もりこんでもかまいません

・ゲームの目的は？
　　→障害物に当たらないようにプレイヤーキャラクターを操作して風船をとり続ける
・プレイヤーキャラクターの移動方法と操作キーは？
　　→左右移動：矢印キー
　　→上下移動：スペースキーを押している間だけ上昇
・障害物と風船の出現パターンは？
　　→ランダム
・ゲームオーバーの条件は？
　　→障害物か海（地面）に当たるとライフが1個減り、3回失敗するとゲームオーバー

注意：画面中央上に「CONTINUE」ボタンを設置してください。その上で「CONTINUE」ボタンをクリックすると、ゲームを最初からやり直せるようにします。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166666/a45b3806-c62e-8827-08b7-0f24185015fd.png)
3：Unityを起動し、任意のプロジェクトネームをつけます。その後、「2D」を選択して「Create Project」をクリックします。

4：AssetStoreからUnity PlayGroundインストールします

![スクリーンショット (375).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166666/e3d5ff62-f000-d6e5-7847-695e023daf15.png)
5：「Assets」→「Images」フォルダから、プレイヤーキャラクター、障害物、風船、地面に相当するグラフィックアセットをシーンビューにドラッグ＆ドロップします。グラフィックアセットは〇などの記号でかまいません。上記は一例です
・プレイヤーキャラクター：円
・障害物：六角形
・風船：正方形

6：プレイヤーキャラクター、障害物、風船、床に対して、当たり判定をBox Collider 2DやCircle Collider 2Dで設定します

7：プレイヤーキャラクターと障害物と風船に、それぞれタグをつけます

8：動作に必要なスクリプトを設定していきます。その後、適切な動きになるようにRigitbody 2Dの値などを調整します
・プレイヤーキャラクターの左右移動：Move with Arrows
・プレイヤーキャラクターの上下移動：Push
・風船と障害物の移動：Auto Move

9：プレイヤーキャラクターが風船と障害物に衝突した際の判定に必要なスクリプトを設定します。衝突時の判定と、衝突してどうなるか（消える、消す、爆発が発生するなど）については、プレイヤーキャラクターにCondition Collisionで設定します

10：プレイヤーキャラクターにライフをHealth System Attributeで設定します

11：障害物がプレイヤーキャラクターに衝突すると、プレイヤーキャラクターのライフが減る仕組みを、Modify Health Attributeで障害物に設定します

12：同様に床がプレイヤーキャラクターに衝突すると、プレイヤーキャラクターのライフが減る仕組みを、Modify Health Attributeで床に設定します。

13：風船にプレイヤーキャラクターが衝突するとスコアが上がる仕組みを、Collectable Attributeで風船に設定します

14：一定時間経過すると自動的に消滅する仕組みを、風船と障害物に対して、Timed Self Destructで設定します

15：風船と障害物をPrefabにします

16：風船と障害物が画面左からランダムに発生する仕組みをつくります。はじめに空のGameObjectを画面左に作成し、そこに縦向きの当たり判定をBox Collider 2Dで設定します。

17：その後、GameObjectに二種類のObuject Creator Areaを設定し、それぞれに対して風船と障害物のPrefabを設定します。詳細はPlayGroundのExampleからDeffenderを参照してください。隕石が自動的に落下する仕組みが参考になります。

18：プレイヤーキャラクターが上に行きすぎないように、16と同じように空のGameObjectを作成して、横向きの当たり判定をBox Collider 2Dで設定します

19：画面中央上にCONTINUEボタンを作成します

20：CONTINUEボタンをクリックすると、ゲームがリセットされる仕組みを作ります。必要なスクリプトと設定の仕方は、11月29日資料を参考にしてください

21：Unity PlayGroundのPrefabsフォルダからUserinterfaceをゲームに設定します。詳細は10月25日資料の29を参考にしてください

22：再生ボタンを押してゲームがうまく動くか確認します。デフォルトでは風船を5個とるとゲームクリアです。リンク先は一例です

https://twitter.com/kono3478/status/1202904523653517312
キッズ用 Ubuntu マシンに入ってきた怪しからんモノ

小学4年生の息子用に作ったUbuntuマシン。

2019年の5月に作ったものを久しぶりに(2019/12)見たらいろいろ出てきて笑った。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/7846b115-41cd-bcbb-7aab-347279158130.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8046f8f4-9005-2b5c-4e73-148c3eee035f.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/36d6c2c5-8c40-8470-ecf6-9d8f7475e4ac.png)


押してみると、こんな画面が出てきました。


![Screenshot from 2019-12-05 20-17-34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/ce067f57-723b-1dc3-f4aa-3a241b7bc782.png)


作成していたのは以下のようにして作ったキッズ用Ubuntuマシン。
「Ubuntu18.04 で MINECRAFT」
https://qiita.com/nanbuwks/items/df10bba9f0ed473827d7

Chromeの通知設定を悪用しているみたいです。
通知設定のここのところを開き、

![Screenshot from 2019-12-06 15-23-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/e8c65880-4557-e55f-026d-867e08b5f915.png)


get-the-real-better-deals.com
veriprtroutg.com

の設定をリセットしました。

# リテラシーを追加

通知設定は「許可」してはいけません

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/3357a858-aa08-9f3e-fa07-3b0ecd1cf331.png)

通知とは、こういうものです。
(これはasahi.comで害はありません)
Mac の動作アニメーションを消したい

動作が遅くてついカッとなって作ってみました。
多分足りないのとかあるので今後更新はしますが

「もっとこんな事できるんだぜ？教えてやるよ」
というイケメン兄貴は是非教えてください。
お願いしますどうかどうかお願いします。

現状はキビキビ動いてくれます。

```shell

#!/bin/bash

# opening and closing windows and popovers
defaults write -g NSAutomaticWindowAnimationsEnabled -bool false

# smooth scrolling
defaults write -g NSScrollAnimationEnabled -bool false

# showing and hiding sheets, resizing preference windows, zooming windows
# float 0 doesn't work
defaults write -g NSWindowResizeTime -float 0.001

# opening and closing Quick Look windows
defaults write -g QLPanelAnimationDuration -float 0

# rubberband scrolling (doesn't affect web views)
defaults write -g NSScrollViewRubberbanding -bool false

# resizing windows before and after showing the version browser
# also disabled by NSWindowResizeTime -float 0.001
defaults write -g NSDocumentRevisionsWindowTransformAnimation -bool false

# showing a toolbar or menu bar in full screen
defaults write -g NSToolbarFullScreenAnimationDuration -float 0

# scrolling column views
defaults write -g NSBrowserColumnAnimationSpeedMultiplier -float 0

# showing the Dock
defaults write com.apple.dock autohide-time-modifier -float 0
defaults write com.apple.dock autohide-delay -float 0

# showing and hiding Mission Control, command+numbers
defaults write com.apple.dock expose-animation-duration -float 0

# showing and hiding Launchpad
defaults write com.apple.dock springboard-show-duration -float 0
defaults write com.apple.dock springboard-hide-duration -float 0

# changing pages in Launchpad
defaults write com.apple.dock springboard-page-duration -float 0

# at least AnimateInfoPanes
defaults write com.apple.finder DisableAllAnimations -bool true

# sending messages and opening windows for replies
defaults write com.apple.Mail DisableSendAnimations -bool true
defaults write com.apple.Mail DisableReplyAnimations -bool true

echo "終了"
exit 0
```
Gist
https://gist.github.com/ProblemaResolt/b658eb998b4882baaf3177be0c978f62

<script src="https://gist.github.com/ProblemaResolt/b658eb998b4882baaf3177be0c978f62.js"></script>
仙台CTFWrite-up

# 概要
先月に仙台CTFに参加してきました！
面白い問題ばかりでとても勉強になりました。来年も機会があれば参加したいと思います。
問題のジャンルはopenworld（独自）、ネットワーク、フォレンジック、マルウェア、制御システム系でした。
制御システム系以外のジャンルを随時アップしていきたいと思います。

# openworld
## 1. 状況確認 100
### ［問題の背景］ インシデント発生日時： 2019年11月04日（月）

- 本日23:42頃、あなたが離席中に、営業所の社員スズキさんから、不審メールが届いたとの電話連絡あったようです。必要な調査・対応を実施してください。


### ［問題］
- スズキさんに電話連絡し状況を確認してください。
オープンワールドのスズキさんをクリックすると、証言を確認できます。

### ［フラグ］
スズキさんの証言の『 』で囲まれた文字列（半角、小文字）

例： abc@localdomain.invalid

### 回答
スズキさんの証言を聞くには「オープンワールドURL」をクリックするとネットワーク構成図のような画面ができてきます。オープンワールドの問題は構成図を元に問題を解いてきます。

フラグ：「attacker@localdomain.invalid」

## 2. 不審メール受信者 100
### ［問題］
- スズキさんが受信した不審メールは、他の社員にも送信されていたようです。スズキさん以外で不審メールを受信したユーザー名を特定してください。

### ［フラグ］
スズキさん以外で不審メールを受信したユーザー名（半角、小文字）

例： user01

### 回答
構成図から公開サーバをクリックして、メールサーバのログを確認します。
そうするとスズキさん（user5）以外にuser13にもメールが届いているのが確認できます。

フラグ：user13

## 3. 不審添付ファイル 100

### ［問題］
- スズキさんが受信した不審メールの添付ファイル（ZIP形式）に格納されているファイル名を確認してください。

### ［フラグ］
不審添付ファイル（ZIP形式）に格納されているファイル名

例： ９月分の見積書.js

### 回答
添付ファイルを確認するには、送信された人達のPCを確認します。
今回のメーラーはthunderbirdなので、もし開いた場合は以下のpathに保存されます。
C:\Users\ユーザ名\AppData\Local\Temp
user5,user13を確認するとuser13で添付ファイルの請求書.zipがあります。
中をみると請求書.jsがあります。

フラグ：請求書.js

## 4. 不審URL 100

### ［問題］
- 不審メールの添付ファイルはダウンローダであり、開封すると不審URLからマルウェアをダウンロードし実行するようです。 ダウンローダがアクセスする不審URLを特定してください。

### ［フラグ］
ダウンローダがアクセスする不審URL（半角、小文字）

例： http://abc.example.com/a.exe

### 回答
jsを見ていきます。
難読化とまではいきませんが、スペースなどがあり見づらくなっているので、編集すると以下のURLになります。
http://slime.example.com/malware.exe

フラグ：http://slime.example.com/malware.exe

## 5. 感染PC 100

###　［問題］
- 不審メールの添付ファイルを開封したPC（マルウェアに感染したPC）のIPアドレスを特定してください。

### ［フラグ］
不審メールの添付ファイルを開封したPCのIPアドレス（半角）

例：172.16.0.10

### 回答
user13が開いたので、システム全体構成図からuser13のアドレスを確認すると、172.16.0.13と確認できる

フラグ：user13

## 6. C2サーバ　100
### ［問題］
- 感染したPCは、C2サーバに接続し、攻撃者に遠隔操作されるようです。C2サーバのホスト名を特定してください。

### ［フラグ］
C2サーバのホスト名（半角）

例： abc.example.com

### 回答
cuckooで解析
通信先を確認

フラグ：golem.freedns.com


## 7. ラテラルムーブメント　100
### ［問題］
- 不審メールにより感染したPCから、ネットワーク経由で他のPCに感染が拡大し、そちらも遠隔操作されたようです。ネットワーク経由で感染したPCのIPアドレスを特定してください。

### ［フラグ］
ネットワーク経由で感染したPCのIPアドレス（半角）
例： 172.16.0.11

###  回答
残りの端末はuser19のみで、構成図から確認するとIPは172.16.0.19とわかる。

フラグ：172.16.0.19


## 8. 攻撃ツール 100
### ［問題］
- 攻撃者は、不審メールにより感染したPCから、他のPCに感染拡大させるため、ネットワーク経由で他のPC上のプログラムを起動できるツールを利用したようです。
- このツールが起動された日時を特定してください。（誤差1分以内を正解とします。）

### ［フラグ］
ツールが起動された日時（yyyy/mm/dd-hh:mm、半角）

例： 2019/11/16-11:12

### 回答
回答作成中
モダンWEBのモダンってなんなのか


## 1.はじめに
&emsp;[『Leverages（レバレジーズ）Advent Calendar 2019』](https://qiita.com/advent-calendar/2019/leverages) 6日目担当の@katakana_n です。

&emsp;本記事では、私がモダンWEBというざっくりとしたお題について
**調べた事と感じた事**（意外だった・先入観があった）を書きました。

## 2.疑問のきっかけと当時の認識
- きっかけ：モダンWEBをネットで凄い見かける
- 当時の認識：下記項目を混ぜ合わせたWebサービスがモダンWEB？
&emsp;・RIA
&emsp;・最新のフロントとバックエンドのWEBフレームワークを使用
&emsp;・フロント部分とバック部分を別々のディレクトリ体系で管理
&emsp;・非同期かつ動的
&emsp;・SPA化
&emsp;・PWA化
&emsp;・セマンティックWEB色が強い
&emsp;・SEO対策
&emsp;・離脱率や直帰率などのアナリティクスを考慮したサイトデザイン設計
&emsp;・マイクロサービス
&emsp;・クラウド
&emsp;・TDD
&emsp;・アジャイル開発

- よくわからないから、とりあえず調べる。  
　→定義がない、この言葉を使ってる人は自分なりの解釈に当てはめて話してる。
　→使われてる背景は概ね共通していた。旧来の手法から刷新するシーンだった。

## 3.モダンWEBの色んな解釈と特徴
- モダンWEBの色んな解釈をまとめてみた
&emsp;・機能面
　　　→画面遷移の通信待ちがない
　　　→ビューとデータの状態管理
　　　→ブラウザ側に殆どの処理をさせる、WEBサーバーはデータ管理のみ
&emsp;・デザイン面
　　　→レスポンシブデザイン
　　　→リアクティブな体験
　　　→マルチメディア・マルチデバイス・クロスプラットフォーム・クロスブラウザの対応
&emsp;・UI/UX面
　　　→ユニバーサルデザインを考慮
　　　→同時スクリーン操作・並行スクリーン操作を考慮
&emsp;・設計面
　　　→コンテナ管理
　　　→マイクロサービス
&emsp;・その他
　　　→教育コストが高い
　　　→パフォーマンスを常にモニタリングしてる

- 解釈の特徴をあげてみた
　・機能面&emsp;&emsp;：シームレスなページ遷移
　・デザイン面 ：視覚的なアプローチでUXの向上
　・UI/UX面&emsp; ：より直感的で、ユーザーのコンテキストを限定していない
　・設計面&emsp;&emsp;：疎結合

## 4.モダンWEB
- モダンWEBにするとどうなる
　→UXが向上し、ユーザーのアクセシビリティが向上する。開発者たちはユーザーの
　　求めるサービスへの対応速度が上がる。しかし導入コストは高い。

- モダンWEBのモダンは結局なんなのか
　→モダンなWEBサービスの開発を支える要素達１つ１つがモダンWEBなのかなと思います。

## 5.さいごに
&emsp;WEB界隈は魅力的な考え方がどんどん増えていき、それに伴いワードも増えます。
皆さんもぜひ気になるワードを調べて、実装してみてください。

**モダンなリンク**
・[『Web技術の基本』](https://www.amazon.co.jp/%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88%E5%9B%B3%E8%A7%A3%E5%BC%8F-%E3%81%93%E3%81%AE%E4%B8%80%E5%86%8A%E3%81%A7%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8BWeb%E6%8A%80%E8%A1%93%E3%81%AE%E5%9F%BA%E6%9C%AC-%E5%B0%8F%E6%9E%97-%E6%81%AD%E5%B9%B3/dp/4797388811)
・[『モダンWeb ―新しいWebプラットフォームの基盤技術』](https://www.amazon.co.jp/%E3%83%A2%E3%83%80%E3%83%B3Web-%E2%80%95%E6%96%B0%E3%81%97%E3%81%84Web%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE%E5%9F%BA%E7%9B%A4%E6%8A%80%E8%A1%93-Peter-Gasston/dp/4873116929)
・[『PRPL パターン』](https://developers.google.com/web/fundamentals/performance/prpl-pattern?hl=ja)
・[『プログレッシブエンハンスメント』](https://developer.mozilla.org/ja/docs/Glossary/Progressive_Enhancement)
・[『プログレッシブウェブアプリ』](https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps)
・[『インターネット歴史年表』](https://www.nic.ad.jp/timeline/)
discordrbで作る、1プロセスで複数BOTを動かす方法

# この記事の対象
- discordrbが何なのか程度はわかる人
- Herokuの無料枠で複数のBOTを稼働させたい人

discordrbを使った基本的なBOTの作り方については他に記事があるため、この記事では割愛させていただきます。

- [イチからDiscord Bot 。for Ruby](https://qiita.com/denebola/items/efaeb0f5c20d44608a71)
- [discordrbの逆引き的Tips](https://qiita.com/denebola/items/d50a92c5e1b59d9de489)

# 作り方
さっそく本題になりますが、discordrb（というかRuby）では[Python(discord.py)のように](https://qiita.com/1ntegrale9/items/d0010489fbeb50aee618)特別マルチスレッドを意識しなくても簡単に1プロセスで複数のBOTを稼働させることができます。
以下がそのコードとなりますが、単にBOTごとにインスタンスを分けるだけで実現可能です。

```ruby
require 'discordrb'

TOKEN1 = #1つ目のBOTのトークン
TOKEN2 = #2つ目のBOTのトークン

bot1 = Discordrb::Commands::CommandBot.new(token: TOKEN1, prefix: "/")
bot1.command(:test1) { "TEST BOT1!" }

bot2 = Discordrb::Commands::CommandBot.new(token: TOKEN2, prefix: "/")
bot2.command(:test2) { "TEST BOT2!" }

bot1.run(:async)
bot2.run
```
1つ注意が必要なのは[`Discordrb::Bot#run`](https://www.rubydoc.info/github/meew0/discordrb/Discordrb/Bot#run-instance_method)はそのままだと以降の行の実行を止めてしまいます。
ですから、最後以外の`#run`では引数に必ず`:async`を渡しておく必要があります。

# 動かす上での問題点
以上のようにインスタンスを分けるだけで複数のBOTを実行することができますが、残念ながら出力ログは分かてくれません。
どちらのBOTも同じようにログを出力するため、基本的に見分けることもできません。
よって実際の開発ではBOT別に十分デバッグを行った上で、運用段階で統合させるのが良いでしょう。
また、1つのアプリをデプロイするために、全てのアプリを起動しなおすことになるため、わりと手間がかかります。

# 開発するときの工夫
実際の開発では上の例のように複数のBOTを1つのコード内に書くことはありませんし、するべきではありません。
そのため、BOTごとにクラスを定義して実行用のスクリプトで呼び出す方が現実的かと思います。
以下は私が実際に運用しているBOTで使用している方法です。

```ruby:test_bot1.rb
require 'discordrb'

class TestBot1
  def initialize(token)
    @bot = Discordrb::Commands::CommandBot.new(token: token, prefix: "/")

    @bot.ready { @bot.game = "TestBot1" }

    @bot.command(:test1) { "TestBot1" }
  end

  def run(async = false)
    @bot.run(async)
  end
end
```

```ruby:test_bot2.rb
require 'discordrb'

class TestBot2
  def initialize(token)
    @bot = Discordrb::Commands::CommandBot.new(token: token, prefix: "/")

    @bot.ready { @bot.game = "TestBot2" }

    @bot.command(:test2) { "TestBot2" }
  end

  def run(async = false)
    @bot.run(async)
  end
end
```

```ruby:execute_bots.rb
require './test_bot1'
require './test_bot2'

test_bot1 = TestBot1.new("BOTのトークン")
test_bot2 = TestBot2.new("BOTのトークン")

test_bot1.run(:async)
test_bot2.run
```

# 最後に
初めてAdvent Calendarというものに参加させていただきました。
優しい日本語を心がけようとした結果、少しおかしな読みにくい文章になってしまいましたが、最後まで読んで頂きありがとうございます。
何かあればお気軽にコメントを頂ければと思います。
それでは。
Jestについて学んだことまとめ

## 目次
1. Jestとは
2. なぜテストが必要なのか
3. 何をテストするのか
4. Jestの使い方について
5. 今後学習すべき課題

## 今回の学習のゴール
- Jestとは何か、何ができるかを知る
- 実際の使い方について知る

## 1. Jestとは
- Facebookがオープンソースとして開発しているテストフレームワーク
- JavaScriptの単体テストのためのツール
- 特徴
    - テストを自動的に並行で実行する
    - ウォッチモードでは変更されたファイルに関連するテストのみを実行する
        - ウォッチモード : テストコードに変更がある度にテストを実行できるモード
- TypeScriptで記述したものでも利用できる

## 2. なぜテストが必要なのか
- 品質の担保のため
    - 不具合が発生しないようにするため
    - 仕様通りに動くことを確認しリリースするため

※ テストカバレッジを出すことで、テストケースが十分に網羅されていないコードをできるだけ少数に抑えることが可能となる（テストカバレッジとは、所定の網羅条件がテストによってどれだけ実行されたかを割合で表したもの）

## 3. 何をテストするのか
- Jestは、JavaScriptの単体テストのためのツールであるので、
関数やメソッドといった小さい単位で1つ1つの処理が正しく機能しているかを確認する
    - 単体テストは、テストの1種
        - ウォーターフォール型の開発では、単体テスト、結合テスト、システムテスト、運用テストがある
        - 結合テストでは、いくつかのモジュールを組み合わせた際に仕様通り動くか確認する
        - システムテストでは、開発環境ではなく本番同様の環境で、仕様通り動くか要件を満たしているか等の確認をする
        - 運用テストでは、システムの運用者（エンドユーザー）が動作を確認する
    - 単体テストは、テストの対象単位が小さく摘出した不具合の修正が比較的簡単であるため、できるだけ多くのバグを摘出する必要がある

## 4. Jestの使い方について
### npmを利用してJestをローカルにインストール

```console
npm install --save-dev jest
```
### matcher関数（値のテストをする関数）を使ったJest使用例
※ matcher関数の一覧は[expect API ドキュメント](https://jestjs.io/docs/ja/expect)を参照

- テストしたい対象を用意

```javascript:sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;    // 関数sumをmoduleとして扱いexportsする
```
- テストコードが書かれたファイルの作成
    - 関数expectは、値をテストしたい時に使用する関数で、値について何らかの事をアサートする関数とともに使用する

```javascript:sum.test.js
const sum = require('./sum');    // exportsされた関数を呼び出す

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);    // 関数expectと関数toBeの値が等しいかテスト
});
```
### package.jsonに以下を記述
- scriptsプロパティは、任意のshell scriptを実行するエイリアスコマンドを定義できる
    - shell scriptで書かれる主な処理は、ファイルの操作、プログラムの実行、テキストの印刷など
    - エイリアスとは、コマンドに別名を付けること
- npm run testでテストを実行することができるようになる

```json:package.json
{
  "scripts": {
    "test": "jest"
  }
}
```
- 上記のファイル構成は以下の通り

```
.
├── package.json
├── sum.js
└── sum.test.js
```

### テストの実行コマンド

```console
npm run test
```
### 実行結果
- テストが成功して問題がなかった場合PASSと表示される
    - テストに失敗するとFAILと表示される

```console
PASS  ./sum.test.js
✓ adds 1 + 2 to equal 3 (5ms)
```
### Jestコマンドのヘルプ
- 使用可能な全てのオプションを参照できる

```console
jest --help
```

### ウォッチモードでテストを実行する場合
- テストコードに変更がある度にテストを実行することができるモード

```console
npm test -- --watch    # npmで実行
npm test -- --watchAll    # npmで全てのテストを実行
```

## 5. 今後学習すべき課題
- [API Reference · Jest](https://doc.ebichu.cc/jest/docs/ja/api.html#content)を参照して、テストファイル内に記述するメソッドについて理解し、実際にテストコードを書く
- テストどこまでやるのか問題



## 参考
- [単体テスト — Vue.js](https://jp.vuejs.org/v2/guide/unit-testing.html#ad)
- [Jest · 快適なJavaScriptのテスト](https://jestjs.io/docs/ja/getting-started.html)
- [Expect · Jest](https://doc.ebichu.cc/jest/docs/ja/expect.html)
- [Jestで始める！ ユニットテスト](https://app.codegrid.net/entry/2018-jest-1)
再起動してもParallelsDesktop 上のwindowsが真っ暗なまま戻らない

# 動作環境
MacOS Mojava
Parallels Desktop 11 for Mac
仮想OS Windows10

## 症状
Windows10を何度再起動しても、画面が真っ暗なまま、唯一できることはcontrol + alt でカーソルを表示させること。

# 解決方法
以下の画面で、「ウィンドウを閉じたとき」の設定を以下のようにシャットダウンに変更する。
<img width="669" alt="windows_blackout.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262477/be9783b8-d8da-8092-22a0-1e8bd3032a7d.png">
複数のGoogleカレンダーの予定をLINEに毎朝通知する

# やりたいこと
複数のGoogleカレンダーの予定をLINEに毎朝通知します．

具体的には，

- 毎朝
- 複数のアカウントカレンダーの予定を
- 当日分
- LINEのグループに

通知するようにします．

# 背景
「予定通知をLINEでできたら便利だな」と思い，この記事『[家族のGoogleカレンダーの予定をLINEに通知する](https://qiita.com/monoqlock/items/55bf4860003ab1405a7f)』を参考にして導入しました．

しかし実際に使ってみると，「週単位じゃなくて**当日単位の予定通知**の方が欲しい！」となったため，実装してみました．

# 所要時間
スクリプトもコピペであれば，30分で設定できると思います．

# 手順
この記事『[家族のGoogleカレンダーの予定をLINEに通知する](https://qiita.com/monoqlock/items/55bf4860003ab1405a7f)』をご覧ください．

概略だけ記すと，

1. 1つのGoogleカレンダーで複数アカウントのカレンダーを確認できるようにする．
2. LINE Notifyの設定をする．
3. GoogleAppsScriptを利用する．

です．
# 変更点
『[家族のGoogleカレンダーの予定をLINEに通知する](https://qiita.com/monoqlock/items/55bf4860003ab1405a7f)』と違う部分は，GoogleAppsScriptのコード内容です．

当日分の予定通知の場合は，以下のコードをコピペします．
この際に２点だけ修正をしてください．

- `token`の設定（１行目）
    - LINE Notifyで作成したアクセストークンを設定します．
- `calendarTitleMap`の設定（４行目あたり）
    - 個人アカウント（gmailアドレス）とカレンダーの名称を対応づけます．

```ruby:daily_calendar.gs
var token = "作成したトークン"; // TODO: ここに発行したアクセストークンを記載

// TODO: ここにカレンダー名を設定
var calendarTitleMap = {
  "hoge@gmail.com" : "hogeの予定",
  "huga@gmail.com": "hugaの予定",
  "ja.japanese#holiday@group.v.calendar.google.com": "日本の祝日",
};

function notifydaily() {

  var calendars = CalendarApp.getAllCalendars();
  var dt = new Date()
  var message = "今日の予定\n\n";
  dt.setDate(dt.getDate());
  message += Utilities.formatDate(dt, 'JST', 'yyyy/MM/dd') + "\n"; 
  var dayText = "";
  for(j in calendars) {
    var calendar = calendars[j];
    
    var calendarName = calendarTitleMap[calendar.getId()]
    if ( calendarName == undefined ) {
      continue;
    }
    
    var events = calendar.getEventsForDay(dt);
    if( events.length == 0 ) {
      continue;
    }
    
    dayText += "< " + calendarName + " >\n";
    for(j in events) {
      dayText += toDayText(events[j]);
    }
    dayText += "\n"
  }
  
  if ( dayText == "") {
    dayText += "予定はありません\n\n";
  }
  message += dayText;
  sendToLine(message);
}

function sendToLine(message){
  var options =
   {
     "method"  : "post",
     "headers" : {"Authorization" : "Bearer "+ token},
     "payload" : "message=" + message
   };

   UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}

function toDayText(event) {
  return toTimeText(event.getStartTime()) + ' - ' + toTimeText(event.getEndTime()) + " " + event.getTitle() + '\n';
}

function toTimeText(str){
  return Utilities.formatDate(str, 'JST', 'HH:mm');
}
```

これ以降の設定も参考記事『[家族のGoogleカレンダーの予定をLINEに通知する](https://qiita.com/monoqlock/items/55bf4860003ab1405a7f)』通りです．

毎朝通知を導入してみたら，予定ブッチが無くなりました．よかったです．
# 参考

『家族のGoogleカレンダーの予定をLINEに通知する』
[https://qiita.com/monoqlock/items/55bf4860003ab1405a7f](https://qiita.com/monoqlock/items/55bf4860003ab1405a7f)

『Googleカレンダーの予定を毎朝LINEに通知する』
[https://blog.piyo.tech/posts/2018-04-17-line-notify/](https://blog.piyo.tech/posts/2018-04-17-line-notify/)

『LINE Notify API Document』
[https://notify-bot.line.me/doc/ja/](https://notify-bot.line.me/doc/ja/)

『Google Apps Script > Calendar Service』
[https://developers.google.com/apps-script/reference/calendar/](https://developers.google.com/apps-script/reference/calendar/)
ばかやろう！！！！　SIerに悪いところなんて！！！　あるわけねぇだろうが！！！！　それは、あいとゆうきのおとぎばなし。

#この投稿は？

筆者の体験を元に記すSIer脱出物語です。

なお、筆者はいわゆる五大SIer出身ではありませんし、なんなら中小企業出身です。

しかも経歴の半分以上がSESになります。すまんな。

　
　
#簡単な職歴

中小企業に新卒入社。

累計5年間SES事業に従事。大手SIerの下での業務経験あり。

累計2年間自社製品開発に従事。オフショアを用いたPM経験あり。

現在は転職してiPaaSを開発中です。
　

　
#現場のExcelワーク

Excel大正義。Excel使うやつは大体トモダチ。

WBSも、設計書も、要件定義資料もExcel。数式は一子相伝。

SIerのWBSはすごいんだ。ボタン押すだけでアクティビティが追加できるぞ。

予実を入力するとアラ不思議！　工数の消化率や見込残工数まで出してくれちゃう！

あるボタンを押せばアラ不思議！

要員ごとの稼働状況が一目で分かるサマリーシートの完成さ！
　

　
　
#なんで脱出したの？

2019/06に前述の中小企業を脱出しました。

理由はおちんぎんが3年間上がらなかったからですね。

二人目の子どもも考えてるのにこのままではアカンかった。

詳しくは[拙note](https://note.com/kosnake/n/n2f6303828c90)をご覧ください。

　
　
#SIerに悪いところなんて！！！

まあ、あるでしょうね。
　
　
#SIer脱出してよかったのか？

よかったですよ。前述の通りSIerとも言えない中小企業でしたけども。

改革を推し進めてはいましたが、依然としてSESが売上の主軸(6割)でした。

上のポジションとなっても、現場バラバラのプロパの統括、および各現場へのBP(Business Partner、いわゆる協力会社、いわゆる下請け)投入・管理が主な仕事。プロパはだいたい原価割れするので、BP投入の利ざやで稼ぐスタイルでした。請負受注やシステムインテグレーションの仕事の割合を増やそうとしてましたけどね。待てませんでした。

下請けも経験した。自社開発も経験した。次の景色が見たくなりました。

　
　
#あいとゆうきのおとぎばなし

この記事は生きとし生ける全ての働く人たちに捧げます。

限りある生を、実りある時間に。

あいとゆうきのおとぎばなしの[元ネタ](http://5pb.jp/games/muvluv/alternative/)
プログラミング初心者の配列のまとめ

今週は制作物を投稿するつもりでしたが、忘備録として投稿したい内容があるのでそっちを先に。

プログラミング学習始めて２ヶ月。JSとPHPを学んできました。
そこでずっとずっとずっと悩みの種の一つが**配列**。
JS時もイマイチで、その後PHPの勉強をしたのですが、ここでも出てくる配列。
今回課題作成にあたり相当配列を使ったので、忘れないよう忘備録として書きます。

当たり前と言えば当たり前の事なんですが、私はここまでたどり着くのに２ヶ月・・・
そして正直まだ全部理解したとも思えず・・・自信はありません。

まず普通の配列

```javascript


let array = ["name","id","pw","emal"];
    //配列の長さを取得
    console.log(array.length); //4
    //配列の１個目を取得
    console.log(array[1]); //"name"
   //"pw"が配列内の何個目にあるか知りたい
    const result = $.inArray("pw",array);
    console.log(result);//2

```

次に連想配列
連想配列はkey:valueで成り立っている

```javascript

 let arary ={name:"鈴木",id:"1111",pw:"aaaa",email:"test@test.com"}
    //配列内のkey名取得
    const key = Object.keys(array);
    console.log(key);//["name", "id", "pw", "email"]
    //nameというkeyのvalueを取得
    console.log(array.name);//"鈴木"
```

最後に多次元の連想配列、普通の配列＋連想配列のイメージ

```javascript
let array = [{ name: "鈴木", id: "1111", pw: "aaaa", email: "test@test.com" }, { name: "田中", id: "2222", pw: "bbbb", email: "test2@test2.com" }, { name: "佐藤", id: "3333", pw: "cccc", email: "test3@test3.com" }
  ];
  // 多次元配列内の１番目の連想配列を取得
  console.log(array[1]);//{name: "田中", id: "2222", pw: "bbbb", email: "test2@test2.com"}
  // 取得した連想配列の"name"keyのvalueを取得
  console.log(arryB[1].name);//"田中"
```

今思い返すと「配列苦手！」と感じていた要因としては、
大体何か作っていて配列使う時はループ処理が伴う事が多かった。
私はまだまだプログラミング脳ではないためループ処理はループ処理でよくわからんかったし（回すって何！？というレベルでした）、その上イメージがつかない配列があってぐちゃぐちゃ。
例えばこういうの

```javascript
let array = [{ name: "鈴木", id: "1111", pw: "aaaa", email: "test@test.com" }, { name: "田中", id: "2222", pw: "bbbb", email: "test2@test2.com" }, { name: "佐藤", id: "3333", pw: "cccc", email: "test3@test3.com" }
  ];
// 多次元配列のキーを取得
  let keyB = Object.keys(arryB);
    console.log(keyB);// ["0", "1", "2"]

for (var i = 0; i < key.length; i++) {
    let all = (array[i])
//多次元配列内の全ての連想配列を取得
    console.log(all);
//取得した連想配列の"id"keyのvalueを取得
    console.log(all["id"]);//"1111","2222","3333"
  }
```


　JSだけの時はこればっかりで訳わからなかったのですが、個人的にはPHPも勉強してデータを扱うようになって、[配列]とループ処理が少しずつわかってきたかも！？って感じです。
Reveal - あなたのWebサービスに10行でデータ可視化(Reveal)機能を組み込み！Getting Started!


# はじめに

## Revealとは
[Reveal  ダッシュボードをアプリケーションに組み込み](https://www.revealbi.io/jp)
> Reveal Embeddedは、アプリケーションに組み込み可能なデータ可視化SDKです。シンプルな価格体系、組み込みの容易さでアプリケーションの価値を最大限向上することができます。

## この記事は
RevealをWebアプリケーションに組み込むための最短手順をご紹介します！

# 前提
・Reveal SDKがインストールされていること。
(スクリプトファイルをコピーして利用するため)

下記ページより入手できます。
[ダッシュボードをアプリケーションに組み込み | データ可視化 | Reveal](https://www.revealbi.io/jp)

# サンプルのフォルダ構成
┣ index.html … 表示のサンプル。後ほど記載。
┗ Reveal
　 ┣ infragistics.reveal.js … Revealのスクリプト本体
　 ┗ infragistics.langpack.ja.js … Revealの日本語リソース

# スクリプトファイルを取得/配置
Revealのインストールフォルダから必要なスクリプトファイルを配置します。
C:\Users\Public\Documents\Infragistics\Reveal\SDK\Web\JS\Client

上記のフォルダから、下記２つのファイルをコピー

infragistics.reveal.js 
infragistics.langpack.ja.js

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/22c0dc6c-16b6-ed31-2fe0-efc187f67069.png)




# サンプルソース


``` index.html

<!DOCTYPE html>
<html>
<head>
 <meta http-equiv="content-type" charset="utf-8">
    <!-- jQuery読み込み -->
    <script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
    <!-- Revealのスクリプト読込 -->
    <script src="./Reveal/infragistics.reveal.js"></script>
</head>

<body>
    <div id="revealView" style="height:600px;" />

    <script type="text/javascript">
        var dashboardId = "dashboardId";
        var revealSettings = new $.ig.RevealSettings(null);
        new $.ig.RevealView("#revealView", revealSettings);
    </script>
</body>
</html>

```

## 動作確認
サンプルソースをブラウザで表示し、Revealの立ち上がりが確認できればOK!

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/6b887b61-a849-1351-c4bc-c3628a2b7f0b.png)


## 参考リンク
Reveal SDKの入手はこちらから
https://www.revealbi.io/jp

# まとめ
この記事では、Revealを表示するまでの最短ソースの実現方法をご紹介しました。
但し、データソースはまだ設定していないため、Revealに表示するデータソースを設定する必要があります。

次回は、Revealにデータソースを設定する手順を紹介します！
box-shadowで月の表現

# 最終成果物
これです。
ぽいですね。
これがbox-shadowプロパティで実現できます。

![moon.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177043/bdedd336-05f1-9cfd-3997-c9da477fc171.gif)

# 実装
## 土台になるhtmlの用意
さっくりと。

```moon.html
<!DOCTYPE html>
<html lang ="ja">
<head>
    <link rel="stylesheet" href="../css/moon.css">
</head>
<body>
    <main class="stage">
        <div class="moon"></div>
    </main>
</body>
</html>
```

## CSS
こちらもさっくりと。
解説はあとあと。
stageはただの背景なのでそんなに気にしなくていいです。

```moon.css
/**
* stage
*/
.stage {
  position: absolute;
  width: 100%; height: 100%;
  background-color: rgb(228, 217, 210);
  display: flex;
  justify-content: center;
  align-items: center;
}
.stage:before,
.stage:after { position: absolute; content: ""; display: block; }
.stage:before {
  top: 20px; left: 20px;
  width: calc(100% - 40px); height: calc(100% - 40px);
  border: solid 5px #6e5c60;
  border-radius: 30px;
  box-sizing: border-box;
  opacity: 0.3;
}

/**
* moon
*/

.moon {
  width: 500px;
  height: 500px;
  border-radius: 100%;
  animation: anime 5s linear infinite;
}

@keyframes anime{
  from{
    box-shadow: none;
  }
  to{
    box-shadow: 500px -200px 0 0 rgb(254, 228, 137) inset;
  }
}
```

## ちょっとだけ解説
実際のイメージとは逆かもですが、黄色の明るい部分がbox-shadowで表現されている部分です。
keyframesで定義されている通り、影がない状態から影がある状態にアニメーションさせています。
円形に別のオブジェクトを重ねようとするとどうしても線形な変化になってしまうので、自身に影をつけることで変化させます。
当然外側に影をつけても月にはならないので内側に変化させるためにinsetをbox-shadowにつけるのを忘れずに。

## まとめ
box-shadowを内側につけるのは何かと使う場面がありそうですね。
意識していないと忘れてしまいそうなプロパティなのでたまに使ってあげましょう。
dart2nativeを使ってggrksコマンドを作る

Dart 2.6で導入されたdart2nativeの話を2日目の記事で書きました。
https://qiita.com/YusukeIwaki/items/28c7dc837cf1a0f9407b

今回はその応用編で、puppeteerを使ったggrksコマンドを作ってみます。
あらかじめ書いておきますが、実用性はありません。

![image](https://user-images.githubusercontent.com/11763113/69257935-2dbabc00-0bff-11ea-8c83-3ff5006b302a.gif)

## pubspec.yamlの編集

```pubspec.yaml
name: ggrks

dependencies:
  puppeteer: ^1.14.1
```

とりあえず最新の [puppeteer](https://pub.dev/packages/puppeteer) を使います。

余談ですが、このpuppeteerのライブラリは非公式のものです。
なんですが、非公式にしてはとても完成度が高く、APIドキュメントなどがしっかり書かれているため、2019年12月現在でも（趣味の用途であれば）十分に使えます。

## ブラウザ操作をする雛形

puppeteer-dartを使うときのボイラープレートコードは、macOSであればだいたい↓です。

```main.dart
import 'package:puppeteer/puppeteer.dart';

main() async {
  final browser = await puppeteer.launch(
    // MacにインストールされているChromeを使う。
    executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',

    // ブラウザ画面を表示しながら（ヘッドレスモードを無効にする）。
    headless: false,

    args: [
      // ゲストセッションで操作する。
      "--guest",

      // ウインドウサイズをデフォルトより大きめに。
      '--window-size=1280,800',
    ],

    // 人間味のある速度で入力/操作する。
    slowMo: Duration(milliseconds: 80),
  );

  // 大抵のサンプルコードはここで単純に browser.newPage() しているだけのものが多いが、
  // ブラウザを開いたときにすでに１つタブが開いている場合には、２つ目のタブが開いてしまう。
  // それを防ぐため、すでにタブが開いている場合にはそれを使うようにする。
  final browserPages = await browser.pages;
  final Page page = browserPages.isNotEmpty ? browserPages.first : (await browser.newPage());

  await page.setViewport(DeviceViewport(width: 1280, height: 800));

  await page.goto("https://github.com/"); // 初期ページの表示

  // ここで色々操作をする

  await browser.close();
}
```

今回は、Google検索をしたいので、

```main.dart
final searchKeyword = "puppeteer"; // TODO: コマンドライン引数か標準入力を受けるように修正する

await page.goto("https://google.com/");
await page.type("input[name='q']", searchKeyword);
await page.keyboard.press(Key.enter);

// 3秒後に閉じる。
await Future.delayed(Duration(seconds: 3));
```

この時点で、 `dart main.dart` すれば

![ggrks.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74571/5c90674e-b5fa-e248-9dee-f278c84c6844.gif)


こんな感じでGoogleでキーワードをカタカタ入力して検索結果を表示することができます。

## コマンドライン引数を受け付けるようにする

コマンドライン引数は、 [args](https://pub.dev/packages/args) パッケージを使って解析するのが普通ですが、今回は面倒なので

```main.dart
main(List<String> args) async {

  final searchKeyword = args.join(" "); 
```

にしちゃいます。

たとえば `dart main.dart puppeteer 使い方` みたいに実行すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74571/73112039-7ce1-70ad-ab4a-0616c6466eff.png)

このように、引数がそのまま文字列になってググられるようにしたいからです。

（もちろん[args](https://pub.dev/packages/args) を使ってもそういうことはできるんですが、ggrksコマンドごときに `-h`（usage表示）とかいろいろ考えたくなかったのでｗｗ :sweat_smile: ）

## dart2nativeでシングルバイナリにする

これはとても簡単で、

```
$ dart2native main.dart -o ggrks
```

以上です。

### ちなみに、ggrksは意外と便利ｗ

完全に余談ですが、

```
$ sudo mv ggrks /usr/local/bin
```

しておけば、ちょっと調べたいときに、

```
$ ggrks よろしくお願いいたします　英語
```

３秒だけブラウザが開いて、地味に便利ですよｗ
（わざわざGoogleトップページでカタカタする必要はないといえばそうなんですがww）

## まとめ

dart2nativeと [puppeteer-dart](https://github.com/xvrh/puppeteer-dart) を使って、ggrksコマンドを作る例を書いてみました。
puppeteer-dartは超便利なので、コマンドラインツールじゃなくてもぜひ使ってみると良いです。
新チームでasanaを少し工夫して利用した件

本記事は [NewsPicks Advent Calendar 2019](https://qiita.com/advent-calendar/2019/newspicks) の11日目の記事です。

# はじめに
はじめまして、NewsPicksエンジニアの清水です。
8月に発足した開発チームを駆動させるべく、チケットの管理に[asana](https://asana.com/ja)を利用しており、その使い方を紹介したいと思います。

# asanaとは
チームで仕事をする場合、メンバーが担当しているタスクや、今後対応が必要なタスクなど、多くのタスクを管理する必要があります。
タスクの管理には、表計算ソフト（ExcelやGoolgeスプレットシートなど）を利用するケースもありますが、専用のタスク管理ツールを利用することで、効率よく管理することが可能となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165221/fc0cf2f4-1df1-8d50-4334-f811758cc3fd.png)


asanaは、タスク管理ツールの一つで、以下のような特徴を持っています。

* 複雑な設定をすることなく、シンプルに使うことができる
* プロジェクトごとに、ビュー（リスト / ボード / タイムライン / カレンダー）を変えることができる
* 一つのチケットを複数のプロジェクトに紐付けることができる

# バックログ
私達のチームでは、チームのマネジメント手法として **スクラム** を採用しています。スクラムの説明は割愛しますが、スクラムではチームで消化するタスクをバックログというリストで管理します。
バックログの運用はシンプルで、取り組みたいタスクを上から順番にタスクが並んでおり、チームのメンバーは手が空いたらリストの一番上のタスクから対応していきます。
実際には、メンバーのスキルによって一番上のタスクを担当することができないケースもありますが、このように運用することで、次やるべきことが見える化されるメリットがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165221/23a86658-a837-ef73-1fa1-16eff0051f69.png)

各タスクには、タスクの重みポイントとしてつけるようにしています。所謂ストーリーポイントですが、新しいチームということもあり、ポイントの付け方の認識をメンバー間で合わせるため、以下のように参考となる人日を併記するようにしました。（ストーリーポイントにはフィボナッチ数列を採用しています）

* 1（1〜2時間）
* 2（半日）
* 3（5〜6時間）
* 5（1日）

# カンバン
バックログには、今作業しているタスク、今後やるべきタスクが全て羅列されているので、全体が確認しやすい一方、作業中タスクのステータスが分かりづらい面があります。
そのため、スクラムのスプリント毎（１週間）に作業するタスクのステータスが可視化できるように、 **カンバン** でのタスク運用をしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165221/96d4ea3a-34e3-7512-c5de-3e4332fb8b52.png)

asanaでは、一つのタスクを複数のプロジェクトに紐付けることができるので、先程のバックログのプロジェクトとは別に、カンバンのプロジェクトを作成し、スプリント計画時に今週のスプリントのタスクをカンバンに紐付けるようにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165221/867cf5f0-df46-1a51-8a62-7ffa49344c18.png)

バックログとカンバンを使い分けることによって、全体のタスクと作業中のタスクを分けて整理することができます。

# KPT
スクラムのスプリントの終わりには、**ふりかえり**という今後のスプリントを改善するための時間があります。
ふりかえりでは、KPTというフレームワークでKeep（継続したいこと）、Problem（直面した課題）、Try（次にやってみること）をメンバーで出し合います。
KPTの運用でよく見かけるのは、ホワイトボードに手書きの付箋を貼って全員で共有するという方法ですが、この方法にはいくつか課題があります。

* 付箋に書いた文字が読めない（クセのある字や、文字が小さいなど）
* 付箋の接着が弱く剥がれてしまう
* 記録に残すため、実施後のホワイトボードを写真に取るが、見返すことはない
* 見返せるようにデジタル化したいが、人手でスプレットシートなどに転記する必要がある

これらを改善するため、KPTをasanaで実施するようにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165221/8f859172-1d32-4470-c2dd-46e952e43c09.png)

asanaでKPTを運用することで、Tryに入れた施策をバックログにも紐付けることができるので、タスクを二重管理しなくても良くなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165221/6c1d11e6-efc4-f651-f4bf-b4c31f555549.png)

# 全体
バックログ、カンバン、KPTそれぞれで作成、管理しているタスクの運用の様子を図にまとめてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165221/449280fe-4fdb-6ca8-3404-3a8c8f1ee99c.png)

このように、チームで実施するタスクを一元管理しつつ、スクラムのイベントごとに適切なビューに切り替えて運用することで、効率よくタスクを管理することができるようになっています。

タスク管理に限らずチーム運用は、そのチームに属しているメンバーや作業内容、組織の規模など様々な要素によって最適な運用が変わってくると思います。今後も、状況の変化に合わせて、アジャイルに改善しながらチームが働きやすくなる環境を整備していきます。
CsvHelperの簡単な日付変換

# CsvHelperの簡単な日付変換で読み込む

CsvHelper 12.2.1

読み込むCSVの日付列が"20190101"のような形式だった時、属性で変換を指定して読み込む方法。
書き込みもたぶん同じ。試してない。

最初はClassMapを書いて読み込みをしていたが、日付を形式変換するためにClassMapを書くのは面倒だなと思って調べてたら、AttributesにFormatがあるなと気づいた話。

[CsvHelper.Configuration.Attributes Namespace](https://joshclose.github.io/CsvHelper/api/CsvHelper.Configuration.Attributes/)

100列とかあったとき、数列のためにClassMapを書くのはつかれるのでちょっとは楽になった。
ただ、何かに影響するかは知らない。

## 最初に書いていたソース

```csharp
//File,Encoding,HasHeaderRecordはどっかで設定
public IEnumerable<CSV_Format> GetRecords()
{
    try
    {
        using (var reader = new StreamReader(File, Encoding.GetEncoding(EncodingName)))
        using (var csv = new CsvReader(reader))
        {
            csv.Configuration.HasHeaderRecord = HasHeaderRecord;
            csv.Configuration.RegisterClassMap<CSV_Format_Mapper>();
            return csv.GetRecords<CSV_Format>();
        }
    }
    catch (Exception ex)
    {
        //..例外処理..
    }
}
```

```csharp
class CSV_Format_Mapper : ClassMap<CSV_Format>
    {
        public CSV_Format_Mapper()
        {
            Map(x => x.col1).Index(1);
            Map(x => x.col2).Index(2);
            Map(x => x.col4).Index(4).TypeConverterOption.Format("yyyyMMdd");
            Map(x => x.col6).Index(6);
        }
    }

    class CSV_Format
    {
        public string col1 { get; set; }
        public int col2 { get; set; }
        public DateTime col4 { get; set; }
        public decimal col6 { get; set; }
    }
```

## Attributesを使ったソース

`CSV_Format_Mapper`を書かなくていい!

```csharp
//File,Encoding,HasHeaderRecordはどっかで設定
public IEnumerable<T> GetRecords()
{
    try
    {
        using (var reader = new StreamReader(File, Encoding.GetEncoding(EncodingName)))
        using (var csv = new CsvReader(reader))
        {
            csv.Configuration.HasHeaderRecord = HasHeaderRecord;
            //csv.Configuration.RegisterClassMap<CSV_Format_Mapper>(); //いらなくなった
            return csv.GetRecords<T>();
        }
    }
    catch (Exception ex)
    {
        //..例外処理..
    }
}
```

```csharp
class CSV_Format
{
    [Index(1)]
    public string col1 { get; set; }
    [Index(2)]
    public int col2 { get; set; }
    [Index(3), Format("yyyyMMdd")]
    public DateTime col4 { get; set; }
    [Index(4)]
    public decimal col6 { get; set; }
}
```

## 参考

[Attributes](https://joshclose.github.io/CsvHelper/examples/configuration/attributes/)
[CsvHelper.Configuration.Attributes Namespace](https://joshclose.github.io/CsvHelper/api/CsvHelper.Configuration.Attributes/)