OmniAICreator/Qiita-1.07M huggingface dataset:
sharp-cliを使ってjpg/pngのWebP変換を自動化する

#WebPへの変換めんどくさい
jpg/pngをWebPに変換したい。PhotoshopでWebPを扱うためのプラグインはあるけど、画像を追加・編集するたびに変換するのは面倒だし、サクッと自動変換できないかな。

#npm-scriptsで自動化したい
普段の実装はnpm-scriptsをタスクランナーとして使っているので、npm-scriptsでやる方法を考えてみました。

#必要なもの
- WebPへの変換：sharp-cli(https://www.npmjs.com/package/sharp-cli)
- ファイルの変更監視：onchange(https://www.npmjs.com/package/onchange)

それぞれnpm installしておきます。

#sharp-cliでWebPへ変換する
~~~console
sharp -i './path/to/image.jpg' -f webp -o {dir}
~~~
`-i` で変換するファイルを指定します。今回はonchangeで追加・変更されたファイルを指定しますが（後述）、一度に変更する場合はglobパターンで`'./images/**/*.jpg'`のように書くことも可能です。
`-f` でフォーマットを指定。（今回はWebPにしたいので、webpを指定します。）
`-o` でアウトプット先を指定します。この時、`{dir}`と書くと、変換元のファイルと同じディレクトリ内に保存することができます。

これで、jpgやpngなどの画像をWebPに変換するコマンドができました。

#onchangeで画像の追加や変更を監視する
これだけでも便利ですが、実際のコーディング作業時には画像を随時追加したり、変更したりすることがあると思います。そんな時毎回コマンドを叩くのは手間なので、画像ディレクトリを監視して、新しいファイルが追加されたり、ファイルが変更されたりしたときに自動的にそのファイルをWebPに変換するようにしてみます。
ファイルの監視には、onchangeを使用します。

##onchangeの使い方
~~~sh
onchange ＜ファイル名＞ -- ＜コマンド＞
~~~
ファイル名の後にハイフンをふたつ繋げて、実行したいコマンドを書きます。
ファイル名の部分はglobパターンで記述することが可能で、複数指定することができます。jpgとpngを指定したい場合は`\".path/to/**/*.jpg\" \"./path/to/**/*.png\"`と指定します。（Mac/Win両方に対応するため、`"`はバックスラッシュでエスケープしておきます）
デフォルトでは指定したファイルに対する変更を全て検知しますが、`-f`オプションで特定のイベントのみに絞り込むことができます。今回は追加と変更に対応したいので、`-f add -f change`と指定します。
追加・変更を検知したファイルは、`{{file}}`を使ってコマンド内で呼び出すことができます。この機能を使って、追加・変更されたファイルをsharpで指定し、変換します。

~~~console
onchange -f add -f change \"./path/to/**/*.jpg\" \"./path/to/**/*.png\" -- sharp -i {{file}}  -f webp -o {dir}
~~~


#package.jsonにコマンドを書き込む
package.jsonのscriptsの部分に、下記を追加します。あとは`npm start`と叩くとファイルの追加・変更の監視が始まります。監視を止める時は`ctrl + c`で。

~~~json
  "scripts": {
    "start": "npm run watch:image",
    "watch:image": "onchange -f add -f change \"./path/to/**/*.jpg\" \"./path/to/**/*.png\" -- sharp -i {{file}}  -f webp -o {dir}"
  }
~~~
【Terminal】ターミナルの起動と終了

#はじめに
今回は、ターミナル操作をするために、ターミナルの起動方法や終了方法、操作をする上で便利な設定を紹介します。

#起動
まず、Launchpadを開きます。

![ScreenShot 2021-07-04 14.40.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/5e7b380c-160f-dd22-266a-5e6ef78e62d7.png)

Launchpadのその他を選択します。

![ScreenShot 2021-07-04 14.41.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/0ac32046-ca5d-f158-4683-9d4665dc2e04.png)

中にターミナルがあるので、選択すると、ターミナルが開きます。

![ScreenShot 2021-07-04 14.41.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/28a62737-7ee8-7dd0-36ea-435f2f95915a.png)

これは少し面倒なので、デスクトップにターミナルを置くか、Dockに固定するか、もしくは以下のようにcommand(⌘)+スベースキーでSpotlightを開き、ターミナルを選択することもできます。
![ScreenShot 2021-07-04 14.44.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/13245c8d-8308-1679-870d-cc2543b2af0a.png)

![ScreenShot 2021-07-04 14.46.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/39888295-cf1e-fb63-3313-cc5c5ad6ab2e.png)

複数起動したい時もあります。そんな時は、command+Nかcommand+Tで複数開くことができます。
![ScreenShot 2021-07-04 14.49.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/c40e7dbf-5dd2-0c13-c685-8b0eaf058340.png)

command+Nの場合
新しくウィンドウが開きます。
![ScreenShot 2021-07-04 14.51.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/7bd70b78-9b1a-245f-a4df-7fa2e6288900.png)

command+Tの場合
同じウィンドウにタブが追加されます。(zshは今は気にしないでください)
![ScreenShot 2021-07-04 14.51.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/f8787ebe-46df-aa31-58cb-c421a36dbfad.png)

#終了
ターミナルを終了させたい時は、左上の赤いボタンを押すか、command+Wのショートカットでシェルも同時に終了します。
![ScreenShot 2021-07-04 14.53.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/10a2cabe-6dfe-7c78-6c5e-59f92719c130.png)

#おわりに
おわりです。
【Python】WebスクレイピングでSeleniumを検討する前に

#初めに

スクレイピングのサイトみていると

「URLが変わらないページはSeleniumを使いましょう」

と書いてあるけど、なんとなくSeleniumってダサいよね。


っていうBeautifulSoupユーザーの為の記事。


#導入
今回は競馬ネットというサイトから競馬レースのデータをスクレイピングすることを考えます。

競馬ネット：https://www.netkeiba.com/

サイトの仕様ですが、下図のようにレース詳細検索画面で検索条件を指定すると20件ずつレースが抽出されるというものになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513378/126e6519-28fa-89f8-6696-f2a20c78e7fd.png)

扨、検索結果画面の方ですが20件ずつしか表示されない為、次の20件を取得する為には当然画面下の「次」ボタンで画面遷移する必要があります。

しかし、検索結果のURLは何ページ目だろうと "https://db.netkeiba.com/" であり、requestsでHTMLソースを取得→BeautifulSoupで解析の王道パターンが一見使えないように思えます。

そうなってくるとSeleniumの使用を検討すると思うのですが、前述の通りSeleniumってなんとなくダサい気がしています(私だけ？)。

ということでrequestsを使ってどうにかこのサイトからレースデータを取得できないか検討してみます。


#ネットワークを確認する
上記のサイトについてURLは変わっていなくとも、画面にレース一覧を表示している以上、何かしらの通信を行ってサーバーからレース情報を取得しているはずです。この通信を探します。

まずブラウザのデベロッパー画面を開きます。ChromeならF12キーを押すと開きます。
そして上部のリボンからネットワークを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513378/866a3123-f209-c3d1-b7fd-2c1077a6e891.png)

この状態で先程の検索結果画面を開くと、何やら怪しげな行が次々追加されていきます。
結論言うとこれらがページを開くために行われた全通信であり、この中にレース一覧データが隠されているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513378/0c0be993-5d64-a09b-01b5-b69138ab8aab.png)


てことで、一行一行のレスポンスを確認しながらそれっぽいものを探します。
今回は1行目がレース情報のソースを受け取っているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513378/6632a982-f6f2-5234-63c9-2c32ed0c81cf.png)


つまりrequestsでこの通信を再現してあげることで、データを取得できそうです。


#実装する
コーディングする前に先程見つけた通信を詳しく調べる為、Headersタブを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513378/21917d00-ed69-1950-cadc-c7fe2fa681d2.png)


色々な項目がありますが、とりあえず今回はGeneralとForm Dataだけ見ればよいです。

Headers画面を見ていると以下のことがわかります。

- リクエスト先のURL：https://db.netkeiba.com/
- リクエスト方法：POST
- 検索条件：Form Dataの通り

Form Data部分を見るとなんとなくわかると思いますが、ここでページの表示内容を制御しています。
例えば"pid:race_list"は「レース情報を開く」ことをあらわすパラメータです。その下は設定した検索条件がつらつらと並んでいます。
ページを遷移してもURLが変わらないのは、表示内容をForm Data部分で制御していたからなのです。

纏めるとForm Dataに条件を指定し"https://db.netkeiba.com/" にPOST通信することで、欲しいレスポンスが得られるということです。

ということで、満を持してコーディングします。
とても単純で、requestsのparam引数に必要なForm Dataを設定してあげるだけです。

```python
import requests
from bs4 import BeautifulSoup

#リクエスト先
url = "https://db.netkeiba.com/"

form_data = {"pid":"race_list",
             "track[]": 1,
             "jyo[]": "05",
             "sort":"date",
             "list" : 20,
             "page": 1
             }

#param引数にForm Dataを与えてpost通信
response = requests.post(url, params = form_data)

#BeautifulSoupで解析するだけ
soup = BeautifulSoup(response.content)

```

