OmniAICreator/Qiita-1.07M huggingface dataset:
VRC テクスチャーのパラメータ(色、反射)などの設定をする


#1 この記事は
VRCのワールド作成にて、半透明のオブジェクト(例：窓ガラス)を作成する方法を説明します。

#2 やり方は？

## 2-1 既存のアセットを利用する場合

下記のサイトからテクスチャーをダウンロードする。2K-JPGが適切なサイズだと思う。
https://ambientcg.com/

![202.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/e281cb09-a4f3-20be-3755-d27256ddf7dd.jpeg)

Webサイトからデータを入手後、データを展開する。目的の画像データをUnityのAssetsに取り込む。
![203.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/f9a2050d-313a-6069-5f60-3f20e6542450.jpeg)

必要があればデータの圧縮を行う。各種パラメータの設定例は、下記画像を確認する。
![204.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/70b693d8-5366-6475-14a5-e2dd7f40fcfd.jpeg)

対象のオブジェクトに上記で編集したテクスチャーをかぶせる。
![205.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/d00819af-d674-713a-e103-f85214edc226.jpeg)

上記操作を行うと「Materials」フォルダが生成される。
![206.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/32cc858f-7646-d143-ea5e-de324da8ba49.jpeg)

「Materials」フォルダ内のテクスチャーを選択し、パラメータの設定する。テクスチャーの光沢を設定したい場合は、Metallicの数値を調整する。Metalic は表⾯の⾦属度具合を調整する。効果としては⼤きな値にすると外の⾵景がたくさん映り込む。⾦属光沢みたいな感じです。

![207.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/953c1c81-749d-2efb-b43f-6d864ccef6bc.jpeg)





## 2-2 独自で設定する場合






1. Create -> Materialを選択する
![211.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/91ba4cfd-a340-4639-7a42-e16718cfaec1.jpeg)

2. Assetsの箇所にアイコンが表示されるので、適当な名前(ここでは、glassと命名した)をつける。

![212.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/ced0d1c0-fc8f-fc8c-44f7-b0b687ef7c59.jpeg)

3. Inspectorを表示させ、「Rendering Mode」をTransparentにする。透明のテクスチャが生成される。

![213.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/9fcb0029-53c3-f887-4331-ad7984a27b56.jpeg)

また、Albedoを選択すると、テクスチャーの色を選択できる。Aの数値を小さくすると透明度が高くなる。

![214.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/d333d6d0-437d-e4b7-01c7-d943f1792ebf.jpeg)

4. 上記で設定したテクスチャーをオブジェクトに貼り付けると、オブジェクトは透明になる。

★上記で作成したテクスチャーと貼り付ける前
![215.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/bef9039f-08ca-0940-e6ce-c5e6ad216065.jpeg)


★上記で作成したテクスチャーを張り付けたあと
![218.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/9aa6dc07-bf9e-2211-a9e7-080dc9f118f9.jpeg)
unicornの自動起動(ubuntu20.04でのinit.d)

##unicornをOS起動時に自動起動させたい
###環境
Ubuntu20.04
rails6
unicorn
nginx

