OmniAICreator/Qiita-1.07M huggingface dataset:
goroutineでバックグランドタスク実行する例


####背景####
以下のことをgoroutineで実現したいです。つまり、メインスレッドでFibonacci計算ではなく、goroutineでバックグランド計算したいです。

![スクリーンショット 2021-12-30 14.35.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/fa722258-c61d-18c0-2647-cc4d4a6c460f.png)

####例1####

```golang
func main()  {
	endChannel := make(chan int)
	go backgroundTask(endChannel)
	<- endChannel // main goroutineを終了させるまで、endChannelの補填を待ち
}

func backgroundTask(endChannel chan int) {
	fmt.Println("background running...")
	fmt.Println("result: ",calculate(45))
	endChannel <- 1
}

func calculate(n int) int{
	if n < 2 {
		return n
	}
	return calculate(n - 1) + calculate(n - 2)
}
```

####例2####

```golang
func main()  {
	endChannel := make(chan int)
	go backgroundTask(endChannel)
	for _ = range endChannel {

	}
}

func backgroundTask(endChannel chan int) {
	fmt.Println("background running...")
	fmt.Println("result: ",calculate(45))
	endChannel <- 1
	close(endChannel)
}

func calculate(n int) int{
	if n < 2 {
		return n
	}
	return calculate(n - 1) + calculate(n - 2)
}
```

####例3####

```golang
func main()  {
	endChannel := make(chan int)
	go backgroundTask(endChannel)
	for {
		_,ok := <- endChannel
		if !ok {
			break
		}
	}
}

func backgroundTask(endChannel chan int) {
	fmt.Println("background running...")
	fmt.Println("result: ",calculate(45))
	endChannel <- 1
	close(endChannel)
}

func calculate(n int) int{
	if n < 2 {
		return n
	}
	return calculate(n - 1) + calculate(n - 2)
}
```


####例4####

```golang
func main()  {
	endChannel := make(chan int)
	go backgroundTask(endChannel)
	for {
		select {
			case <- endChannel:
				return
		}
	}
}

func backgroundTask(endChannel chan int) {
	fmt.Println("background running...")
	fmt.Println("result: ",calculate(45))
	endChannel <- 1
	//close(endChannel) // case<-endChannelの処理はfor分を終了してあるから、closeしなくても良いです。
}

func calculate(n int) int{
	if n < 2 {
		return n
	}
	return calculate(n - 1) + calculate(n - 2)
}

```


####例5####
```golang
func main()  {
	wg := sync.WaitGroup{}
	wg.Add(1)
	go backgroundTask(&wg)
	wg.Wait()
}

func backgroundTask(wg *sync.WaitGroup) {
	fmt.Println("background running...")
	fmt.Println("result: ",calculate(45))
	wg.Done()
}

func calculate(n int) int{
	if n < 2 {
		return n
	}
	return calculate(n - 1) + calculate(n - 2)
}
```

###まとめ###

バックグランドで動いているgoroutineをメインgoroutineから待つ必要があるため、専用なendChannelを用意するか、sync.WaitGroupでコントロールするかという二つの案があります。
さらに、endChannelをメインgoroutineから待つ方法はfor文、for range文、<- endChannel、for select分、という四つの案があります。
zsh-completionsの"insecure directories"が消えなかった時の対処

## 概要

M1 Macbook Airを買ったので、環境構築している際に発生した話。

zsh-completionsはzshの補完を強化してくれる機能だが、インストール時にちょっとつまづいたのでメモ。

https://github.com/zsh-users/zsh-completions

## brewからインストール

```bash
brew install zsh-completions
```

するとこんな表示が出ます。

```
To activate these completions, add the following to your .zshrc:

#
# Executes commands at the start of an interactive session.
  if type brew &>/dev/null; then
    FPATH=$(brew --prefix)/share/zsh-completions:$FPATH

    autoload -Uz compinit
    compinit
  fi

You may also need to force rebuild `zcompdump`:

  rm -f ~/.zcompdump; compinit

Additionally, if you receive "zsh compinit: insecure directories" warnings when attempting
to load these completions, you may need to run this:

  chmod -R go-w '/opt/homebrew/share/zsh'
```

## 指示に従って操作

### 1. ~/.zshrcに表示されたスクリプトをコピペ

vimなど適当なエディタを開いて、以下を`~/.zshrc`に貼り付け

```
  if type brew &>/dev/null; then
    FPATH=$(brew --prefix)/share/zsh-completions:$FPATH

    autoload -Uz compinit
    compinit
  fi
```

### 2. 表示されたコマンドを実行

```
❯ rm -f ~/.zcompdump; compinit
zsh compinit: insecure directories, run compaudit for list.
Ignore insecure directories and continue [y] or abort compinit [n]? y
```

ディレクトリが安全じゃないと怒られますが、yを押します。

### 3. 上記のエラーを消す

`"zsh compinit: insecure directories"`が表示されたら、`chmod -R go-w '/opt/homebrew/share/zsh'`を実行してねとあるので、実行します。

```
❯ chmod -R go-w '/opt/homebrew/share/zsh'
```

### 4. .zshrcをリロードしてチェック

1.の手順で書き込んだ.zshrcの内容を読み込みます

```
❯ source ~/.zshrc
```

すると以下のメッセージが

```
zsh compinit: insecure directories, run compaudit for list.
```

**手順通りにやったのに消えてない！！**

## 原因：chmodで権限変更するディレクトリが違った

```
zsh compinit: insecure directories, run compaudit for list.
```

このメッセージを見る限り、compauditで安全でないディレクトリが見られるようです。

```
❯ compaudit
There are insecure directories:
/opt/homebrew/share
```

先ほど`chmod`で権限変更したパスは`/opt/homebrew/share/zsh`だったので、これが原因のようです。
3.で叩いたコマンドを以下に変更して実行します。

```
chmod -R go-w '/opt/homebrew/share'
```

すると、

```
❯ source ~/.zshrc
（なにも表示されない）
```

無事、警告が消えてくれました。

各種バージョンによって権限変更するディレクトリが異なるっぽいので注意ですね。


## 環境

