OmniAICreator/Qiita-1.07M huggingface dataset:
postgres distinctしたカラムと別でorder byしたい！

問題
取り出したいものは、重複なくしたidですがその並びを時間や数字で並び替えた状況で、idをとってきたい！

テーブルA
id   時間
1　　　２時
2　　　３時
3　　　１１時　　　
1　　　10時
1　　　８時

この時、単純に
select distinct id from テーブルA order by 時間
では、
SELECT DISTINCT, ORDER BY expressions must appear in select list
と出る。
これは、order byで指定するものはdistinctで指定したカラムでないといけない。


解決策
サブクエリを使う
select * from (select distinct on (id) * from テーブルA) subA order by 時間;


手順１
サブクエリで重複なくしたレコードを生成。
２
そのレコードの中で、並び替える


ポイント
①distinctではなく、distinct onを使う。distinctのみでは、単一のカラムが出てきてしまう。ここで出したいのは、時間を出して時間で並び変えたいから、distinct onして＊でカラム指定で全フィールド取り出す。

②サブクエリの後の（）の後の名前をつける必要がある。（任意の名前）

③全フィールド出した結果、最後に時間でorder byする。
PostgreSQL日本語マニュアル活用３つの技

本記事は「PostgreSQL Advent Calendar 2020」の 8日目です。


PostgreSQLのマニュアルは日々少しずつ進化しています。
今日はあまり知られていないであろうPostgreSQLのマニュアルの活用術を３つ紹介します。
#1.翻訳中のマニュアルを参照する
PostgreSQLの日本語マニュアルはボランティアの手で翻訳、改善が進められています。
各バージョンのマニュアルは翻訳が完了してから公式サイトに公開されます。
しかし、この翻訳、改善中の最新マニュアルは毎日ビルドされており、以下から確認することができます。
英語の原文も表示されるため、翻訳前の記述と比較する際にも便利です。

最新バージョンの記述が知りたいときはこちらを参照しましょう。

https://pgsql-jp.github.io/current/html/ 

#2.バージョン10以前のリリースノートを効率良く参照する
バージョン10までは過去全てのリリースノートのリンクが掲載されていました。

https://www.postgresql.jp/document/10/html/release.html

しかし、バージョン11からリリースノートはマニュアルのサイズがあまりに大きくなるため、該当メジャーバージョンのリリースノートのみがリンクされるようになりました。

https://www.postgresql.jp/document/11/html/release.html

バージョンアップする際の非互換を探す時など、昔のリリースノートを確認したい場合はバージョン10のマニュアルのリリースノートを利用すると効率的です。

#3.リリースノートの修正内容を詳しく知る
リリースノート内容をさらに詳しく知りたい場合、HTMLのソースコードを
覗くとその変更や追加を行ったコミットログを確認することができます。
(コメントアウトされているため、ブラウザからのHTML表示では確認できません)
これを元にgitやHackersを辿ることでその変更の詳しい経緯や議論を確認
することができます。

例）
https://www.postgresql.jp/document/11/html/release-11-5.html

  </p></li><li class="listitem"><!--
Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
Branch: master [5562272a4] 2019-07-23 17:22:15 -0400
Branch: REL_12_STABLE [3ffe655c0] 2019-07-23 17:22:15 -0400　←コミットログ
Branch: REL_11_STABLE [ec7f9a740] 2019-07-23 17:22:15 -0400　←コミットログ
--><p>
<!--
Prevent dropping a partitioned table's trigger if there are pending
trigger events in child partitions (&Aacute;lvaro Herrera)
-->
子パーティションに保留されたトリガイベントがある場合に、パーティションテーブルのトリガの削除を防止しました。
(Álvaro Herrera)
</p><p>

#まとめ
PostgreSQLのマニュアルは使いやすいよう、少しずつ進化しています。
PostgreSQLについてもっと詳しく知りたい場合などに活用ください。
デザイナーがマネージャーになりたがらないらしいというお話

## ごあいさつ
はじめまして。オークファンでEC事業担当デザインチームのマネージャーをしている@af-ogaです。
DTPデザインを3年ほど経験し、その後WEBデザインを1X年(歳バレ防止)やらしてもらってます。
オークファンに来て1年3ヶ月経ちました。

プロフィール写真の猫様はハナちゃんとメイちゃんです。
お友達の飼っている猫様で、今はもっと大人になって少しふてぶてしくなっております。
。。。好き♡九州に去年引っ越してしまってもう1年以上お目にかかれていないけど、好き♡

さて、私の癖についてはどうでもいいですね。

## このテーマにした理由
Advent Calendarに参加するにあたり、何書こうかなーと、デザイナーらしい何かを作ってみるのも楽しそうだなーとかも思いましたが、最近よく耳にするデザインチームのマネージャーについて書いてみることにしました。
ネタ元は先日の**Designship 2020 EXTRA STAGE**でみかけた「**デザイン組織とマネジメントのリアル**」です。登壇者は山下 一樹氏・篠原 健氏・野崎 駿氏・岡崎 耕太氏（モデレーター）。
ちなみに、日曜だったのでパジャマでクイックルワイパーかけながら流し見してました。オンラインイベントって参加のハードル下がって最高かよ◎

## トークセッションには共感しかなかった
どんな話をしてくれるのかとワクワクしていたのですが、トークのテーマとして出たパネルには「**デザイナーがマネージャーになりたがらない**」と書かれていました(笑)
結構衝撃のテーマでしたね。いろいろな会社のデザインリードが集まって話す内容がこれとは。。。出た瞬間『どこの会社でもそうなのかー』と爆笑しました。

理由として上がっていたのは「**デザイナーになる人は、そもそもモノ作りが好きでこの世界に入ってくる人が多いので、ほぼ全員スペシャリストを目指したい**」←そりゃそうだー。私だってそうだものー!!!爆死

## そんな私がマネージャーになった経緯
**なんか決まってた**。

これにつきます。
上記で登壇されていた方の中にも、「なんか気がついたら」って言ってる人がいたので、『ですよねー』と心の中で大きめの声で言いました。

オークファン入社の前職でデザインチームのリーダーをやっていたこともあり、業務もその時とたいして変わらないということで、それほど抵抗感がなかったのですが、このリーダーになったときも、なりたかったわけではなく、周りを見渡してもちょうど時期的に新人が多かったりで他に居なくて、**なんか決まってた**。

そして、オークファンに来て半年でマネージャーへ。
正直、『えっ、先に居た人がやればいいのでは?!』って思いましたw
**どんだけみんなマネジメントしたくないんだ**って(笑)

## 私が思う、デザインチームのマネージャーはこんな人にオススメ
1. 10年以上毎日デザインしてコード書いて新しい技術勉強しての生活に、少しマンネリを感じているがデザイナーをやめる気はさらさら無い
2. 気がついたら人に教える立場になっていた
3. 人のお世話が好き
4. デザイナーだけど組織や経営に興味がある
5. お金の話が得意
6. マネジメントがされていない環境で働いた経験があり、他の人にそんな思いをさせたくない

この中の2個ぐらい当てはまれば、良さそうかなと思います。
私は、1,2,6かな。3は末っ子育ちの私にはあまり無い要素です。

## 一旦やってみるという選択
マネージャーになると、

**プレイングとマネジメントの葛藤は常にある**

『自分でやったほうが早い、教えるのがめんどい、そもそも本当は私が全部デザインしたい、スキル上げたい、デザインじゃない仕事ばかりやってる』。。。書き出すと煩悩の塊のようだ^^;

だだ、そんな欲とは別に、登壇されていたGoodpatchの方も言っていた「**経営の視座に立ったり、事業成果・組織成果にコミットすることで、プレイヤーとしてのレベルも上がる**」について、前職のリーダーの頃から実感があります。
マネージャーになると関わる人も増えて、必然的に広い範囲で見渡してデザイン出来るようになるのかなと。
広い視野で見れることはUIやUXデザインには重要な要素だと思います。
さらにはデザイナーが一人でデザインしているより、チームで作ったほうが良いものが出来ていれば、マネジメントしている私も、良いデザインを世の中に送り出すことに貢献できているのかなと考えるようになりました。
そして、永遠にマネージャーから抜け出せないわけではないので、そのうちまたプレイヤーに戻ったって良いし、その時この経験は絶対に強みになると思っています。

GoodpatchさんとYahoo!さんにはマネージャーお試し期間のような機会があって、自分の適応性が測れたりするとのことで、良いシステムだと思いました。もう少し深く聞きたかった。。。
気軽にやってみようという気持ちになりそうです。

## まとめ
今回は、Designship 2020 EXTRA STAGEのトークセッションに習い、人をマネジメントする事についてはあえて触れませんでした。
それだけで3倍ぐらいの文字数になりそうです^^;

もしかしたらもしかして、これを偉い人が読んで必要と思えば、オークファンにもマネージャーお試し期間が出来る日が来るかもしれないですね|дﾟ)ﾁﾗｯ

世の中に(社内にも)少しでも『機会があればマネージャーやってみようかな』と思うデザイナーが増えてくれれば嬉しいです^^
お読みいただきありがとうございました！
クラウドサーバーを作る 

# クラウドサーバーを作る
この記事では、Raspberry Pi4、NextCloudを使ってクラウドサーバーを作成します。
## 環境

|環境 |
|---|---|
|Raspberry Pi 4 modelB|
|Ubuntu 20.04  |
|NextCloud |
## §1.Raspberry Piをセットアップする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/e533a117-1679-5d87-2eeb-1a128ced85f8.png)
### §1.1Ubuntuをインストールする
Raspberry Pi Imagerを使って、Ubuntu LTS 2020をMicorSDに入れます。
Imagerで、フォーマット等ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/016b444d-3bb8-c5e0-1c4e-1c600168cddb.png)