###設定
以下参考にしたところ
[Unicorn の自動起動と etc/init.dの使い方](https://qiita.com/dossy/items/cd68f2545639b9507d40)

ここにあるshellスクリプトをunicornというファイル名で/etc/init.dに置きます。
chmodは755に

###update-rc.d
ubuntu20.04の場合、chkconfigコマンドが入っていないので
update-rc.dで自動起動の設定をします。
そのためシェルスクリプトにrun levelを書いて置く必要があります。
(以下の### BEGIN INIT INFOから### END INIT INFOの部分)
これを記述しておかないとupdate-rc.dが機能しません。

```sh:/etc/init.d/unicorn
#!/bin/sh
### BEGIN INIT INFO
# Provides:          myrec
# Required-Start:    $all
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:
# Short-Description: unicorn shell
### END INIT INFO

USER="ec2-user"
NAME="Unicorn"
ENV="production"

ROOT_DIR="/var/www/application"

PID="${ROOT_DIR}/tmp/pids/unicorn.pid"
CONF="${ROOT_DIR}/config/unicorn.rb"
OPTIONS=""
CMD="RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c ${CONF} -E ${ENV} -D"

start()
{
  if [ -e $PID ]; then
    echo "$NAME already started+${PID}"
    exit 1
  fi
  echo "start $NAME"
  su - ${USER} -c "cd ${ROOT_DIR} && ${CMD}"
}

stop()
{
  if [ ! -e $PID ]; then
    echo "$NAME not started"
    exit 1
  fi
  echo "stop $NAME"
  kill -QUIT `cat ${PID}`
}

force_stop()
{
  if [ ! -e $PID ]; then
    echo "$NAME not started"
    exit 1
  fi
  echo "stop ${NAME}"
  echo ${PID}
  kill -INT `cat ${PID}`
}

reload()
{
  if [ ! -e $PID ]; then
    echo "$NAME not started"
    start
    exit 0
  fi
  echo "reload $NAME"
  ##kill -HUP `cat ${PID}`
  su - $USER -c "cd ${ROOT_DIR} && bundle exec unicorn_rails:reload"
  ## su $USER -lc "cd ${RAILS_ROOT}&& bundle exec rake unicorn_rails:reload"
}

restart()
{
  force_stop
  sleep 5
  start
}


case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  force-stop)
    force_stop
    ;;
  reload)
    reload
    ;;
  restart)
    restart
    ;;
  *)
    echo "Syntax Error: release [start|stop|force-stop|reload|restart]"
    ;;
esac
```
#####OS起動時に自動起動
chkconfigはubuntuでは使えないので、以下のコマンドを投入

```sh:sh
$ sudo update-rc.d unicorn defaults
```
このコマンドは/etc/rc*.d/（*はrun level)にシンボリックリンクを張ります。
これでOS起動時にunicornが起動します。

#####確認

```sh:sh
$ ls -l /etc/rc*.d | grep unicorn
```

#####自動起動をやめたいとき

```sh:sh
$ sudo update-rc.d unicorn remove
```
ドメインの基礎知識をまとめてみました。

DNSの仕組みの中で出てくるドメイン。

なんとなく「IPアドレスに名前がついたものでしょ」という認識程度で深く調べてみたことがなかったので、認識確認の意味も含めちょっと調べてみました。

参考URL
https://muumuu-domain.com/supports/about-domain
https://www.kagoya.jp/howto/webhomepage/01/
https://www.cman.jp/network/term/ip/p3/

#ドメインとは


###「ドメインとはインターネット内での住所に位置づけられるもの」

要するに自分の認識通り、IPアドレスと同じ意味合いという認識で間違いはないようですが、さらにわかりやすくいうのならば、、

IPアドレス：住所を緯度で表したイメージ

ドメイン：住所を国、地域名で表したイメージ

てな感じのようです。

また使われ方としてURL上やメール上（＠〇〇.comみたいな）で使われていますが、
####要するにサーバーの位置を表しているということ！
（当たり前のことではありますが。。）





#ドメインの種類について

もう少し掘り下げてみてみるとドメインにはいくつか種類があり、
〇〇〇〇.comの丸の部分に自分の好きな文字を入れた「独自ドメイン」

またよく見かける「com」「jp」など「.」のあとに続くものをトップレベルドメインと言われる。
これは要するに、国や企業、組織ごとで振り分けられている名前の箇所ということのようです。

いくつか種類がありますが、割愛します。（気になる方はURL参照）


#おまけ・・・IPアドレスは固定なものではない？？

最後にIPアドレスについて。
学習する中の教材で「IPアドレスは基本ランダム（動的）?」みたいなことを言ってので、おまけでその真意も調べてみました。

結論、「クライアント側（PC）は動的（自動）で設定することが推奨される」ということらしい

固定としてIPを設定する場合は、Webサーバなど使用用途をはっきりさせている場合に多い。
よくよく考えているとサーバのIPが動的だとDNSでの設定で紐付けるIPアドレスが一致しなくなるし、それはそうかって感じでした。
（IPアドレスの範囲を指定してとかならできるけど）

他にもメリット、デメリットあり、
動的だとIPアドレスを悪用した攻撃を受けにくくなったり、
プロバイダー費用が安くなったりあるらしい。
デメリットとしては、いわば流動的なIPアドレスになるので、アクセスがしにくくなったり、
不正なアクセスがあった際などはその特定が難しくなったりと弊害もあるよう。。
HTML・CSSを書く時のメモ

#はじめに
この記事は私がHTML・CSSの学習で学んだことや、コーディングの際に覚えておきたいメモを記載したものです。適宜更新していきます。

#HTML・CSSテンプレート
##HTML
```html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>○○○○○○○○○○</title>
</head>
<body>
<header>
  <div class="container clear">
    <div class="header-left">

    </div>
    <div class="header-right">
      <ul class="header-nav">
        <li class="header-nav-item"><a href=""></a></li>
        <li class="header-nav-item"><a href=""></a></li>
        <li class="header-nav-item"><a href=""></a></li>
        <li class="header-nav-item"><a href=""></a></li>
      </ul>
    </div>
  </div>
</header>

<section class="top">
  <div class="container">

  </div>
</section>

<section class="about section">
  <div class="container clear">

  </div>
</section>

<section class="contact section">
  <div class="container clear">

  </div>
</section>

<footer>
  <div class="container clear">
    <p class="copyright">Copyright(C) ○○○○○○○○○○ ALL Rights Reserved.</p>
  </div>
</footer>


</body>
</html>

```
##メモ
###clearクラス
レスポンシブ対応の際にfloatを外して縦並びに戻したい要素の親要素に入れておく。
メディアクエリでする。

```css
.clear::after {
  clear: both;
  content: "";
  display: block;
}
```


#CSS
```css

/* ===================
common
=================== */

body {
  color: black;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
  line-height: 1.5;

}

img {
  height: auto;
  width: 100%;
}

a {
  color: black;
  text-decoration: none;
}

a:hover {
  opacity: 0.7;
}

.container {
  width: 90%;
  max-width: 960px;
  margin: auto;
}

.clear::after {
  clear: both;
  content: "";
  display: block;
}
```
##body

###line-height: 1.5;
目的：行の高さを指定する。
１だと行が詰まって読みにくいため、間隔を空ける。


##a
###text-decoration: none;
目的：テキストの装飾的な線の表示を設定する。
aタグの下線を消す。

##float:left;
目的：縦並びの要素を浮かせて横に移動させる。
参考ツイート
https://twitter.com/098ra0209/status/1085519869485887494
浮き上がった要素の下に次の要素が入り込むので、以下の方法で回避する。

##display: flow-root;
目的：floatによる回り込みを回避する。
回り込みを回避したい要素のCSSに追加する。
下の`.clear::after`と異なりclearタグをクラスに追加する必要が無く、1行で済むためこちらを使うことにする。

##.clear::after
目的：floatによる回り込みを回避する。
floatを解除したい要素の親要素にclearタグを追加し、以下のCSSを記載する。

```css

.clear::after {
  clear: both;
  content: "";
  display: block;
}

```
pyenvでインストールしたpythonをrootユーザー権限（sudo）で使う方法

# pythonの環境を確認
```
$which python
/home/[user]/.pyenv/shims/python
```
pyenvで管理されているpythonにパスが通っている。

```
$python -V
Python 3.7.7
```
バージョンは3.7.7

# sudoで実行したときの挙動を確認する
```print_python_version.py
import platform
print(platform.python_version())
```
pythonのバージョンがプリントされるスクリプト

```bash
$python print_python_version.py 
3.7.7
```
一般ユーザーとして実行する。pyenvのpythonで実行されている。

```bash
$sudo python print_python_version.py 
2.7.16
```
rootユーザーの権限で実行する。pythonのバージョンが3.7.7でない。

```
$sudo which python
/usr/bin/python
```
システムのpythonで実行されている。

# 実行するpythonをshebangで明記する
```print_python_version_shebang.py
#!/home/[user]/.pyenv/shims/python

import platform
print(platform.python_version())
```


```
chmod +x print_python_version_shebang.py
```
実行権限を与える。

```
$./print_python_version_shebang.py
3.7.7
```
一般ユーザーとして実行する。pyenvのpythonで実行されている。

```
$sudo ./print_python_version_shebang.py
3.7.7
```
rootユーザーの権限で実行する。pyenvのpythonで実行されている。

# まとめ
shebangで使用したいpythonのパスを明記すれば解決した。
【Android】UI テストに Page Object デザインパターンを適用する

## Page Object デザインパターン

UI テストにおける Page Object デザインパターンとは、１つの画面を１つのオブジェクトとして定義し、画面に対する操作や検証をオブジェクト経由で行う設計指針です。このデザインパターンを適用させることにより、可読性や保守性を向上させることができます。

コードを見た方がわかりやすいと思うので、今回は簡単な具体例で考えてみます。

## ログイン処理の UI テスト

Espresso を使った次のようなログイン処理の UI テストを例に考えます。

```kotlin
@Test
fun loginSuccess() {
    // ユーザー ID を入力
    onView(withId(R.id.user_id)).perform(
        ViewActions.replaceText("test_user_id")
    )
    // パスワードを入力
    onView(withId(R.id.password)).perform(
        ViewActions.replaceText("test_user_password")
    )
    // ログインボタンをクリック
    onView(withId(R.id.login_button)).perform(click())

    // ホーム画面に遷移して「ようこそ」が表示されていることを確認
    onView(withId(R.id.welcome)).check(
        matches(withText("ようこそ"))
    )
}
```

ログインに必要な情報を入力してログインをクリックし、次のページで「ようこそ」と表示されることを確認する UI テストです。

ここではログイン画面とログイン後表示されるホーム画面の２つの画面が登場します。この２つの画面について、それぞれ Page Object デザインパターンに沿ってオブジェクト化してみます。

### ログイン画面のオブジェクト化

まずはログイン画面をオブジェクト化します。

Page Object デザインパターンに従って画面をオブジェクト化するときは「その画面でできること」を抽出して１つずつメソッド化します。今回のログイン画面で言えば下記のとおり。

- ユーザー ID 欄にテキストを入力する
- パスワード欄にテキストを入力する
- ログインボタンを押してログインする

この３つをオブジェクトに実装します。

```kotlin
class LoginPage() {
    fun inputUserId(userId: String): LoginPage {
        // ユーザー ID を入力
        onView(withId(R.id.user_id)).perform(
            ViewActions.replaceText("test_user_id")
        )
        return this
    }

    fun inputPassword(): LoginPage {
        // パスワードを入力
        onView(withId(R.id.password)).perform(
            ViewActions.replaceText("test_user_password")
        )
        return this
    }

    fun clickLoginButton(userId: String, password: String): HomePage {
        // ログインボタンをクリック
        onView(withId(R.id.login_button)).perform(click())

        // 遷移先であるホーム画面のオブジェクトを返却する
        return HomePage()
    }
}
```

３つのメソッドが実装できました。ここでポイントとなるのはメソッドの戻り値です。メソッドの戻り値は必ず Page Object にします。処理のあと画面に止まるのであれば `this` を、画面を遷移するのであれば遷移先のオブジェクトを返します。こうすることでメソッドチェーンが可能となり可読性が向上します。

```kotlin
LoginPage().inputUserId("...")
    .inputPassword("...")
    .clickLoginButton()
```

### ホーム画面のオブジェクト化

次にホーム画面をオブジェクト化します。

```kotlin
class HomePage() {
    fun assertWelcomeMessage(): HomePage {
        //「ようこそ」が表示されていることを確認
        onView(withId(R.id.welcome)).check(
            matches(withText("ようこそ"))
        )
        return this
    }
}
```

今回は特にホーム画面で操作することがないので「ようこそ」が表示されていることを確認するアサーションだけ実装します。

### 完成形

下記がテストの完成形になります。

```kotlin
@Test
fun loginSuccess() {
    LoginPage().inputUserId("test_user_id")
        .inputPassword("test_user_password")
        .clickLoginButton()
        .assertWelcomeMessage()
}
```

一番最初に示したコードよりも、何をやっているか直感的でわかりやすくなっているかと思います。

また、誤ったパスワードが入力されたときにログインが失敗するテストを作りたい場合、`inputPassword()` に不正なパスワードを入力することでログインに失敗させることができます。ログイン成功、失敗それぞれのテストでメソッドを使いまわせるため、保守の側面においても効果的かと思います。
Herokuデプロイしたらレイアウトが総崩れした

忘れないための備忘録！

今回Herokuにデプロイした時に
開発環境側で出来ていたレイアウトを確認したら
レイアウトがぐちゃぐちゃになっていて
唖然としました。

Heroku上で動作する環境の仕様やアセットパイプラインの挙動が異なるため見たいです。

野呂さんが自分が直面している問題の解決法を載せていてくださったので
試してみたらすぐ解決。

[Rails初学者がつまずきやすい「アセットパイプライン」]
(https://www.transnet.ne.jp/2016/02/28/rails%E5%88%9D%E5%AD%A6%E8%80%85%E3%81%8C%E3%81%A4%E3%81%BE%E3%81%9A%E3%81%8Dcolnr%E3%80%8C%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3/)


***Heroku上に反映するためには、2つの作業をすることが確実な方法。***

 

・本番環境上でアセットパイプラインを通るようにプリコンパイル処理を実行する

・本番環境上でアセットパイプラインを自動で通るように設定を変更する


***Herokuにファイルを送付する前に***

```
$ rake assets:precompile RAILS_ENV=production
```
>を開発環境上のコンソールで実行します。

***config/production.rbファイル内の記述のうち***

```
config.assets.compile = false

```
>の記述を見つけ、「falseをtrueに書き換えて」保存する。

これで、Heroku上で使われる環境上のHTMLにCSSやJavaScriptを反映させることができる。
チュートリアル「静的ウェブサイトをホスティングする」をやってみる

#はじめに
このチュートリアルを実際にやってみた記録です。

https://aws.amazon.com/jp/getting-started/hands-on/host-static-website

##できるようになること
GitHubに登録した静的なウェブサイトをAmplifyで公開します。GitHub上のコンテンツが更新されると自動的に再デプロイされる仕組みになります。

##準備するもの
* AWSのアカウント
* GitHubのアカウント

#手順
実際のチュートリアルの中ではReactのコンテンツを作っていますが、React環境がなかったためindex.htmlファイルが一つの簡易コンテンツ版としました。gitコマンドの操作わからなかったのでGitHubのウェブサイトから操作しています。

##GitHubにRepositoryを作成してhtmlファイルを置く

1. GitHubにログインし、右側の「+」マークを押して、「New repository」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/8cd3d653-5f7b-2dfd-eef8-513d4f15c875.png)
1. 「Repository name」を適当に入力したら「Create repository」ボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/d7821572-c5e0-0861-fd93-650cd427d8ec.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/a3583307-1698-f1be-8778-b23632b165c8.png)

