OmniAICreator/Qiita-1.07M huggingface dataset:
【Docker】Mac×Dockerで環境構築する時に気をつけること

新しく参入した現場でエンジニアがやる最初の仕事・・そう、開発環境の構築。

この記事では、私が２０２２年４月の転職を機にWindowからMacユーザとなり、Dockerを使って環境構築しようとした時の苦労と学びを紹介したいと思います。

- Mac乗り換えを考えているが、環境構築できるか不安だ
- まさしく今Mac×Dockerでつらみにハマっている

というようなあなたの参考になれば。

# この世には２種類のMacがいる

Macユーザにはもう既知も既知でしょうが、**この世には２種類のMacがいます**。Intel x86アーキテクチャか、arm64アーキテクチャかです。意外と（自分のような）Windowsどっぷりマンは知らなかった。

非エンジニアの方向けに補足しておくと、これはコンピュータの中央演算装置（CPU、プロセッサ）の構造による分類です。ここでは細かい説明を省いて（け、決してできないとは言ってない）、それぞれを「Intel系」「Mac系」と呼ぶことにします。

Macを製造するAppleはもともと、このCPUをWindows　PCにも搭載されているIntel系を調達していたのですが、２０２０年11月、満を持してMacのために開発したMac系のCPUを搭載するようになりました。

そしてこのCPU構造の違いが、今回私を苦しめる原因になったのです・・

# M1 Macでエラーが解消しない・・？

ここらで、私がどのように苦しんだかも話しておこうと思います。

転職初日から、参入プロジェクトに既存であったキャッチアップ資料を参考に、Mac系CPUを搭載したMacbook ProでDockerコンテナを利用して開発環境（ローカルでいくつかサーバが立ち上がる）を作ろうとしました。ちなみにOS Montereyのv12.2.1です。**無垢で純真な生まれたてのMacユーザである**私は、安直に「ターミナル」を起動し、docker-composeコマンドでイメージをビルド、そしてコンテナ実行、と進めていきました（だってLinuxならこれでうまくいきそうだったんだもん）。これが苦労の始まりとも知らずに。

必要上、立ち上げたコンテナの中で、”yarn install”をする手順があったのですが、そこで「必要なコマンドが見つかりません」というようなエラーに遭遇。しかしそこはエンジニア、この程度のエラーなら慣れています。必要なコマンドが見つからないなら、ちゃんとセットアップしてあげれば良いのです。簡単、簡単。と思いきや、またも同じエラーが発生。およよ？

```py
# 発生したエラーのイメージ
[4/4] Building fresh packages...

    ...
error /app/node_modules/@sentry/cli: Command failed.
Exit code: 1
Command: node xxx...
Arguments: 
Directory: /app/node_modules/@sentry/cli
```