因みにデベロッパー画面にはありませんが、Form Dataの"page"パラメータを指定することで、検索結果の何ページ目の情報を取得することができます。

#終わりに
ログインを必要とするサイトからのスクレイピングでも応用できます。
目指せ脱Selenium。
PHPのlaravelで画面から簡単に変数の値を見る方法

PHPのlaravelで変数の値を見る簡単な方法があります。
Laravelで変数の値を見てデバッグする場合、

- `php artisan psysh-console`や
- Log出力をする

などあります。
たとえば、Log出力して変数の値を見る場合

```php
use Illuminate\Support\Facades\Log;
Log::info($books);//知りたい変数名 を入れる
// 出力場所は storage/logs/laravel.log 
```
とします。

もっと簡単に画面から手軽に見たい場合は以下のようにすると良いです。

```php
throw new \Exception($books);//知りたい変数名 を入れる
//または、var_dump($books);
```

こうすると画面から見たときにエラーの画面になり、変数に何が入っているのかがわかります。
例：

```php
  public function index()
  {
      // DBよりBookテーブルの値を全て取得
      $books = Book::all();
	  throw new \Exception($books);

      // 取得した値をビュー「book/index」に渡す
      return view('book/index', compact('books'));
  }
```
画面から該当ページにアクセスすると、以下のように知りたい変数の値を見ることができます。
![スクリーンショット 2021-07-04 17.45.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610591/591952ac-4f5e-36e5-09cd-2a92703355ed.png)
python 3Dグラフ　平面図形の描画

matplotlib に平面図形をプロットする例


#実行サンプル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423803/2b03414c-c1d4-6a66-c49c-dd317c1e0c6b.png)


#実行環境
python3.7
windows10

#実行手順
windowsコマンドラインから実行

# ソースコード

```
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, PathPatch
from matplotlib.text import TextPath
from matplotlib.transforms import Affine2D
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.patches import Rectangle


fig = plt.figure()
ax = fig.add_subplot(projection='3d')

# Draw a circle on the x=0 'wall'
#p = Circle((5, 5), 3)

#-----------------
# 原点配置
#pLeftRight = Rectangle(xy=(0, 0), width=1, height=3 ,facecolor='magenta',edgecolor='magenta',alpha=0.5)
#ax.add_patch(pLeftRight)
#art3d.pathpatch_2d_to_3d(pLeftRight, z=0, zdir="x")
#
#pFrontBack = Rectangle(xy=(0, 0), width=5, height=2 ,facecolor='yellow', edgecolor='yellow',alpha=0.5)
#ax.add_patch(pFrontBack)
#art3d.pathpatch_2d_to_3d(pFrontBack, z=0, zdir="y")
#
#pTopBottom = Rectangle(xy=(0, 0), width=8.5, height=3.5 ,facecolor='cyan',edgecolor='cyan',alpha=0.5)
#ax.add_patch(pTopBottom)
#art3d.pathpatch_2d_to_3d(pTopBottom, z=0, zdir="z")


#----------------
# オフセット配置
# zdir="x" の場合, オフセット座標→Rectangle(xy=(Y軸, Z軸) pathpatch_2d_to_3d(z=X軸)
pLeftRight = Rectangle(xy=(9, 1), width=1, height=3 ,facecolor='red',edgecolor='red',alpha=0.5)
ax.add_patch(pLeftRight)
art3d.pathpatch_2d_to_3d(pLeftRight, z=3, zdir="x")

# zdir="y" の場合, オフセット座標→Rectangle(xy=(X軸, Z軸) pathpatch_2d_to_3d(z=Y軸)
pFrontBack = Rectangle(xy=(1, 5), width=5, height=2 ,facecolor='green',edgecolor='green',alpha=0.5)
ax.add_patch(pFrontBack)
art3d.pathpatch_2d_to_3d(pFrontBack, z=3, zdir="y")

# zdir="y" の場合, オフセット座標→Rectangle(xy=(X軸, Y軸) pathpatch_2d_to_3d(z=Z軸)
pTopBottom = Rectangle(xy=(3.1 , 6.1), width=7.5, height=3.5 ,facecolor='blue',edgecolor='blue',alpha=0.5)
ax.add_patch(pTopBottom)
art3d.pathpatch_2d_to_3d(pTopBottom, z=9, zdir="z")


ax.set_xlim(0, 10)
ax.set_ylim(0, 10)
ax.set_zlim(0, 10)

ax.set_xlabel("X-axis")
ax.set_ylabel("Y-axis")
ax.set_zlabel("Z-axis")

plt.show()

```

# メモ
使っているライブラリ、関数など
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.patches import Rectangle
art3d.pathpatch_2d_to_3d

# 参考資料
参考にしたサイトは以下。

参考URL：matplotlib公式サイト　pathpatch_2d_to_3dの使い方
https://matplotlib.org/stable/gallery/mplot3d/pathpatch3d.html#sphx-glr-gallery-mplot3d-pathpatch3d-py

参考URL：3D空間に直方体作成 pathpatch_2d_to_3dのRectangleの使い方
https://sabopy.com/py/matplotlib-3d-43/
【Terminal】ターミナルの基本用語

#はじめに
今回は、ターミナルやコマンドラインを学習する上で、必要な知識をまとめます。

#コマンド
コンピュータに命令するための文字(lsやcdなど)のこと。
このコマンドを入力する場所をコマンドラインという。

#ターミナル
コマンド入力に使うmacOS標準搭載のアプリ。

#プロンプト
以下の例だと、`oonishireon@M1-MacBook-Pro ~ %`のところをプロンプトという。
![ScreenShot 2021-07-04 13.17.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/549f7dd0-9d16-41a3-a268-d08053b44a0c.png)

#カーソル
%以降の実際にコマンドを入力するところをカーソルという。
(touchとはファイルを作るコマンドですが、コマンドの詳細は今回はあまり紹介しません。)
![ScreenShot 2021-07-04 13.22.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/46b744ca-8fdf-8ce0-65bf-39075714642b.png)

#シェル
ターミナルはシェルを使うための画面です。シェルは、ユーザーからコマンド（文字）入力を受け取り、OSの機能を呼び出してその結果をターミナルに表示します。つまり、ターミナル画面の入力と出力は必ずシェルを通して行われています。

#OS
コンピュータはCPU、メモリ、入出力装置などのハードウェアの組み合わせでできており、これらの制御を行っているのがOS（オペレーティングシステム）です。OSがあることで、さまざまなアプリケーションを実行できる環境が整っています。
macのOSはmacOSというOSになっています。他にも、WindowsやUNIX（Linux）といったOSがあります。

#カーネル
OSの中心部分で、OSの核です。ハードウェアのアクセス、プロセスの管理などを行なっている。
macOSのカーネルはMach（マーク）です。

#Darwin
Darwinとは、
2000年にAppleがリリースしたUnix系のOSS（オープンソースソフトウェア）です。これに、さまざまなソフトウェアや変更を加えたOSがmacOSで、macOSのベースになっています。

ターミナルで確認してみましょう。
![ScreenShot 2021-07-04 14.19.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/ccaaf2c1-f4b1-fc30-b6a2-1bb89d0fb3b8.png)
ターミナルで`uname`と打ち、エンターキーを押すと`Darwin`と出力されます。


#おわりに
随時更新予定です。
標準入力で文字と数値を入力して数値を取り出したい。【備忘録】

#文字と数値の入力は分けるのが当たり前？
```
name = gets.chomp
age = gets.to_i
```
のように、文字列と数値で分けて書く基本を最初の方に学びましたが、頭を悩ませる問題と出会いました。
まだ、解くための技術や知識、プログラミングとしての語彙が少ない自分には難しいです。


# 問題
n人の名前と年齢が　Qiita 30 のように名前と年齢の間には半角空白が入力される。
名前と年齢に１を加えた数値を　Qiita 31のように出力してください。

# 考えた事
・n人の不特定多数の要素があるので、n回入力（n.times)は使う
・文字列と数値が同じ変数に入っているので、取り除く（name.gsub(/[^0~9]/."")
・取り除いたものに　＋１　をする。

#　結果
n.times　の部分と取り除いたものに+1をするは合っていたが、エラー頻出するばかりで解けたものじゃありませんでした。
以下答え

```
n = gets.to_i  #n人の入力

name_age = Array.new(n) #配列Arrayを生成して、n個入力
n.times { |i| name_age[i] = gets.split(' ')} 
#ここで、入力された文字と数値は配列の中で分けられる。
#例）|1| name_age|1| = ['Qiita' ’３０']

name_age.each do |person|
  name = person[0] #０番目に名前が格納されているので変数nameに代入
　　　　age  = person[1].to_i #1番目に年齢が格納されているので変数ageに代入
                  #^~~~~標準入力されているので、数値に変換
puts name + ' ' + (age +1 ).to_s #数値に変換したageを文字に再変換して出力
end 
```

# 今回の学び
配列名　= Array.new　で変数を作成できる
配列に入力された文字に空白がある事で、gets.split(' ')で文字列を分けることができる
分けた文字列を変数に入れ直して.to_iで数値に変換、またto_sで文字に変換できる

