OmniAICreator/Qiita-1.07M huggingface dataset:
Auth0と連携したSingle Page Web ApplicationでTokenベース認証の動作を確認する

# はじめに
この記事ではAuth0と連携済みのSingle Web Applicationを利用してTokenベース認証の動作を確認しています。

# 環境
環境と認証・認可のフロー概要です。
**<font color="DarkOrange">この記事ではImplicit Flowを使った実装を行っています。本番環境ではより安全なAuthorization Code Flow with PKCEを推奨します。</font>**
[参考](https://auth0.com/blog/oauth2-implicit-grant-and-spa/)

- **ブラウザ** : Chrome
- **クライアント** : Single Page Web Applications
- **認可サーバ** : Auth0
- **リソースサーバ** : AWS API Gateway

<img src="https://i.imgur.com/bT1sVEE.png" width=70%>

# 動作確認
ChromeからSPA1にアクセスしてユーザをサインアップします。
**<font color="DarkOrange">サインアップが成功するとAuth0からSPAにID Token, Access Tokenが払い出されて、SSO用にChromeのLocal Storageに各々のTokenが保存されます。</font>**

<img src="https://i.imgur.com/WnNIfiS.jpg" width=70%>
<img src="https://i.imgur.com/ANedqUs.png" width=70%>

Chromeのデベロッパーツールを開いてLocal Storageに保存されたID Token, Access Tokenを確認します。　
**<font color="DarkOrange">この記事では説明をわかり易くするためにChromeのLocal StorageにToken保存しています。本番環境ではSecure Cookieに保存してユーザが読めないようにして下さい。Local Storageには絶対に保存しないで下さい。</font>**
<img src="https://i.imgur.com/0vrwC2r.jpg" width=70%>

Chromeで新しいタブを開いてSPA1にアクセスします。
**<font color="DarkOrange">ChromeのLocal Storageに保存されているID Tokenを確認してSSOできました。</font>**
<img src="https://i.imgur.com/TG7rHE3.jpg" width=70%>

Chromeで新しタブを開いてSPA2にアクセスします。認可サーバから払い出されたLogin Sessionが保存されていることがわかります。Loginを押すとLogin Sessionを認可サーバに渡してID Token, Access Tokenを取得しSSOできました。

<img src="https://i.imgur.com/Dfw3VP1.jpg" width=70%>

<img src="https://i.imgur.com/GRmK3lA.jpg" width=70%>

Chrome以外のブラウザでSPAにアクセスしてデベロッパーツールでLocal Storageを確認します。Auth0から払い出されたLogin Sessionを持っていないためSSOできません。
<img src="https://i.imgur.com/kr5ykOl.png" width=70%>

# おわりに
Tokenベースの認証は、認可サーバが払い出したTokenをクライアント側に持たせることができるため、一度認可サーバに認証された後はTokenが有効な間はユーザエージェントとクライアント間で認証を完結することができます。なお、[Auth0 SDK for Single Page Applications](https://github.com/auth0/auth0-spa-js)は認可サーバが持っているSession情報をチェックして、クライアント側が保持しているTokenが無効になっている場合はRefresh Tokenを認可サーバのToken End Pointに送信して新しいTokenをシームレスに取得しています。クライアントから認可サーバの認可エンドポイントを呼び出す回数を減らせるのでシステム全体のスループットも上がりますね。

# 参考
[Cookies vs. Tokens: The Definitive Guide](https://dzone.com/articles/cookies-vs-tokens-the-definitive-guide)
[Security Best Practices for Managing API Access Tokens](https://dzone.com/articles/security-best-practices-for-managing-api-access-to)
医療従事者のための機械学習・ディープラーニング~学習方法①~


医療系に関する情報が少ないと思い、投稿していきたいと思います。
まずは、医療系で有名な学習法について紹介したいと思います。

私も昨年受講した、日本メディカルAI学会公認資格講座です。
https://www.jmai-shikaku.com/

現在、受講には、受講申込み時点で日本メディカルAI学会の会員に限られていますが、
オンライン講義資料は以下URL/Githubから学習することができます。

メディカルAI専門コース オンライン講義資料
https://japan-medical-ai.github.io/medical-ai-course-materials/

以下Githubからオンライン講義資料はすべて学習することができます。
https://github.com/japan-medical-ai/medical-ai-course-materials

日本メディカルAI学会が行っている日本メディカルAI学会公認資格資格の
コースの一部となっています。コースは、事前に学ぶ
①オンライン受講メディカルAI専門コース
②応用編：講義及び小テスト（日本メディカルAI学会終了翌日）

オンライン講義資料は、Preferred Networksの岡野原大輔副社長や，株式会社キカガクの吉崎亮介社長などにて作成されており、大変わかりやすい内容となっております。

医療従事者の方で、医療データで用いて、AIの開発を行ってみたいと考えておられる方には是非おすすめです。
【Sorcery】Sorceryで使えるようになるメソッドとその活用例

[SorceryのGitHub](https://github.com/Sorcery/sorcery#api-summary)に書いてあることをまとめました。
Coreのものだけです。実際の使用法、活用例などを挙げているので参考になればと思います。
公式GitHubではメソッド名をクリックすると定義のページに飛びますので、詳しいコードはそちらをご覧ください。

## require_login

ログインをしていないユーザーをアクション単位で弾く。
アクセスしようとしたURLをセッションに格納し、`not_authenticated`を実行するメソッド。
以下のように`before_action`で指定する。

```ruby:hoges_controller.rb
before_action :require_login
```

アクションごとに変える場合は、`only: :action`を付ける。
アクション内の分岐など、もっと細かい単位で弾きたい場合は後述の`logged_in?`を使う。


### not_authenticated

先ほどの`require_login`内で、このメソッドも実行される。
デフォルトでは`redirect_to root_path`（自動的にルートに飛ばされる）と定義されているが、カスタマイズしたい場合は`application_controller`で上書きをする。

```ruby:application_controller.rb
class ApplicationController < ActionController::Base
  protected

  def not_authenticated
    redirect_to login_url, alert: 'ログインしてください'
  end
end
```

## auto_login(user)
その名の通りオートログイン。メールアドレスやパスワードを使わず`user`としてログインする。
想定される使い方としては、以下のようなものが挙げられる。

### ユーザー登録後の自動ログイン
```app/controllers/users_controller.rb
class UsersController < ApplicationController
  def create
    @user = User.new(user_params)
    if @user.save
      auto_login(@user)
      redirect_to root_url, notice: 'ユーザーを登録しました'
    else
      flash.now[:alert] = 'ユーザーが登録できませんでした'
      render :new
    end
  end
end
```

### ゲストユーザーログイン
```app/controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
  def guest_login
    guest_user = User.find_by!(role: 'guest')
    auto_login(guest_user)
    redirect_to root_path, notice: 'ログインしました'
  end
end
```

### 開発環境でのログイン
```app/controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
  def login_as
    user = User.find(params[:user_id])
    auto_login(user)
    redirect_to root_path, notice: "#{Rails.env}環境でログインしました"
  end
end
```

```config/routes.rb
Rails.application.routes.draw do
  if Rails.env.development?
    get '/login_as/:user_id', to: 'user_sessions#login_as', as: :login_as
  end
end
```

「`/login_as/1`などにアクセスすると自動的にそのユーザーとしてログインする」ので、`if Rails.env.development?`は**必ず**付ける。

## current_user

きっと一番よく使う。
現在ログイン中のuserを返す。コントローラ、ビューで使える。

## logged_in?

現在ログイン中かどうか、true or falseで返す。コントローラ、ビューで使える。
ログインしているかどうかによって場合分けをしたいときに使うことが多い。

```erb:view.html.erb
<% if logged_in? %>
  <%= link_to 'プロフィール', user_url(current_user) %>
<% else %>
  <%= link_to 'ログイン', login_url %>
<% end %>
```

## redirect_back_or_to(dafault_url, flash_hash = {})

ログインのアクションで使う。
`require_login`のときにセッションに格納されたURLまたはデフォルトのURLにリダイレクトする。
`flash_hash`はデフォルトでsuccess, dangerにも対応しています。

```ruby:user_sessions_controller.rb
class UserSessionsController < ApplicationController
  def create
    @user = login(params[:email], params[:password])
    if @user
      redirect_back_or_to root_url, success: 'ログインしました'
    else
      flash.now[:danger] = 'ログインに失敗しました'
      render :new
    end
  end
end
```
【Django】'The SECRET_KEY setting must not be empty.'の対処法

#はじめに

Qiita初投稿です。
間違い等があればご指摘お願いいたします。

#概要

「動かして学ぶ！Python Django開発入門」の10章で、
認証用アプリケーション（accounts）を作成し、makemigrationを実行しようとしたところ、

```python:
'The SECRET_KEY setting must not be empty.'
```

というエラーに遭遇。

#試したこと

####・accounts/migrations配下の'\_\_init__.py'**以外**のファイル削除

→そもそもmakemigrationsコマンド自体が実行できないので、'\_\_init__.py'以外のファイルは見当たらず...

####・settings.pyにコード追加

settings.pyに

```python:settings.py
from .settings_common import *
```
という一文追加。

→**エラーが出なくなった！！**

#原因

settings.pyに

```python:settings.py
SECRET_KEY = 'hogehoge'
```

がないためエラーが発生していたらしい。

この教材の途中で、本番環境と開発環境を分けるために

+ 'settings_common.py'
+ 'settings.dev.py'

っていうファイルを作成して、'settings.py'の中身を全部
'settings_common.py'に移す作業があったんだけど、
そのせいで'settings.py'にSECRET_KEYがないと見なされていたらしい...。
（'settings.py'は空ファイル）

試してはないけど、'settings.py'に直接SECRET_KEYを指定してもできそう。
それだと同じコードを2回も書くことになると思うしimportした方が良いと思われる。

#おわりに

なんとか解決できて良かった...

友人曰く、settings.pyを分けるときのベストプラクティスもあるそうなので、そっちも勉強してわかり次第記事にしたいな...。
（自分用）Rails設計時（実装時）の注意点のまとめ

Railsに限らないトピックも含まれそう

* モデルとビューのどちらに実装しようか迷うときは、Decoratorパターンを検討する
* モデルの共通化
    * Mix-inを使う場合は、 `ActiveSupport::Concern` を利用する
    * STI（単一テーブル継承）
        * 継承を利用して、似たようなActiveRecordモデルクラスの共通化を図る
        * 継承関係にある一連のモデルクラスはすべて1つのテーブルに対応付けられる
            * 各クラスのインスタンスに対応するレコードは、すべて同一のテーブルに格納される
            * 対応するテーブルには `type` というカラムを用意する必要がある
                * 各レコードが所属するクラス名が格納される
        * https://guides.rubyonrails.org/association_basics.html#single-table-inheritance
* コントローラの共通化にMix-inを使う場合は、モジュールを `app/controllers/concerns` に配置する
* ビューで使うユーティリティメソッドはカスタムヘルパーとして `app/helpers` に書く
    * 全てのビューから呼べるので、「小さく作る」「具体的に命名する」点に気をつける
    * コントローラとビューの間で共通的に利用したい処理は、コントローラにメソッドを定義し、それをコントローラで `helper_method` に指定することもできる
    * 特定のモデルに関する処理を書かないように注意し、そのような場合はモデルやDecoratorに寄せることを検討する
* （複数のモデルが絡むような）特定の処理は専用のオブジェクトを作成する
    * サービスオブジェクト（サービスクラス）と呼ばれる設計パターン
    * 特定の処理一つのみに専念し、小さく作るようにする
    * モデルに書くべき処理をサービスに書かないように気をつける
Nuxt を winser でサービス化する

Nuxt で作成したアプリケーションを WinSer でWindowsサービス化しようとしたらいろいろはまったので備忘録として対処を残しておく。

#背景
nodejs で作成したアプリケーションを Windows環境でサービス化するためのツールとして、 [WinSer](https://www.npmjs.com/package/winser) がある。
start コマンドとして「node index.js」のように node.exe を直接叩く場合は特に設定をする必要はないが、 NuxtJS のような専用の起動コマンドが存在するような場合に、npm や yarn からは起動できてもWindowsサービスとして起動できないということが発生する。

#対策
WinSer （で使用される nssm）は絶対パスか、パスが通ったコマンド出なければ実行できない（ように見える）。また「.cmd」拡張子のファイルは拡張子込みで記述する必要がある。
##1. WinSer をインストールする
npm に上がっている WinSer は[バグっている](https://github.com/jfromaniello/winser/pull/43)ので修正されたものを拾う。

```
yarn add winser "git+https://github.com/LiberisLabs/winser.git"   
```

##2. パスを通す
yarn へのパスを通す。
以下がもしないなら、サービスを実行するユーザーの環境変数の Path に追加する。そのユーザーで yarn をグローバルインストールしてあることが前提。

```
C:\Users\<username>\AppData\Roaming\npm
```

Local System アカウントで実行するなら、システム環境変数に追加する。

##3. package.json に winser 要のタスクを追記する
```package.json
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "install-service": "winser -i -a --startcmd \"yarn.cmd nuxt start\" --set \"ObjectName .\\appuser password\"",
    "uninstall-service": "winser -r -x"
  }
```
WinSer は標準では start をもとにサービスを作成するが、それでは動かないため --startcmd で start の代わりの実行コマンドを記述する。さらに、 --set で実行ユーザーとパスワードを指定する（Local System で実行するなら不要）。
やっていることは nuxt.cmd を叩いているだけだが、直接見つけられないため、yarn を叩くことで 
nuxt.cmd を見つけている。

サービス化した場合、サービスの起動停止を自動化したくなる。UACを無効化したくなるが、その必要はなく、特定ユーザーにサービスに係る権限を与える方法は[この辺り](https://support.microsoft.com/ja-jp/help/914392/best-practices-and-guidance-for-writers-of-service-discretionary-acces)を参照する。

## 2020/05/12追記
nodejs 14 にアップデートしたせいか？ nssm から yarn を通して起動できないという状況が発生。npm からなら起動できる。
npm から起動するなら、そもそも --startwithnpm を指定すればよし。

```
node .\node_modules\winser\bin\winser -i --startwithnpm --set "ObjectName .\username password"
```

#参考
[WinserでNode.jsのサーバーをサービス化してみる](http://sourcechord.hatenablog.com/entry/2015/05/21/011501)
[NSSM](https://nssm.cc/)
[WinSer](https://github.com/jfromaniello/winser)
docker-compose を CI で実行するとき， MySQL の起動完了まで確実に待つ

# 背景

- [jwilder/dockerize: Utility to simplify running applications in docker containers](https://github.com/jwilder/dockerize)
- [ufoscout/docker-compose-wait: A simple script to wait for other docker images to be started while using docker-compose](https://github.com/ufoscout/docker-compose-wait)

この辺は全部試したが， PHP から接続しようとすると `Connection Refused` が多発する。**TCP で接続可能になってから実際に利用可能になるまで若干のラグがある**ため，もっと確実な方法を探していた。

# 対処法

```bash:とりあえずこれを書いておけ
sh -c 'docker-compose logs -f <MySQLコンテナ名> | { sed "/\[Entrypoint\]: MySQL init process done\. Ready for start up\./ q" && kill $$ ;}' >/dev/null 2>&1 || :
```

```yaml:YAMLのリストに書く場合はエスケープが必要なのでパイプから改行する
- |
  sh -c 'docker-compose logs -f <MySQLコンテナ名> | { sed "/\[Entrypoint\]: MySQL init process done\. Ready for start up\./ q" && kill $$ ;}' >/dev/null 2>&1 || :
```

ログを見れば確実！ログに `MySQL init process done` と出ればアプリケーションレベルでも必ず有効な状態であることが保証される。

# おまけ

```bash:php-fpm&#32;版
sh -c 'docker-compose logs -f <FPMコンテナ名> | { sed "/NOTICE: ready to handle connections/ q" && kill $$ ;}' >/dev/null 2>&1 || :
```

```bash:あわせ技（その1）
sh -c 'docker-compose logs -f <MySQLコンテナ名> | { sed "/\[Entrypoint\]: MySQL init process done\. Ready for start up\./ q" && kill $$ ;}' >/dev/null 2>&1 &
sh -c 'docker-compose logs -f <FPMコンテナ名> | { sed "/NOTICE: ready to handle connections/ q" && kill $$ ;}' >/dev/null 2>&1 &
wait
```

引数なし `wait` で一気に終了を待つ場合は終了ステータスが不問になるため， `|| :` は不要です。

```bash:あわせ技（その2）
{
  sh -c 'docker-compose logs -f <MySQLコンテナ名> | { sed "/\[Entrypoint\]: MySQL init process done\. Ready for start up\./ q" && kill $$ ;}' &
  sh -c 'docker-compose logs -f <FPMコンテナ名> | { sed "/NOTICE: ready to handle connections/ q" && kill $$ ;}' &
  wait
} >/dev/null 2>&1 
```

リダイレクトをまとめて見やすく。
discord.pyで改行されない問題

某ゲーム用のbotを作っていた時に気がついたのですが、
iOS版Discordだと改行がされないことがあります

PC版Discord
![pc_discord.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/d9cb9040-aa05-bafc-88c3-0e67d5a44368.png)

iOS版Discord
![iOS_discord.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/a7eacc3a-7e53-3dfb-9b54-df5dc265970d.png)

みてわかるとおり、「いずみ」の後ろの改行が無視されています

原因を探ったのですが、その部分だけ改行の前にスペースが入っています

```python

message = 'いずみ \n2回目'

```

改行の前のスペースをなくすことで、iOS版でも改行されるようになりました
【初心者向け】押さえておきたいスクラム用語

# 概要
本文はスクラム開発に参画したけれど、「なんかたまに発表する偉そうな人（プロダクトオーナー）やら、リーダー気取り（スクラム開発ではスクラムマスター）がなんかカタカナで意味のわからない単語喋ってんな、意味わかんねーな」　って方に向けた記事です。
スクラム開発は最近ウォーターフォールの代わりとして、取り入れられている開発手法ですが、聴き慣れない単語ばかりで戸惑うことばかりです。
筆者は、本記事記載時点で、はじめてスクラム開発の案件に参画し、2週間が経過しました。
まだ、十分に理解したとはとても言いにくいですが、とりあえず押さえておいたほうが良さそうな単語をいくつか選定し、簡単にまとめましたので、もしよろしければストックしていただき必要に応じて見直していただけたらと思います。

# 用語
## スプリント
お客さんへの最終納期を、進捗管理しやすいように細切れにしたもの。通常は1週間から4週間。

## バックログ
やることリストをカッコよく言い換えたもの。

> バックログ（backlog）という英語の意味は、「積み残した仕事」という意味です。スクラムでは、あなたが取り掛かる予定の仕事を「取り掛かる順」に並べたリストを、バックログと定義しています。

【引用元】
https://www.atmarkit.co.jp/ait/articles/1111/15/news126.html


## プロダクトバックログ
全体でのやることリストをカッコよく言い換えたもの。
> プロダクトバックログは、機能や技術的改善要素を優先順位を付けて記述したものです。ステークホルダ全員が参照し、現在のプロダクトの状況を把握できるようにします。

【引用元】
https://www.atmarkit.co.jp/ait/articles/1208/07/news128.html

## スプリントバックログ
その期間（スプリント）でのやることリストをカッコよく言い換えたもの。
> スプリント・バックログは、プロダクト・バックログからスプリント期間（1～4週間）分を抜き出した「チームのタスクリスト」です。

【引用元】
https://www.atmarkit.co.jp/ait/articles/1208/07/news128.html

## デイリースクラム
朝会をカッコよく言い換えたもの。
昨日やったこと、今日やること、障害になっていることの3つを報告する。
15分を目処に終了させるが、スクラムマスターがネチネチツッコミ出すとその幅に収まらなくなるので注意が必要。

## バックログリファインメント
バックログ（やることリスト）のそれぞれの要素に対して、認識齟齬（言い逃れ）できないように、作業内容、時間などいちいち定めていくもの。なお、リファインメントが定義って意味。

## プロダクトオーナー、スクラムマスター、開発チーム
それぞれスクラムの開発側の関係者たち。なお外側にはステークホルダーという利用者がいる。
上流から順番にプロダクトオーナー、スクラムマスター、開発チームになる。
### プロダクトオーナー
#### 役割
プロダクトに責任を持つ人
####やること
やることリスト（プロダクトバックログ）を並び替える

### スクラムマスター
#### 役割
スクラムがうまくいくように全体を支援する
####やること
開発チームの開発の妨げになるものを削除する


### 開発チーム
#### 役割
プロダクトの開発を行う
####やること
開発
自身に割り当てられたバックログ（やることリスト）の消化

### スプリントレトロスペクティブ
振り返りのカッコつけた言い換え
スプリントが終わった後に行われる。

## 最後に
今回、用語をかなりざっくりと偏見に基づいて、まとめてしまっているかもしれないです。
なので、厳密に細かく詳しく知りたい方は以下をご覧ください。これらを読んでおくことでよりスムーズな開発を行うことができるかと思われます。

#### 参考資料
ryuzee.com/wp-content/site_images/7124/Scrum_overview_by_ryuzee.pdf
https://www.ryuzee.com/contents/blog/7124
https://www.atmarkit.co.jp/ait/articles/1208/07/news128.html
https://www.scrumguides.org/docs/scrumguide/v2017/2017-Scrum-Guide-Japanese.pdf
AWS EBS（Elastic Block Storage）拡張の所要時間

# オンラインで940GBのEBSボリュームを1.5TBに拡張した
## EC2環境
OS（Windows2012）とディスク（3TB）が無料枠の範囲外なので、時間との戦いです:grinning:

| キー | バリュー |
|:-:|:-:|
|OS   |Windows2012(not R2)   |
|インスタンスタイプ   |t2.micro   |
|ディスク   |D(940GB),E(940GB)   |

## 手順
- ①まずはEC2作成。DとEドライブは各々940GBを予め割当しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280358/8a0fd15f-825a-2aa5-ee76-9021ca88c4d2.png)

- ②DとEドライブに適当なファイルを作成しておきます。（正常にファイルシステムが拡張されたかの確認用）

- ③AWSマネージメントコンソールからDとEドライブを各々1.5TBに拡張。状態が「optimizing」から「in-use」になるまで約7分（早い:open_mouth:）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280358/4d4bbbc0-bf50-6faa-09fb-e141182070c2.png)

- ④OSから「ディスクの管理」画面にてディスクをスキャンするとEBS拡張した分のディスクが見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280358/e02aeee9-910b-1c6c-696b-c25e6f1dc4b0.png)

- ⑥ファイルシステムを拡張。この手順実施後はすぐに拡張したサイズが認識されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280358/03634d7e-c2ca-5b37-6c2f-3019f99c7f4a.png)

- ⑦最後に②で作成したファイルが正常に見えたら成功です。

## ここまでかかった時間は約10分でした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280358/72081894-3985-261d-a794-b9a1de4e314c.png)

後は、EC2とEBSを削除して終了です。
コストが幾らかかったか少し心配:sweat:

## さいごに
- 今回のファイルシステム拡張は短時間で終わりましたが、[ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/monitoring-volume-modifications.html
)を見る限りでは時間がかかる可能性を想定しておいた方が良さそうです。オンプレの場合とは違うという意識・感覚は必須ですね。
- まさに「Elastic（弾力性のある）」な「バネ」のような実験くんでした。
- 後日・・・ある日曜日早朝の時間帯に、940GBから1.5TBに2個のEBSを同時に拡張したところ、約30分で「in-use」に変わりました。私が試した限りでは営業時間帯以外に実施すると早いと感じています。
- 安全面や経験値不足から「in-use」になってからファイルシステム拡張していますが、「optimizing」でも拡張できるとマニュアルからは読み取れます（未検証です）。
Importrange関数で業務効率化にチャレンジ

#目的
Nゼミのグループの編集を生徒用と教員用のシート双方の編集が手間なので、Importrange関数を使って効率化したい

#所感
想像していたよりもずっと簡単だった。範囲がずれると生徒に閲覧されてはいけないデータまで公開することになるので、チェック等が必要かと感じた。

[参考シート](https://docs.google.com/spreadsheets/d/1OH7CS5mQfm1PnXieVPoFo29BXVvrL20p__6Wst_kkoY/edit#gid=1536250370)
#Ruby + Faker で 16進数 の Mac アドレスを生成する例

```rb
require 'Faker'
# => false

Faker::Internet::mac_address
# => "ca:ea:fb:ab:cc:b9"
Faker::Internet::mac_address.upcase
# => "32:05:2B:AE:CB:59"
```

ruby的に頑張らなくても良かったんだ

```rb
Array.new(6) { Faker::Number.unique.hexadecimal(digits: 2).to_s.upcase }.join(':')
# => "1E:42:12:27:E2:CB"
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2949








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
FlaskでFormを使うための、必要最低限の知識

# 概要
FlaskのFlask-WTFを使ってFormを定義・レンダリング・バリデーションする方法

### Formの定義
```python
class AnimalForm(FlaskForm):
    name = StringField('name', validators=[validators.Required(), validators.length(max=30)])
    kind = StringField('kind', validators=[validators.Required(), validators.length(max=10)])
    description = TextAreaField('description', validators=[])
```
##### ポイント
- FlaskFormを継承して作る
- validatorsには複数のvalidatorを渡すことができる


### Formのレンダリング
```html
      <form method="POST">
      <p>{{ form.name.label }}:{{ form.name(size=30) }}</p>
      <p>{{ form.kind.label }}:{{ form.kind(size=20) }}</p>
      <p>{{ form.description.label }}:{{ form.description(cols="50", rows="20") }}</p>
      <button type="submit">Submit</button>
      </form>
```
##### ポイント
- labelにアクセスすることでformで定義した名前を取得できる
- それぞれのフィールドはcallableになっており、HTMLをレンダリングする
- fieldをレダリングするときに、引数を渡すとHTMLのプロパティに変換してくれる



### SubmitされたFormのバリデーション
```python
    form = AnimalForm()
    if form.validate_on_submit():
        name = form.name.data
        kind = form.kind.data
        description = form.description.data
```
##### ポイント
- validate_on_submitでpostかどうかのチェック・データのバリデーションをしてくれる
- dataにアクセスすることで、バリデーション後のデータを取得できる
raspberry pi に forked-daapd をインストールする

パッケージとして配布されているforked-daapdはWeb Interfaceが無効化されている。Web Interfaceを使うため、ソースコードからビルドしてインストールする。

# 環境

* [Raspberry Pi 2 Model B](https://www.raspberrypi.org/products/raspberry-pi-2-model-b/)
* Ubuntu 18.04.3 LTS

# 必要なパッケージのインストール

たくさんある。

```
# apt install git gawk gcc make autoconf libtool gperf default-jdk antlr3 libantr3c-dev libavahi-client-dev libconfuse-dev libsqlite3-dev libmxml-dev libevent-dev libunistring-dev libjson-c-dev libasound2-dev libpulse-dev libplist-dev libsodium-dev libprotobuf-dev libwebsockets-dev libcurl4-gnutls-dev libgnutls28-dev
```

# ソースコードのダウンロード

```
$ git clone https://github.com/ejurgensen/forked-daapd
```

# ビルド

以下は、`/usr/local`にインストールする場合。

```
$ cd forked-daapd
$ autoreconf -i
$ ./configure
$ make
$ sudo make install
$ sudo cp forked-daapd.service /usr/local/lib/forked-daapd
```

`/etc/forked-daapd.conf`を要件に応じて変更する。

# サービスの登録

daapdの実行ユーザーを作成する。

```
$ sudo adduser --system --home /usr/local/var/cache/forked-daapd daapd
```

daapdユーザーが書き込めるようにディレクトリの所有者を変更する。

```
$ sudo chown -R daapd /usr/local/var/cache/forked-daapd
```

```
$ sudo ln -s /usr/local/lib/forked-daapd/forkd-daapd.service /etc/systemd/system
$ sudo systemctl enable forked-daapd
$ sudo systemctl start forked-daapd
```
じゃんけんプログラムを改変してた

#前回のあらすじ
・if文とSwitch文を使ってじゃんけんプログラムを組んだ
#今日やったこと
・関数定義して、ソースコードをスッキリさせた
・While文を使って、連勝している間はじゃんけんが続き、最終的にレコードが出るように改変した。
（今回の教科書『いちばんやさしいJavaScriptの教本』）
#今回のエラー
・改変前プログラムをコピペしてて、関数名を古いままにしてたのでエラーが起こった
#感想
関数って、ソースコードがスッキリするし１つ１つの部分がわかりやすくなるし、すごく便利な存在なんだな～と思った。
#次回の目標
HTMLとCSSとJSを結びつけて活用できるようになるぞ
【Rails】キャッシュされた古いページが一瞬表示されるのを避ける方法

#困っていたこと
取得したパラメータによって表示したいページを変更したくて
以下のようなコントローラ設定の時、

```ruby:articles_controller.rb
class ArticlesController < ApplicationController
  def show
    if session[:for_article_show] == 1
      render '/articles/pattern_A'
    elsif session[:for_article_show] == 2
      render '/articles/pattern_B'
    end
  end
end
```
`session[:for_article_show]`が1の時に
pattern_A.html.erbが表示され、その後
`session[:for_article_show]`が2に変更されてshowアクションが実行されると、
pattern_B.html.erb
が**直接**表示されると思っていました。

実際は、**一瞬だけ
pattern_A.html.erb
が表示され**、その後すぐに
pattern_B.html.erb
の表示に切り替わりました。

これでは非常に見栄えが悪く、困っていました。

#原因
Rails標準gemである、turbolinksが原因でした。

turbolinksによって、
あるアクションによって描画されたページがキャッシュに存在した場合、
リクエストを送る前にまずキャッシュからプレビューを描画し、
レスポンスが返ると最新の状態を表示するようです。

[【参考】turbolinks github　"Application Visits" 項](https://github.com/turbolinks/turbolinks)


#解決策
プレビュー機能が実行されたくないリンクを、以下タグで囲ってあげることで
ページのプレビューが表示されることがなくなりました！

```erb
<div data-turbolinks="false">
  <%= link_to article.title, article %>
</div>
色だけを指定してUIImageを作る

検索しても最近はswiftの記事ばかりがヒットしてちょっと辛い…。
## 動機
ダミーイメージとして色、サイズだけを指定してUIImageを作りたかった。
## やり方
毎度のことながらStack Overflowにお世話になります。
[ios - Creating a UIImage from a UIColor to use as a background image for UIButton - Stack Overflow](https://stackoverflow.com/questions/6496441/creating-a-uiimage-from-a-uicolor-to-use-as-a-background-image-for-uibutton)

CGRectの部分で画像サイズを指定、引数のcolorでUIColorを指定するだけでUIImageが返ってきます。

```objectivec
+ (UIImage *)imageFromColor:(UIColor *)color {
    CGRect rect = CGRectMake(0, 0, 1, 1);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
```

```objectivec
UIImage *cloud_image = [self imageFromColor:[UIColor whiteColor]];
```
【Rails】link_toメソッドでaria-haspopup、data-toggleなどのHTML表現を入れる方法

#エラー発生

Railsのlinks_toメソッドで下記のようにaria-haspopup、aria-expanded、data-toggleなどのHTML表現を入れようとしたところ、エラーが出た。

```
<%= link_to root_path, class: 'nav-link', data-toggle: dropdown, aria-haspopup: true, aria-expanded: false, id: header-profile do %>

  <%= image_tag('xxx.jpg', size: '60x60') %>

<% end %> 
```

syntax error, unexpected 〇〇, expecting 〇〇
というエラーが出まくる。
構文エラーなのでどこか書き間違えがあるのかと思ったが、コードを見ても余計な文字や入れ忘れがあるように見えない。

#解決方法
調べて見るとlink_toの引数のハッシュとしてつける場合、キーをシングルクオテーションをつける必要がある。例えば、`data-toggle: dropdown`は`'data-toggle': :dropdown`という風に書き換える。

```
<%= link_to root_path, class: 'nav-link', 'data-toggle': :dropdown, 'aria-haspopup': :'true', 'aria-expanded': :'false', 'id': :'header-profile' do %>

  <%= image_tag('xxx.jpg', size: '60x60') %>

<% end %> 
```
参照
https://teratail.com/questions/124849
pythonでAtcoderするためのVS Codeデバッグ環境作ってみた

最近Atcoderデビューしたのですが、コードテストするときにあっちこっちタブ切り替えるのがちょっと面倒だったので…
VS CodeでF5デバッグできる環境を作ってみました。

# 環境

---

**VS Code**
バージョン: 1.41.1 (user setup)
コミット: 26076a4de974ead31f97692a0d32f90d735645c0
日付: 2019-12-18T14:58:56.166Z
Electron: 6.1.5
Chrome: 76.0.3809.146
Node.js: 12.4.0
V8: 7.6.303.31-electron.0
OS: Windows_NT x64 10.0.17763

**python**
Python 3.7.3

---

作業用ディレクトリを作成し、その中に以下のファイルを作成、実行します。

```python:make_directory.py
import os

for i in range(10):
    folder_name1 = "ABC{:x<3}".format(i)
    os.makedirs(folder_name1, exist_ok=True)

    for j in range(10):
        folder_name2 = folder_name1 + "/ABC{}{}x".format(i,j)
        os.makedirs(folder_name2, exist_ok=True)

        for k in range(10):
            folder_name3 = folder_name2 + "/ABC{}{}{}".format(i,j,k)
            os.makedirs(folder_name3, exist_ok=True)
            file_name = folder_name3 + "/ABC{}{}{}".format(i,j,k)

            with open(file_name + "A.py", mode='w') as f:
                pass
            with open(file_name + "B.py", mode='w') as f:
                pass
            with open(file_name + "C.py", mode='w') as f:
                pass
            with open(file_name + "D.py", mode='w') as f:
                pass
            with open(file_name + "E.py", mode='w') as f:
                pass
            with open(file_name + "F.py", mode='w') as f:
                pass
            with open(folder_name3 + "/input.txt", mode='w') as f:
                pass
```

そうすると、作業用ディレクトリの中にディレクトリとファイルが生成されます。

**作成されるディレクトリ**

100コンテスト単位のディレクトリ
↓
10コンテスト単位のディレクトリ
↓
1コンテスト単位のディレクトリ

**作成されるファイル**
、
ABC001A.py～ABC001F.py
input.txt

（1コンテスト単位のディレクトリの中）

launch.jsonも編集します。

atcoder_debugの部分が書き足されていて、各ディレクトリにあるinput.txtを引数で渡しています。

```launch.json


{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [

        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal"
        },
        {
            "name": "atcoder Debugger",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "args":[
                "<",
                "${fileDirname}/input.txt"
            ]
        },
    ]
}
```

あとは解いてる問題のpyファイルにコードを書いて、pyファイルのあるディレクトリのinput.txtに入力値をコピペして、F5キーを押せばデバッグできます。
Data Robotのマニュアルを読む

クイクイックスタート
1.プロジェクトをつくる
2.目的変数を用意する
3.予測のモデルの作成スピードを考える。
4.モデリングのプロセスを考える
5.評価するというボタンを押す
まずはこれで一通りできるはずです。
WinForms で「値をNull にすることはできません。パラメーター名:source」な場合に見直す点

WinForms でアプリケーションを開発していて、(閉じる前までは) デザイナで開けていたフォームが開けなくなり、次のエラーが報告されるケースで見直す点をメモする。

>値をNull にすることはできません。パラメーター名:source

もしくは 

>オブジェクト参照がオブジェクト インスタンスに設定されていません。 

Visual Studio 2015 は確か上のエラー、同 2019 では下のエラーメッセージになった。


## 見直す点

このエラーは、`ArgumentNullException` を受け取ったデザイナが表示している。

デザイナがフォームを表示するとき、フォームに貼り付けられたすべてのコントロールをインスタンス化、そして `Load` も呼び出す。その過程で、誰かが **引数に null を与えてはいけないメソッドに null を与えた** ことで例外がスローされた。

したがって、フォームの Load 時に呼び出されるイベントのコールバックを見直せばよい。

## サンプル

次に、端的なサンプルと再現手順を挙げる。

1. Visual Studio で WinForms プロジェクトを生成して、プロジェクトにカスタムコントロールを追加してフォームに貼り付ける。
1. 貼り付けた後に、次のコメントアウト部分を有効にしてフォームを保存する。
1. フォームを閉じて、開きなおす。
1. 上記のエラーが発生する。

```csharp
public partial class UserControl1 : UserControl
{
    // 前略

    IEnumerable<string> s;

    private void UserControl1_Load(object sender, EventArgs e)
    {
        //if (s.Count() > 0)
        //{
        //    // somthing...
        //}
    }
}
```

エラーメッセージの `パラメータ名:` 以降に表示されるのは、例外をスローしたメソッドが Null を検出した仮引数名のようだ。


## 確認した環境

- Visual Studio: Microsoft Visual Studio Community 2019, Microsoft Visual Studio Community 2015
- Windows: Windows 10 Home
CloudTrailのログをS3に保管する

https://aws.amazon.com/jp/cloudtrail/
クラウドトレイルは、AWSの操作履歴を記録するサービスで
現在はデフォルトで全リージョン有効になっています。

###保管する理由
有効期限が90日間となっていて、以降のログは自動的に削除してしまうため
以降も保持できるようS3などに保管して置くのがより良いです。

###保管時に合わせて確認したい
・S3のライフサイクルでGlacierに移すことで課金を多少抑えられる
・保存先バケットやオブジェクトは削除不可のポリシを全ユーザに設定する
　（監査担当のみ読み取り可能にしておくなど）

###追加課金が必要だができること
・S3のオブジェクトに対するAPI経由のGet/Putログを取得できる
　ほぼ同等機能としてS3のアクセスログがあり、そちらと比較すると・・・。
　　より優れている点
　　　最大15分程度の遅延でログ出力できる
　　　データロストの心配がない
　　悪い点
　　　とくに思い当たりません
　　　※インターネット経由のパブリックアクセスでもログは出ます

・リソース登録/更新のふるまい監視ができる（CloudTrailInsights）
https://aws.amazon.com/jp/blogs/news/announcing-cloudtrail-insights-identify-and-respond-to-unusual-api-activity/

###参考
**CloudTrailのログ例(S3のオブジェクトをGetしたものを一部抜粋）**
パブリックアクセスはCloudTrailのログは出ないと思っていたが入るようです

```json
# public access
"userIdentity":{ 
"type":"AWSAccount",
"principalId":"",
"accountId":"ANONYMOUS_PRINCIPAL"
}

# console access
"userIdentity":{ 
"type":"AssumedRole",
"principalId":"user:user",
"arn":"arn:aws:sts::accountid:assumed-role/admin/user",
"accountId":"accountid",
"accessKeyId":"user",
"sessionContext":{ 
"sessionIssuer":{ 
"type":"Role",
"principalId":"user",
"arn":"arn:aws:iam::accountid:role/admin",
"accountId":"accountid",
"userName":"user"
}
```

**S3のアクセスログとCloudTrailのログのフォーマット差分**
S3のアクセスログの配信が来ないため比較できません・・・。
のちほど配信が来たら追記いたします。

**GuardDutyの検知**
今回検証目的でCloudTrailの監査ログ停止やS3のパブリックアクセスブロックを無効にしたところ、インシデントとして上がりました。
![20200118.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110457/5710bec6-7659-676d-2460-4edcfbc43564.png)
忌まわしき環境変数についてのメモ

# 環境変数
####一覧
```
printenv
```
####変数名を指定
```
printenv 環境変数名
```

#### 環境変数を消す
```
unset 環境変数名
```

# 設定方法
#### 先頭に追記
```
export PATH=ぺろぺろ:$PATH
```

#### 後尾に追記
```
export PATH=$PATH:れろれろ
```

#### PATHを一新
```
export PATH="にゅるぱこぱこ"
```
shell の種類と版

自分の機材がどのshell入れているか忘れた。
仕事場のはzshがこの間入っていた。

```shell-session:macos/bash
$ printenv | grep shell -i
SHELL=/bin/bash
PYENV_SHELL=bash
$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
Copyright (C) 2007 Free Software Foundation, Inc.
```

何のShellを使っているか確認する方法
https://server-setting.info/freebsd/what-shell.html

試して見た。

```shell-session:macos/bash
$set | grep -ai versionreturn
```

何も出なかった。dockerのubuntuでも同様。

dockerのubuntuではprintenv | grep shell -iも何もでなかった。

```shell-session:docker/ubuntu
# set | grep -ai shell        
SHELL=/bin/bash
SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
```

docker/ubuntuではbashだった。ていうか、自分で起動するときにbash指定してた。


#文書履歴(document history)
ver. 0.01 初稿 20200118 午前
ver. 0.02 ubuntu追記 20200118 正午
ver. 0.03 URL追記　20230302

### 最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。

####  Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
Google 二段階認証設定をONにする方法

# 目的

- Googleの二段階認証をONにする方法をまとめる
- ※公式のドキュメントにも記載があるのでそちらの方がわかりやすい可能性がある

# 実施詳細

1. Googleに任意のアカウントでログインする。
1. Googleのホームにアクセスする。
1. 右上に存在する自分の画像をクリックする。(画像の「み」と書いてる丸い部分)
![スクリーンショット 2020-01-18 9.42.43（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/b67d4005-52d4-0be5-97f7-f0ea4d5e65c7.png)

1. 「Googleアカウントを管理」をクリックしてアカウント管理画面に移動する。
![スクリーンショット 2020-01-18 9.42.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/6c84b83d-cf67-32d2-ce1c-dd4940449e97.png)

1. 左のメニューの「セキュリティ」をクリックする。
![スクリーンショット 2020-01-18 9.44.19（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/2d37ebbd-3138-fb5e-6c31-a66ec548d01f.png)

1. 「Googleへのログイン」の「2段階認証プロセス」の「>」をクリックする。
![スクリーンショット 2020-01-18 9.46.41（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/b57a7e4d-bce0-3560-50fd-acd63ce29d81.png)

1. 「使ってみる」をクリックする。
![スクリーンショット 2020-01-18 9.47.16（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/e48de3a4-63fb-9b70-18d1-39f857a2c763.png)

1. パスワードを入力して「次へ」をクリックする。
![スクリーンショット 2020-01-18 9.47.42（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/43558faf-b2f8-7d25-a04a-a88c61083c42.png)

1. 電話番号を入力しコード取得をする方法を選び「次へ」をクリックする。
![スクリーンショット 2020-01-18 9.50.42（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/5d5d6ee7-12b4-a0bf-c7e2-2e833cabbf20.png)

1. 取得したコードを入力する。
![スクリーンショット 2020-01-18 9.51.07（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/557a989b-29f9-663e-a888-39fbaf007947.png)

1. 「有効にする」をクリックする。
Windows : Apacheを起動する

# 目次
1. Apacheを起動する
2. Visual C++ 2015のランタイムをインストールする
3. Apacheが起動しているかを確認する

# 1. Apacheを起動する
![apache-launch-windows10-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/8726bfa3-d287-d013-fbec-03131be3a4aa.png)
Apacheを起動するためには、C¥:Apache24¥binフォルダの中にあるhttpd.exeをダブルクリックします。

![apache-launch-windows10-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/054e669e-6c24-ccea-30b0-6c36ac5e3759.png)
Apacheが起動します。画面には、コマンドプロンプトが自動で表示されます。

![apache-launch-windows10-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/ff225cf8-4662-f9e3-dc1e-b949ef0b2ce3.png)
もし上記のようなダイアログが表示された場合は、起動に失敗しています。これはPCに「Visual C++ 2015のランタイム」がインストールされてないため発生します。その場合「Visual C++ 2015のランタイム」をPCにインストールする必要があります。

![apache-launch-windows10-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/8088b214-ccc1-fca3-b339-4568c535028a.png)
初回起動した場合、「Windowsセキュリティの重要な警告」ダイアログが表示されます。「プライベートネットワーク」にチェックをつけ、「アクセスを許可する」ボタンをクリックします。
Note : コマンドプロンプトを使ってApacheを起動することができます。

### フォルダを移動する
```
cd C:¥Apache24¥bin
```
まず上記のコマンドを入力し「Enter」キーを押し、httpd.exeファイルがあるbinフォルダに移動します。

### Apacheを起動する
```
httpd.exe
```
上記のコマンドを入力し「Enter」キーを押すとhttpd.exeが実行されapacheが起動します。

# 2. Visual C++ 2015のランタイムをインストールする
![apache-launch-windows10-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/1a830bc0-c6d9-8a2c-d448-4261e7f08a1f.png)
Microsoftの「Visual Studio 2015 の Visual C++ 再頒布可能パッケージ」のダウンロードページを表示し、「ダウンロード」ボタンをクリックします。

![apache-launch-windows10-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/456204c0-ae29-eca3-f7c8-709f96a9f966.png)
今回は64bit版をインストールするため「vc_redist_x64.exe」にチェックを付け「次へ」ボタンをクリックします。するとEXE形式のファイルがダウンロードされます。 

![apache-launch-windows10-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/8889ffb7-f5d8-b999-1ece-54df2041b313.png)
ダウンロードしたEXEファイルをダブルクリックするとインストーラーが起動します。
ライセン条項の内容を確認した後、「ライセンス条項および使用条件に同意する」にチェックをつけ、「インストール」ボタンをクリックします。

![apache-launch-windows10-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/073e233d-3f2a-abe5-a578-2ccc3449a0a1.png)
しばらくするとインストールが完了します。「閉じる」ボタンをクリックし、インストーラーを終了させます。
`C¥:Apache¥bin¥httpd.exe`をダブルクリックすると、今度は正常にApacheが起動するはずです。

# 3. Apacheが起動しているかを確認する
Apacheが正常に動作しているかを確認するためにMicrosoft Edgeからアクセスし確認します。

![apache-launch-windows10-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/4bbeb341-6b31-96e8-bb5f-da8d7bf072b7.png)
Microsoft Edge（他のブラウザでもかまいません）で`http://localhost`にアクセスし、上記のように「It works!」と表示されていれば問題ありません。

Apacheが正常に起動しています。

Apacheの起動手順についての説明は以上です。
中学2年生がRailsでウェブサービスを作った

中学2年生の私がウェブサービスを作ってみました。
ほかにも中学2年生で作った方がいるようですが。。ｗ
<br>

ウェブサービス遊びサーチ
https://asobisarchapp.herokuapp.com/

<h1>ウェブサービス公開までの経緯</h1>
まず私はプログラミングを始める前にショートカットキーを覚え、
それからプログラミングを覚えました。
最初はプログラミング言語ではない、マークアップ言語（ＨＴＭＬ,ＣＳＳ）を勉強していて、そのあとに、javascriptを勉強しました。
ちなみに、スクールなどには通わず、プログラマーの人に教えてもらっています。別にお金を払っているわけでもありません。。

それがこの人です。
https://www.youtube.com/channel/UClRPOSBS_N4cnLPLjNvOJdw

このがつさんにおしえてもらって、いろいろたくさんの言語を覚えることができました。
そして、javascriptとHTMLとCSSをある程度やって、Rubyを勉強し始めて、ついにRailsに入った感じです。
そして、いろいろ教えてもらいながら、2,3月後に遊びサーチを公開しました。

<h4>Rails勉強中に本当に参考になったもの</h4>
<hr>
https://www.youtube.com/watch?v=QD54YOYqkcQ&list=PLLtm0VpE-z3NMFXMaLW6NqSVHqLLLAIRi

本当にわかりやすい解説が最高でした。

<h2>最後に</h2>
<p>中学生でもスクール通わずにウェブサービスつくれるんだぞ！ということを言いたかったです。</p>

ほかにもUnityもやってまだ未完成ですが、ゲームも公開しています
https://htmljsgit.github.io/Unity2D-/

twitterもやっていたんですが、パスワードわすれてログインできませんｗ

前までやっていたtwitter
https://twitter.com/HTMLrailskuro?lang=ja

youtubeチャンネル

https://www.youtube.com/channel/UCfqvt18D9iDvt9EfkLZM_3Q

<h3>参考記事</h3>

https://qiita.com/Anharu/items/09f29b6eafd3b8db5534

終わり
スペック


![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513367/e9603a4e-917f-717c-ab4c-0f4f15394925.jpeg)
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513367/a9afb744-8d90-fdbd-2474-f501178abeb6.jpeg)
![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513367/d78bd13c-dd05-621b-98fa-3e5ba8a492e1.jpeg)
![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513367/1863b022-4f87-a163-d4dd-5ed5751addc4.jpeg)
![5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513367/a277cb0c-2687-d96f-4184-740d0ac22653.jpeg)
UnityでListの最小値を取得する最速の方法

A*経路探索のコードを書いていてListの最小値を取得する最速の方法が気になったので検証してみました。
前回、[速度比較のやり方を模索してみた](https://qiita.com/kenkenpa464/items/a3cf6f7cfe70d491223a)のはこの為だったりします。
#for文 vs Min()
普通にfor文で全要素を一つづつ比較していくのとlinqのMin()を使うのではどっちが速いんでしょうか？

コードは以下です。
0～100000のランダムな整数の入った要素数１０万のListを宣言してその中から最小値を取得、
Profiler.BeginSample/EndSampleで、最小値を取得する部分だけを計測しています。

```c#
public class MinTest {

    //for文のやつ
    [Test]
    public void UseFor() {
        var randamValues = GetRandamValues();
        Profiler.BeginSample("MinTest.UseFor");
        var min = randamValues[0];
        for (int i = 1; i < randamValues.Count; i++) {
            min = randamValues[i] < min ? randamValues[i] : min;
        }
        Profiler.EndSample();
        Debug.Log(min);
    }

    //Min()
    [Test]
    public void UseMin() {
        var randamValues = GetRandamValues();
        Profiler.BeginSample("MinTest.UseListMin");
        var min = randamValues.Min();
        Profiler.EndSample();
        Debug.Log(min);
    }

    List<int> GetRandamValues() {
        var randamValues = new List<int>();
        for (int i = 0; i < 100000; i++) {
            randamValues.Add(Random.Range(0, 100000));
        }
        return randamValues;
    }
}
```
##結果
| |GC Alloc |Time|
|:--|--:|--:|
| UseFor|0B |1.18ms|
| UseMin|40B|1.49ms|
速度には気にするほどの差は出ませんが、Min()はGC Allocが発生してしまいますね。
#条件分岐の書き方で差は出るの？
やっぱり普通にfor文使うのが速いですね。
しかし、もう一つ気になることがあります。
条件分岐の書き方で差が出るかどうかです。

```c#
//for文のやつ
    [Test]
    public void UseFor() {
        var randamValues = GetRandamValues();
        Profiler.BeginSample("MinTest.UseFor");
        var min = randamValues[0];
        for (int i = 1; i < randamValues.Count; i++) {
            min = randamValues[i] < min ? randamValues[i] : min;//←ここの書き方で差は出るの？
        }
        Profiler.EndSample();
        Debug.Log(min);
    }

```
以下の３つを試してみます

###①if文
```c#
if (randamValues[i] < min) min = randamValues[i];
```
###②条件演算子

```c#
min = randamValues[i] < min ? randamValues[i] : min;
```
###③条件演算子（条件式を反転）

```c#
min = randamValues[i] >= min ? min : randamValues[i];
```
##結果
誤差で結果が上下するので、１０００回の平均を計測しました。
微妙に差が出ますが、気にするレベルではないですね。

| |GC Alloc |Time|
|:--|--:|--:|
|①if文|0B|1.28120ms|
|②条件演算子|0B|1.26898ms|
|③条件演算子（条件式を反転）|0B|1.24765ms|
#まとめ
普通にfor文使うのが速いしGC Allocも発生しない！

ご意見ご感想、多分これが一番速いと思います等ありましたらコメントを頂けますと幸いです！
IntellijでGolangやるときの設定Tips

Gakuです。
Intellijで新規Golang PJを作成した際、いつも忘れるので、自分用の備忘録として残しておきます。

# go rootの設定(必須)
Preference > Language & Frameworks > Go > GOROOT

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47132/6337f61f-388f-ba16-4529-2601e9a59f64.png)
でGOROOTを設定する。


# go modを有効にする
pj rootフォルダで

```
gakumbp:ddd-golang gaku$ go mod init
go: creating new go.mod: module github.com/gaku3601/ddd-golang
```
上記を実行し、go.modを作成する。
Go Modulesの設定をしていないと、実行は可能だがコードがエラーの状態になってしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47132/7206e9ea-2bbb-79f4-40cc-2fdc44f5d605.png)

Preference > Language & Frameworks > Go > Go Modules(vgo)
で以下のように設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47132/adde3f58-5948-eec5-e4b6-f6d11b0085a7.png)

これで、コードのエラーがなくなる。

# 自動fmt、自動imports
Preferences > Tools > File Watchers
の+でgo fmt・goimortsを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47132/758f1f33-ead9-f7dc-907e-c1d5ada46f83.png)

これで自動フォーマット、自動importが効くようになる

# linter
Preferences > Tools > File Watchers
でgolangci-lintを選択
go.modをpj root以外に設定している場合、Working directoryをgo.modが配置している場所と同じところを指定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47132/5c1acc48-b2c9-729f-060f-5c40c164308f.png)
lintが効くようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47132/eb913198-3461-f414-0c5e-84714f03b1e5.png)
AWS認定 Alexa スキルビルダーに合格したので受験の感想など


![ai_smart_speaker_character.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8219/e1f10f1a-9087-cefc-0232-020c29e4efc4.png)


先週、AWS認定 Alexa スキルビルダー 受験して無事合格したので感想など
（最近スキル開発から遠ざかってますが...）

### 経歴など

- 約1年ほど前に趣味でAlexaスキル（AudioPlayer系）を２つほど公開済み
    - 逆に言うと、ビジュアルを伴うマルチモーダルなスキル、ダイアログを利用したような会話が主体となるようなスキルは未経験
- 業務で日常的にAWSのサービスを利用（4年程度）
    - 特にスキルでもよく利用される以下のサービスについては大体把握している（~~チョットできる~~ 「何もわからない」くらい）
        - Lambda
        - S3
        - DynamoDB
        - CloudWatch Logs

### 感想

スキルを実装／公開した経験があれば比較的簡単だと感じました。

以下のようなキーワードに注意しておくと良さそうでした。

・スキルの種類について（できること／できないこと）
・子供向けスキルの制約
・呼び出し名の制約
・セッションの扱い方
・永続属性の扱い方
・SSML
・ダイアログ
・Lambda関数のテスト／デバッグ方法
・スロットの解決方法（発話の結果スキルが実際に受け取る値について）
・ダイアログモデル
・スキル公開後の修正

特に、以下のページにある「試験ガイド」と「サンプル問題」には必ず目を通しておくことをオススメします。

https://aws.amazon.com/jp/certification/certified-alexa-skill-builder-specialty/

予習／復習の教材として「Alexa道場」も良いと思います

https://developer.amazon.com/ja-JP/alexa/alexa-skills-kit/webinars
Vim スクリプトで配列の各要素を加工したいときに使う map() 関数

## はじめに

Vim スクリプト内で配列を扱う際、ruby の `map` メソッドのように、配列の各要素に一定の処理をかけた配列を再度利用できるかどうかについて調べてみました。

## tl;dr

組み込み関数である `map()` 関数を使うと良さそうでした。

`map(list, 'v:val')` のように使うのですが、第2引数で行う処理の中で `v:val` と書くことで、リスト内の要素を指定できます。

## 例

例えば文字列のリストがあったとき、各文字列要素の末尾に「: 」というような suffix をつける場合は以下のように書くことができます。

```vim
list = map(['1st', '2nd', '3rd'], 'v:val . ": "')
```

結果は `['1st: ', '2nd: ', '3rd: ']` という形になります。

## おわりに

Vim スクリプトの組み込み関数だけでも便利な機能がたくさんありますね。今まで書いていた配列の実装がもう少しシンプルに書けそうだなと思いました。

## 参考

* [Vim の map() や filter() に渡すラムダ内で v:val や v:key が使用できる - Secret Garden(Instrumental)](http://secret-garden.hatenablog.com/entry/2016/10/14/000000)
* [usr_41 - Vim日本語ドキュメント](https://vim-jp.org/vimdoc-ja/usr_41.html#41.7)
【Vuetify】<v-avator>を使って背景色を動的に変更するサンプル

## はじめに
Vue.jsのUIコンポーネントライブラリである**Vuetify**のうち、`<v-avator>`を使って色を動的に変更するサンプルを残します。



## 環境
```yaml
OS: macOS Catalina 10.15.1
Vue: 2.6.10
vuex: 3.1.2
vuetify: 2.1.0
```
## 前提:`<v-avator>`とは？
[Avatar component — Vuetify.js](https://vuetifyjs.com/ja/components/avatars)

**Vuetify**が提供している、以下のような**アバター**をお手軽に実装出来る**コンポーネント**です。
※画像は公式ドキュメントより拝借しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483292/bc1010c5-4bdb-eff2-c963-0bf68db375aa.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483292/8f61b59b-45d2-4715-985a-d4640180087b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483292/1310dfae-7355-ac0e-b24b-c9cde117151c.png)

今回はこの`<v-avator>`を使って、中の文字列が

- 1 -> 黄色
- 2 -> 青
- 3 -> 緑

と、それぞれ**背景色を変わる**というサンプルコードを残します。
※**Vuetify**のインストールがまだの方は、以下記事の後半等ご参照下さい。
[【環境構築】Docker + Rails6 + Vue.js + Vuetifyの環境構築手順 - Qiita](https://qiita.com/terufumi1122/items/237b5465e11b26297bde)

## 結論：コード
### 子コンポーネント
シンプルに`<v-avator>`だけを表示するようにしています。

```vue:SampleChild.vue
<template>
  <div>
    <v-avatar
      :color="avatorColor"
    >
    {{ displayName }}
    </v-avatar>
  </div>
</template>

<script>
  export default {
    name: 'SampleChild',
    //propsでv-avator部分を親コンポーネント側で動的に変更出来るようにする
    props: {
      displayName: '',
      avatorColor: '',
    }
  }
</script>
```


### 親コンポーネント
続いて親コンポーネントです。
`v-for`を使って、先程作成した子コンポーネントを`numbers`という配列の要素数に応じて表示するようにしています。

```vue:SampleParent.vue
<template>
  <div>
    <!--配列numbersの要素数だけ表示する-->
    <div v-for="number in numbers" :key="number.id">
    <!--子コンポーネントがpropsで渡した２つの変数を親側で使用-->
      <SampleChild
       :avatorColor="color[number.name]"
       :displayName="number.name"
       >
      </SampleChild>
    </div>
  </div>
</template>

<script>
import SampleChild from './SampleChild';

export default {
  name: 'SampleParent',
  components: {
    SampleChild,
  },
  data() {
    return {
      //表示される配列
      numbers: [
        {id:1, name:1},
        {id:2, name:2},
        {id:3, name:3},
      ],
      //number.nameに応じて変わる背景色
      color: {
        1: 'yellow',
        2: 'blue',
        3: 'green',
      }
    }
  },
}
</script>
```

## 出力
無事、動的に背景色が変更されていることが確認出来ました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483292/b5c2293b-7a05-d50d-0b4c-62522e0b2fd9.png)

### 確認：`number.n`を変更した場合の出力
以下のように変更してみます。

```vue:SampleParent
<template>
...略
</template>

<script>
//...略
  data() {
    return {
      numbers: [
        {id:1, n:2}, //ここのnを1->2へ変更
        {id:2, n:2},
        {id:3, n:3},
      ],
//...略
      }
    }
  },
}
</script>
```
### 変更結果
無事、`numbers.n`に応じて背景色が変化してくれています！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483292/0ccdcc6e-7ae5-48f0-43f1-8726a9a0e861.png)


この考えを応用すれば、**特定のステータスの人**だけ**アバターの背景色**を変える、などの表示が可能となります。

## おわりに
最後まで読んで頂きありがとうございました:bow_tone1:

どなたかの参考になれば幸いです:relaxed:

## 参考にさせて頂いたサイト（いつもありがとうございます）
- [Avatar component — Vuetify.js](https://vuetifyjs.com/ja/components/avatars)
「良いものとはそのまま使って良いもののことである。」


### 良いパソコンとは、買ってきてそのまま使って使いやすいパソコンである。

つまり、Mac Book Pro

### 良いOSとは、インストールしてそのまま使って使いやすいOSである。

つまり、MacOS

### 良いテキストエディタとは、インストールしてそのまま使って使いやすいテキストエディタである。

つまり、VSCode

### 良いIDEとは、インストールしてそのまま使って使いやすいIDEである。

つまり、IntelliJ

### 良い食べ物とは、買ってきてそのまま食べて美味しい食べ物である。

つまり、バナナ
Zellerの合同式から或る日の曜日を得る〜ついでに万年暦〜

Zellerの合同式から、ある日の曜日が何曜日であるかを算出します。

```calcal.py
#!/usr/bin/python3
import sys
y = int(sys.argv[1])
m = int(sys.argv[2])
d = int(sys.argv[3])
youbia = ["日", "月", "火", "水", "木", "金", "土"]

if (m == 1 or m == 2):
    md = m+10
    yd = y-1
else:
    md = m-2
    yd = y

a = yd // 100
b = yd % 100
youbi = (int(2.6*md - 0.2) + d + b + b//4 + a//4 - 2*a)%7

print("西暦", y, "年", m, "月", d, "日は", youbia[youbi], "曜日です。",sep="")

```

出力例

```
$ calcal.py 1967 5 12
西暦1967年5月12日は金曜日です。
$ calcal.py 1994 12 25
西暦1994年12月25日は日曜日です。
$ calcal.py 1995 12 24
西暦1995年12月24日は日曜日です。
$ calcal.py 1998 12 24
西暦1998年12月24日は木曜日です。
$ calcal.py 2000 5 12
西暦2000年5月12日は金曜日です。
$ calcal.py 2019 12 25
西暦2019年12月25日は水曜日です。
$ calcal.py 10000 5 12
西暦10000年5月12日は金曜日です。
$ 
```


#万年暦
cal.py version 2.0
曜日算出と万年暦を纏めたコードを示します。曜日算出関数は、kkddさんの提示してくれた整数演算のものです。
$ ./cal.py y m で、西暦y年m月のカレンダーを表示します。
$ ./cal.py y m dで、西暦y年m月d日の曜日を表示します。
天文学的紀年法で、yは0や負数も指定できます。
BC1年はcal.pyの西暦0年、BC2年はcal.pyの西暦-1年に相当します。

```cal.py
#!/usr/bin/python3
import sys
argvs = sys.argv
argc = len( argvs )
months=[31,28,31,30,31,30,31,31,30,31,30,31]
youbia = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]

def dayofweek(year, month, day):
  m = (month-3)%12
  y = year if month >= 3 else year - 1
  n = day + (13*m+2)//5 + y + y//4 - (y//100) + y//400 + 2
  return (n%7)

def printcal(y,m):
  mm=months[m-1]+(1 if (m==2 and (y%4 == 0 and y%100 != 0 or y%400 == 0)) else 0)
  print(y,m,sep='/')
  print (*youbia,sep=' ')
  f=dayofweek(y,m,1)
  print("    "*f,end='')
  for i in range(1,mm+1):
    print(" %2d " %i,end='')
    if f==6:
      print("")
    f=(f+1)%7
  if f!=0:
    print("")

if argc==3:
  y = int(sys.argv[1])
  m = int(sys.argv[2])
  printcal(y,m)
elif argc==4:
  y = int(sys.argv[1])
  m = int(sys.argv[2])
  d = int(sys.argv[3])
  f = dayofweek(y,m,d)
  print(y, "/", m, "/", d, " is ", youbia[f],sep="")

else:
  print("Usage : cal.py y m [d]")
  exit(1)

```

# 出力例

```
$ cal.py 2020 2
2020/2
Sun Mon Tue Wed Thu Fri Sat
                          1 
  2   3   4   5   6   7   8 
  9  10  11  12  13  14  15 
 16  17  18  19  20  21  22 
 23  24  25  26  27  28  29 
$
```
競技プログラミング用のD言語でいい感じに入力を取るライブラリ

#まえがき
自分のために作ったのですが、
使ってて結構気持ちいいので記事にしました。
一番下に本体があるのでコピペして使ってください。

#どんな感じか
例えばグラフだと、

```
//N
//An Bn
3
1 2
2 3
1 3
```
これを読もうとするコードはこんな感じになると思うんですけど結構冗長ですよね。

```d
struct Edge{
    long a, b;
}
long N;
readf("%d", N);
Edge[] edges;
foreach(i;0..N){
    long x, y;
    readf("%d %d", x, y);
    edges ~= Edge(x, y);
}
```
このライブラリを使うとこんな感じで読めます。

```d
struct Edge{
    long a, b;
}
auto N = scanElem;
Edge[] edges = scanElem!Edge(N);
```
#機能
空白区切りで1つずつ読んでいきます
改行などもいい感じに処理してくれます

```d
T scanElem!(T=long)
T[] scanElem!(T=long)(long size)
T scanElem(T)()if(is(T==struct))
Tuple!List[] scanElem(List...)(long size)
Tuple!List scanElem(List...)()
```
テンプレートに型を渡します。
構造体を渡すとメンバーを上から順番に読んでくれます。
構造体が入れ子になっていても再帰的に読んでいきます。
複数渡すとタプルにして返します。

scanElemの引数に読み込む個数を渡すと配列にいれてくれます。
引数なしならそのまま1つです。

##例
##文字列も取れます

```d
//N
//NAMEn AGEn
3
harusann2 22
nako 3
tako 1
```

```d
void main(){
    struct User{
       string name;
       long age;
    }
    long N = scanElem;
    User[] users = scanElem!User(N);
}
```

###入れ子にも出来ます

```
//N
//Xn Yn Rn
2
1.2 2 0.3
3.8 4.2 0.9
```

```d
void main(){
    struct Vector{
       real x, y; 
    }
    struct Cicle{
        Vector pos;
        real r;
    }
    long N = scanElem;
    Cicle[] cicle = scanElem!Cicle(N);
}
```

###タプル

```
1 2
```

```d
void main(){
    Tuple!(long,long) HW = scanElem!(long,long);
}
```

#本体
コピペして使ってください

```d
T[] scanElem(T=long)(long size)
{
    T[] list = new T[size];
    foreach(i;0..size)
    {
        list[i] = scanElem!T;
    }
    return list;
}

T scanElem(T)()
if(is(T==struct))
{
    T res;
    foreach(ref field; res.tupleof){
        field = scanElem!(typeof(field));
    }
    return res;
}

Tuple!List[] scanElem(List...)(long size)
{
    auto list = new Tuple!List[size];
    foreach(i;0..size)
    {
        list[i] = scanElem!List;
    }
    return list;
}
Tuple!List scanElem(List...)()
{
    List res;
    foreach(i, e; List){
        res[i] = scanElem!e;
    }
    return tuple(res);
}

T scanElem(T = long)()
if(isBasicType!T||isSomeString!T)
{
    import core.stdc.stdlib;
    static auto scanBuf = appender!(char[])([]);

    scanBuf.clear;

    int c = ' ';
    while (isWhite(c) && c != -1)
    {
        c = getchar;
    }
    while (!isWhite(c) && c != -1)
    {
        scanBuf ~= cast(char) c;
        c = getchar;
    }
    return scanBuf.data.to!T;
}

```
Day8 管理機能と画像アップロード機能

今日は大きく分けてタイトル二つを実装した。
他はずっと問題だったLink_toがGET以外のリクエストを送信できない問題も解決することができた。
#管理機能
管理機能は、ユーザが意見や問合せなどを送信できるフォームと、その内容を管理者のみが見れるという仕組みを実装した。特に新しいことはなかったが、SyntaxErrorなどがよくあったため、しっかりと確認することはくせにしたいと思う。
#画像アップロード機能
プロフィールへのコメントする際と、ユーザが登録する際のプロフィール画像に使う際、そして上述した管理機能の問合せフォームに添付する時の３つの画像アップロード機能を実装した。
工夫した点は、表示するのはすべて100*100にリサイズされたサムネイルで、拡大表示をすれば下の画像を見ることができるようにした点。
#感想
なんとなくわかるけど、正確にはわかっていないということがある。例えば今日実装した画像アップロード機能はその最たる例で、動いてるけど、基礎がわかっていないと解決できない問題が発生したらこの知識では対処ができないと思う。
これから課題リストに、画像アップロードのロジックや学習したことをまとめるが、なんとなくではなくて、しっかりと正確に理解することを心がけたい。
#これから
今日でいよいよ根幹となるサーバサイドの機能は大方実装することができた。
明日からは、細かいところの修正やぐちゃぐちゃのコードの整理に入りたい。そのあとはいよいよCSSでデザインを整えて、その後Rspec？でテストコードを実装しようと思う。
どこかでHerokuにデプロイを挟んだ方がいいんだろうか？絶対にどこかでエラーが出そうなので覚悟しておきたい。