1. Repositoryができたら、直下に下記のようなhtmlファイルを登録します。

```html:index.html
<html>
<head><title>My Static Web</title></head>
<body>
<h1>Hello World!</h1>
Nice to meet you.
</body>
</html>
```

ブランチ名は「main」となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/a4a7bbf5-c8b1-a835-7544-07cbb063f575.png)

これでコンテンツの作成が終わりました。

##Amplifyに接続する

1. [Amplifyのコンソール](https://ap-northeast-1.console.aws.amazon.com/)を開いて右上の「New app」ボタンから「Host web app」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/2a568dca-65ef-6dff-c91f-3f88ba4253a3.png)
1. 「From your existing code」のメニューで「GitHub」を選んで「Continue」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/89b64e24-7217-ac82-a5a4-8f8c0d905c8b.png)
1. ここで初めての場合GitHubの認証が行われます。GitHubのUIDとPASSWORDが必要になります。
1. 認証が完了したら先ほどのリポジトリとブランチを選んで「次へ」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/a53739de-16f8-8636-9e61-2c3651db495a.png)
1. 「ビルド設定の構成」の画面が出てくるので、「Allow AWS Amplify.....」にチェックを入れて「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/94bb8a86-76ed-95b7-591c-e23ca771204d.png)

1. 確認画面で「保存してデプロイ」をクリックします。
1. デプロイが少しずつ進んでいきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/31fa34da-b3b6-1b3e-ef31-3098e2881541.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/a235393d-577a-e985-cfa8-4aa9ace68f1d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/5233ce1b-c373-690e-e13a-89dba305e74e.png)

1. デプロイが完了したら、左側のプレビュー画面かURLをクリックするとデプロイされた画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/216bfd2b-f8cb-87a3-8ae4-b8e159bf5601.png)


##GitHubのファイルを更新する

1. GitHubでファイルを更新するたびにAmplifyが自動で再デプロイを行います。ちなみにビルド中にURLをクリックすると、変更前のコンテンツが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/a08a1dd8-2fc0-0c8d-03d7-04a485fa848e.png)

#おわりに
これだけの手順で、GitHubにcommitしたら自動でデプロイ公開されるので、便利さに驚きました。

#参考文献
https://qiita.com/bobrock/items/e2a678ef4137a6cdc151
【VSCode】ファイルを開くショートカットキー

対象のファイルを選択して`⌘ + ↓`で開ける。

`^ + Enter`で開くと新しいエディター画面で開いてしまうので、普通に開く方法がないか探していました。

意外と困っている人がいるかなと思ったので、メモがてら公開しておきます。

## 参照