ほとんどわかっていない状態でよくこの問題に取り組もうとしたものです。
読書と同じく、意味のわからない所はきちんと調べてまとめていく事で、自分の血肉にしていきたいです。
もし間違い等ありましたらコメントお願いします。
kivyMDチュートリアル其の弍什肆 Components - Progress Bar篇

おはこんばんは。いかがお過ごしでしょうか。
いつの間にか梅雨入りしていることが最近分かったのですが、影響もあり体の方も絶不調な
投稿者であります。なんかこれ投稿しているときにずっと体調よくないとか言ってる気も・・・
みなさんも、体調にはお気をつけくださいませ(おせっかいがすぎる)。

最近、Flutterの方を触っているとFirebaseというSaasでもない、かといってPaasでも
ないmBaasというサービスがよく目に入るようになりました。Qiitaでもよく記事にされて
いるのを見かけたりしますよね。なんか調べると認証やDBなど肩代わりしてもらうとあるでは
ないですか。

https://ja.wikipedia.org/wiki/Firebase

これは対抗製品と謳っているKivyMDでも目が離せないですね。少し触っただけですが、結構
触れやすいこともあり、気が向けば記事にしようかなと考えている次第であります。乞うご期待
のほどを。

こういうのがあるとありがたいですね。ただただ、リストを表示しただけのアプリよりかは
こういう実戦形式のアプリを作ったほうがやりがいがありますし、色々学べることもありで。
まぁ、でもまずはこちらのComponentsを片付けて合間を見てアプリを作るかしないと何も
始まりません。

ちょっと前置きも長くなってきたので、さっそく今週も始めていきましょう。
今日はProgress Bar篇になります。

## Progress Bar

恒例行事ですが、リンクの方は飛ばします。

こちらのコンポーネントはスマホアプリを触っていると、見たことがないという方の方が
少ないように思えるくらいです。タスクの進捗バーだったり、ちょっと待てよ(誰かのモノ
マネ風に)という意味合いの円形の動くアイコンのようなものだったり様々あります。

マニュアルの方でも以下の3つ用意しているよという記載がありますね。

* MDProgressBar
* Determinate
* Indeterminate

残念ながら今日は、動かない関係でMDProgressBarしかお見せできませんが、さっそく
実物を見てみることとします。まずはコードから。

### MDProgressBar

```python:xxiv/progressbar.py
from kivy.lang import Builder

from kivymd.app import MDApp

KV = '''
BoxLayout:
    padding: "10dp"

    MDProgressBar:
        #orientation: "vertical"
        #color: app.theme_cls.accent_color
        value: 50
'''


class Test(MDApp):
    def build(self):
        return Builder.load_string(KV)


Test().run()

```

これも申し訳ありませんが、コードは以上になります・・
Barを自動で変更することはできるかなとか結構調査をしていたのですが、なかなか上手く
いかずで・・結果、時間切れとなってしまいました。
\# 誰か知っている方がいればコメントください！

今日に関しては過去1番可読性・視認性が優れているといっても過言ではないくらい、触れる
までもないくらいですが一応触れておきます。

```python
MDProgressBar:
    #orientation: "vertical"
    #color: app.theme_cls.accent_color
    value: 50
```

コメントアウトしたものは「Vertical orientation」と「With custom color」を
それぞれ実装したものになります。このままだとどちらも有効化してないんですけどね。
ごくごく簡単。なにも変更なければvalueプロパティを指定するのみです。

## 結果

はい、さくっと結果に移りますがどうなったかを見てみましょう。
\# といってもなんの変哲もありませんが

![116.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/fa494911-03cb-dba2-8329-b64dafb936b1.png)

んー、つまらない・・
ただただ実行したのみになります。まぁ動いていることは確かですが。

![117.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/b5aab29b-9c35-7140-c3ee-d58bade1e26e.png)

ちなみにコメントアウトを外して実行したものが上のキャプチャになります。
これも問題なさそうですね。

## まとめ

はい、後の方は動かないので今日はここまでとなります。
動的なものも試してみたかったのですが、今後の期待ということで。
Changelogに改善したという文言がなかったので、バージョンを上げたとしても改善されない
かもしれませんが・・

ということでこのままではあまり使用用途がないかもしれませんが、もし全ての機能が使える
ようになったらアプリの幅や豊かさが上がるのは間違いありません。現状では、少し首を長く
して待っていましょう。

来週の予定では前回飛ばしていたRefreshLayout篇をやることにします。味気がない結果と
なりましたが、勝手ながら今日はここまでとします。

それでは、ごきげんよう。

## 参照

> Components » Progress Bar
> https://kivymd.readthedocs.io/en/latest/components/progress-bar/

> Wikipedia - Firebase
> https://ja.wikipedia.org/wiki/Firebase
python機械学習

### 目的
機械学習の勉強を始めるにあたり学んだことをアウトプットとして記事にするのを目的とする
ゴールがないとダレてしまうのでデータ分析試験とG検定受験を目標に掲げてまずは頑張ることとする

- データ分析試験
https://www.pythonic-exam.com/exam/analyist

- G検定
https://www.jdla.org/certificate/general/

###微分
微分とは接線の傾きをもとめることである
微分して求まった関数を`導関数`と呼び、その導関数に入れる値のことを`微分係数`と呼ぶ

`微分係数`を入れたあとに実際の求めたい値が得られることとなる

具体的には導関数は以下の式で表される

$$
f’(x) = \lim_{h \to 0} \frac{f(x+h)-f(x)}{h}
$$

これに例えば$1$の微分係数を入れると

$$
\begin{eqnarray}
f’(1) &=& \lim_{h \to 0} \frac{f(1)-f(1)}{h} \\
      &=& \lim_{h \to 0} \frac{0}{h} \\
      &=& \lim_{h \to 0} 0 \\
\end{eqnarray}
$$

>$f’(1)=0$

$x$の微分係数を入れると

$$
\begin{eqnarray}
f’(x) &=& \lim_{h \to 0} \frac{f(x+h)-f(x)}{h} \\
      &=& \lim_{h \to 0} \frac{f(x+h-x)}{h} \\
      &=& \lim_{h \to 0} \frac{h}{h} \\
      &=& \lim_{h \to 0} 1 \\
\end{eqnarray}
$$

>$f’(x)=1$


$x^2$の微分係数を入れると

$$
\begin{eqnarray}
f’(x)^2 &=& \lim_{h \to 0} \frac{f(x+h)^2-f(x)^2}{h} \\
      &=& \lim_{h \to 0} \frac{f(x^2+2xh+h^2-x^2)}{h} \\
      &=& \lim_{h \to 0} \frac{2xh+h^2}{h} \\
      &=& \lim_{h \to 0} 2x+h \\
\end{eqnarray}
$$

>$h→0$より$h=0$を代入し
>$f’(x)^2=2x$

- よくある間違いとして$x$に$x^2$を代入しようとして$f(x^2+h)$となってしまうことがある。
- $x$に$x^2$を代入するのではなく$(x+h)$に$x^2$を代入するので$(x+h)^2$というように全体を2乗する必要があることに注意

なぜこのような間違いが多いかというとおそらくだが分子の$f(x+h)-f(x)$という式がそもそも`yの増加量`を表していたということがピンときていないためだと思う。
仮に微分係数を2とした場合は2→2まで増加する(＝yの増加量は0という意味)ので導関数の式の分子は必ず0になることから`x軸がいくら増えようがyは0`なのである
この時グラフを思い描くと`傾きは0`になると考えると理解しやすいと思われる

上記をまとめると次の公式が得られる
以後微分はこの公式を使っていく

| 微分係数 | 導関数 |
|:-:|:-:|
|1 | 0  |
|$x$|  1 |
|$x^2$| $2x$ |
|$x^n$| $nx^{n-x}$ |
|$\log x$|$$\frac{1}{x}$$|
GASでGoogleドキュメントのアジェンダを作成

# きっかけ
私の勤務先の会社ではアジェンダにGoogleドキュメントを使用しております。
その際にGoogleドキュメントに**上部に追記する形**でアジェンダを残しています。
Googleドキュメントを新たに作成するのは見かけたが追記するパターンは見かけなかったので実装してみました。

# 目的
現状だと都度アジェンダとなるテンプレートを手動でコピーして行っているので、この手動作業をなくすことを目的としています。また、なるべく時間をかけずに実装することを目的とします。なので多少のレイアウト崩れ等は目をつぶります。

# 方法検討
パターン①GASにテンプレートとなる文章を埋め込む
　→ テンプレートの内容が変わった際に修正が大変そう。
パターン②元となるドキュメントにテンプレートを用意しておく
　→ GASでのドキュメント操作が大変そう
パターン③テンプレートを別ドキュメントに用意しておく
　→ 新規ファイルを作成する方法を見かけるので容易にできそう

ということで今回は③で実装してみます

# 準備

## テンプレートファイルの準備
内容はなんでもOK

![朝会.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142542/7733aa70-0bf0-0cf1-8f65-88dacfb40456.png)

## アジェンダを追記するファイルを準備

![アジェンダ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142542/a3af9894-23a7-6c0d-4de8-be390c23911a.png)

# 実装

## テンプレートからドキュメントにコピーする
以降のコードはアジェンダを追記するドキュメントのGASに記載してください