* Macbook Air (M1,2020, 16GB RAM）
* zsh 5.8 (x86_64-apple-darwin21.0)
* zsh-completions 0.33.0_1
Gstreamer Write Pluginビルド手順

# Write Pluginビルド手順
GstreamerのPlugin作成のTutorialを参考しましが、サイトに記載されていないわなはここで記述します。

# gst-template1.18 取得
## 1.ソース取得
以下のリンクから1.18ソースを取得します。

      https://gitlab.freedesktop.org/gstreamer/gst-template  

## 2.ソース修正（重要）
gitコマンドからgst-template取得する場合、ビルドのscript中にgstreamerバージョンチェックがあります。これを修正しないとビルドでエラーになります。ビルドscriptファイルを手動で修正が必要です。

meson.buildにバージョン修正３箇所があります。「1.19.0.1」を自分のgstreamerバージョンに合わせて修正してください

    /gst-template/meson.build/meson.build 

1. `project('gst-template', 'c', version : '1.19.0.1', license : 'LGPL')  `
2. `gst_dep = dependency('gstreamer-1.0', version : '>=1.19.0.1', ` 
3. `gstbase_dep = dependency('gstreamer-base-1.0', version : '>=1.19.0.1',  `

Cファイル名の修正

    /gst-template/gst-plugin/meson.build  

gstmyfilter.cに合わせて、小文字と大文字注意'src/gstMyFilter.c',  

## 3.ビルド  
gst-template1.18/README.mdに従ってビルド実行  

1. gst-template-1.18に移動します
2. 以下のコマンドを実行

        meson builddir
        ninja -C builddir

3. `gst-template-1.18\builddir\gst-plugin`
4. `/usr/local/lib/gstreamer-1.0/`にsoインストール

        sudo cp -i ./builddir/gst-plugin/libgstplugin.so /usr/lib/x86_64-linux-gnu/gstreamer-1.0/


pluginファイル  

    builddir/gst-plugins/src/libgstplugin.so  

## 4.plugin中身の確認
`gst-inspect-1.0`コマンドでpluginを確認する

    gst-inspect-1.0 libgstplugin.so

OK：pluginの情報が表示  
NG：エラーメッセージ  

## 5.plugin動作の確認

    gst-launch-1.0 -v -m fakesrc ! "plugin名前" ! fakesink silent=TRUE
    「I'm plugged, therefore I'm in.」出力

# 参考
1. https://gstreamer.freedesktop.org/documentation/plugin-development/basics/boiler.html?gi-language=c
Obsidianの小技その5｜ノートコンポーザでノートの一部を切り出す

### はじめに

つねに開きっぱなにしているMarkdownメモツール[Obsidian](https://obsidian.md)。1年ぐらい使ってみたので、ストレスフリーに近づける、いいかんじの小技をご紹介してみます。

### ノートコンポーザ機能をつかう

#### どういうときにつかうか？

ファイルAが長くなってきて、一部をファイルBに切り出したいとき。

たとえばネコについて書いていたが、途中でじいさんのことに脱線してしまい、べつのノートにわけておいたほうがいい、とおもった。とか。

#### 動きのながれ

まずはノートを書きます。そして、切り出したい部分を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/379af834-28e4-9485-33d0-556faa1bdf0c.png" width=60%>

`command + P`を押して、コマンドパレットを表示します。コマンドパレットの一番上に`ノートコンポーザ:現在の範囲を抽出...`があるので（[後述](#コマンドパレットにピン留めする)）、選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/d2631284-21b0-abda-ce0c-5cf16f53c225.png" width=60%>

切り出し先のファイル（ファイルB）の名前を指定します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/fded2f06-f1e8-dd23-671e-640a5913bd7f.png" width=60%>

切り出し元（ファイルA）には、内部リンクだけが残っています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/e07b1960-8910-7475-d6ec-114c0f96eb65.png" width=60%>

切り出し先（ファイルB）には、切り出し元がどこか、いつ切り出しがおこなわれたかが記録され、つづいて切り出した内容がコピーされます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/173cb20e-d5cc-eeea-acf5-e105825ed2fb.png" width=60%>

### ノートコンポーザを便利につかう設定

#### ノートコンポーザをONにする

`設定（歯車アイコン） > オプション > コアプラグイン > ノートコンポーザ`
をONにします。

#### コマンドパレットにピン留めする

`設定（歯車アイコン） > プラグインオプション > コマンドパレット > コマンドの新規ピン留め`
で、`ノートコンポーザ: 現在の選択範囲を抽出...`を追加します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/75039965-c036-73f2-0b05-c32dbc6b1218.png" width=60%>

これを追加しておくと、`commmand + P`でコマンドパレットを呼んだとき、いちばんうえに`ノートコンポーザ: 現在の選択範囲を抽出...`があらわれます。

#### テンプレートを書き、指定する

新規ノートを作成し（たとえば`yymmdd_ノートコンポーザ`）、テンプレートを書きます。

```markdown
--
from: [[{{fromTitle}}]]
at: ({{date:YYYY-MM-DD}} {{time:HH:mm}})

{{content}}
```


`設定（歯車アイコン） > プラグインオプション > ノートコンポーザー > テンプレートファイルの場所`
で、いま作成したノートの名前を、テンプレートファイルとして指定します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/db440e28-3c63-1da8-a456-fe78efc573dc.png" width=60%>

こうしておくと、切り出し先のノートに、自動的に

```markdown
--
from: [[211230_吾輩は猫である]]
at: (2021-12-30 11:51)

（以下、切り出した内容）
```

などと、切り出し元のファイル名や、切り出した日付を挿入してくれます。

### 操作再掲

ややこしそうに見えますが、いちど設定してしまえば、あとは

1. 範囲を選択
1. `command + P`→`enter`

でノートの切り出し完了です🎉

## おわりに

いいメモアプリ（ノートアプリ）がありがたいのは、

- とりあえず書き始められること
- あとで加工がかんたんなこと

だとおもいます。あとは

- 日付・時刻情報がかんたんに（もしくは自動で）記入できること

ではないかと。

Obsidianには、コアプラグイン（標準機能）にノートコンポーザがあります。これとテンプレート機能をうまく組み合わせれば、「とりあえずどこかにノートを書き始めて」「ある程度アウトプットできた後に、ノートやコンテンツの置き場所を柔軟に変える」ことができます。

「いまこの瞬間に考えるべきことが少ない」メモツール（ノートツール）があると、ストレスフリーな人生にちょっとでも近づけるのではないかとおもっています。

### ご参考

[Obsidian｜使いかたとコツ（目次）](https://qiita.com/hann-solo/items/ac8fa75394813e8adcf4)
ubuntu20 LAMPP phpmyadmin 

LAMP
```

# ufw(ファイアウォール)をインストール
sudo apt install ufw

# インストール直後はufwはファイアウォールとして指定されないためufwを有効化「このコマンドを実行するとssh接続が切れるかも知れませんがいいですか？」と聞かれるので y を入力してEnter
sudo ufw enable

# sshのポートを開く
# これを行わないとssh切断したあと接続出来なくなってしまいます！
sudo ufw allow 22

# Apacheが使用するポートを開く
sudo ufw allow 80

```

sudo vi LAMPP.sh

```
sudo apt-get install -y php
sudo apt-get install -y php-intl php-mbstring php-mysql php-gd 
sudo apt-get install -y php-curl php-common php-json php-mbstring php-zip php-tokenizer
sudo apt-get install -y php-fpm　
sudo apt-get install -y php-xml 
sudo apt-get install -y mysql-server
sudo apt install -y python3-pip
sudo apt install -y sqlite3
sudo pip3 install -y uwsgi
sudo apt-get install -y python3-dev default-libmysqlclient-dev
sudo apt-get install -y python3 python3-pip 
sudo pip3 install mysqlclient
sudo apt-get install -y sqlite3
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo aptitude install npm
sudo apt install -y nodejs
sudo apt-get install -y apache2
sudo apt install -y apache2 wget unzip 
sudo pip3 install  mysqlclient
sudo apt-get install python3-dev default-libmysqlclient-dev
sudo pip3 install uwsgi
```
sudo chmod u+x LAMPP.sh
sudo ./LAMPP.sh


apache2

```
#インストールが完了したら、Apache Webサーバーを有効にして起動します。
sudo apt-get install libapache2-mod-php
sudo apt-get install apache2
sudo systemctl enable apache2
sudo systemctl restart apache2

#Ubuntu 20.04 に phpMyAdmin をインストールします。
#抽出アーカイブをダウンロードした後、適切な場所に移動します。
sudo apt install phpmyadmin
sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-available/phpmyadmin.conf
sudo a2enconf phpmyadmin.conf
sudo systemctl reload apache2.service
sudo systemctl restart apache2

```
設定したユーザーとパスワードでログインできます。

http://IP/phpmyadmin/index.php
LaravelのcommandでUser以外のDBデータをEloquentで取り出せない件

## TL;DR
Laravelは便利なもので、php artisan hogehoge ってコマンドを簡単に作れます。
これを利用して定期実行させたりもできて使っているのですが、、

**User以外のmodel呼び出しでeloqunet使えない！！！**

結局、インジェクションのリスクが少ない箇所だったので、直接SQL叩いて解決しました。```DB::select(DB::raw())```

# 症例

例えば

app/Console/Commands/HogeCommand.php

```php
    public function handle()
    {
        $users=User::get();
        //色々な処理
        return Command::SUCCESS;
    }

```

これは出来るわけです。

でも、このユーザーに紐付いた日記テーブル(diaries)から値を取ろうとすると


```php
    public function handle()
    {
        $users=User::get();
        $diaries=Diary::get();
        //色々な処理
        return Command::SUCCESS;
    }

```

ここでの$diariesは空のオブジェクトになります。
もちろんデータは入っていまして、Controllerとかで呼び出す分には正しく動きます。

```php
    public function handle()
    {
        $users=User::with('diaries')->get();
        //色々な処理
        return Command::SUCCESS;
    }

```

withを使って呼び出してもdiariesの情報は手に入りません……空になります。

エラーも出ていないのが厄介なところです。

# 考察

Laravel素人なので詳しいことは分かりませんが。WordPressのテーマ制作に似たような症例があります。
>functions.phpにおいて記事の情報(タイトルやACFのget_fieldなど)は引っ張ってこれるがカテゴリなどのタクソノミーの情報(get_termsなど)は引っ張ってこれない。

これと同じく、command実行時点ではuser以外のmodel情報はまだ読み込まれていないのかもしれません。

# 一時的な解決策

**SQLの直打ち**

SQLインジェクションの危険があるため、お気をつけてください。
commandでの利用だとそこまで危険性がないので、私はこの方法を取りました。

例

```php

 $counter=DB::select(DB::raw("select count(*) as counter from ".$table." where user_id=".$user_id));

```

原点回帰という訳です。
【Ruby のまずいコード】引数の扱い

# お題

引数として文字列の配列が与えられたとき，それらをハイフンで繋いだ文字列を返すメソッドを書いてください。
配列の要素はすべて文字列であると仮定して構いません。
ただし，要素は空文字列の可能性があり，これを除いたものだけをハイフンで繋ぎます。

つまり，以下のような動作をするものとします：

```rb
p join_with_hyphen(["foo", "bar", "", "baz"])
# => "foo-bar-baz"
```

（メソッド名が英語として妥当でない気がしますが，英語が苦手なのでよく分かりません。得意な方は教えてください）

# コード

```rb
def join_with_hyphen(strings)
  strings.delete("")
  strings.join("-")
end
```

# 問題点

このメソッドはお題のとおりに動作します。
しかし，引数のオブジェクトを破壊的に変更しているのは非常に悪い流儀です。残念ながらこういうコードをよく目にします。

`join_with_hyphen` を呼び出す側では，与えた実引数を他の目的にも使うかもしれません。
その場合，オブジェクトを勝手に変化させられると困るのです。
これは分かりにくいバグの原因になります。

```rb
def join_with_hyphen(strings)
  strings.delete("")
  strings.join("-")
end

ary = ["foo", "bar", "", "baz"]

p join_with_hyphen(ary)
# => "foo-bar-baz"

p ary.length
# => 3 （えっ?!）
```

# 改善

原則として，メソッドは与えられた引数に対して破壊的な操作を行うべきではない，と（初心者のうちは）覚えておきましょう。

今回のお題については [Enumerable#grep_v](https://docs.ruby-lang.org/ja/3.0.0/method/Enumerable/i/grep_v.html) を使って

```rb
def join_with_hyphen(strings)
  strings.grep_v("").join("-")
end
```

とすればいいでしょう。

一般に，

```rb
def foo(arg)
  # なんとかかんとか
end
```

というメソッドで，`arg` が指しているオブジェクトを加工して結果を得たいというとき，非破壊的メソッドを使えばいいのですが，破壊的メソッドを使う必要がある場合は

```rb
def foo(arg)
  arg = arg.dup # 複製を作る
  arg.some_destructive_method # 破壊的操作
  # なんとかかんとか
end
```

と書くことができます。

さて，与えられた文字列に対してさまざまな変換を順次施す，ということがよくあります。このようなとき，すべて非破壊的メソッドを使って

```rb
def foo(str)
  str.downcase
    .tr(chars1, chars2)
    .gsub(r1, s1)
    .gsub(r2, s2)
    .gsub(r3, s3)
    .gsub(r4, s4)
end
```

のように書くこともできますが，メソッドチェーンの中で次々と String オブジェクトが出来て，それら中間のオブジェクトがすべてガーベジ[^garbage]になってしまいます。
たいがいそれで問題無いのですが，`foo` が多数回呼ばれ，`str` が非常に巨大な文字列であるような場合は望ましくありません。

[^garbage]: 永久に参照されることのないオブジェクト。

破壊的メソッドを用いれば無駄なオブジェクトの増加が避けられますが，`String#dup` を用いずとも

```rb
def foo(str)
  str = str.downcase
  str.tr!(chars1, chars2)
  str.gsub!(r1, s1)
  str.gsub!(r2, s2)
  str.gsub!(r3, s3)
  str.gsub!(r4, s4)
  str
end
```

のように最初だけ非破壊的メソッドを使えばいいと思います。

# 余談

この記事の「コード」節で掲げたコードは，**うっかり**引数を破壊した例でした。
しかし，引数の破壊的変更を意図したメソッドを設計することはあります。

組込みライブラリーでいうと，例えば [ObjectSpace.#count_objects](https://docs.ruby-lang.org/ja/3.0.0/method/ObjectSpace/m/count_objects.html) が該当します。
これは存在するオブジェクトを種類ごとに数えて，その結果をハッシュとして返すメソッドなのですが，このメソッドの実行によってハッシュが増えてしまうことを防ぐために，結果を格納するハッシュを引数で与えることができるようになっています。
シェルスクリプトを使う際、文字列が空の時にエラーで返すようにしたい。

例えば、`rm -rf ${STR}/`とスクリプトを書いた時に`${STR}`が空だったら大惨事世界大戦になるのでそれを防ぎたい。

### 現状確認

以下のようにしていると、`${STR}`が空の時でもエラーとならない

```bash:test.sh
#!/bin/bash                                                                                                                                                                                                 

STR="test"
unset STR

echo ${STR}/
```

```
$ bash test.sh

```

### 変数展開

以下の`${STR:?}/`のようにシェルスクリプトの変数展開を用いると、`${STR}`が空の場合にエラーを返す

> [【シェル芸人への道】Bashの変数展開と真摯に向き合う](https://qiita.com/t_nakayama0714/items/80b4c94de43643f4be51)

```bash:test.sh
#!/bin/bash                                                                                                                                                                                                 

STR="test"
unset STR

echo ${STR:?}/
```

```
$ bash test.sh
test.sh: line 6: STR: parameter null or not set
```

### シェルの設定を変更

変数が多い時、エラー処理として全ての変数に変数展開を用いるのは大変なので、シェルの設定を変更したい。
`set`コマンドで、設定していない変数があったらエラーとする。
`set -u`をスクリプトのはじめに付ければ良いだけでとてもシンプル。

> [【 set 】コマンド――シェルの設定を確認、変更する](https://atmarkit.itmedia.co.jp/ait/articles/1805/10/news023.html)

```bash:test.sh
#!/bin/bash                                                                                                                                                                                                 

set -u
# set -euo pipefail 指定でよく使われる
#   -e errexit: パイプやサブシェルで実行したコマンドが1つでもエラーになったら直ちにシェルを終了する
#   -u nounset: パラメーター展開中に、設定していない変数があったらエラーとする（特殊パラメーターである「@」と「*」は除く）
#   pipefail パイプラインの返り値を、最後のエラー終了値（0以外で終了した際の値、全ての実行が成功した場合は0）にする

STR="test"
unset STR

echo ${STR}/
```

```
$ bash test.sh
test.sh: line 6: STR: unbound variable
```

`set -euo pipefail` 指定でよく使われる。当分はこれを使うことにします。
（新規作成の場合はこれで良さそうだが、スクリプト保守時は`set -u`を加えた際の影響範囲が大きいかもしれないので、変数展開と使い分ける。）

# 参考
[【シェル芸人への道】Bashの変数展開と真摯に向き合う](https://qiita.com/t_nakayama0714/items/80b4c94de43643f4be51)
[シェルスクリプトマナー](https://kitsunetanukidashi.hatenablog.com/entry/2014/07/12/231833)
[【 set 】コマンド――シェルの設定を確認、変更する](https://atmarkit.itmedia.co.jp/ait/articles/1805/10/news023.html)
【AWS】Auto Scalingグループで新しいEC2インスタンスの起動を無効化する設定を行う

#はじめに
Auto ScalingグループのAuto Healingの設定を解除する方法について色々と調査した為に備忘録も兼ねて記事にしております。先日、ALB配下にEC2インスタンスを紐付けて更にAuto Scalingを設定して色々と試しておりましたが、料金を見ると中々のお値段だったので、なるべく起動設定などは変更せずに、せめてEC2インスタンスだけは全て停止させておきたいな、と感じて調べてみました。

目的としては、起動しているEC2インスタンスはそのままの起動状態となりますが、停止した、もしくは停止させた場合に新しくインスタンスを起動させないようにしたい、というようなものになります。

#一部のインスタンスをAuto Scalingから外す場合
もし特定のEC2インスタンスをAuto Scalingグループの管理下から外す場合、EC2インスタンスのデタッチを行い、再度Auto Scalingグループの管理下に戻す場合は、対象のEC2インスタンスをアタッチすることになると思います。その場合は以下説明が参考になると思います。

[Auto Scaling グループからの EC2 インスタンスのデタッチする](https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/detach-instance-asg.html)

[Auto Scaling グループに EC2 インスタンスをアタッチする]
(https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/attach-instance-asg.html )

#全てのインスタンスをAuto Scalingの管理下から外したい
ところが全EC2インスタンスを管理下から除外するとなると少し面倒です。簡単に設定を変更して、Auto Scalingの管理下から外したい場合はヘルスチェックプロセスを停止することで実現出来るようです。

仕組みとしてはAuto Scalingグループにはプロセスの一時停止機能が提供されており、一時停止するプロセスで"Health Check"を指定します。その結果、EC2インスタンスおよびALBのヘルスチェックの結果として、インスタンスがUnhealthyとマークされなくなるようです。詳しくは以下ユーザーガイドをご参照ください。

[中断の選択 ~ Auto Scaling グループのプロセスを一時停止および再開する](https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/as-suspend-resume-processes.html#choosing-suspend-resume)

#実際の設定画面
実際に設定すると以下の様になります。

**①Auto Scalingグループの選択**
コンソール画面の「EC2」から「Auto Scaling グループ」を選択し、対象のグループのチェックボックスにチェックを入れます。
![as1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691200/e8672f98-0f6d-a135-f6a3-4d151444df32.png)
**②Auto Scaling設定の編集画面を開く**
「Auto Scaling グループ」ページの下部に分割ペインが開かれるので「詳細」タブの下部にある、「高度な設定」欄の「編集」をボタンを押します。
![as2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691200/f0aadff4-6ebf-3c35-6d74-ed3f5ac5bb65.png)
**③中断プロセスの設定**
高度な設定の中で「中断されたプロセス」欄のプルダウンリストから、「Health Check」を選択します。
![as3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691200/0090b0c4-2595-5edc-9d8f-d88bd70e140c.png)
**④確認と後進**
「Health Check」が指定されていることを確認したら「更新」ボタンを押下します。これで設定は完了です。
![as4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691200/9c87170d-c471-f15e-624f-b50f3ae4a9fc.png)
実行中のEC2インスタンスを停止させても新たなインスタンスは起動されないはずです。

#まとめ
AWSで自宅学習を行っている方、また規模の小さい事務所で手探りで構築を勧めている方などはEC2インスタンスの費用が気になる為にこまめに落としておきたいものの数日後には元に戻したい、ということもあるかと思います。そんな時は結構お世話になるかもしれません。
ResXManagerを使用して多言語対応を行う

## 0. はじめに
Visual Studioで多言語対応が必要なアプリケーションを開発する際、**ResXManager**という拡張機能が便利そうだったので、使用方法などを簡単にまとめてみました。
**ResXManager**は、各言語リソースファイルを開かなくとも、専用の画面で言語キー(文字列)を参照/追加/更新/削除できる機能になります。

## 1. ResXManagerをダウンロードする
Visual Studioメニューの「拡張機能 > 拡張機能の管理」から、**ResXManager**をダウンロードします。
※ダウンロード後、変更を反映するため、Visual Studioの再起動が必要かと思います。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/bac3814e-7662-ac36-c0ab-41d5d61a4c97.png)

## 2. 言語リソースファイルを追加する
まずは準備として、ソリューションエクスプローラーコンテキストメニューの「追加 > 新しい項目」からリソースファイルを作成します。
名前は何でもいいですが、私は「Strings.resx」としました。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/3051352a-eb57-3490-d03a-42f640d0cf9f.png)

## 3. ResXManagerを使ってみる
Visual Studioメニューの「ツール > ResX Manager」を選択すると、ResX Resource Managerが起動します。

### 3-1. デフォルトの言語を変更する
Configurtionタブの「Netural Resouces Language」から、デフォルトの言語を変更できます。
元々は英語になっているかと思いますので、日本語に変更しました。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/95b1c1c6-9e89-8db8-aebc-9849dfecd995.png)

### 3-2. 言語を追加する
Mainタブの「Add new language」から、言語を追加できます。
今回は英語・フランス語を追加してみました。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/bf2215f4-ea7a-7547-d83e-504ad9f86822.png)

対応するリソースファイル(Strings.en.resx、Strings.fr.resx)が自動で生成されます！
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/709d93ac-0912-435d-cf83-5fee063dad27.png)

### 3-3. キー(文字列)を追加する
「Add new key」から、キー(文字列)を追加できます。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/f3a0fa37-373e-a73c-08ce-f8fa360204d5.png)

文字列を追加しない場合は、赤塗りで表示されます。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/cf95075e-67fe-e5c5-02ee-cb34f1892f46.png)

### 3-4. キー(文字列)を削除する
「Delete selected items」から、キー(文字列)を削除できます。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/53b1936a-04c5-5234-081d-b6641eac9cf8.png)

## 4. 出力してみる
```C#
class Program
{
	static void Main(string[] args)
	{
		// 日本語
		Console.WriteLine(Strings.HelloWorld);

		// 英語
		Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
		Console.WriteLine(Strings.HelloWorld);

		// フランス語
		Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr-FR");
		Console.WriteLine(Strings.HelloWorld);
	}
}
```

![w.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/b7583614-9f05-b36c-6f70-cac048f0bbac.png)

## 5. おわりに
- 「〇〇言語に〇〇キーの文字列が設定されていない！」ということにすぐ気づけるのでとても便利ですね:innocent:(今回この拡張機能を使おうと思ったきっかけがコレでした)
- 私が必要としていた機能は上記に記載した範囲でしたが、他にも「キー(文字列)のコピー/ペースト」「エクセルへのインポート/エクスポート」 といったことが行えるみたいです:innocent:
Pythonでソースコードファイルのディレクトリ位置を指定して外部ファイルをロードする方法

Pythonの開発の際、私はVisual Studio Code を使うことが多いのですが、その際、デバッグ実行しようとすると、実行時のカレントディレクトリの位置のせいで、外部ファイルが読み込めないということがたまに発生します。
（私の場合、特に、ワークスベース内にディレクトリ分けしてソースを作っているからですねー💦）

そういうことにならないために、ソースコード上に明示的に、ソースコードのディレクトリ上の位置を書きたいとこなのですが、ベタでフルパスで書くという方法はファイルの場所が変わったときや配布することを考えると望ましくはありません。なので、動的にその場所を取得する方法を紹介しておきます。

こんな感じで、テキストファイルを読み込んで出力するだけのプログラムを適当に書いてみます。

![画像の貼り付け先_ 2021-12-30 12-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/99dee702-0a96-c57a-ca60-f1c3817f6d20.png)

Visual Stukio Codeの実行ボタン（または、デバッグ実行ボタン）をクリックすると案の定、こんな感じで「FileNotFoundErrr（ファイルが存在しないことを示すエラー）」になります。
そりゃそうですよね。実行時のカレントディレクトリの場所に読み込むファイルがないためです。

![画像の貼り付け先_ 2021-12-30 12-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/3bdc823a-0508-3004-6d47-4f1bf169f29c.png)

そこで、ソースを↓のように書き換えるわけです。

```python:testBase.py
import os
dirname =  os.path.dirname(__file__)

test_data = open(dirname + "/hoge.txt", "r")

for i in test_data:
  print(i)

test_data.close()
```

これは何をしているのかというと、ソースコードファイルの場所を取得して、それを基準にファイルを指定するようにしているのです。
**「\_\_file\_\_」**は、ソースコードのファイルを示す予約後で、「os.path.dirname(str)」関数を使うことで、ソースコードファイルのあるディレクトリを取得するという意味になります。

![画像の貼り付け先_ 2021-12-30 12-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/cae39480-0c97-0aad-9c2a-14082440333a.png)

これで、問題なく、ファイルが見つかってファイルの内容が表示できるわけですね。
めでたしめでたしー:clap::clap::clap::clap:

【補足】
ついでに補足ですが、、
↓のソースを実行してみると。。

```python:test01.py
import os

# カレントディレクトを取得
print('getcwd:      ', os.getcwd())
# ソースコードファイルのパスを取得
print('__file__:    ', __file__)
# ソースコードファイルのファイル名のみを取得
print('basename:    ', os.path.basename(__file__))
# ソースコードファイルのディレクトリのみを取得
print('dirname:     ', os.path.dirname(__file__))
```

```:実行結果
getcwd:       H:\Project\PythonTest
__file__:     h:\Project\PythonTest\Base\test01.py
basename:     test01.py
dirname:      h:\Project\PythonTest\Base
```

以上です。こういうのって割と便利なので、覚えておきましょー。
何かの参考にしていただければ幸いです。
sam localで起動したLambdaにProfileを当てて起動する

# TL;DR

* `sam local start-lambda --profile [profile-name]`
* `[profile-name]`に割り当てたRoleを指定したprofileを指定して起動すると、lambdaにもprofileを渡してくれる
* `AWS_PROFILE=[profile-name] sam local start-lambda`でもいい
* profileはAWS CLI `(.aws/config, credentials)` で設定するものと同一
* 普通にコマンドラインで起動時にprofileを指定しているのであれば、samの時も同様に指定してあげること

# 背景

* SAM CLIで作成したアプリ内で、AWS SDKを使ってAWSから情報を取得なりして応答するAPIを作成していた
* 一旦デバッグ目的で直接起動して動作確認はできたけど、`sam local start-api`経由だとRoleが渡ってなかったやんどう渡すやんこれ...

#　やってた内容
## コード

```python
import boto3
import json


def lambda_handler(event, context):
    result = main()

    return result

def main():
    cli = boto3.client('ec2')
    result = cli.describe_instances()

    return result


if __name__ == '__main__':
    main()
```

みたいなコードで情報を取得して、API GW経由で結果を返すAPIを作成しようとしていた

## そのまま実行
```bash
AWS_PROFILE=kono-profile python kono_code.py
```

直接実行時はProfileを指定してた

## SAM CLI経由で実行
```bash
sam local start-api
```

何も気にせずこれで実行すると、`default` profileに目的のものが設定されていなければ`InvalidClientTokenId`とかで怒られる

直接実行時と同じようにprofileを指定してあげると、コンテナ内のlambdaにもprofileの情報を渡してくれるよう
StandardSetControllerクラスとは

## StandardSetControllerクラス
複数のレコードを分割して管理できるクラス。
分割セットを自由に切り替えられるので、ページネーションによく使われるイメージ。

## 基本的な使い方


```
//1. インスタンス作成
List<Account> accList = [SELECT Name FROM Account];
Apexpages.StandardSetController ssc = new Apexpages.StandardSetController(accList);

//2. インスタンスの状態を変える
ssc.setPageSize(5); //1セットに格納するレコード数を指定
ssc.Next();         //次のレコードセットに切替

//3. インスタンスから値を取得する
List<Account> accResults = ssc.getRecords(); //現在のレコードセットを取得
```

実際は↑みたいな書き方をする場面は少ない。
実践的なサンプルコードは[こちら](https://qiita.com/xQIEBo4zFWKZ0ig/items/0f10af8424ac0b24b756)

## インスタンス化のパターン
1.sObjectのリストを渡す

```
//公式docsより引用
ApexPages.StandardSetController ssc = new ApexPages.StandardSetController(accountList);
```


2.クエリロケータ（Database.getQueryLocator）の返り値を渡す

```
//公式docsより引用
new ApexPages.StandardSetController(Database.getQueryLocator([SELECT Name,CloseDate FROM Opportunity]));
```


### 1と2の違い
レコード数の上限（10000）を超えた時の動きが違う。
 sObjectのリスト：上限を超えたら切り捨てられる
 クエリロケータ：エラーが起こる（Limit Exception）
 

## おまけ：インスタンスをSystem.debugで出力してみる
`
public with sharing class pagination {
    public pagination() {
        List<Account> aList = [SELECT id FROM Account];
        Apexpages.StandardSetController ssc = new Apexpages.StandardSetController(aList);
        System.debug(Logginglevel.WARN,ssc);
    }
}
`

### 結果
`
ApexPages.StandardSetController[Account]
`


## 参考文献
- https://developer.salesforce.com/docs/atlas.ja-jp.230.0.apexcode.meta/apexcode/apex_pages_standardsetcontroller.htm
エンジニアとして一年と少し経ったので、やらかした事をまとめてみる。

# やっぱり失敗しちゃいますよね？
+ stackoverflow, Qiita記事のコピぺ
+ エラーを解決できずに、数時間死にたくなる
+ ゴミコードを書いてしまい、デバックで苦労する。などなど。

こんにちは！新米エンジニアのりゅうです。今日から、新年の抱負の一つである、エンジニアとしてのスキル、知名度をあげる。それを達成するためのto doとして、キータ記事の週一更新をやっていこうと思います（まだ、新年ではないのにフライングしている事はすみません笑）

記念すべき、第一投稿としましては、僕がエンジニアとして働いていた中での失敗点を列挙させていただきます。

# 技術的な失敗
## 1. チュートリアルやstackoverflow記事のコピぺ
エンジニアなら一度は経験があると思う **コピペ**

問題点
+ コードを説明できない。
+ エラーが発生した時に、なぜエラーになったのかわからない。
+ コピペしたので、コードの書き方、意味を憶えない。同じ課題に直面した時にまた調べないといけない。

改善点
+ ライブリー、フレームワークを使用する時は一度公式のdocumentをしっかりと読む。
+ エラーが発生した時にstackoverflowなどで解決策をしらべるのはいいが、なぜ、それがエラーになったのか、どのように解決したのかをしっかりと理解する。

## 2. 雑なエラーハンドリング、ログを残さない。
独自エラーの作成が一番めんどくさくないですか？

問題点
+ ログを書かかないと、コードが長くなった時にどのコードの前後にエラーが発生して処理が止まったのかがわからない。
+ エラーをしっかり書かないと、チーム開発の際に、発生したエラーが無視していいものなのか、そうでないのかがわからず無駄に時間をかけてしまう。

改善点
+ 複雑or大事な処理を行う際はlogを残すようにする。
+ 発生したエラーに対して、どのようなエラーなのかを簡単にざっくりと理解できるようなエラーメッセージを残す。
+ Not implementedを使用する。

## 3. 型を指定しない、docsを書かない
docsを書くのめんどくさいですよね。

問題点
+ 型を指定せず、関数の引数を定義する。
+ docsを書かかないで関数を定義すると、どのようなデータを入力して、何が帰って来るのかがわからないので、エラーになった時、解決に時間がかかる。
+ 複雑な関数の場合、理解するのに時間がかかる。

改善点
+ 常に型を指定する(Typescriptの使用など）
+ Docs generatorを使用して、短時間にわかりやすいdocsを書く。


# 精神的な失敗
## 1. 質問を怖がる
質問するのって勇気がいると思いませんか？

問題点
+ エラーが発生した時など、質問するのを躊躇って、無駄に時間を消費してしまう。

改善点
+ とにかく、具体的でわかりやすく、解決方を提示しやすい質問を作成して、質問をする相手が嫌がらないような質問をする。
+ 勇気を出す。

## 2. 100点のものを最初から作ろうとする。
完璧を目指したいですよね...。

問題点
+ 時間がかかってしまう。
+ 自分の視点で完璧なものは他の視点から見た時に完璧でないことが多い。

改善点
+ 70点のものができたら、一度feedbackをもらうようにする。
+ 一度に完璧なものを作るのではなく、徐々に完璧にしていくようにする。

#最後に
拙い文章ですが、以上で締めたいと思います。最後まで読んでいただきありがとうございました！
本当に僕個人の反省点のまとめになったのですが、僕の失敗が誰かのやく立つことを祈っています。
laravel8 ルーティングファイルを分ける

# 概要

- laravelのルーティングファイルweb.phpに記載されている内容を新しく作成したルーティングファイルに記載する方法をまとめる

# 情報

- ルーティングファイルを分割したコードを下記のリポジトリにアップしておく。
    - [https://github.com/miriwo0104/laravel8_easy_crud/tree/route_file_branche](https://github.com/miriwo0104/laravel8_easy_crud/tree/route_file_branche)

# 方法

1. `アプリ名ディレクトリ/routes/`直下に新規のルーティングファイル「test.php」を作成して下記の様に記載する。

    ```アプリ名ディレクトリ/routes/test.php
    <?php
    
    use Illuminate\Support\Facades\Route;
    
    Route::get('/test', function() {
        return 'test';
    });
    ```

1. `アプリ名ディレクトリ/app/Providers/RouteServiceProvider.php`の`boot()`内部を下記の様に修正する。

    ```アプリ名ディレクトリ/app/Providers/RouteServiceProvider.php
    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace)
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web.php'));

            // 下記を追記
            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/test.php'));
        });
    }
    ```

1. ローカルサーバーを起動して[http://127.0.0.1:8000/test](http://127.0.0.1:8000/test)にアクセスしたところ「test」の文字列が表示されたのでルーティングは問題なく動作している。
電子書籍で写真集を作ってみる

電子書籍で写真集を作ってみる、ということを思いついた。
判型は、縦書き・右綴じのものを見開きが良さそう。
が、いろいろ調べてそういうものがなくてたどり着いたのが以下の流れです。

原稿を、まずpagesで作る。
テンプレートの「ブック-横」に「写真集」があったのでそれを使ってみる。
この原稿をepubで書き出せば直接Apple Booksで公開。pdfで書き出してkindle comic creatorで取り込めばKDPで公開できる（はず）。

pages原稿とは別に、1枚絵の表紙画像もタテヨコ比1.6:1で用意する。こちらは（macosの）previewで編集。

原稿をとりあえず完成させて、一旦先に、pdf出力してcomic creatorに読み込ませてみる。
kindle側での気づきで何か修正するならpagesで修正して波及させる。

なお、comic creator自身は何の問題もなく動作するのだが、`html/scaled-images/`ディレクトリに、
各ページの日本語ファイル名の画像が作成されてしまうと、これをkindle previewerが読めないという程度の低い問題がある。
このファイル名は読み込んだPDFファイルのファイル名から来ているので、pagesのPDF exportの際に多バイト文字でファイル名をつけない。

comic creatorビルド＆プレビューで、previewerの起動に失敗するが、`.mobi`ファイルは
comic creatorの保存先ディレクトリ内に作成されている。
こちらはKDPにアップロードすればよい。

Apple Booksでの公開は、pagesから一回epubで書き出して確認。
この後、pages原稿をiCloudに**移動させ**、リモートで生成したepubファイルをダウンロードして「プレビューを確認」する。
ここで何故かcomic creatorが起動してepubを読めずに手詰まるが、一度ダウンロードできていればプレビューして確認したと扱われる。
プレビュー確認自体は上で自分でやっているのを信じて公開させる。


参考：
+ https://support.apple.com/ja-jp/HT208716
+ https://lululea.com/it/kindle
+ https://girlsnomadlife.com/how-to-make-mobi-files/
Volumio 3 + 秋月電子の激安USB-DACで、DAC側の音質調整を行う

# はじめに
ネットラジオを聞きたくて、Raspberry Piに[Volumio 3](https://volumio.com/)をインストールしました。
USB-DACは、秋月電子で激安で売られている[１０Ｗ＋１０ＷステレオＤ級アンプモジュール（ＵＳＢＩ／Ｆ付き）](https://akizukidenshi.com/catalog/g/gM-02404/)をテキトウな箱に入れて接続しました。
![M-02404.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679798/9f8e4b16-e826-06d1-47ef-891f99742c3a.jpeg)

このモジュール、高音・低音域などちょっとした調整ができるようですが、VolumioのGUIから設定できません。悩んだ末にALSA経由で変更できましたので、簡単に設定方法を残しておきます。Volumio 3で実施しましたが、たぶん2でも同じかと思います。

# SSHコンソールを有効に
まず、テスト設定画面でSSHを有効にします。

```
http://<VolumioのIPアドレス>/dev/
```
※なお、VolumioのIPアドレスの記載は、Volumioの「設定」「システム」⇒「プレーヤー名」に記載した名前に「.local」に置き換えても接続できます。(例: プレーヤー名が「myvolumio」 ⇒ myvolumio.localと書きます )


# SSH経由でログインし、ALSAのミキサー画面で音質調整を行う。
SSH経由でログインします。Windows10 であればコマンドプロンプトから以下で接続します。詳しくは[SSH access on volumio](https://volumio.github.io/docs/User_Manual/SSH.html) を見てください。

```
ssh volumio@<VolumioのIPアドレス>
```
ログインしたら、以下コマンドでサウンドデバイスの音量設定画面を出します。

```
sudo alsamixer
```
起動した直後は、HDMIデバイスの設定画面が表示されますので、[F6]キーでデバイスを選びます。
![alsamixer-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679798/bfe670da-d886-6758-ec6b-296957f4b6fb.jpeg)

設定はリアルタイムで反映されますので、音楽などを再生しながら設定すると良いでしょう。
自分が使用しているDACは、「Bass Boost」「AGC」などの設定がありますが、これらは[M]キーで変更できます。
![alsamixer-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679798/57e2fe7f-2e8e-99fd-9071-00d4de421e61.jpeg)

設定が完了しましたら、[ESC]キーで終了します。

# 変更結果を保存する。
変更した設定は、再起動すると元に戻ってしまいますので、設定を保存します。

```
sudo alsactl store
```
で /var/lib/alsa/asound.state に保存されます。
【勉強メモ07】MSの自動回答ツールを作成しよう


#はじめに
今回記事作成者の機械学習などの勉強＆メモのために記事を作成しています
間違いなどありましたらコメントにてご指摘いただけると幸いです。

#目的
アンケート結果から可視化を行いたいが、まだ実施していないため、データがない。
そのため、ダミーデータを作成する。

#実施方法
MicrosoftのFormsの自動回答ツールをPythonで作成します。

#自己責任
これを参考に自動化する場合は自己責任でお願いします。
この記事を参考にし、損害が発生しても一切責任は取りません。

#00.今回の環境
PC：MacBook Air (M1）(メモリ:16GB)
Pythonのバージョン: 3.8.5
Choromバージョン: 96.0.4664.110

#01.Chromeのドライバーを準備する。

Google Chromeの右上に縦点3つがあるのでそこをクリック
「Chrome ⇨ヘルプ⇨Chromeについて→Chromeのバージョン確認」
上記手順でChromeのバージョンを確認します。

バージョンを確認したのちに下記URLでChromeで自動化行えるドライバーをダウンロードする。
ドライバーはChromeのバージョンに合わせて行う。
今回は「96」のバージョンのため、下記文言に従ってダウンロードをする。
If you are using Chrome version 96, please download ChromeDriver 96.0.4664.45

ドライバーのありか
https://chromedriver.chromium.org/downloads

ダウンロードしたドライバーは
Pythonファイルと同じ場所に置いておく

#02.Pythonの環境構築をする。

```py
#pipインストールでPythonで行える環境を構築する。
#最初に実施するときはコメントアウトを外してインストールしてください。
!pip install selenium
!pip install chromedriver
#最新バージョンかは要確認
#クロムのバージョンと一致しているかを確認
!pip install chromedriver_binary==96.0.4664.45

```
##Pythonのバージョンを確認する場合

```py
#　Pythonのバージョンを確認したい場合
import sys

print(sys.version)

```

#03.　実行準備を進めていく

```py
#ライブラリーを読み込む
# webページ読み取り用
from selenium import webdriver
# chromを読み取り用
import chromedriver_binary
# 待機時間設定用
import time
#　ランダムに回答する用
import random
#　日付、時間を出力する用
import datetime
##上記のは、どのくらい時間がかかるか計測する用である。
##下記プログラムを実行することで実行したときの時間を出すことができる。
#print(datetime.datetime.now().strftime('%Y年%m月%d日 %H:%M:%S'))


```
#04.自動化のための関数を作る
複数ページにわたる場合、毎回プログラムを記載するのは大変である。
そのため、関数を作る方が良い

```Py
#Q ⇨設問数
#s ⇨選択肢
#D ⇨上から何問目か

def Sec4 (Q,s,D):
    y = Q + 1
    x = s + 1
    d = D + 1
    #クリックするcopy xpathを入力する
    Xpath='//*[@id="form-container"]/div/div/div[1]/div/div[1]/div[2]/div[2]/div['+str(d)+']/div/div[2]/div/div['+str(y)+']/div['+str(x)+']/input'
    #クリックする関数を作成する
    element = driver.find_element_by_xpath(Xpath)
    
    return element.click()


```

Xpathの見方は下記URLを参考

# 参考URL
https://asyano.jp/forms-jidou/

https://asyano.jp/xpath/


```py
#次のページに移動する方法
def Next():
    #回答後にエラーが出ないように次のページいくまでに2秒待つ
    time.sleep(2)
    #クリックするcopy xpathを入力する
    Xpath = '//*[@id="form-container"]/div/div/div[1]/div/div[1]/div[2]/div[3]/div[1]/button[2]/div'
    #クリックする関数を作成する
    element = driver.find_element_by_xpath(Xpath)
    #クリックを実行する
    element.click()
    #回答後に2秒待つ
    return time.sleep(2)

```

#05.ブラウザーを開くプログラムを構築する

```py

#Chromeを読むこむためのドライバーを呼び出す
#同じフォルダーにドライバーがある場合
driver = webdriver.Chrome(executable_path="./chromedriver")

#Chromeを呼び出す
driver = webdriver.Chrome()

#呼び出すURLを指定する
url = '呼び出したいURLを記入する'

#URLを開く
driver.get(url)

#4秒待機する（開くのに時間がかかっても動かせるようにするため）
time.sleep(4)


```
vscodeでtypescriptをデバッグする環境を構築した(docker,windows10)

フォルダ構成は以下のような感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495919/e0e6a686-fd20-822c-4220-46918c60a1ba.png)

##docker環境を構築

```docker-compose.yml
version: '3'

services:
  php:
    build: ./php-apache/
    volumes:
      - ./php.ini:/usr/local/etc/php/php.ini
      - ./html:/var/www/html
    ports:
      - 8080:80
```

##xdebugとnodeとnpmをインストールする

```docker:dockerfile
FROM php:7.3-apache

# Xdebugのインストール
RUN pecl install xdebug-2.9.8 \
&& docker-php-ext-enable xdebug

RUN apt-get -y update
RUN apt-get install -y \
    curl \
    gnupg
    
# nodeのインストール
RUN curl -fsSL https://deb.nodesource.com/setup_17.x | bash - && \
apt-get install nodejs

# npmのインストール
RUN npm install npm@latest -g
```

gitでコマンドを打っています。ビルドする。

```
$ docker-compose build
```

コンテナを起動する。

```
$ docker-compose up -d
```

コンテナに入る。

```
$ docker container exec -it docker_php_1 bash
```

typescriptをインストールする。

```
$ npm install -D typescript
```

tsconfig.jsonを生成する。

```
$ npx tsc --init
```

tsconfig.jsonの設定。

```tsconfig.json
 "target": "es6",
 "module": "commonjs",
 "sourceMap": true,
 "outDir": "./dist/",
 "rootDir": "./src/",
 "noEmitOnError": true,
 "strict": true,
 "esModuleInterop": true,
 "experimentalDecorators": true,
 "forceConsistentCasingInFileNames": true
```

typescriptソース。

```/src/index.ts
function sayHello(): void {
  console.log('Hello!');
}

console.log(sayHello());
```

vscodeのデバッグ設定。

```lanch.json
    "version": "0.2.0",
    "configurations": [
        {
            "type": "pwa-chrome",
            "request": "launch",
            "name": "debug typescript",
            "url": "http://localhost:8080/section9-setup/",
            "webRoot": "${workspaceFolder}",
          }
    ]
```

typescriptファイルをコンパイルする。
(index.jsとindex.js.mapが生成される)


```
$ npx tsc
```

index.htmlの記述。

```index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./dist/index.js"></script>
</head>
</html>
```

index.tsにブレークポイントを置く。デバッグするとブレークポイントで停止した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495919/05e68917-1377-889a-e91d-7ed375f5bf7e.png)
(補足)ちなみにブラウザも立ち上がる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495919/54ee7dd5-bbb9-9aea-0bc6-5295e2926df3.png)
JSON データを POST で受けるテストサーバを作る

IoTデータを受けるサーバでは、API として JSON データを POST するものが多い。
ちゃんと JSON データが送られているかな？ とデバッグする時に、自前でちゃちゃっとテストサーバーを作ってみる。

# PHP スクリプト

```

<!DOCTYPE HTML>
<HTML><HEAD><META CHARSET=UTF-8><TITLE></TITLE></HEAD>
<BODY></BODY>
<PRE>
<?php

// $data = $_POST['data'];
// echo $data;

$json = file_get_contents("php://input");
$contents = json_decode($json, true);
var_dump($contents);

?>
</PRE></BODY></HTML>

```

最初は

```

// $data = $_POST['data'];
// echo $data;
```

としていたが、JSONのPOSTは通常のPOSTメソッドじゃないということで、上記のように書き直し。


使い捨てのスクリプトだったのだけど、これ便利、超絶便利、という声があったので公開しておきます。
動画にバーチャル背景をつけることはできるのか？ → SemanticImageでかんたんに

#撮影済みの動画にバーチャル背景をつける方法

<img src="https://user-images.githubusercontent.com/23278992/147275276-5c108efd-f61d-4ba7-a27d-c3df5bb7cc5b.gif", width=600>

既に存在している動画にバーチャル背景をつけられれば、
面白い編集ができる。
#バーチャル背景はリアルタイムでしかつけられないのか？

バーチャル背景は撮影時に設定するものが多い。
既存の動画を処理したい。
しかし、動画の処理を書くのは大変そう。

#[**SemanticImage**](https://github.com/john-rocky/SemanticImage)で秒で解決


[**SemanticImage**](https://github.com/john-rocky/SemanticImage)というライブラリなら、
かんたんに既存の動画にバーチャル背景を適用できる。

#使用方法

###１、SemanticImageをインポートする
SwiftPackageManagerで[**SemanticImage**](https://github.com/john-rocky/SemanticImage)を追加する。

```swift
import SemanticImage
```

###２、背景合成を実行

```swift
sematicImage.swapBackgroundOfPersonVideo(videoURL: url, backgroundUIImage: uiImage, { err, processedURL in
    // 処理済み動画URLをここで使う
})
```

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
簡単な開発内容をお書き添えの上、お気軽にご連絡ください。
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
シェル学習 grep2

####grepによる検索と切り出し

後ろの文字が「田」のものを抜き出す

```
$ echo 中村 山田 上田 田代 | grep -o "[^ ]田"
山田
上田

```

grep -o "[^ ]田"
→スペースでは無い1文字の後ろに田が付く
【Mac】Atomでcmd+Rを実行すると"no symbols found"が出るときの解決法




#Atomでpythonファイルを実行するとき、cmd+Rを押しても以下のようなエラーが出るときの解決法を紹介していきます。
![スクリーンショット 2021-12-30 9.35.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/f93ac719-573f-4514-b783-0869919b6872.png)



##解決法①：間違えてwindowsのショートカットを使ってないか確認
・Windows：alt+R　で実行
・Mac： cmd+Rで実行

押し間違えてる方多いらしいので、まずここを確認してください。




##解決法②Atomのデフォルトのショートカットを変える

**トップバー→Atom→環境設定**
![スクリーンショット 2021-12-30 9.30.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/cb838702-970d-bc36-3a6d-5768fb0b51b9.png)
**環境設定→キーバインド→"cmd-r"を検索してください**
キーバインドはAtom上のショートカットの一覧表みたいなものです。
"cmd-r"を検索してください。今現在、"cmd-r"がどんなコマンドになっているのか確認しましょう。
![スクリーンショット 2021-12-30 9.45.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/a2865b63-92bd-c317-2450-a039f533c5f5.png)
↓見つかりました、現状"cmd-r"を実行すると、**"symbols-view:toggle-file-symbols"**が行われている状態になっているらしいです、これがエラーの原因になっていたみたいです。
![スクリーンショット 2021-12-30 9.47.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/db548ca0-ace1-9c5e-a694-a60fd374898c.png)
これを変えていきましょう、↓の青い文字**"キーマップファイル”**をクリックしてください
![スクリーンショット 2021-12-30 9.52.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/0a3ea233-6953-2fae-65f8-b81b7a017966.png)
すると、↓の画像のようなkeymap.csonというファイルが開きます。
![スクリーンショット 2021-12-30 9.57.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/68b5c460-11a9-ab42-088b-6bd6f97f535c.png)
ここの1番下の行に、以下の2行をコピペして追加してあげてください。
```'.platform-darwin atom-text-editor':
 'cmd-r': 'run:file'```

そうすると、現状の"cmd-r"のショットカットを新しいものに上書きすることができます。<font color="Red">※追加したら、必ずcmd+Sで変更内容を保存してください。</font>

![スクリーンショット 2021-12-30 9.55.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/d51d25bf-ec61-7faf-c3a0-93c92c4cc930.png)

ここまで来たら、あと一歩！
####<font color="Red">Atomを再起動させてください</font>

これで解決です！

実行したいpythonファイルを開いて、cmd+Rを押してみると、ちゃんと実行されるようになりました。
![スクリーンショット 2021-12-30 11.23.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/812bd8d7-ef55-c68a-46da-5069f2f322a9.png)




##補足：
[stackoverflow](https://stackoverflow.com/questions/32922230/atom-editor-cmd-r-no-symbols-found)でも同じ質問が上がっていましたが、特に解決方法が書かれていなかったのでこの記事を作成しました。

<font color="DarkGray">[先程検索したとき](https://camo.qiitausercontent.com/341ff552089f8f0de9a66b92bb9533511533c38d/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f323434373634332f61323836356236332d393262642d633331372d323435302d6130333966353333633566352e706e67)にあったように、デフォルトのショートカットだと"cmd-r"を実行すると"symbols-view:toggle-file-symbols"が行われてしまいます。このショートカットを"run:file"に変えることで"cmd-r"を押すとpythonファイルが実行できるようになります。</font>

試しに変更後、もう一度キーバインドで"cmd-r"を検索してみると、↓のように2つのコマンドが表示されます。
![スクリーンショット 2021-12-30 11.08.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2447643/46fd43df-7a59-7825-d4fc-d26861a4a93d.png)
一応2つ表示されているものの、"symbols-view:toggle-file-symbols"の上に"run:file"が上書きされていて、現状"run:file"が最新のコマンドになってます。
古いmacOSを段階的に最終対応のOSへアップデートする

## Goal

MacBook Air (13-inch, Mid 2012) を初期化し、OSをMountain LionからCatalinaまでアップデートした時の手順を参考情報として記録します。

## References

* ["MacBook Airのモデルを識別する"](https://support.apple.com/ja-jp/HT201862). Retrieved Dec 29, 2021.
* ["以前のバージョンのmacOSを入手する"](https://support.apple.com/ja-jp/HT211683). Retrieved Dec 29, 2021.

## Pre-Requisites

* MacBook Air (13-inch, Mid 2012)
* OS X Mountain Lion 10.8

## How To

### アップデートの道程を確認する

Referencesに掲載した"MacBook Airのモデルを識別する"より、手元のMacBook Airで実行できる最終対応のOSを確認します。

今回のケースの場合、"macOS Catalina 10.15.7"と確認できました。従って、Mountain LionからCatalinaへのアップデートをゴールとしました。

Referencesに掲載した"以前のバージョンのmacOSを入手する"より、Mountain Lionからアップデートできる最新のOSを確認します。

今回のケースの場合、"macOS Mojave 10.14"と確認できました。しかし、Mountain Lionでは、App Storeが意図通りに動作せずMojaveへアップデートできません。そのため、インストーラーからアップデートできるSierraへ先ずはアップデートします。

今回のアップデートの道程は、次の通りです。

1. Mountain Lionをインストーラーを使用してSierraへアップデートする。
2. SierraをApp Storeを使用してCatalinaへアップデートする。

### Mountain LionをSierraへアップデートする

Referencesに掲載した"以前のバージョンの macOS を入手する"より、"macOS Sierra 10.12"のリンクをクリックし、Sieraのインストーラー (InstallOS.dmg) をダウンロードします。

ダウンロードしたInstallOS.dmgを開き、InstallOS.pkgを実行します。インストーラーが起動するので、指示に従ってインストールを完了します。このインストールは、OSをインストールするものではなく、OSのアップデートプログラムをインストールするものです。OSのアップデートには、引き続き操作が必要です。

Finderでアプリケーションを開き、追加された"Sierraインストール"というアプリケーションを実行します。Sierraへのアップデートプログラムが起動するので、指示に従ってアップデートを完了します。

#### キーチェーンパスワードを繰り返し求められる

Sierraへのアップデート後、clouddを始めとするプログラムから"キーチェーン'ログイン'を使おうとしています。"というダイアログが繰り返し立ち上がり、認証もキャンセルもできず、ダイアログを閉じられない現象が発生しました。

この現象は、ユーザアカウントのパスワードとログインキーチェーンが一致しないことが原因のようです。

この現象は、次のサイトの"必要に応じて新しいログインキーチェーンを作成する"に記載されている手順に従って、自分のデフォルトキーチェーンをリセットすることで解消できます。

* ["macOS Mojave以前でmacOSユーザアカウントのパスワードを変更またはリセットする"](https://support.apple.com/ja-jp/HT211672). Retrieved Dec 29, 2021.

### SierraをCatalinaへアップデートする

Referencesに掲載した"以前のバージョンの macOS を入手する"より、"macOS Catalina 10.15"のリンクをクリックします。App Storeで"macOS Catalina"が開きます。

"入手"をクリックします。Catalinaへのアップデートプログラムが起動するので、指示に従ってアップデートを完了します。
VisualStudio2019 + OpenCV4.1.1 + CUDA10.1 の環境構築

# VisualStudio2019 + OpenCV4.1.1 + CUDA10.1 の環境構築

## 環境構築

### 参考

- <https://qiita.com/Susumu0417/items/c0823f6649d2dddc1679>
- <https://nln.jp/wp/archives/5974>
- <https://takap-tech.com/entry/2021/06/03/215015>

### ダウンロード・インストール

- OpenCV 4.1.1
  - <https://opencv.org/releases/page/3/>
      1. Windows
      1. opencv-4.1.1-vc14_vc15.exe
- opencv_contrib 4.1.1
  - <https://github.com/opencv/opencv_contrib>
      1. Tag
      1. 4.1.1
      1. Code
      1. Download ZIP
      1. opencv_contrib-4.1.1.zip
- CUDA Toolkit 10.1 Update 2 Download
  - <https://developer.nvidia.com/cuda-toolkit-archive>
      - <https://developer.nvidia.com/cuda-10.1-download-archive-update2>
          1. Windows
          1. x86_64
          1. 10
          1. exe[local]
          1. cuda_10.1.243_426.00_win10.exe
- CMake Latest Release (3.22.1)
  - <https://cmake.org/download/>
      1. cmake-3.22.1-windows-x86_64.msi
      1. Add CMake to the system PATH for all users
      1. 環境変数
          - PATH
              - C:/Program Files/CMake/bin
- Visual Studio Community 2019

### OpenCV モジュール生成

- CMakeでOpenCVをビルドするソリューションファイルを生成する
  1. cmake-gui 起動
  1. ソースコード
      - E:/Program/OpenCV/opencv/sources
  1. ビルドバイナリ
      - E:/Program/OpenCV/build
  1. Configure
      - Visual Studio 16 2019
      - x64
      - Use default native compilers
      - Finish
  1. Check
      - BUILD_EXAMPLES : ON
      - BUILD_PERF_TESTS : OFF
      - BUILD_TESTS : OFF
      - INSTALL_CREATE_DISTRIB : ON
      - OPENCV_EXTRA_MODULE_PATH : E:/Program/OpenCV/opencv_contrib-4.1.1/modules
      - WITH_CUDA : ON
      - WITH_OPENGL : ON
  1. Configure
  1. Check
      - CUDA_ARCH_BIN : 6.1
          - <https://developer.nvidia.com/cuda-gpus>
              - Geforce GTX 1070 Ti
      - CUDA_ARCH_PTX : 6.1
      - CUDA_TOOLKIT_ROOT_DIR : C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.1
  1. Configure
  1. Generate
- OpenCVをビルドする
  1. E:/Program/OpenCV/build/OpenCV.sln
  1. Debug
      1. 1回目 : 30min
          - 初回は何故か外部からの変更が発生
      1. 2回目 : 20min
      1. CMakeTargets/INSTALL
          - ビルドのみ
  1. Release
      1. 1回目 : 30min
      1. CMakeTargets/INSTALL
          - ビルドのみ
- E:/Program/OpenCV/build/install
    - /include
    - /x64/vc16/bin
    - /x64/vc16/lib
<初心日記>セキュリティコンテストについて勉強したこと、、、

<h2>セキュリティコンテスト参加の為に勉強したこと</h2>

こんにちは。Uriです。
今回は、セキュリティコンテストに参加するために、
僕が勉強したことをまとめてみます。。。

<p>
<h3>やったこと一覧</h3>
<ol>
<li>セキュリティコンテストってなに？</li>
<li>セキュリティの知識を付けよう</li>
<li>基本的なIT知識をつけなきゃいけない</li>
<li>過去問題を解いてみよう</li>
</ol>
</p>

<p>
<h3>1．セキュリティコンテストってなに？</h3>
まず、セキュリティコンテストってどんなことするの？という疑問についてです。
以下の本を購入して読んでみました。<br><br>
<a href="https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%82%B3%E3%83%B3%E3%83%86%E3%82%B9%E3%83%88-CTF%E3%81%A7%E5%AD%A6%E3%81%B6%E8%84%86%E5%BC%B1%E6%80%A7%E6%94%BB%E7%95%A5%E3%81%AE%E6%8A%80%E8%A1%93-%E6%A2%85%E5%86%85-%E7%BF%BC/dp/4839973490">詳解セキュリティコンテスト ~CTFで学ぶ脆弱性攻略の技術</a><br><br>

この本、とっても分かりやすかったです。
簡単なイメージとしては、
旗取り合戦や宝探しをする競技のようなイメージを持ちました笑

色んなシステムや、ファイルからFLAGと呼ばれる文字列を探しだすことで、ポイントを稼いでいくというシステム。
その文字列を探す過程で、サーバやネットワークなどにおけるセキュリティ知識を活用していくというものみたいですね。
(ざっくりとした感想ですみません笑)
</p>

<p>
<h3>2．セキュリティの知識を付けよう</h3>
セキュリティコンテストというだけあって、セキュリティ知識がないと始まらない！
そこで、システムセキュリティの勉強を始めました。

使用したのは、以下の書籍。<br><br>

<a href="https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8/dp/4797393165">体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性が生まれる原理と対策の実践</a><br><br>

この本、PHPの知識とかが前提となっているみたいで読むのに少し苦労しました。
<br><h3>とにかく分厚い！！！！</h3><br>

けど、初心者の僕でも理解できるように細かく記載があって一度目を通した後も辞書的な役割で利用したりしてました。<br>
この本の作者さんは、徳丸浩さん。<br>
セキュリティの業界では、有名な方でこの本の試験もあるとか。。。<br>
(頑張って受けてみたい。。。)<br>
</p>

<p>
<h3>3．基本的なIT知識をつけなきゃいけない</h3>

セキュリティって奥深いですよね。。。汗<br>
サーバ周り、ネットワーク周り、アプリケーションなどなど個別でセキュリティの事を考えなければならないかと思えば、個別で考えていては対策できないことも沢山あります。<br>

セキュリティの勉強をする中で、特に認証認可と呼ばれるログインとかする機能のセキュリティは、とても興味深かったです。<br>
これを考えるときには、SQL文の読ませ方に問題があったり、キャッシュにログイン情報が残ってしまっていたりと、セキュリティ以外の知識が沢山必要ですよね。。。<br>

知識習熟には、セキュリティの勉強の中で並行してネットワークとアプリケーションについて勉強するようにしました。<br>
</p>

<p>
<h3>4．過去問題を解いてみよう</h3>
ここまでくると、過去問を解いてみたいという欲求がMAXです！
過去問というか、例題にはなるのですが、以下のサイトを用いました。
<br><br>

<a href="https://ctf.cpaw.site/index.php">CpawCTF</a><br><br>

このサイト、常設CTFといって気軽にセキュリティコンテストの例題を解く事が出来るものです。<br>
問題数もかなりあって解きごたえありました笑<br>

自分の場合は、かなり解ける問題もあって、本記事で紹介した2つの書籍を勉強するだけでもかなり解ける問題はあるのだなーと実感しましたね。笑<br>
</p>
<h3>まとめ</h3>
今回は、セキュリティコンテストについて興味を持った僕がどんな勉強をしてきたのかということを長々と話してきました。<br>
宝探しのようでとても面白い競技だなと改めて思いましたね笑<br>
皆様もぜひ、参加してみてはいかがでしょうか？

<p>

</p>
Validation failed: # must exist 解決法　

##はじめに
Railsでポートフォリオを開発中に、rails consoleで投稿機能がしっかりデータベースに入っているかを確認した。
しかし、model.saveで実行した結果・・・
=>false
という結果が出た。

データベースに保存できていない。

##試したこと

model.save!
上記の様に！をつけてエラーがどこにあるのかを確認できる。

そうすると・・・
ActiveRecord::RecordInvalid (Validation failed: モデル must exist)

というエラーが出てきた。

```java:モデル.rb
class モデル < ApplicationRecord
 belongs_to :user, optional: true
end
```

optional: true
をつけるだけで問題が解決した。