[visual studio code \- VSCode: Open file from file explorer with Enter key on Mac OSX \- Stack Overflow](https://stackoverflow.com/questions/35157786/vscode-open-file-from-file-explorer-with-enter-key-on-mac-osx)
FirebaseでSSOをやってみた（非推奨）

非推奨としているのはローカルで実験したのみで、セキュリティリスクをあまり考慮していないからです。

## 最初に

今回のやり方はFirebase公式で紹介されている方法ではないです。
とりあえずローカル環境で動かしたってだけなのでセキュリティについても漏れがあります。
また、[参考にした記事](https://dev.to/johncarroll/how-to-share-firebase-authentication-across-subdomains-1ka8)にあるcsstは実装していません。もし本番運用される際は理解した上で追加実装してください。

（参考記事で紹介されているcsstはCSRF対策のもので、CSRFトークンではなくJWTで対応したのだと思います）

https://qiita.com/mejileben/items/ae7b346f0fc4a59101b5

## 構成図

![firebase-sso-sample.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510204/bc0448a6-fe0d-e96f-f2ff-abfce2f0583d.jpeg)

## 実装

### Vue

Vue.jsのメインとなるコードはこれだけです。

``` xxx.js
const response = await axios.get('http://localhost:5000/customToken', {withCredentials: true});
firebase.auth().signInWithCustomToken(response.data.firebaseToken);
```

Tips:  ProjectBのAuthenticationにユーザーが存在しなくても、signInWithCustomTokenで認証できます。

### Express

https://github.com/matometaru/accounts-express

- CORS
- サブドメインでクッキーの共有（今回はlocalhostなので関係なし）
    - [サブドメインの異なるサービス間で cookie を共有する](https://qiita.com/il-m-yamagishi/items/9aad5737c80d5bfd5eb8)

## 最後に

認証周りの実装は考慮することが多くて大変ですね。
ProjectAのAutheticationを[Auth0](https://auth0.com/jp/)に置き換えれば Sessionを使うことなくSSOの実現が可能です。

[Auth0](https://auth0.com/jp/)は公式でSSOの実装例、Firebaseとの連携方法も紹介されています。詳しい料金は調べてませんが、月1万、年12万で認証周りのセキュリティが強化でき、保守コストが下がるなら全然安いと感じました。

## 参考

https://note.com/yusukeoshiro/n/n4fe9eeac499a

https://dev.to/johncarroll/how-to-share-firebase-authentication-across-subdomains-1ka8

https://auth0.com/blog/jp-developing-real-time-apps-with-firebase-and-firestone/
【個人開発】栃木SCのパートナー企業を検索できるサイトを作ってみた。

# はじめに
JリーグのJ2に所属している[栃木SC](https://www.tochigisc.jp/sponsor/)のパートナー企業の一覧表示と絞り込みなどで検索を行えるサイトを、自分の勉強も兼ねて作成してみました。
※企業数は全然網羅できていません。手作業でまとめているので心が折れました・・・。随時追加していく予定。

# 作ったサービス

https://elastic-shockley-e9a519.netlify.app

GitHub：https://github.com/ur-oot/PartnerList

# 作ったきっかけは？
ずっと前からWebアプリを何か作りたいなと思っていたところに、たまたま以下のツイートを見かけました。

https://twitter.com/mobconsa106/status/1403306690456391687

自分自身も栃木SCのサポーターで、サポーターというのは日頃からどうしたらクラブ・サポート企業に還元できるかを考えているものです。このツイートを見て栃木SCのパートナー様でも同じようなサイトがあると面白いんじゃないかと思い、全面乗っかりで作成しました。

話が逸れますが、栃木SCは2018年5月に界隈で良くも悪くも？何かと話題の江藤美帆氏(えとみほ氏)[@etomiho](https://twitter.com/etomiho)をマーケティング戦略部長に招き入れ、J2リーグの中でもいち早くデジタル化に舵を切ったクラブです。IT業界に身を置く私としてもITに力を入れているクラブは少なく、とても話題性があるクラブではないかと思っています。
気になる方はぜひチェックしてみてください。

# 使い方
話を戻して、アプリの使い方です。
凝った機能は実装していない(というよりも、一覧表示・詳細ページ・ちょっとした検索機能ができたとこで初版をリリースした)ので、使い方で困ることはないと思います。

# 使用技術
#### インフラ
- GitHub
- Netlify

#### フロントエンド
- HTML
- CSS(SCSS)
- JavaScript
- Vue.js
- BootstrapVue

フレームワークの選定にあたり色々調べたところ学習コストが低く、初心者でも比較的扱いやすいということでVue.jsを選びました。Vue.jsを使っていることもありSPAでアプリを実装しています。また、過去に少しだけBootstrapを触ったことがあったのでBootstrapVueを選びました。

# 今後の対応予定
#### インフラ
現状だと企業情報を直接JSONファイルに記載して読み込んでいるので、AWSのDynamoDBで管理して、API Gatewayで取得できるようにしたいと思う。

#### フロントエンド
Bootstrapで実装してみたが、カードスタイルなど簡単に実装できるがカスタマイズがしにくかったので、Vuetifyに徐々に移行していきたいと思う。
ついでにデザイン面でもそれなりのデザインにしたいと思う。

#### 機能
実装している機能が全然ないので以下を追加できればと思う。
※随時追加更新予定。

- [ ] お気に入り機能
- [ ] ジャンル別表示
- [ ] 企業のソート機能
- [ ] 絞り込みしてから詳細ページに遷移したあと戻ると絞り込みが初期化されるので保持するようにする
- [ ] アプリ上から登録・編集を行える機能
[Unity]Twitter認証の導入で躓いた話

Twitterのアカウント連携を実装しようと色々躓いたメモ。

#■Firebaseを導入
https://firebase.google.com/?hl=ja

とりあえずFirebaseを利用してみた。
導入手順に沿ってアプリケーション作って、Unity用のSDK(firebase_unity_sdk_8.1.0.zip)を落とす。


###問題１
「dotnet3」「dotnet4」の2フォルダに分かれてる…。
当然ドキュメントにはそこらへんに触れた記述はない。

ド素人に合わせたドキュメントなんてあるわけないかと、と調べたところ
どうやら.NET のバージョンっぽい。
→.Netは4系を利用しているのでdotnet4のフォルダの方を選択

###問題2
.unitypackageがたくさんある。
どれを入れればいいのか公式ドキュメントを読み進めたところ、
認証系だけであれば「FirebaseAuth.unitypackage」だけでいいらしい。


手順に沿って進めていき、FirebaseのコンソールからAuthenticationを選択。
「Sign-in metod」にTwitterがあった。

押してみたところの入力を求められる。
・APIキー
・APIシークレット

なんぞこれ、と調べてみたらどうやらTwitterAPIを利用するために
まずTwitterのDeveloper登録？が必要みたい。

#■TwitterのDeveloper登録
https://developer.twitter.com/

### 問題3
アカウント登録が面倒。
なんか目的とか英語で書いてね、って言われる。しかも承認までに時間がかかりそうな感じ。
ビビッて別の方法がないか調べたけど見つからずしぶしぶ英語(Google翻訳さんに感謝)で書いて、登録。
そしたら即承認されたのかコンソールが使えるようになっていた。

### 問題4
ここからが本当に困ったところ。
https://firebase.google.com/docs/auth/unity/twitter-login?hl=ja
__"Twitter でログインするための手順に沿って、OAuth アクセストークンと OAuthシークレットを取得します"__

OAuth アクセストークンと OAuthシークレットとか急に言われても…。
とにかくTwitterへのログインは別の方法でやらないといけないみたい。
というわけで下記のアセットを利用することに。
_Twitter Kit for Unity_

TwitterDemo.sceneを起動して、実機で確認してみると
"fail to get request token" といったエラーが出てログインできない。

調べてみると
https://github.com/twitter-archive/twitter-kit-android/issues/134

Twitterのコンソールから
callback URLsに
__twittersdk://__
を追加しないといけない模様。
※2018年以降は必要みたい。

callback URLsに上記を追加したところ、
なぜかSaveが押せない…。

調べてみても解決方法がわからず。
試しに元々入れていたcallback urlを修正してみたところそれでもSaveが押せない。
もうお手上げ、ということでTwitterのコンソールからappを再作成し、
最初にcallback URLsを設定するタイミングでtwittersdk://を入力したら無事Saveできて
Twitterのアカウント認証画面が立ち上がった、という話。

まだ何も進んでない…
GCE上にkaggle Dockerを構築してGCSをマウントした

#0.Intro
エラくハマりました。。。GCEもきちんと使ったことないのもありますが何というか勝手が違いますね(何との比較?)

#1.GCE構築
デフォルトのus-central1(アイオワ)で構築しようと思いました。最初は最近使えるようになったと話題のA100を割り当てたりしてみたのですがそもそも、多分ビギナーだからでしょうか、割り当てしてらもえず。P100ならどうかと思ったのですがこちらもだめ。仕方なくT4×4にて妥協(?)。
皆様はMarketplaceから持ってきておられますが、何故かGPUの割り当てがないと言われます。

よって一からGCE立てて環境を作ることにしました。個人的にGPUの割り当てにハマりました。GPUの割り当てはいくつかあるのですが、どうやら
![t4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66198/b1d3993d-51dc-81c9-53f8-49097311e8bd.png)

というNVIDIAA (型番) GPUs　というのがいわゆるインスタンスにGPU割り当てる時に設定する項目のようです隣のVirtual Workstationは「仮想ワークステーション（NVIDIA GRID）を有効にする」を有効にした時に消費される割り当てのようです。
![t4_virtual.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66198/c9e8175c-a7f6-a0b8-bd96-7805c562f4a8.png)
今回はOSはubuntu20.04にしました。ディスクは200Gとしています。(実は一回けちって50Gにしたところディスクが足りないと怒られてやり直している)

GCPのリソース不足でゾーンをus-central1-bに切り替えてやっとこさ構築完了。

GCEを構築できたら
[NVIDIA Docker って今どうなってるの？ (20.09 版)](https://medium.com/nvidiajapan/nvidia-docker-%E3%81%A3%E3%81%A6%E4%BB%8A%E3%81%A9%E3%81%86%E3%81%AA%E3%81%A3%E3%81%A6%E3%82%8B%E3%81%AE-20-09-%E7%89%88-558fae883f44)
を参考にNVIDIA Dockerを入れます。ホストのubuntuには CUDA Toolkit 11.1 Update 1 Downloads を入れています。もちろんインストールの仕方は上記にあるようにドライバだけです。

kaggle dockerのインストール仕方は特に変わったところはありません。あちこちにあるチュートリアルのままです。
kaggle dockerをビルド後起動

```
docker run --rm --gpus all -it kaggle/python-gpu-build  /bin/bash
```
で起動しコンテナに入れることを確認。

#2.GCSマウント
GCEのローカルだけでは心許ないのでGCSをマウントしたいと思います。
※[こちら](https://ryamashina.com/itml/20200907/)を参考にしました。

上記サイトに記載のシェルをコピーして作成し実行、gcsfuseをインストールします。
その後に

```
gcloud auth application-default login
```
を実行しブラウザから認証します。
その後環境変数を設定。

```
export GOOGLE_APPLICATION_CREDENTIALS=~/.config/gcloud/application_default_credentials.json
```
ここまできたらようやく目的のバケットをマウント出来ます。

```
gcsfuse -o allow_other {バケット名} /media/data
```
このときに「 -o allow_other」オプションがないとコンテナ内でpermission deniedで怒られます。
またこのオプションを使うには

```
/etc/fuse.conf
```
というファイル内の

```
# mount_max = 1000
user_allow_other
```
と「user_allow_other」のコメントを外して有効化してください。
<font color="Red">※セキュリティ上の問題も指摘されています。ここは自己責任で。</fond>

ここまできてやっとこさ

```
docker run --rm --gpus all -v /media/:/media/  -it kaggle/python-gpu-build  /bin/bash
```
GCE上のKaggle DockerにGCSをマウントしアクセスできました。
GitHub Sourtree 別のアカウントに切り替えたい

# 背景

GitHub アカウントを 2 つ持っているとします。

- account-A
- account-B

**account-B のリポジトリに account-B ユーザーでプッシュしたい**とします。現在の問題は、**account-B のリポジトリに プッシュすると account-A でプッシュされてしまう** ことだとします。

# 解決方法

左上の「ツール」をクリックし、その中の「オプション」をクリックします。認証タブをクリックし、「追加」をクリックすると右のウィンドウが現れます。その後、「OAuth トークンを再読み込み」をクリックします。認証に成功した後、ユーザー名を確認し「OK」をクリックします。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/d18acf8a-660a-550c-4165-6b86d52fd9e0.png)

追加したアカウントの右側に表示されている「デフォルトに設定」をクリックします。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/47c5af32-7862-e287-35e6-47683d96fefa.png)

右上の歯車のマークの「設定」をクリックし、詳細タブをクリックします。account-B のユーザー名、メールアドレスを入力します。**メールアドレスを変更することを忘れないでください。**最後に「OK」をクリックします。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/2b5270cc-8109-1210-e829-fc41e95eb602.png)

この状態でプッシュすると、account-B でプッシュできることが確認できました。

# 参考記事

https://qiita.com/piyo_prg/items/8672bb47f944055cbab0
【Python3】macのpyenv環境下でtkinterを使えるようにする。

#はじめに
tkinterをimportしたファイルを実行しようとしたところ...
長文のエラー文が出ました。

```
file "/usr/local/cellar/python@3.9/3.9.5/frameworks/python.framework/versions/3.9/lib/python3.9/runpy.py", 
line 188, in _run_module_as_main mod_name, mod_spec, code = _get_module_details(mod_name, _error) file 
"/usr/local/cellar/python@3.9/3.9.5/frameworks/python.framework/versions/3.9/lib/python3.9/runpy.py",
 line 147, in _get_module_details return _get_module_details(pkg_main_name, error) file 
"/usr/local/cellar/python@3.9/3.9.5/frameworks/python.framework/versions/3.9/lib/python3.9/runpy.py", line 111, in _get_module_details __import__(pkg_name) file 
"/usr/local/cellar/python@3.9/3.9.5/frameworks/python.framework/versions/3.9/lib/python3.9/tkinter/__init__.py", line 37,
 in <module> import _tkinter 
# if this fails your python may not be configured for tk modulenotfounderror:
 no module named '_tkinter' mac
```

エラーを省略すると...`ModuleNotFoundError: No module named '_tkinter' mac`
とりあえず、macはデフォルトではtkinterを使えないようです。
macでtkinterを使えるようにする方法を下記にまとめます。

###環境
・macOS Catalina
・Homebrewはインストール済み
・pyenvを使用している
・Python3.9.6
・zsh使用

###参考記事
[Macのpyenv環境下でtkinterを使えるようにする方法
](https://qiita.com/saki-engineering/items/92b7ec12ed07338929a3)[pyenvでインストールしたpythonでtkinterがimportできなかった時。
](https://qiita.com/zabu/items/f1b0a58c8dfa810526dc)[【もう迷わない!? mac編】Pyenv環境からTkinterをインストール](https://kuroro.blog/python/zTeIS7KyJGQv87n1kue5/)

#解決手順
基本的には上記の参考記事と同じことをしていきます。
そのため詳しくはリンクをご覧ください。

###Pythonのアンインストール
```
% pyenv global system
% pyenv uninstall 3.X.X
```

↑で、`pyenv global system`ができない場合は`rm ~/.python-version`コマンドを実行する。

###tcl-tkのインストール

```
% brew install tcl-tk
% brew info tcl-tk
```

↑上記コマンドで表示されたコードをコピーして`.zshrc`に貼り付けします。

```
% vi .zshrc
```

```zsh:.zshrc
export PATH="/usr/local/opt/tcl-tk/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/tcl-tk/lib"
export CPPFLAGS="-I/usr/local/opt/tcl-tk/include"
export PKG_CONFIG_PATH="/usr/local/opt/tcl-tk/lib/pkgconfig"
```

###Pythonの再インストール

```
% PYTHON_CONFIGURE_OPTS="--with-tcltk-includes='-I/usr/local/opt/tcl-tk/include' --with-tcltk-libs='-L/usr/local/opt/tcl-tk/lib -ltcl8.6 -ltk8.6'" pyenv install 3.X.X
```

上記参考記事通りにここまで進めて、順調♪と思いきや...

```
% python -m tkinter
```

でインストールができているか確認したところ、最初に記載したエラーがまた出ました...
↑ここまでで解決した人はいいのですが、解決しなかった場合について記載していきます。

#再解決手順
上記解決手順の`Pythonのアンインストール`を実行します。

次に下記コマンドを実行します。

```
% brew install python-tk@3.9
% python -c 'import tkinter;print(tkinter.TkVersion);'
```

最後に、上記の`Pythonの再インストール`を行いましょう。
これで`python -m tkinter`を実行するとtkinterが開けました🎉

参考記事
[MacOS BigSurはpython3tkinterを使用してエラーを報告します](https://blog.csdn.net/sjwbcb/article/details/116790775)
[Why my Python installed via home brew not include Tkinter
](https://stackoverflow.com/questions/36760839/why-my-python-installed-via-home-brew-not-include-tkinter)

#最後に
なぜ`python-tk@3.9`をインストールしないと動かなかったのかはよくわかりませんでした。
ご存知の方いましたら教えていただけますと幸いです。
Swift パターンマッチ

通常Switch文で使用されると思われるパターンマッチだが```if```や```guard```文```while```にも使用される

if
---

```swift
 let age = 8
 if case 1...12 = age {
 print("小学生です")
}
```
switch文では条件をすべて網羅しつつ、できないものはdefaultで拾う書き方をするがif文では網羅する必要がない際に使われる。

guard
--

```swift
 let age = 23
 guard case 1...20 = age else {
   return 
 } 
print("二十歳以下です")
}
```

while
---
パターンに合うまではその処理を繰り返し回す。

```swift
 var nextAge = Optional(1)
 while case let age? = nextAge {
 if age >= 20 {
   nextAge = nil
  } else {
   nextAge += 1
 }
}
```
[Rails] 自作のアクションのルーティング設定（memberとcollection）

##はじめに
検索機能の実装過程で新しい気づきがあったので記事に残しておきます。
よろしくお願いします。

##自作のアクション

ここではRailsの7つのアクションとされるもの以外に、自分で作ったアクションのことを「自作のアクション」と呼んでいます。

今回検索機能を実装するにあたって、新たにコントローラーに「search」アクションというものを作成しました。

```ruby
  def search
    @tweets = Tweet.search(params[:keyword])
  end
```

コントローラーの中にこんな感じで記述しました。
モデルの方でこの中で使われているsearchメソッドは定義されていますが、今回は特に説明はしません。

##memberとcollection

memberとcollectionはルーティングを設定するときに使用できる、URLや実行されるコントローラーを任意にカスタムできるものです。

例えばmemberを使ってルーティングを設定すると下記のようになります。

```ruby
Rails.application.routes.draw do
  resources :tweets do
    member do
      get 'search'
    end
  end
end
```

rails routesすると↓

```terminal
Prefix           Verb    URI                                 Pattern
search_tweet      GET    /tweets/:id/search(.:format)       tweets#search
```

collectionを使用すると下記のようになります。

```ruby
Rails.application.routes.draw do
  resources :tweets do
    collection do
      get 'search'
    end
  end
end
```

rails routesでルーティング確認すると↓

```terminal
Prefix           Verb    URI                                 Pattern
search_tweets    GET    /tweets/search(.:format)              tweets#search
```

この二つの違いは、URLの指定先に:idが含まれているか否かになります。
memberは:idあり。
collectionは:idなし。


##終わりに
実装途中にこれ大事だ！と思い取り急ぎ記事にしました。
実際に実装した検索機能の手順は追って記事にしたいと思います。
【新卒研修】初めて新規開発をして学んだこと

#はじめに
こんにちは。
4月に新卒でイーリバースドットコムに入社した高倉です。
この記事は、私が３ヶ月の研修期間を経て感じたことをアウトプットする目的で書いております。

##研修前のレベル感
私の大学での専攻は機械工学で、授業では軽くプログラミングに触れる程度。
授業以外で個人的に興味をもってプログラミングを勉強し始めたのは大学3年生の秋くらいでした。
YouTubeのチュートリアル動画やUdemyの講座を観ながら、実際にコードを書いて学習をしていました。

入社前に触ったことがあった技術は、以下の通りです。
言語：JavaScript, Ruby, Python, Go, C#, HTML, CSS
ライブラリ・フレームワーク：React, Ruby on Rails
その他：SQL, git, Docker, AWS
##業務内容
新規の業務系バッチ処理機能開発における、以下の工程を行いました。

- 詳細設計
- 機能実装
- テスト（単体、結合）

##使用技術

- C#, .Net Core 3.1
- MySQL 5.6
- AWS(AWS Batch, Amazon Aurora, DynamoDB)

#先輩からの技術的な学び
##パフォーマンスを意識する
Linqでクエリを投げる箇所の実装で、クエリ発行回数を減らすように以下のようにレビューを受けました。
**修正前**

```C#
foreach (data in datas)
{
    var query = _sampleDbContext.SampleDb.Add{new SampleType
        // 省略
    }
    query.Context.SaveChanges() //ここでクエリが発行される
}
```

**修正後**

```C#
var i = 0;
foreach (data in datas)
{
    var query = _sampleDbContext.SampleDb.Add{new SampleType
        // 省略
    }   
    if (i % 100 == 0)
    {
        query.Context.SaveChanges() //データ量が膨大な場合の対処
    }
    i++;
}
query.Context.SaveChanges() //データ量が膨大な場合の対処
```
それほど多くないデータ量であれば修正前でも問題ないのですが、今回扱うのはかなりの量のデータだったので修正が必要でした。
個人で勉強用に開発をしていたときは動かすことしか考えておらず、このような細かいパフォーマンスの面まで考えることはありませんでした。
しかしこれからは扱うデータ量が膨大なため、余計な負荷をかけない実装を心がけたいと思いました。
##常にテストのことを考えて実装する
DBのカラムに日付を挿入する処理で、SystemのDateTimeを使用していたところ、外部クラスにDateTimeを返すメソッドとして定義し、それを使うようにレビューを受けました。
**修正前**

```C#
var query = _sampleDbContext.SampleDb.Add{new SampleType
    date = System.DateTime.Now()
}
```
**修正後**

```C#
using SystemDate; //外部に定義した自作クラス

var query = _sampleDbContext.SampleDb.Add{new sampleType
    date = SystemDate.GetSystemDate() //DateTime.Now()を返すだけのメソッド
}
```
「正しい日時がDBにインサートされること」のテストを書く際に、修正前だとテスト実行の度にDateTime.Now()は異なる日時を返すのでテストが書けません。
修正後のコードであれば、GetSystemDate()をモック化して指定した日付を返す仕様にできるので、テストが書けるようになります。

恥ずかしながら、テストコードは就職して初めて書きました。
実装時からテストのことも考えていないと後で困るということを学んだので、次に活かしたいと思います。

##使う人のことを考えてログメッセージを作る
**修正前**

```C#
_logger.LogError("APIからの距離データ取得に失敗しました。")
```
**修正後**

```C#
_logger.LogError("APIからの距離データ取得に失敗しました。、データNo={0}、始点住所={1}、終点住所={2}",
    dataNo, originAddress, distinationAddress);
```
修正前だとエラーは発見できてもどのデータで発生したのかわかりません。
ログの出し方に正解はありませんが、理想は**そのメッセージを読んだ人が誰であっても、適切な対処を取れること**だと思いました。
#全体的な研修の感想
##入社前に不安になる必要はなかった
新卒一期生かつエンジニアの新卒は私だけだったこともあり、研修や業務についていけるか不安でした。
そのため、入社前に会社で使っている技術を中心にぼちぼち勉強をしていました。
（コロナで卒業旅行などに行けなかったので、時間だけはありました（笑））

しかし、そこまで心配する必要はなかったなと思います。
どれだけ勉強していっても、結局先輩に聞きまくってググり倒していくことになるので安心してください（笑）。
むしろそれが当たり前で、**入社してから質問する力を鍛えていく方が重要**だと学びました。

とはいえ、会社で使っている技術の基礎だけでも抑えておくと、入社後に圧倒的に楽なのは間違いありません。
もし時間があれば、基礎だけでもやっておくことをオススメします。
##実務的な研修のデメリット
私が行ったような実務的な研修は、体系立った学習をするだけの研修よりも実践的なスキルが身に付くというメリットがあると感じました。
対してデメリットは、先輩社員のサポートがあるとはいえ難易度の高いタスクが渡される時があることです。

初めのうちは「それが自分にできることなのか」という判断は難しいため**「良く分からない所」や「製品の質に直結する」という実装などは、迷わず先輩に聞くことが大事**だと思いました。
私の場合は、周囲の先輩のフォロー＆レビューなどもあり、大きなミスは起こりませんでした。

##毎日の充実感
研修といえど、自分が書くコードはお客様が将来実際に使う製品です。
それがなによりのモチベーションになりましたし、エンジニアとして働けているんだという充実感に大きく繋がりました。
学生のときのように自分で勉強するだけの日々では、絶対に味わえなかった感覚です。

#最後に
この記事が、新卒もしくは転職でエンジニアを目指している方の参考に少しでもなりましたら幸いです。
RSpecでauthenticate_userを突破する


##前提
・以下にアクセスできるかテストしたい
・アクセス先でcurrent_userを用いた処理をしているため、サインインした状態でいたい

```
hotel GET    /hotels/:id(.:format)     hotels#show
```


##やっていこう

```ruby
#spec/rails_helper.rb
RSpec.configure do |config|
  # テスト時にdeviseのヘルパーを呼び出すことができる => sign_inが使えるになる
  config.include Devise::Test::IntegrationHelpers
  # gemのベースであるwardenのプロキシサーバーのエラーが起こるための対処法
  config.include Devise::Test::ControllerHelpers
end
```

```ruby
#spec/controllers/hotels_controller_spec.rb
require 'rails_helper'

RSpec.describe HotelsController, type: :controller do

  describe "GET #show" do
    before do
      @user = FactoryBot.create(:user)
    end

    it "returns http success" do
      # 先ほどdeviseのヘルパーを呼び出せるようにしたため使える
      sign_in @user
      # get :show, id: @user.id だとidを渡せなかった
      get :show, params: { id: @user.id }
      expect(response).to have_http_status(:success)
    end
  end

end

```



## 参考記事
[Rails RSpec コントローラーテストでログイン状態にする](https://qiita.com/kaichi_lvg/items/ca538e196fe1d2c31784)
[【Rspec】Devise::MissingWardenエラーの解決策](https://qiita.com/chiaki-kjwr/items/b9d5d4b6d12a0ac05ac9)
[Rails5の勉強: unknown keyword: idについて](https://qiita.com/Floym/items/254c1a8afe87d09fd32e)
【AtCoder】ABC212をPython3で解説（ABCD）


ABC212の解説。

https://atcoder.jp/contests/abc212

## A - Alloy
### 解説

```Gold, Silver, Alloy```を問題文のとおりに条件分岐してあげるとAC。

### コード
```python
a, b = map(int, input().split())

if 0 < a and b == 0:
    print('Gold')
elif a == 0 and 0 < b:
    print('Silver')
elif 0 < a and 0 < b:
    print('Alloy')
```

## B - Weak Password
### 解説

暗証番号の強さについて求める問題。

弱い暗証番号というのは、

(1)同じ数が4つ続いているもの
(2)```0-9```の数字が各桁で1ずつ増えているもの

である。

(1)については、```s.count(s[0])```で文字列のはじめの数字について、文字列sの文字を数え、```4```であれば、すべて同じ数なので、```Weak```。

(2)については、数字の折返しを含めて、```temp```を```'0123456789012'```と指定する。この中に```s```があれば、各桁で1ずつ増えるものなっているので、```Weak```。

それ以外のものについては、```Strong```を出力する。

### コード

```python
s = input()
temp = '0123456789012'

if s.count(s[0]) == 4:
    print('Weak')
elif s in temp:
    print('Weak')
else:
    print('Strong')
```

## C - Min Difference
### 解説

数列```A```、数列```B```の中から、差の最小値を持つものを出力する問題。

単純に2重ループをして解けるように見えるが、```N```、```M```の最大値が$2 \times 10^5$をとっているので、計算量が$O(NM)$となってしまい、実行時間が間に合わない。では、どうすればいいか。

これを実装するために、**数直線**を用いる。

数直線上に表すには、数字を並び替えてあげる必要があるので、先にソートしておく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/716184/c49d1fdc-1781-7b76-069e-b609ab952ffe.png)


まず、A、Bのそれぞれの値をみて、値の絶対値の差を取る。

次に、今見た数値で小さい方をもつ数列から、次の値を参照する。同様に値の絶対値の差をとっていく。こうすることで、最終的に値の大きいものに値の小さいものができるだけ近づいて、絶対値の差を求めることができるので、最小値を求めることができる。


### コード
```python
n, m = map(int, input().split())
alist = list(map(int, input().split()))
blist = list(map(int, input().split()))

alist.sort() # 数列Aをソート
blist.sort() # 数列Bをソート
result = 10**9+7 # 比較する値の設定

a = 0
b = 0

while a < n and b < m: # AとBの値がすべて取れるような条件の指定
    if abs(alist[a]-blist[b]) < result: # 結果より絶対値の差が小さければ
        result = abs(alist[a]-blist[b]) # 値を更新

    if alist[a] < blist[b]: # 値の小さい方をもつ数列の値を1つずらす
        a += 1
    else:
        b += 1

print(result)
```

## D - Querying Multiset
### 解説

ボールと袋の条件分岐問題。制約上、そのまま実装することはできない。したがって、今回はheapというものを使用する。

heapについては以下の記事をご覧いただきたい。

https://qiita.com/uniTM/items/9630ed9d51f62b3e35ab

コードの関係上、操作2から説明する。

操作2は、袋に入っているすべてのボールについて、そこに書かれている数を足し合わせるというもの。しかし、これをいちいちすべてのボールについて、足し合わせていると、膨大な計算量になる。したがって、操作3でボールを取り出す際に、今まで操作2で足し合わせたものを足せば良い。

操作3は、袋に入っている最小値のかかれたボールを取り出すというもの。これは、```heapq.heappop()```で難なく最小値をとりだすことができる。通常の```pop```であれば、計算量は$O(N)$だが、```heappop```は、$O(logN)$なので、十分少ない。取り出す際に、操作2で足し合わせた数値を足してあげることで正しい答えが出力できる。

操作1は、袋にボールを入れてあげる作業だ。これは、```heapq.heappush()```で実装できるが、ひとつ注意点がある。それは、ボール入れるときに操作2で足した値を引いてあげることである。操作1で値を入れるとき、もともと入っているボールにかかれている数値は操作2で足した値分、大きくなっている。つまり、その分引いてあげることで帳尻を合わせることができる。


### コード
```python
import heapq

q = int(input())
sack = []
heapq.heapify(sack)
total = 0

for i in range(q):
    query = list(map(int, input().split()))
    if query[0] == 1:
        heapq.heappush(sack, query[1]-total)
    elif query[0] == 2:
        total += query[1]
    else:
        ans = heapq.heappop(sack)
        print(ans+total)
```

## 編集後記

ABCDまで解説すると、時間がかかる.
けど、勉強になる.
Rails 6 Herokuデプロイ時のエラー(Precompiling assets failed.)

Herokuデプロイ中に起きたエラー


```sh
methods since the "loose" mode option was set to "true" for @babel/plugin-proposal-class-properties.
       The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding
       	["@babel/plugin-proposal-private-methods", { "loose": true }]
       to the "plugins" section of your Babel config.
       Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-methods since the "loose" mode option was set to "true" for @babel/plugin-proposal-class-properties.
       The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding
       	["@babel/plugin-proposal-private-methods", { "loose": true }]
       to the "plugins" section of your Babel config.
       Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-methods since the "loose" mode option was set to "true" for @babel/plugin-proposal-class-properties.
       The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding
       	["@babel/plugin-proposal-private-methods", { "loose": true }]
       to the "plugins" section of your Babel config.
       
 !
 !     Precompiling assets failed.
 !
 !     Push rejected, failed to compile Ruby app.
 !     Push failed
```

***[Precompiling assets failed.]***

[参考記事](https://stackoverflow.com/questions/66163589/rails-6-failing-to-deploy-to-heroku-modulenotfounderror-module-not-found-erro)

Rails6系を使用している時に、
herokuへのアプリケーションデプロイでPrecompile assets failedになることがあるっぽい
よくみてみると使用している
Bootstrapのバージョンが5系の時は
```
$ yarn add popperjs/core
```
を実行してから
再度デプロイをすることで、問題なくcompileができるようになるっぽい。

ちなみに使用しているBootstrapが4系の時は
```
$ yarn add popper.js
```
を実行すれば問題ないかも。
TerraformでVPCエンドポイントを一気に作る

## はじめに
- Terraformの勉強記録です

- 本稿ではVPCエンドポイントを一気に作ります
- 今回は例としてSSMへのアクセスに用いる3つのVPCエンドポイントを作成します
- 誤りの訂正・より良い方法のご助言、どしどしコメント頂ければ幸いです


### Terraform 実行環境
- AWS Cloud9
    - Amazon Linux2
    - t2.micro
- Cloud9を使う理由
    - 標準でTerraformが備わっているため

### アウトライン
1. 変数の定義
1. VPC・サブネット・セキュリティグループの作成
1. VPCエンドポイントの一括作成

###　1. 変数の定義
- `vpc_endpoints`で**作成したいVPCエンドポイント名を要素にもつリスト**を定義しています

```go:variable.tf
locals {
  name = "terraform"
  region   = "ap-northeast-1"
}

# VPC
variable "vpc_cidr" {
  type    = string
  default = "10.1.0.0/16"
}

# Subnet
variable "subnets" {
  type = map(any)
  default = {
    private_subnets = {
      private-1a = {
        name = "private-1a",
        cidr = "10.1.10.0/24",
        az   = "ap-northeast-1a"
      },
      private-1c = {
        name = "private-1c",
        cidr = "10.1.11.0/24",
        az   = "ap-northeast-1c"
      },
      private-1d = {
        name = "private-1d",
        cidr = "10.1.12.0/24",
        az   = "ap-northeast-1d"
      },
    },
  }
}

# VPC Endpoint
variable "vpc_endpoints" {
  type    = list(any)
  default = ["ssm", "ssmmessages", "ec2messages"]
}
```

###　2. VPC・サブネット・セキュリティグループの作成

- VPC

```go:vpc.tf
resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  instance_tenancy     = "default"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "${local.name}-vpc"
  }
}
```


- サブネット

```go:subnet.tf
resource "aws_subnet" "private" {
  for_each = var.subnets.private_subnets

  vpc_id = aws_vpc.main.id

  cidr_block        = each.value.cidr
  availability_zone = each.value.az

  tags = {
    Name = "${local.name}-${each.value.name}"
  }
}
```

- セキュリティグループ

```go:security_group.tf
resource "aws_security_group" "vpc_endpoint" {
  name        = "vpc_endpoint-sg"
  description = "vpc_endpoint-sg"
  vpc_id      = aws_vpc.main.id

  ingress {
    description = "HTTPS from VPC"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "${local.name}-vpc_endpoint-sg"
  }
}
```

###　3. VPCエンドポイントの一括作成
- `var.vpc_endpoints`の要素をfor_eachで回す

```go:vpc_endpoints.tf
resource "aws_vpc_endpoint" "interface" {
  for_each = toset(var.vpc_endpoints)

  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.${local.region}.${each.value}"
  vpc_endpoint_type   = "Interface"
  private_dns_enabled = true

  # privateサブネットのidをfor式で一括取得
  subnet_ids = [for sn in aws_subnet.private : sn.id]
  security_group_ids = [
    aws_security_group.vpc_endpoint.id,
  ]
  depends_on = [
    aws_vpc.main, aws_subnet.private
  ]
  tags = {
    Name = "${local.name}-${each.value}-endpoint"
  }
}
```

- 完成

## おわりに
- 無事にスッキリしたコードでTerraformでVPCエンドポイントを一気に作ることができました
- ネタがあればまた記事を書こうと思います
パイロットライトは『種火』

災害対策（DR）計画の中で、用語からイメージしにくい **『パイロットライト』** について調べました。

# 1.パイロットライトは『種火』

oracle先生のサイトでイメージしやすい言葉を見つけました。
[パイロット・ライトのディザスタ・リカバリ(DR)トポロジの設計](https://docs.oracle.com/ja/solutions/oci-pilot-light-dr/index.html#GUID-05921C82-52AB-40DE-BC48-92B8F11EEDFF)
>パイロットライトという用語は、ガス駆動ヒーターなどのデバイスで常に点灯し、必要に応じて素早くデバイスを起動できる小さな炎を指します。

いつでも火がおこせるよう消さずに残しておく小さな火、『種火』のイメージでよさそうです。

具体的に言うと、DRリージョンに低スペックのDBを起動してシステムの最も重要なコアデータをレプリケーションしておき、復旧時はこのDBをスケールアップして完全な本番環境をすばやくプロビジョニングするという災害対策方法です。
種火から火を起こすようなイメージですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/862e8a87-8817-b7ff-5632-97899e19003e.png)



# 2.4つの災害対策(DR)

AWS Well-Architected フレームワークの信頼性の柱にて4つうたわれている災害対策 (DR) のうち、パイロットライトの位置づけは左から2番目にあたります。図は[(AWS公式docs)災害対策 (DR) を計画する](https://docs.aws.amazon.com/ja_jp/wellarchitected/latest/reliability-pillar/plan-for-disaster-recovery-dr.html)の引用です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/e2f58f53-7780-9a6a-9903-750156add88f.png)

4つの災害対策(DR)について以下の表にまとめます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/cf9952c3-6474-c61e-b726-702c189a2acd.png)

例えば「RDSと、その他のリソースを展開するためのCFnテンプレートが準備されている」のであれば、このDR対策はパイロットライトだなと予測がつきます。

「バックアップ＆リストア」を選択すれば、コストは下がりますが復旧までに時間がかかります。
「Active-Active」を選択すれば、復旧までの時間は最短で済みますがコストがかかります。
稼働しているシステムの要件によってコストバランスを考えた災害対策が必要になります。

# 3.低コストの災害対策を選択する場合
すべての災害対策に当てはまりますが、実際に災害が発生した場合の復旧手順や訓練計画まで実施する必要があります。運用部隊への引き継ぎは手順書の連携だけでなく、実際に手を動かして手順を確認し、いざというときに慌てないよう準備しておくのが最も重要と考えています。


# 4.参考
[(AWS公式Well-Architectedフレームワーク)災害対策 (DR) はどのように計画するのですか?](https://wa.aws.amazon.com/wellarchitected/2020-07-02T19-33-23/wat.question.REL_13.ja.html)
在宅ワーク中の人に「電話してもいいかな？」という気をつかわずに済むLINEBotを作ってみました！

#電話はPCの前にいる時だけにして欲しい
今回は在宅ワークで使えそうなツールを制作しました。
在宅ワーク中の相手に電話して良いかどうか、気を使うことがあります。自宅は職場と違い、公私の区別がつきにくいから電話はせめて在宅ワーク中（ＰＣ操作）の時だけにして欲しいとの思いからでたアイデアです！

#WebアプリでPC前の状況をAI画像判断
PCのインカメラで得た映像をAI画像判断しています。

https://twitter.com/Tanaka_LV5/status/1424407459259506706


ポイントはNord-RED側に送っているのはテキスト情報のみです。映像を送ったり、監視カメラで見張られている訳ではありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/54f0008d-9dcd-4987-4bee-f01d427a4e92.png)



#使用ツールとNode-RED全体フローの紹介
**使用したツール**
[CodePen](https://codepen.io/ta4711/pen/WNjYeoL?editors=1111)
[TeachableMachine](https://teachablemachine.withgoogle.com/train)
[Node-RED](https://elements.heroku.com/buttons/joeartsea/node-red-heroku)
[LINE for Business](https://www.linebiz.com/jp/)

CodePenは作成したツールURLにリンクします。JSコードの36行目にあるサーバアドレスを書き換えてご使用下さい。

**Node-REDの全体フロー図**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/5b50eb0c-ef7f-11a7-b352-df911ed3048d.png)
CodePenからデータを取得するフローとLINEBotからのメッセージを応答するフローの2つで構成されています。

#取得した情報の活かし方が分からない？
今回、一番苦労したのはCodePenから取得した情報をLINEBotにどう反映させるかでした。フローの流れの中で情報を取得する方法（”http request”ノード）はわかるのですが、、、。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/9110714d-8640-8f40-e6cd-3cf6367ad6f0.png)
CodePenからの情報は”http in”ノードを使って取得しています。これまでに習ったフローでこれをどう使ったらよいのやら。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/6bfbaa7a-caa8-cde9-4dad-caeae9de1ee3.png)
#”file"を活用する
”file in”ノードと"file"ノードの２つが解決してくれました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/9e1624ed-2f20-dbbe-b562-8f628abbcf32.png)

異なるフローからの情報を受け渡してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/edcbcec8-619e-852a-3485-cf135fdc9bcc.png)
**”file in”ノード側の設定**
CodePenから得たテキストデータをファイルに上書きします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/12a69760-5300-f22b-ef1d-884b50593e8a.png)
**”file”ノード側の設定**
CodePenから得たテキストデータをLINEBotで取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/e8e73aa6-fcf3-7aa5-3c03-067b7744db79.png)

#取得した情報を応答メッセージを送ります
CodePenから取得した情報を“switch”ノードで仕分けして返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/57868099-1ad6-6af1-b14b-392fc0b8513d.png)
PCの前で作業している時は”対応可能”として電話番号情報を追加したメッセージを送ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/d8d5cd53-edd9-9b9a-c03d-8f8e7efac667.png)
離席中や電話中の場合は状況をメッセージで送ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/032a5985-6426-8b5c-4681-76b568732aba.png)
#今後の構想）予定情報送信機能も追加します！
Googleのスプレットシートを使って予定情報を送るフローを組み込めばより使えるLINEBotになると考えています。

https://twitter.com/i/status/1424067789115912197

このアイデアを活用↓

https://qiita.com/aya2648/items/86c4476f697cdd2f9c78

在宅ワークが快適になる様に今後も研究を続けていきます。
最後まで読んで頂き、誠にありがとうございます。
コピペで乗り切るエンジニアがSwiftUIを勉強してみた（ファイル構成について）

さて、前回SwiftUIの実行環境を用意しました。
SwiftUIのファイル構成と軽くソースの解析を
「Hello world」を使って確認していきます。
（前回：[コピペで乗り切るエンジニアがSwiftUIを勉強してみた（環境構築編）](https://qiita.com/antk/items/4bd97f0baa770ecef870)）

## ファイル構成について
プロジェクトをつくった際にデフォルトでたくさんファイル作成される。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1009893/9d8a06bd-77dd-3765-2e87-56c129223b67.png" width="200px">

* TestHelloWorld
 * TestHelloWorldApp.swift  
作成するアプリケーションのエントリポイント。  
@mainと記述された箇所が該当。

 * ContentView.swift  
作成するアプリケーションのビューの役割。  
画面に表示するボタンや文字を配置する。
 * Assets.xcassets  
アプリで使用する画像を格納するフォルダ。  
表示したいファイルはここに追加する。
 * info.plist  
アプリ内の共通設定。  
アイコンやバージョンの設定や権限まわりの設定を設定する。
 * Preview Content
     * Preview Assets.xcassets

* TestHelloWorldTests
XCTestフレームワークを使ったユニットテストを実装するためのもの。
使い方はまだ分からないので一旦スルーで。
 * TestHelloWorldTests.swift
 * Info.plist
* TestHelloWorldUITests
XCTestフレームワークを使ったUIテストを記載します。
こちらも使い方はまだ分からないのでスルーで。
 * TestHelloWorldUITests.swift
 * Info.plist
* Products
各種ビルド後のアプリケーション本体。
 * TestHelloWorld.app
 * TestHelloWorldTests.xctest
 * TestHelloWorldUITests.xctest


## 実行までの流れ

### 初期起動（エントリーポイント）
さて、上記のフォルダ構成で記載した通り、
SwiftUIでは初期起動（エントリーポイント）は
「@main」で指定されるとのこと。
なので、「このプログラムはどこから始まるのかな？」となったら
まずは「@main」を探すと良いかと思います。

```swift
import SwiftUI

@main
struct TestMusicLibraryForSwiftUIApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```

エントリポイントであるTestMusicLibraryForSwiftUIApp から呼び出された
ContentView も上記フォルダ構成で記載した通り、
画面レイアウトを記述していきます。
下記に記載の通り、Text("Hello, world!").padding()
で画面上に「Hello, world!」という文言を表示させます。
また、ContentView_Previews側はプレビュー表示の際に使用されます。

```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```

以上！ひとまずこのくらいで！