```　
/*
 * コピー
 */
function insertTaskAssignmentAgenda() {
  // テンプレートから内容を取得(https://docs.google.com/document/d/xxxxxxxxxxxxxxxxxxxxxxxxxxxx/edit)
  const fileId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  const templateDocument = DocumentApp.openById(fileId);
  
  // 挿入する行番号
  let insertRowNumber = 1;
  let document = DocumentApp.getActiveDocument();

  // テンプレートからコピー
  templateDocument.getBody().getParagraphs().forEach(paragraph => {
    let para = paragraph.copy();
    if (insertRowNumber == 1) {
      // 日時を置換
      const title = para.getText().replace("{date}", getDate(0));
      document.insertParagraph(insertRowNumber++, title).setAttributes(para.getAttributes()).setFontSize(13).setBold(true);
    } else if (para.getType() === DocumentApp.ElementType.LIST_ITEM) {
      document.insertListItem(insertRowNumber++, para.getText()).setGlyphType(DocumentApp.GlyphType.BULLET).setAttributes(para.getAttributes());
    } else {
      document.insertParagraph(insertRowNumber++, para.getText()).setAttributes(para.getAttributes());
    }
  });
  
  // 区切り線
  document.insertHorizontalRule(insertRowNumber++);
}

/*
 * 日時
 */
function getDate(addDays = 1) {
  const now = new Date();
  now.setDate(now.getDate() + addDays);  
  return Utilities.formatDate(now, 'Asia/Tokyo', 'YYYY-MM-dd');
}
```

## メニューに登録
```　:アジェンダを追記するドキュメントのGASに記載する
function onOpen() {
  let ui = DocumentApp.getUi();
  let menu = ui.createMenu('アジェンダ');
  menu.addItem('朝会', 'insertMorningMeetingAgenda');
  // アジェンダの数だけメニューに登録
  menu.addItem('XXXXX', 'XXXXXXXXXXXXXXXX');
  menu.addToUi();
}
```

## 問題点

下記のように実行するとなぜか以下の現状が起こったり起こらなかったりする

- リンクは貼られているが書式が反映されない
- 箇条書きの書式が違う

![結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142542/f4a42ef6-4c61-f61a-dceb-9df5f2e6dde7.png)

## 自動作成について
このままでもよいが必要に応じてトリガーを設定すれば全自動で作成するようにできます

# まとめ
これでアジェンダを手動でコピーする手間がなくなりました
#.ipynbファイルを.pyに変換 (Docker,JupyterLab)

Dockerコンテナ内で動かしている`.ipynb`ファイルを`.py`ファイルに変換する方法を備忘録として記しておきます。

1つのコードで簡単に行えます。

変換したい`.ipynb`ファイルの最後に以下のコードを書いて実行 (`Shift` + `Enter`) するだけで完了です。

```python:*.ipynb
import subprocess
subprocess.run(['jupyter', 'nbconvert', '--to', 'python', '[ipynbファイルがあるディレクトリパスを入力]/*.ipynb'])
```

`'python'`という箇所がファイル拡張子の定義場所となっています。
(`'Script'`に変更すると、`.txt`形式になります)

上のコードを実行することにより、変換された`.py`ファイルが同一ディレクトリ上に新規作成されます。
同一ディレクトリ上にある全ての`.ipynb`ファイルが変換されるため、特定の1つのみを.pyファイルに変換したい場合は、ファイル名を指定することにより可能となります。
(`*.ipynb`の箇所を存在するファイル名に変更)
出力されない場合は、パスに誤りがある可能性があるため、ログなどを再度確認してみてください。
VirtualBoxにCentOS環境を構築する

#環境構築
１．Virtualboxを立ち上げて、[新規]を押す。
２．名前・タイプ・バージョンを以下のように設定。

|       |                      |
|:-:|:-:|
|  名前  | CentOS7 （任意の名前)|![最終起動.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1725946/dd22d786-096f-11ef-d39d-e832b50a2cbd.png)![最終起動.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1725946/67243170-af9c-2fad-1280-9bcec010b1c4.png)


|  タイプ|   Linux  |
|  バージョン |  Red Hat(64-bit) |

３．以降を以下のように設定して作成

|  |  |
|:-:|:-:|
| メモリサイズ   |  1024MB |
| ハードディスク  | 仮想ハードディスクを作成する  |
| ハードディスクのファイルタイプ  |  VDI（Virtual Disk Image） |
|  物理ハードディスクにあるストレージ |  可変サイズ |
| ファイルの場所とサイズ  |  16.00GB  |

４．作成完了したら緑の右矢印の軌道をクリック。
右側のファイルのアイコンをクリックして追加を選択。
インストールしたisoファイルを選択し起動をクリック。
![iso..png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1725946/7ed7274e-5ace-ceaa-6aab-5eba36a9843f.png)
５．以下の写真のようにinstall　CentOS7を選択
![CentOS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1725946/4bec8568-71a1-c792-fa92-ff88cf774f43.png)
６．日本語を選択して続行をクリック
![select2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1725946/eccb5f9e-c1f8-36db-cbdb-93d0471f85ff.png)

７．各種設定を行っていきます。

| 設定箇所 | 設定 |
|:-:|:-:|
| ソフトウェアの選択   | サーバー（GUI使用）を選択し完了をクリック　|　
| インストール先  | 特になにもせず完了をクリック |
| ネットワークとホスト名  |  右上のオフをオンに変更し完了をクリック|
上記の三か所を設定したら右下のインストールの開始をクリック

８．rootパスワードとユーザーの作成

- ROOTパスワード

|  |  |
|:-:|:-:|
| rootパスワード  | 好きなパスワードを設定し完了をクリック<br>（決して忘れないようにすること）　|　
| 確認  | 確認のため同じものを入力　|　

- ユーザーの作成

|  |  |
|:-:|:-:|
| フルネーム  | （例）Osake Daisuki　|　
| ユーザー名  | （例）Drinker　|　
| パスワード  | Drinkerのパスワード　|　
| パスワードの確認 | 確認のため同じものを入力　|　

ROOTパスワード・ユーザーの作成が完了したら再起動をクリック

９．ライセンスに同意と設定の完了

- イセンスに同意をクリックして左下のチェックマークにチェックを入れ完了をクリック
- 右下の設定の完了をクリック
- 日本語を選択
- 再度日本語を選択
- プライバシーについてはお好きなものを選択

今回初めての場合はいかのようなものが現れる
気になる方はよく見ておきましょう。
![firsttime.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1725946/66b113ba-8617-8505-6e7c-66d8d8d5a217.png)

![fine.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1725946/c4699cd0-b0af-2169-39e1-66102855ca5d.png)

上記のような画面になれば環境構築は終了になります。
お疲れさまでした。

###あとがき
今回初めて記事の執筆を行いました。
至らない点などあるかと思いますがご容赦ください。
Heroku環境でReactアプリのビルドに失敗する(Node version not specified in package.json)原因はNodeのバージョン違いでした

## 内容
Reactアプリのビルドがローカル環境では成功するのにHeroku環境で失敗する事象に出会った。
その原因と解決法についての記事です。
手掛かり→```Node version not specified in package.json```

## 開発環境

|対象      |バージョン  |
|:--------|--------:|
| Node.js | v15.8.0 |
| npm     | 7.18.1  |

## 概要

React アプリを作成し、Heroku にデプロイした。  
当初はビルドに成功していたが、改修を行っていたところビルドに失敗するようになった。
ローカル環境ではビルドに成功しており、Herokuでのみ失敗している。

エラー文は↓

```bash:エラー文
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! app-name@0.1.0 build: `react-scripts build`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the app-name@0.1.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR!     /tmp/npmcache.VWw0a/_logs/2021-06-29T14_37_39_318Z-debug.log
-----> Build failed
       
       We're sorry this build is failing! You can troubleshoot common issues here:
       https://devcenter.heroku.com/articles/troubleshooting-node-deploys
       
       Some possible problems:
       
       - Node version not specified in package.json
         https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version
       
       Love,
       Heroku
       
 !     Push rejected, failed to compile Node.js app.
 !     Push failed

```

## 原因

原因はNodeとnpmのバージョンがpackage.jsonに記述されていないことだった。


エラー文の```- Node version not specified in package.json```に注目すると、「Nodeのバージョンがpackage.jsonで特定されていない」ことがエラーの原因ではないかと推測されている。

package.jsonを見ると確かにNodeのバージョンについての記述がない……。  

ローカル環境のNode、npmのバージョンを確認すると以下の通り。

```
$ node -v
v15.8.0
$ npm -v
7.18.1
```

Heroku側でのバージョンを確認するためにビルドのログを確認すると以下の通り。

```
remote:        Resolving node version 14.x...
remote:        Downloading and installing node 14.17.1...
remote:        Using default npm version: 6.14.13
```

となっており、ビルドに使用するnodeとnpmのバージョンがローカルとHerokuでは違っていることがわかる。
おそらくこれが原因だろうと目星をつけた。

## 解決
[Heroku Node.js Support | Heroku Dev Center](https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version)を参考にして、解決のために、package.jsonに以下の記述を追加する。

