OmniAICreator/Qiita-1.07M huggingface dataset:
Docker MongoDB mongo-express

# MongoDB を Docker で使いたい
私はアプリを開発する際にデータベースをMac等のローカル環境にダウンロードしたくないので、Dockerというコンテナ管理ツールを使用しています。移行も楽なので。本番環境でも使いたいのは山々ですが、[Kubernetes]("https://kubernetes.io/ja/docs/home/")周りの知識がないので中々踏み込めないという感じです。まぁ規模にも因るんですが。   

この記事は**Docker**を使って**MongoDB**をたてるサンプルみたいなもの。他にわかりやすいものがなくて、作る際に調べた記憶があったので。  

動作環境はMacOS Catalina

# Goal
**docker-compose.yml**ファイルを作成して**MongoDB**と**mongo-express**をlocalhostにたてます。  

**MongoDB**というのはNoSQL  
**mongo-express**というのはMySQLでいう**phpMyAdmin**みたいなもの。**MongoDB**の中身が見易くなる。  

[Docker](https://docs.docker.com/get-started)

[MongoDB](https://docs.mongodb.com/manual/introduction)

[mongo-express](https://github.com/mongo-express/mongo-express)

# docker-compose.yml
```
# Use root/example as user/password credentials
version: "3.1"

services:
  mongo:
    image: mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root   # ユーザー名
      MONGO_INITDB_ROOT_PASSWORD: tree  # パスワード
    ports:
      - 27014:27017
    volumes:
      - ./db:/data/db
      - ./configdb:/data/configdb

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - 8080:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root   # ユーザー名
      ME_CONFIG_MONGODB_ADMINPASSWORD: tree   # パスワード
```

# 解説
**docker-compose.yml**ファイルの基本的な書き方は以下参照。
https://docs.docker.com/compose/compose-file/

**ports**の指定は以下参照
https://qiita.com/tksugimoto/items/23fcce1b067661e8aa46#%E6%A4%9C%E8%A8%BC%E7%B5%90%E6%9E%9C

**volumes**で指定した場所にデータベースのファイルが作成されます。
**sample/docker-compose.yml** にファイルがあったとすると**sample/db**と**sample/configdb**が作成されます。

# How To Use
```
whoami$ pwd
/Users/whoami/sample
whoami$ ls
docker-compose.yml
whoami$ docker-compose up -d    // -d は daemon で実行という意味
Creating network "sample_default" with the default driver
Creating sample_mongo-express_1 ... done
Creating sample_mongo_1         ... done
whoami$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
1aeb90deadd0        mongo               "docker-entrypoint.s…"   23 seconds ago      Up 22 seconds       0.0.0.0:27014->27017/tcp   sample_mongo_1
6649bb697412        mongo-express       "tini -- /docker-ent…"   23 seconds ago      Up 9 seconds        0.0.0.0:8080->8081/tcp     sample_mongo-express_1

whoami$ docker-compose down
Stopping sample_mongo_1         ... done
Stopping sample_mongo-express_1 ... done
Removing sample_mongo_1         ... done
Removing sample_mongo-express_1 ... done
Removing network sample_default
whoami$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```
**docker-compose up -d**した後ブラウザで[http://localhost:8080/]を開くと、そこに**mongo-express**があります。

# 注意
ポート番号の指定を適当にやりすぎると**MongoDB**がたたない。DockerのMongoDBのポートが27017しかないみたいな記事も見た事がある気がする。   
mongo-expressはdockerでは開発環境しか使えないらしい。

# 予告
これでたてたMongoDBに[Node.js](https://nodejs.org/en/about/)から繋ぐ方法も書こうと思う。

# 公式ref

https://hub.docker.com/_/mongo

https://hub.docker.com/_/mongo-express
terraformのformatlistでリストの要素と文字列を合体



```
  target_ami = formatlist(
    "arn:aws:ec2:ap-northeast-1:611111111111:instance/%s",
    data.aws_instances.instances.ids[*]
  )
```


```
> formatlist("aaaaaaaaaaaaaaaa/%s", data.aws_instances.instances.ids[*])
[
  "aaaaaaaaaaaaaaaa/i-11111111111111111",
  "aaaaaaaaaaaaaaaa/i-66666666666666666",
]
```
terraform consoleの使い方

## 用法
- data型などの、terraform planを実行しないと内容を確認できないものの中身を見ることができる
- リスト型、Map型などの型や、取得されるidなどの実態をあらかじめチェックすることができる

## 実行

```
terraform console
```

出力

```
> data.aws_instances.instances.ids[*]
[
  "i-01e56922222222222",
  "i-02de9a42111111111",
]
```

## ワンライナーで出力したい場合

```
echo data.aws_instances.instances.ids[*] | terraform console
```
Seleniumの操作を音声付きで動画に記録する方法

# 目的
Seleniumの操作を動画で記録したい。
その際にブラウザの音声も記録したい。

# 方法
以下のelgalu/seleniumのコンテナを使用すると簡単にできる。
https://github.com/elgalu/docker-selenium

以下のサンプルはSeleniumでYoutubeの動画を30秒間再生して、その様子を動画に保存するサンプルである。

**環境**
macos Catalina 10.15.6
v14.10.1
 
**事前準備**

```
npm init -y
npm install --save selenium-webdriver
mkdir videos
```

**テストコード**

```js
const {Builder, By, Key, until} = require('selenium-webdriver');
(async function example() {
  let driver = await new Builder()
    .forBrowser('chrome')
    .usingServer('http://localhost:4444/wd/hub')
    .build();
  try {
    await driver.get('https://www.youtube.com/watch?v=WX6_koWVVpY');
    // 再生をする
    await driver.findElement(By.className('ytp-play-button')).click();
    const elTimeCurrent = await driver.findElement(By.className('ytp-time-current'));
    let bFlg = true;
    const timeId = setInterval(async ()=>{
      // 一秒毎にマウスを動かして再生時間が隠れないようにする
      const rc = await elTimeCurrent.getRect();
      let x = Number(rc.x);
      if(bFlg) x += 1;
      driver.actions().move({x: x, y:rc.y}).perform();
      bFlg = !bFlg;
    }, 1000);
    // 30秒再生するまで待つ
    await driver.wait(until.elementTextContains(elTimeCurrent, '0:30'), 40*1000);
    clearInterval(timeId);
  } finally {
    await driver.quit();
  }
})();
```

**dockerコンテナの起動〜テストコードの起動するシェルスクリプト**

```shell:sample.sh
docker run -d --rm --name=grid -p 4444:24444 -p 5920:25900 \
  --shm-size=2g -e VNC_PASSWORD=hola \
  -e VIDEO=true \
  -e AUDIO=true elgalu/selenium

sleep 5
docker exec grid wait_all_done 30s

node test.js

docker exec grid stop-video
docker cp grid:/videos/. videos
docker stop grid
```

このスクリプトを実行するとvideosフォルダにvid_chrome_25550_firefox_25551.mkvが作成される。
このファイルはブラウザにドラッグ&ドロップすると再生して確認可能。

# 参考
https://www.selenium.dev/selenium/docs/api/javascript/index.html
https://github.com/elgalu/docker-selenium/blob/master/docs/videos.md
pythonの環境設定（virtualenv+pipができない）

こんにちはpython初心者でdjangoでappを制作しようとしているものです。(python3系での開発)
anaconda + djangoでもできるみたいですが、情報が少ないので後々チャレンジします。まずpyenv、virtualenv、pip、anacondaの違いを確認。
https://mycodingjp.blogspot.com/2018/12/python-venv-virtualenv.html
https://oversleptabit.com/archives/2195
https://qiita.com/caad1229/items/325ca5c8ad198b0ebce7
virtualenv＋pipで行くことを決意しました。公式サイトではvenvコマンドで仮想環境を作ってました。それでもできたんですが、一旦は置いておきます。
https://www.python.jp/install/macos/virtualenv.html

```
% python -V
```
で自身のpcのバージョン確認。私は２系がすでに入っていました。２系はサポート終了なので、３系をインストールします。
流れとしては
xcode→homebrew→python3といくはず。
ちなみにhomebrewを使用するためにxcodeのinstallが必要みたいです。（homebrewはパッケージ管理するもの。）

```
% xcode-select --install
```
homebrewのインストールはネット検索するとコマンドはすぐ出てきます

```
% /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
```
% brew install python3
```
ここでいよいよ仮想環境を作ります。まずはvirtualenvのインストール


```
% sudo pip install virtualenv
```
すると

```
sudo: pip: command not found
```
と。commandがない？ネットによるとpythonをインストールすると付随してくるような書き込みが。。pipはいないのか？

```
% where pip
```
```
/usr/local/bin/pip
```
私の場合はバージョンの問題かなと思ったので、バージョンをupdateします。pip3へ。。

```
% pip3 install --user --upgrade pip
```


pipコマンド使えない時はこちらも見るとヒントがもらえます
https://www.python.jp/install/ubuntu/pip.html
https://qiita.com/sf213471118/items/3ee4ebd5d39856345682
https://qiita.com/tom-u/items/134e2b8d4e11feea8e12

再度試します

```
% sudo pip install virtualenv
```
行けました！！！！

おそらく違う方法もあるのかなと公式サイトを見て思いましたが、そこはまた検討します。

あとはサクサク行けたのでよかったです。

```
% virtualenv -p python3 好きな名前
```
python3を指定して仮想環境を作ります。
作った中に入ってみます

```
% . .好きな名前/bin/activate
```
もしくは

```
% source 好きな名前/bin/activate
```
抜ける時は

```
% deactivate
```
とっても時間がかかりましたが、なんとか一安心。一つapp作り終えたら、公式の方法も試そうと思います。間違いがあればお気軽に添削お願いいたします。
Jupyterで簡単な画像認識をしてみた

## 概要
https://qiita.com/uz29/items/ec854106355bf783e316
前回で準備が終わったのでまずは既存の学習モデルであるVGG16を使って画像判別プログラムを作った。

##ライブラリのインポートとモデルのインポート
初回はモデルのダウンロードが行われる。

```Python
import glob
import pprint
import numpy as np
import tensorflow as tf
from PIL import Image

model = tf.keras.applications.vgg16.VGG16(weights='imagenet')
```

##予測スクリプト
フォルダに入っている画像をまとめて予測にかけたかったので、globでパス一覧を取得しそれぞれの画像の配列を作成している。
予測は一度の関数の呼び出しで複数画像を同時に処理できるらしい。

```Python
#フォルダ内の写真を一括で予測
file_list = glob.glob("./images/*")

pil = []
imgs = []
for path in file_list:
    # 画像読み込み
    img_pil = tf.keras.preprocessing.image.load_img(path, target_size=(224, 224))
    pil.append(img_pil)
    # 画像を配列に変換
    img = tf.keras.preprocessing.image.img_to_array(img_pil)
    # 4次元配列に変換
    imgs.append(img)
imgs = np.stack(imgs, 0)

# 前処理
img_p = tf.keras.applications.vgg16.preprocess_input(imgs)
# 予測
predict = model.predict(img_p)
result = tf.keras.applications.vgg16.decode_predictions(predict, top=5)
```

##結果の表示

予測結果は以下で見ることができる。

```Python
pprint.pprint(result[0])
plt.imshow(pil[0])
```

[('n02124075', 'Egyptian_cat', 0.42277277),
 ('n02123159', 'tiger_cat', 0.18187998),
 ('n02123045', 'tabby', 0.12070633),
 ('n02883205', 'bow_tie', 0.0892005),
 ('n02127052', 'lynx', 0.024664408)]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259220/dea028d3-0091-4ac4-6f43-b219fef9951b.png)


```Python
pprint.pprint(result[1])
plt.imshow(pil[1])
```

[('n02119789', 'kit_fox', 0.6857688),
 ('n02119022', 'red_fox', 0.24295172),
 ('n02120505', 'grey_fox', 0.065218925),
 ('n02114855', 'coyote', 0.004371826),
 ('n02115913', 'dhole', 0.00046840237)]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259220/8b67528f-d5b0-ac4c-2ef2-4aefaef90480.png)


```Python
pprint.pprint(result[2])
plt.imshow(pil[2])
```

[('n02138441', 'meerkat', 0.9073721),
 ('n02137549', 'mongoose', 0.092063464),
 ('n02447366', 'badger', 0.00037895824),
 ('n02361337', 'marmot', 8.514335e-05),
 ('n02441942', 'weasel', 2.4436611e-05)]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259220/59a606ad-3a15-85e0-ca4d-20bd3aa9934e.png)

動物の細かい種類はVGG16に含まれていなくて異なる場合もあるがおおむね正確な種類を返してくれている。
今後は自分で学習モデルを作って予測させてみたい。
プログラミング学習スタート！！

##自己紹介
愛知県在住の19歳、自動車部品メーカの工場で働いてます。
#プログラミングを始めたきっかけ
高校卒業後、特にやりたいことがなかったため就職することを決めました。就職先は自動車部品メーカの工場でした。
仕事内容は、ハイブリット車のモータとガソリンを切り替える部品を一日600個以上作るライン工程。ただ同じ作業を永遠と繰り返すだけ。やりがいなどなく、時計を見て早く１日が過ぎるのを祈り続ける毎日、仕事を続けていくうちに何のために働いているのかわからなくなっていきました。
その時ふと思いました、

「今死んだら後悔するな、、、」

この思いをきっかけにやりたいことをやろう！転職しよう！そう決心しました。
***
やりたいことを考えていくと、誰かのためになることがしたい、多くの人の助けになることがしたいというざっくりとしたやりたいことが出てきました。
そんな仕事がないかと探していると、エンジニアという、世の中にある問題をITの力で自動化し解決していると知りました。これを知り、私自身何かサービスを作り誰かの役に立ちたい、そのためにエンジニアになろうと決意しました。

##これから
プログラミング学習を進めていく上での、ロードマップ、アウトプットをして行きます。
未経験からエンジニアを目指す人一緒に頑張りましょう！！！！
sidekiqのリトライ上限を設定して死んだキューをslackで通知する方法

#はじめに
非同期でjobを処理してくれる[sidekiq](https://github.com/mperham/sidekiq)を導入する中で、利便性を生かしつつも自分のアプリ専用にカスタマイズしたい、そんな時に役に立った設定をまとめています。

#sidekiqとは
sidekiqとは、非同期処理を可能にしてくれるライブラリです。複数のジョブを同時に実行させる時などに、各ジョブのqueueの名称を分けることで、処理の優先順位を指定することができます。似たようなライブラリにresqueやdelayed_jobなどがあるかと思います。
簡単に導入できるのですが、つまづいてしまったキューをデフォルトで25回だか26回だかリトライするとか、その後はDEADとなって実行していたキューのログが見られないなどといった面倒な点もあります。
そこでこの記事では、例外を投げた時などにいつまでもリトライせず上限を設定してDEADとし、その際にslackにキューの内容とエラーメッセージを投げるという設定をする方法についてお話しします。

#環境
Ruby 2.6.6
Rails 6.0.2
sidekiqにはredisが必要になります。

```
# On OSX
brew update
brew install redis
brew services start redis
```

#失敗したキューをダッシュボードで確認する
gemに[sidekiq-failures](https://github.com/mhfs/sidekiq-failures)を追加することでダッシュボードで確認することができ、失敗したキュー全てをリトライさせることもできます。

```
gem 'sidekiq-failures'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656820/8f3c5acb-0b12-4edf-7884-19ccce61d6cc.png)

failuresの一覧でもエラーの詳細が確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656820/e248aa10-d68c-490e-7f17-c4bf4a724b44.png)

他にも投げられたキューを知る＆分析するなどでたくさんgemがあるようですので参考までに載せておきます

- [utgarda/sidekiq-status](https://github.com/utgarda/sidekiq-status)
- [russ/sidekiq-history](https://github.com/russ/sidekiq-history)
- [davydovanton/sidekiq-statistic](https://github.com/davydovanton/sidekiq-statistic)

#リトライの上限を設定する
sidekiqは確かデフォルトで25,6回程度リトライをしてからキューを殺すといった仕様になっていたかと思います。
そこで、たくさんのジョブを一気に処理させる時など、そこまでリトライしなくていいからダメになった何度かチャレンジしてダメになったら教えて・・・という人のために、リトライの上限をjobファイルに記載します。

```ruby:app/jobs/your_job.rb
class YourJob < ActiveJob::Base
  ...
  queue_as :default
  sidekiq_options retry: 5
  ...
end

```

これで5回トライしてダメだったキューはDEADキューとなります。

#キューの死亡をslackで通知
Railsアプリにおいてslack通知をとても簡単にしてくれるgemが[slack-incoming-webhooks](https://github.com/shoyan/slack-incoming-webhooks)です。

```
gem 'slack-incoming-webhooks'
```

通知させるチャネルのURL取得は[このページ](https://slack.com/intl/ja-jp/help/articles/115005265063-Slack-%E3%81%A7%E3%81%AE-Incoming-Webhook-%E3%81%AE%E5%88%A9%E7%94%A8)を確認してください。

initializerでキューが死亡した場合の処理を設定(チャネルのURLは.envに保存します)

```ruby:app/config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  config.death_handlers << ->(job, ex) do
    slack = Slack::Incoming::Webhooks.new(ENV['SLACK_WEBHOOK_URL'])
    attachments = [{
      title: "Sidekiq failure",
      text: "ONE DEAD JOB IS FOUND:\n (#{job['args']}) \n msg(#{job['error_message']})",
      color: "#fb2489"
    }]
    slack.post "", attachments: attachments
  end
end
```

これで自然とDEADになってしまったキューはslack通知されるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656820/19e99fd1-e5a9-38fd-495a-34177cf328ee.png)
#注意点

- sidekiqのダッシュボード上でキューを殺しても通知は来ない
config.death_handlersに通知の設定をする場合、ダッシュボード上でマニュアルにキューを死亡させた場合には通知が来ません。なのでリトライ上限の5回を超えた場合にのみ通知が来るようになります。

- rescure_from　Exceptionで通知設定するとリトライしてくれない
例外処理なので一度ジョブを処理してエラーとなると死亡と看做され、slack通知はしてくれますがリトライはしてくれません。なんらかの事情で処理されずそれでもリトライして欲しい場合には、上記の通りconfig.death_handlersでslack通知の設定をおすすめします。
SwiftのFirestoreで前方一致検索をする


例えばこんなデータがあったとして  

```
let usersRef = Firestore.firestore().collection("Users")
usersRef.document("UserA").setData([
    "name": "UserA",
])
usersRef.document("UserB").setData([
    "name": "UserB",
])
```

こう書く

```
let postRef = usersRef.order(by: "name")
    .start(at: [検索したい文字列]).end(at: [検索したい文字列 + "\u{f8ff}"])
```
外部キーのカラムを追加するのはどんな場合か？

疑問
　・外部キーのカラムを追加する方法は知っているが、どんな時にそれを記述すれば良いのか、分からない。
　
結論
　・そのテーブルのアソシエーションがbelongs_to :　X(Xはテーブル名)
　 の場合は使う。

説明
![README.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738881/b3b7c817-187f-7f83-d92c-a1b8e5953b61.jpeg)

例として、上の画像で説明します。
itemsテーブルは、usersテーブルに対してのアソシエーションがbelongs_toなので、
referencesを使い、usersテーブルにあるカラムを追加するということです。

他にも、外部キーのカラムを追加する場合はあるかもしれないですが、
belongs_toがあるテーブルでは、他テーブルの外部キーカラムを使うと考えて問題ありません。
[Node.js]Express Validatorが使えない？？


こちらの書籍を使ってNode.jsの学習をしてました。(ちなみに今回私が使用しているのは初版です)

[Node.js超入門 第3版](https://www.shuwasystem.co.jp/book/9784798062433.html)




#Express Validatorが使えない？？
そこで学習を進めていると、以下のエラーが吐かれました。

```
TypeError: validator is not a function
    at Object.<anonymous> (作業フォルダ/app.js:38:9)
```

validatorが関数ではありませんと言われてしまいました。

そこで該当するソースコードをチェックしてみます。

```app.js
var validator = require('express-validator');

（省略）

app.use(validator()); //エラーの該当部分
```

validatorを利用する前には、requireでモジュールをロードして、変数validatorで定義しています。
スペルミスもないです。

**なぜエラーが？？？**

とそこで、この書籍はメルカリで購入した初版だったこともあり、誤字や古い情報がちょこちょこあるのを思い出しました。
それで以下から
[正誤表](https://www.shuwasystem.co.jp/support/download/5522/Seigohyo.pdf)
を確認すると

やっぱりあった！！


>>本書で使用している Express Validator は、現在 ver.6 となり、仕様が変更されているため、本書の記述の通りでは正常
に動作しなくなっています。
Express Validator をインストールする際、以下のようにして ver. 5 をインストールしてご利用下さい。
・既に最新版をインストールしている場合、アンインストール
npm uninstall express-validator
・ver.5 をインストール
npm install --save express-validator@5.3.1
[引用：Node.js 超入門［第 2 版］ 【正誤表】 - 秀和システム](https://www.shuwasystem.co.jp/support/download/5522/Seigohyo.pdf)


そもそもアプリにインストールしていた、Express Validatorに原因がありました。

正誤表の通りに再度、Express Validatorをインストールして無事エラーは解決しました。

なるべく新しい書籍を選ぶようにしたいけど、新品は高くて...~~(もっと給料上げて~)~~
特殊変数$1, $2, $3 ... で巨大な整数を使おうとすると、警告が表示される

Rubyには、`$1, $2, $3 ...`という特殊変数があり、`$n`には最後に成功したパターンマッチで n 番目の括弧にマッチした値が代入されます。

```ruby
"abc" =~ /(.)(.)(.)/
p $1 #=> "a"
p $2 #=> "b"
p $3 #=> "c"
```

[2020/09/26現在のるりま](https://docs.ruby-lang.org/ja/latest/method/Kernel/v/1.html)には

> 番号 n はいくらでも大きな正整数を利用できます。

とありますが、実際には超巨大な値を使おうとすると、warningが表示されます (遊んでいるときに気が付いた)

```
$ ruby -e '$9999999999999999'
-e:1: warning: `$9999999999999999' is too big for a number variable, always nil
```

こうなると`$n`のnとしてどれだけの値が使えるのか気になってくるので、簡単な二分探索を使った以下のコードで調べてみたところ、自分の環境では最大値は1073741823のようでした。

```ruby
require 'stringio'

ok = 0
ng = 10**10

while (ok-ng).abs > 1
  io = StringIO.new
  $stderr = io

  mi = (ok+ng)/2
  eval("$#{mi}")
  if io.size == 0
    ok = mi
  else
    ng = mi
  end

  $stderr = STDERR
end

p ok #=> 1073741823
```

別の方法で確認してみても、`$1073741823`が最大で、それよりも大きい値になると警告がでるようです。ただ1073741823という値はいかにも環境依存っぽいので、環境によってはもっと大きい値まで使えるかもしれませんし、もっと小さい値で警告が出てくるかもしれません。

```
$ ruby -e '$1073741823' 
#=> 何も起きない

$ ruby -e '$1073741824'
#=> 警告が出力される
#=> -e:1: warning: `$1073741824' is too big for a number variable, always nil
```

当然の疑問として、キャプチャ数が1073741823個を超える正規表現でマッチが成功した場合どうなるのかということですが、これは無問題。Rubyではキャプチャ数の上限が32767と決まっており、それを超えるような正規表現はコンパイルに失敗します。

```
$ ruby -e 'Regexp.compile("(.)"*32767)' 
#=> 何も起きない

$ ruby -e 'Regexp.compile("(.)"*32768)'
#=> RegexpErrorが発生する。メッセージは次の通り
#=> `initialize': too many capture groups are specified:
```

自分は以下のような二分探索を用いた簡単なスクリプトで32767という値を見つけましたが、Rubyの正規表現エンジンである鬼雲のソースコードを見ると、[`ONIG_MAX_CAPTURE_GROUP_NUM`というキャプチャ数の上限を示す変数があって、これが32767になっているようです。](https://github.com/ruby/ruby/blob/c5eb24349a4535948514fe765c3ddb0628d81004/include/ruby/onigmo.h#L438) であれば、特殊変数`$1, $2, $3 ...`の側の最大値を32767にしてもよいような気はしますが(´・ω・`)

```ruby
ok = 0
ng = 10**8

while (ok-ng).abs > 1
  mi = (ok+ng)/2
  begin
    Regexp.compile("(.)"*mi)
    ok = mi
  rescue RegexpError => e
    ng = mi
  end
end

p ok #=> 32767
```

**環境情報**

```
$ ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
```
【Chrome拡張ツール】OctotreeでGitHubをディレクトリツリーで直感的に操作する！

# はじめに
GitHub上で特定のファイルを探す時にエディタのように、
ディレクトリツリーを展開しながらファイルを探せたらいいな、とずっと思っておりました。　　

もちろんGitHubもツリー構造にはなってますが、いちいち画面のロードを挟むし、上位階層に戻る時など若干の煩わしさを感じておりました。  
特にフレームワークを使っている場合などは、どんなディレクトリ/ファイルがぶら下がっているかを視覚で感じながら操作できたらより便利だと思います。

そんな時に知ったのが「Octotree」というChromeの拡張ツールです。
知っている人には今さらだと思いますが、便利だったので紹介します。

## Octotree

Chromeの「Octotree」という拡張ツール。
これを使うことによってエディタのディレクトリツリーのようにリアルタイムにツリーを展開していくことが可能となります。

**まずは通常のGitHubの画面。**

![スクリーンショット 2020-09-26 15.30.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530688/b624a271-705f-68e4-ecec-2a7bd5a635ba.png)

みなさんお馴染みの画面かと思います。
通常であれば、検索機能で目的のファイルやキーワード検索をしたり、クリックでポチポチ画面遷移をしながらツリーを展開します。

**次にOctotree導入後の画面**

言葉での説明ではイメージしづらいので、実際の動きをご覧ください。

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530688/5f75d829-a06a-f3f3-ac5a-1f12c0cfab41.gif)

画面の左に「Octotree」というタブが表示されるようになり、
カーソルをマウスオーバーするとディレクトリツリーが表示されます。
command + shift + s(Mac)でOctotreeの表示/非表示のショートカットもあります。
あとはポチポチと展開していくだけ。
検索も可能です。


地味な機能ではありますが、ツリー構造を直感で把握/操作できるので気に入ってます。

# 使い方

1. [Chromeウェブストア](https://chrome.google.com/webstore/detail/octotree/bkhaagjahfmjljalopjnoealnfndnagc) からOctotreeをダウンロード
2. GitHubで公開リポジトリを開くと、「Octotree」のタブが表示され使用できるようになります。
※表示されない場合はChromeの拡張ツールの設定で有効になるように指定しましょう。

※使用時にプライベートリポジトリではGitHubのアクセストークンの入力を求められるので、
GitHubの**Settings > Developer settings > Personal access tokens**
の画面で「Generete new token」からOctotree用にトークンを生成して、Octotreeに設定します。
[GitHubのPrivate access tokensの詳細はこちらの公式Docへ](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token)
※トークン名は任意のものでOKです。
※Generate new tokenで設定するscopeは「repo」のみでOKです。
※GitHub Enterpriseで使用する場合はアクセス権限の許可が必要です。

![スクリーンショット 2020-09-26 16.10.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530688/db31c3a6-d58e-876c-3477-47e9bd41b852.png)

![スクリーンショット 2020-09-26 16.15.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530688/35c44281-3108-215c-a22e-b1799e38fe64.png)

![スクリーンショット 2020-09-26 16.20.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530688/5b6d76b1-c769-2335-7186-2c4204bf7136.png)

![スクリーンショット 2020-09-26 16.20.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530688/3a8e7618-7970-21f9-5ba5-143f8ccaa984.png)

![スクリーンショット 2020-09-26 16.23.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530688/c1cf29cc-68ef-5dca-71b1-d98df6b1aada.png)


# 最後に

Octotreeを使用するとGitHunでのファイルアクセスが格段に便利になるので、
ご存知なかった方は使ってみてはいかがでしょうか。
※GitLabでも使えるみたいです(詳しく見てませんが)。

最後まで読んで頂きありがとうございました。
コンフィギュレーション・マネジメント、アーンド・バリュー・マネジメント、コンフリクト・マネジメント、ポートフォリオマネジメント


応用情報技術者平成28年秋期 午前51

PMBOKの統合変更管理プロセスにおいて，プロジェクトのプロダクト，サービス，所産，構成要素などに対する変更と実施状況を記録・報告したり，要求事項への適合性を検証する活動を支援したりする活動はどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/f5ccfa44-73dc-519e-c1a6-4ad30059b984.png)


１、
・アーンド・バリュー・マネジメント
⇒×。アーンド・バリュー・マネジメント(EVM)は、プロジェクトにおける作業を金銭の価値に置き換えて定量的に実績管理をする進捗管理手法です。コストマネジメントやタイムマネジメントにおいて使用されます。

・コンフィギュレーション・マネジメント
⇒×。コンフィギュレーション・マネジメントは、構成管理とも呼ばれ、変更に係る次の作業を実施する活動です。
　・プロダクト・構成要素などの仕様・特性を文書化する
　・変更の実施状況を記録し報告する
　・変更事項の適合性を検証する監査に情報を提供する

・コンフリクト・マネジメント
⇒×。コンフリクト(Conflict)とは、日本語で「紛争」「葛藤」「衝突」「争い」などを意味を持つ言葉です。コンフリクト・マネジメントは、プロジェクト内で発生するコンフリクトを解決しチームを成功に導くための活動です。

・ポートフォリオマネジメント
⇒×。ポートフォリオマネジメントは、組織が抱えている多数のプロジェクトを区分し、資源配分の最適化を目指す活動です。


参照：
https://www.ap-siken.com/kakomon/28_aki/q51.html
SSL インスペクション環境下で Kaggle API を使う

## 概要

社内教育など、会社が学校から Kaggle API を使いたくなる場面があると思います。ところが、会社や学校では大抵 [UTM](https://ja.wikipedia.org/wiki/統合脅威管理) が導入されており、外部の API を使うことは容易ではありません。

[一部の UTM は SSL インスペクション機能を提供](https://www.zscaler.jp/products/ssl-inspection)しており、SSL で暗号化された通信を監視するためにプロキシサーバー上で一度通信を復号化します。この復号化の際にサーバー証明書が UTM が独自に発行したものに差し替わるため、クライアント側に UTM の独自 CA 証明書をインストールし、その CA 証明書を使って認証する必要があります。

認証に使う CA 証明書の指定方法はアプリケーションによって異なり、OS の環境変数を参照するものと、アプリケーション固有の設定ファイルで指定するものがあります。Kaggle API は後者で、[設定ファイル `kaggle.json` に CA 証明書を指定する裏オプションを持っています](https://github.com/Kaggle/kaggle-api/search?q=ssl_ca_cert)。ただし、この記事を書いている時点の [v1.5.8 の README](https://github.com/Kaggle/kaggle-api/blob/bc19055b304f32dd4a53df1238119b4a8dd54230/README.md) にはこのオプションは明記されていないため、今後のバージョンアップでひっそりと使えなくなるかもしれません。

## 解決方法

### 1. UTM の独自 CA 証明書をインストール

UTM の独自 CA 証明書をインストールします。独自 CA 証明書の入手方法は UTM 毎に異なるため、UTM の管理者に聞いてください。独自 CA 証明書を入手したら、インストールします。インストール方法は以下の記事が詳しいです。

[独自(root)CA のインストール方法](https://qiita.com/msi/items/9cb90271836386dafce3)

### 2. Kaggle API の設定ファイルに独自 CA 証明書のパスを指定

kaggle.json の `ssl_ca_cert` オプションに、独自 CA 証明書のパスを指定します。以下は Ubuntu の場合です。Ubuntu だと全 CA 証明書を束ねた CA バンドル `/etc/ssl/certs/ca-certificates.crt` があるので、それを指定します。

少し脱線しますが、Kaggle API はプロキシサーバーも設定ファイルで指定します。OS の環境変数 (`HTTP_PROXY` など) は読み込んでくれないため、注意してください。

```json
{
  "username": ***,
  "key": ***,
  "proxy": ***,
  "ssl_ca_cert": "/etc/ssl/certs/ca-certificates.crt"
}
```
MySQL の procedure で大量のデータを用意してみる（速くはない）

適当に以下のようなデータをほしいとします。今回は10万レコードを作成してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45822/e46dd563-8702-48b7-c576-1d320c57ea5f.png)

# その1 procedure でやってみる

```sql
create table hoge (num int, name varchar(255));

delimiter //
create procedure insert_hoge(in x int)
begin
  declare i int default 1;
  set @q = "insert into hoge values ()";
  while i < x do
    set i = i + 1;
	set @q = concat(@q, ',()');
  end while;
  prepare stmt from @q;
  execute stmt;
end
//
delimiter ; 

call insert_hoge(100000);

/* 適当に null で10万行埋めてから、update でランダムな値にする */

update hoge set
  num = round(rand()*100000),
  name = concat('name', round(rand()*100000));
```

これはそんなに速くなくて15秒くらいかかります。

# その2 cross join でやってみる


こっちの方が早いです5秒くらいですみます。


```sql
create table piyo (num int, name varchar(255));

insert into piyo values (), (), (), (), (), (), (), (), (), ();

insert into piyo (select piyo.num, piyo.name from piyo, piyo p2, piyo p3, piyo p4, piyo p5);

update piyo set
  num = round(rand()*100000),
  name = concat('name', round(rand()*100000));
```

# その3 procedure で、値もいれてみる

update を無くして、最初からランダムを insert してみます。これは遅くて30秒くらい

```sql
delimiter //
create procedure hoge(in x int)
begin
  declare i int default 0;
  set @q = "insert into hoge (num, name) values ";
  while i < x do
    set i = i + 1;
    set @name_value = concat('name', round(rand()*10000));
    set @value = concat('(', i , ', "', @name_value, '")');
    if i = 1 then
  	  set @q = concat(@q, @value);
  	else
	  set @q = concat(@q, concat(',', @value));
	end if;
  end while;
  prepare stmt from @q;
  execute stmt;
end
//
delimiter ;
```

# その4 procedure でバルクインサートしない場合

while の中で毎回 insert などをすると、たぶん2分以上かかると思います。

# まとめ

procedure でぴったり狙った件数のデータを出すのはかっこよさそうですが、速さは cross join でやる方が早いので、そちらの方が実用的かと思います。

procedure の中で、user-defined variable や prepared statement 使ってみたりして勉強になりました。
プロパティアクセスで無限にアクセスしてみる

# 前置き

注意：この記事はとりあえず書いてみたかったので書いただけで、特に深い意味もなければ学ぶ事も特にないと思います。それでも良い方はどうぞ

# コードを書いてみる

```js:a.js
const a = {a:1,b:1};
a.a = a;
console.log(a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.b);
```
（このconsole.log内を書きたかったがために記事を書いてる）

# コードの説明
これだけだとtwitterにでも投稿してろ、となるのでコードの説明。

## 一行目
a,bのキーを持つオブジェクト`a`を用意する。
この時、オブジェクトの`a`と、キーのaは全く別物なので注意

##二行目
オブジェクト`a`のキーaに、オブジェクト`a`を代入する。
なお、`a.a`のようにドットでアクセスするのを__[プロパティアクセサー](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Property_Accessors)__といい、オブジェクトのキーにアクセスする方法の一つ[^5]。javascriptでこの記法を避けて通るのは不可能[^4]なので記述方法自体は誰でも知っているはず。
[^5]: もう一つは`a["a"]`という方法。キーを_文字列_ で指定する必要がある。
[^4]: `document.getElementById`という表記で既に使っているし。
元々int型の`1`が入っていたのにオブジェクト型の`a`を代入できるのは、javascriptに型の指定が無いから。
この代入により、オブジェクト`a`のキーaには、元々のオブジェクト`a`自体が入っている。

ちなみに、javascriptは参照渡しのような動作[^1]を行うため、`a===a.a`はtrueになる。
なので、`a===a.a.a`もtrueになり、無限に辿ることが出来るようになる。

## 三行目
無限にアクセスできるaを辿り、bを出力する。
もちろん最後の`a.b`は、単純に`a.b`を記述したのと同じなので、定義したb=1が出力される。
ただ、実際に無限に書くのは難しいものもあるので、ここでは20個で止めている。

# 終わりに
実際にこのような使い方をすることはまず無いとは思いますが、参照渡しの言語だとこういう事もできるよというお話でした。


[^1]: 曖昧表現の理由：[JavaScriptに参照渡し/値渡しなど存在しない](https://qiita.com/yuta0801/items/f8690a6e129c594de5fb)
[ASP.NET Core] HTMLヘルパーを使ってリスト形式の入力画面を作るときの注意

#HTMLヘルパーを入力画面かつList型のクラスで使うときの注意
ASP.NET Core (MVC)でHTMLヘルパーを使って、テーブルタグで複数行入力し、List型のクラスでポストデータを受け取る画面を作ろうとしたら、入力データがポストされずハマったのでメモ

結論はforeachじゃなくて普通のforでやればOK

## NG
foreachだとpostされてこないよ

```
@foreach (var row in Model.Rows)
{
<tr>
    <td>@Html.EditorFor(m => row.ColA)</td>
    <td>@Html.EditorFor(m => row.ColB)</td>
</tr>
}
```


## OK
forだとOK

```
@for(var i = 0; i < Model.Rows.Count; i++)
{
<tr>
    <td>@Html.EditorFor(m => m.Rows[i].ColA)</td>
    <td>@Html.EditorFor(m => m.Rows[i].ColB)</td>
</tr>
}
```
SceneKitに平面のラベルを貼る方法

SceneKitに平面のラベルを貼って情報を出す方法のメモ。

**仕上がり**
<img width="300px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116010/bf118f26-26e4-cd6a-1c8d-6c0b3ef2ad03.png">

1. `GameViewController.swift`に次のコードを追加する。

```swift:GameViewController.swift
import SpriteKit
class LabelScene: SKScene {
    override public init(size: CGSize){
        super.init(size: size)
        
        self.scaleMode = SKSceneScaleMode.resizeFill
        
        let label = SKLabelNode(fontNamed: "Chalkduster")
        label.text = "test"
        label.fontSize = 65
        label.fontColor = .blue
        label.position = CGPoint(x:frame.midX, y: label.frame.size.height)

        self.addChild(label)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("Not been implemented")
    }
}

```

2. `GameViewController.swift`の`viewDidLoad`の最後にコードを追加する。

```swift:GameViewController.swift
scnView.overlaySKScene = LabelScene(size:scnView.bounds.size)
```

これで、画面上にラベルが表示されます。
音声分析におけるフーリエ変換後の声の高さ（ヘルツ）を理解する

# はじめに

音声分析において、フーリエ変換後の周波数領域で、声の高さ（ヘルツ）がどのように得られるのかをまとめた。

この記事は、私が前に書いた記事を読んでからの方が理解しやすいように思う。
[音声分析におけるフーリエ変換とスペクトログラムを理解する](https://qiita.com/shirowanisan/items/6af2cc4c4be0c57bef06)

# 周波数とヘルツ(Hz)

- 周波数：`単位時間あたりの振動数`のこと。単位時間とは1秒ではなく任意。
- ヘルツ(Hz)：`周波数の単位`。周波数の単位がヘルツの場合は`１秒あたりの振動数`。

人間は`音の高さ`を`１秒あたりの振動数`で認識する。そのため、周波数の単位がヘルツ(Hz)でないと、音の高さを知ることができない。しかし、python等のライブラリでフーリエ変換を行う場合は、周波数領域の単位が得られないことが多い。では、どのように周波数領域の単位をヘルツに変換するのかを考える。

![スクリーンショット 2020-09-26 14.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651198/8c0ffefe-f7bb-699c-2a56-05aac073d7be.png)

# wavファイルの1秒とは

wavファイルの時間軸の何点が1秒間であるかは`単位付きのサンプリング周波数`で示される。「単位付きの」と表現しているのは、上記で説明した通り、`サンプリング周波数に単位がない場合は1秒あたりでない可能性がある`からだ。サンプリング周波数の単位がヘルツの場合は`wavファイルの1秒間の点数`を示す。サンプリング周波数(Hz)は1秒を何点で表すかであり、音の高さを示す周波数ではないので注意が必要。

![スクリーンショット 2020-09-26 14.44.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651198/489ceabe-6b7e-a84c-39ea-1d568811e748.png)

ちなみに、点で波の1周期を描画するためには最低でも2点必要である。そのため、サンプリング周波数20kHzで描画できる最大の波の振動数は10000周期。すなわち、サンプリング周波数20kHzのwavファイルで表現できる音の最大周波数は10kHzまでである。

|サンプリング周波数|wavを音にしたときに表現できる最大の周波数|
|-------------------|----------------------------|
|20kHz|10kHz|
|30kHz|15kHz|
|40kHz|20kHz|

人は約20kHzまでの音しか聞こえないと言われている。そのため、サンプリング周波数はだいたい40kHzあれば良いと言われている。

# フーリエ変換後の周波数領域でのヘルツ(Hz)

では、音声ファイルをフーリエ変換した場合、周波数領域の単位がどのようになるか考える。まずは、wavファイルの条件を明確にする。今回はサンプリング周波数20kHzで時間軸の点数40000点（2秒）のwavファイルで考える。

|サンプリング周波数|音の最大の周波数|1秒あたりの点数|時間軸の点数|
|---------------|------------------------------|-------------|--------|
|20kHz|10kHz|20000点|40000点（2秒）|

このwavファイルをフーリエ変換する。フーリエ変換は時間領域全体に対して適用される。そのため、フーリエ変換後の周波数は`40000点（2秒）を単位時間とした値`となる。ここで、1秒を単位時間とするには`20000（サンプリング周波数）/40000（横軸の点数）`をかければ良い。すなわち、今回の場合は周波数領域の周波数軸を`1/2`することで、単位をヘルツ(Hz)に変換することができる。これで、周波数領域でも音の高さを知ることができる。

![スクリーンショット 2020-09-26 14.41.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651198/66cb18b3-dd38-2941-a03f-a46aa85a8ad2.png)

# 短時間フーリエ変換後の周波数領域でのヘルツ(Hz)

では、音声ファイルを短時間フーリエ変換した場合、周波数領域の単位がどのようになるか考える。wavファイルと短時間フーリエ変換の条件は以下のようにする。

|サンプリング周波数|音の最大の周波数|1秒あたりの点数|時間軸の点数|短時間フーリエ変換の窓幅の点数|
|---------------|------------------------------|-------------|--------|--------|
|20kHz|10kHz|20000点|40000点（2秒）|2000点（0.1秒）|

このwavファイルを短時間フーリエ変換する。短時間フーリエ変換は時間軸に対して窓幅ごとに適用される。そのため、フーリエ変換後の周波数は`2000点（0.1秒）を単位時間とした値`となる。ここで、1秒を単位時間とするには`20000（サンプリング周波数）/2000（窓幅の点数）`をかければ良い。すなわち、今回の場合は周波数領域の周波数軸を`10倍`することで、単位をヘルツ(Hz)に変換することができる。これで、周波数領域でも音の高さを知ることができる。

![スクリーンショット 2020-09-26 14.42.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651198/af65c5c4-d16f-9374-3c7f-b20c66106508.png)

# ヘルツ(Hz)でスペクトログラムを見る

縦軸を周波数(Hz)、横軸を時間(秒)でスペクトログラムを作成した。どちらの声が高いか、スペクトログラムからも読み取れる。

![スクリーンショット 2020-09-26 15.05.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651198/c8cac6de-2c14-2b2a-b494-0b5567c808b4.png)
【2D OD】YOLO v1 v2 v3の歴史


<h1>YOLOとは?</h1>
モデルの由来でもあるYou Look Only Once、1stageのObject Detectionを提案したのがYoloとなる。
これまではRCNNなどの2stageが主流であった。
1stageにすると初期のBounding Box(Anchor)を定義するから、offsetのみを推定すれば良くなる。そうすると推定の複雑さが減り、さらに計算コストも下がるという事で提案された。

<h1>YOLO(V1)</h1>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/b89544d1-850c-5b40-f709-9ae316eebd9e.png)

RCNNでは2000個のBonding Boxを推定していたがYOLOではSxSxB(7x7x2=96)個のBounding Boxのみを推定すれば良くなった。

<h3>パイプライン</h3>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/79a8976d-4864-8481-87cc-311496c9022f.png)

1. 画像サイズを448x448(任意の値)に変換する
2. CNNを用いてDetection
3. 出てきたoutputは同じ物体をいくつも検出してる事があるので、Non-maximum suppression(IOUが一定値以上の場合Confidence Scoreが一番高い物のみを出力)を行う

<h3>出力の定義</h3>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/2dd68fc7-7bf2-90fb-7b37-8743cf62f91a.png)

1.　入力画像をSxS(7x7)のグリッドに分割する
2.　それぞれのグリッド毎にB個のBounding Box(位置やサイズ)とC個のクラスの確率(それぞれ0~1)
3.　出力は下記の式のようになる


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/9033fb95-4849-0761-00e0-597db74aee11.png)

S ->Grid Size(7)
B ->Bounding Boxの数(2)
C ->分類するClassの数(20)
5 ->x,y,w,h,confidence


<h1>YOLOV2</h1>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/3057d881-cb9b-39d7-29b8-93de856247c4.png)


<h3>アンカーボックス</h3>
YOLO(V1)では各グリッド毎に物体の位置を直接求めていたのに対して、[Anchor Box](https://qiita.com/minh33/items/14667f38f7a169859db1)のオフセットを学習する事で、問題が簡素化され学習しやすくなった

<h3>小さい物体の検出</h3>
YOLOV1では小さい物体の検出が困難という課題があった。7*7のグリッドサイズを13*13にした所小さな物体の検出がしやすくなった

<h3>Batch Normalizationの追加</h3>
Batch Normalizationにより学習の安定化

<h3>Multi-Scale Trainingで物体サイズへの多様化</h3>
YOLOV1ではサイズの物体があると物体の検出が困難であった。入力画像のサイズをランダムに変えて学習する事によって、様々なサイズの物体を学習する事が出来、精度が向上





<h1>YOLOV3</h1>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/bdc0bb35-a343-888f-cb6d-543331227376.png)

<h3>Bounding Boxにobjectness Scoreの追加</h3>
それぞれのBounding Boxにobjectness Scoreが推定されるようになった。
そうする事によって推定されたBounding BoxがGround Truthにoverlapせずにassignされなかった場合にobjectness scoreがlossとしてobjectness scoreを下げる事が出来る。FP(False Positive)が減る


<h3>Class Predictionのsoftmaxの除去</h3>
YoloV2ではSoftMaxを使い物体の確率を出していた。
この方法で人間と男性の確率は0.45:0.55みたいになる。
しかし男性は人間でもあるため、0.9:0.87みたいな結果が欲しい。

<h3>FPN(Feature Pyramid Networks)構造の導入</h3>
FPNを使う事でGlobalとLocalの情報を得る事が出来る。

<h3>複数解像度の物体検出</h3>
52x52,26x26,13x13のそれぞれの解像度で物体を推定する事でNetworkの安定化する。

<h1>結論</h1>
・過去のupdateを見ると色々と実験されて今の状態があるだなと感じた

<h1>参考文献</h1>
You Only Look Once:Unified, Real-Time Object Detection
https://pjreddie.com/media/files/papers/yolo.pdf

YOLO9000:Better, Faster, Stronger
https://arxiv.org/pdf/1612.08242.pdf

YOLOv3: An Incremental Improvement
https://arxiv.org/abs/1804.02767
カタカナ語わかんない！

プログラミングの本を読む時に引っかかるポイントというのは数あるが、
自分はその中でまず真っ先にこれをあげたいと思う。


**専門用語のカタカナ語の意味がわからねえ！**


いやジャーゴンの有用性はわかる。
このジャーゴンという表現自体が一々部外者には通じない専門用語という長々とした文章を書かなくていいというメリットになっているんだ、わかる。
だったらただ『専門用語』といえばいいだろ！
目慣れないカタカナを使うな！
日本語が表意文字である力を活用しろ！
一々ニュアンスを頭の辞書から引っ張り出して来るのがめんどくさいんだよ！！！

と言う訳で、よく見かけるカタカナ語を平易かつ雑に和訳することにした。
雑な和訳なので完全にニュアンスを再現できている訳ではないが、とりあえず目慣れなさによる混乱や自信のなさぐらいは防げるだろうと思う。

##クラス
**ひな形**。

##フィールド
**（オブジェクトの）持ち変数**。

##インスタンス
**クラスから作る奴**。
**一時作成物**。

##メソッド
**指示**。

##メンバ
**（クラスの）中身**。
フィールド（持ち変数）とメソッド（持ち指示）のこと。

##コンストラクタ
**新規オブジェクト作成関数**。

##オーバーライド
**（継承前との）被り名上書き**。

##シングルトン
**一人っ子**。

##コンパニオン
**同名仲間**。

##インターフェース
**異種接続**。

##
****
SPF(Sender Policy Framework)検証の仕組み

応用情報技術者平成28年秋期 午前43


受信した電子メールの送信元ドメインが詐称されていないことを検証する仕組みであるSPF(Sender Policy Framework)の特徴はどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/d678c242-f5ec-79c2-e23e-b9a94ce55902.png)


１、SPF(Sender Policy Framework)は、
SMTP接続してきたメールサーバのIPアドレスを基に、正規のサーバから送られた電子メールかどうかを検証する技術です。受信メールサーバ側にて電子メールの送信元ドメインが詐称されていないかを検査できます。

SPFでは以下の手順で送信元IPアドレスの検証を行います。
・送信側は、送信側ドメインのDNSサーバのSPFレコード(又はTXTレコード)に正当なメールサーバのIPアドレスやホスト名を登録し、公開しておく。

・送信側から受信側へ、SMTPメールが送信される。

・受信側メールサーバは、受信側ドメインのDNSサーバを通じて、MAIL FROMコマンドに記載された送信者メールアドレスのドメインを管理するDNSサーバに問い合わせ、SPF情報を取得する。

・SPF情報との照合でSMTP接続してきたメールサーバのIPアドレスの確認に成功すれば、正当なドメインから送信されたと判断する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/29c2a6c3-7765-501d-42b0-331e7b89f477.png)


大事のことは、SPFレコードを登録・公開するとのこと。
ドメインを検証するので、直接にそのドメインで正当性を確認する意味がないですね。
そのドメインのIPアドレスが正当性があるかを確認すればよいとのこと。


※DNSBL(DNS Blacklist)とは、
迷惑メールの温床になっているオープンリレーサーバのIPアドレスや、スパム行為の発信元IPアドレスを一覧を公表したもの

※DNSサーバは、コンピュータ・ネットワークにおいて、Domain Name System（DNS）の「名前解決」機能が実装されたサーバである。



参照：
https://www.ap-siken.com/kakomon/28_aki/q43.html
通信処理で重くなり過ぎないようにするには

API呼び出しなど、ネットワークを通じてリクエストを投げる・レスポンスを受け取るなどはコストのかかる処理で、呼び過ぎるとユーザーの回線に余計な負担を与える。また時間がかかるため、反応が遅いと感じられUXに悪影響を与えることがある。そのためどこでどう呼ぶかを考える必要がある。

### 呼ぶAPIの数の制限

例えばアプリなどで一画面で呼ぶAPIが多すぎると遅くなってしまう。そのため、1画面で呼ぶAPIは２〜３個までなどある程度基準を設け、一度に呼ぶAPI数が多くなり過ぎないように設計する。
 
### 回線状況の考慮

できれば、ユーザーがそのアプリ等を使う状況を考慮に入れ、通信回線がどのくらい良いかも念頭に置いておくと良い。例えば、電車の案内のアプリであれば、電車内とりわけ地下鉄など電波状況の悪い場所で使う場合もあることから、そのような場面であまり時間のかかる処理を入れるのは好ましくない。

### APIを呼ばなくて済むのではないか検討

同じデータを取ってくるだけなのに何度もAPIを呼ぶのは無駄である。そのため、一度取ってきたデータをデバイスのメモリに一時保存、あるいはストレージに恒久保存して対処する事ができないかを検討する。

また一部のデータが欲しいだけなのに、多くのデータを取ってくるAPIを呼ぶなどもやはり無駄となる。

なるべく通信を節約しようとすれば、何度もAPIを呼ばずに既に呼んだAPIの結果をある程度使い回すなどの動作をする必要があり、プログラムが複雑になってくる。どこまでそうした動作をするかはプロジェクトの状況によって違うが、普段からそういう状況でどうコーディング・デバッグするか知見を積み重ねていく事が重要。

### APIを呼んでいる最中の対応

APIを呼んでいる最中、UIまでも止まってしまう（タップとかクリックとかユーザーの反応を受け付けなくなる）とフリーズしたかのような印象をユーザーに与えてしまう。そのため、通信処理とUI処理のスレッドを分けるなどして対処する。

また、通信処理が終わるまでの間、100ms~200ms程度異常かかるようであればローディングの表示（グルグル回るアイコン、またはゲージが徐々に満タンに近づくバーなど）をするのが望ましい。この場合、通信の開始時にローディング表示を開始する。そして通信が成功しようと失敗しようと、通信が終了すればローディング表示を止めることになる。

### 参考

[MdN Design -［優れたUXを目指して］アプリの性能について：第３回](https://www.mdn.co.jp/di/tech/4816/73696/)
[Android Developers - Keeping your app responsive](https://developer.android.com/training/articles/perf-anr)
相関副問い合わせ


#相関副問い合わせの勉強

``` ``
create table Test(id integer, title varchar(100),syouhinid integer);
create table syouhin(id integer, title varchar(100));

insert into Test(id, title,syouhinid) values(1, "kazu",100);
insert into Test(id, title,syouhinid) values(2, "yamada",200);
insert into Test(id, title,syouhinid) values(3, "todoroki",500);

insert into syouhin(id, title) values(100, "tako");
insert into syouhin(id, title) values(200, "ika");
insert into syouhin(id, title) values(300, "saba");

-- select * from Test;
-- select * from syouhin;

-- select * from Test where exists (
-- 	select 1 from syouhin
-- 	where syouhin.id = Test.syouhinid)

update Test Set 

Test.title=(
	select syouhin.id from syouhin
	where syouhin.id = Test.syouhinid
)

where exists (
	select 1 from syouhin
	where syouhin.id = Test.syouhinid);


select * from Test;
-- Your code here!
ServiceNow - Display Business Ruleの利用

#概要
ServiceNowではサーバからの情報をフォームに表示する場合はGlideAjaxを使う場合が多いです。
例えばログインされているユーザの社員番号を表示させるにはクライアントスクリプトからGlideAjaxを利用してScript Includeに定義したスクリプトを呼び出します。
GlideAjaxは非同期通信のためにクライアント側に結果が送り返されるまでに数秒時間が掛かる場合もあります。
Display Business Ruleはフォームが作成される前に呼び出されるため、クライアントスクリプトから呼び出される必要はありません。そのため、直ぐにフォームに反映されます。

#仕組みと制限
Display Business Ruleを利用する場合はフォームが関連するデータベーステーブルに表示ビジネスルールを定義します。そのルール内でg_scratchpdに値を設定します。onLoadクライアントスクリプトでその値を参照することができます。
要するにインシデントフォームで使うことはできますが、テーブルと関連していないカタログクライアントスクリプトからは使えません。

#実装
##ビジネスルール
次のようなビジネスルールを作成します。
![display_business_rule_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/625d60d5-9c38-66dc-2ce1-fb02376c22a9.png)
1.項目「時期」を「表示」に設定します。
2.スクリプトを記述するので「詳細」をチェックします。
![display_business_rule_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/83f15f30-91fe-6c61-23f6-f6d0083fce34.png)
3.フォームで必要な値をg_scratchpadに設定します。

##クライアントスクリプト
1.スクリプトを実行するフォームを開きます。
2.フォームにクライアントスクリプトを定義します。
「他のアクション」アイコンをクリックして、「構成」＞「クライアントスクリプト」を選択します。
![display_business_rule_client_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/678bc0a5-dc95-634a-3287-4414f8e8bcc7.png)
3.ビジネスルールと同じテーブルを指定します。
スクリプトにビジネスルールで設定したスクリプトを利用することができます。
![display_business_rule_client_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/abfbc0a8-add2-2c5e-ef43-6aefe7f9eb9c.png)

以上
Vue3の環境にVuetifyがインストールできない

#Vue3の環境にVuetifyがインストールできない

vue add vuetifyを実行した時、次のようなエラーがでて、インストールが完了しません。

```
 Error: You cannot call "get" on a collection with no paths. Instead, check the "length" property first to verify at least 1 path exists.
Error: You cannot call "get" on a collection with no paths. Instead, check the "length" property first to verify at least 1 path exists.
    at Collection.get (/home/masa/.n/lib/node_modules/@vue/cli/node_modules/jscodeshift/src/Collection.js:213:13)
    at injectOptions (/home/masa/.n/lib/node_modules/@vue/cli/lib/util/codemods/injectOptions.js:15:6)
    at runTransformation (/home/masa/.n/lib/node_modules/@vue/cli/node_modules/vue-codemod/dist/src/run-transformation.js:61:17)
    at /home/masa/.n/lib/node_modules/@vue/cli/lib/Generator.js:290:23
    at Array.forEach (<anonymous>)
    at Generator.resolveFiles (/home/masa/.n/lib/node_modules/@vue/cli/lib/Generator.js:276:24)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async Generator.generate (/home/masa/.n/lib/node_modules/@vue/cli/lib/Generator.js:175:5)
    at async runGenerator (/home/masa/.n/lib/node_modules/@vue/cli/lib/invoke.js:111:3)
    at async invoke (/home/masa/.n/lib/node_modules/@vue/cli/lib/invoke.js:92:3)
```

# 解決策

vuetify3がリリースされるまで待つ


https://github.com/vuetifyjs/vuetify/issues/11162#issuecomment-616353160

以下の試したことを実行すると上のエラーは解消するが別のエラーがでて動きません。

# 試したこと

main.jsに次のコードを書いてから、vue add vuetifyを実行する。

```
new Vue({
    render: h => h(App),
}).$mount('#app');
```
jQueryでセレクトボックスの選択要素を移動する

二つセレクトボックス（Selectタグ)があるサイトで、片方のセレクトボックスの選択要素を別のセレクトボックスに移動させるメモ

移動元の指定をoption:selectedにするのがミソ
```$("#移動元SelectタグのID option:selected").appendTo($("#移動先SelectタグのID"));```

移動ではなくコピーしたいときはclone()を挟むだけ
```$("#コピー元SelectタグのID option:selected").clone().appendTo($("#コピー先SelectタグのID"));```

##Sample
``` html:html部分
<!-- 移動元 Selct Tag-->
<select id="selectFrom" size="10">
    <option value="1">りんご</option>
    <option value="2">みかん</option>
    <option value="3">なし</option>
    <option value="4">いちご</option>
</select>

<!-- 移動先 Selct Tag-->
<select id="selectTo" size="10">
    <option value="5">ぶどう</option>
</select>

<!-- 実行ボタン-->
<input type="button" id="move" value="->" />
```
``` javascript:javascript部分
<script type="text/javascript">
    $(function () {
        $("#move").on("click", function () {
            // 移動元のSelectから移動先のSelectに移動
            $("#selectFrom option:selected").appendTo($("#selectTo"));

            // 移動ではなくコピーしたいときはclone()を挟むだけ
            // $("#selectFrom option:selected").clone().appendTo($("#selectTo"));
        });
    });
</script>
```
ハイブリッド暗号方式（hybrid cipher）

応用情報技術者平成28年秋期 午前42

OpenPGPやS/MIMEにおいて用いられるハイブリッド暗号方式の特徴はどれか。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/132ce742-7b75-a511-9225-46bf67e0894e.png)


１、ハイブリッド暗号方式は、 hybrid cipher
公開鍵暗号方式を用いて共通鍵を通信相手へ安全に配送し、以後はその共通鍵を使用して暗号化通信を行う方式です。TLSやS/MIMEで採用されています。

※hybrid 　交配種、雑種、混血、掛け合わせ／合成物、混成物

それぞれの暗号方式を他方と比較すると次のような短所があります。
・共通鍵暗号方式
　　・安全に鍵を配送するのに手間が掛かる
　　・通信相手が増えると必要な鍵数が多くなる

・公開鍵暗号方式
　　・暗号化・復号に要する計算量が多いため処理に時間が掛かる


ハイブリッド暗号は、両者を組み合わせることで、鍵を安全に配送しながら低い処理負荷での暗号化・復号を可能にしています。


参照：
https://www.ap-siken.com/kakomon/28_aki/q42.html
初めてのGitコマンド一覧【初心者向け】

エンジニア4ヶ月目のtomoakiです。
実務でよく使っているGitコマンドについて、備忘録も兼ねてまとめていきます。

現場に入りたてのエンジニアがよく使うコマンドを中心に記載しているので、過不足あると思いますがご容赦ください。m(_ _)m
適宜、追加していく予定です。

#git init
gitプロジェクトを新規作成します。
作成したいディレクトリに移動してから`git init`コマンドを叩いてください。

```
$ git init
Initialized empty Git repository in <ディレクトリ名>/.git/
```

#git clone
指定したリポジトリ名のプロジェクトを、指定したディレクトリにコピーします。


```
＄ git clone <リポジトリ名> <ディレクトリ名>

Cloning into '<ディレクトリ名>'...
remote: Enumerating objects: 190, done.
remote: Counting objects: 100% (190/190), done.
remote: Compressing objects: 100% (128/128), done.
remote: Total 190 (delta 53), reused 172 (delta 38), pack-reused 0
Receiving objects: 100% (190/190), 70.62 KiB | 420.00 KiB/s, done.
Resolving deltas: 100% (53/53), done.
```

#git status
ワーキングツリー、ステージングエリアの状況を確認します。
変更したファイルや新規追加したファイルがステージングエリアにある場合は以下のように表示されます。

```
$ git status

On branch <ブランチ名>
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   <変更したファイル名>

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	<新規作成したファイル名>
```
ステージングエリアに追加したファイルがある場合は、以下のように表示されます。

```
＄ git status

On branch <ブランチ名>
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   <ステージングエリアに追加したファイル名>
```


#git add
ワーキングツリーで編集したファイルをステージングエリアにアップします。

```
# ファイル名を指定して追加する場合
$ git add <ファイル名>

# ステージングエリアの全てのファイルを追加する場合(.は全てのファイルを意味します)
$ git add .

# 編集したファイルの一部を追加する場合
$ git add -p
```
`-pオプション`をつけて実行すると、以下が表示されます。
表示された箇所を追加する場合は`「y」`、追加しない場合は`「n」`、さらに細かく指定する場合は`「s」`を入力します。

```
(1/1) Stage this hunk [y,n,q,a,d,s,e,?]?
```
`-pオプション`は、便利なので覚えておくと何かと役に立ちます。

#git commit
ステージングエリアに上がっているファイルをローカルリポジトリにコミットします。
`-mオプション`で、コミットメッセージを追加できます。

```
＄ git commit -m "<コミットメッセージ>"

[master aa1db46] <コミットメッセージ>
 8 files changed, 67 insertions(+), 21 deletions(-)
 create mode 100644 <コミットしたファイル名>
```
##git commit --amend
コミットメッセージを修正したい場合は、`git commit --amend`コマンドが使えます。
開いたvimエディタで直接コミットメッセージを編集できます。

なお、git commit --amendで修正して良いのは、git pushする前のコミットのみです。
git push後だとコンフリクトが発生するので、注意してください。

```
$ git commit --amend

↓↓ vimエディタが開き、コミットメッセージを編集できる

<コミットメッセージ>

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sat Sep 26 14:59:19 2020 +0900
#
# On branch master
# Changes to be committed:
#       modified:   <コミットしたファイル名>
```

#git push
ローカルリポジトリにコミットしたファイルをリモートリポジトリにプッシュします。
`git push`コマンドを実行する前に、`git remote add`コマンドでリモートリポジトリを登録しておいてください。

```
$ git push <リモートリポジトリ名> <リモートブランチ名>

Enumerating objects: 34, done.
Counting objects: 100% (34/34), done.
Delta compression using up to 8 threads
Compressing objects: 100% (17/17), done.
Writing objects: 100% (18/18), 2.56 KiB | 2.56 MiB/s, done.
Total 18 (delta 10), reused 0 (delta 0)
remote: Resolving deltas: 100% (10/10), completed with 9 local objects.
To <リポジトリ名>
```

続く…
認証デバイスの特徴ー虹彩認証、USBメモリのディジタル証明書、指紋認証デバイス、接触型ICカード、非接触型ICカード

応用情報技術者平成28年秋期 午前41

アクセス制御に用いる認証デバイスの特徴に関する記述のうち，適切なものはどれか。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/3627a818-5851-ca09-81c4-e5639718ff3b.png)


１、
・USBメモリにディジタル証明書を組み込み，認証デバイスとする場合は，利用するPCのMACアドレスを組み込む必要がある。
⇒×。ディジタル証明書が格納されたUSBメモリは、それ自体が鍵の役割を果たします。
このためMACアドレスを組み込まなくても、USBメモリを挿し込みさえすればどのPCでも認証を受けられます。

・成人には虹(こう)彩の経年変化がなく，虹彩認証では，認証デバイスでのパターン更新がほとんど不要である。
⇒○。虹彩認証は、眼球の特徴で本人認証を行うバイオメトリクス認証技術です。
虹彩とは、眼球の黒目部分、瞳孔の外側にある円状の部分のことで、その部分のしわのパターンが個人ごとに異なることを認証に利用しています。
虹彩認証の精度はメガネやコンタクトレンズを着用してもほとんど低下しません。年を経ると変化する顔や声と異なり、一度登録した虹彩パターンは生涯にわたって利用可能です。

・静電容量方式の指紋認証デバイスでは，LED照明を設置した室内において正常に認証できなくなる可能性がある。
⇒×。認証デバイスに直に触れて指紋を読み取るため、室内の明るさは問題になりません。

光源が認証精度に影響するのは顔認証や虹彩認証です。

・認証に利用する接触型ICカードは，カード内のコイルの誘導起電力を利用している。
⇒×。非接触型ICカードの説明です。
接触型ICカードは、読み取り機に挿入した際に表面の金メッキの端子部分から外部電源が供給される仕組みになっています。

参照：
https://www.ap-siken.com/kakomon/28_aki/q41.html
【AWS CloudFormation】EC2のユーザーデータでWebサーバーをインストールする

#はじめに
EC2の構築作業を省力化のため、CloudFormationにおいてEC2のユーザーデータ（EC2起動時に実行されるシェルスクリプト）を使って、Webサーバーをインストールする方法を学習した。その方法を備忘録として残したい。

#手順
CloudFormation>スタック>スタックの作成で、ステップ１では下記のように設定する。
yamlのテンプレートは以下を指定する。
設定し終えたら、次へ進む。

![スクリーンショット 2020-09-25 16.44.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/22e86c70-1a8f-ab80-d9a1-22436ae8d55e.png)

テンプレート↓
ImageId: ami-〇〇については、〇〇の部分をEC2でAMI IDにあるものに直して入力する。

```

---
Parameters:
  SSHKey:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Name of an existing EC2 key pair for SSH access to the EC2 instance
    
Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: ap-northeast-1a
      ImageId: ami-〇〇
      InstanceType: t2.micro
      KeyName: !Ref SSHKey
      SecurityGroups:
        - !Ref SSHSecurityGroup
      # ユーザーデータからWebサーバーをインストールする
      UserData: 
        Fn::Base64: |
          #!/bin/bash -xe
          yum update -y
          yum install -y httpd
          systemctl start httpd
          systemctl enable httpd
          echo "Hello World from user data" > /var/www/html/index.html

  # EC2セキュリティグループ
  SSHSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SSH and HTTP
      SecurityGroupIngress:
      - CidrIp: 0.0.0.0/0
        FromPort: 22
        IpProtocol: tcp
        ToPort: 22
      - CidrIp: 0.0.0.0/0
        FromPort: 80
        IpProtocol: tcp
        ToPort: 80
```

ステップ２でスタックの名前とSSHKeyを指定する。今回は「user-data-example」とした。SSHKeyではすでに作成されたSSHKeyを適宜指定する。
次へ進む。
![スクリーンショット 2020-09-25 16.45.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/853426a7-d680-ff57-8940-73d406f799d4.png)

ステップ３では特に何も入力せず、デフォルトのままで次へ進む。
![スクリーンショット 2020-09-26 14.36.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/87450196-20d0-8635-2872-e92c133e9428.png)
![スクリーンショット 2020-09-25 16.46.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/78cae146-4f07-3962-0164-dd8a6909d8e3.png)
ステップ４で内容に誤りがない確認し、スタックの作成を押す。
![スクリーンショット 2020-09-25 16.47.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/6632baf1-9894-6e97-9287-71b98234102a.png)
![スクリーンショット 2020-09-25 16.47.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/6f5de5cb-f618-315b-7b42-d74009609b1c.png)
該当スタックが正しく作成されているか、ステータスで確認する。
![スクリーンショット 2020-09-26 14.38.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/c59dddbc-8d51-4344-0d86-90eeca0c68fd.png)
EC2>インスタンスに行き、作成されたインスタンスの詳細を確認する。
問題がなければパブリックIPv4アドレスをURLに入力すると、「Hello World from user data」が画面に表示される。
![スクリーンショット 2020-09-26 14.41.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/78480993-c309-90ce-a6f8-acf7b186dc74.png)

参考
Ultimate AWS Certified SysOps Administrator Associate 2020
https://dev.classmethod.jp/articles/using-variables-in-ec2-user-data-in-cloudformation/
FizzBuzz問題の備忘録

昨日のドリルで登場したFizzBuzz問題。

模範回答としては、

```
def fizz_buzz
  num = 1
  while num <= 100 do
    if num % 15 == 0
      puts "FizzBuzz"
    elsif num % 3 == 0
      puts "Fizz"
    elsif num % 5 == 0
      puts "Buzz"
    else
      puts num
    end

    num = num + 1
  end
end

fizz_buzz
```

というのが正解だったけど、
rubocopを使ったところ、

```
def fizz_buzz
  num = 1
  while num <= 100
    if (num % 15).zero?
      puts 'FizzBuzz'
    elsif (num % 3).zero?
      puts 'Fizz'
    elsif (num % 5).zero?
      puts 'Buzz'
    else
      puts num
    end
    num += 1
  end
end

fizz_buzz
```
と言う形で、
数式を()で括り「その数値が0か否か」を判断する、
zero?メソッドを使った別の記述が(偶然だけど)できた。

rubocop的にはやはり、
可能な限りスッキリと整頓した記述がいいんだろうな。
画像高さをキープしたまま画面の幅いっぱいに背景画像を表示させる方法

# どうも7noteです。画面幅いっぱいに背景画像を表示したい時の方法を紹介。
また、1920pxくらいある**大きな画面で見たときにも崩れにくい方法も解説します。**

どうも7noteです。
この記事は以下へ引っ越しました。

https://naruweb.com/coding/bgheight-keep/