OmniAICreator/Qiita-1.07M huggingface dataset:
[Rails6] Bootstrap4導入〜適用されているか確認まで

#はじめに
https://qiita.com/kazutosato/items/d47b7705ee545de4cb1a
こちらの記事を参照させていただいております。

筆者のver：　webpacker-4.3.0,　 Rails 6.0

#Webpackerを用いての導入
yarn addでjQueryとBootstrapを加えます。Bootstrapが使用するpopper.jsも入れます。

```:ターミナル
$ yarn add jquery bootstrap popper.js
```
以下のようになれば成功です。
[![Image from Gyazo](https://i.gyazo.com/6863a03f2be18d046042a9b3c94cb1c9.png)](https://gyazo.com/6863a03f2be18d046042a9b3c94cb1c9)

webpackの設定でProvidePluginを加えると、importやrequireなしで$やBootstrapのJavaScriptが使えるようになります。
下記のように、追記します。

```config/webpack/environment.js
const { environment } = require('@rails/webpacker')

// jQueryとBootstapのJSを使えるようにする
const webpack = require('webpack')
environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: 'popper.js'
  })
)
// ここまで

module.exports = environment
```

app/javascriptディレクトリの下にstylesheetsディレクトリを作り、application.scssを次のように記述します。

```app/javascript/stylesheets/application.scss
@import '~bootstrap/scss/bootstrap';
```

application.jsに次の2行を加えます。

```app/javascript/packs/application.js
import 'bootstrap';
import '../stylesheets/application';
```

レイアウトにstylesheet_pack_tagを加えます。

```app/views/layouts/application.html.erb
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
```

#Bootstrapが適用されているか確認
<a href="https://getbootstrap.com/">Bootstrap公式<a/>

左下のGet startedをクリック
[![Image from Gyazo](https://i.gyazo.com/08f574b67cce7e5962f6d6aefe880ff9.png)](https://gyazo.com/08f574b67cce7e5962f6d6aefe880ff9)

introductionページに飛んだら少し下にスクロール。
そして、Starter templateのコードをコピーします。
[![Image from Gyazo](https://i.gyazo.com/1c04a8b96d8f75335eb3901bfcc05c30.png)](https://gyazo.com/1c04a8b96d8f75335eb3901bfcc05c30)
コピーしたコードをviewsファイルに貼り付けます。
[![Image from Gyazo](https://i.gyazo.com/95d11b6d722082fe2a803c2c036da88a.png)](https://gyazo.com/95d11b6d722082fe2a803c2c036da88a)
※ちなみに２行目の"en"は英語表記の意味なので、日本語表記の"ja"に変更してください
するとブラウザにHello, worldが表示されます。
[![Image from Gyazo](https://i.gyazo.com/5723221e71df2a6ba19298f8b0bbca38.png)](https://gyazo.com/5723221e71df2a6ba19298f8b0bbca38)

なんでもいいのですが
Bootstrap4のclass="display-1"属性を、h1要素に指定してみると、
[![Image from Gyazo](https://i.gyazo.com/fb439d06cbb2c5bdcd30efafd21cf02b.png)](https://gyazo.com/fb439d06cbb2c5bdcd30efafd21cf02b)
テキストが大きくなりました！
これでBootstrapが適用されていることの確認ができました。
何も変わらなければ適用されていません。
[![Image from Gyazo](https://i.gyazo.com/cad7d2e2eb468a0bb0b08bac9f1a6733.png)](https://gyazo.com/cad7d2e2eb468a0bb0b08bac9f1a6733)
Railsのルーティングについて学び直そうと思う…②

#はじめに
昨日に引き続き、Railsのルーティングについて、基本的なことから復習しています。

[Railsのルーティングについて学び直そうと思う…①
](https://qiita.com/TerToEer_sho/items/82cf422ac2b270001722)

##基本形


`HTTPリクエスト URL, to: 'コントローラ名#アクション名' `
**※省略形もあります**

HTTPリクエストとは、getやpostなど。
##ルール
- 読み込まれる順番は、上から。  
 →つまり、より限定的なURL程、上に記述しないと、予期しないところでマッチしてしまう。
ex)
「りんご」で、一致させたいのに、「くだもの」で一致してしまうみたいな…  
…より、わかりにくくなったらすみません。

```ruby

get "posts/:id" => "posts#show"
get "posts/new" => "posts#new"
```

- :idは似たURLの中でも最後に書く。`:id`は変数なので、何にでも一致してしまう。
【Python】それぞれのオブジェクトがリストを持つ（共有しないようにする）には？

Python初学者です！

とある教材のコード課題を解いていてなかなか理解できなかったので、記事にすることにしました。

頑張って現時点で理解できているだけの用語と知識で言語化してみました。

**もし、説明でおかしなところや理解がまだまだ浅い部分がありましたらつよつよエンジニアの皆さんよりご指摘いただけると幸いです><！！**

（2021-01-22 @shiracamus  さんよりご教授いただきましたので追記します！ありがとうございますm(_ _)m）
## 使用環境
macOS BigSur バージョン11.1
Google Colaboratory

## 課題
というわけで早速、その課題です。

***Q. 次のクラスはバグを持っている。***
***複数インスタンスを行った場合addメソッドを呼び出すと、それぞれのオブジェクトにリストが共有されている。***
***これをデバッグし、正常に動作させよ。***

```py
class Sample:
    li = []
    def __init__(self, name):
        self.name = name

    def add(self, name):
        self.li.append(name)

a = Sample('test1')
b = Sample('test2')
a.add('test1 a')
b.add('test2 b')

print(a.li) 

# 出力結果
# ['test1 a', 'test2 b']

```

## 原因

これをどのようにすればいいのでしょうか。

まず、出力結果から考えると問題文の通り、`['test1 a', 'test2 b']`と出力されているのが分かります。

本来は、どのような出力を期待していたのかというと、 コードを見る限り**`print(a.li) `で`['test1 a']`のみを出力したい**のだと推測できます。

このようなことが起きている原因がどこにあるのかというと、**`a.add('test1 a')`にも`b.add('test2 b')`においても同じリスト`li = []`が使われているから**だと考えられます。

ではなぜ、同じリストが使われてしまっているのでしょうか？？

それは**コンストラクタ外に変数が記述されている（＝インスタンス変数ではなく、クラス変数になっている）から**です。

これを理解するために必要な**3つの知識**をまとめます。
（私はこの３つのことをよく理解していませんでした・・・）

## 重要事項
### ①コンストラクタ
**コンストラクタ**とは**インスタンスが生成されるときに自動的に呼び出されるメソッドのこと**で、対象のクラスのインスタンスを初期化するために利用します。
※厳密には、「コンストラクタから呼び出される初期化メソッド」という方が正しいそうです。

コンストラクタは**`「__init__」`**で定義します。そしてクラスの中の関数の第一引数には**`「self」`**と指定します。

それぞれインスタンスを生成する際には、それぞれのデータを持たせたいわけですからこれによって初期化されるようになればいいわけです。

### ②インスタンス変数
（2021-01-22 @shiracamus  さんよりご教授いただきましたので追記します！ありがとうございますm(_ _)m）

そしてこれを実装する際にもう一つ大事な概念、メソッド上で定義する変数のことを**インスタンス変数**と言います。

インスタンス変数は、**それぞれのインスタンス（オブジェクト）ごとに独立している**という性質を持っています。

さらに、そのインスタンス変数には**self（インスタンス自身）**をつけるのがルールです。

基本の書き方は以下のようになります。

```py

def __init__(self, 引数):
  self.インスタンス変数 = 引数
```
なのでコンストラクタでインスタンス変数を定義するには、`self.li = []`と書くのが良さそうです。

### ③クラス変数


**クラス変数**とははじめに書いていたように**class直下に定義している変数のこと**です。

また、このクラス変数は**全てのインスタンスで共有される**という性質を持っています。

だから、最初のコードではリストがa,bどちらのインスタンスにも共有されてしまったのです！（なるほど:thinking::bulb:）

②③をまとめると、
**1. インスタンスに変数を代入した場合は、インスタンスに変数が作られる（クラス変数とは別）**
**2. インスタンスに変数を代入しなければ、クラス変数を参照する**

この辺りはよく混同しやすいそうで、以下の記事も参考にさせていただきました！
（@7shi さんありがとうございます:smile:）
[『Pythonでクラス変数とインスタンス変数を取り違えてハマった』][0]
[0]:https://qiita.com/7shi/items/d37493c58a8bb8d7beed

## 解決方法

ということで、以上のことを抑えたらコードを書いてみます。

```py
class Sample:
    def __init__(self, name):
        self.name = name
        self.li = []

    def add(self, name):
        self.li.append(name)

a = Sample('test1')
b = Sample('test2')
a.add('test1 a')
b.add('test2 b')
a.add('test3 a')
b.add('test4 b')

print(a.li)
print(b.li)

## 出力結果
## ['test1 a', 'test3 a']
## ['test2 b', 'test4 b']

```

出力結果もそれぞれのインスタンスに対してリストが生成されています:smile:

``__init__``にてインスタンス変数を作ると、それぞれのインスタンス（aとb)毎に初期化されたliという空のリストが渡されているからですね！

まだまだなれませんが数をこなして慣れていきますっ！:muscle:

では、次回もよろしくお願いします！
Laravelで画像を表示する方法

PHP、Laravelの初学者です。

Laravelで画像を表示させる方法がわかったので、メモしておきたいと思います。

※ 使用しているLaravelのバージョンは6.xです。違うバージョンをご使用の方はご注意ください。
また、私はMacを使用しているので、Windowsをご使用の方もご注意ください。

# Laravelで画像を表示させる方法

①「自分のプロジェクト/storage/app/public」の中に利用したい画像を置く。

　私は「/storage/app/public」にtop-page.jpgを入れました（以下の画像をご覧ください）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790372/2f5d21ee-0e90-9d7e-7688-9e95350a2b24.png)

② シンボリックリンクを張る

Laravel6.xの公式ドキュメントを見たところ、
「/storage/app/public」においた画像を使えるようにする（Webからのアクセスを許す）には、
「『public/storage』から『storage/app/public』へシンボリックリンクを張る」という作業が必要になるようです。

<a href="https://readouble.com/laravel/6.x/ja/filesystem.html">Laravel6.xの公式ドキュメント</a>

シンボリックリンクって何だろう？🤔

>シンボリックリンクとは、オペレーティングシステム（OS）のファイルシステムの機能の一つで、特定のファイルやディレクトリを指し示す別のファイルを作成し、それを通じて本体を参照できるようにする仕組み。

 <a href="https://e-words.jp/w/%E3%82%B7%E3%83%B3%E3%83%9C%E3%83%AA%E3%83%83%E3%82%AF%E3%83%AA%E3%83%B3%E3%82%AF.html">こちらから引用</a>

んー。まだ難しい。
もう少し噛み砕いて説明された記事がありました。

<a href="https://wa3.i-3-i.info/word1151.html">シンボリックリンクとは</a>

要は「代理人」のような役割を持つのが、このシンボリックリンクだそうです。
例を引用させていただくと

>例えば、ファイルＡと、シンボリックリンクＡ’があるとしましょう。
シンボリックリンクＡ’は、ファイルＡのシンボリックリンクです。このシンボリックリンクＡ’を開くと、ファイルＡが開きます。
ファイルＡを直接開いたのと同じ結果です。

>要は、代理人みたいなものですね。
シンボリックリンクは、自分がそのファイルやフォルダであるかのように振る舞います。

とのことです。

さて、前置きが長くなりましたが、このシンボリックリンクを張るには、以下のコマンドを実行しましょう。

```none:ターミナル
php artisan storage:link
```

③シンボリックリンクを張ることができたら、ビューファイルに以下のように記述すれば画像を表示できます。

```php:index.blade.php
<img src="/storage/top-page.jpg">
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790372/aa425d9b-ed28-4b45-71c9-e5612ab60bd4.png)

こんな感じで成功しました！

以上です。
何かありましたらコメントで教えていただけますと幸いです。

ここまで読んでいただきありがとうございました。
Gitのコミットメッセージに迷った時にみるチート

シンプルにこのチートから選ぶといい
https://www.tam-tam.co.jp/tipsnote/program/post16686.html

基本は、Railsチュートリアルのこの箇所
https://railstutorial.jp/chapters/beginning?version=6.0#code-default_root_route

```Mac:Railsチュートリアル
コミットメッセージは現在形かつ命令形で書くようにしましょう29 。
Gitのモデルは、（単一のパッチではなく）一連のパッチとしてコミットされます。
そのため、コミットメッセージを書くときには、そのコミットが「何をしたのか」と過去形の履歴スタイルで書くよりも「何をする」ためのものなのかを現在形かつ命令形で書く方が、後から見返したときにわかりやすくなります。
さらに、現在形かつ命令形で書いておけば、Gitコマンド自身によって生成されるコミットメッセージとも時制が整合します。詳しくは『開発基礎編 Git』の 「Gitにコミットするとは」をご覧ください。
```
コマンドライン（command line）の基本のまとめ

#コマンドラインとは？
文字だけでコンピュータを操作するものです。
コマンドラインは、 cmdやCLI、プロンプト、コンソール、ターミナルと呼ばれることもあります。
Windowsならコマンドプロンプト、Macならターミナルを開き、操作します。

#コマンドでファイルを作成する
`touch ファイル名` を入力した後にEnterキーを押すと、ファイルを作成することができます。

```
$ touch ファイル名
```

#ファイルの中身を表示する
`cat ファイル名` を入力した後にEnterキーを押すと、ファイルの中身を表示することができます。

```
$ cat ファイル名
```

#ディレクトリ(フォルダ)を作成する
`mkdir ディレクトリ名` を入力した後にEnterキーを押すと、ディレクトリ(フォルダ)を作成することができます。

```
$ mkdir ファイル名
```

#ファイル名を変更する
`mv ファイル名 新しいファイル名` を入力した後にEnterキーを押すと、ファイル名を変更することができます。

```
$ mv ファイル名 新しいファイル名
```

#ファイルをコピーする
`cp コピーするファイル名 新しいファイル名' を入力した後にEnterキーを押すと、ファイルをコピーすることができます。

```
$ cp コピーするファイル名 新しいファイル名
```

また、ディレクトリごとコピーする場合は `cp -r コピーするディレクトリ名 新しいディレクトリ名` です。

#ファイルを削除する
`rm ファイル名` を入力した後にEnterキーを押すと、ファイルを削除することができます。

```
$ rm 削除するファイル名
```

また、ディレクトリごと削除する場合は `rm -r ディレクトリ` です。



#補完機能を使う
ファイル名などを入力するときなどの入力途中に `Tabキー` を押すことで、残りのファイル名を補完してくれます。
効率が良くなり、ファイル名などの打ち間違いによるエラーを防ぎやすくなります。

#ディレクトリを移動する
`cd ディレクトリ名` で指定したディレクトリに移動することができます。
現在いるディレクトリ、作業しているディレクトリのことをカレントディレクトリと呼びますが、 `cd ディレクトリ名` とすると `$` の左にカレントディレクトリが表示されます。
AppleScript ハンドラの高速化

#ハンドラのデータ受け渡し

 [構造化プログラミング](https://e-words.jp/w/構造化プログラミング.html)を行なう上で、
サブルーチン(ハンドラ)は
プログラムの見通しを良くするために必要だと言われます。

ところが、**AppleScript** はハンドラでのデータ受け渡しがとても遅く、
繰り返しハンドラを呼び出すとさらに遅くなります。

それはそれで、実行速度は工夫次第で何とかするもの、
と思い込んでましたが、それにしても遅いです。

本当は、工夫よりも知識と探求心なんじゃないか、
と思います。

以下は、
(1)1〜10,000をループさせて、
(2)ループ変数をハンドラへ渡し、
(3)ハンドラでループ変数を文字列化してリストに追加、
(4)ハンドラからリストを戻す。
というスクリプトです。

<details><summary>**サンプルコード1**</summary><div>

```AppleScript:sample1
use framework "Foundation"
use scripting additions

set eDate to current application's NSDate's timeIntervalSinceReferenceDate()

property theResult : {}

set theResult to {}

repeat with i from 1 to 10000
	set theResult to my theLoop(i)
end repeat

display alert ((((current application's NSDate's timeIntervalSinceReferenceDate()) - eDate) & "秒かかりました") as string)

----------------------------------※Script Librariesハンドラを想定

on theLoop(i)
	set end of theResult to i as string
	return theResult
end theLoop
```

</div></details>

私のMacBook Pro(os10.14.6／2.2GHz Intel Core i7)では
こうなりました。
![0122_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500852/2dc58997-2107-9d88-8eee-519e449a82b2.png)
そりゃそうです。
**「こんなループ、ハンドラの中でやらなきゃ遅いに決まってんだろ！」**
と先輩から怒られる代物です。
#script object を使用したハンドラ処理

そこで試して頂きたいのが、
以前投稿した、 [script object を使用した高速化処理] (https://qiita.com/ginn_nezz/items/b7b1ad86f61d47bdf10d) です。

repeat 文のループ変数、及びリスト変数を script object として設定、
**script object 自体を引数と戻り値にしています。**

<details><summary>**サンプルコード2**</summary><div>

```AppleScript:sample2
use framework "Foundation"
use scripting additions

set eDate to current application's NSDate's timeIntervalSinceReferenceDate()

script theIterator
	property record : 0
end script

script theResult
	property record : {}
end script

set record of theIterator to 0
set record of theResult to {}

repeat with i from 1 to 10000
	set record of theIterator to i
	set theResult to my theLoop(theIterator)
end repeat

display alert ((((current application's NSDate's timeIntervalSinceReferenceDate()) - eDate) & "秒かかりました") as string)

----------------------------------※Script Librariesハンドラを想定

on theLoop(theIterator)
	set end of record of theResult to record of theIterator as string
	return theResult
end theLoop
```

</div></details>

結果はこうなります。
![0122_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500852/62217433-ea36-6d1a-955f-f51b70789289.png)

またもや1/10以下！

どうも **AppleScript** は変数の処理に負荷が掛かっており、
プログラムの中で使う変数を全て script object にすることで
なぜか負荷が軽減されるようです。

特にハンドラのデータ受け渡しを
script object にしてしまうことがポイント。

デメリットとしては
センテンスがかなり冗長になってしまうので
プログラムの見通しが悪くなりそうですが、
Cocoa フレームワーク呼び出しも相当なものなので、
要は「慣れ」だと思います。

ぜひお試しください。
【Web Developer Roadmap】【フロントエンド編】＃01−How does the internet work?

記事の前提はこちらをご参照ください。

[【新春企画】Web Developer Roadmap を真面目に勉強するまとめ【フロントエンド編】](https://qiita.com/drafts/2103bac3c0f2aa51e515)

`「強みは技術力です！」`
と、かっこいいことがちゃんと言えるようになりたいという想いと、
いつでもアクセス可能のように備忘も兼ねて書きます。

それではスタート！

#1.How does the internet work?

インターネットとは、、、

>インターネット【Internet】 の解説
個々のコンピューターネットワークを相互に結んで、世界的規模で電子メールやデータベースなどのサービスを行えるようにした、ネットワークの集合体。データのやりとりにTCP/IPという標準化された通信規約（プロトコル）を用いるため、個々のコンピューターの機種によらず通信を行える。また、WWW（ワールドワイドウェブ）という標準的な情報提供システムが用いられ、文書以外にも画像や音声、動画などのデータを閲覧・視聴できる。
出典：デジタル大辞泉（小学館）

###ここのコンピュータネットワークを相互に結ぶについて
####コンピュータの種類
#####サーバー
クライアントが要求した情報を提供するコンピューターのこと。
1. Webサーバー
2. メールサーバー
3. DNSサーバー

#####クライアント
一般ユーザーが利用するコンピューターがクライアントになる。
サーバーに対して要求した情報を受け取る。

####相互に結ぶために
インターネットに接続されたそれぞれのコンピューターにはIPアドレスと呼ばれる独自の住所のようなものを持っている。
IPアドレスは数字の組み合わせでできており、以下のように表記される。
　 nnn.nnn.nnn.nnn
 　※nは0-255の数字
scikit-learnの基本

# なぜscikit-learnを使うのか？
おそらくscikit-learnを使うことを考える人は何かしらのデータを持っていて、そこから何かしらの知識を得たいという人がほとんどであると思います。データから何かしらの知識や知見を得ることをデータマイニングと呼びます。
データを生かして知見を得るためには、そのデータの統計的な情報を出力したり、データを利用するための数学的な解析を行わなければなりません。これを簡易的に行うことのできるライブラリを網羅的に備えてくれているのが、scikit-learnです。


一応僕も理系大学院を卒業して、開発職についているわけなんですが、数式をコードに起こすのってとっても大変ですよね。そんな人でも簡単に効率的な分析ができるよう作られています。
ということで、こんな人におすすめです。

- アルゴリズムとか理論とかよくわからないけど、データをもって何かしたい人
- AIについて少し勉強したけど、具体的な手法を使いたい人

# scikit-learnの基本情報
英語が読める人→[ここ](https://scikit-learn.org/stable/)
英語が読めない人→このまま

2010年にGoogleによって開発され、機械学習のデファクトスタンダードとして、広く利用されています。データを持つ人はチートシートと呼ばれる以下の画像にしたがって分析を行うことが推奨されています。
![ml_map.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632081/dce955cb-63a4-cbb8-7720-faae7431b189.png)

(出典)https://scikit-learn.org/stable/tutorial/machine_learning_map/

自分の持っているデータとにらめっこして、たどりつく緑の四角のアルゴリズムをググってみましょう。使い方はすぐに見つけることができると思います。

以下ではscikit-learnが得意とする問題についてご紹介していきます。

## 回帰
持っているいくつかのデータを使って、目標のデータを予想する問題。株価の予測とか、連続的な値を予想する。

## 分類
回帰とは違い、離散的な値を予測する問題。どのグループへ分類するかはこちらで決める。最近ネットで車が写っている写真を選ばされたことはないだろうか？それはこの問題の正解例として利用されている。

## クラスタリング
上の分類と似ているが、どのグループへ分類するかが指定されない分類問題。よくわからないデータがあるけど近いもの同士まとめるときに使用する。

## 次元削減
データの中で主なるものを見つけ、データの種類を減らす。主成分分析が代表的。

# 終わりに
これからそれぞれのアルゴリズムについても整理していければと思います。よろしくお願いします。
Rspec createとbuildの違い

#目的
・テストコードにおけるcreateとbuildの違いについて理解を深める

#内容

テストコードにおいて下記のコードを実行したら、

```
pry(#<RSpec::ExampleGroups::User::Nested>)> sign_in(@room_user.user)
NoMethodError: undefined method `user' for nil:NilClass
Did you mean?  super
```
とのエラーコードが出ました。
userの中身が空ですといった内容のエラーです。コードは正しいと思われるのですが、何故でしょうか。
理由を深掘りしてみます。

記

```user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  before do
    @user = FactoryBot.build(:user)
   #↑ここが原因
  end

  describe 'ユーザー新規登録' do
    it "nicknameとemail、passwordとpassword_confirmationが存在すれば登録できること" do
      expect(@user).to be_valid
    end

    it "nicknameが空では登録できないこと" do
      @user.nickname = nil
      @user.valid?
      expect(@user.errors.full_messages).to include("Nickname can't be blank")
    end

    it "emailが空では登録できないこと" do
      @user.email = nil
      @user.valid?
      expect(@user.errors.full_messages).to include("Email can't be blank")
    end

    it "重複したemailが存在する場合登録できないこと" do
      @user.save
      another_user = FactoryBot.build(:user)
      another_user.email = @user.email
      another_user.valid?
      expect(another_user.errors.full_messages).to include("Email has already been taken")
    end

    it "passwordが空では登録できないこと" do
      @user.password = nil
      @user.valid?
      expect(@user.errors.full_messages).to include("Password can't be blank")
    end

    it "passwordが5文字以下であれば登録できないこと" do
      @user.password = "00000"
      @user.password_confirmation = "00000"
      @user.valid?
      expect(@user.errors.full_messages).to include("Password is too short (minimum is 6 characters)")
    end

    it "passwordが存在してもpassword_confirmationが空では登録できないこと" do
      @user.password_confirmation = ""
      @user.valid?
      expect(@user.errors.full_messages).to include("Password confirmation doesn't match Password")
    end
  end
end
```

#buildはデータベースに保存する機能はない
上記、

```
 @user = FactoryBot.build(:user)
```
に注目すると、buildメソッドを使用しているが、createにデータベースへインスタンスを保存する役割はありません。
そのため、データベースが空という意味の
`user' for nil:NilClass
が表示されました。

#データを保存する際はcretate
当該部分を正しく訂正すると

```
@user = FactoryBot.create(:user)
```
となります。
buildに対してcretateはデータベースへアクセスし、インスタンスを保存する役割があります。

では、buildを使用する理由はなんでしょうか。
buildはデータベースへのアクセスという処理がない分、createよりも処理が早いというメリットがあります。
膨大なデータを扱う際のテストはcreateの必要がない部分はbuildを用いる方が良いでしょう。

#総括
create：DBにインスタンスを保存する
build：メモリに一時的にインスタンスを生成する

テストにおいて、データベースにアクセスする必要がある処理にはcreate。一方、アクセスする必要ないものはbuildを用いる。buildはアクセスがない分、自動化テストの処理が早くなるメリットがある。
営業マンがEC2に挑戦したら/etc/fstabに返り討ちにされた話

所属する会社がAWSに力を入れているため、実際に触ってみようということで、

- Amazon LinuxにApacheをインストールして、PCからhttp接続
- EBSを新たにアタッチ、マウントして使用する
- バックアップを保存し、EC２インスタンスをまるごと削除し、復元する。

という課題にチャレンジしました。

ハンズオン形式でしたので、「まずは最後までサクッと経験しよう」の期待とは裏腹に、トラブりましたので顛末を書いてみようと思います。
数カ月後に読み返した際に、かわいいなぁと思えるように。

# 想定していたプロセス
<dl>
<dt>EC2インスタンスをたてる</dt>
<dd>・AMIはAmazon Linux 2</dd>
<dd>・ユーザデータにApacheのインストール、起動、再起動後も有効とするシェルスクリプトを記載</dd>
<dd>・セキュリティグループにHTTPを設定</dd>
<dt>ターミナルでEC2の起動確認をする</dt>
<dd>・ssh接続でEC2インスタンスに接続</dd>
<dd>・Apacheが正常に起動しているか確認（systemctl statusコマンド）</dd>
<dd>・起動ログを確認してユーザデータに記載した内容を確認（cat /var/log/cloud-init-output.log）</dd>
<dt>EBSをアタッチ・マウントする</dt>
<dd>・同一のAZにボリュームを作成する</dd>
<dd>・作成したEC2インスタンスにアタッチする（デバイスには /dev/sdf と入力）</dd>
<dd>・ファイルシステムを作成する(mkfs -s /dev/xvdf)</dd>
<dd>・ファイルシステムの型を確認し、UUID=~~~をメモしておく(mkfs -s /dev/xvdf)</dd>
<dd>・マウントするディレクトリを作成する（mkdirコマンド）</dd>
<dd>・マウントする（mount /dev/xvdf マウント先ディレクトリ）</dd>
<dd>・ディスク情報を確認し、マウントされたことを確認する（de -hコマンド）</dd>
<dd>・削除後、復元した際に自動でマウントする設定をする（vi /etc/fstab）</dd>
<dd>・マウントを解除する(umount マウント先ディレクトリ)</dd>
<dd>・再起動する（reboot コマンド）</dd>
<dd>・ssh接続で再度EC2インスタンスに接続</dd>
</dl>
この先もまだプロセスがありましたが・・・
# エラーが起きた箇所
マウントを解除して、再起動後、ssh接続ができませんでした。
コマンドを打ってもプロンプトが現れてくれません。

# 振り返る
`reboot`も`umount`もシンプルで間違えていないよなと。
`vi /etc/fstab`でミスしたのはほぼ間違いなさそうそうでした。

# 原因と対処
とりあえず出てきたエラーや状況をコピペして暗中模索。。
AWSマネジメントコンソールから直接ログを見ることができることを知り、ログを見てみると
```emergency mode　〜なんちゃら〜```
と出力されており、下記ページにたどり着きました。

[EC2 Linux インスタンスが起動せず、緊急モードになるのはなぜですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-linux-emergency-mode/ "タイトル")

詳細は上記にあるので、流れだけ書くと下記の手順で復旧できました。
1. 復旧したいEC2インスタンスを停止し、ルートボリューム（デフォルトでアタッチされているボリューム）をデタッチ
2. 同一AZで新しくEC2インスタンス（救世主）を起動し、１でデタッチしたボリュームをセカンダリ（２つ目）としてアタッチ
3. 救世主にSSH接続し、マウント先ディレクトリを作成、マウントする
4. `vi /etc/fstab`で教わったとおりに書き換えて保存する！
5. ボリュームをアンマウントし、救世主からセカンダリボリュームをデタッチする
6. 復旧したいEC2インスタンスにアタッチして、起動
7. SSHできることを確認！（涙

# 学べたこと
正直なことろ、viコマンドで再度/etc/fstabを書き換える際は復旧に必死で、
「どこを間違えたのか」
という最も大事なことをわからず復旧してしまったことは、最大の後悔です。
しかし、文字ひとつですべてが動かなくなる怖さを学べましたし、よしとしようかなと。

今度は冷静に原因分析しないとなと思った次第です。


# おわりに
Markdownというもの初めてだったので、
https://qiita.com/Qiita/items/c686397e4a0f4f11683d
を見ながら記述しました。纏めていただいておりとても助かりました、感謝です!
ExcelでCSV閲覧の際の0落ち問題

# 概要
WEBアプリケーションからダウンロードしたCSVをエクセルで開くと
0埋めしている社員番号から0が消えて表示される問題があったので、
対応内容をまとめました


# 開発環境
* ruby 2.6.5
* Rails 5.1.7


# まず、CSVを確認
出力されるCSVに問題はなく、０埋め済の社員番号が記載されていた。

```csvs:sample.csv

employee_number,address
012345,tokyo
```

なのにエクセルで開くとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532385/2caca506-b617-0d6e-9fe5-d3fe917ba226.png)


# エクセルで0落ちされないようCSVを加工
0落ち問題対応策の記事は多く、その1つは
CSVに変更を加える方法だった。
エクセルで文字列として表示できるよう、以下の記述に変更すれば
確かに0落ち問題が起きなかった。


```csvs:sample.csv

employee_number,address
="012345",tokyo
```

# でも、CSVはいじりたくない。
CSV出力は大量データを閲覧する目的もあるが、
そのCSVをアプリケーション側にインポートする目的もあった。
社員番号のようにDBではキーとなる値をいじりたくなかった。

# エクセルファイル出力機能をアプリケーションに追加
### caxlsx gemをインストール
インストール方法はgithubを参照
https://github.com/caxlsx/caxlsx

### 各セルの表示形式を文字列に設定、エクセルファイルを出力
表示形式を指定しないと「標準」表示形式となり、
0落ち問題がおきるため、各セルの表示形式を
文字列として設定する必要がある。

* エクセルファイル出力の実装例

```ruby
package = Axlsx::Package.new

package.workbook.add_worksheet do |sheet|
  header = ['employee_number','address']
  values = ['012345','tokyo']
  sheet.add_row header
  # types オプションで各セルの表示形式指定ができる
  #　https://github.com/caxlsx/caxlsx/blob/master/lib/axlsx/workbook/worksheet/worksheet.rb#L385
  sheet.add_row values, types: Array.new(values.size, :string)
end

data = package.to_stream
File.open('/tmp/zero_test.xlsx', 'w') do |file|
  file.write data.read
end

```

### 出力されたエクセルファイルを確認
出力されたファイルを開いてみると
社員番号が正しく表示された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532385/bf576955-85bc-db18-912c-27693676a752.png)
【Laravel】オレ得 Eloquent/QueryBuilderメモ集

## 概要
よく忘れるので自分用メモ✏️
※日々追加...

## データ取得
### get
```php
$users->get();
// 返り値は collection<StdClass>
```

### first
```php
$users->first();
// 返り値は StdClass
```

## WHERE句
### whereIn（含む）
```php
$users->whereIn('id', [1, 2, 3]);
```
### whereDate（日付)
```php
$query->whereDate('created_at', '=', '2020-01-22');
```

## JOIN句
### LeftJoin
```php
DB::table('users as U')
  ->select('U.name, U.age, J.role')
  ->leftJoin('jobs as J', 'j.user_id', '=', 'U.id');
```

## AND/OR
### AND検索
```php
$query
  ->where('name', '=', $value1)
  ->where('age', '=', $value2);
```

### OR検索
```php
$query
  ->where('name', '=', $value1)
  ->orWhere('age', '=', $value2);
```

### OR+AND検索
```php
$query->where(function ($query) use ($keyword) {
     $query->where('name', 'LIKE', '%' . $keyword . '%')
           ->orWhere('age', 'LIKE', '%' . $keyword . '%');
});
```
【Rails】1対1のアソシエーションにおけるネストされたリソース設計について

## はじめに

リソース設計を考えるときに悩んだ結果をまとめました。
コード例はRailsです。


### 忙しい人のための要約

```
PUT questions/:id/answer
```

でupsertする。


## DB構造

![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322882/51b02f6a-5322-4bf5-5e3f-82f9072fec82.png)

questionsテーブルとanswerテーブルが1対1の関係です。
answerがquestionに紐づくので、外部キーはanswersに持たせます。


## モデル

```rb:question.rb
class Question < ApplicationRecord
  has_one :answer, dependent: :destroy
end
```

```rb:answer.rb
class Answer < ApplicationRecord
  belongs_to :question
end
```

特に言うことのないシンプルな形です。


## リソースどうしよう？

さて、「ある質問に対する回答を追加する場合」を考えました。
オーソドックスな1対多の場合はこんな感じになるはずです。

```
POST questions/:id/answers
```

では、「更新」は？

```
PATCH questions/:question_id/answers/:id
```

しかし、これを1対1で想定すると違和感があります。

- 「ある質問に対する回答」は一つしかないのに、`question_id`と`answer_id`をリクエストで送るのが冗長
- 一度回答を作成したら、同じ質問に対して回答を新規作成することはない

「ある質問の回答」を追加することと更新することは同等の意味を持つはずです。

> **HTTP の `PUT` リクエストメソッド**は、新しいリソースを作成するか、指定したリソースの表現をリクエストのペイロードで置き換えます。
[PUT \- HTTP \| MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/PUT)

ということなので、Railsのupdateメソッドに相当します。

```
PUT questions/:id/answer
```

というリクエストで回答の値を更新することにします。

既にanswerが存在しているときに、新たなanswerをnewとかcreateすること自体がおかしいです。
question1のanswerは一つしかないので、newとedit、createとupdateは等価といえます。
なので、単一リソースのときはedit/updateで作成または更新の行動をしたい。
POST, PATCHを使い分けるためには、リクエスト（URL）がanswerの有無を知る必要があるので、違和感があります。URLがそこまで責任を持つべきではありません。

URLが
:no_good:「question1のanswerを新しくこの値で作成してくれ」とか「question1のanswerがあるはずだから、この値に書き換えてくれ」
:ok_woman:「answerがあるかどうかは知らんけど、question1のanswerの値をこうしてくれ」
ってお願いして、それに答えるのが自然です。


## ルーティング

```routes.rb
resources :questions do
  resource :answer, only: %i[edit update show]
end
```


## コントローラ

`#find_or_initialize_by`という便利なメソッドがあるので、それを使うだけで他は普通のCRUDの場合と変わりません。

```answers_controller.rb
class AnswersController < ApplicationController
  before_action :set_question

  def show
    @answer = @question.answer
  end

  def edit
    @answer = Answer.find_or_initialize_by(question_id: @question.id)
  end

  def update
    @answer = Answer.find_or_initialize_by(question_id: @question.id)
    if @answer.update(answer_params)
      redirect_to question_answer_path(@question, @answer)
    else
      render :edit
    end
  end

  private

  def set_question
    @question = Question.find(params[:question_id])
  end

  def answer_params
    params.require(:answer).permit(:text)
  end
end
```


## 終わりに

という考えでこういうリソース設計にしたのですが、補足やオススメの書籍などありましたらコメントをいただけるとありがたいです。
fatal: ambiguous argument 'HEAD^': unknown revision or path not in the working tree.

# 事象 : ２つめのコミットをリセットしようとしたら失敗した
```bash
# 1. プシュっていないコミットが２つあって、２つともコミットを取り消したい
$ git log origin/master..master
Merge: 45... 89...
Author: macOS <ponsuke@example.com>
Date:   Fri Jan 22 21:26:17 2021 +0900

    Merge branch 'master' of https://github.com/{ユーザ}/{リポジトリ} into master

commit 45...
Author: macOS <ponsuke@example.com>
Date:   Fri Jan 22 20:35:04 2021 +0900

    こみっとこめんと

# 2. １つ取り消して・・・
$ git reset --soft HEAD^

# 3. もう１つも取り消そうとしたら
$ git log origin/master..master
commit 45... (HEAD -> master)
Author: macOS <ponsuke@example.com>
Date:   Fri Jan 22 20:35:04 2021 +0900

    こみっとこめんと

# 4. 怒られた
$ git reset --soft HEAD^
fatal: ambiguous argument 'HEAD^': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
```

## 原因 : HEAD^のってどれのことやねん！という状態
「えっ？一個前のコミット・・・」

```bash
# HEADを確認したら・・・
$ git reflog
45ea498 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
d5f1e7f HEAD@{1}: pull --allow-unrelated-histories: Merge made by the 'recursive' strategy.
45ea498 (HEAD -> master) HEAD@{2}: commit (initial): こみっとこめんと
```

### 対応 : HEADを使わないでどこまでリセットしたいかちゃんと伝える
```bash
# 1. originまで戻してね
$ git reset --soft origin/master

# 2. プシュしてないコミットは無くなりました。
$ git log origin/master..master
$
```

複数のコミットはいっきに取り消しましょう、面倒です。

> コミットを指定するときに、~(チルダ)と^(キャレット)を使ってあるコミットからの相対位置で指定することもできます。この時に、よく使われるのがHEADです。~(チルダ)を後ろに付け加えることで何世代前の親かを指定することができます。^(キャレット)は、ブランチのマージで親が複数ある場合に、何番目の親かを指定することができます。
> [ブランチの切り替え｜サル先生のGit入門【プロジェクト管理ツールBacklog】](https://backlog.com/ja/git-tutorial/stepup/03/)
【2】Django の管理画面からアプリケーションのデータベース管理をする

## 概要
* Docker-composoe + Django環境で作業環境を整えます。
* Djangoは専用の管理画面からデータベースの操作（作成や編集など）が行えます。
    * つまりPHPMyAdminなどが不要!!

## 環境
* Docker + Docker-compose が利用できること。
* Python3.6
* Django3.1(最新)

## 前提
* [Docker-compose + Django + MySQL + Nginx + uwsgi を使った環境の初期設定](https://qiita.com/muneki/items/55daf41e925a969aa5b5) が完了していること
    * djangoが起動中である
    * データベースへアクセスできる
    * 管理画面へアクセスできる
* または、同等の環境であること

## 手順
### アプリケーションの作成
* アプリケーションの作成
    * django: Dockerコンテナ名
    * sample: アプリケーション名

```
$ docker-compose exec django python3 manage.py startapp sample
```

### コンフィグの修正
* `src/app/settings.py`を編集する
    * INSTALLED_APPS に作成したアプリケーションを追加する
       * sample: フォルダ名
       * SampleConfig: `src/app/sample/apps.py` に書いてある`class`名

```src/app/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sample.apps.SampleConfig',         # 追加
]
```

### モデルの作成
* `src/app/sample/models.py`を編集する

```src/app/sample/models.py
from django.db import models


class Test1(models.Model):
    class Meta:
        verbose_name_plural = "テスト1"

    test1_name = models.CharField("テスト名",max_length=25)
    test1_value = models.CharField("テスト値",max_length=25)
    def __str__(self):
        return self.test1_name


class Test2(models.Model):
    class Meta:
        verbose_name_plural = "テスト2"

    test1= models.ForeignKey(Test1, on_delete=models.PROTECT)
    test2_name = models.CharField("テスト名",max_length=25)
    test2_value = models.CharField("テスト値",max_length=25)
    def __str__(self):
        return self.test2_name
```

### 管理画面の設定
* `src/app/sample/admin.py`を編集する

```src/app/sample/admin.py
from django.contrib import admin

# Register your models here.

from sample.models import Test1, Test2
admin.site.register(Test1)
admin.site.register(Test2)
```

### マイグレーション

* マイグレーションファイルを作成して実行

```
$ docker-compose exec django ./manage.py makemigrations
$ docker-compose exec django ./manage.py migrate
```

## 確認
* 下記へログインするとモデルで作成したデータベースが操作できる
    * `http://<IP>:8000/admin`
JSとLaravelでAPI通信する際に日付データを合わせる(unixtime <-> Date)

# 概要

サーバーさん => Sさん
フロントさん  => Fさん

あるときこんなやりとりを目撃しました。

>Sさん < 日付のフォーマットは20200222で送ってください
>Fさん < ここは2020/02/22で送ってください
>Sさん < この場合は2020-02-22で送ってください
>続く....

そのとき第三者の私はこう思いました。
> 私 < Unixtimeでやりとりすれば、同じフォーマットでやりとりできるんじゃね？と...

## やってみた。

```js:javascript
// Date -> UnixTime
new Date().getTime() / 1000;
// 1611320223.828

// UnixTime -> Date
new Date(unixTime * 1000);
// Fri Jan 22 2021 21:57:44 GMT+0900 (日本標準時)
```

※バックエンドはLaravelを使用しています

```php:php
// Date -> UnixTime
$date = new DateTime('now');
$date->format('U');
// "1611320663"

// UnixTime -> Date
$dateTime = new DateTime('@' . (int)$unixTime);
$dateTime->setTimeZone(new DateTimeZone('Asia/Tokyo'));
// 2021-01-22 22:04:23.0 Asia/Tokyo (+09:00)
```

## 感想
一旦これでUnixtimeでやりとりできそう！
もっと良いやり方などがありましたら教えてください。
【Unity】uGUIの謎を1つ1つ解明する

ヤッホー☆(こんにちは！)
今まで何となくで使っていたuGUIについて、理解を深めるためにまとめて行こうと思います。

早速、Hierarchyビュー上でUI > Imageを追加すると...
![スクリーンショット 2021-01-22 21.55.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044221/23b1416f-2dbc-bf55-e442-57423cb0ba02.png)
<font color="Red">**いきなり謎が3つ出現しました...！(絶望)**</font>

## 謎① Sceneビューに突如現れた白枠
これは画面の大きさを示す枠線で、Gameビューから画面サイズを変更すると...
![スクリーンショット 2021-01-22 22.06.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044221/0bc85386-fcaa-e67d-725a-1e045bf51d7d.png)

![スクリーンショット 2021-01-22 22.07.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044221/f1d289be-9f3d-12f9-5adc-4d6eee0ede63.png)

白枠のサイズが変化する！！

## 謎② 突如Hierarchyに追加されるCanvasゲームオブジェクト
is-a, has-a 関係


is-a 関係と has-a 関係というのは、オブジェクト指向に限った話ではないです。
一般的な物事の本質を捉えるための分析のしかた、考え方についてのメタファです。

#is-a（分類法）
A is a B.
上の一文をみただけだと「is-a 関係 = 継承」と思うかもしれませんが、ちょっと違います。
分類法とは、物事を分類していくことで、その物事の本質を掴もうとする分析方法です。

#has-a（分割法）
A has a B.
こちらも分類法同様に「has-a 関係 = 包含」ではありません。
分割法は、より小さく物事を分割していくことで、その物事の本質を掴もうとする分析方法です。

#参考
https://think-on-object.blogspot.com/2011/11/is-ahas-is-ahas-top-is-a-is-b.html
コマンドラインからmp4を倍速に変換する

コマンドラインからmp4を倍速に変換する備忘録

# ffmpegを使って倍速にします

入力：`src.mp4`
出力：`dst.mp4`

```sh:インストール
sudo apt install ffmpeg
```

```sh:（例）3.3倍速に変換する
ffmpeg -i src.mp4 -vf setpts=PTS/3.3 -af atempo=3.3 dst.mp4
```

```sh:（例）1.5倍速に変換する
ffmpeg -i src.mp4 -vf setpts=PTS/1.5 -af atempo=1.5 dst.mp4
```

# ffmpegで動画から領域を切り出す

`(x,y)=(0,30)`から`1920*950`の領域を切り出す場合

```
# 事前確認
ffplay -i src.mp4 -vf crop=1920:950:
# 変換
ffmpeg -i src.mp4 -vf crop=1920:950:0:30 dst.mp4
```

# ffmpegで先頭`3sec`を削除

```
# 事前確認
ffplay -ss 3 -i src.mp4 -c copy
# 変換
ffmpeg -ss 3 -i src.mp4 -c copy dst.mp4
```

# 動画のカットと結合

#### カット

`src.mp4`の`0sec`から`1sec`をカットする場合

```
ffmpeg -ss 0 -i src.mp4 -t 1 -c copy dst.mp4
```

#### 結合

`part1.mp4`と`part2.mp4`を結合する

事前に結合対象のファイルを`mylist.txt`に列挙

```sh:mylist.txt
file /hoge/fuga/part1.mp4
file /hoge/fuga/part2.mp4
```

以下を実行

```
ffmpeg -safe 0 -f concat -i mylist.txt -c copy dst.mp4
```

[Ubuntu: ffmpegでmp4のカットと結合](https://www.kwonline.org/memo2/2019/03/07/ffmpeg-cut-and-concat-mp4-on-ubuntu/)

# 参考
[ffmpegを使って動画の再生速度を変えてみる](http://fftest33.blog.fc2.com/blog-entry-36.html)
printfデバッグを劇的に効率的にするライブラリicecream-cpp

コードをデバッグする際にはデバッガを使うこともあれば、単純に`printf` (`cout`,`cerr`) を埋め込んでデバッグすることもあると思う。
この記事では [icecream-cpp](https://github.com/renatoGarcia/icecream-cpp) というprintfデバッグの際に非常に便利なライブラリを紹介する。
Pythonにも[同名のライブラリ](https://github.com/gruns/icecream)（紹介記事は[こちら](https://qiita.com/purun/items/c7aca300b970344214cf)）があるが、そのPythonのicecreamのようなものをC++用に書いたライブラリがicecream-cppである。

リポジトリ : https://github.com/renatoGarcia/icecream-cpp

# 使い方

例えば以下のように変数の内容を`cerr`に出力してデバッグするという経験は誰でも日常的にしていると思う。

```cpp
  int i = 40;

  // 何かしらの処理の後、iの内容を出力
  std::cerr << "i: " << i << std::endl;
```

どの変数かわかるように変数名を出力して、そのあとで変数の中身を出力しているが、この辺りは定型句なので毎回書くのは若干面倒だ。変数が単純な型ではなく、`vector`などのコンテナのときに中身をイテレートする処理を書いたりすると、だいぶ面倒だ。

Icecreamはこのような面倒なことを代わりにやってくれて、変数の名前と中身をいい感じに標準エラーに出力してくれる。やり方は非常に簡単で、出力したい変数に対して`IC(...)` というマクロを呼ぶだけ。

```cpp
#include <icecream.hpp>

int main() {
  int i = 40;
  IC(i);         // 自分でcerrを書く代わりに、IC(...)を呼ぶだけ。

  return 0;
}
```

実行結果は以下のようになる。

```txt
ic| i: 40
```

## 他の型の場合

他の型でもうまく表示してくれる。primitive型、`std::string`の文字列、STLコンテナなどうまく表示してくれる。

```cpp
  std::string s = "Hello world";
  char c = 'X';
  std::vector<double> v = {0.2, 0.5, 1.0};
  IC(s,c,v);

  std::map<std::string, double> m = { {"foo", 1.0}, {"bar", 2.0}};
  IC(m);

  std::set<int> my_set = {3,5,7,1};
  IC(my_set);
```

```txt
ic| s: "Hello world", c: 'X', v: [0.2, 0.5, 1]
ic| m: [("bar", 2), ("foo", 1)]
ic| my_set: [1, 3, 5, 7]
```

自分で定義したクラスについても表示できる。

```cpp
  class MyClass {
    public:
    int i;
    double d;
  };

  MyClass mc;
  mc.i = 10; mc.d = 3.14;
  IC(mc);
```

```txt
ic| mc: {i: 10, d: 3.14}
```

（ただし、2021年1月時点ではユーザー定義したクラスのメンバーがコンテナのときにうまく表示できないようだ。おそらくバグだと思うが、この件はgithubで[issue](https://github.com/renatoGarcia/icecream-cpp/issues/14)を立てて報告している）

また `operator<<(ostream&, T)`が定義してある型であれば、それを使って出力される。

## コンテキストの表示

`IC`マクロを引数なしで実行すると、実行時のコンテキスト（メソッド名とソースの行番号が表示される。）例えば、if文でどちらが実行されているかデバッグするためにprintfを使う代わりにICを使うと便利。

```cpp
  if (b == 2) {
    IC()
    ....
  }
```

```txt
ic| x.cpp:61 in "int main()"
```

## 出力時のプレフィックスを設定する

デフォルトでは `ic| `という文字列がプレフィックスとして出力されるが、この部分をカスタマイズして情報を追加することができる。
例えば、どのスレッドで実行しているかを出したいときは以下のようにすると、それ以降の出力でスレッドの情報が出力される。他にもタイムスタンプを出したり、MPI並列化されているプログラムならばランク番号を出したりしても良いかもしれない。

```cpp
icecream::ic.prefix("thread ", std::this_thread::get_id, " | ");
```

```txt
thread 0x107c02dc0 | i: 40
```

## 出力時にコンテキストも表示する

以下のように設定すると、それ以降の出力でコンテキストの情報も出力される。

```cpp
icecream::ic.include_context(true);
```

```txt
ic| x.cpp:65 in "int main()"- i2: 40
```

# インストール方法

インストール方法は公式の[リポジトリのreadme](https://github.com/renatoGarcia/icecream-cpp#install)でいくつか紹介されている。
しかし、ヘッダ１ファイルをインクルードするだけなので、プロジェクトのgitリポジトリにサブモジュールとして追加してしまうのが一番簡単かつ移植性が高いと思われる。

```shell-session
git submodule add git@github.com:renatoGarcia/icecream-cpp.git icecream
```

でicecream-cppのリポジトリをサブモジュールとして追加し、あとはinclude pathにサブモジュールのパスを追加すればよい。cmakeを使っている場合は、以下の１行を追加する。

```cmake
include_directories(${CMAKE_SOURCE_DIR}/icecream)
```

あとは、ヘッダファイルを読み込むだけで利用できる。

```cpp
#include <icecream.hpp>
```
気にするな！で済ませない、自分の技術力の無力さを感じた時に見直す4つのフロー

エンジニアとして働くと周りの社員が凄すぎて落ち込むことあると思います。
最近では実務経験がなくてもスクールとかで劣等感を感じる事もあるかと。
自分は最近周りのエンジニアの成長スピードに劣等感を感じ、ひどく落ち込んだのでそういう人が1人でも減ればいいなーと思って書きました。

ひどく落ち込んだ人を一時的に慰める行為として気にするな！と声をかけるのはありです。あくまで自分が気にするな！で済ませないようにしましょうという話です。

# ステップ1：今の努力量と方向性を考えてみる
落ち込んだ時にすぐにやるべき事は劣ってる原因をすぐに改善できるか？

例えば努力量を増やすなら
*・SNSやテレビ見る時間を減らして早起きする*
*・好きでもない趣味を止める*
*・飲み会にいく頻度を減らす*　など

方向性を見直すなら
*・先輩や上司に勉強すべき内容を聞く*
*・勉強してる事は今すぐ使う内容なのか確認する*　など

自分は毎日12~14時間ぐらいプログラミングをやった上で上司相談しても劣等感を感じてしまったのでステップ1だけで解決しませんでした。(上司はすごく優しくいい事を言って頂きました。あの時はありがとうございます)




# ステップ2：自分に何ができるのか考えてみる
「俺はあの人みたいにすぐ理解できない・・・」
「私はあの人みたいにエンジニアをまとめる事ができない・・・」
「僕はあの人みたいに文章を上手くまとめられない・・・」

などなど人と比べれば無限に自分の弱点が出てきます。
これから成長すればいい！とよく言われると思いますがこれはただの気休めです。
自分の「できない事、苦手な事」を徹底的に洗い出しましょう。
そして、それらの分野で戦わない事です。
大人ができない事を無理にできるようにしたってせいぜい平均止まりです。
それより自分の好きor得意な事を徹底的に伸ばし「○○ならミウミさん」と呼ばれるように頑張る事にしました。
自分の例を出すとこんな感じですね

### 得意な事、好きな事
*・圧倒的努力量*
*・情報発信*
*・文字をまとめる事*
*・思い立ったら行動する(俗にいう行動力)*

### 苦手な事
*・一度で理解する事*
*・複数のタスクを同時にこなす事*
*・アドリブで上手く説明する事(俗に言うコミュ力？)*


# ステップ3：エンジニアでも活躍できる場所はたくさんある
上記で自分の得意な事をまとめた後はそれをエンジニアで活かせるか考えてみましょう。
コードを書くだけではありません。例えばエンジニアでも下記のような事で活躍する事もできるでしょう。

・ドキュメントやマニュアルをまとめたり、Qiitaに投稿する
*→コミュ力や技術力に自信はないがわかりやすい文章を作成するのが得意*

・twitterで投稿する(社内、社外問わず)
*→コミュ力や技術力に自信はないが人を動かせる文章を作成するのが得意*

・youtube活動を始める(社内、社外問わず)
*→技術に自信がないが自分の考えを事前にまとめ話す事が得意*

・ディレクター業にシフトする
*→技術に自信がないがアドリブで話す事に自信がある*

などなど・・・
自分は過去にゲーム関連のブログを１００記事以上投稿していたので投稿と情報発信に力をいれる事にしました。確かに自分は優秀な人より成長も遅いし、話が上手いわけでもない。
だからこそ誰よりも多く情報発信をし会社の成長を手助けできるポジションを狙う事にしました。勿論、技術の勉強は今まで通り続けますよ！


# ステップ4：生活基準を見直す
そんな事を言ったってエンジニアで活躍できる気がしないよ！と言う人は一度外の世界を見るといいでしょう。苦手分野であるエンジニアを続けても辛いだけです。精神が崩れ病気等になったそれこそ莫大な出費がかかります。上で説明した通り苦手な分野で戦っても勝ち目はありません。

エンジニアを辞めれば収入が下がるかもしれませんが田舎に暮らす事で必要な出費も下がります。
**今の収入を無理して維持する必要があるのか？**を一度考えてみましょう
無駄遣いは一度やめればすぐにやめられるものです。
そんなの無理だよ！と思ってる人も多いと思いますが挑戦するのに一番大変なのは**新しい事に時間を使う労力ではなく今までの習慣を手放す事**です。つまり最初の一歩を踏み出せばほぼ勝ち！って事です。
実際自分もエンジニア勉強する前は1日8~10時間ぐらいゲームしてましたけど、今は0です。もっと早くエンジニアになればよかったと後悔してますw


## 活躍する場は慎重に選ばなきゃならない
人は比べてしまう生き物です。ある程度気にしない事は出来ますが完全に消すのは無理です。だからこそ自分が勝てる！活躍できる！と思った場所を探すのはとても大切です。
**比べてしまう自分も責めるのでなく、比べる自分を活かす生活を今日から始めませんか？**
そうすれば今何をすべきか本気で考えるようになるでしょう

###おまけ
当記事は1時間で完成しました。隣の先輩に「コード書く時と姿が違う」と言われましたw
Railsの検索メソッドの基礎（whereでLIKE句を使う）

### めちゃくちゃ曖昧に理解していたこんな文

検索用メソッドで出てくるこんな文。めちゃくちゃ曖昧に理解していたので、復習します。

```Ruby:
@users = User.where('name LIKE ?', "%#{params[:name]}%")
```

`('name LIKE ?', "%#{params[:name]}%")`はどういう意味かというと...（ちゃんと[Railsガイド](https://railsguides.jp/active_record_querying.html#%E9%85%8D%E5%88%97%E3%81%A7%E8%A1%A8%E3%81%95%E3%82%8C%E3%81%9F%E6%9D%A1%E4%BB%B6)に書いてあった）

検索に使う語句が**可変である**時の書き方らしい。
第一引数（`name LIKE ?`）の`?`の部分が、第二引数（`%#{params[:name]}%`）と置き換えられる。

そして、`where`では、上と下の書き方は同じ結果が得られる。

```Ruby:
@users = User.where(name: 'sato')
@users = User.where("name = 'sato'")
# どちらもidが1のデータが得られる
```
発行されるSQLは若干異なるが、それぞれこんな感じ。

```SQL
SELECT `users`.* FROM `users` WHERE `users`.`name` = 'sato';
SELECT `users`.* FROM `users` WHERE (name = 'sato');
```

`User.where('id = 1')`の`id = 1`が、
SQL文の`WHERE (id = 1)`に入っているイメージか。

**【注】**この書き方は[SQLインジェクションの可能性がある](https://railsguides.jp/security.html#sql%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3)ので、実際には書かない用が良い。


### SQL

一方で、SQLでの`LIKE`句はこのように使う。

```SQL:
SELECT 列名 FROM テーブル名 WHERE 列名 LIKE '検索文字';
```
↑ちなみに、これは「完全一致」の時

- `'%検索文字列'`...前方一致
- `'検索文字列%'`...後方一致
- `'%検索文字列%'`...部分一致

### 改めて、最初の文と合わせてみる

では、改めて、最初の文を眺めてみる。

```Ruby:
@users = User.where('name LIKE ?', "%#{params[:name]}%")
```

この時、仮に**「sato」**という文字列が`params[:name]`として渡ってきていると仮定すると、

```Ruby:
@users = User.where('name LIKE ?', "%sato%")
```
となり、

```SQL
SELECT `users`.* FROM `users` WHERE (name LIKE '%sato%');
```
このようなSQLが発行され、`name`が**「sato」**さんのデータだけが抽出される。

### 追記：LIKE句で複数単語検索をしたい場合
今回、実現したいことはLIKEでの複数単語検索だったので、`LIKE`句の複数単語検索ではどのようなSQLが発行されるのか調べてみました。

例えば、住所録の中から`%山%`さんと`%川%`さんをOR検索で探したい時には、

```SQL
SELECT * FROM users WHERE name LIKE '%山%'
                       OR name LIKE '%川%';
```
らしいので、
Railsで複数単語検索を実現するには、キーワードを配列に入れて、`each`で回して、それぞれで、下記の処理をすれば良さそうですね＾＾

```SQL
@users = User.where('name LIKE ?', "%#{params[:name]}%")
```

続きは次回、実装します〜
Slackで特定のメッセージを取得するby C#

# はじめに
Slack APIで自動でメッセージを投稿して、
そのメッセージを別のチャンネルにメッセージを引用したので
その覚書

# やりたいこと
chat.postMessage APIを利用して投稿した値のリクエストに対するレスポンスからtsを取得。

その後、chat.getPermalink APIのmessage_tsとして設定することにより
レスポンスとしてメッセージURLを取得できる。
その値をchat.postMe APIで投稿する。

今回はchat.getPermalink APIで設定する部分を紹介する。

公式ドキュメントは以下。
必要なあるいは設定できる引数やレスポンスの形式が記載されているので
APIを使う前に目を通した方が良い。

・chat.postMessage
https://api.slack.com/methods/chat.postMessage

・chat.getPermalink
https://api.slack.com/methods/chat.getPermalink

# ソース

```C#
public class Responce
{ 
  public string permalink{get; set; }
}
```
```C#
public string Main()
{
  var parameters = new NameValueCollection();

  //クエリ作成
  parameters.ADD("token",["トークン"]);
  parameters.ADD("channel",["チャンネルID"]);
  parameters.ADD("message_ts",["取得したいメッセージのts"]);

  using(var client = new WebClient())
  {
    //リクエストを送信し、レスポンスを取得
    byte[] responceByte = client.Upload.Values("https://slack.com/api/chat.getPermalink",parameters)

    string responceStr = Encoding.UTF8.GetDtring(responceByte);
    Responce responce = JsonConvert.DeserializeObject<Responce>(responceStr);

    //取得したメッセージのURLを返す
    return (responce.permalink);

}
```

Content Type: application/x-www-form-urlencodedの形式で
トークン、チャンネルID、tsを引数としてリクエストを送信してやれば良い。
VSCodeもWSL2もいらない！？ GitHub CodespacesでElixir/Nerves体験ハンズオンを動かしてみた

2020年12月27日に開催された「Elixir/Nerves(ナーブス)体験ハンズオン！」では、@takasehideki さんが用意した、WSL2 + VSCode + Remote-Containersというイケてる環境でした。

[イベントページ@connpass](https://algyan.connpass.com/event/197306/)
[アーカイブ動画@youtube](https://www.youtube.com/watch?v=A1AiQZR7UFQ)

devcontainerなので、、、これ、[GitHub Codespaces](https://github.co.jp/features/codespaces)でも動くんじゃね？
ってことで、試してみました。


Codespacesをポチして、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109634/7080b07c-1db4-0daf-d019-1563c5b38a73.png)

ハンズオン環境のリポジトリを入力。
Create codespaceをポチ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109634/604645eb-05ad-6647-3ff9-281b1fae6632.png)

イメージをダウンロードなどのログがダダダーーーっと表示されて、、、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109634/c4e3e15b-f9c5-8724-d86b-fc055bd6c1a2.png)

ブラウザ上で（！）VSCodeが起動。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109634/09d6d26e-a19e-8cbe-1157-807e8ee0c6a9.png)

web.exを編集してみたり、、、フツーにVSCode使えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109634/7d8238ed-730d-1c66-edcc-9a0064230251.png)

mix firmwareを実行。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109634/2551b54c-74fd-0361-e24c-053aadc79052.png)

ファームウェアのビルドは約3分でした。

* 手元PCに、VSCodeもWSL2も何にも入れなくてもいい最強。
* WSL2じゃないので、mix firmwareも遅くない。（が、VSCodeのファイル変更追跡が若干気になる）
* 現段階は、出来上がったファームウェアを簡単に手元に取ってくる術が無いので、頭ひねらないといけない感じ。（NervesHubという選択肢は良さそう。）
Arduinoからツイート＋Webサーバー化

書きかけ

Arduino Nano EtherでツイートとWebサーバー化をします。

使用ボードはこちら
https://www.diymore.cc/products/enc28j60-ethernet-network-module-shield-v2-0-for-arduino


参考リンク
Tweet Library for Arduino 
http://arduino-tweet.appspot.com/

Arduinoから温湿度をツイートする方法 - Grow up 
https://knkomko.hatenablog.com/entry/2019/09/17/012226

````c
#include <UIPEthernet.h>
#include <Twitter.h>

Twitter twitter("TWITTER_TOKEN");

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x78, 0xEE  };  
IPAddress ip(192, 168, 0, 117);
IPAddress myDns(192, 168, 0, 1);
                        
EthernetServer server(80);

void setup() {

  Serial.begin(9600);

  Ethernet.begin(mac, ip, myDns);
  Serial.print("IP Address: ");
  Serial.println(Ethernet.localIP());

  server.begin();
  
  String message = "Hello, World! from Arduino Nano ethernet a :-) #Arduino";

  char* msg = message.c_str();
  Serial.print("connecting ...");

  if (twitter.post(msg)) {
    int status = 0;
    status = twitter.wait();
    if (status == 200) {
      Serial.println("OK.");
    } else {
      Serial.print("failed : code ");
      Serial.println(status);
    }
  } else {
    Serial.println("connection failed.");
  }

}

void loop() {

  // listen for incoming clients
  EthernetClient client = server.available();

  if (client)
  {  
    Serial.println("-> New Connection");

    // an http request ends with a blank line
    boolean currentLineIsBlank = true;

    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();

        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank)
        {
          client.println("<html><title>Hello World!</title><body><h3>Hello World!</h3></body>");
          break;
        }

        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r')
        {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }

    // give the web browser time to receive the data
    delay(10);

    // close the connection:
    client.stop();
    Serial.println("   Disconnected\n");
  }
}
~~~~
【Rails】scopeの定義とProcオブジェクト

## scopeとは
よく利用する検索条件に名前をつけてひとまとめにしたもの。
railsガイドでは以下のように解説されています。

> スコープを設定することで、関連オブジェクトやモデルへのメソッド呼び出しとして参照される、よく使用されるクエリを指定することができます。スコープでは、where、joins、includesなど、これまでに登場したすべてのメソッドを使用できます。どのスコープメソッドも、常にActiveRecord::Relationオブジェクトを返します。このオブジェクトに対して、別のスコープを含む他のメソッド呼び出しを行なうこともできます。

## scopeの書き方

```ruby:models/book.rb
class Book < ApplicationRecord
  scope :costly, -> { where("price > ?", 3000) }
end
```
scopeの第一引数にメソッド名、第二引数にProcオブジェクト(のラムダ)を定義することで、コントローラーやモデルで<code>Book.costly</code>と書いたとき、<code>Book.where("price > ?", 3000)</code>と書いたのと同義になります。これによるメリットは以下の２つです。

- 繰り返し利用できる
- 可読性が向上する

何度もクエリを書かなくてよくなるのに加えて、<code>Book.costly</code>とあれば、高価な本を探しているんだなとひと目で分かります。

また、引数を渡すこともできます。

```ruby:models/book.rb
class Book < ApplicationRecord
  scope :written_about, ->(theme) { where("name like(?)", "%#{theme}%") }
end
```

scopeを定義した際の返り値のクラスはActiveRecord::Relationとなるので、scopeをメソッドチェーンでつなげたり、Query Interfaceを呼び出すこともできる。

```ruby
Book.costly.written_about("ハリーポッター").limit(1)
=> #<ActiveRecord::Relation [
#<Book id: 1, name: "賢者の石", published_on: "1999-10-21", price: 4000>
]>
```

### ブロックが複数行に渡る場合
scopeの第二引数はProcオブジェクトのラムダを使います。ブロックが複数行に渡る場合は下のような書き方が一般的です。

```ruby:models/book.rb
scope :written_about, lambda { |theme|
  return if theme.blank?

  where("name like(?)", "%#{theme}%")
}
```
以上

## 補足
### Procオブジェクトとは
ブロックをオブジェクト化したProcクラスのインスタンスです。

```ruby
hello_proc = Proc.new { "hello" }
hello_proc.call
=> "hello"
```

### Procオブジェクトの作成方法

```ruby
Proc.new { |a, b| a + b }
proc { |a, b| a + b }
->(a, b) { a + b }
lambda { |a, b| a + b }
```
厳密には上2つと下2つのオブジェクトは異なります。下２つはラムダと呼ばれ、scopeの第二引数で使っているものです。ラムダは引数のチェックがより厳密です。検索条件で渡ってくる引数は決まっているため、ラムダを使っていました。

```ruby
add_proc = Proc.new { |a, b| a.to_i + b.to_i }
add_proc(10)
#=> 10 

add_lambda = ->(a, b) { a.to_i + b.to_i }
add_lambda(10)
#=> ArgumentError: wrong number of arguments (given 1, expected 2)
```

### Procオブジェクトの実行方法

```ruby
add_proc = Proc.new { |a, b| a + b }

add_proc.call(10, 20)
add_proc.yield(10, 20)
add_proc.(10, 20)
add_proc[10, 20]
```

## 参考
https://railsguides.jp/active_record_querying.html#%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97
パーフェクトRuby on Rails
怖いよ, coqdoc さん！

Coq には、コメントをドキュメントとして扱う機能があります。ソースコードからドキュメントを生成するには `coqdoc` というコマンドを使います。

`coqdoc` は LaTeX や HTML などを生成させることが出来ます。私も HTML のドキュメントを生成させたりしています。

coqdoc は CSS と HTML を一緒に生成します。しかし、この内容が見づらいと私は感じていました。理由は以下の二つです。

* 横幅が制限されているため、 PC のディスプレイだと巨大な余白が出来る。
* ソースコードの部分とドキュメントの部分で背景の色が違い、ドキュメントだけを一塊として強調する仕組みになっているが、同じ見出しの下にあるドキュメントでも塊が分割されていたり、見出しを跨いでドキュメントが一塊になっていたりしていて、私にとっては気持ち悪さを感じる。

coqdoc が生成する通常の CSS をそのまま使っているサイトは印象として少ないのですが、 [Infinite Data and Proofs - Certified Programming with Dependent Types](http://adam.chlipala.net/cpdt/html/Coinductive.html) が一例になります。これを見ればデフォルトのデザインがどのようなものか分かります。

これを改善するために、私は一から独自の CSS を作成しようと考えました。もちろん、デフォルトの CSS を改変する方法もありますが、これは LGPL-2.1 であるため、私のプロジェクトには改変版を含めることが出来ませんでした。

## 地獄の窯が開いた

CSS を書くためには対象となる HTML の構造を知らなければなりませんでした。 coqdoc が生成する HTML がどのようなものなのか、 Google Chrome のデベロッパーモードを使って探検してみました。

```coq
(**

最初の段落。

次の段落。

*)
```

このようなコメントがどのような HTML になるか読者は予測できますでしょうか？ それぞれの段落が `p` タグで包まれるんでしょと思ったあなたは正常です。 coqdoc は `p` タグを使いません。

```html
<div class="doc">
最初の段落。

<div class="paragraph"> </div>

次の段落。
</div>
```

このような HTML が生成されます。意味不明です。 `div` はブロック要素のはずです。気力を削がれながらもデフォルトの CSS を確認しました。

```css
.paragraph {
    height: 0.75em;
}
```

このように高さが指定されていました。つまり、段落と段落の間のスペースを `div` 要素で表現しているのです。段落の間の隙間のために `br` 要素を使う人がいるのは知っていましたが、こんな世界があったとは驚きです。私は無知でした。

## 些細な他の問題

ソースコードを表現するためには `pre` 要素を使うのが普通だと思いますが、大量の `br` 要素を使っていました。

coqdoc では `The dog is [foo baa].` という風にドキュメントの中にインラインでコードを埋め込むことが出来ます。これが `The dog is <span class="inlinecode">foo</span> <span class="inlinecode">baa</span>.` と変換されます。空白が `span` タグに包まれていません。 `span.inlinecode` という風に指定して文字サイズを大きくしようとしても、空白だけが大きくなりません。

HTML の中に余計なスペースがたくさんあります。元々のテキストの中に HTML のタグなどを差し込むという処理を基本としていると伺えます。

`body` 要素の直下に `div id="page"` 要素だけがあり、その中に他の全ての要素が入っている構造になっています。フラットにすれば良いのではと疑問に思いました。

ドキュメントの塊がドキュメントの構造と一致しないのは、コード部とドキュメント部が交互に切り替わる構造になっていたのが原因でした。これは一貫した設計であり理解できます。しかし、この条件下でのドキュメント部は一塊として見れないものだと感じます。

私が見ていた HTML の中では `h1` 要素が二回現れていましたが、これは Markdown の `# foo` と同じことであり、ユーザー側が `h1` 要素に変換される構文を使わないことで回避可能でした。

`div id="header` と `div id="main"` と `div id="footer"` 要素でページ全体を三つに区切っていました。これは今ならそのものずばり `header` と `main` と `footer` 要素があります。使うべきというようなものではありませんが。

## ショックを乗り越えて

何とか新しい CSS を仕上げました。その成果は[ここ](https://hexirp.gitlab.io/googology-in-coq/GiC.Base.html)で見ることが出来ます。デザインに関しては素人なので、まだまだ悪い所があるはずなのですが、私自身がきちんと見れるところまで完成させられたので、ひとまずは満足しました。

ちなみに、 GitLab Pages を初めて使ったんですが、 CI の中でファイルを吐き出せば自動的に引っ張り上げてくれるようになっていて、リポジトリの中に生成物を置く必要がある GitHub Pages と比較して設計の筋がとても良かったです。最初はリポジトリをホストするだけだった GitHub と、最初から周辺のツールまでまとめて扱うことが目標だった GitLab の違いが表れていると思うと、面白いです。

## ライセンス

この記事のライセンスは [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/legalcode) とします。