**フォーマット**
(Rasberry Pi Imagerを使うと、フォーマットもしてくれます)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/2a66700d-c1ff-f4cf-3f2c-c90f8e284ccc.png)



### §1.2Ubuntuを起動する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/01ec1fe5-7d22-30ad-1639-61a9e77ce564.png)


ラズパイ4はデスクトップ向けUbuntuでもサクサク動きます。

### §1.3アップデート
![raspi2020126_4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/07b64777-13ff-b627-5626-8c793c38348f.gif)


## §2.クラウド構築
### §2.1 NextCloudインストール
```
sudo snap install nextcloud
```
![raspi10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/ddb9336e-d39d-8695-0c82-11b7d7e01805.png)

### §2.2 管理アカウント設定
```
sudo nextcloud.manual-install username password
```
## §3.使ってみる
Raspberry PiのIPアドレスを確認して、同じネットワーク内にある別PCからwebブラウザで見るとNext Cloudを使用できるようになります。
```
http://ラズパイのIPアドレス
```
Raspberry PiのIPアドレスを固定したり、ドメインを設定することで外部からでもクラウドサーバーに接続できるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/35acb465-836d-14b4-6ce0-947e3efa093a.png)

## §4.おまけ(ファイルサーバーを作る)

### Sambaインストール
```
sudo apt install samba samba-common-bin
```

### Sambaのconfigを変える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/2df3c2f8-080c-6288-4999-0fbc322dbb86.png)
```
[share]
path = /home/share
browseable = yes
writable = yes
省略
```
### Shareフォルダを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/4ffebd80-b908-ba04-b016-da142fcca54c.png)


### Samba再起動
```
sudo systemctl restart samba
```

## §5.おまけ(ラズパイにssh接続(Windows))
```
ssh RaspberryPiユーザ名@IPアドレス
```
## §5.終わりに
いかがでしたでしょうか？
Raspberry Piを使うと、自宅でサーバー周りについて、手を動かしながら学べるのでとても楽しいです。
【AWS】ファーストタッチレイテンシーの現象を試してみた


# Snapshotからリストアしたボリュームへの初回アクセスはパフォーマンスが落ちる
Snapshotからボリュームをリストアした場合、ブロックに初めてアクセスする時にS3にデータを取りに行きます。そのため、初回アクセスのパフォーマンスが落ちます。これをがファーストタッチレイテンシー(ファーストタッチペナルティ)と呼びます。

[Amazon EBS ボリュームの初期化](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ebs-initialize.html)

今回はこの現象を確認していきます。

# 検証環境とシナリオ
1. Windowsサーバを一台たて、EBSボリュームでCドライブ(120GB:gp2)とDドライブ(120GB:gp2)の準備をします。
1. Cドライブに10GBのデータを作成します。
1. DドライブのSnapshotを作成します
1. 既存のDドライブをデタッチし、取得したSnapshotから作成したボリュームを新しくDドライブとしてアタッチします
1. ここで、CドライブからDドライブへデータを転送して時間を計測します

# 手順
環境構築のコマンドです。

## Cドライべへダミーファイルを作成
```
fsutil file createnew dummy.data (10737418240)
```
## DドライブのEBSSnapshotを作成
```
aws ec2 describe-volumes
aws ec2 create-snapshot --volume-id <voi_id>--tag-specification 'ResourceType=snapshot, Tags=[{Key=Name,Value=testsnapshot}]' --description "for test"
```
https://docs.aws.amazon.com/cli/latest/reference/ec2/create-snapshot.html

:::message
空のボリュームだとファーストタッチレイテンシーが発生しないので、空である場合は何か適当にファイルを配置してください。
:::

## DドライブをEC2インスタンスからデタッチ
```
aws ec2 detach-volume --volume-id <vol_id>
```
https://docs.aws.amazon.com/cli/latest/reference/ec2/detach-volume.html

## DドライブをSnapshotからリストア
```
aws ec2 create-volume --snapshot-id <snapshot_id> --volume-type gp2 --availability-zone ap-northeast-1d 
```
https://docs.aws.amazon.com/cli/latest/reference/ec2/create-volume.html

## DドライブをEC2にアタッチ
```
aws ec2 attach-volume --device <device> --instance-id <instance_id> --volume-id <vol_id>
```
https://docs.aws.amazon.com/cli/latest/reference/ec2/attach-volume.html

## CドライブからDドライブへ転送
```
$watch = New-Object System.Diagnostics.StopWatch
$watch.Start()
Copy-Item  C:\Users\Administrator\Desktop\dummy.data D:\
$watch.Stop()
$t = $watch.Elapsed
"{0} min {1}.{2} sec" -f $t.Minutes,$t.Seconds,$t.Milliseconds
```

## 計測まとめ
| 回数 | 経過時間|
| :--- | :--- |
| 1回目 | 22 min 56.65 sec |
| 2回目以降 | 1 min 19.341 sec |

## まとめ
初回とそれ以降ではかなり差が開きました。ただ、本来であればデータを作成したボリュームのSnapshotを作成し、そのボリュームをリストアしてデータ転送を確認したかったのですが、それだとファーストタッチレイテンシーが発生しなかったので、そこは別で調べようと思います。
【AWS】PrivateHostedZoneを他のアカウントと関連付ける方法


# Private Hosted Zone(PHZ)とは
PHZはDNSのレコードを格納するコンテナです。PrivateとPublicがありますが、Privateだと名前解決をVPC内のみで行うことができます。作成時にドメインを指定しますが、VPC内でそのドメインとサブドメインのDNSクエリに対応することができます。

# アカウントAのPrivate Hosted Zoneに登録されたレコードをアカウントBから参照したい
まず、PHZはドメインとVPCを1:1で関連付けます。VPC内で完結するため、アカウントAのVPCからアカウントBのVPCの名前解決をすることはデフォルトではできません。方法として、PHZに別アカウントのVPCを関連付けるという操作を行います。これは、CLIから対応する必要があります。

# 今回の検証環境について
2つのアカウントを用意して、VPCAとVPCBを作成します。ちょっとわかりにくくなりましたが、黒点線での囲いはアカウント単位です(つまり、2つのアカウントが存在して、その中に環境を構築していることを表しています)

各VPCに紐づくPHZAとPHZBを作成し、各VPCに配置されたEC2インスタンスから別アカウントのEC2に対して、互いに名前解決ができるかを確認していきます。