ここで私はチームのシニアエンジニアに相談、「この世には２種類のMacがいる」ことを知り、dockerコンテナ実行時には前述したCPUアーキテクチャを考慮することがあることを知ります。具体的な対策は[こちら](https://tubuyaki-tech.com/tubu-mac-docker/)でどうぞ。（私のブログ記事へジャンプします）
cronまとめ

LinuxやUnixでは、プログラムを決まった時間に自動で走行することができます。
cronは、ジョブを自動実行するためのデーモンプロセスです。

```
ジョブの作成
crontab -e

実行中のジョブの確認
crontab -l

ジョブの停止
crontab -r
```

# link 
[crontabの記述方法](http://uguisu.skr.jp/Windows/crontab.html)
Effective Java 第3版まとめ（項目4）

# 項目4.privateのコンストラクタでインスタンス化不可能を強制する

## 書かれている内容

* ユーティリティクラスは、インスタンス化されるようには設計されていない（インスタンスには意味がない）
* 明示的なコンストラクタがなければ、コンパイラはデフォルトコンストラクタを提供する
* ユーザにとってこのコンストラクタは、他のコンストラクタと区別がつかない
* 抽象クラスもうまくいかない。サブクラスを作成できるし、サブクラスをインスタンス化できる。継承するために設計されていると誤解される
* privateのコンストラクタでインスタンス化できないようになる
* privateのコンストラクタでAssertionErrorをthrowすることで、クラス内から誤って呼び出された場合の保険となる
WEEKDAY関数

案外この数式の質問が多い。毎回返り値の　1　は何？って考えるのでここにまとめておきます。

1:日曜日
2:月曜日
3:火曜日
4:水曜日
5:木曜日
6:金曜日
7:土曜日

# 2日後で週末を避ける場合

```
CASE(
WEEKDAY(TODAY()),
1,2,
2,2,
3,2,
4,2,
5,4,
6,4,
7,3,
0 )
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d7261a57-b357-cec3-784e-5fd42a80b4f8.png)


# 3日後で週末を避ける場合

```
CASE(
WEEKDAY(TODAY()),
1,3,
2,3,
3,3,
4,5,
5,5,
6,5,
7,4,
0 )
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6130744e-e003-bf62-2242-0d0e7663d155.png)


# 特定の曜日を求める

```
$Flow.CurrentDate +
CASE( WEEKDAY ( $Flow.CurrentDate ),
1,4,
2,3,
3,2,
4,1,
5,0,
6,-1,
-2)
```

[Formula to return certain day during the week](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000Jdnqb)

# 営業日として30日を加えた日を求める

+ [Calculate 30 Business Days from a given date](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000JfydJ)

```
CASE( WEEKDAY(date_field__c + 30),
2,date_field__c + 41,
3,date_field__c + 40,
date_field__c + 42)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/190df524-ca5e-3e7d-624b-1a1960db8d5b.png)


# 前の週の月曜日を求める

[Excel formula to calculate Monday of the previous week](https://excel-exercise.com/calculate-monday-previous-week-with-excel/)

excelもSalesforceと同じで日曜日が1

日付に対応する曜日を返します。 既定では、戻り値は 1 (日曜) から 7 (土曜) までの範囲の整数となります。
スマートウォッチ開発#3

前回の投稿から訳2週間ほどが経過したが、依然としてスマートウォッチ開発を進めている。

前回までは、android wacthのwear OSアプリ開発を試みた。結論、参考書にあるandroid studioでの動確を確認でき加速度を取得するアプリを作成することまではできたが、実際に自分が考えたコードを書くことができなかった。理由は、慣れ親しんでいない言語kotlin、javaでの開発となるからと考えた。

従って、紆余曲折するもののjava scriptを用いるfitbit studioでアプリ開発を再考した。
現在、アプリのアーキテクチャ理解と、コードをbuildして、自身のスマートフォン、時計での動作を確認することができた。fitbit web内に記載されるコードでの動確は完了したので、今後は実際にコードを記載して進めていく。

現在、詰まっている箇所は、「コードをどのようにして書くのかがわからない」こと。
　○	スマートウォッチにリアルタイムに信号を送信
　　　■	fitbit端末にhttp通信でリクエスト送信
　　　　　●	リクエストを送信するのはpostman
　○	通信を受信したタイミングでスマートウォッチのバイブレーション
　　　■	fitbit APIでGETリクエスト受信
　　　■	バイブレーション起動

残り1週間強で上記部分のコード記載を行い、動確まですればMVPは終了とする。

以上
Go言語 無名関数の書き方

Go言語の無名関数の記事が少ないので、ここでいくつか例を上げたいと思います。

## 環境
go 1.18

## 例1 : 即時実行
```go:input
package main

import "fmt"

func main() {

	// 無名関数
	func() {

		fmt.Println("Welcome! to Go Lang")
	}()

}
```

```terminal:ouput
Welcome! to Go Lang
```
## 例2 : 変数に代入してから実行
Go言語では無名関数を変数に割り当てる事ができます。
無名関数を変数に割り当てると、その変数は関数型となり、関数をコールするようにその変数をコールする事ができます。
```go:input
package main

import "fmt"

func main() {

	// 変数に無名関数を割り当て
	value := func() {
		fmt.Println("Welcome! to Go Lang")
	}
	value()

}
```

```terminal:output
Welcome! to Go Lang
```
## 例3 : 無名関数に引数を渡す
無名関数に引数を渡す事もできます。
```go:input
package main

import "fmt"

func main() {

	func(ele string) {
		fmt.Println(ele)
	}("Let's Go")

}
```

```terminal:output
Let's Go
```
## 例4 : 任意の関数に無名関数を引数として渡す
```go:input
package main

import "fmt"

// 無名関数を引数に渡す
func GFG(i func(p, q string) string) {
	fmt.Println(i("Go", "for"))
}

func main() {
	value := func(p, q string) string {
		return p + q + "Go"
	}
	GFG(value)
}
```

```terminal:output
GoforGo
```
## 例5 : 無名関数を戻り値として返す
```go:input
package main

import "fmt"

// 無名関数を返却
func GFG() func(i, j string) string {
	myf := func(i, j string) string {
		return i + j + "Golang"
	}
	return myf
}

func main() {
	value := GFG()
	fmt.Println(value("Welcome ", "to "))
}
```

```terminal:output
Welcome to Golang
```
楽天銀行に自動ログインする

### なんか自動ログインがうまくいかない

ということで、

https://www.tampermonkey.net/

を使用して自動ログインをしてみることとしました。

### 想定以上に簡単なスクリプトです。

なんだ、これならできるじゃん、ってほど、簡単です。

```rakuten-bank-autologin.js
// ==UserScript==
// @name        楽天銀行自動ログイン
// @namespace   https://fes.rakuten-bank.co.jp/MS/main/RbS?CurrentPageID=START&&COMMAND=LOGIN
// @version     0.0.1
// @description:楽天銀行自動ログイン
// @author      nano
// @match       https://fes.rakuten-bank.co.jp/MS/main/RbS?CurrentPageID=START&&COMMAND=LOGIN
// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js
// @license     PDS
// @grant       none
// ==/UserScript==

(function() {
    'use strict';
		var url='https://fes.rakuten-bank.co.jp/MS/main/RbS?CurrentPageID=START&&COMMAND=LOGIN',
			form='LOGIN',
			id_name='LOGIN:USER_ID',
			id_value='ログインＩＤ',
			pass_name='LOGIN:LOGIN_PASSWORD',
			pass_value='パスワード';

	document.forms[form].elements[id_name].value=id_value;
	document.forms[form].elements[pass_name].value=pass_value;
    $('.btn-login01 a').click();
})();

```

ちなみに、form.submit(); となっていない理由として
ボタンのリンクにJavaScriptも埋め込まれているために、
それを正しく動作させるためです。

なお

```
https://fes.rakuten-bank.co.jp/MS/main/RbS?CurrentPageID=START&&COMMAND=LOGIN

```
こちらのURLを直接ブックマークに入れるとよいでしょう

### 勢いに乗って楽天カード e-navi の自動ログインも

楽天いじめではなく、むしろ楽天をより快適に利用するためのものです。

```楽天カード自動ログイン.js

// ==UserScript==
// @name        楽天カード自動ログイン
// @namespace   https://www.rakuten-card.co.jp/e-navi/
// @version     0.0.1
// @description:楽天カード自動ログイン
// @author      nano
// @match       https://www.rakuten-card.co.jp/e-navi/
// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js
// @license     PDS
// @grant       none
// ==/UserScript==

(function() {
    'use strict';
		var url='https://www.rakuten-card.co.jp/e-navi/',
			form='indexForm',
			id_name='u',
			id_value='楽天ＩＤ',
			pass_name='p',
			pass_value='楽天パスワード';

	document.forms[form].elements[id_name].value=id_value;
	document.forms[form].elements[pass_name].value=pass_value;
    $('.loginButton').click();
})();
```

### なぜ、Tampermonkeyを使うの？

よく、自動ログインをさせようとするとき

http : // example.com / ? id=xxxx & pass = xxxx
とか

```なにかのHTML.html
<form action=http://example.com/ method="POST">
<input name="id" value="xxx">
<input name="pass" value="xxx">
<input type="submit">
</form>
```
と、いきそうなのですが、

今はセキュリティーの問題で動的に乱数をフォームに入れていたり、
自ドメイン以外では動作しないよう、クロスドメインでの動作を拒否していたりします。

しかし、Tampermonkey なら同一ドメインで動作しますので、気にせず動作します。


### さいごに

残高照会が認証いらずで、すごく楽になりました。
2022/4/14主にITとかセキュリティの記事

「Apache Struts 2」に脆弱性 - 悪用観測ある既知脆弱性の対処不十分で
https://www.security-next.com/135746

ランサムウェア身代金、平均支払額が前年比8割増
https://www.security-next.com/135678

感染増加に便乗？　「偽コロナワクチンナビ」が再来
https://www.security-next.com/135743

「Adobe Acrobat/Reader」に深刻な脆弱性 - アップデートが公開
https://www.security-next.com/135701

au装うフィッシング - 誘導に「Google翻訳」を悪用するケースも
https://www.security-next.com/135708

経済産業省、産業界・経営層に「サイバー攻撃対策の徹底」呼びかけ(4/12)
https://news.mynavi.jp/techplus/article/20220412-2319890/

“サイバー攻撃への対策徹底を” 経産省 企業トップらに求める(4/12)
https://www3.nhk.or.jp/news/html/20220412/k10013577921000.html

パロアルト、2022年度版ランサムウェア脅威レポート公開(4/12)
https://news.mynavi.jp/techplus/article/20220412-2320345/

auを装ったフィッシングメールに注意、Google翻訳に似せた誘導URLも(4/12)
https://news.mynavi.jp/article/20220412-2319919/

スマホで不正アクセスし会社のデータ削除　容疑で佐賀市の女逮捕11日、佐賀県警サイバー犯罪対策課と佐賀南署(4/12)
https://www.saga-s.co.jp/articles/-/838773

Emotet（エモテット）の感染を疑ったら・・・(4/12)
https://www.risktaisaku.com/articles/-/67143

サイバー攻撃に態勢整備を(4/12)
https://jp.reuters.com/article/idJP2022041201000882

中国のサイバー犯罪グループ、VLCのエクスポート機能悪用した攻撃展開か(4/12)
https://news.mynavi.jp/techplus/article/20220412-2319590/

＜独自＞防衛省、サイバー防衛でインフラ事業者支援検討(4/12)
https://www.iza.ne.jp/article/20220412-A7YKCPH4SZKL7MOYCTJEHG2ACE/

牧島デジタル相、多様な人材をセキュリティー人材に車座対話で共有(4/12)
https://dempa-digital.com/article/304429

Twitter詐欺師がAzukiのクリエーターになりすまし、NFTの詐欺(4/12)
https://nextmoney.jp/?p=49547

マイクロソフト、クラウドとソフト契約巡る一部顧客の不満に対応へ(4/12)
https://www.bloomberg.co.jp/news/articles/2022-04-12/RA7EDADWLU6C01

中国政府、大手ネット企業のアルゴリズムを規制へ(4/12)
https://www.zaikei.co.jp/article/20220412/668139.html

Googleアナリティクスの仕組みを知って、アクセス解析でサイトを改善しよう(4/12)
https://webtan.impress.co.jp/e/2022/04/12/42564

露の報復、リスク低減を…米ランド研究所上級政治研究員　サミュエル・チャラップ氏［分析　ウクライナ危機］(4/12)
https://www.yomiuri.co.jp/world/20220412-OYT1T50060/

他のウイルス対策アプリで対処できないマルウエアの除去に助けが必要？SpyHunber 5のHelpDeskはカスタム・マルウエアフィックスを実現(4/12)
https://kyodonewsprwire.jp/release/202204129842

ウェブブラウザー、今最もよく使われているのは？(4/12)
https://japan.zdnet.com/article/35186077/

京セラのプリンタと複合機にデータ窃取の脆弱性、アップデートを(4/12)
https://news.mynavi.jp/techplus/article/20220412-2319895/

インターネット分断とは　ウクライナ侵攻で閉じる世界(4/12)
https://www.nikkei.com/article/DGXZQOUC0543R0V00C22A4000000/

「OpenSSH 9.0」、量子コンピューターを使った攻撃からの保護をデフォルトに(4/12)
https://japan.zdnet.com/article/35186176/

成人年齢引き下げに伴って増大するオンライン上のリスクに注意(4/12)
https://gunosy.com/articles/e21hv

みずほ銀行の失敗に学ぶ(4/13)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/040400287/040400001/

「目的は金銭」と誤認させデータ破壊　ウクライナ侵攻数時間前の攻撃(4/13)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/052100113/033000079/

知られざるプログラミングの常識　なぜ「状態は悪」なのか(4/13)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/052100112/033000037/

東北大、IC設計データに紛れた不正機能を高速に検知する技術を開発(4/13)
https://xtech.nikkei.com/atcl/nxt/news/18/12629/

押さえておきたい無料バックアップソフト、HDDメーカーの独自製品も使える(4/13)
https://xtech.nikkei.com/atcl/nxt/column/18/01980/030900007/
eval-whenの挙動を確認してみた

# eval-whenの挙動を確認してみた

common lispで、eval-whenの使いどころがイマイチぴんときません。
挙動を確認することで、理解が深まるといいなと思います。
処理系はSBCLです。

## REPLで実行してみる
```common-lisp
CL-USER> (eval-when (:execute)
  (print 'execute))

EXECUTE
EXECUTE
CL-USER> (eval-when (:load-toplevel)
  (print 'load-toplevel))

NIL
CL-USER> (eval-when (:compile-toplevel)
  (print 'compile-toplevel))

NIL
```
:executeのみ実行されました。ロードも、コンパイルもしていないので、これはこれで納得です。

## loadしてみる
   eval-when.lispに保存したうえで、ロードしてみます。
```common-lisp
(eval-when (:execute)
  (print 'execute))

(eval-when (:load-toplevel)
  (print 'load-toplevel))

(eval-when (:compile-toplevel)
  (print 'compile-toplevel))

```

```common-lisp
CL-USER> (load "eval-when.lisp")

EXECUTE
T
```

:executeのみevalされました。:load-toplevelがevalされないのは意外です。

## compile-fileはどうか？
同じソースファイルをコンパイルしてみます。
```common-lisp
CL-USER> (compile-file "eval-when.lisp")
; compiling file "eval-when.lisp" (written 14 APR 2022 03:24:19 AM):
; compiling (PRINT (QUOTE LOAD-TOPLEVEL))
COMPILE-TOPLEVEL

; wrote eval-when.fasl
; compilation finished in 0:00:00.001
#P"eval-when.fasl"
NIL
NIL
```
evalされたのは:compile-toplevel。これもまあそうかなという感じ。
ここで:load-toplevelのみがコンパイルされていますね。(3行目)

## コンパイルされたファイルをloadしてみる

```common-lisp
CL-USER> (load "eval-when.fasl")

LOAD-TOPLEVEL
T

```
:load-toplevelがevalされました。これはつまり、:load-toplevelのloadがコンパイルされたファイルのロードであるということですね。

## 小出先生のおっしゃるとおりでした。
以下、小出誠二先生のブログより引用させていただきます。
[PAIP, auxfns.lisp のウォークスルー : セマンティックウェブ・ダイアリー](http://blog.livedoor.jp/s-koide/archives/1877255.html) 
> ここで eval-when はその囲まれたフォームをいつ評価したらよいのかを指定するための特殊形式です．もっぱら用いられるのはこのように，compile，load，eval がすべて並んだものですが，その意味はコンパイル時に評価するか(compile)，コンパイルされた fasl ファイルをロードするときに評価するか(load)，ソースコードを実行時に評価するか(eval) というものです．

> そして compile，load，eval はそれぞれ :compile-toplevel，:load-toplevel，:execute を使うべきとされています．ではそのように直してしまいましょう．コロンをつけることをお忘れなく．
(eval-when (:execute :compile-toplevel :load-toplevel)

以前にも拝見していた記事ですが、手を動かさないと知識として定着しないということですね（反省）
InsufficientInstanceCapacityによって1日中EC2が起動できなかった話


# InsufficientInstanceCapacityとは
EC2やRDSで発生する事象で、特定のAZの特定のインスタンスタイプを起動するために必要な容量がAWSの物理ホスト上で確保できないため発生するエラーです。例えばap-northeast-1aのm4.largeインスタンスが非常に多く利用されていた場合、在庫がないため1aのm4.largeを起動することができなくなります。

対処法としては
・少し時間をおいて起動する(容量が空くまで待つ)
・インスタンスタイプを変更して起動する
・AZを変更して起動する
・キャパシティの予約
・リザーブドインスタンスの購入
などがあります。

# 状況
システムのAWS移行プロジェクトにおいてEC2を複数台使用しており、開発期間中はコスト抑制のためEC2を自動停止・自動起動するLambdaを設定していました。
時期としては環境構築が終わり、インフラのテストを実施し始めた‥というところでした。

# EC2が全然起動しない!
ある朝出社すると、既に起動しているはずのEC2(ap-northeast-1cのt3.xlarge)が停止したままでした。
Lambdaのログを確認してInsufficientInstanceCapacityが原因だと分かったため、EC2管理画面から「インスタンスの開始」ボタンを押し、起動を試見ましたが、何度ボタンを押しても返ってくるのは「InsufficientInstanceCapacityにより起動できませんでした」のエラ〜メッセージのみでした。

テスト期間だったのでインスタンスタイプやAZを変更して起動することはできず、時間をおいてボタンを押すことしか出来ませんでした。Excelが開くのを待っている最中にボタンを押す‥、お昼ご飯を食べている最中にボタンを押す‥と、暇さえあればボタンを押していましたが一向に起動できませんでした。

# 結局
起動できたのは**18:00を回ってから**でした。
おそらく多くの会社で定時を過ぎたことにより使用されていたインスタンスが解放されたのでしょう。
起動できなかったインスタンスに関わるテストは実施できなかったため、もうテスト期間中はEC2を停止しないことに決めました。

# 感想
過去にもInsufficientInstanceCapacityに遭遇したことはありましたが数分時間を置けば起動できていたため、まさか1日中起動できないことがあるとは思っていませんでした。**甘く見ていました**。
今回は開発期間中だったから良かったものの、本番環境で起きたらと思うと恐ろしくなりました。EC2の場合、キャパシティ予約をせずに停止時間を取ることは避けるべきでしょう。
(RDSの場合は下記の記事内容から、そもそも停止時間をとること自体がよくないとのことです。
https://blog.serverworks.co.jp/tech/2019/06/26/stopdbinstance/
)

開発期間は開発期間で進捗遅れにも繋がったりするため、「テスト期間に入ったら1日中稼働させる」などのルールを決めても良いかもしれないです。そのため、開発期間中にかかるAWS利用料は24時間フル稼働すること前提で多めに見積もっておきましょう。
AWS認定クラウドプラクティショナーの勉強方法【AWS初心者】


# はじめに
新卒1年目・AWS初心者でAWS認定クラウドプラクティショナーに合格するまでの勉強方法をまとめました。
これから資格取得を目指す方向けの記事です。

# 受験を決めた当時の自分のスペック
- 新卒1年目エンジニア🐥
- 大学で情報系を専攻していたので、ITの知識はある程度持っている
- AWSに関しては完全に初心者で、入社後に2ヶ月くらい軽く触った程度
（ **Lambda**, **EC2**, **S3**, **CloudWatch**のみ ）

正直、情報系の知識はそこまでなくてもできると思います。
サーバーやデータベースと聞いて大体イメージできるのであればいけそう。


# 勉強期間
2021年8月下旬〜
およそ2週間（平日2時間、休日4時間）
↓↓↓
2021年9月中旬
一発で合格 🙌🏻

点数は控えますが、スコアパフォーマンスというフィードバックを見る限りバランス良くできたと思います。
![Screen Shot 2022-04-13 at 23.16.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1809963/863b3877-51e0-1048-5222-baaf849ec6cc.png)


# 勉強方法
ある程度知識を詰め込めばいけるので、そこまで色々やったわけではありません。

### AWS認定公式
まずは試験ガイドやサンプル問題を見て、試験のイメージを掴んでおきます。
https://aws.amazon.com/jp/certification/certified-cloud-practitioner/

### 参考書で体系的に学ぶ

この参考書は初心者にもやさしい内容なのでおすすめです。
基礎知識を学ぶには充分でした。
[AWS認定資格試験テキスト AWS認定 クラウドプラクティショナー](https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-AWS%E8%AA%8D%E5%AE%9A-%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%BC-%E5%B1%B1%E4%B8%8B-%E5%85%89%E6%B4%8B/dp/4797397403/ref=asc_df_4797397403/?tag=jpgo-22&linkCode=df0&hvadid=295691444786&hvpos=&hvnetw=g&hvrand=1770575054954372273&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009310&hvtargid=pla-718362586207&psc=1&th=1&psc=1)

### Udemyの模試
上記参考書を理解できるようになったら、模試で実際に問題を解いていきます。
7回分ありますが、私は時間がなくて演習テスト1〜4しかできませんでした。
ただ、基本レベルは90％以上、応用レベルは80％以上取れるまで解きました。
本番は応用レベルくらいの難易度に感じたので、これくらいできたほうが安心です。

Udemyは月に数回セールをしているので、セール中に買っておきましょう！
[【CLF-C02版】この問題だけで合格可能！AWS 認定クラウドプラクティショナー 模擬試験問題集（6回分390問）](https://www.udemy.com/course/aws-4260/)

# 受験
試験は、テストセンターor自宅で受験可能です。
私は確実に静かな場所で受験したかったので、テストセンターでの受験を選びました。

Udemyの模試とは違い、本番の試験ではAWSの日本語訳が絶妙に理解しにくいで、試験内容よりもそこのほうが難しかったです。1問ごとに日本語と英語を切り替えられるので、そんなときは英語に切り替えましょう。

試験終了後、画面に合否が表示されます。
2時間後くらいにマイページから結果を確認できました。

# プラクティショナーを取得するメリット
ここで、私が思うプラクティショナー取得のメリットを書いておきます。
- AWSの体系的な知識が効率的に学べる
- AWSからお墨付きがもらえる（証明書やデジタルバッジもあります）
- 多くの企業がクラウドサービスを活用しはじめており、需要が伸び続けている（今最も人気のあるIT資格の一つです）

今後も業務で使う機会が多いので、まずは基礎知識の証明であるプラクティショナーを入社半年で取得できてよかったです。

# おわりに
お読みいただきありがとうございました 🌱

プラクティショナー合格の4ヶ月後に、上位資格であるソリューションアーキテクトのアソシエイト試験（SAA）にも合格しました。こちらも追って記事にしたいと思います。
rshでの遠隔コマンドが実行できない

# 対処法
.rhostsがあるか確認する。なかったら作る。
アクセスがrefuseされるとき
```
systemctl status rsh.socket
```
を実行し、enableかどうか確認する。
動いてなかったら以下のコマンドを実行して解決
```
systemctl enable rsh.socket
systemctl start rsh.socket
```
pythonで複数のPDFファイルを一括で保護解除

複数のPDFファイルの保護を一括で解除するツールを作成したので、ソース公開します。
(python初心者がとりあえず動くもの作っただけなので綺麗なソースではありませんが…)

## 1.ツール作成を思い立った背景
* 公式HPからダウンロードできる国家試験の過去問PDFは大抵の場合が保護付き。
* 学習過程でマーカーを付けたり、ファイル結合や編集を行いたい場面が多々あり、保護が邪魔:worried:

## 2.ツールの目的
* 開催回、科目、問題/解答毎に別ファイルになっているPDFの保護解除を一括で行う
* 1ファイルずつ手作業で保護解除はしたくない:tired_face:

# 3.ツールの仕様
* 実行ツールと同じディレクトリ内のPFDファイルを全て保護解除して保存する
* 動作環境はWindows10
* pythonで作成

## 3.1 ツール実行
1. ツール(exeファイル)を保護解除したいPDFファイルと同一ディレクトリに格納
![before_bulkUnlockPDF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388674/74489afd-0ee9-1344-0ee0-3b972562cab4.png)

2. 実行中の様子
![r_ulkUnlockPDF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388674/0a54dc2d-877b-109c-4108-aca5b1978426.png)"～完了"の文字が出たら[X]ボタンで閉じる

3. フォルダ「unlockPdf」が作成され、配下に保護解除済みPDFが出力された
![after_bulkUnlockPDF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388674/bf41cef5-cae3-bd7e-10fc-eebe94c9c07d.png)
全ファイルが保護解除済み、これでPDFが編集できます:laughing:


## 3.2 ソース

```python:bulkUnlockPDF.py
import os,sys,glob
from pikepdf import Pdf

#カレントディレクトリに出力用のディレクトリ作成(ない場合のみ)
dirNm = "/unlockPdf"
if not os.path.exists(os.getcwd() + dirNm):
    os.makedirs(os.getcwd() + dirNm)

#カレントディレクトリ内のPDFファイルを取得してループ
files = glob.glob(os.getcwd() + "\*.pdf")
for file in files:
	pdffile = Pdf.open(file,password="")
	newPdf = Pdf.new()
	newPdf.pages.extend(pdffile.pages)
	saveFileNm = os.getcwd() + dirNm + "/" + os.path.basename(file)
	#出力済みフォルダに同名ファイルがない場合、PDF保護解除ファイルを出力
	if not os.path.exists(saveFileNm):
		newPdf.save(saveFileNm)
		print(saveFileNm + "を出力しました。")
	else:
		print(saveFileNm + "は既に存在します。")

#終了メッセージ出力
input("PDFの保護解除完了")
```
python実行環境をインストールしておらず、実行ツール(exe)だけ欲しい方はこちら
　　↓↓↓
<a href="https://drive.google.com/file/d/1Bk9FuTd2_S6WKB4gKNc_uXsWXe5hyEa2/view?usp=sharing" download="bulkUnlockPDF.exe">bulkUnlockPDF.exe</a>
　　↑↑↑

# 4.さいごに感想
* かねてから勉強したかったpythonを初めてinstallしてツール作成しました:relaxed:
* python最高～～:heart_eyes: もっと勉強したくなった:hugging:
* あ、、pythonの勉強は目的ではなくて、試験合格が目的でした:joy:...頑張ります…
Timed out waiting for deviceのエラーについて

先日、CentOS7のサーバーが突如ダウンし、緊急モードで起動しました。ログを見てみるとタイトルの通り、Timed out waiting for device...　のエラーが。こいつを直すのに、苦労したので記事を書くことにしました。

結論から話すとエラーの原因は、/etc/fstab内にありました。
OSは起動時にfstabを読んで、ディスクパーティションやブートファイルをファイルシステムにマウントします。
/etc/fstabについては以下の記事の説明がわかりやすいです。

参考記事：[fstabについて](https://qiita.com/kihoair/items/03635447591358210772)

# エラーの原因
私のfstab内ではデバイスをdev_mapper_data等の名前で指定してmountさせていましたが、再起動時にデバイス名がディスクの認識順によって入れ替わることがあります。つまり、違うディスクにマウントされ、マシンエラーが起こります。また、今回エラーを吐いていたディスクが最近増設したHDDだったので、取り分け敏感だったのかもしれません。
# 解決法
**この症状は、デバイス名の代わりにユニークな値であるUUIDを指定することで正しくOSがデバイスを認識してくれます。**
後で調べたらCentOS7では普通UUIDで指定するらしいです。知らなかった...

UUIDは以下のコマンドで確認することができます。
```bash
blkid
```
golangci-lint: exhaustivestruct

備忘録。

構造体のフィールドが全部初期化されているかどうかをチェックしたい場合は[exhaustivestruct](https://github.com/mbilski/exhaustivestruct)が便利。
exhaustivestructを有効化した上でstruct-patternsに構造体が [Path#Match](https://pkg.go.dev/path#Match) に合致するように記載する。
struct-patternsはパッケージ名も含められるので別パッケージで同名の構造体があっても対応できる。

ハマったポイントとして、struct-patternsに指定するのはチェックしたい構造体が定義されているパッケージおよび構造体名を指定する必要がある点。
勘違いしてチェックしたい構造体が呼び出されているパッケージ名を指定しようとしていた。

```go
package exampleA

type Target {
  Hoge string
}

package main

func main() {
  t := Target{}
}
```
上記の場合、struct-patternsには `exampleA.Target` を指定する。

exhaustivestructの使い道としては自動生成される構造体の呼び出し元で定義漏れがないかをチェックする場合
例えばOpenAPIやProtocolBufferを使って構造体を自動生成している場合とかに便利。

# 参考

https://github.com/mbilski/exhaustivestruct
https://golangci-lint.run/usage/linters/#exhaustivestruct
https://pkg.go.dev/path#Match
python3 -m http.serverをCORSにする【Access-Control-Allow-Origin】

```bash
echo "import sys
from http.server import HTTPServer, SimpleHTTPRequestHandler, test

class CORSRequestHandler (SimpleHTTPRequestHandler):
    def end_headers (self):
        self.send_header('Access-Control-Allow-Origin', '*')
        SimpleHTTPRequestHandler.end_headers(self)

if __name__ == '__main__':
    test(CORSRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)" | python3 -- - 8000
```

or

```bash
echo -e "import sys\nfrom http.server import HTTPServer, SimpleHTTPRequestHandler, test\nclass CORSRequestHandler (SimpleHTTPRequestHandler):\n def end_headers (self):\n  self.send_header('Access-Control-Allow-Origin', '*')\n  SimpleHTTPRequestHandler.end_headers(self)\nif __name__ == '__main__':\n test(CORSRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)" | python3 -- - 8000
```

毎回、検索してファイル作成して動かすのめんどくさいのでワンライナーにしてみました

```javascript
const data = await fetch('http://localhost:8000/1.json').then(r=>r.json())
```

### 参考
https://stackoverflow.com/questions/21956683/enable-access-control-on-simple-http-server

Access to fetch at 'http://localhost:8000/1.json' from origin 'https://qiita.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
GET http://localhost:8000/1.json net::ERR_FAILED 200
Uncaught (in promise) TypeError: Failed to fetch
    at <anonymous>:1:1
unity Android でステータスバーの高さを取得する方法


![Screenshot_20220414-002120 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2123950/31cef996-a292-b221-7fd2-2b4968326813.png)

unityでAndroidにビルドする際、コンテンツが隠れないようにするため、ステータスバー（通知とか充電の部分）の高さを取得したいことがあります。
明確な記事がなかったので、その方法を記載しておきます。

# コード

```.cs
#if !UNITY_EDITOR && UNITY_ANDROID   
using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
    using (var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
    {
        using (var window = activity.Call<AndroidJavaObject>("getWindow"))
        {
            using (var view = window.Call<AndroidJavaObject>("getDecorView"))
            {
                using (var rect = new AndroidJavaObject("android.graphics.Rect"))
                {
                    view.Call("getWindowVisibleDisplayFrame", rect);
                    Debug.Log(rect.Get<int>("top"));
                }
            }
        }
    }
}
#endif
```

# 補足

``Debug.Log()`` のところを適当に弄ってください。

単位はピクセルです。`` Screen.CurrentResolution.height `` とかで割ってあげれば、画面に対するステータスバーの割合を取得できるかと思います。
Prisma で Upsert Many はないのか



**ない**です。
updateMany や deleteMany はあるのに・・・
ですが似たようなことを簡単に実現できそうです。

# 結論

公式の例をもとにすると複数の User 情報をまとめて Upsert したい場合は以下のようになるかと思います。

```ts
 async upsertUserMany(userList: User[]):Promise<{count:number}> {

  // map関数でupsertのクエリを複数作成
  const query = userList.map(user => (
      prisma.user.upsert({
        where: {
            email: user.email,
        },
        update: {
            name: user.name,
        },
        create: {
            email: user.email,
            name: user.name,
        },
      })
  ))
  // $transaction APIで同一トランザクションで実行
  const result = await prisma.$transaction([...query])

  return { count : result.length }
}
```

# ちょっと解説

`User[]`型の userList に対し map で複数回の操作を実行し、prismaPromise の query を複数生成します。この時点ではまだ DB に対し更新処理がかかりません。

$transaction で同一トランザクションで複数の upsert を実行、ここでテーブルにたいして操作が行われます。

なお`return {count : result.length} `としているのは公式の[updateMany](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#updateMany)や[deleteMany](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#deletemany)関数の戻り値に似せた作りをしたかっただけです。
実行されたクエリのぶんだけ返却値の要素がありますので、lengthで擬似的に操作したレコードのcountをとることができます。

# $transaction はどういう挙動をとるのか？

`$transaction`で更新クエリがデータベースの同一トランザクション内で実行されます。
アプリケーションが関数の最後に到達すると、トランザクションはデータベースへコミットされます。
仮に処理の途中でエラーが起きると例外ををスローするので、自動的にロールバックがかかります。

# 参考文献

[Transactions and batch queries](https://www.prisma.io/docs/concepts/components/prisma-client/transactions)

[Prisma Client API reference](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference)
AWS Cloud9でPython基礎～ファイルの読み書き

2022/4/6(水)に行われたAWSセミナー「Pythonの基礎から学ぶ!サーバーレス開発はじめの一歩」で学んだPython部分の復習。

# 1.AWS Cloud9セットアップ
Cloud9を起動。適当に名前を付けて他はすべてデフォルト値でCloud9を起動する。

# 2.ファイルの読み書き

## 2-1.Pythonでファイルを読み込む

組み込み関数[open()](https://docs.python.org/ja/3/library/functions.html#open)と[with文](https://docs.python.org/ja/3/reference/compound_stmts.html#with)を使う。

Cloud9上で、以下2ファイルを作成する。

```py:input_text_file.py
def open_input(fileA):
    with open(fileA, 'r') as f:
        textA = f.read() # .read()メソッドを使ってファイルの内容を読み込み
        print(textA) # 読み込んだ内容を変数textに代入
    
open_input("text.txt")
```

```py:text.txt
The quick brown fox
```

Cloud9画面下部のTerminalで`input_text_file.py`を実行する。

```
$ python input_text_file.py 
The quick brown fox
```

`text.txt`の内容を`input_text_file.py`で読み込めた。

### 補足：外部ファイルから入力を取得するときの形式

```py:外部ファイルから入力を取得するときの形式
with open(filename, 'r') as variable_name:
    # variable_name に対しての処理を入力する
```

- `'r'`：読み込み用に開く (デフォルト)
- `'w'`：書き込み用に開き、まずファイルを切り詰める

## 2-2.Pythonでファイルに書き込む

### 2-2-1.新規ファイルを作成し書き込む
Cloud9で以下ファイルを作成する。

```py:write_text_file.py
with open('sample.txt', 'w') as f:
    f.write('This is sample text.') # .write()メソッドを使ってファイルに書き込み
```

Cloud9画面下部のTerminalで`write_text_file.py`を実行する。

```
$ python write_text_file.py
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/4882d02b-757a-2978-7972-2a76422e8f48.png)

`sample.txt`が生成され、内容が書き込まれている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/af4f4771-6959-7c44-bbf6-7be93ca32366.png)

### 補足：外部ファイルに書き込むときの形式

```py:外部ファイルに書き込むときの形式
with open(filename, 'w') as variable_name:
    # variable_name に対しての処理を入力する
```

- `'r'`：読み込み用に開く (デフォルト)
- `'w'`：書き込み用に開き、まずファイルを切り詰める

### 2-2-2.既存ファイルに追記する

組み込み関数 open() のモードを`'a'`に指定して追記する。
- `'a'`：書き込み用に開き、ファイルが存在する場合は末尾に追記する

Cloud9で、以下ファイルを作成する。
（`input_text_file.py`、`write_text_file.py`を参考にする）

```py:write_text_file2.py
def open_input(fileB):
    with open(fileB, 'a') as g:
        g.write(' jumps over the lazy dog.')
        
open_input("text.txt")
```

Cloud9画面下部のTerminalで`write_text_file2.py`を実行する。

```
$ python write_text_file2.py
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/df7f75bb-1e5d-a5aa-ee14-9785db09598b.png)

`text.txt`に、内容が追記されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/1ae443f6-84cc-63e6-ffbe-ef9acebb69dd.png)

# 参考

https://docs.python.org/ja/3/library/functions.html#open

https://docs.python.org/ja/3/reference/compound_stmts.html#with

https://qiita.com/emiki/items/65eb26492be5315d929d

[AWS Cloud9でPython基礎](https://qiita.com/emiki/items/65eb26492be5315d929d)
[AWS Cloud9でPython基礎～ファイルの読み書き](https://qiita.com/emiki/items/f93bddb4a1fd76b102b5)
[AWS LambdaでPython基礎](https://qiita.com/emiki/items/5daa0e31b8a8fa7c680a)
[AWS Cloud9でPython基礎～Amazon S3を利用する](https://qiita.com/emiki/items/7433971c9f1ee03dd9ea)
[AWS Cloud9でPython基礎～Amazon S3とAmazon Translateを利用する](https://qiita.com/emiki/items/b95fad815d9f8e360dd0)
[AWS LambdaでPython基礎～Amazon S3とAmazon Translateを利用する](https://qiita.com/emiki/items/0f9bbddd6f4cd475f12b)
60秒遅延なしでシャットダウンする方法【Ubuntu 22.04 Jammy Jellyfish】

# 電源ボタンを押したときに即時パワーオフ

```bash
gsettings set org.gnome.SessionManager logout-prompt false
```
シャットダウン
```bash
gnome-session-quit --power-off
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/42019255-c283-f3f5-b3df-8610489420b4.png)


### 参考
https://www.reddit.com/r/pop_os/comments/nwphr2/disable_60_seconds_delay_for_shutdown_restart/
C++ 競プロのためのTipsまとめ

### 想定読者

- AtCoderで 茶〜水 程度
- C++使い

### 目的

- 知らなくても支障はないものたちだけど、使えると便利だから貯めていく！(随時更新)

### 参照渡しで、入力値を配列に楽に入れる

- 参照渡しをすると、配列に簡単に値を取り込める
- 特に、複数の配列があり、それぞれ長さが異なるときに便利！
- ref: [物理好きさんのABC246の解説](https://atcoder.jp/contests/abc246/editorial/3702)

```cpp
// 一度適当な変数を経由して入れる例
for (int i = 0; i < n; i++) {
    int tmp; cin >> tmp;
    a[i] = tmp;
}
```

```cpp
// おすすめのやり方
for (auto &x : a) cin >> x;
```

### 配列の初期化方法

- 空の配列を初期値にすると、 0 や false で初期化できる！
- ref: [C++の配列を宣言したときの初期値は0なのか？
](https://teratail.com/questions/168427)

```cpp
int a[n] = {}; // 0で埋められる
bool b[n] = {}; // falseで埋められる
```

### 行受け取り

- 例えば "B G R" を、3つの char ではなく、1行の文字列でまとめて受け取れる
- ref: [tatyamさんのABC244Dの解説](https://atcoder.jp/contests/abc244/editorial/3594)

```cpp
string s;
getline(cin, s);
```
コマンドプロンプトで`cd -`を再現してみる(doskey)

`pushd`と`popd`をうまく使えばいい話ではあるのかもしれないけど、普段の`cd`の代わりにとなるとめんどくさかったので...  
あと「Linuxだと`cd -`というのが便利らしいぞ」というのは耳にしていたので、ちょくちょくLinux環境も触りたいと思っていたのもありUNIX風のに慣れるという意味もあります  

## 前準備
どこかしらにdoskey.txtや.doskeyなど適当な名前でエイリアスを設定するためのファイルを置いておきます（ここでは`%USERPROFILE%\doskey.txt`）  
このファイルにdoskeyの書式で記述することによりエイリアスを設定することができます  

私はAlacrittyをメインで使っているので、（中で動いてるのはcmd.exe）次のような内容を`%appdata%\alacritty\alacritty.yml`にいい感じに書き加えます  
コマンドプロンプトを直で触ってる方は[この記事](https://qiita.com/RoaaaA/items/694ae4ccfa4a69fc8286)なんかが参考になるかもしれません（レジストリからAutoRunを設定する必要がある）  

```yaml
shell:
  program: cmd
  args:
    - /k;doskey /macrofile=%USERPROFILE%\doskey.txt # /k;init.bat（柔軟性を持たせたい場合に別途作成して代わりにする）
```

## 設定
doskey.txtに以下のような内容を書き足します  
```bat
cd=if "$1"=="" (pushd %USERPROFILE%) else if "$1"=="-" (popd) else (pushd $*)
```

`doskey /macrofile`はどうやら一行ずつしかパースできないようなので、一行にまとめてあります  

バラしてやるとこうです  
```bat
if "$1"=="" (
	pushd %USERPROFILE%
) else if "$1"=="-" (
	popd
) else (
	pushd $*
)
```
引数がなければcdを`%USERPROFILE%`に移動し、引数が`-`なら（つまり`cd -`なら）popd、つまり一つ前のディレクトリに戻ります  
それ以外ならば普通に引数をとってpushdします（doskey内では引数を取る際の`%`が`$`になります）

一応同じような感じでbatとして使えなくもないでしょうが、どうせ`cd`として使うにはdoskeyからエイリアスをはる必要があるのでこのぐらいなら直接書いちゃってもいいんじゃないかなぁ、と思います  

通常コマンドプロンプトでは引数を指定せずに`cd`を実行するとカレントディレクトリが得られますが、それが使えないと不便なので[^1]doskey.txtに以下のような内容を書き加えるとよいでしょう  
```
pwd=cd
```

### Q.ふつうのcdを使いたい場合にはどうすればよいですか？
doskeyのエイリアスは行頭に該当文字がある場合にしか機能しないようなので、一応`@cd`とすればもともとのコマンドが起動できます  
```
C:\>cd /?
（エイリアス側で指定したpushdのヘルプ内容...）
C:\>@cd /?
（cdのヘルプ内容...）
```

### Q.pushdはよくわからないので使いたくないです（お前cdじゃないだろ案件）
多少長くはなりますが、このような案もあります：  
```bat
cd=if "$1"=="" (set oldpwd=%cd% & cd %USERPROFILE%) else if "$1"=="-" (set oldpwd=%cd% & cd %oldpwd%) else (set oldpwd=%cd% & cd $*)
```

バラシ：
```bat
if "$1"=="" (
	set oldpwd=%cd%
	cd %USERPROFILE%
) else if "$1"=="-" (
	set oldpwd=%cd%
	cd %oldpwd%
) else (
	set oldpwd=%cd%
	cd $*
)
```

一つしか巻き戻せないですしいちいちsetしてるのがナンセンスぽくはありますが、Git Bashで試してみた感じこちらの方がオリジナルの動作に近くはあるのかもしれないですね  

ちなみに、`/macrofile`内では`$t`や`^&`などの記法を使わず素直に`&`でいいっぽいです  

試しに以下のようなものをdoskey.txt内に記述してみますと、私環境ではコマンドプロンプトくんが「More? More? More?」などと意味不明なことをのたうち回りやがります（処理自体はする）  
謎だ...（わりと恐怖体験だった）  

追記：`(`と打ってEnterするとそれらしき感じになる（More?というプロンプトが一生出続ける）ので、多分カッコ周りがおかしくなってるんだと思われます  
```bat
cd=if "$1"=="" (set oldpwd=%cd% $t cd %USERPROFILE%) else if "$1"=="-" (set oldpwd=%cd% $t cd %oldpwd%) else (set oldpwd=%cd% $t cd $*)
```

## 感想
かなりべんり（だと思う）  

## 参考
[WindowsのDOS窓でls叩いたらdirして欲しい、ほか - Qiita](https://qiita.com/kfjt/items/a51fa60eb8f568f16a58)  
[【 cd 】コマンド／【 pwd 】コマンド――カレントディレクトリを変更、表示する：Linux基本コマンドTips（167） - ＠IT](https://atmarkit.itmedia.co.jp/ait/articles/1712/14/news021.html)  


[^1]: 一応`echo %cd%`したりはできますが
【GCP】Cloud Buildトリガーで困った話メモ


GCPのCloud Buildを使って、Githubのリポジトリへのプッシュをトリガーに、自動ビルドしてGAEにdeployする流れを作ろうと思ったら、色々苦労したところがあったので、メモを残す。


# (1)そもそもリポジトリに接続できない

Source RepositoriesでGitHubのリポジトリを選んで「選択したリポジトリを接続」を押しても、1分くらいぐるぐる待ったあとに「リポジトリに接続できませんでした」というエラーメッセージが出てくる。
Private Repositoryだからダメなのか？と思ってPublicを選んでみても同様。
どうすりゃいいんだよと思っていたところ、とりあえず空っぽのリポジトリを1つ新規に作成すれば、内部的な何かのフラグがONになって接続できるようになるらしいとのことで。
実際、空リポジトリつくったあとは同様の操作で接続できた。
これGCPのバグでは。。。

# (2)トリガーが動かない

GitHubにpushしてもトリガーが起動しない。
トリガーを手動で実行したところ **Couldn't read commit** というエラーメッセージ。

これは、Cloud Buildのトリガーの画面で「リポジトリを接続」していなかったから。
以下スクショの赤枠から操作する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392942/a9492709-bf9e-df3f-111b-d146ffbb7128.png)

この操作後、トリガーの設定画面で、リポジトリの項に「GitHub」とは別に「GitHubアプリ」というのが選べるようになる。
これを選択してトリガーを作る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392942/ace58b23-e738-f419-8b5b-61d9eda14f0b.png)

# (3) Permission errors

## (3)-1. Permission 'cloudbuild.builds.create' denied

**generic::permission_denied: goa-auth: Permission 'cloudbuild.builds.create' denied on resource 'projects/1234567890abcdef' (or it may not exist)** というエラーが発生。（ `projects/1234567890abcdef` の部分は変えてあります）
とりあえずCloud Buildの管理権限つければいいのかと思い、トリガーの実行Service Accountにロールを付与した。
そしたらまた別のエラーが発生

## (3)-2. if 'build.service_account' is specified, ...

**generic::invalid_argument: generic::invalid_argument: if 'build.service_account' is specified, the build must either (a) specify 'build.logs_bucket' (b) use the CLOUD_LOGGING_ONLY logging option, or (c) use the NONE logging option** というエラーが発生。
「トリガーを実行するService Accountは(a)か(b)か(c)のログ権限のいずれかだけ持ってりゃいい」ということのようで、平たく言えば「余分な権限もちすぎ」だと怒られているようだ。
これは実際その通りで、トリガーを実行するService Accountを個別に指定していて、かつそのService Accountがかなり色々できる強い権限をもったService Accountだったからだった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392942/ff2b4c89-8f8d-d25b-fcfe-1245b938e2a9.png)

ここを意図的に選択した場合、上記のように厳密なPermissionのチェックがかかるようだ。
未指定の場合は **[projectid]@cloudbuild.gserviceaccount.com** というService Accountが使われるらしいので、特に理由がない限りは、トリガーの実行Service Accountは指定せず、デフォルトのService Account  **[projectid]@cloudbuild.gserviceaccount.com** にロールを付与していった方が良い。
というわけでこの枠を未指定にし、デフォルトのService Accountで実行してもらうように変更。
ついでに、IAMの設定画面でこのService Accountに「App Engineデプロイ担当者」のロールを付与。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392942/a2a0ebda-6727-a146-b31d-f9b884af85c2.png)


最後にまた別のエラーが発生。。。

## (3)-3. You do not have permission to act as ...

**You do not have permission to act as '[project name]@appspot.gserviceaccount.com'** というエラーが発生。
これは[こちらの記事](https://uyamazak.hatenablog.com/entry/2021/02/22/135431)が参考になった。
トリガーの設定で「App Engine」と「Service Accounts」を有効にする。


# おわりに

なかなか大変な作業だった。。。
GitHubにpushさえすれば、あとはビルド・デプロイまでいい感じでやってくれる他のPaaS系サービスを触っていると、なんという面倒くさい作業なのだと感じる部分は、正直ある。
まあでも構築できてしまいさえすれば後は楽なものなので。
このメモを屍として残すことで振り返りは終わりにする。
ラズパイでSoftEtherのインストール

ラズパイにsoftetherのインストールしたので備忘録としてまとめます。
# 準備
```
sudo apt update -y && sudo apt upgrade -y
```

# インストール等
```
sudo apt install -y software-properties-common
sudo apt-add-repository ppa:paskal-07/softethervpn
sudo apt install -y softether-vpnserver
sudo systemctl start softether-vpnserver
sudo systemctl enable softether-vpnserver
```
# 起動の確認
```
sudo systemctl status soft*
● softether-vpnserver.service - SoftEther VPN Server
     Loaded: loaded (/lib/systemd/system/softether-vpnserver.service; enabl>
     Active: active (running) since Wed 2022-04-13 16:23:50 BST; 5min ago
    Process: 2337 ExecStart=/usr/libexec/softether/vpnserver/vpnserver star>
   Main PID: 2339 (vpnserver)
      Tasks: 32 (limit: 16777216)
        CPU: 6.525s
     CGroup: /system.slice/softether-vpnserver.service
             ├─2339 /usr/libexec/softether/vpnserver/vpnserver execsvc
             └─2340 /usr/libexec/softether/vpnserver/vpnserver execsvc

Apr 13 16:23:49 raspberrypi systemd[1]: Starting SoftEther VPN Server...
Apr 13 16:23:50 raspberrypi vpnserver[2337]: The SoftEther VPN Server servi>
Apr 13 16:23:50 raspberrypi systemd[1]: Started SoftEther VPN Server.
```
docker compose で起動したコンテナ内での pytest 実行時に breakpoint で止める

# はじめに
web sever の実行時に breakpoint で止める方法を書いた記事はたくさん見かけます。
しかし、dokcer compose したコンテナ内での  pytest 実行時に breakpoint で止める記事は見かけず、苦労したので書きます。
(test code に break point を置いた場合の話です)

# 確認した環境
- macOS Big Sur 11.6.1
- Visual Studio Code Version: 1.59.0
- Docker Desktop 4.3.1.
- Docker Engine v20.10.11

# 実践
## ローカルでのステップ
- VsCodeからコンテナに attach するための extension を install する
    - https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
- docker compose up でアプリケーションの dev コンテナ を起動する
- VsCode の左端の緑部分をクリック
    - ![スクリーンショット 2022-02-03 23.43.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110482/0fde984a-2652-6f4c-0062-cdef8ea13a11.png)
- Attach to Running Container... を選択
    - ![スクリーンショット 2022-02-03 23.46.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110482/6fe13023-9e4b-2d47-469e-399485212cb5.png)
- attach できるコンテナの一覧が出るので、 アプリケーションの dev コンテナを選択する
    - 選択するとリモートコンテナコンテナに入れる

## リモートコンテナ(アプリケーションの dev コンテナ)内のステップ
- リモートコンテナの中身が新しく VSCode 
- [公式の debug 記事](https://code.visualstudio.com/docs/editor/debugging) に記載のある VsCode の debugger 機能を含む extension を install する
    - https://marketplace.visualstudio.com/items?itemName=ms-python.python
    - リモートコンテナの中に必要
- VsCode のエクスプローラーで以下を確認する
    - テストコードが存在すること
    - アプリケーションのコードが存在すること
    - .vscode フォルダ内に launch.json が存在すること
- launch.json の configurations 項目を確認する
    - name : 任意 (ここでは exec pytest)
        - 後で debug を開始する際の名称になる
    - request : launch
    - module : pytest

``` launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Module",
            "type": "python",
            "request": "launch",
            "module": "pytest",
            "args": [
                "tests"
            ]
        }
    ]
}
```

- vscode の下バーのインタプリタ設定項目が remote コンテナのインタプリタになっていることを確認する
    - ![スクリーンショット 2022-02-04 0.14.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110482/b4a1a011-b54c-99d4-9c8e-ab4fc38af03c.png)
- pytest 実行時に止めたい場所に break point を置く
    - test code に break point を置きます
- 左メニューの debug をクリックする
    - ![スクリーンショット 2022-02-04 0.10.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110482/fb244e15-9d9e-1c4a-fa8d-ef0aff372052.png)
- 下記ボタンを押して pytest が実行される
    - ![スクリーンショット 2022-02-04 0.12.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110482/a643196e-53e5-a5ba-9ebd-61bb39641dce.png)
- break point で止まってくれるはずです (あとはよしなに debug してください)
- お疲れ様でした!!
Node.jsでリバースプロキシを書いた


# リバースプロキシとは
インターネットにてリクエストをほかのサーバの代わりに受けて（代理：proxy）他のサーバへ中継してくれるサーバ
![rproxy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638607/dc2ba0c7-bf6d-fa20-d710-f856e41a5f9e.png)

# なぜわざわざNode.jsで書くのか
ふつうはNginxを使う。
今回は小規模な自分用サーバのために使うので、ほかの機能で使っているnode.js
にまとめて載せられると便利だと思い書いた。

# コード
https://github.com/wonderhorn/nodegate

ポイント
- [http-proxy](https://github.com/http-party/node-http-proxy)を使う、プロキシもリバースプロキシもこれでできる
- http-proxyのバグでPOSTが通らないのでヘッダをいじる：https://github.com/wonderhorn/nodegate/blob/master/gate.js#L35
node.jsの仕様上jsonが壊れるケースがあるらしく、stringifyしなおす
- 応用：エンドポイントによって飛ばす先を変える
これで同一サイト内の一部機能だけ別のサーバに持たせたりできる
https://github.com/wonderhorn/nodegate/blob/master/gate.js#L61

# 動作
中継しない例：https://wonderhorn.net/
自分のサイト・静的コンテンツを配信している

他のサーバに中継する例 https://wonderhorn.net/ipaddress
ここではCMANさんのipアドレスチェッカーに中継しているが、ipアドレスが
クライアントではなく中継サーバのものになっている点に注目
中継が成功しているということである
【Laravel】取得した配列が空かどうかを判別し、空の場合メッセージを返すメソッド

## 1. confirmEmptyArrayメソッド 
```App/Lib/MyFunc.php
<?php

namespace App\Lib;

class MyFunc 
{
    public static function confirmEmptyArray($array, $empty_message)
    {   
        if (empty($array)) {
            return $empty_message;
        } else {
            return $array;
        }   
    }
}   
```

## 2. 使い方
```App/Controllers/HomeController.php
<?php

namespace App\Http\Controllers;

use App\Lib\MyFunc;　

class HomeController extends Controller
{
    public function *** {
        $array = Model::where()-> ...略...->get()->all();

        $array = MyFunc::confirmEmptyArray($array, '空です');
    }
}
```
WSL2 のメモリー上限を設定する

docker for WindowsでOracleDBを作成したらメモリが食いつぶされてしまったので、その対策。

# .wslconfig

* https://docs.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig

`%USERPROFILE%\.wslconfig`に下記内容を書き込む

```ini
[wsl2]
memory=2GB
```

スクリプトなら

```
echo [wsl2]>> "%USERPROFILE%\.wslconfig"
echo memory=2GB>> "%USERPROFILE%\.wslconfig"
```

OSかWSLを再起動して適用。
Qiita初投稿完全ガイド

　　
　　
　　
この投稿を読めば誰でもQiitaに投稿できるようになれます。
　　

# はじめに
プログラミングを勉強し始めQiitaという便利なサイトに出会い、自分も投稿しようと考えたがTwitterで投稿するようにはいかないのが分かりまとめることにした。

ここまで書くのにも`マークダウン記法`・`行間`・`見出し`の知識・技術が必要になる。
ちなみにここまで書くのにも自分は1時間ほど時間を使ってしまっている笑

# 文章を書く
Qiitaはマークダウン記法という形式で文章を書かなければならない。
マークダウン記法とはHTML（HyperText Markup Language）などのマークアップ言語を、簡略化できるようにプログラムされたものである。
要はHTMLの簡略版である。
HTMLほどではないが一定のルールがある　＝　ルールを学ぶ必要がある。
とはいっても簡単なルールなので安心してほしい。

## マークダウン記法
「日本語マークダウンユーザー会」では、マークダウン記法の特徴を以下にまとめている。

>① 手軽に文章構造を明示できること
② 簡単で、覚えやすいこと
③ 読み書きに特別なアプリを必要としないこと
⓸ それでいて、対応アプリを使えば快適に読み書きできること

>引用元：日本語Markdown「ユーザー会Markdownとは」

Qiitaでなくても使用されている記法である。
実際にQiitaで使用するであろうルールを紹介する。

### 見出し
`半角#`と`半角スペース`を記入することで見出しを作ることができる。
見出しの大きさは#の数によって変わる。

>例
#　1見出し
##　2見出し
###　3見出し
…
######　6見出し

# 1見出し
## 2見出し
### 3見出し
…
###### 6見出し

`※見出し行に下線が自動的に付くのは##2個まで`
### 行間
行間を空けるのにもルールがある。
1行空けるのであればいつも通りの改行でいいのだが複数行空ける時は空白を2つ作らなければならない。

○○（○　＝　　スペース）
○○

↑2行空ける場合の図

### 引用
引用を使用する場合は >

### 強調
半角 ` （Pの横のキー）で囲む

## ソースコード記入
```
このようにコードを記入する場所
```
の設定の仕方を解説する。

>例　Rubyで出力する場合
半角`（Pの横のキー）×3つ　 + ｒｂ
puts hello
半角｀（Pの横のキー）×3つ

```rb
puts 'hello'
```

## おわりに
以上が必要最低限のQiita文章作成ガイドである。
基本的には一般的なマークダウン記法であるが一部Qiita専用記法もあるみたいなので適宜調べてみてほしい。

ぐっばい

## 引用
https://qiita.com/kenbu/items/46103d5c595d468f3c82
https://qiita.com/Qiita/items/e84f5aad7757afce82ba
https://backlog.com/ja/blog/how-to-write-markdown/
https://qiita.com/shizen-shin/items/a997bc228fa2850c9fce#%EF%BC%97markdown%E3%81%A8%E3%81%AF

## 追記
4/14 15:40追記
マークダウンの書き方は投稿欄やコメント欄の右上にある「？」をクリックすると表示される。
この記事は初投稿者向けに簡略にまとめたものです。
以下ガイドラインやサポートを一読して文章作成に入ろう。

コミュニティガイドライン | Qiita Support
https://help.qiita.com

良い記事を書くためのガイドライン | Qiita Support
https://help.qiita.com

Qiita Support
https://help.qiita.com
Docker, Jupyter-notebookでCirqを使った量子計算の学習

Macで確認しましたが、WindowsでもLinuxでもDockerが使える環境なら使えると思います。

適当なディレクトリを作って、

```shell
mkdir cirq && cd cirq
```

適当なテキストエディタでdocker-compose.ymlを作る。

```yaml:docker-compose.yml
version: "3.8"
services:
  cirq-notebook:
    image: sanori/cirq-notebook:latest
    volumes:
      - ${PWD}/:/home/jovyan/work
    ports:
      - 8888:8888
    container_name: cirq-notebook
```

下の様にコンテナを立ち上げると、

```shell
docker-compose up
```

こんなのが出てくるので、

```shell_session
cirq-notebook  | [C 2022-04-13 10:34:08.350 ServerApp]
cirq-notebook  |
cirq-notebook  |     To access the server, open this file in a browser:
cirq-notebook  |         file:///home/jovyan/.local/share/jupyter/runtime/jpserver-9-open.html
cirq-notebook  |     Or copy and paste one of these URLs:
cirq-notebook  |         http://[何か英数字列]:8888/lab?token=[何か英数字列]
cirq-notebook  |      or http://127.0.0.1:8888/lab?token=[何か英数字列]
```

`http://127.0.0.1:8888/?token=[何か英数字列]`の箇所を選択し、URLとしてブラウザで開きます。
Jupyter Notebookが立ち上がるので、後はこのサイトを見て学習

https://qiita.com/s_zh/items/bb5c14d21f4dcbcf5426

とは言え、上の記事はバージョン`'0.3.1.35'`によるもの、こちらで使っているイメージ`sanori/cirq-notebook:latest`は`'0.14.0'`なので、元記事のコードは一部変更が必要です。変更箇所は多いですが、種類としては下の4種です。

```diff_python
# Create a circuit
- circuit = cirq.Circuit.from_ops(
+ circuit = cirq.Circuit(
-    cirq.RotXGate(half_turns=0.2)(qubit),
+    cirq.ops.XPowGate(exponent=0.2)(qubit),
    cirq.measure(qubit, key='m')  # Measurement.
)
```

```diff_python
# Simulate the circuit several times.
- simulator = cirq.google.XmonSimulator()
+ simulator = cirq.Simulator()
result = simulator.run(circuit, repetitions=200)
```

```diff_python
qubit = cirq.GridQubit(0, 0)
# Create a circuit
- circuit = cirq.Circuit.from_ops(
+ circuit = cirq.Circuit(
    cirq.H(qubit),  
    cirq.measure(qubit, key='m')  # Measurement.
)

print("Circuit:")
print(circuit)
```

```diff_python
# Simulate the circuit several times.
simulator = cirq.google.XmonSimulator()
result = simulator.simulate(circuit)

- result.final_state
+ result.final_state_vector
```

:::note warn
ただし、上の変更が元の`0.3.1.35`と同等と言えるかは確信はありません。
:::
基本情報技術者試験対策　30日目

基本情報技術者試験勉強　30日目
-
この記事の目的
-
今年の5月に基本情報技術者試験を合格するために、過去問で間違えた箇所をただまとめる自分のための記事

プロフィール
-
・文系大学の３年生
・ITパスポートは保有
・ウェブアプリやサイト作成を個人で行ったことがある程度
・猫好き

今日の目標
-
午前問題を50問解き、10問以内に間違えを抑える。

間違った箇所
-
1、2相コミット
トランザクションのコミットを次の２つの段階に分けて行うことで、分散データベース環境でのトランザクションの原始性、一貫性を保証する

2、レインボー攻撃
想定され得るパスワードとハッシュ値との対のリストを用いて、入手したハッシュ値からパスワードを効率的に解析する

3、リストラクチャリング
企業が事業規模に合わせて組織を再編成する

4、インクリメンタルモデル
基本的なシステムアーキテクチャの上に機能の優先度に応じて段階的に開発

振り返り
-
今日は午前問題を50問取り組んだが、結果として、43問正解することができた。2進数から16進数への変換や論理和、論理積といった問題で間違うことが多い。あとは、初めて聞く問題や語句で間違える。次回も引き続き、テクノロジ系の問題をメインに80問解き、解答時間も1問1分程度で取り組む。

>引用
基本情報技術者試験ドットコム
https://www.fe-siken.com
Oracle Database 21c Express Edition の docker イメージを作る

# 環境

* Windows 10
* Docker Desktop for Windows


# 準備

1. [Oracle Database 21c Express Edition for Linux x64 ( OL8 )](https://www.oracle.com/jp/database/technologies/xe-downloads.html) をダウンロード
2. 適当なディレクトリにダウンロードしたファイルと下記ファイルを配置

ファイル構成
```
oracle-database-xe-21c-1.0-1.ol8.x86_64.rpm
setup.sh
setup.bat
```

## setup.sh
注: 改行コードをLFにする必要がある。

```bash
#!/bin/sh
set -euxo pipefail

# bashを追加
apk add --no-cache bash

# 一時ディレクトリにoracle/docker-imagesをcloneして、あらかじめダウンロードしたファイルと合成
git clone https://github.com/oracle/docker-images.git /tmp/oracle-docker-images
cp -r /tmp/oracle-docker-images/* /docker-images/
rm -rf /tmp/oracle-docker-images

# dockerイメージを作成
/docker-images/OracleDatabase/SingleInstance/dockerfiles/buildContainerImage.sh -v 21.3.0 -x
```

## setup.bat

```bat
docker run ^
    --name "oracle-image-setup" ^
    --rm ^
    -v "%~dp0setup.sh:/setup.sh:ro" ^
    -v "%~dp0oracle-database-xe-21c-1.0-1.ol8.x86_64.rpm:/docker-images/OracleDatabase/SingleInstance/dockerfiles/21.3.0/oracle-database-xe-21c-1.0-1.ol8.x86_64.rpm:ro" ^
    -v "/var/run/docker.sock:/var/run/docker.sock" ^
    -it ^
    docker:20-git ^
    /bin/sh -c "/setup.sh;/bin/sh"
```

※ バッチファイルにする必要はないが、volumeは絶対パスにする必要があるためバッチファイルの方が楽。

# dockerイメージを作成
setup.batを実行する。完了するまで1343秒（約23分）かかった。

```shell
$ docker images
REPOSITORY                       TAG                      IMAGE ID       CREATED         SIZE
oracle/database                  21.3.0-xe                62896fbfa980   4 minutes ago   6.53GB
```

# dockerイメージを保存
そのまま使う場合は不要。

```shell
docker save oracle/database:21.3.0-xe -o ./oracle21xe.tar
```

# docker-compose
```yaml
services:
  oracle21xe:
    container_name: oracle21xe
    image: oracle/database:21.3.0-xe
    restart: unless-stopped
    volumes:
      - oracle21xe-data:/opt/oracle/oradata
    ports:
      - 1521:1521

volumes:
  oracle21xe-data:
```

```shell
docker-compose up -d oracle21xe
```

これまた初期化に時間がかかります。12分程度。

# パスワード設定
初期パスワードはランダムなので、パスワードを初期化する必要がある。

```shell
docker exec oracle21xe /opt/oracle/setPassword.sh PASSWORD
```

# 参考資料
* https://github.com/oracle/docker-images/tree/main/OracleDatabase/SingleInstance

# おわり
Oracleもう少し小さくなってほしい。
link_toとform_tagのデフォルトメソッドについて。

## 結論

```link_to```  メソッド -> ```GET```メソッドがデフォルト。
```form_tag```メソッド -> ```POST```メソッドがデフォルト

### link_toメソッド
下記のようなroutes.rbメソッド違いの同じURLが存在する時、postメソッドのURLにリンクするためには```{method:"post"}```が必要です。（```{method:"post"}```がないと、getメソッドのパースにリンクされてしまう。）  

```routes.rb
post "posts/:id/destroy" => "..."
get "posts/:id/destroy" => "..."

```
```show.html.erb
<%= link_to (”destroy",”/posts/#{@post.id}/destroy),{method:"post"}) %>
```    

### form_tagメソッド
form_tagメソッドですと、```post "posts/:id/destroy" => "..."```にデータを渡すためには、引数にmethodを指定する必要はありません。
下記のコードで渡すことができます。
```
<%= form_tag('/posts/#{@post.id}/destroy') do %>
  <div><%= submit_tag 'Save' %></div>
<% end %>
```

### なぜ？

```link_to```メソッドも```form_tag```メソッドも同じくURLを扱うメソッドなのに、なんで```link_to```のみ```{method:"post"}```が必要かが、学習する際に、疑問でした。
それで、railsのgit hubを参照すると、  
#### ```link_to``` メソッドの説明
>==== Options  
 <tt>method: symbol of HTTP verb</tt> ...
...
      #   Note that if the user has JavaScript disabled, the request will fall back
      #   to using GET ....

methodのオプションでJavaScirptが無効になっている場合は、Getメソッドを使用することになる。と書いてます。

#### ```form_tag```メソッドの説明
>The method for the form defaults to POST. 
...
<tt>:method</tt> The method to use when submitting the form, usually either "get" or "post".
      #   If "patch", "put", "delete", or another verb is used, a hidden input with name <tt>_method</tt>
      #   is added to simulate the verb over post.

formのデフォルトメソッドはPOSTだと書いています。
そして、メソッドがサブミットするときはpostが:methodオプションのhiddenインプットとして追加されるとなってます。


## 終わりに
学習をしていく上で'なぜ？'と思うときは、まずその言語のソースコードを読んでみることが大事だと教わりました。
今回はメソッドのデフォルトがGETやPOSTになっているからこういう動きをします！という簡単な内容でしたが、
ブログの検索しても出なかった内容が、ソースコードを読むことですぐに解決できましたので、ソースコードを読む習慣が大事だと実感したいい経験でした。

読んでくださってありがとうございました。