```json:package.json
{
  ...
  "engines": {
    "node": "15.x",
    "npm": "7.x"
  },
  ...
}
```


Herokuに変更を反映して再度ビルドを行うと、成功した。  

今回の事象では、ローカル環境では正常に動く一方Herokuでは動かない状況だったため、環境の違いが原因ではないかと推測ができた。
ただし最初はビルドに成功していて、改修を行ったタイミングで失敗するようになった原因はわからない。

今回は勉強のための制作だったため被害は出なかったが、これが稼働中のサービスだったり業務で請負ったものだったりと思うと恐ろしいですね。

#### 教訓：環境ごとにバージョンが違うとえらいことになるので、バージョン管理は明確にするべき。

## 参考文献
[Node.js のデプロイのトラブルシューティング | Heroku Dev Center](https://devcenter.heroku.com/ja/articles/troubleshooting-node-deploys)
RubyよりPHPの方が初心者に優しかった

RubyとPHPはどちらも簡単でWebアプリを作りやすい言語というイメージがありますが、**初心者から見るとPHPの方が断然簡単でした。**
Rubyからスタートする場合と比べて挫折しづらいと思います。


RubyとPHPといっても、それぞれライブラリを含んだ比較となっています。
PHPはRails、PHPはLaravel、smartyです。


## Rubyと比べてPHPの方が良かった点
* コードを修正する際にwebサーバーの再起動が不要
* phpにはrubyのpassengerにあたるものがない
* DB接続が簡単
* 複数DBを横断的にアクセスできる
* viewファイルの位置がわかりやすい
* メソッドに括弧があってわかりやすい
* webアプリを作るためにライブラリが必要ない

### 詳細
* コードを修正する際にwebサーバーの再起動が不要
    * PHP:コードを修正する際にwebサーバーの再起動が不要です。
    * Ruby:コードを修正するたびに再起動が必要です。Dockerの場合、Docker自体の再起動またはウェブサーバー(puma,apache)の再起動が必要です。

* phpにはrubyのpassengerにあたるものがない
    * PHP:apacheとPHPのコードだけでWebアプリを作れます
    * Ruby:Railsを使った場合、apacheとRubyのコードをつなぐpassengerというものが必要です。アプリケーションサーバー？というのか複雑なものです。このpassengerに関する記述をapacheのconfファイルに記述しないといけません。サブディレクトリ対応させるときにもpassengerに気をつけないといけません。

* DB接続が簡単
    * PHP:laravel,smartyなどライブラリ必要なくできます。厳密には、PHPのPDOというモジュールを使っているのですが、phpの標準的なインストール
    ``` sudo apt-get install php ``` などをすると標準で入っています。
    * Ruby:railsなどライブラリを使わないといけない。

* 複数DBを横断的にアクセスできる
    * PHP:laravelを使うと、コード内で対象のDBを指定して複数のDBに接続できます。
        * 参考：[[Laravel]Laravelで別々のDB（MySQL）に接続させる方法 - Qiita](https://qiita.com/qiita-kurara/items/2e3efb4ccbb2489b05c3)

        ```php
        DB::connection('mysqldb1')->select('select * from users');
        DB::connection('mysqldb2')->select('select * from users');
        ```

    * Ruby:実は、ruby,railsでもできるみたいですが、色々難しそうです。少なくともappのコード内に書くのではなく、モードごとに設定する？
        * 参考：[Railsで複数DBに接続してみたい - Qiita](
https://qiita.com/akiko-pusu/items/35e2c3d6f1d9b45b807f)


* viewファイルの位置がわかりやすい
    * PHP:コントローラがviewファイルを明示的に呼び出すことを記述します。初心者でも、コントローラにリクエストがいってViewファイルを呼び出す流れがわかりやすいです。
    
    ```php
      // 取得した値をビュー「book/index」に渡す
      return view('book/index', compact('books'));
    ```
    * Ruby:上記のように書く必要がないため、（上記と同じ例であれば）暗黙的に「book/index.html.erb」を呼び出すことになります。
    

* メソッドに括弧があってわかりやすい
    * PHP:メソッドに括弧が必要です
    * Ruby:メソッドに括弧が不要です(括弧を書くこともできますが)。これは括弧がない方が楽なのではないか？と思うかもしれませんが、括弧がないことによってかなり混乱しやすいです。下記のリンクでその問題点について言及しています。
[【Ruby】メソッドの引数の個数についての疑問と検証 - Qiita](https://qiita.com/akihiro_kubota/items/4d83e1c85fc1f5cf0850)
    
* webアプリを作るためにライブラリが必要ない
    * PHP:ライブラリ必要なく、apacheの読み出す場所にphpファイルを置いておくとアプリを作成できます。というか、apacheもインストールすることなく以下のコードのようにサーバーを立ててアプリを開発できます。
初心者にとっては、まずアプリが動くまで短い方が挫折しにくいのでかなり良い部分です。
参考： [PHP: ビルトインウェブサーバー - Manual](https://www.php.net/manual/ja/features.commandline.webserver.php)

    ```
php -S localhost:8000 -t app/
    ```
    
    * Ruby:railsなどライブラリが必要です。ただ、railsにも`rails server`があるので、apacheは使わずともアプリを起動することはできます。
[AWS SDK for Python (Boto3)] EC2のタグ情報でEBSのタグ情報を設定する

## はじめに

EC2のタグ情報をもとに、EC2に紐づくEBSにタグ情報を設定するスクリプトの紹介です。
↓ このように、EBSのタグ情報を更新します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/5030da1d-d9cd-2f28-f8b6-ab2a77b1649c.png)

`-f` オプションは、対象のEC2を絞り込みます。EC2のＮameタグに含まれる文字列を設定します。文字列は前方一致です。`-f aws-test`とした場合、Nameタグが `aws-testかきくけこ` のEC2のみがEBSタグ更新の対象になります。対象のEC2に複数のEBSが紐づく場合は、それら全てが対象になります。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/98f6cea8-5176-5978-c09e-161630be7ad4.png)


## 実行環境

Pythonスクリプトの実行環境はWindows10です。

```powershell
PS C:\> python --version
Python 3.9.5
PS C:\> pip list
Package         Version
--------------- --------
boto            2.49.0
boto3           1.17.104
botocore        1.20.104
pip             21.1.3
PS C:\> aws --version
aws-cli/2.2.16 Python/3.8.8 Windows/10 exe/AMD64 prompt/off
```

## スクリプト

スクリプトはgithubに格納しました。

https://github.com/zgw426/AWS-SDK_setEbsTagsFromEC2TagsInfo

## スクリプト実行方法

`-f`,`-d` の2つのオプションを使用します。

|オプション|概要|
|---|---|
|-f|EC2のNameタグに含まれる文字列を設定します。文字列は前方一致|
|-d|`False`を指定するとdry-runが **無効** になり、EBSのタグ情報を設定します|

スクリプトの実行方法

```powershell
PS C:\> python test.py -f {EC2 Nameタグのフィルタ文字列(前方一致)} -d False
```

実行例１）EC2のNameタグの文字列が `aws` で始まるEC2に紐づくEBSをタグ更新の対象にする

```powershell
PS C:\> python test.py -f aws -d False
```

実行例２）EC2のNameタグの文字列が `aws-test` で始まるEC2に紐づくEBSをタグ更新の対象にする

```powershell
PS C:\> python test.py -f aws-test -d False
```

実行例３）`-d` オプションを指定しない場合は dry-runが **有効** になり、処理対象の情報表示のみ行います。

```powershell
PS C:\> python test.py -f {EC2 Nameタグのフィルタ文字列(前方一致)}
```

## スクリプト実行結果サンプル

スクリプトを実行したときの出力サンプルです。

```powershell
PS C:\Users\usr01\test> python setEbsTags.py -f aws-test -d False
Python Version Check [OK] : sys.version_info(major=3, minor=9, micro=5, releaselevel='final', serial=0)
==========================================================
[1]     ---------------------------
        EC2 InstanceID = i-00000000000000001
        タグ名= Name,   値= aws-testかきくけこ
        タグ名= project,        値= projectかきくけこ
        タグ名= cost,   値= costかきくけこ
        EBS IDs= ['vol-000000000000001', 'vol-000000000000002']
==========================================================
----------------------------------------------------------
[Dry-run:OFF] EBSのタグ情報を更新->開始
[1](EBSタグ更新) ---------------------------
        EC2-ID=i-00000000000000001
        EBS=['vol-000000000000001', 'vol-000000000000002']
        Tags=[{'Key': 'Name', 'Value': 'aws-testかきくけこ'}, {'Key': 'project', 'Value': 'projectかきくけこ'}, {'Key': 'cost', 'Value': 'costかきくけこ'}]
[Dry-run:OFF] EBSのタグ情報を更新->終了
----------------------------------------------------------
PS C:\Users\usr01\test> 
```
Class "App\Models\Blog"  not  found　（フォルダの場所が違っていたというだけ）

## （結論）フォルダの場所が違っただけでした。
![スクリーンショット 2021-07-04 13.28.10（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1376379/99a42c79-3e01-1828-cdde-809a36a9a69e.png)



検索して記述を直しても全然解決しなかったのですが，ふとフォルダを見ると

### 修正前
![スクリーンショット 2021-07-04 13.14.53（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1376379/f56d33fb-c47d-a518-1f73-3c84db814732.png)
違和感・・・。

あ💡

モデルの中の，さらにモデルの中に「Blog」ファイルがありました。

### 修正後
![スクリーンショット 2021-07-04 13.15.07（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1376379/ed7f677d-2586-1734-6b9b-5377848b7c05.png)

エラーの時は，落ち着いて見直さないといけないと思いました😅
NetlifyへのNode.jsの環境設定に苦戦した話

# はじめに
NetlifyにNode.jsの環境を構築しようとして、苦労したのでその内容をここに残します。簡単に構築できると思っていましたが、なんやかんやで１ヶ月以上は掛かったように思います:sweat_smile:なんとかNetlifyに環境の設定はできましたが、完璧にはいけませんでした。。

# Node.jsとnpmのインストール方法
こちらのprogateのサイトが参考になりました。ここはすんなり上手くいきました。

https://prog-8.com/docs/nodejs-env-win

https://prog-8.com/docs/nodejs-env

上記以外でNode.jsのバージョン管理するツールのnvmをインストールしてNode.jsを管理する方法もあります。こちらにも挑戦しましたが、なかなか難易度が高かったです:sweat:

https://photo-tea.com/p/17/hexo-start-kit-tools-4/

# Netlify Functionの構築
Netlify FunctionとはNetlify内のアドオンであるFaaS（Function as a service)です。AWS Lambdaのように特に設定もなく、ソースコードを実行してくれます。実は裏側ではAWS Lambadaが実行基盤として動いているそうです。
これがあると便利なようなのでインストールはしておいた方が良いようです:point_up_tone1:

https://note.com/shimakaze_soft/n/ncee10d32fe89#MvTBM

しかし！
この中で出てくる「netlify-lambda」のインストールでエラーが発生し、このエラーに１ヶ月程度悩まされました。。色々なサイトを見ましたが、「netlify-lambda」のエラーは一向に解消されずといったところでした。エラー記事はあまり見つけることができませんでした。

Netlifyが提供している「netlify-lambda」のリポジトリはあったのですが、ここでのインストールもエラー発生というところでした:sweat_smile:

https://github.com/netlify/netlify-lambda

# 辿り着いた結果
以下のソースを使用しました。そのため、上記でインストールしたものは全て削除しました:sweat_smile:

https://github.com/netlify-labs/netlify-functions-express

こちらはNode.jsとExpress（Node.jsのフレームワーク）を使用して、Netlifyに環境が設定できるソースとなっています。そのままソースをデプロイすることができたので、このソースを加工しながらコーディングを進めました。ローカルで確認しながらコーディングを進めたかったのですが、その方法は分からず。。というところです。

### コーディングの進め方
NetlifyとGithubの連携を行う。
※NetlifyとGithubの連携方法は以下で紹介しています。

https://qiita.com/nacho0707/items/3ef87f412be7b92b9d33

次に、GitHubでプルリクエストを作成します。
するとデプロイ可能かどうかを解析してくれて、デプロイ成功または失敗したかの判定をしてくれます。成功の場合は下記画像のように緑色の✔となり、失敗の場合は赤色の×が表示されます。
また、デプロイ後のプレビューを確認できるので、そこで上手くできていればマージをするという方法で進めました。（下記画像の赤線の箇所を押下すると確認できます）

![netlify.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700107/ad88b5fa-72f1-64c0-84ef-085073a17b40.jpeg)

# さいごに
なんとかNode.jsの環境を構築できたので、NetlifyとNode.jsの連携にお困りの方は最後に紹介している方法で設定するのが良いかと思います。ソースの中身は全て理解できていないところもあるので、徐々に理解し次回は自分の書いたソースで環境の設定ができるようになりたいです！
AtCoderログ：0005 - ABC 157 A

# 問題

https://atcoder.jp/contests/abc157/tasks/abc157_a

## 問題文
> 高橋君は、全 $N$ ページから成る書類を両面印刷します。両面印刷では、$1$ 枚の紙に $2$ ページ分のデータを印刷することが出来ます。
> 最小で何枚の紙が必要か求めてください。

## 制約
> ・$N$ は整数
> ・$1 \le N \le 100$

## 収録されている問題セット
- [AtCoder に登録したら次にやること](https://qiita.com/drken/items/fd4e5e3630d0f5859067) ([第01問類題](https://qiita.com/drken/items/fd4e5e3630d0f5859067#%E7%AC%AC-1-%E5%95%8F--abc-086-a---product-100-%E7%82%B9))

# 回答
## 回答1 (AC)
$N$ が偶数ならば印刷するページ数は半分の $\frac{N}{2}$ ページです。また、$N$ が奇数ならば印刷するページ数は $\frac{N+1}{2}$ ページになります。これを素直にコードにしてACとなりました。

```C++:abc157a-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int n;
  cin >> n;
 
  if ( n%2==0 ) {
    cout << n/2 << endl;
  } else {
    cout << (n+1)/2 << endl;
  }
}
```

## 回答2 (AC)
$N$ が偶数ならば $N+1$ を2で割った商は $\frac{N}{2}$ と等しくなるので、$N$ が偶数でも奇数でも印刷するページ数は (C++の式として) $(N+1)/2$ ページになります。このことをコードにすると以下のようになりました。if 文が不要になるため、とてもシンプルなコードです。

```C++:abc157a-2.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int n;
  cin >> n;
 
  cout << (n+1)/2 << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc157/tasks/abc157_a/editorial) → [ユーザ解説](https://blog.hamayanhamayan.com/entry/2020/03/02/000708)
回答2と同じ方針でした。

## [AtCoder の解説](https://atcoder.jp/contests/abc157/tasks/abc157_a/editorial) → [コンテスト全体の解説](https://img.atcoder.jp/abc157/editorial.pdf)
回答2と同じ方針でした。最初から回答2を思いつく必要があるのでしょう。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0004 - ABC 088 A](https://qiita.com/RoadLynton/items/58906355ec8f8e0112c0)
- 次の記事 → [AtCoderログ：0006 - ABC 208 に参加しました](https://qiita.com/RoadLynton/items/029fb11fa9b5bbfd95ce)
【第6章】Railsチュートリアルでデータベースに新規ユーザーが保存できない時にやったこと

[Railsチュートリアル第6章(第6版)](https://railstutorial.jp/chapters/modeling_users?version=6.0#cha-modeling_users)-6.3.4 ユーザーの作成と認証- でデータベースに新規ユーザーを登録しようとすると、rollback transactionが動いて保存が取り消されてしまう。![Railsチュートリアル第6章.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505219/7552c95f-bbb0-963b-591b-7b9703ff37f7.png)

#やったこと① メッセージ内容を確認した
まず、よくメッセージ内容を確認した。すると、

```
ActiveRecord::StatementInvalid (SQLite3::BusyException: database is locked)
```
とあった。データベースがロックしてあるようだ。

#やったこと② SQLite3のdatabase is lockedについて調べた
分からないことはさっさと検索する。すると以下の記事がヒットした。
引用：http://fanblogs.jp/scripts/archive/61/0

この記事によると、***ファイル名を別名にしてコピーすることでロックが解除できる***ようだ。
よく分からないがやってみることにする。

#やったこと③ データベースのファイルを別名にし、そのコピーを元の名前で作成した
記事に従って以下のコマンドを叩いてみた。
1. mvコマンドを使ってロックされているSQLiteのデータベースファイルを別名にする。

```
$ mv development.sqlite3 bk.development.sqlite3
```
2. cp -p コマンドを使って元と同じファイル日付で、元と同じファイル名としてコピーする。

```
$ cp -p dk.development.sqlite3 development.sqlite3
```
するとrollback transactionが表示されずに、***新規ユーザーの登録に成功した。***
![Rチュートリアル(6_3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505219/896975f9-8129-20b6-1a6f-19ba1bf6bf9e.png)

#まとめ
やったこと①②③の流れで解決できた。
C++のメモリ解放実験②


shiracamus様からご指摘があったので、再度私のほうでプログラムを検証し、再度メモリ解放実験を行いました。


```C++
//============================================================================
// Name        : At4.cpp
// Author      : 乃木坂好きのITエンジニア
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;

//メイン処理
int main(){
  //ポインタ変数を定義する
  int *p1;



  p1 = new int;         // (※) int 型変数１個のメモリ確保

  //p1をxのアドレスで初期化
  *p1 = 10;
  //p1のポインタの値を表示
  cout << "p1がさしている整数型は:" << *p1 << endl;
  //p1のポインタの値を1000にする
  *p1 = 1000;

  cout << "p1 が指している整数型は: " << *p1 << "\n"; //p1ポインタの値を表示

  delete p1;    // (※) メモリの解放

  cout << "メモリ解放後のp1 が指している整数型は: " << *p1 << endl;　//メモリ解放後のp1ポインタが指し示す値


  return 0;
}
```

表示結果は次の通りです。
![result.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1055346/841910c1-709b-13a5-9b7e-22e68f5da9e0.jpeg)
ModuleNotFoundError: No module named 'パッケージ名' への対処　python3　Error　Module

# 概要

PATH設定が原因で、任意のModuleが読み込めずに
pythonのパッケージが使用できない時があるので、その対処について

# 環境
- python 3.9
- Mac

# 対処例

**ModuleNotFoundError: No module named 'pandas'**
と表示された場合

まず該当のパッケージ（ここではpandas）がインストールされているか確認＆`パッケージがインストールされているパスを確認`する

```zsh:インストール状況を確認するコマンド（ここではpandas）
# 確認パッケージが異なる場合はpandasの部分を対象のパッケージ名で書き換えて実行

pip3 show pandas
```
```zsh:出力例
Name: pandas
.
.
Location: /usr/local/lib/python3.9/site-packages
.
.
```

```zsh:コンソールで実行
python3 -c "import sys; print(sys.path)"
```
```zsh:出力例
/Users/HOGEHOGE/.pyenv/versions/3.9.0/lib/python3.9/site-packages:
/Users/HOGEHOGE/Library/Python/3.9/bin:
/Users/HOGEHOGE/.pyenv/versions/3.9.0/lib/python3.9/site-packages:
.
.
```
`※ 標準の出力では見づらい形式で出力されるので、適宜改行・整形する`

前項で出力したpandasのパス（Location: `/usr/local/lib/python3.9/site-packages`）が出力表示に含まれているかを確認する。
表示されないようであれば、**\$PATH**（もしくは**\$PYTHONPATH**）にpandasのパスを追加する。

# パスの追加
使っているシェルによって`~/.bashrc`や`~/.zshrc`に追記する

```zsh:追加するパス
# pip3 show pandas 実行時のパス情報↓

/usr/local/lib/python3.9/site-packages
```
```zsh:~/.zshrc
# 記載例
# PYTHONPATHの中身を:でつなげてワンライナーで記述してる。改行して記載する際は末尾に\をつける 

# python path
export PYTHONPATH=${HOME}/.pyenv/versions/3.9.0/lib/python3.9/site-packages:\
${HOME}/Library/Python/3.9/bin:\
/usr/local/lib/python3.9/site-packages:\
$PYTHONPATH
```

# 余談

とりあえずエラー回避して動かしたい人向けの対処方法ですね

# 参考

>
[pythonでImportError: No module named ・・・が出たときの確認方法と対処](https://web.plus-idea.net/2017/05/python-import-error-no-module-name/)
[Python Tips：ワンライナーが書きたい](https://www.lifewithpython.com/2015/01/python-use-command-one-liner.html)
GatsbyでMissing "key" prop for element in iteratorが出る

# はじめに
こんにちは。クワガタかカブトムシかでいうとクワガタ派です、筆者です :raising_hand: 

さて、Gatsbyで作ったほぼほぼチュートリアルでいじってないコードに機能追加する機会がありました。
Reactもあんまり理解していないが故に、お作法でつまづきました。


# GatsbyでMissing "key" prop for element in iteratorが出る

Contentfulからpost一覧を取得して、postの数だけitemを生成したいのですが、スクリーンショットのように怒られたました :innocent:

```js
const posts = data.allContentfulPost.edges
return (
  <Wrapper>
    <List>
      {posts.map(({ node }) => {
        return (
          <ArticleItem
            title={node.title}
            heroImage={node.heroImage}
            slug={node.slug}
          />
        )
      })}
    </List>
  </Wrapper>
)
```

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/90da7772-9f2e-a74d-e2ed-42d4dedadeae.png)

# 原因
`ArticleItem`にkeyを渡してないため。

Reactのドキュメントには以下の通りの記載があります。

>Keys should be given to the elements inside the array to give the elements a stable identity:

https://reactjs.org/docs/lists-and-keys.html#keys

# 解決策
以下のように`ArticleItem`にkeyで一意の値を渡してあげれば大丈夫です :ok_hand:

```js
  const posts = data.allContentfulPost.edges
  return (
    <Wrapper>
      <List>
        {posts.map(({ node }) => {
          return (
            <ArticleItem
+             key={node.slug}
              title={node.title}
              heroImage={node.heroImage}
              slug={node.slug}
            />
          )
        })}
      </List>
    </Wrapper>
  )
```

また、Reactのドキュメントに記載の通り、最悪indexを渡せばいいそうです。

# おわりに
小さなことですが、知らないことでしたし、こういうことで怒ってくれるのがちょっとうれしいとも感じました。
引き続きググりながら機能追加進めつつ、コードの理解を深めていこうと思います:bow:

それでは:bow:
[Rails]存在しないIDでfindしてエラーになった時の対処法

## はじめに
本記事はfindしてエラーなった場合の対処法について書いたものです。

## 環境
Rails 6.0.3
Ruby 2.6.3

## 本題
結論から書くと`find_by`を使うか`where`を使うかのどちらかになります。
一意のIDからなど一つのレコードを取得したい場合は`find_by`を使い、複数のレコードを取得したい場合は`where`を使います

```
User.find_by(id: 1)

User.where(name: "taro")
```

理由としてそれぞれ値が見つからなかったときに`nil`と`[]`が返ってくるからです。
findと比較して見てみましょう

```
User.find(1) => ActiveRecord::RecordNotFound: Couldn't find User with 'id'=1

User.find_by(id: 1) => nil

User.where(id: 1) => []
```

上記を見ると`find`の場合例外が発生し`find_by`、`where`の場合は`nil`と`[]`が返っていることがわかります。

以上のことから既にないレコードを検索してしまう可能性のあるところでは`find_by`や`where`を使うといいと思います

## 参考

https://railsguides.jp/active_record_querying.html
2.4GHz 5GHz とは

## 勉強前イメージ

よくwifiとかで出てくるやつ
2.4GHzが壁とかにも強いけど5GHzは強くないとか、そんなイメージ

## 調査

### 2.4GHz 5GHz とは

wifiで使用されている無線電波の周波数のことを示しています。
それぞれの特徴は以下になります。

- 2.4GHzの特徴
	- メリット
		- 障害物に強く、電波が遠くまで届く
		- いろんなwifi端末が対応している
	- デメリット
		- いろんな製品で使用しているので混雑して不安定になる可能性がある

- 5GHzの特徴
	- メリット
		- 他の製品ではあまり使用されない帯域なので繋がりやすい・安定している
		- 高速な通信が可能
	- デメリット
		- 障害物に強く、遠くなると電波が弱くなる
		- 古いルーターだと対応していない事がある

### wifiの通信規格

wifiの通信規格には IEEE 802.11 といった、IEEEが策定している無線LANの標準規格があります。
他にも優先LANのethernetを扱う802.3や Bluetoothの802.15があります。

規格によって最大通信速度が変わります。
以下を見るとwifiでよく見る `BUFFALO-XXXXX-a` とか `BUFFALO-XXXXX-g` とかの意味がわかります。 (wifiの名前は適当です、ありそうなやつ書いてます。)
aだったら5GHz帯で、gだったら2.4GHz帯。どっちも最大通信速度は一緒と下だけでは読み取れます。
多分他にもいろいろ違いはあると思います。

- IEEE 802.11a
	- 周波数 : 5GHz帯
	- 最大通信速度 : 54Mbps
- IEEE 802.11b
	- 周波数 :  2.4GHz帯
	- 最大通信速度 : 11Mbps
- IEEE 802.11g
	- 周波数 : 2.4GHz帯
	- 最大通信速度 : 54Mbps
- IEEE 802.11n
	- 周波数 : 5GHz帯, 2.4GHz帯
	- 最大通信速度 : 600Mbps
- IEEE 802.11ac
	- 周波数 : 5GHz帯
	- 最大通信速度 : 6.9Gbps
- IEEE 802.11ax
	- 周波数 : 5GHz帯, 2.4GHz帯
	- 最大通信速度 : 9.6Gbps

これはどこで見れるかというと、
例えば私が持ってるpixel4aの使用を [こちら](https://store.google.com/jp/product/pixel_4a_specs?hl=ja) から確認すると
`Wi-Fi 2.4 GHz + 5 GHz8 802.11a/b/g/n/ac`  と記載されているので、
上記に記載されている一番下以外は使用できることになります。

![1Google Pixel 4a のハードウェア仕様 - Google ストア - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/e6d9da74-7648-1d1f-f2a6-117ada1fd947.png)

## 勉強後イメージ

よく見るけど、あまり知らなかったシリーズ調べてみた。
スマホ買う時とか見てたけど、正直あまり理解出来てなかった。
対応している機器があったら使えるのね。


## 参考

- [Q．【Wi-Fiルーター】2.4GHzと5GHzの違いについて](http://qa.elecom.co.jp/faq_detail.html?category=&id=5953)
- [無線LANの基礎知識](https://www2.elecom.co.jp/network/wireless-lan/column/wifi_column/00062/)
- [Google Pixel 4a を、もっと詳しく。](https://store.google.com/jp/product/pixel_4a_specs?hl=ja)
【Docker】EC2にDockerをインストールする　no.27

![パンプキン カフェ (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/665e3400-a480-ce0a-f0ff-3655792eeca1.png)


こんにちは。まゆみです。

Dockerについての記事をシリーズで書いています

[前回の記事](https://qiita.com/Mayumi_Pythonista/items/5527b517f28084ba7612)では、ターミナルからEC2にアクセスする方法を書かせていただきました。

今回の記事では、<font color="Red">EC2にDockerをインストールしていく方法</font>を書いていこうと思います

現在、EC2のなかに入っていることが前提で書いています。(EC2への入り方が分からない方は前回の記事を読んでくださいね。)

ではさっそく始めていきますね。

#手順通りにするだけ

EC2にDockerをインストールすると言っても、わりとそのままマニュアル通りに進めていくだけになります

どのようなコマンドを打つか、順に書いていきますね

##sudo yum update -y

```
sudo yum update -y
```

上記のコマンドによって、リモートマシーンにインストールするパッケージが最新のものであるようにします

##sudo amazon-linux-extras install docker

```
sudo amazon-linux-extras install docker
```

前回の記事でAmazon Linux 2 AMI でインスタンスを作っていますので、上記のようなコマンドになります

このプロセスでリモートマシーンにDockerがインストールされます

##sudo service docker start

```
sudo service docker start
```

このコマンドでDockerがスタートされます。

この後、試しにdockerのコマンドを打ってみましょう

私は、

```
docker run --help 
```
でdocker run のオプションの使い方を表示してみました。


![2021-07-04_12-20-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/2abf0fca-ab0d-ac13-4ef2-d54a24105dd8.png)

うまく行きました。＼(^o^)／

#まとめ

今回の記事はここで締めくくらせていただきます。

次回は、クラウド上にローカルで作ったイメージをpushする方法を書いていきますね。
# VSCode でDocker コンテナ内の JupyterLab を使う

VSCodeを使用してDockerコンテナ内のJupyterLabに接続するための方法の際、少し躓きましたので、備忘録としてここに記しておきます。

###開発環境

以下の環境での動作確認済です。(2021/07/04現在)

* MacBook Air (M1, 2020) 
* MacOS Big Sur 11.4

###断り
拡張機能には何が必要なのかというのはそれほど調べなかったので、Python関連の拡張機能は他のサイトをご参照ください<(_ _)>
筆者はとりあえず色々入れてみた結果使えるようになったので、どれが必要でどれが不要かというのははっきりわかっていない状態です。

追記(2021/07/10)
自分が何を入れたのかを調べた結果は以下のような感じです。

* [Python Extension Pack](https://marketplace.visualstudio.com/items?itemName=donjayamanne.python-extension-pack) ←補完機能利用のため
* [Jupyter](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter) ←コードをJupyterLabの形式で使用するため
* [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) ←必要なのかは不明

この3つが入っている状態なのに利用できない場合は教えてください<(_ _)>

### 手順
####1.Dockerileの作成
JupyterLabのファイルを保存するディレクトリ(任意)に以下のように`Dockerfile`と`work`ディレクトリを作成します。

```
.
┣━ Dockerfile
┗━ Work/
```

これが出来たら、`Dockerfile`に以下のコードを記入&保存します。


```dockerfile:Dockerfile
FROM continuumio/anaconda3
RUN jupyter notebook --generate-config
WORKDIR /root/.jupyter
RUN echo 'c.NotebookApp.allow_root = True' >> jupyter_notebook_config.py && \
    echo 'c.NotebookApp.ip = "0.0.0.0"' >> jupyter_notebook_config.py && \
    echo 'c.NotebookApp.token = "ここには任意の文字列を記入"' >> jupyter_notebook_config.py && \
    echo 'c.NotebookApp.port = 8888' >> jupyter_notebook_config.py && \
    echo 'c.NotebookApp.open_browser = False' >> jupyter_notebook_config.py

RUN mkdir -p /home/work
WORKDIR /home/work

CMD [ "jupyter", "lab"]
```

このコードに関しては、記事の末端に記している方のページを参考にしました。
任意の文字列入力欄は、以後使うtokenとなります。(日本語対応はおそらくしていないため、)英数字で好きな文字列を入力してください。

####2. Dockerfileのイメージビルドとコンテナ立ち上げ
以下のコードをターミナルに入力してイメージビルド&コンテナ作成を行います。
イメージ名及びコンテナ名は任意です。

**イメージをビルドするコマンド :**

```zsh
docker build . -t [イメージ名]
```
**コンテナを作成するコマンド :**

```zsh
docker run -v $(pwd)/work:/home/work -p 80:8888 --name [コンテナ名] -it [イメージ名]
```

コンテナ作成が完了したら、一度ブラウザにて[http://localhost/](http://localhost/)にアクセスしJupyterLabが起動するかどうかを確認します。
ここでtokenの入力が求められるので、`Dockerfile`にてあらかじめ決めておいた文字列を入力し、以下のような画面が確認できれば完了です。
![browser_jupyter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1726209/4bea9853-e295-822a-7afc-25cdf3ebbf2c.png)

####3. コンテナ内のJupyterLabとVSCodeをリンクさせる
VSCodeを開き、先ほど作成したWorkディレクトリを開きます。
`Command` + `Shift` + `P` を使ってコマンドパレットを開き、入力欄に
`Jupyter: Specify local or remote Jupyter server for connections`
と入力し、該当するものを選択します。![command.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1726209/f2be4bda-c3d9-8d2d-d1ae-b60e4b940d39.png)

`Default`と`Existing`の選択画面が表示されるので、`Existing`を選択し、URL入力欄に以下のように入力します。
`http://localhost/?token=「ここにDockerfileにて設定した文字列を入力」`
これで接続設定は完了です。VSCodeをReloadするように誘導されると思いますので、Reloadしたあと動作するかどうかを以下のように確認してみてください。
![final.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1726209/aa7acc56-8699-81dd-edeb-34db1019f048.png)

###参考にした記事
https://qiita.com/s-inoue-git/items/2b5c65a1f11a1ba4a38e
Spring SecurityのHeaderWriterFilterのメモ

確認したバージョンは `Sprint Security 5.5.0`

HTTPレスポンスヘッダーにセキュリティ関係のものを付与するフィルターです。

[WebSecurityConfigurerAdapter#applyDefaultConfiguration](https://github.com/spring-projects/spring-security/blob/5.5.0/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.java#L225)で設定されているので、デフォルトで有効になっています。

## ヘッダの出力タイミング
[こちら](https://github.com/spring-projects/spring-security/blob/5.5.0/web/src/main/java/org/springframework/security/web/header/HeaderWriterFilter.java#L69)のコードによると
ヘッダの出力タイミングは、処理前、処理後と選べるようで
デフォルトでは処理後となっているようです。

処理後の場合は、リクエスト、レスポンスがそれぞれ `HeaderWriterRequest`, `HeaderWriterResponse` でラップされ レスポンスの [onResponseCommitted](https://github.com/spring-projects/spring-security/blob/5.5.0/web/src/main/java/org/springframework/security/web/header/HeaderWriterFilter.java#L125) のタイミングで割り込んでヘッダの出力が実行されるようです。

タイミングを処理前に変更したい場合は `addObjectPostProcessor` などを使って変更することができそうです。

## 出力の仕組み
`HeaderWriterFilter` は内部に 「`List<HeaderWriter> headerWriters` 」のフィールドを持っており [writeHeaders](https://github.com/spring-projects/spring-security/blob/5.5.0/web/src/main/java/org/springframework/security/web/header/HeaderWriterFilter.java#L97) で各HeaderWriterのwriteHeadersメソッドを呼び出しています。

この `HeaderWriter` の一覧は [HeadersConfigurer#getHeaderWriters](https://github.com/spring-projects/spring-security/blob/5.5.0/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java#L382) で作られています(たぶん)

## デフォルトで適用される HeaderWriter
[HeadersConfigurerの下の方](https://github.com/spring-projects/spring-security/blob/5.5.0/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java#L546) を見ると 各HeaderWriterを作るためのコンフィグ用のクラスがあります。

このコンストラクタの中で

```java
private ContentTypeOptionsConfig() {
    enable();
}
```

のように `enable` が呼び出されているものがデフォルトで有効になっています。

ソースによると

- `ContentTypeOptionsConfig`
- `XXssConfig`
- `CacheControlConfig`
- `HstsConfig`
- `FrameOptionsConfig`

が有効になっています、実際にこれらのヘッダーが出力されています。

## HeaderWriter の無効/有効の切り替え

```java

	@Override
	protected void configure(HttpSecurity http) throws Exception {
        http.headers()
            .cacheControl().disable()
            .httpPublicKeyPinning()
    }
```

などで無効や有効にすることができます。
また [defaultsDisabled](https://github.com/spring-projects/spring-security/blob/5.5.0/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java#L348) を実行すると デフォルトのものを全て無効にすることができます。


## HeaderWriterの追加

`addHeaderWriter` に HeaderWriterの実装クラスのインスタンスを指定することで追加ができます。

条件によって変化しない静的なものであれば[StaticHeadersWriter](https://github.com/spring-projects/spring-security/blob/5.5.0/web/src/main/java/org/springframework/security/web/header/writers/StaticHeadersWriter.java) を使うことができます。

```java

	@Override
	protected void configure(HttpSecurity http) throws Exception {
        http.headers()
			.addHeaderWriter(new StaticHeadersWriter("x-neko", "nyan"))
    }
```