![](https://storage.googleapis.com/zenn-user-upload/zm95qkz19ys8w8fcd2c6xul7a8og)

# 検証を構築する
## PHZを作成してレコード登録
アカウントAとBの両方でEC2とPHZを構築し、PHZにEC2のレコードを登録します。

### アカウントAのレコードと現時点での名前解決の状況
EC2インスタンのIPとFQDNです。
![](https://storage.googleapis.com/zenn-user-upload/p08m3822yybzpsedgakjupv1ccx2)

同じVPC内の名前解決はできますが、別アカウントのVPCの名前解決はできません。
![](https://storage.googleapis.com/zenn-user-upload/jvxxmwfmkn9wt8zjvv53fiagtpvd)

### アカウントBのレコードと現時点での名前解決の状況
ここの説明は上記と同じため割愛します。
![](https://storage.googleapis.com/zenn-user-upload/ark1oavikpuaf57j0vql9pedkzpx)

![](https://storage.googleapis.com/zenn-user-upload/oap0gsh7odjc4cmnmku3x68kso9q)

## PHZと別アカウントのVPCの関連付け
まずは、アカウントAのPHZにアカウントBのVPCを関連付けます。

最初はこんな感じです。このVPCはアカウントAのVPCです。
![](https://storage.googleapis.com/zenn-user-upload/wh1fr8ec8wbh8z5pbersumrvfiw9)

1. アカウントAで、実行IAMユーザの作成します。ユーザに`Route53FullAccess`を付与します。
2. 1.で作成したユーザで下記コマンドを実行する。つまり、アカウントA側で実行します。
```
aws route53 create-vpc-association-authorization --hosted-zone-id <AのPHZID> --vpc VPCRegion=ap-northeast-1,VPCId=<BのVPCID>
```
3.  アカウントBで、実行IAMユーザの作成し、ユーザに`Route53FullAccess`、`VPCFullAccess`を付与します。

4. 3.で作成したアカウントで下記コマンドを実行します。つまり、ここではアカウントB側で実行します。
```
aws route53 associate-vpc-with-hosted-zone --hosted-zone-id <AのPHZID> --vpc VPCRegion=ap-northeast-1,VPCId=<BのVPCID>
```

そうすると、こうなります。アカウントAのPHZにアカウントBのVPCを関連付けることができました。
![](https://storage.googleapis.com/zenn-user-upload/vbqvdtw5m6v2p8v2a3723d141uct)

次は、BのPHZにAのVPCを関連付けます。手順は同じです。

アカウントBで実行
```
aws route53 create-vpc-association-authorization --hosted-zone-id <BのPHZID> --vpc VPCRegion=ap-northeast-1,VPCId=<AのVPCID>
```

アカウントAで実行
```
aws route53 associate-vpc-with-hosted-zone --hosted-zone-id <BのPHZID> --vpc VPCRegion=ap-northeast-1,VPCId=<AのVPCID>
```

# 検証の結果をみてみる
検証結果を見てみます。先程はできなかった別アカウントの名前解決ができています。

A->B
![](https://storage.googleapis.com/zenn-user-upload/gsh8jrttnmxk7hwntrsbrprqqbuu)

B->A
![](https://storage.googleapis.com/zenn-user-upload/343mvljwmx3zwiultggtl5vhuyk7)
【Docker】コンテナ作成までの操作#1

<h1>本投稿の目的</h1>
・Dockerの操作についての議事録です。

---
<h1>学習に使った教材</h1>
Udemyの ["米国AI開発者がゼロから教えるDocker講座"](https://www.udemy.com/course/aidocker/) を教材として使用しました。

---

<h1>○container作成 (1.作成済みimageを利用する場合)</h1>

<h3>○dockerへlogin</h3>

```
docker login
```

・Docker Hubに登録したID,passを入力する
・Login Succeededで成功

<h3>○imageを取得</h3>

```
docker pull <image名>
```

・Docker Hub のhome から  u/library でimageリストを見れる
・image list の中から必要なimageを選択
・そのimageの適切なTAG (version)を選択

<h3>○Hostに保存済みのimageのlistを取得</h3>

```
docker images
```

・取得したimageが存在することを確認する

<h3>○container作成</h3>

```
docker run <image名>
```

・作成したいcontainerの素となるimage名を指定してrunを実行

**【出力結果例:hello-worldのimageで確認】**

```
Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

・上記のメッセージが表示される
・container作成後にプログラムが実行されたためこれが表示される
・(今回の例では,hello-worldのテキスト出力プログラム)

<h3>○container一覧の確認</h3>

```
docker ps
```

・アクティブなcontainerを表示する
・ps は process statusの略

```
docker ps  -a
```
・全てのcontainerを表示する
・-a は allの略

<h1>○Docker run について</h1>

・docker run を入力すると次のコードたちが連続してシーケンスで実行される

**【runの流れ】**
①.create
②.execute
③.exit

**【解説】**
<①.create>
・runを実行するとcreateが実行される
・containerが作成される

<②.execute>
・createに紐づいてexecuteが実行され・
・デフォルトのプログラムが実行される(今回だとテキスト出力)

<③.exit>
・executeのプログラムが実行されるとexitが実行される
・containerから抜ける

<h1>○pullの省略</h1>
・imageをpullで取得せずにrunを実行できる (以下の流れで実行)
①Hostにimageがないかを確認
②Hostには無いためDocker Hubからimage名を探して取得
③imageをrunする


<h3>○実際の例</h3>

```
docker run ubuntu
```
・ubuntuというOS用のimageに対してpullせずにrunを実行

**【出力結果】**

```
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
da7391352a9b: Pull complete 
14428a6d4bcd: Pull complete 
2c2d948710f2: Pull complete 
Digest: sha256:c95a8e48bf88e9849f3e0f723d9f49fa12c5a00cfc6e60d2bc99d87555295e4c
Status: Downloaded newer image for ubuntu:latest
```

**【解説】**
・pullした時にimage layerがcompleteと表示される
・imageは複数のimage layer から構成される
・コンテナ作成すると新たなimage layerが追加される
・新たなimage layerは書き込み可能なため,コンテナで作業後にimageを別名保存するろとここが更新される

<h3>○layer構成の旨味</h3>
・共通のlayerはcontainer間で共有できる
・差分の新たなlayerのみをスペースとして使用するためスペース削減になる

**【例:container_Aを編集しimage_Bとして保存。これをrunしconatainer_Bを作成した場合を想定】**
・container_A = image_A = layer1 + layer2
・container_B = image_B = container A + 作業 = layer1 + layer2 + layer3 (3が作業部分)

**【解説】**
・container_Bはlayer3分をスペースに必要とする
・layer1,2はcontainer_Aのスペースで保存済みのためcontainerBで新たにスペースは必要ない

---
[解決](Rails, Vue)CORSエラーAccess to XMLHttpRequest at 'http://localhost:3000' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

## なぜこのエラーが出るのか。
https://qiita.com/att55/items/2154a8aad8bf1409db2b

## 解決方法(Rails, Vue)
railsのgem

```ruby:gemfile
#gem rack-coes
```
のコメントアウトを外し、

```
$bundle install
```
↓
config/initializers/cors.rbにある記述も下のようにコメントアウト。

```ruby:config/initializers/cors.rb
# Be sure to restart your server when you modify this file.

# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.

# Read more: https://github.com/cyu/rack-cors

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://localhost:3000', 'https://localhost:8080/'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end
```

originsは、サーバーサイド(API),フロントの順で書きます。
↓
Dockerの場合は、再度コンテナを立ち上げて
↓
完了。
「形態素解析」と「係り受け解析」

# 概要、背景

* 「形態素解析」と「係り受け解析」について調べてまとめる
* 「[データサイエンティストスキルチェックリスト](https://www.datascientist.or.jp/common/docs/skillcheck_ver3.00.pdf)」の「データサイエンス力」項目で**「形態素解析や係り受け解析の概念を説明できる」**とあるため、勉強を兼ねて
* スタート時点：「自然言語処理？かなんか聞いたことはある気がするけど、何するんだっけ？」

# 「形態素解析」「係り受け解析」とは

* 形態素解析
  * **文を形態素（言語で意味を持つ最小単位）に分割し、品詞等を判別する作業**
* 係り受け解析
  * **各単語間の「主語・述語」「修飾語・被修飾語」などの関係を調べること**
* 調べた内容は↓

# 調べたもの

## 形態素解析

### [形態素解析（Wikipedia）](https://ja.wikipedia.org/wiki/%E5%BD%A2%E6%85%8B%E7%B4%A0%E8%A7%A3%E6%9E%90)より

> 形態素解析（けいたいそかいせき、Morphological Analysis）とは、文法的な情報の注記の無い自然言語のテキストデータ（文）から、対象言語の文法や、辞書と呼ばれる単語の品詞等の情報にもとづき、形態素（Morpheme, おおまかにいえば、言語で意味を持つ最小単位）の列に分割し、それぞれの形態素の品詞等を判別する作業である。

* 文を形態素（言語で意味を持つ最小単位）に分割し、品詞等を判別する作業。
* 分割には対象言語の文法や、辞書と呼ばれる単語の品詞等の情報を使う。
* 自然言語処理の分野における主要なテーマのひとつ。「機械翻訳」や「かな漢字変換」などに使われる。

### [形態素解析に代表される自然言語処理の仕組みやツールまとめ](https://www.cogent.co.jp/blog/morphological-analysis-natural-language-processing/)

> 形態素解析の基本4点
> 
> * 「形態素」とは文章を分解した中にある最小単位
> * 文章を形態素に分類するための処理を「形態素解析」と呼ぶ
> * 形態素解析は「形態素解析ツール」で実行する
> * 形態素解析ツールに登録されている「辞書」の情報と照らし合わせて形態素を割り出す

* 文章を形態素に分類するための処理
* 「形態素」=文章を分解した中にある最小単位
* 活用事例
  * 検索エンジン
  * 仮名漢字変換
  * ロボットの音声認識
  * スマートフォンの音声アシスタント
  * スマートスピーカー
  * 翻訳システム
  * SNSのトレンド分析

## 係り受け解析

### [統計的係り受け解析入門](https://www.slideshare.net/unnonouno/ss-5724050)

* 係り受け解析：各単語（or文節）の係り先を決定する
* 応用例：情報抽出

### [自然言語処理のステップ③：「構文解析」とは？](https://ailearn.biz/learn/20200920883)

> 「係り受け」（かかりうけ）とは、文を文節に分けてそれぞれの文節の関係を調べることです．

# 参考にしたサイト

## 形態素解析

* [形態素解析（Wikipedia）](https://ja.wikipedia.org/wiki/%E5%BD%A2%E6%85%8B%E7%B4%A0%E8%A7%A3%E6%9E%90)
* [形態素解析に代表される自然言語処理の仕組みやツールまとめ](https://www.cogent.co.jp/blog/morphological-analysis-natural-language-processing/)
* [2019年末版 形態素解析器の比較](https://qiita.com/hi-asano/items/aaf406db875f1c81530e)

## 係り受け解析

* [統計的係り受け解析入門](https://www.slideshare.net/unnonouno/ss-5724050)
* [自然言語処理のステップ③：「構文解析」とは？](https://ailearn.biz/learn/20200920883)
在宅ワークエンジニアがチャイルドコーチングマイスターを取得した話

この記事は [子育てエンジニア Advent Calendar 2020](https://adventar.org/calendars/5302) の8日目です。

コロナ禍...
在宅ワーク...
体力とヒマを持て余す子供達...


> - 忙しいとき子供の行動についイラッとする
> - 子供が言うことを聞かなくて困っている

コンピューターサイエンスを知らずしてプログラミングすると壁にぶち当たるように、
知識を学ばずに子育てをして壁にぶち当たりました。

私と同じような子育てエンジニアの方に、もしかしたらタメになるかも知れない話を書きます。

## チャイルドコーチングマイスター
会社の福利厚生を利用し、チャイルドコーチングマイスターという資格を取得しました。
https://jafa.jp/shikaku17

子供に言うことを聞かせる資格ではありません。
子供と信頼関係を築き、可能性を伸ばしてあげるための資格です。

### コーチング？
スポーツなどのコーチと語源は同じらしいです。
コーチングとは対話の中で自分から答えや課題を見つけられるよう導く技術のことです。
一時期テレビでよく放送されていたメンタリズムもコーチング技術の一種らしいです。

### 資格取得まで
WEBの教材を読み、WEBで試験を受講します。
平均1ヶ月程度で取得可能とされています。
私は短期集中して5日間で合格しました。

## 学んだこと

学んだことを少しだけご紹介します

### 承認する
教材にマズローの5段階欲求説が出てきます。
子供の承認欲求を満たしてあげることが、より高い人間性を育むために必要である と。
「あぁ〜そういえば忙しさにかまけて目を合わせないで返事することあったなぁ」
なんて反省しました。
目を合わせて話すことも相手を承認する行為の一つです。

言ってることがはちゃめちゃなら、その言い分は承認しなくとも
その子の存在はちゃんと承認してあげる というのが大切なようです。

### 敏感期
子供が特定のものに急に興味を示し、いつの間にか飽きている...
また何か始めても飽きるんじゃないかな...
なんて思うことがしばしばありました。
が、これは大事な成長のサイクルであることを知りました。

幼少期に能力を習得するため特定のものに強い興味を示すことはあるそうです。
そして、習得が完了すると興味が薄れる。
これを敏感期というそうです。

## 資格取得してどうなったか
チャイルドコーチングを学び、資格を取得をした結果どうなったか。

- 子供が意図しない行動をとる
- 言うことを聞かない

という困った状況が即解決するようなことはありません。

ただ、今までであればイライラして叱責していたような場面でも、

- `まずはあの手法でコミュニケーションをとろう` と考えることができます
- うまくいかない場合も、`一旦距離をおく・休憩する` ことが必要な場面を知っています
- 子供の行動に対して積極的にアプローチできます

## 最後に
コーチングによる結果がすぐに子供の成長として感じることはできません。
が、 `どうしたら良いか分からない` 状態から `どうするべきか考えられる`ようにになりました。
これは大きな進歩で、精神的にも楽になりました。

家庭にも少しは笑顔が増えたかな...？
Linuxで動かすスクリプトの1行目の設定

Linux環境である言語のスクリプトを実行する場合、
**エラーが出る可能性を低くするために**に、シバン(スクリプトの1行目)には以下のように記載した方がいいです。

```bash
#!/usr/bin/env (language)
```

具体的には、

- `#!/usr/bin/env ruby`
- `#!/usr/bin/env python`

といった風に使います。

## そもそもenvコマンドとは

envコマンドとは、環境変数の値を一時的に設定 or 削除してコマンドを実行することができるコマンドです。

例えば、dateコマンドで比較してみると以下のようになります。

```console
# 通常時(LANG=ja_JP.UTF-8)のコマンド

$ date
2020年 12月 8日 火曜日 08時54分06秒 JST


# LANG=Cに設定したコマンド

$ env LANG=C date
Tue Dec  8 08:53:42 JST 2020


# bashの場合は、頭のenvは省略できる

$ LANG=C date
Tue Dec  8 08:53:47 JST 2020


# 環境変数LANGを一時的に設定せずにdateを実行

$ env -u LANG date
Tue Dec  8 08:59:18 JST 2020


# 全ての環境変数を一時的に設定せずにdateを実行

$ env - date
Tue Dec  8 08:59:21 JST 2020
```

また、引数なしで`env`と実行すると環境変数一覧が表示されます。
これは `printenv` コマンドと同様の出力結果になります。

## スクリプトへの活用

シバンとは、Linux環境でスクリプトの1行目に記述する特殊な文字列のことであり、
そのスクリプトを実行するインタープリタを示します。

シバンを `#!/usr/bin/env (language)` としてenvコマンドを使用することで、
**PATH環境変数の通っている場所**から言語のインタープリタが検索されます。

pythonスクリプトの場合を比較してみます。

- `#!/usr/bin/python` と記載した場合
  - pythonのインストールパスが `#!/usr/local/bin/python` だった場合にエラーとなる
  - virtualenvなどの仮想環境で使用されるpythonパスではないため、仮想環境にてスクリプトを実行できない
- `#!/usr/bin/env python`と記載した場合
  - PATH環境変数にpythonコマンドが通っていれば使用できる
      - 汎用性・システム間の移植性が高い
  - virtualenvなどの仮想環境上でも使用できる(仮想環境起動時にPATHがうわがかれ)

後者の方がメリットが大きいことは明らかです。

## 最後に

シェルスクリプトを使い場合には、おまじないのように`#!/bin/bash`と記載すれば問題なさそうですが、
他のプログラミング言語を使用するときには、 `#!/usr/bin/env command` を記載した方が良さそうです。

## Reference

- [Pythonプログラムの#!/usr/bin/env pythonの意味を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン](https://techacademy.jp/magazine/22254)
- [bash スクリプトの先頭によく書く記述のおさらい | Money Forward Engineers' Blog](https://moneyforward.com/engineers_blog/2015/05/21/bash-script-tips/)
- [/usr/bin/envを使って移植性の高いスクリプトを書く方法 | マイナビニュース](https://news.mynavi.jp/article/20180620-650003/)
【Rails】大量のデータを入力する方法について調べた事(バルクインサート)

csvファイルのインポート機能を実装している際に生じた問題点の解決案が今回のお題です。
備忘録として記述しております。

### Gem 「activerecord-import」を使う。
ライブラリをGemfileに追加し、bundle installを行います。
サーバーの再起動も忘れずに。
(私はすっかり忘れていて、小一時間動作に迷いました。)
stock(入荷物)モデルを作成し、毎日500行程度のcsvファイルを読み込みます。
が、どうにも遅い気がするのですよね。
すでに、インポート機能は作っていましたのでまずはこちらから

```ruby:stock.rb変更前
  def self.import(file, calendar)
    CSV.foreach(file.path, headers: true) do |row|
      stock = find_by(id: row['id']) || new
      row_hash = row.to_hash.slice(*CSV_HEADER.keys)
      stock.attributes = row_hash.transform_keys(&CSV_HEADER.method(:[]))
      stock['calendar_id'] = calendar
      stock.save
    end
  end

  CSV_HEADER = {
    '書店コード' => 'store_code',
         # 〜〜省略〜〜
    '買切雑誌' => 'purchased'
  }.freeze
```
こちらを


```ruby:stock.rb変更後
  def self.csv_import(file, calendar)
    stocks = []
    CSV.foreach(file.path, headers: true) do |row|
      stock = Stock.new
      stock = find_by(id: row['id']) || new
      row_hash = row.to_hash.slice(*CSV_HEADER.keys)
      stock.attributes = row_hash.transform_keys(&CSV_HEADER.method(:[]))
      stock['calendar_id'] = calendar
      stocks << stock
    end
    Stock.import stocks
  end

  CSV_HEADER = {
    '書店コード' => 'store_code',
    # 〜〜省略〜〜
    '買切雑誌' => 'purchased'
  }.freeze
```
こちらに変更しました。
1行ずつsaveしていたものを、纏めて一度に登録したって感じでしょうか。
これをバルクインサートと言うそうです。
データベースに入れたいデータを、がっつりと用意しておいて
「これ、やっちょいて〜」と、まとめて指定できるinsert文です。
DBさんが反旗を翻さないか心配ですが・・・。
それにしても便利なライブラリですね。感謝！
ちなみに、「valudate: falseオプション」をつけることでバリデーションをスキップし、
さらに高速化するらしいのですが、私は怖かったのでつけませんでした。
それでも、localhost上でもherok上でも目に見えて高速化しました！
「もっとこうしたら、早くなるよ！」
と言う記述方法がございましたら、教えていただければ幸いです。
## 参考にさせていただいたサイト様
https://techblog.lclco.com/entry/2019/07/31/180000
ありがとうございます！
AdobeXDの素敵な機能をご紹介！

こんにちは！
あっという間に12月。
またアドベントカレンダーの季節がやってまいりました。
そしてSketchからAdobeXDに切り替えたよー。という記事を書いてからはや一年。
プロジェクト１つはXDで進めましたが、その後Photoshopでの作成が多く、実はXDまだ初心者状態です。

そんな中、「なんて便利なんだ！」と思った機能を２つご紹介します！
XDを使いこなしている方には当たり前といいますか、これこそXDと言うような機能かと思いますが、まだXD使ってないよという方にはぜひ知っていただきたい機能です！

# 01 繰り返し要素が簡単に！ -リピートグリッド-
リピートグリッドは繰り返しの要素を簡単に作成できる機能です。

コンテンツを作成する時によくあるこんなくり返しの要素。
Photoshopだったら画像・タイトル・本文を選択してコピーを作成していきますね。
XDではその必要はありません。
さっそく見ていきましょう。
![スクリーンショット 2020-12-04 11.22.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/3855c402-94d6-dba1-0f12-68004a5b5789.png)

## 使い方
#### 01　要素を選択して「リピートグリッド」ボタンをクリック
繰り返したい要素を選択ツールで選択し、右上にある「リピートグリッド」ボタンをクリックします。
![step1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/af31b78a-3c63-9d71-4450-ad218c6d9112.png)

#### 02　枠を下に引き延ばす
「リピートグリッド」ボタンをクリックすると選択した要素の枠が緑色になるので枠の下にカーソルを合わせて引き伸ばします。
![step2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/395b7aee-5f43-f2b3-507e-92ac48b3cdb8.png)

#### ０３　要素が繰り返される
選択してボタンをクリック。そして引き伸ばすだけで、引き伸ばした分だけ要素が繰り返されます。
なんて簡単便利！ちなみに、右に引き伸ばすと右に要素が繰り返されます。
なので、レスポンシブページを作るときにもとっても便利です。
![step3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/67bf65e8-2326-345f-0b22-b02afe84ccc2.png)


# 02 レイアウト替えが一瞬 -スタック-
スタックは簡単に要素を入れ替えることができる機能です。

長い長いページを作成した後に、やっぱりこの要素は上に持っていきたい！
そんなことを言われたら、今までならもう大変！
ですが、スタックを使えば一瞬で要素を入れ替えることができます！

## 使い方
#### 01　ブロックごとにグループ化
まとめたいブロックごとにグループ化します。
![スクリーンショット 2020-12-04 11.30.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/494b1093-dd70-01af-3064-3e76d8b43243.png)

#### 02　全てのブロックをグループ化
それぞれグループ化したブロックを全て選択してさらにグループ化します。
![スクリーンショット 2020-12-04 11.32.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/c59b27e6-0c2c-22c0-7c5b-bf9a36cb9a03.png)

#### 03　動かしたいブロックを移動
動かしたいブロックをダブルクリックで選択し、shiftキーを押しながら移動させます。
ブロックごとにあけたマージンはそのままで要素を入れ替えることができます。
![step3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/fb3313d6-081a-38a6-ca0d-40cb73f4ea68.png)

# 03 おまけ
アップデートされたテキストボックスも便利です。
![text.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/ba3161af-f897-bee3-cd2c-84b2eef10c78.png)

## 幅の自動調整
![スクリーンショット 2020-12-04 12.20.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/35302652-2907-df44-008f-ccd55206caaf.png)
テキストの量に応じて幅が伸びるものです。
今までもありましたね。

## 高さを自動調整　NEW！
![スクリーンショット 2020-12-04 12.20.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/ccb409e1-8467-805e-4f5e-d74cb0671547.png)
横幅は固定ですが、テキストの量に応じて高さが伸びます。

## エリア内テキスト
![スクリーンショット 2020-12-04 12.20.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/703746ea-2d66-ef40-93df-dc71f0835558.png)
幅も高さも固定。
エリアよりテキストが多くなるとテキストが見えなくなります。

## 高さの自動調整とスタックを組み合わせてみる
スタックの機能を使うとマージンは固定になるので、文章が伸びるのに合わせてボタンの位置も下に下がります。
![txt2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192856/0cecdcf3-50d0-f3d4-b7ee-157d93d3638d.png)


# まとめ
今回はこれぞXDという機能を紹介しましたが、いかがでしたでしょうか？
紹介した機能のほかにも、画像やテキストをパッと挿入できたり、
アトミックデザインをするときに便利なツールなど、
あったらいいなと思う機能が充実しているなと感じました。
XDはアップデートされるたび、魅力的な機能がどんどん追加されていくので
今後もっとサイトを作りやすく、使いやすくなっていくのではないでしょうか。
楽しみですね！
では、みなさまよいお年をお迎えください！
Aura Componentを使い込む1(受発注システムで使う)

# はじめに

Salesforceではプログラミングのスキルがなくてもアプリを作ることが可能なローコード開発を推進していますが、私としてはLightning Experienceの能力を使い倒すために、もっと積極的にコーディングして欲しいと思うところです。

と言っても何ができるのかが分からないと、納得いかないと思いますので日頃私が開発している画面で事例をしめしたいと思います。

最初に断っておきたいことがあります。残念ながら私自身の勉強不足でLightning Web Component を使いこなせてません。よって、事例としてはAura Componentになります。

標準機能だけだとできないことも、コーディングすればSalesforceでも他のプラットフォームに負けないUIを実現できることを知って欲しいと思います。受発注システムなどの業務系システムであってもSalesforceでできますのでね。

# 開発方針

**PCで使う画面**
1. jQueryなどのJavaScriptライブラリ（フレームワーク）は使わない。
2. Salesforceで予め用意されているAura Componentだけを組み合わせて開発する。
3. ブラウザはGoogle Chromeを原則として使う。IEだけにしかない機能は使わない。
4. 見た目は極力Salesforceの標準画面に似せて作る。（知らない人が見たら、標準画面に見えるようにする）


**PDFの作成** 今回の画面にはPDFの要件がないので、改めて紹介したいと思います。
1. レイアウトがラフでいい場合は　Visualforce page　を使ってPDFを作成する
2. レイアウトを厳密にしたい場合は、別途外部サーバーを使って作成することも考慮する。


# 業務用の画面(発注残を検索して、入荷処理を行う)

![20201206-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/fbd0f96c-0c76-f1ed-363d-e3c8261db678.png)

ListViewだと、検索条件をうまく指定できないのでlightning:datatableを使って検索画面を作ります。

以下の機能を実装しました。
1. ページャー機能。次ページ、前ページボタンをクリックしてページを切り替える。
2. ユーザの要望により、Page Downキーに次ページボタン、Page Upキーに前ページボタンを割り当てる。[^1]
3. 1ページ内に表示できる行数の変更を可能にする。
4. オブジェクトの明細は標準画面を別タブで開く。(検索結果を維持できるようにするため）
5. 得意先、仕入先はAccountオブジェクトを5桁のコード、会社名、読み仮名で検索できるようにする。
6. テキストをラップするをデフォルトにして長い文字列も最初から表示できるようにする。(datatableではツールチップが使えないため)
7. 各項目にソート機能を付ける。
8. チェックボックスをOnにしたものを入荷処理の対象とする。またチェックした順番を維持する。(モーダル画面で実装)

### 2ページ目
![20201206-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/1910097e-576d-67bd-4cc3-c4162b99bb94.png)

### Accountオブジェクトの検索と引用

検索条件で使用するAccountオブジェクトを指定します。

![20201206-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7574b8b6-1f06-2b6a-4756-39200315dec2.png)

左上:何も指定しない時(得意先コードの昇順)
右上：Name項目に愛知が含まれる得意先を表示
左下：得意先コードが12で始まる得意先を表示

別画面に移動して、検索条件を指定しなくてもいいようなUIにしています。[^2]

### 上から３つ選んだ場合
![20201206-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/e7c02517-b978-7fd1-c70d-a2ef1b045ec3.png)

分かりやすいように、モーダル画面の一番右の列に選んだ順番を表示しています。

### 一旦、チェックを外し３行、２行、１行と選んだ場合
![20201206-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3192e10d-75de-ab14-9044-6aa184101a31.png)


# 最後に

私自身はSalesforceについては独学です。と言っても新入社員時代に会社で教えてもらったのもMVS上でのJCLとPL/I（ピーエルワン）くらいでLinux、PHPとオープンソースで遊んできましたが、どれも独学でしたね。研修会なども行けなかったです。そんな古い技術者でも十分に使えるのが、Aura Componentのいいところだと思います。ローコード開発も悪くはないですが、コーディングすれば応用範囲はずっと広がります。本当に能力の高い人は別として普通の技術者は数をこなして訓練するしかないと思います。もし、参考にしたいという方がいらっしゃれば、公開できる範囲で具体的なソースコードも披露できればと思います。どんどん、コーディングにもチャレンジして欲しいと思います。

[^1]: [Aura component でショートカットキーのイベントを得る](https://qiita.com/Keiji_otsubo/items/53becb163c0aac8a9923)
[^2]: Winter21のリリースで少々影響を受けました。　[Winter'21での不具合](https://qiita.com/Keiji_otsubo/items/3b47f3529f0c55df4f2f)
openapi-generatorのadditional-propertiesを指定して生成されるコードをカスタマイズしよう

https://github.com/OpenAPITools/openapi-generator

openapi-generatorはOpenAPIの定義ファイルから、API ClientやServer stubsなどを自動生成してくれる便利なものです。対応言語も豊富なので、これからAPI Clientを作ろうと考えている方は、これを用いて自動生成することをおすすめします。

```
$ openapi-generator generate -i ./openapi.yml -o ./openapi_client -g ruby
```

上記のコマンドを実行すると、openapi.ymlをもとに、openapi_clientというディレクトリ配下にrubyのコード（実態はgem）が生成されます。

openapi-generatorコマンドには多彩なオプションがあり、以下のコマンドで確認ができます。

```
$ openapi-generator help generate
```

本記事ではこの中にある `additonal-properties` というオプションについて説明します。

## additonal-propertiesについて

このオプションは、生成される各言語ごとのオプションを設定できるものです。

https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/ruby.md

例えばRubyのAPI Clientであれば上記のドキュメントにあるものがすべてadditional-propertiesで指定できます。
RubyのAPI Clientはデフォルトでは `openapi_client` というgem名で生成されますが、このgemの名前を変えたい場合は下記のようにオプションを指定することで変更ができます。

```
$ openapi-generator generate -i ./openapi.yml -o ./openapi_client -g ruby --additional-properties=gemName=qiita_client
```

最近だと1つのリポジトリから複数のサービスのAPIを呼び出すことも多々あるでしょう。その場合はopenapiの定義ファイルが複数あることになると思いますが、すべて同じopenapi_clientというgemで生成されてしまうとどれか一つのサービスのAPIしか呼び出せなくて困ってしまいます。
そこで上記のオプションを使って別のgemとして生成することで、複数のサービスのAPIを呼び出すことが可能になります。
他にも便利そうなオプションがいくつかありますが、additional-propertisに複数指定したい場合はカンマ区切りでkeyとvalueをつなげると良いようです。詳しくはドキュメントを見てください。

言語ごとにオプションがいろいろあるので、すでに自動生成している方も一度ドキュメントを確認してみると良いのではないでしょうか？
それでは良い自動生成生活を！
SSHKit::Runner::ExecuteErrorが出たときの話【AWS,Capistrano】

#はじめに

Capistranoを使用して、AWSに自動デプロイを行なった際に下記のエラーが出たので、備忘録として投稿します。


##エラー内容

```ruby:ターミナル
$  bundle exec cap production deploy
```

にて、デプロイを試みると、

```ruby:ターミナル
（中略）
/home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/sshkit-1.21.1/lib/sshkit/runners/parallel.rb:15:in `rescue in block (2 levels) in execute': Exception while executing as ec2-user@xx.xxx.xxx.xxx: Authentication failed for user ec2-user@xx.xxx.xxx.xxx (SSHKit::Runner::ExecuteError)
(Backtrace restricted to imported tasks)
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as ec2-user@xx.xxx.xxx.xxx: Authentication failed for user ec2-user@xx.xxx.xxx.xxx


Caused by:
Net::SSH::AuthenticationFailed: Authentication failed for user ec2-user@xx.xxx.xxx.xxx

Tasks: TOP => rbenv:validate
(See full trace by running task with --trace)
```

とこのようなエラーが表示されました。SSHの接続の部分で不具合が起こっているのかな？との簡単な予想を立てて、検索をしてみました。

[こちら](https://qiita.com/Ikuy_h/items/a4d260a359f8bcb7a787)の記事を参考にさせていただき、SSHキーが消えてしまっていると考え、.sshにて下記のコマンドを実行すると解決しました。

```ruby:ターミナル
$ cd ~/.ssh
.ssh $ ssh-add ~/.ssh/hoge.pem
```

なぜ、急にキーが消えてしまったのかは不明です。。。。


##AWSのデプロイ時のエラーについて

AWSのエラーが起きた際には、下記の確認をまずは行なっていきたいと思います。

・ローカル→GitHubへのpushのし忘れがないか
・GitHubからEC2への反映（git pull origin master）のし忘れはないか
・EC2サーバー側でエラーログの内容確認をする
・データベースが正しく起動しているか
・EC2サーバー側の環境変数は正しく設定できているか
・EC2インスタンスの再起動を行なってみる
Conoha WINGで初めてWordpressを触った話

この記事は[ConoHa Advent Calendar 2020](https://qiita.com/advent-calendar/2020/conoha)の8日目の記事です。
7日目の @ybk2020 さんともろかぶってしまっていますがご了承ください...

# はじめに

これまでNuxt.jsやDjangoなどでサイトを作ってきたことがあるのですが、自分のブログを作るにあたってノーコードで作ることができるWordpressを使うことにしました。

https://virtualimage-lab.com/

## なぜノーコード(Wordpress)なのか？

### メンテナンスが楽

自分でコードを書いていないため、セキュリティーなどの面で責任を負う必要がなくなります。また、それのメンテナンスにかける時間を無くすことができます。

### いつでも変更できる

私はyStandardというテーマを使用していますが、テーマ変更をweb上でできるため、開発環境の構築が不要です。
今使っているWindowsには一切開発環境を入れていないため、どこでも変更できるという利点が素晴らしいと思います。

# Conoha WINGをお勧めする理由

## けっこうやすい

私は3年払いをしたのですが、月に400円ととても安くなっています。
よくある長期支払いだと安くなるシステムですが、ブログをやるのであれば長期的に使うことが見込まれるので、安く抑えられると思います。

## サーバーの管理が不要

WINGではサーバーの管理をせずにWordpressを変更するだけで操作可能ということで、そちらの管理も不要なのが素晴らしいと思います。
~~私はめんどくさがり屋なのでするのは好きではないです~~

## ドメインが一つ無料

これが一番大きいかなと思うのですが、ドメインが一つ無料です。自分で管理する必要もなく、無料で使えてしまうのですごい機能だと思っています。

# さいごに

私はもちろん自分でコードを書いてサイトを作るのも好きですが、メンテナンスの観点からするとノーコードが主流になってくるのではないかなあ、と思っています。
Wordpressは少し自分でいじることもできるのがいいですね。

明日のアドベントカレンダーは @yamagami2211 さんです!

ではでは～
pandasでSeriesの値として保存されるリストを列方向に展開する

## 概要
以下を横方向に展開したいときに、さっと検索しても方法が出てこなかったので、忘れそうなのでメモ

```py
import pandas as pd
df=pd.Series([[1,2,3] for c in range(5)])
df
#0    [1, 2, 3]
#1    [1, 2, 3]
#2    [1, 2, 3]
#3    [1, 2, 3]
#4    [1, 2, 3]
#dtype: object

```

## コード
### リストを列方向に展開してバラす
`pd.Series`を`apply`するだけ

```py
dfx=df.apply(pd.Series)
dfx
# 	0 	1 	2
#0 	1 	2 	3
#1 	1 	2 	3
#2 	1 	2 	3
#3 	1 	2 	3
#4 	1 	2 	3
```

### ※もし文字列のリストをバラしたい場合

```
df=pd.Series([["aa","bb","cc"] for c in range(5)])
df.apply(lambda x:" ".join(x)).str.split(expand=True)

```
※元が数字で、もし列にバラしたときに各列のデータ型が文字列型に変換されてもいいなら、`" ".join(map(str,x)).str.split(expand=True)`とかにしてもいいかも

### ※そもそも元々がリストではなく分割できそうな文字列だった場合
```
df=pd.Series(["aa,bb,cc","dd,ee,ff","gg,hh,ii"])
df.str.split(pat=",",expand=True)

# 0    aa,bb,cc
# 1    dd,ee,ff
# 2    gg,hh,ii
# dtype: object

# 0	1	2
# 0	aa	bb	cc
# 1	dd	ee	ff
# 2	gg	hh	ii

```




### 列方向のデータをリストに集約する（元に戻す）
```py
dfx.unstack().reset_index()
#列がlevel_0で行がlevel_1になって縦持ちデータに変換される
#columns.nameやindex.nameが設定されるとそれが反映される
#	level_0 	level_1 	0
#0 	0 	0 	1
#1 	0 	1 	1
#2 	0 	2 	1
#3 	0 	3 	1
#4 	0 	4 	1
#5 	1 	0 	2
#6 	1 	1 	2
#7 	1 	2 	2
#8 	1 	3 	2
#9 	1 	4 	2
#10 	2 	0 	3
#11 	2 	1 	3
#12 	2 	2 	3
#13 	2 	3 	3
#14 	2 	4 	3

dfx.unstack().reset_index().groupby("level_1")[0].apply(list) #または.agg(list)
#※カラムやSeriesのnameなどがリセットされるが、元の形には戻る。
#level_1
#0    [1, 2, 3]
#1    [1, 2, 3]
#2    [1, 2, 3]
#3    [1, 2, 3]
#4    [1, 2, 3]
#Name: 0, dtype: object
```

## DataFrameで複数の列にリストが含まれているの場合
複数の列にそれぞれ列があるような場合は、
内包表記で各列に適用してあとで`concat`して横方向にくっつける。
もっといい方法ありそう…、誰か教えてください

```py
df=pd.DataFrame([[[1,2,3],[1,2,3]] for c in range(5)])
df
# 	0 	1
#0 	[1, 2, 3] 	[1, 2, 3]
#1 	[1, 2, 3] 	[1, 2, 3]
#2 	[1, 2, 3] 	[1, 2, 3]
#3 	[1, 2, 3] 	[1, 2, 3]
#4 	[1, 2, 3] 	[1, 2, 3]

dfx=pd.concat([df[x].apply(pd.Series) for x in df.columns],axis=1)
dfx
# 	0 	1 	2 	0 	1 	2
#0 	1 	2 	3 	1 	2 	3
#1 	1 	2 	3 	1 	2 	3
#2 	1 	2 	3 	1 	2 	3
#3 	1 	2 	3 	1 	2 	3
#4 	1 	2 	3 	1 	2 	3
```

## 参考
QAStack データフレームの行をパンダのグループでリストにグループ化する方法は？ https://qastack.jp/programming/22219004/how-to-group-dataframe-rows-into-list-in-pandas-groupby
踏み台サーバー経由の~/.ssh/configの記述

## ~/.ssh/config
~~~ ~/.ssh/config
# 踏み台サーバー
Host login
  HostName login.example.com
  User user_name
  Port 22
  IdentityFile ~/.ssh/ec2key.pem

# 目的のサーバー
Host server
  HostName server.example.com
  User user_name
  Port 22
  IdentityFile ~/.ssh/ec2key.pem
  ProxyCommand ssh -W %h:%p login
~~~

| キーワード |内容|
|----|---------|
|Host|任意の接続名|
|HostName|ホスト名|
|User|ユーザー名|
|Port|ポート番号|
|IdentityFile|鍵へのPATH|
|ProxyCommand|接続時の実行コマンド|

## ProxyCommand
| キーワード |内容|
|----|---------|
|ssh -W|クライアントの入出力を指定したホストに送る|
|%h|ホスト名(目的のサーバー)|
|%p|ポート番号(目的のサーバー)|
|login|踏み台サーバー|

## ssh コマンド
以下コマンドでlogin経由でserverに接続させる

```
ssh server
```

## 参考
[~/.ssh/configについて](https://qiita.com/passol78/items/2ad123e39efeb1a5286b)
[多段SSHの設定を.ssh/configにまとめる](https://qiita.com/ik-fib/items/12e4fab4478e360a82a1)
[.ssh/configファイルでSSH接続を管理する](https://qiita.com/0084ken/items/2e4e9ae44ec5e01328f1)
[多段ssh設定のまとめ](https://rcmdnk.com/blog/2014/06/08/comptuer-linux-windows-putty/)
HTML・CSSメモ

#はじめに
HTMLとCSS(Scss)の用語メモ

##:root
:rootセレクタはルート要素にcssを適用するためのセレクタ。
ルート要素は最上位階層の要素のことで、通常のhtmlファイルだとhtmlタグに当たる[1]。

##css変数
公式では「カスケード変数のためのCSSカスタムプロパティ」と呼ばれている[2]。
例えば

~~~css
.html{
   --my-color: #ffffff;
}
.test{
   color: var(--my-color);
}
~~~

とするとtext要素の文字が白くなる。これは定義した要素とその小要素全てに使える。

##svgタグ
コードを書いて画像を描画することができるタグ詳しくは[3]へ。

##box-sizing
box-sizingとは最新のCSS規格「CSS3」から追加されたプロパティ。
「要素の幅（width）と高さ（height）の中にpaddingとborderを含めるかどうか」という設定ができる[4]。

~~~css
// 初期値paddingとborderを含めない
box-sizing: content-box; 
// paddingとborderを含める
box-sizing: border-box; 
// 親要素のborder-boxの値を引き継ぐ
box-sizing: inherit;
~~~

##ベンダープレフィックス
プロパティ名の前に書く「-webkit-」「-moz-」「-o-」「-ms-」などの文字のこと。
これを書くことで古いブラウザにCSS3のプロパティを対応させることができる[4][5]。
-webkit-ならchromeとsafariなどに対応する。

~~~css

-webkit-box-sizing: border-box;
~~~
使用すうる時は上のようにプロパティの前につける。

##font-smoothing
フォントのアンチエイリアスを調節するプロパティ[6]。
新しいプロパティなのでベンダープレフィックスがついていることが多い。

~~~CSS
//ぎざぎざ
-webkit-font-smoothing: none;
//滑らか
-webkit-font-smoothing: antialiased;
// 初期値
-webkit-font-smoothing: subpixel-antialiased;
~~~



##参考文献
[[1] CSS 3のセレクタ解説：:root、:not、:empty、:target - builder by ZDNet Japan](https://builder.japan.zdnet.com/html-css/sp_css-firefox-safari/20387778/)

[[2] Web制作がめっちゃ捗る！CSS変数の基礎と実践テクニック – WPJ](https://www.webprofessional.jp/practical-guide-css-variables-custom-properties/)

[[3] SVGのviewBoxをわかりやすく紐解く｜NEWS｜株式会社INDETAIL（インディテール）](https://www.indetail.co.jp/blog/13002/)

[[4] 【CSS】box-sizing:border-boxの使い⽅｜効かない時は？](https://saruwakakun.com/html-css/reference/box-sizing)

[[5] ベンダープレフィックスは何のためにつけるの？使い⽅を紹介 | Webmedia](https://www.itra.co.jp/webmedia/bender-prefix.html)

[[6] [CSS] フォントのアンチエイリアス設定 | metrograph.jp](https://metrograph.jp/css-font-smoothing/)
【Grasshopper】重複する点の取り扱い

# 「Cull Duplicates」を使う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610425/61f43c53-ab8c-3b06-636b-a0d25b7e17de.png)

上図に示すように点が重複している場合、点集合を操作することができます。具体的には、2つの操作方法があります。
①重複する点を削除して1つにする
②重複する点をすべて削除する

今回使用するコンポーネントは「Cull Duplicates」です。
オプション操作ができるので説明します。


## ①重複する点を削除して1つにする
重複する点を削除して1つにしたいときは、「Cull Duplicates」コンポーネントを右クリックして「Leave One」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610425/86a7d19e-d79f-00bb-dad3-363402fab63e.png)

図に示すように、4番目（index=3）のリストが消えていることがわかります。このように、「Cull Duplicates」コンポーネントを使うことで、重複のない点集合を作ることができます。


## ②重複する点をすべて削除する
重複する点をすべて削除したいときは、「Cull All」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610425/3f6c63b7-3801-dc96-cb09-f99aeb9ad589.png)

図に示すように、重複していた1番目（index=0）と4番目（index=3）の点が消えています。このように、「Cull Duplicates」コンポーネントを使うことで、重複点をすべて削除した集合を作ることができます。
Nimのメモリ管理を理解する① ― Nimの新しいGC、ARCについて

Nim作者のAraqは長年、Nimオリジナルの、これまでよりもより効率の良いGCをNimに組み込む研究をしてきました。そして今年リリースされたv1.2においてARCが、そしてv1.4ではORCが使えるようになりました。
この新しいGCであるARCとORCとは一体何なのか、これまでの参照カウントやマークアンドスウィープとはどう違っているのかについて解説していきます。

# これは何？
ARC及びORCは全く新しい発想で作られたGCではありません。しかしそれは「ムーブセマンティクス」を最適化させた参照カウントです。

Nimはコンパイル言語です。NimのソースコードをCにコンパイルし、GCCによってCをバイナリにコンパイルしますが、その時にNimのソースコードにデストラクタを自動で挿入します。

```nim
proc main = 
  let mystr = stdin.readLine()

  case mystr
  of "hello":
    echo "Nice to meet you!"
  of "bye":
    echo "Goodbye!"
    quit()
  else:
    discard

main()
```
↓ 自動で変換

```nim
var mystr
try:
  mystr = readLine(stdin)
  case mystr
  of "hello":
    echo ["Nice to meet you too!"]
  of "bye":
    echo ["Goodbye!"]
    quit(0)
  else:
    discard
finally:
  `=destroy`(mystr)
```

スコープが終了した後にデストラクタを必要とする変数のデストラクタ呼び出しを、Nimコンパイラが自動的に挿入します。これによって「スコープベースのメモリ管理」ができるようになります。
これらの仕組みのおかげで、ARCはこれまでの参照カウントに比べて以下のような利点があります。

- ムーブセマンティクス
  - コンパイラがプログラムを静的に分析し、メモリコピーを可能な限り参照に変換する能力。
- 共有ヒープ
  - 異なるスレッドが同じメモリにアクセスし、スレッド間で変数を渡すために変数をコピーする必要がない。スレッド間でのデータの分離と送信に関するRFCも参照してください)
- より簡単な FFI
  - 参照カウントは各外部スレッドが手動で GC をセットアップする必要がありますが、ARC ではそうではない。これはまた、他の言語（.dll、.so、Python拡張など）から使用するためのNimライブラリを作成するためには、ARCの方がはるかに良い選択であることを意味する。
- ハードなリアルタイムプログラミングに適している。
- コピーの省略
  - 多くの場合、コピーを単純な参照にすることができる。

このように、ARCを使えば多くの場合でプログラムを高速化し、メモリ使用量を減らし、予測可能な挙動を持つようにできます。

しかしARCはあくまで参照カウントであるため、例えば変数AがBに依存し、変数BがCに依存し、変数CがAに依存しているような循環参照の場合には参照カウントは上手く機能できません。これらのサイクルを見つけてGCを動かすには、サイクルカウンターが必要です。
![](https://nim-lang.org/assets/news/images/yardanico-arc/cycle.svg)
これまでのNimの参照カウントGCではサイクルカウンターはマークアンドスウィープで実装されてきましたが、これをARCをベースにして新しく作ることになりました。

# ORC
ORCはARCをベースにしたNimの全く新しいサイクルコレクタです。グローバルトレースしかないその他のGCとは違い、ORCはスコープの単位をベースにしたローカルトレースを含み、処理するべきサイクルトレースを含むので、得に非同期処理の時に使われるべきです。
ORCは今後のアップデートでNim標準のGCになる予定です。

# 使い方
Nimのバージョン1.2以降で使えるようになっていますが、いくつかのバグ修正を含んだ1.4以降で使うことが推奨されています。
コンパイルオプションに指定するだけで簡単に有効になります。

```bash
nim c --gc:arc main
nim c --gc:orc main
```
# ベンチマーク
![スクリーンショット 2020-12-08 8.29.13.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295826/94c6ae49-346b-0498-3133-a7de851cfb77.jpeg)


# 参考文献
[Introduction to ARC/ORC in Nim](https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc-in-nim.html)

こちらはNim作者Araq本人によるプレゼンです。英語のわかる方、興味を持った方がぜひご覧になってみてください。
https://www.youtube.com/watch?v=yA32Wxl59wo
BigQueryで気を付けたい、日時データの型

# はじめに
サムザップ [#2 AdventCalendar 2020](https://qiita.com/advent-calendar/2020/sumzap2) の12/8の記事です。

今回はBigQueryの日時データの型について書いていきたいと思います。

# 困った事
BigQueryに格納している元データは、DBからCSV形式等で出力してロードしています。
サンプルとして、以下の様なCSVデータをBigQueryにテーブルスキーマ自動検出モードでロードしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/62d4b566-5fae-82cf-650f-a34d372e3765.png)
BigQueryにロードした結果は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/b7c138c0-5913-5d61-0116-9b6ce9568888.png)
プレビューで確認すると、日時の型がtimestamp型になっており、日時の後に「UTC」表示が付いています。
本来の意図としては「JST」になってほしいのですが、表示上はCSVのデータとあっているものの、タイムゾーンがUTCと表示されてしまっているので、ちょっと違和感があります。これを解決するために色々試してみたいと思います。

# タイムゾーンを付けてBigQueryにロード
ロードするCSVの日時データを、タイムゾーンを付与した以下のISO 8601形式にしてロードしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/3bc9c1ff-70e9-6424-614e-3315e8572e49.png)

BigQueryのプレビューを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/27a49ec2-6c05-dd3f-32e8-5065f0dcc6aa.png)
CSVに記載した日時がUTC時間に変換されて格納されました。データ的にはあっているのですが、表示はあくまでもUTC表示なのでちょっと使いづらいです。
ただし、BigQueryのクエリエディタで「FORMAT_TIMESTAMP」関数を使う事で、JST表示に変換する事は出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/86de25b8-5523-ea59-b6d0-56e950e5fbc1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/68a25860-823e-4329-b6d5-75c484cfff4e.png)
ただし、これだとBigQueryのデータを使う側で毎回FORMAT_TIMESTAMPをしなければならないので、ちょっと面倒です。

# BigQueryのテーブル定義をdatetime型で指定する
BigQueryにデータをロードする際、テーブルスキーマ自動検出モードにすると日時データがtimestamp型になってしまうので、以下の様に手動でスキーマをdatetime型にしてロードしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/62d4b566-5fae-82cf-650f-a34d372e3765.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/7b635083-c484-ba55-5e42-5f422d40f9c7.png)
BigQueryのプレビューを確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136467/44912cf7-23f6-c51f-ba50-da13e2d79a47.png)
CSVに記載されている通りの日時が表示されています。datetime型はタイムゾーンを持たないので、当然と言えば当然なのですが・・・。

# BigQueryのtimestamp型をdatetime型に変更したい！
既に大量のデータが格納されているBigQueryのテーブルで、日時データがtimestamp型になっている物が多数あるため、datetime型に変換したいと思いましたが、どうやら型の変更はできないようです。
[BigQuery ドキュメント テーブル スキーマの変更](https://cloud.google.com/bigquery/docs/managing-table-schemas?hl=ja)
取れる方法としては、datetime型に変更した新たなテーブルを作って、古いテーブルから新しいテーブルへデータを移行するしかないようです。

# 終わりに
BigQueryのプレビュー表示で、日時の表示に「UTC」が付いている事に違和感を感じて調べ始めたのですが、既にtimestamp型で格納されてしまっているデータについては、新たなテーブルを作って入れ直しが必要なことがわかりました。ただデータ入れ直しとなると、BigQueryの検索時にかかる費用が大きくなりそうなので、現状は「UTCって表示されているけど、データ的にはJSTだよ」って解釈で使っていくしかなさそうです。
今後新たなデータ取り込みをする場合は、BigQueryのテーブル作成時に「テーブルスキーマ自動検出モード」を使わずに、手動でテーブルスキーマを指定して取り込むようにしたいと思います。

（いつかBigQueryでテーブルスキーマの型変更が出来るようにならないかな・・・）
vagrant up でエラーが出たときの対処法


```
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["hostonlyif", "create"]

Stderr: 0%...
Progress state: NS_ERROR_FAILURE
VBoxManage: error: Failed to create the host-only adapter
VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component HostNetworkInterfaceWrap, interface IHostNetworkInterface
VBoxManage: error: Context: "RTEXITCODE handleCreate(HandlerArg *)" at line 95 of file VBoxManageHostonly.cpp
```
みたいなエラーがでたときの対処法は以下のシェルを実行してください。


`sudo "/Library/Application\ Support/VirtualBox/LaunchDaemons/VirtualBoxStartup.sh" restart`

上記シェルの実行時に以下のエラーが出たときの対処は↓のリンクにあるようにプライバシー設定で許可を与えてください。

```
Loading VBoxDrv.kext
/Library/Application Support/VirtualBox/VBoxDrv.kext failed to load - (libkern/kext) system policy prevents loading; check the system/kernel logs for errors or try kextutil(8).
```

https://developer.apple.com/library/archive/technotes/tn2459/_index.html#//apple_ref/doc/uid/DTS40017658
GitLab Pages と Storybook でデザイナーに確認してもらう環境の構築

# この記事について

[株式会社Re:Buildアドベントカレンダー Advent Calendar 2020](https://qiita.com/advent-calendar/2020/rebuild) の 8日目の記事です。

個人的に今後やっていきたい内容なので、記載している内容はプロジェクトで利用しているわけではないですが、もっとこうしたほうが良いなどアドバイスコメントいただけると幸いです。

# やりたいこと

1. デザイナーにコンポーネント単位で確認してもらいたいので Storybook を利用したい
1. 開発中はプロジェクトメンバーのみが見れる形にしたい

1つ目は Storybook を利用するだけなので問題なくできる。
2つ目は Github Pages を最初検討していたんですが、プロジェクトメンバーのみの閲覧権限を入れるところが解決できず困った。[Gitlab Pages はアクセスコントロールが可能](https://docs.gitlab.com/ee/user/project/pages/pages_access_control.html)とわかったので試してみる。

# Storybook 環境の構築

下記のコマンドですぐ構築完了です。

```bash
$ npx create-react-app sample-storybook
$ cd sample-storybook
$ npx sb init
$ yarn run storybook
```

# GitLab Pages への配信設定

```yml:.gitlab-ci.yml
image: node:12-alpine

pages:
  stage: deploy
  script:
    - yarn install
    - yarn build-storybook
    - rm -rf public && mkdir -p public
    - mv storybook-static/* public
  artifacts:
    paths:
      - public
  only:
    - master
```
# アクセスコントロールができているのかアクセスしてみる

シークレットウィンドウを起動してアクセスしてみたところ GitLab の Sign In ページに飛ばされることを確認できました。設定から アクセスできる人すべて or プロジェクトメンバーのみ が選べるのでどちらも機能しました(反映にはすこし時間がかかった)。

やりたかったことは達成できました。しかし、配信されたサイトは描画に時間がかかりました。
確認すると 2.5MB と大きいサイズの js が存在しています。
調べてみた感じだと下記のPRがマージされれば小さくなる可能性はありそうでした。
https://github.com/storybookjs/storybook/pull/12406

![スクリーンショット 2020-12-08 6.54.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82745/d89a0afa-a63b-198d-83fd-3df940be4a31.png)

# gzip 対応をする

自分でできる対応はしておいたほうが良いと思うので圧縮していきます。

[PageSpeed Insights のリファレンス 圧縮を有効にする](https://developers.google.com/speed/docs/insights/EnableCompression?hl=ja)を参考にすると最新のブラウザはすべて対応しているのでやっていきます。

> 最新のブラウザはすべて gzip 圧縮に対応しており、すべての HTTP リクエストで自動的に圧縮のネゴシエーションを実施します。gzip 圧縮を有効にすると、転送されるレスポンスのサイズが最大で 90% 削減されるため、リソースのダウンロード時間の大幅な短縮、クライアントのデータ使用量の削減、最初のページ レンダリング時間の改善といった効果があります。

GitLab Pages では Pages にデプロイする際に gzip しておけば対応可能との issue を見つけたので試します。
https://gitlab.com/gitlab-org/gitlab-pages/-/issues/12

```diff:.gitlab-ci.yml
image: node:12-alpine

pages:
  stage: deploy
  script:
    - yarn install
    - yarn build-storybook
    - rm -rf public && mkdir -p public
    - mv storybook-static/* public
+   - find public -type f \( -name \*.html -or -name \*.css -or -name \*.js \) | xargs -I {} sh -c "gzip -k {}"
  artifacts:
    paths:
      - public
  only:
    - master
```

2.5MB と大きいサイズの js が 5.9kB と圧縮できていることがわかる。
(svgもテキストなので圧縮したほうがよかったかもしれない)

![スクリーンショット 2020-12-08 7.09.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82745/a9e53f99-1187-a2c0-66cb-d4c0016419e1.png)

# さいごに

やりたいことで上げた下記の2点をどのようにして実現できそうか試してみました。

1. デザイナーにコンポーネント単位で確認してもらいたいので Storybook を利用したい
1. 開発中はプロジェクトメンバーのみが見れる形にしたい

今回確認に利用したコードは下記で公開しています。
https://gitlab.com/togana/sample-storybook

GitLab Pages は下記です。
https://togana.gitlab.io/sample-storybook

次は Storybook を形骸化させないためにスナップショットテストを盛り込むなどを試して行こうかと思っています。

# 参考

https://docs.gitlab.com/ee/user/project/pages/pages_access_control.html
https://ja.reactjs.org/docs/create-a-new-react-app.html
https://storybook.js.org/docs/react/get-started/install
https://gitlab.com/gitlab-org/gitlab-pages/-/issues/12
初めてのwebアプリ実装

某プログラミングスクールの実装課題を完了したので、記録を残しておきます。
なお、私がかけた時間はトータル24時間強でした。スクールの定める予定時間を大幅に上回っていたため、恐らくかなりエラーに苦しめられた方だと思います。。


なぜ記録を残すのか
----------------------
将来の私のために、初めてアプリを作った時の新鮮な感情を残しておきたいため。
また、同じように初めての実装で悩んでいて、挫折しそうな人に、考え方の参考として見ていただきたいため。


##実装を通しての学び
実装を通しての学びは以下の3つです。

1. アウトプットの重要性
- プログラミングの勉強においてエラー対処は利点しかない
- エラーの解決手順


### 1.アウトプットの重要性
これはどんな学問に対しても当てはまることです。ただ、学生の頃の試験勉強と比較すると、プログラミングの勉強の方が、よりアウトプットは重要だと思いました。

理由としては、答えは一つではないものの、答えを導き出すためには明確な論理がある、からです。

プログラミングにおいて、答えは一つではなく、明確な論理を持って実装に当たる必要があります。
答えは非常に多くのパターンがあり、実装のためには様々なことを頭の中から出せる状態にしておける必要があると思います。また、勉強したことを実行すれば100点が必ず取れるような物でもありません。様々な要因からエラーが必ずおきます。

勉強したことをアウトプットできる状態にして、さらに予測不能なエラーに対処できる力を身に付ける。これがプログラミングにおけるアウトプットの意義だと思います。


### 2.プログラミングの勉強においてエラー対処は利点しかない
これはどんな人にとっても間違いないことだと思います。
なぜなら、エラーでは、不備の箇所を明確にしてくれるからです。
例えば、数学の問題を間違えたとして、どこが分かっていないかは、自分で考える必要があります。反対にプログラミングは、どこが間違っているかを明確にしてくれて（エラー文が表示されている場合）、どのように修正するべきかも提案してくれたりします(Did you mean)。
エラーってポジティブ要素に聞こえてきませんか？

### 3.エラーの解決手順
MVC実装程度のアプリ開発におけるエラー解決手順ですが、私が実際にエラー対処する中での解決手順です。
1）エラー文の解析
　簡単なエラー文やDid you mean?が出ていれば、即解決です。複雑なエラー文であっても、検索すれば、簡単に解決できることも。

2)エラー文で指摘されているファイルのチェック
　スペルミスや構文ミス（特にend抜け）がないかをチェック

3)MVCの流れをチェック
　1),2)で解決しない場合は、　MVCの処理がおかしくなっているはずなので、流れをチェックします

4)分かっている人に質問する
　1)~3)を実施して不可能な場合は大人しく諦めましょう。ただし、質問の仕方としては、参考資料を持って、こうしようとしたけど、思い通りにいかなかった、などしっかり考えた証を見てもらいながらだといいと思います。

1)〜3)については時間をかければかけるほど、4)での定着率は高まります。私はdevise導入時に、マイグレーションの
記述を消しすぎていることに気づかず、6時間以上ストップしていました。もう一生userモデルのマイグレーションファイルの記述をおざなりにすることはないと思います。

## まとめ
グダグダと書いてきましたが、結論、僕が伝えたいことは、エラー発生はポジティブ要素だということです。
エラーにかける時間が長ければ長いほど、特にだと思います。
実装の達成感はとてつもないです。とにかくやり切ることが成長につながると思います。