OmniAICreator/Qiita-1.07M huggingface dataset:
switch文

# switch文
if文以外の条件分岐の方法として、switch文があります。switch文は「`ある値によって処理を分岐する`」場合に用いることができます。
記述は「`switch(条件の値){処理}`」のように記述します。

```js:例
const rank= 1;

switch(rank){
  case 1:   //caseの末尾は:(コロン)を用います
    console.log('金メダルです');
    break;
  case 2:
    console.log('銀メダルです');
    break;
}
```
```text:出力結果
金メダルです
```
上記のように記述することで、出力結果を得ることができました。
switch文の中に**`case`**を追加することで処理を分けることができます。
上記のように定数`rank`の値が`1`の時、「金メダルです」が出力されるようになっています。
また、**`break`**も非常に重要であり、switch文を終了する命令を出す役割があります。
`break`が無いと、合致したcaseの処理を行った後、その後のcaseの処理も実行されてしまいます。
仮に上記の「case 1:」の処理後に「break;」 がなかった場合、その後のcaseの処理である「銀メダルです」も実行されてしまいます。
よって、`break`を忘れず記述する必要があります。

## default
switchの条件の値がcaseのどれにも一致しなかった時、**`default`**のブロックが実行されます。
イメージとしては、if文のelseと似ているのではと考えています。


```js:例
const rank= 4;

switch(rank){
  case 1:   //caseの末尾は:(コロン)を用います
    console.log('金メダルです');
    break;
  case 2:
    console.log('銀メダルです');
    break;
  case 3:
    console.log('銅メダルです');
    break;
  default:
    console.log('メダルはありません');
    break;
}
```
```text:出力結果
メダルはありません
```
上記のように記述することで、定数`rank`の値がどのcaseの値にも一致しなかったので、
`default`の処理が実行されました。

仮に上記をif文で記述した場合、

```js:if文
const rank = 4;

if(rank == 1){
  console.log('金メダルです');
} else if(rank == 2){
  console.log('銀メダルです');
} else if(rank == 3){
  console.log('銅メダルです');
} else {
  console.log('メダルはありません');
}
```
```text:出力結果
メダルはありません
```
上記のように記述することになります。
分岐が多く複雑な場合、switch文で書き換えるとシンプルで読みやすいコードにできます。
FirestoreからJSON状態でのエクスポートとインポート手順

Firestoreに格納済みデータをテキストデータで一括コンバートするために使用

## npmのインストール

- 下記の手順に従ってインストール
https://www.npmjs.com/package/firestore-export-import

## Firebase admin 秘密鍵を取得
- FirebaseのFirebase Admin SDKから秘密鍵jsonの取得

## Firestoreのjson形式での export と import

- Firestoreからエクスポート
`firestore-export -a ./adminkey.json -b ./backup.json -p`

- Firestoreへインポート
`firestore-import -a ./adminkey.json -b ./import.json`
Angularでカメラ撮影してみる

前回の続きになります。
https://qiita.com/NoOne/items/42918d1f4f4e3fe59329
<hr>
まずはテンプレート。今回は撮影ボタンと撮影した画像を表示するcanvasを用意します。

```app.component.html
<div class="container">
    <video autoplay class="video"></video>
    <button id="capture" class="btn btn-success cap-btn" (click)="captureImg()">撮影</button>
    <canvas id="canvas" class="canvas"></canvas>
</div>

```
<hr>
続きましてts。ボタンイベントハンドラを追加しました。

```app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent  { 
  private video: any;

  //撮影フォーム設定
  ngOnInit(): void {
    this.video = document.querySelector('video')!;

    const options = {
      video: true
    }
    navigator.mediaDevices.getUserMedia(options)
    .then(stream => {
      this.video.srcObject = stream;
    })
    .catch((error) =>{
      console.log(error);
    })
  }

  //撮影ボタン押下時の処理
  captureImg(){
    let canvas = document.getElementById('canvas') as HTMLCanvasElement;
    const context = canvas.getContext('2d');
    context?.drawImage(this.video, 0, 0, canvas.width, canvas.height);
  }
  
}


```
<hr>
CSSも記述します。最低限携帯でも撮影できることを想定したつくりにしております(本当に最低限です)。

```app.component.css
.video {
    border:12px solid #222;
    background: grey;
    height:70%;
    width: 70%;
}

.cap-btn {
    height: 70%;
    width: 70%;
    font-weight: bold;
    font-size: 56px;
}

.canvas {
    border:12px solid #222;
    background: grey;
    height:70%;
    width: 70%;
}

```
<hr>
bootstrapも入れてます。

```
npm install bootstrap@next
```

```index.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularDetectFace</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
</head>
<body>
  <app-root></app-root>
</body>
</html>
```

<hr>
下記はライブデモです。(stackblitの仕様上？PCからの起動のみ)
https://stackblitz.com/edit/angular-ivy-bh4pfe?file=src%2Fapp%2Fapp.component.ts
<hr>
何故かブラウザ(stackblitz内)再起動が必要なのでお試しの際はお手数ですが再起動してください。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/ae90b239-61f2-2a58-0768-05d269698716.png)
公開鍵1つに対して、実行可能コマンドを1つだけ紐付ける

# scpコマンドをcronjobで定時実行させる
※「シス環系女子 season2 第3話」の備忘録です。

公開鍵1つに実行可能なコマンド列1つだけ設定しておけば、万が一秘密鍵が流出しても実行できるコマンドは設定したコマンド1つだけなので安心できる。

そのやり方の記事。

以下記事よりssh接続可能なコンテナ2つを前もって準備しておくこと。
https://qiita.com/neo_fukafukafukka/items/34ece05e14547d847450

## crontabによる自動scpが失敗するケース

以下のscpコマンドを、手動で実行するだけなら成功する。

```
# scp -P 2222 root@172.17.0.2:/root/master_file.txt ./
master_file.txt                                   100%   15     2.3KB/s   00:00
```

※便宜上、上記コマンドを以下のようにシェルスクリプトにまとめておく。

```
#!/bin/bash
scp -P 2222 root@172.17.0.2:/root/master_file.txt ./
```

以下のようなソースで定時に自動でscp実行させようとすると失敗するケースがある。

```
// ※crontabs入れてなかったので入れる。
# yum -y install crontabs

# crontab -l
MAILTO=""
*/2 * * * * /bin/bash get_master_file.sh

// cronを起動する
# systemctl start crond

// 秘密鍵にパスフレーズがある場合は、いつまで経ってもmasterコンテナのファイル(master_file.txt)が取得できない。（crontabが失敗してる。）
```

- 対策

秘密鍵にパスフレーズを入力せず、公開鍵にコマンド列1つを関連づける。
※コマンド列は1つしか関連付けられない。


## 公開鍵にコマンド列1つを関連づける

slaveコンテナ内で公開鍵を新しく生成・コピーする。

```
# mkdir .ssh/for_get_master_file

# cd .ssh/for_get_master_file/

# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /root/.ssh/for_get_master_file/id_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/for_get_master_file/id_rsa.
Your public key has been saved in /root/.ssh/for_get_master_file/id_rsa.pub.
The key fingerprint is:
// 省略

# vi id_rsa.pub
// 公開鍵をコピー
```

上記でコピーした公開鍵を、masterコンテナ内のauthorized_keysに追加する。

```
# vi authorized_keys 
// slave側の公開鍵を既存の公開鍵の下にペーストする

// 以下のように「echo hoge」だけ使えるように設定してみる。
ssh-rsa AAAAB3Nza~~~省略~~~14G06GK7 root@6b3305967d37
command="echo hoge" ssh-rsa AAAAB3Nza~~~省略~~~4BgA/iOol root@6b3305967d37
```

すると以下のようにslaveコンテナ側ではcrontabがいつまで経っても成功しない。（master_file.txtが取得できない。）

```
# ls
anaconda-ks.cfg  get_master_file.sh
```

次にslaveコンテナ側の公開鍵に対応するコマンドを以下のように修正してみる。

```
# vi authorized_keys 
// slave側の公開鍵をペーストする

// 以下のように「/bin/bash get_master_file.sh」の処理の中身(scpコマンド)を使えるように設定してみる。
ssh-rsa AAAAB3Nza~~~省略~~~14G06GK7 root@6b3305967d37
command="scp -f /root/master_file.txt" ssh-rsa AAAAB3Nza~~~省略~~~4BgA/iOol root@6b3305967d37
```

すると以下のようにslaveコンテナ内で、masterコンテナのmaster_file.txtが取得できていることが確認できる。（crontabが実行できた。）

```
# ls
anaconda-ks.cfg  get_master_file.sh  master_file.txt
```

## なぜ公開鍵へ関連付けたコマンドが「scp -f /root/.ssh/master_file.txt」なのか？

master側で実行されているscpコマンドの実態が「scp -f /root/.ssh/master_file.txt」だから。

slaveコンテナからmasterコンテナに対してscp実行した時、実はmaster側でもscpが実行されていて、それが上記のコマンド。

設定するのはあくまでサーバー側で実行されるコマンドであることに注意。（「scp -P 2222 root@172.17.0.2:/root/master_file.txt ./」を設定するのではないことに注意。）
Orbi WiFi6 APモードでイーサネットバックホール

ネットギアのWiFi6対応 メッシュWiFiルータを購入。
[AX1800 Orbi WiFi 6 Micro メッシュWiFi システム スターターキット2台セット（RBK352）](https://www.jp.netgear.com/orbi/RBK352.aspx)

APモードでバックホール通信にイーサネットを使う方式で接続。マニュアルを見ると、親機のLANポートに子機（サテライト）のLANポートを接続する必要があるように書いてあるが、APモードの場合、下記の構成でもいけた。

![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126781/30145813-eda2-c0e1-5222-75ea080ca296.png)


親機のWANポートと、子機のLANポートを上位ルータのLANポートに接続する形。最小限の配線ですんだ。

管理画面でもサテライトとの接続が5Gから有線に変わった。
![スクリーンショット 2021-05-03 17.29.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126781/69fe622c-e622-64ab-b78e-5e6dd8f8283e.png)

Orbiアプリでも親機と子機の接続を表す線が点線から実線に変わった。
![スクリーンショット 2021-05-03 17.34.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126781/58873c27-c4f7-446c-6341-3d34ea806825.png)
【PHP】IPを判別するプログラム

最近PHPを始めたカラボンです。

今回は接続しているIPを判別する方法を教えていきたいと思います。

↓コード↓

```PHP
<?php

if ($_SERVER["REMOTE_ADDR"] == 'ここにIPを入れる')
{



}
else{

	echo('表示は許可されていません');
	exit;
}
?>


```

コードの解説

```PHP

if ($_SERVER["REMOTE_ADDR"] == 'ここにIPを入れる')

```
if文でIPを判別。{}の中身は空でもよし！

```PHP

else{

	echo('表示は許可されていません');
	exit;
}

```

exit;で処理を終了する。
今から学ぶReduxの基礎（概要編）

## Reduxとは

一言で言うと、「state(状態)を管理をするためのライブラリ」となります。
しかし、これだけだと何も分からないので順を追って説明していきます。

## 状態管理とは

まず、状態管理とは何かを簡単に説明します。

例としてアプリケーションには、以下のような情報を保持する場合があります。

- ユーザーがログインしている
- チェックボックスがチェックされている
- モーダル が表示されている

これらの情報を「状態」と呼び、状態管理とはこれらの情報を管理するものです。

## Reactで状態を管理する方法とReduxを使う理由

### Reactで状態を管理する方法

Reactで状態を管理する方法として、以下のようなものがあります。

- 関数コンポーネントでReact HooksのuseStateを使用
- クラスコンポーネントを使用

useStateに関して、詳しくは以下を参照

[https://qiita.com/seira/items/f063e262b1d57d7e78b4](https://qiita.com/seira/items/f063e262b1d57d7e78b4)

これらはローカルステートと呼ばれています。

### Reduxを使う理由

では、なぜReactで状態を管理する方法があるのにReduxを使うのか。

その理由として、コンポーネントを跨いで状態を共有したいと思った時にローカルステートでは以下の方法で状態を共有する必要があります。

1. 上位のコンポーネントに必要な状態を全て持たせる
2. 上位のコンポーネントから子、孫コンポーネント必要な情報バケツリレーしていく

しかし、この方法だと以下のような問題が発生します。

- どんどんコードが複雑化していく
- 親子関係のないコンポーネント間では状態を共有することができない

これらの解決策としてReduxを使うことができます。

## Reduxで何ができるのか

Reduxを利用することで、コンポーネントの親子関係の有無に関わらず複数のコンポーネントからアクセスできるステート（グローバルステート）を作ることができます。

※ その他にも色々あるが、ここでは省略

## Reduxの登場人物とデータフロー

Reduxを理解する上で避けては通れない言葉や概念を解説していきます。

### 登場人物

- Store
    - アプリケーションの全ての状態を保持するオブジェクト

    ```jsx
    {
        value: 0,
    }
    ```

- Action
    - 「何が起きたのか」という情報を持ったオブジェクト
    - 以下の例では、deposit（入金）と入金金額を表したアクションを作成しています

    ```jsx
    {
        type: 'deposit',
    	payload: 10
    }
    ```

- Action Creater
    - Actionを作成するメソッド
    - 毎回Actionを書くのは手間であり、typo時にバグの原因にもなるため指定されたActionを返すメソッドを作成する

    ```jsx
    const deposit = (value) => {
    	return {
    		type: 'deposit',
    		payload: value
    	}
    }
    ```

- Reducer
    - stateとActionを受け取り、変更したstateを返す純粋関数（同じ引数を渡せば、毎回必ず同じ結果を返す関数）

    ```jsx
    const reducer = (state = [], action) {
      switch (action.type) {
        case 'deposit':
          return { ...state, value: action.payload };
        default:
          return state;
      }
    }
    ```

- dispatch
    - 発送（する）、派遣（する）などの意味を持つ英単語
    - ActionをStoreに送る役目を担う
    - 以下の例では、ボタンがクリックされた時にdepositというActionをStoreに送る

    ```jsx
    <button onClick={()=>{ dispatch(deposit()) }}>$10を入金</button>
    ```

## データフロー

ここまでコードと文章でまとめましたが、なかなか理解しづらいので処理の流れを図で表したものを紹介します。
![ReduxDataFlowDiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315789/fc27392a-8e3c-d820-9758-e4dcbd13bf45.gif)

（引用元：https://redux.js.org/tutorials/essentials/part-1-overview-concepts#redux-application-data-flow）

上の図はイベントによってUIに表示されている\$0という状態を\$10という状態に変更しています。

（UIと書いてある部分が普段私たちが見ている画面の表示部分です）

これをもとにstateが更新される流れを順に見ていきましょう。

1. クリック等のイベントが起きるとreducerに向けてActionをdispatch（送信）します
2. reducerは現在のstateとActionを受け取り、新しいstateを作成します
3. 最後にUIの表示変更をして終わりです

## Reduxの三原則

Reduxは公式ドキュメントで以下の3つの原則を掲げています。

- Single source of truth（信頼できる唯一の情報源）
    - Reduxでは複数の状態を一元管理させることで、デバッグのしやすさを実現しています
- State in read-only（stateは読み取り専用にする）
    - 状態を直接変更するのではなく、actionを発行します
- Changes are made with pure functions（変更はすべて純粋関数で行われる）
    - 同じ引数を渡せば、毎回必ず同じ結果を返す関数で状態の変更を行います
Next.js + Redux Toolkit でページ遷移時に Store がクリアされてしまった場合に疑うべき箇所

# 概要
Next.js と Redux Toolkit を使ってみたくて検証していたところ、
A画面→B画面に遷移した際にA画面で保存したStoreの内容がB画面で
取得できないという事象に遭遇しました。
解決してみれば超単純な修正でしたが、そこに至るまで迷走したのでメモ残します。

# 技術要素
主な技術要素は以下の通りですが、今回の記事では技術要素の説明は割愛します。

- [Next.js](https://nextjs.org/)
- [Redux](https://redux.js.org/)
- [Redux Toolkit](https://redux-toolkit.js.org/)

# ダメな例
まずはダメだったコードです。

- 補足
    - Reducer の中身はここでは割愛
    - [configureStore](https://redux-toolkit.js.org/usage/usage-with-typescript#configurestore)  は Redux Toolkit の Store を作るための便利関数

```typescript:store.ts
const createStore = () => {
  const middlewareList = [...getDefaultMiddleware(), logger];

  return configureStore({
    reducer: rootReducer,
    middleware: middlewareList,
    devTools: process.env.NODE_ENV !== 'production',
    preloadedState: preloadedState(),
  });
};

export default createStore;
```

```typescript:_app.tsx
import { Provider } from 'react-redux'
// 省略
...

return (
  <>
    // 省略
    ...
    <Provider store={createStore()}>
      <Component {...pageProps} />
    </Provider>
  </>
);
```

原因はここでした。

```typescript
<Provider store={createStore()}>
```

これは Next.js を使ってなければ動くっぽいですが、Next.js の場合は動きません。
ページ遷移する度にこの`createStore`関数が呼び出され、Storeがクリアされてしまっていました。
（クリアというか正確には InitialState で初期化されます）
Redux Toolkit を使わず Redux だけを使用する場合も同様、関数呼び出しではダメです。

# ちゃんと動いた例
ではどうするのか。

```typescript:store.ts
const middlewareList = [...getDefaultMiddleware(), logger]
const store = configureStore({
  reducer: rootReducer,
  middleware: middlewareList,
  devTools: process.env.NODE_ENV !== 'production',
  preloadedState: preloadedState(),
})

export default store
```

```typescript:_app.tsx
import { Provider } from 'react-redux'
// 省略
...

return (
  <>
    // 省略
    ...
    <Provider store={store}> // <--- ここです
      <Component {...pageProps} />
    </Provider>
  </>
);
```
はい。関数呼び出しをやめただけで動きました。
[公式ページ](https://redux-toolkit.js.org/tutorials/quick-start#provide-the-redux-store-to-react) でもこの書き方になっていますね。

# まとめ
Next.js を使用する際は store の関数呼び出しはしないこと！
ただググると関数呼び出し例がヒットする時があるので、Next.js を使う際は気をつけましょう。
Docker＋Seleniumによるブラウザテストでエラー（  Selenium::WebDriver::Error::WebDriverError:   tab crashed　）

# 開発環境
- Ruby 2.7.2
- Docker 3
- RSpec
- Selenium

# 背景
seleniumによるchromeのブラウザテストで、Ajaxによるボタン押下処理の自動テストを作成していました。

# 発生したエラー
```
Failures:
1.1) Failure/Error: first("input[value='ログイン']").click

          Selenium::WebDriver::Error::WebDriverError:
            tab crashed
              (Session info: chrome=89.0.4389.82)
```

beforeで記述したログイン処理にてエラーが起きました。
頻度としては2回に1回程度で、ブラウザテストの不安定さによるものが原因と考えられました。

調査したところ、メモリーが切れた場合に、生じるエラーとのことでした。
https://bugs.chromium.org/p/chromedriver/issues/detail?id=1884

# 解決策

docker環境で確保されるメモリサイズが小さいことが原因と予想しました。
docker-compose.ymlからメモリーサイズを変えられることがわかったため、下記のように修正しました。

```docker-compose.yml
  chrome:
    image: selenium/standalone-chrome
    ports:
      - "4444:4444"
    shm_size: '2gb' #追加
```
# 結果
無事に治りました。
これでも治らない場合は、以下の対応が考えられます。

① メモリサイズを2gbよりも大きく変更
② 表示ブラウザの画面サイズを小さくする設定に変更


# 参考資料
https://wonwon-eater.com/python-selenium-docker/
[Rails] Rspecでテストコードの実装③

# はじめに
テストコードの実装②をみていない方は[こちら](https://qiita.com/tochisuke221/items/6d09c2a1baf249ce4e75)からご覧ください。



#コントローラの単体テスト
今回はコントローラの単体テストについてまとめていきます。コントローラのテストでは、あるアクションにリクエストを送ったとき、想定通りのレスポンスが生成されるかどうかを確かめることが主な役割です。RSpecの中でもRequest Specと呼ばれる手法を利用します。
なお、コントローラーのテストコードは、結合テストコードに記述する内容と、同じような責務を果たすことが多いです。よって、今回は簡単にまとめるのみといたします。

###Request Spec（参考）
RSpecが提供している、コントローラーのテストコードを書くために特化した手法です。RSpecの導入が完了していれば使用できます。



##テストコードの具体的な実装

まずはファイルの生成をします。

```terminal
rails g rspec:request tweets
```
次に生成されたファイルに以下のようにテスト項目を入力してください。（テスト項目は完璧ではありません、あくまで一例です）
なお今回、すでにある投稿に対してテストを行いたいので、buildではなく　createを使用しています。

```spec/requests/tweets_spec.rb
require 'rails_helper'
describe TweetsController, type: :request do

  before do
    @tweet = FactoryBot.create(:tweet)
  end

  describe 'GET #index' do
    it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do 
　　 　get tweet_path(@tweet)
    　expect(response.status).to eq 200
    end
    it 'indexアクションにリクエストするとレスポンスに投稿済みのツイートのテキストが存在する' do 
　　　 get tweet_path(@tweet)
      expect(response.body).to include(@tweet.text)
    end
    #一部省略
  end
end
```

一つづつ見ていきます。

###get
get tweet_pathのように、どこのパスにリクエストを送るかを記述します。

###response
リクエストに対するレスポンスのこと。
このレスポンスで取得できる情報に、想定する内容が含まれているかを確認することで、テストコードを書くことができます。

###response.status
そのレスポンスのHTTPステータスコードを出力できます。

###response.body
response.bodyと記述すると、ブラウザに表示されるHTMLの情報を抜き出すことができます。

<br>
コントローラの単体テストでは、リクエストに対して、どんなレスポンスをするかの確認をしていることを意識しながら見るとわかりやすいのではないでしょうか

#おわりに
お疲れ様です。
今回はかなり簡潔にコントローラの単体手薄とについてまとめましたので、「え、これだけ？」と不安になる方もいるでしょう。しかし心配無用です！！
先に書いた通り、結合テストでしっかり確認していくので問題はありません！！！！
次回をぜひ楽しみにしていてください！

つづき
[Rspecでテストコードの実装④](https://qiita.com/tochisuke221/items/c5884afc803803a10c48)
【エラー対処】【ゆめみiOS研修】Swift Unit Test -> Could not cast value of type 'xxx' to 'xxxTests'

[株式会社ゆめみ iOS研修](https://github.com/yumemi-inc/ios-training)
システムエンジニアとして働いているものコードを書く機会が少ないため、プライベートでコードを書く習慣を身につけたいと思い見つけた新人育成用カリキュラム。

[Session8](https://github.com/yumemi-inc/ios-training/blob/main/Documentation/UnitTest.md)でのテストコード作成時に以下のエラーで躓いたため備忘録として記載します。
###エラーログ
```swift
Could not cast value of type 'yumemi.ViewController' (0x108f463f8) to 'yumemiTests.ViewController'
```
テストコードで`UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()`より`ViewController`を生成しようとしたが、実行時にエラーとなる。
ログの内容的にTargetの呼び出し先が関係していそう。

###バージョン
| ツール      |       バージョン |
|:-----------------|------------------:|
| Xcode             |              12.4 |
| Swift             |              5 |

###テストコード

```swift:ViewControllerTests.swift
import XCTest
@testable import yumemi

class ViewControllerTests: XCTestCase {

    var viewController: ViewController!

    override func setUpWithError() throws {
        viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
        _ = viewController.view
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testPerformanceExample() throws {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }
}
```

###解決方法
テスト対象の`ViewController`を参照するとTarget MembershipにTest Target(今回はyumemiTests)が含まれていたため、チェックを外したらエラーは解消され、テストコードからViewControllerを参照できるようになった。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480691/11364a5f-2c90-0574-e05c-7bc99041093c.png">

###その他
解決はしたものの理由は分かっていないため、ご存知の方がいればご教授頂けますと嬉しいです。
まだ綺麗にコードを書けていませんが奮闘中です。
[yumemi個人演習用リポジトリ](https://github.com/riku3/yumemi)
HuggingFace Transformers で BERT (もどき）を pretrain する

# 概要

BERTは自然言語処理(NLP)ではデファクトスタンダードだが、pretrain が気軽に出来ないのが難点である。そのため、BERTのハイパーパラメータを変えて、モデルを小さくしたら、性能がどのように変化するのかやってみた。

# 実験

- 日本語版Wikipediaの15%のデータを使って pretrain
    - pretrain したモデルは num_hidden_layers 以外は BERT-base と同じ
    - Next Sentence Prediction は性能が悪くなるので、外してある
    - batch size 16
    - step 150000
- ライブドアニュースコーパス(LDCC)の半分のデータを用いてfinetune
- LDCC の1文を9つのジャンルのどれかに分類する問題を解く
- 環境
    - GPU NVidia GeForce GTX-1060 6GB
    - メモリ 16GB
    - Intel Core i7
    - Ubuntu 18.04
    
# 結果
| モデル | Accuracy | モデルサイズ(MB) |pretrain 所要時間|
|:-----------|------------:|------------:|------------:|
| 東北大BERT(whole-word-masking)  | 0.780|424MB||
| num_hidden_layers = 6 |  0.753  | 261M |8.5時間|
| num_hidden_layers = 3  |  0.746 | 180M |7時間|

# 所感
- 当たり前だがモデルサイズが大きいほど精度が上がる
- num_hidden_layers = 6 および 3 のモデルサイズが意外に変わらない
    - BERTは transformer の layer 部分以外のパラメーターが100MBくらいある
- num_hidden_layers = 3 で比較的少量(Wikipedia 全体の15%)で7時間というお気軽な pretrain でもそこそこのパフォーマンスを残しているので、時と場合によっては、こういうお気軽 pretrain かつ軽量なモデルで何かをやってみてもよいのかもしれない。
- transformers の BertForPreTraining クラスを使うと簡単に pretrain できることがわかった
    - ここの loss を少しいじると Next Sentence Prediction を外すこともできる

# 次回予告
pretrain に必要なコードは、案外世の中で公開されていない気がしたので、今回、私がやったことをネットに全部公開してみたい（拙いコードですが・・・）。というわけで、次回に続く。

# 後日談
続きを書きました。
[HuggingFace Transformers で BERT (風モデル）を pretrain する（ソースコード解説）](https://qiita.com/elm200/items/70f41fcdb8dd113f0612)
Github Actionsでmasterにpushされたらterraform applyするCIを作る

## やりたいこと
- mainブランチにpushされたら、fmtされているかチェックして`terraform apply`を実行する

### 用意するファイル
- `.github/workflows/`にyamlファイルをセットするのみでいい
- jobsの上から実行されて、一つでも失敗するとGithubActionsがエラーになる
- ディレクトリを指定する場合は、`working-directory: ./deployment/terraform`のようにする（run cdとかではない）
- 次の例は`development`と`production`のWorkspaceを利用している環境
- aws userを作成しクレデンシャルを控えておく

```.github/workflows/ci-master.yml
name: ci-master

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  terraform:
    name: Terraform
    runs-on: ubuntu-latest

    defaults:
      run:
        shell: bash
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: <key>
        aws-secret-access-key: <secretkey>
        aws-region: ap-northeast-1

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1
      with:
        terraform_version: 0.13.5

    - name: Terraform Format
      working-directory: ./deployment/terraform
      run: terraform fmt -recursive -check

    - name: Terraform development
      working-directory: ./deployment/terraform
      run: |
        terraform init
        terraform workspace select development
        terraform validate
        terraform plan -var-file=development.tfvars
        terraform apply -var-file=development.tfvars -auto-approve

    - name: Terraform production
      working-directory: ./deployment/terraform
      run: |
        terraform init
        terraform workspace select production
        terraform validate
        terraform plan -var-file=production.tfvars
        terraform apply -var-file=production.tfvars -auto-approve

```

## 実行している様子
- mainにpushすれば動作
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/dbd5fde2-0c75-4f07-4fd9-803357132e63.png)


## 参考

- https://qiita.com/HeRo/items/935d5e268208d411ab5a
- https://github.com/hashicorp/setup-terraform
+C言語をMACで (環境構築）

##はじめ
環境構築に戸惑ったので、簡単な方法を紹介します

MacBook Air(2019) 1.6hz　intelcore i5
OS BigSurにアップデート済み。

##必要なソフト

Xcode
これをダウンロードすると、簡単にC言語が動くようになります。
Vim 
テキストエディタです。ここにC言語を書き込みます
gcc
コンパイラです。c言語を読み込み動かします。
##1まずはやってみよう
Xcodeをインストールappstoreで検索！
vimをインストールhttps://howpon.com/17364#Vim-2

これが終わったら、ターミナルにて
1　vim test.c
2  enter
 fileに飛ぶのでそこで i を一回押すと文字入力画面になるので

---------------
♯include < stdio.h > 
int main(void) {
printf("確認が完了したよ");
return 0;
}

--------

と入力しescを押して、:wqと入力してエンターを押すとターミナルの画面にもどります。
そこでgcc test.c と入力し　エンターを押します
ここでエラーが起きなければ ./a.out　と入力して、
確認が完了したよ　と出れば完了です。

みにくい記事ですが、お役に立てればと思います。
Kibanaで、covid-19の感染者データを移動平均でプロット

感染対策が機能しているか判断するには潜伏期間の2週間を考慮するために移動平均で評価する必要がある。そこで、Elastic search社のKibanaを利用して、covid-19の感染者データを2週間の移動平均でプロットする。
#環境
ElasticSearch version 7.12.1
Kibana
#kibanaに読み込ませるデータの準備
csvフォーマットのファイルを読み込ませる。
1行目は項目名にする。
文字コードがsift-JISでは文字化けするので、utf8でエンコードする。
日付フォーマットを’2021-05-11’のように西暦年と2桁の月日の数字を「ー」で区切るフォーマットに変換する。
県によってはCSV形式でなく、EXCELフォーマットで公開しているので、EXCELがあると便利。
最近のEXCELではUTF-8のCSVファイルで保存できるようになった。
居住地が管轄保健所になっている場合もあるが、居住地名が長いとグラフの表示が冗長になるので短く変換すると良い。データのフィルター機能で確認する。
##kibanaにデータを読み込ませる
elasticのHomeにある「Upload a file」リンクから、
csvファイルを「drag and drop」エリアにドロップしてファイルを読み込ませる。
SummaryのTime fieldが表示されていない場合は、日付フォーマットに問題がある。
宮城県のデータには確定日に「欠番」と記述されたレコードがあるので、このレコードを削除する。EXCELのデータフィルターで確認する。
#kibanaでグラフをプロット
1. サイドメニュのAnalysticにあるVisualize Libraryから開始
2. Create new visualizationをクリックし、読み込んだデータを選択
3. 作成手法はAggregation Base
4. グラフの種類はLineまたはAreaなど、時間軸とカウント数の関係を表示できるタイプを選択
5. 読み込ませたデータをプロットするデータ源に選択
 
###プロット
プロットする時間域を1ヶ月から3ヶ月程度に設定し、x軸をDate Histgram、y軸をレコード数の移動平均、パラメータを居住地になるように設定する。

1. y軸の指定
2. Bucketsにsplit seriesを追加
3. Bucketsにx軸を追加。 x軸をsplit seriesより先に追加すると警告がでるがドラッグで順序を変更可能

####y軸
Aggregation : "MovingAvr"
Metric: 　　　 "Custom metric"
Custom metricのAggregation: "Count"
Advancedに「{"window":14}」と記述し14日の平均期間を指定
####split series
Aggregation : "Terms"
Field       : "居住地"
Order by    : "Custom metric"
Custom metricのAggregation: "Count"
Order       : "Descending"
Size        : "5" (プロットするパラメータ数)
####x軸
Sub aggregation: "Date Histgram"
Field       : "@timestamp"
Minimum interval : "Day"

#
Git コミット名を書き換える

# はじめに
railsでアプリを作成中にgitでプッシュした後に、コミット名を変更したい場合にどうしたらいいのか、学習した内容を記事にしました。
#### 修正するための流れは
- `git commit --amend`
- エディタ内でコミット名を編集
- git push -f origin リポジトリ名

の流れになります。

# 直前のコミットを書き換える
`git commit --amend`
このコマンドを使用することで、前回のコミットにファイルの追加を行ったり、コミットコメントの変更を行ったりできます。

```
×××××@×××××MacBook-Pro ××××× % git log
commit ×××××××××××××××××××××××××××××× (HEAD -> main, origin/main)
Author: ××××× <××××××××××××××××××××>
Date:   Mon May 3 14:43:02 2021 +0900

    first commit
# ここのコミット名を編集したい
```
まず、

```
×××××@×××××MacBook-Pro ××××× % git commit --amend 
```
のコマンドを実行すると、エディタが表示されるので、`insert`モードにして、コミット名を編集します。
編集が完了したら、

```
「ESCボタン」　からの、、、
:wq  # 編集したエディタを保存するコマンド
```
これで、コミット名がローカル上に反映されるので、次は、リモートリポジトリに編集内容を反映させます。

# 強制的にリモートリポジトリを書き換える

これまでの過程で、ローカルリポジトリのコミット名の書き換えは完了しましたが、リモートリポジトリには反映されていません。
しかし、いつものように
`git push origin main(master)`
などと入力した場合はエラーが発生します。
これはリモートリポジトリととローカルリポジトリに不整合が生じているからです。
これを解決するために強制的にローカルブランチをリモートブランチに上書きできるコマンドを実行します。

```
git push -f origin リポジトリ名
```
これで、pushしたコミット名を編集することができます。
このコマンドは強制的にブランチを上書きするコマンドなので、使用する際は注意が必要です。
SQL -  保存されているデータを並び替えて表示する(ORDER BY, DESC, LIMIT) 

#はじめに
学んだSQL関係の知識を、忘れないように定期的にQiitaにアウトプットしています。
今回は、数字のデータを元に、テーブルのデータを並び替えて表示させる方法をいくつか紹介します。

#使用するテーブル
使用するテーブルのデータは、以下のようになっています。

```
+----+-----------------------+------------+------------+-----------+----------+
| id | name                  | sauna_temp | water_temp | area      | sex      |
+----+-----------------------+------------+------------+-----------+----------+
|  1 | ウェルビー栄             |         90 |         16 | 愛知       | 男性    |
|  2 | 湯ラックス               |         93 |         12 | 熊本       | 男女OK  |
|  3 | ウェルビー福岡           |         85 |         16 | 福岡      | 男女OK   |
|  4 | サウナイーグル           |        110 |          7 | 愛知      | 男性     |
|  5 | かるまる池袋            |        100 |          5 | 東京      | 男性     |
|  6 | スカイスパ              |         70 |         16 | 神奈川    | 男性     |
|  7 | サウナラボ              |         70 |         22 | 愛知      | 女性     |
|  8 | ウェルビー名駅           |         80 |         18 | 愛知      | 男性     |
+----+-----------------------+------------+------------+-----------+----------+
 ```

##数値が小さい順に並べる方法

sauna_tempというカラムの数値が小さい順に並べたい！という時は、以下のようなコマンドを使用します。
「ORDER BY」を使用することで、対象のカラムの数値が小さい順に並び替えて表示することができます。

```SQL:
SELECT name,sauna_temp FROM tables ORDER BY sauna_temp;
-- SELECT <表示させたいカラム名> FROM <対象テーブル名> ORDER BY <対象のカラム>;

+-----------------------+------------+
| name                  | sauna_temp |
+-----------------------+------------+
| スカイスパ              |         70 |
| サウナラボ              |         70 |
| ウェルビー名駅           |         80 |
| ウェルビー福岡           |         85 |
| ウェルビー栄             |         90 |
| 湯ラックス               |         93 |
| かるまる池袋             |        100 |
| サウナイーグル           |        110 |
+-----------------------+------------+
```

##数値が大きい順に並べる方法

数値が大きい順にデータを並べたい際は、先ほどの「ORDER BY」に加えて、「DESC」というコマンドを入れることで実現します。

```SQL:
SELECT name,sauna_temp FROM tables ORDER BY sauna_temp DESC;
-- SELECT <表示させたいカラム名> FROM <対象テーブル名> ORDER BY <対象のカラム> DESC;

+-----------------------+------------+
| name                  | sauna_temp |
+-----------------------+------------+
| サウナイーグル           |        110 |
| かるまる池袋            |        100 |
| 湯ラックス              |         93 |
| ウェルビー栄            |         90 |
| ウェルビー福岡           |         85 |
| ウェルビー名駅           |         80 |
| スカイスパ              |         70 |
| サウナラボ              |         70 |
+-----------------------+------------+
```

#表示させる数を指定する
例えば、データの個数が多すぎて全部のデータを表示させたくはないけど、トップ５だけを抽出したいなあ、、、という場面があるかもしれません。そうゆう時は、「LIMIT」を使用すれば効率良くデータを表示させることができます。
以下は、sauna_tempの数値が大きいものを５つだけ表示させたい場合です。

```SQL:
SELECT name,sauna_temp FROM tables ORDER BY sauna_temp DESC LIMIT 5;

+-----------------------+------------+
| name                  | sauna_temp |
+-----------------------+------------+
| サウナイーグル           |        110 |
| かるまる池袋             |        100 |
| 湯ラックス               |         93 |
| ウェルビー栄             |         90 |
| ウェルビー福岡           |         85 |
+-----------------------+------------+

```
Reactとの連携　７　完成

```rb:app/javascript/pack/***jsx
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

var target_dom = null;

document.addEventListener('DOMContentLoaded', () => {
   target_dom = document.querySelector('#data');
   const url = new URL(location.href);
   let f = url.searchParams.get("name");
   if (f == null){ f = ''; }
   getData(f);
});

function getData(f){
  let url = "http://localhost:3000/data/ajax";
fetch(url)
  .then(
    res => res.json(),
      (error) => {
        const el = (
          <p>ERROR!!</p>
        );
        ReactDOM.render(el, target_dom);
    }
  )
  .then(
    (result) => {
      console.log(result);
      let arr =[];
      for(let n in result.rss.channel.item){
        let data = result.rss.channel.item[n];
        arr.push(
           <tr>
             <th>{data.title}</th>
             <td class="small">{data.pubDate}</td>
           </tr>
        );
      }
      const el = (
             <table class="table mt-4">
               <thead class="thead-dark">
                <tr><th><a href={data.link}>{data.title}</a></th>
                <th>Date</th></tr>
               </thead>
                <tbody>{arr}</tbody>
             </table>
      );
      ReactDOM.render(el, target_dom);
    },
    (error) => {
      console.log(error);
      const el = (
        <p>ERROR!!</p>
      );
      ReactDOM.render(el, target_dom);
    }
  );
}
```

![20210503-164336.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/127072cc-9356-1b73-8705-38a1eb0a079f.png)
セッターとゲッターの使い方

##セッターとゲッターの役割
**セッター**
　クラス外からインスタンス変数の値を**変更**できるインスタンスメソッド
**ゲッター**
　クラス外からインスタンス変数の値を**出力**できるインスタンスメソッド

**使用例**

```rb:
class People
  # セッター（'name='までがメソッド名）
  def name=(name)
    @name = name  # 2. メソッドの引数を@nameに入れる
  end
  # ゲッター
  def name
    @name  # 3. @nameを出力する
  end
  
  # ゲッターの応用
  def introduction
    puts "私の名前は#{@name}です。" # 1. メソッドを呼ぶ際に@nameを任意に変更したい
  end
end

# １〜３の過程で、セッターメソッドに渡した引数がインスタンス変数に入るようになった。

user = People.new
user.name=("太郎")       # セッターを使い、"太郎"が@nameに入った
puts user.name               # ゲッターを呼ぶと@nameが出力される
#=> 太郎                 
user.introduction      
#=> 私の名前は太郎です。 

user.name = "花子"       # セッターで@nameの値を"花子"に設定した
user.introduction
#=> 私の名前は花子です。
```

**まとめ**
　インスタンス変数の「**メソッド間で同じ値を共有する**」という性質と
　インスタンスメソッドの「**クラス外でも使用できる」**という性質を組み合わせることで
　「**クラス外でもインスタンス変数の値を変更・出力できる**」という使い方をしたものが、
　ゲッターとセッターである。


##簡単に使う
セッターを定義　`attr_writer :メソッド名`
ゲッターを定義　`attr_reader :メソッド名`

ゲッターとセッターをまとめて定義　`attr_accessor :メソッド名`
【Linux】サーバ監視用のLinuxコマンドまとめ

現場でサーバ運用を行うにあたり、どのLinuxコマンドを実行するかが曖昧だったので自分用に簡単にまとめました。

#topコマンド
topコマンドで現在動作しているプロセスを一覧で確認できます。

![スクリーンショット 2021-05-03 15.23.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/c7877a88-9700-a251-87fb-a31b55a77319.png)

**1行目**
稼働時間やロードアベレージなどの情報が表示されます。

| 項目 | 説明 |
|:-|:-|
| 02:23:54  | 現在時刻  |
| up 3 min  | 稼働時間  |
| 1 user  | ログインユーザ数  |
| load average: 0.36, 0.65, 0.32  | 実行待ちプロセス数の平均値(過去15分, 5分, 1分)  |

**2行目**
実行中のタスク(=プロセス)状態が表示されます。
ゾンビ状態のタスクとは、処理が完了しているのにメモリ上に存在しているタスクのことをいいます。
ゾンビ状態を解くためには、ユーザがkillコマンドを発行する必要があります。

| 項目 | 説明 |
|:-|:-|
| total  | タスクの合計  |
| running  | 実行中のタスク数  |
| sleeping  | 待機中のタスク数  |
| stopped  | 停止中のタスク数  |
| zombie  | ゾンビ状態のタスク数  |

**3行目**
CPUとタスクの情報です。
CPU使用率を判断するときはここをみます。

| 項目 | 説明 |
|:-|:-|
| us  | ユーザプロセスの使用時間  |
| sy  | システムプロセスの使用時間  |
| ni  | 優先度付プロセスの使用時間  |
| id  | アイドル状態の時間  |
| wa  | I/O待ちプロセスの使用時間  |
| hi  | ハードウェア割込の使用時間  |
| si  | ソフトウェア割込の使用時間  |
| st  | 仮想マシンのリソース割当待ち時間  |

**4行目**
メモリの使用状況です。
バッファとキャッシュの違いは以下になります。

- バッファ: もう一度アクセスされる可能性が高いデータが保存される
- キャッシュ: 直近でアクセスのあったデータが保存される

**5行目**
スワップ領域(ハードドライブ上のメモリ領域)の使用状況です。

#freeコマンド
freeコマンドを実行すると、topコマンドの実行結果の4, 5行目の詳細を確認することができます。
`-m`オプションでメガバイト表示になります。

![スクリーンショット 2021-05-03 16.00.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/1aa76a1f-d2c5-1f82-18d1-876ba13982a6.png)

#psコマンド
プロセスの状態を確認し、サーバにどのような処理が負荷をかけているのかをみることができます。
`-aux` `-ef`オプションとよく一緒に使われます。
これらのオプションの実行結果は大体同じです。

| オプション | 表示内容 |
|:-|:-|
| a  | 端末操作のプロセス  |
| u  | CPUやメモリの使用率など  |
| x  | 端末操作以外のプロセス  |

![スクリーンショット 2021-05-03 16.08.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/76e61a89-9f5d-59fc-552f-d6d07ccd8559.png)

| 項目 | 説明 |
|:-|:-|
| USER  | 実行ユーザ  |
| PID  | プロセス番号  |
| %CPU  | プロセスのCPU使用率  |
| %MEM  | プロセスのメモリ使用率  |
| VSZ  | プロセスが確保した仮想メモリ領域のサイズ  |
| RSS  | 物理メモリ領域のサイズ  |
| TTY  | 標準入出力となっている端末  |
| STAT  | プロセスの状態表示  |
| START  | プロセスの開始時刻  |
| TIME  | CPUの累積使用時間  |
| COMMAND  | 実行中のプロセス  |

#killコマンド
ソンビ状態のプロセスなどを強制終了させることができます。

```
$ kill [プロセスID]
```
強制終了の他にも、さまざまなシグナルを送ってプロセスの挙動を変えることができます。

![スクリーンショット 2021-05-03 16.13.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/6e5939fd-9475-d03a-cf68-f6cffbdede70.png)

例えば、`kill -1 [プロセスID]`を実行すると、プロセスにHUPというシグナルが送られます。

#jobsコマンド
実行中のジョブを表示することができます。

```
$ jobs
```
ちなみに、シェルから見たときの処理の単位をジョブ、カーネルから見たときの処理の単位がプロセスです。
シェルのコマンドラインに入力した１行が１つのジョブになります。

また、`bg`でジョブをバックグラウンドへ移行したり、`fg`でフォアグラウンドへ移行することもできます。

```
$ bg [ジョブ番号]
```

```
$ fg [ジョブ番号]
```

#参考資料

https://gihyo.jp/magazine/SD/archive/2019/201908
Salesforce を自動化するにあたっての設定【気が付いたときに更新】

# はじめに
- Salesforce はとても便利で、高機能、カスタマイズもしやすいです。
- Salesforce からは、色々な情報（例えば、新機能のお知らせだったり）をアナウンスしてくれます。
- しかし、自動で決まった動作するように組み立てていた場合、アナウンスなど想定外の画面が表示されてしまうことで、自動実行が停止してしまいます。
 - 夜間に実行、朝確認したら全く動いていない、となったら泣きそうです😭
- 実施しておくと良い設定をまとめておこうと思います。


# 設定
#### ネットワークセキュリティ
- 「ID検証画面」を表示させないようにするため、[ネットワークアクセス] で [信頼済み IP 範囲] を指定する。
- または [プロファイル] - [ログイン IP アドレスの制限] で できる限りのIPの範囲を指定する。
 - 詳細は https://qiita.com/xx_mana/items/7f532a977184037ea80c

#### 組織情報
- [組織情報] - [ログイン通知] - [システムメンテナンスに関する通知を非表示]　→ ON
- [組織情報] - [ログイン通知] - [システムダウンタイムに関する通知を非表示]　→ ON

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309141/ec85df15-5818-bbd2-02d0-012142a32dbe.png)

- 以下のような画面が表示されることを防げる（はず）ですが、中々表示されることが少ないこともあり、未確認。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309141/3c2af1b3-a17e-31e6-1517-5dfea09cb47e.png)

#### セッションの設定
- [セッションの設定] - [セッションタイムアウト] - [タイムアウト値] → 長めに　（2021/5/22 追加)

#### ユーザの設定
- 「携帯電話を登録」画面を表示させないために、「電話を登録しません」を選択しておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309141/878cced9-5e1c-aa6e-0bcb-f9b506d184b2.png)

- ログイン直後に設定画面が表示されないようにするため、[ユーザ] - [設定画面をデフォルトページに設定]　→ OFF

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309141/4f67a5a4-d9c3-aa51-6c79-6e70de78bfb1.png)


- ユーザのパスワード有効期限切れによって、パスワード変更画面が表示されることを防止するため、[プロファイル/権限セット] の [システム権限] - [パスワード無制限] → ON
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309141/18291f89-f36d-7c47-e1c9-a93a3ed0f057.png)

- Classic モードのみに操作を限定する場合は、[プロファイル/権限セット] の [システム権限] - [Lightning Experience ユーザ]　→ OFF

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309141/b19f267e-b902-747a-a3b1-efb6855cf5d1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309141/03cdd38a-4d34-5e0b-978a-2ee9de8db32a.png)


# 自動化と組み合わせると便利な機能
- ログイン（こちらですが「Winter'22」で無効になるそうです。https://help.salesforce.com/s/articleView?id=000363298&type=1）
 - `https://login.salesforce.com/?locale=jp&un=username&pw=password` でアクセスすることで、ログイン操作を録画不要。
 - usernameにログインユーザID、passwordにログインユーザのパスワードを設定。
  - パスワードなどが平文なので、取扱注意。
  - ~~パスワードに & などが含まれると正しく動かない模様。~~
  - URLエンコードで対処できる模様。
        - Autify では、以下のような確認画面が出ました。対応が必要のようです。
        - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309141/cc2e1827-35c2-e226-a307-3c0cca811ea2.png)



# さいごに
- あくまでも、自動で実行させるための工夫と設定となります。用量、用法を守って正しく使いましょう😊




### ご了承ください
- まだまだ勉強中の部分もあります。間違っている箇所もあるかもしれません。
- Salesforce は、この時点のバージョン(2021年4月～5月頃) での内容になります。今後、仕様変更が変わることによって、内容の通りにならない可能性もあります。ご了承ください。
 - また、URLなども変更になっている可能性もあります。
No template for interactive requestエラーの解消法

### No template for interactive requestが発生しエラーの解消がわからなくなった

---
https://gyazo.com/53c8f85fe30fed4c81781190aa737907

『購入画面へ進む』を押すと上記のエラーが発生しcontroller,show,index関係を見直したが不明。。。

メンターへ相談し、解消法を聞いたところ```app/controller/order_controller.rb```部分が単数形になっている事、
内部の```class OrderController < ApplicationController```のorderが単数形になっている部分の指摘を受けた。

改めて```app/controller/orders_controller.rb```に変更と
```class OrdersController```へ変更

その後、```rails routes```をして再度ルーティングの確認をするとURLが変わっている部分があるのでshow.html.erb 部分を修正し```control c```,```rails s```と再起動したところ解消できた。

####コントローラ名は複数形にすることが命名規則なので、今後も注意をします。
エラーメッセージを表示させるためには？

### エラーメッセージを表示させるには？

_error_messages.html.erbなどがある場合は下記の様にrenderを使用して呼び出す

```html.erb
<%= render 'shared/error_messages', model: @order %>
```

#####学習時のメモとして残しておきました。
ログイン状態でも他のユーザーの編集をできないようにする

###ログイン状態でも他のユーザーの編集が出来てしまう状態をログインしていてユーザーIDが一致していないと編集出来ない状態にする。


```controller.rb
def edit
    @item = Item.find(params[:id])
   redirect_to root_path unless current_user.id == @item.user_id
end
```

#####上記を記載していないと直接URLを打ち込む事で編集できてしまう。それを制御するためにはunlessを用いてcurrent_user.id == @item.user_idの時でないと編集できないようにした。


#####今日もまた良い学習になりました。
KDP：google documentで作った原稿に論理目次を入れる

目次にしたい見出しを選択状態にしてCtrl＋Alt＋1(数字は任意)

docx形式で保存

以下のコンバーターでepub形式に変換
https://www.aconvert.com/jp/ebook/docx-to-epub/

ちなみに空白行を作るときは全角スペースをいれないと消えてしまうので注意
プルリクエストのコンフリクト解消方法

###プルリクエスト後にコンフリクトが発生している

●解消方法●
❶リモートのプルリクエストでコンフリクトが起きている
❷ローカルでgit merge masterを実行することで、ローカルにも同じコンフリクトを起こす
❸ローカル上でコンフリクトを解消（緑と青のどちらかを残す）し、コミットプッシュすれば同じコンフリクトが起きているリモートも解消される

コンフリクト解消も勉強になりました〜！
単体テストコードエラー

##単体テストコード
###エラーコード

⇒expected [ ] to include "Item must exist"

上記の場合はバリデーションが定義されていないことを表す

⇒expected [Item must exist] to include ""

上記の場合は、includeが定義されていない場合を表す


自分がミスした部分をメモ替わりに投稿します。
新規投稿、ログイン、ログアウト実装時　pathの書き方注意点

新規投稿、ログイン、ログアウト等ルートパスを記載する際の注意点を記載します！(めっちゃ初歩です）

```app/views/shared/_header.html.erb
<%# CSS・・・assets/stylesheets/shared/header.css %>
<header class='top-page-header'>
  <div class='search-bar-contents'>
    <%= link_to image_tag("furima-logo-color.png", class:"furima-icon"), "/" %>
    <form class="search-form" action="#">
      <input class='input-box' placeholder='キーワードから探す'>
      <button class="search-button">
        <%= image_tag "search.png", class:"search-icon" %>
      </button>
    </form>
  </div>
  <div class='nav'>
    <ul class='lists-left'>
      <li><%= link_to 'カテゴリー', "#", class: "category-list" %></li>
      <li><%= link_to 'ブランド', "#", class: "brand-list" %></li>
    </ul>
    <ul class='lists-right'>
      <%# deviseを導入できたら、ログインの有無で表示が変わるように分岐しましょう%>
      <% if user_signed_in? %>
        <%= link_to current_user.nickname, "#{@user.name}", class: "user-nickname" %>
        <%= link_to 'ログアウト', "destroy_user_session_path" , method: :delete, class: "logout" %>
      <% else %>
        <%= link_to 'ログイン', "user_session_path", class: "login" %>
        <%= link_to '新規登録', "new_user_registration_path", class: "sign-up" %>
      <% end %>
      <%# //deviseを導入できたら、ログインの有無で表示が変わるように分岐しましょう%>
    </ul>
  </div>
</header>
```

上記だとpathにそのままアクセスしてしまう。

例）新規登録ボタンを押すと
⇒new_user_registration_pathへ直接アクセスする

これの解決方法として""を外すこと！たったこれだけ！！


```app/views/shared/_header.html.erb
app/views/shared/_header.html.erb
<%# CSS・・・assets/stylesheets/shared/header.css %>
<header class='top-page-header'>
  <div class='search-bar-contents'>
    <%= link_to image_tag("furima-logo-color.png", class:"furima-icon"), "/" %>
    <form class="search-form" action="#">
      <input class='input-box' placeholder='キーワードから探す'>
      <button class="search-button">
        <%= image_tag "search.png", class:"search-icon" %>
      </button>
    </form>
  </div>
  <div class='nav'>
    <ul class='lists-left'>
      <li><%= link_to 'カテゴリー', "#", class: "category-list" %></li>
      <li><%= link_to 'ブランド', "#", class: "brand-list" %></li>
    </ul>
    <ul class='lists-right'>
      <%# deviseを導入できたら、ログインの有無で表示が変わるように分岐しましょう%>
      <% if user_signed_in? %>
        <%= link_to current_user.nickname, "#{@user.name}", class: "user-nickname" %>
        <%= link_to 'ログアウト', destroy_user_session_path , method: :delete, class: "logout" %>
      <% else %>
        <%= link_to 'ログイン', user_session_path, class: "login" %>
        <%= link_to '新規登録', new_user_registration_path, class: "sign-up" %>
      <% end %>
      <%# //deviseを導入できたら、ログインの有無で表示が変わるように分岐しましょう%>
    </ul>
  </div>
</header>
```

####※リンク先には""を付けないように注意が必要！
単体テストコードエラー解消 Failure/Error: expect(@user.errors.full_messages).to include("First name can't be blank")

##◉単体テストコード発生　Failure/Error: expect(@user.errors.full_messages).to include("First name can't be blank")
###◯furimaアプリ実装中に単体テストコードを実装
###エラーメッセージが発生したのでその時の対処と共にアウトプット

```spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  describe '#create' do
    before do
      @user = FactoryBot.build(:user)
    end
  
    it 'passwordとpassword_confirmationが5文字以下では登録できない' do
      @user.password = '00000'
      @user.password_confirmation = '00000'
      @user.valid?
      expect(@user.errors.full_messages).to include('Password is too short (minimum is 6 characters)')
    end
    it 'nicknameが空では登録できない' do
      @user.nickname = ''
      @user.valid?
      expect(@user.errors.full_messages).to include ("Nickname can't be blank")
    end
    it 'emailが空では登録できない' do
      @user.email = ''
      @user.valid?
      expect(@user.errors.full_messages).to include("Email can't be blank")
    end
    it 'emailは@が含まれていなければ登録できない' do
      @user.email = 'sample.com'
      @user.valid?
      expect(@user.errors.full_messages).to include("Email is invalid")
    end
    it 'passwordが空では登録できない' do
      @user.password = ''
      @user.valid?
      expect(@user.errors.full_messages).to include("Password can't be blank")
    end
    it 'first_nameが空では登録できない' do
      @user.first_name = ''
      @user.valid?
      expect(@user.errors.full_messages).to include("First_name can't be blank")
      #　ここでエラーが発生した
    end
```

エラーメッセージは↓

```
1) User#create first_nameが空では登録できない
     Failure/Error: expect(@user.errors.full_messages).to include("First name can't be blank")
       expected [] to include "First name can't be blank"
     # ./spec/models/user_spec.rb:38:in `block (3 levels) in <top (required)>'
```

よく見ていくと
to include後の（"First name can't be blank")とエラーが記載されている。

もしかしたら、＿がいらないのか？と仮定し削除して再度bundle exec rspec spec/models/user_spec.rb 実行。

```
User
  #create
    passwordとpassword_confirmationが5文字以下では登録できない
    nicknameが空では登録できない
    emailが空では登録できない
    emailは@が含まれていなければ登録できない
    passwordが空では登録できない
    first_nameが空では登録できない
    last_nameが空では登録できない
    first_name_kanaが空では登録できない
    last_name_kanaが空では登録できない
    birthdayが空では登録できない
    passwordが存在してもpassword_confirmationが空では登録できない
    重複したemailが存在する場合登録できない
    passwordが5文字以下では登録できない

Finished in 0.1892 seconds (files took 1.01 seconds to load)
13 examples, 0 failures
```

### なんとか解消！！
###＿の部分は忘れがちなので注意して覚えておこう！
UbuntuでC#のアプリを開発する

# はじめに

C#のアプリを開発するための環境をUbuntu20.04.2LTSサーバ上につくります。MacからVS Codeを使用してUbuntuにリモート接続します。
WindowsでWSLにインストールしたUbuntuに「Remote - WSL」で接続すれば、同じ方法で、Windows側のVS Codeで開発とデバッグができます。
VS Codeの操作の詳細は記載していません。VS Codeにすでに慣れている方を対象としています。

# 用意するもの
Ubuntu20.04.2LTS　サーバ
Mac
VS Code

# SSHでサーバに接続
VS Codeに「Remote - SSH」拡張機能をインストールします。
UbuntuサーバにVS Codeから「Remote - SSH」で接続します。

# Ubuntu20.04.2LTS　サーバのセットアップ
今回は、UbuntuサーバをMacのVM上（parallels desktop）に作成しました。
クラウドでも実マシンでも要領は同じだと思います。

VS　Codeのターミナルから以下のコマンドを実行します。

.Net 5.0をapt-getでインストールできるようにします。

```bash
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
```

.Net 5.0 SDKをインストールします。

```bash
sudo apt-get update
sudo apt-get install -y apt-transport-https
sudo apt-get install -y dotnet-sdk-5.0
```

# VS Code
次に、Ubuntuサーバでデバッグ等が行えるように、C#の拡張機能をインストールします。リモート接続した状態で、「C# ms-dotnettools.csharp」を表示すると、図のようにinstall in SSH: xxx.xxx.xxx.xxxと表示されます。この状態で、インストールすると拡張機能がUbuntu側にインストールされます。Mac側には必要ありません。
![スクリーンショット 2021-05-02 18.20.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613072/53b3d8b7-e6f8-c376-391c-6b57d9997ab2.png)

# プロジェクトの作成
VS　Codeのターミナルから以下のコマンドを実行してプロジェクト作成します。

```bash
dotnet new console --name CSharpTest
```
ここで、フォルダを開いている場合は、一旦フォルダを閉じて、CSharpTestフォルダを開きます。
次に、メニューからTerminal->Run Build Taskを選択すると、右下にC#の拡張機能がビルドの設定を作成するかどうか聞いてくるので、Yesを選択します。

![スクリーンショット 2021-05-03 15.34.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613072/acd04414-5cea-f1de-098e-405d0ad94d15.png)

プロジェクトフォルダ（この例では、CSharpTest）に、.vscodeフォルダが作成され、その中に、ビルド(tasks.json)と実行(launch.json)の設定ファイルが作成されます。
うまくいかなかった場合、.vscodeフォルダを削除して、sshを切断してからやり直します。
また、プロジェクトのフォルダを開いた状態で行わないと、.vscodeが変な場所に作成されてしまってうまくいかないことがあります。

![スクリーンショット 2021-05-03 15.36.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613072/d30baddf-9fca-6b76-2f81-1ce7b7154546.png)

#ビルドとデバッグ

三角マークに虫のアイコンがあるボタンを押すと Runボタンが表示されます。

![スクリーンショット 2021-05-03 15.49.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613072/a7673022-dc8f-4276-ddc8-306fdaf396a0.png)
なぜか、.NET Core Launch(console)が2つ表示されていますが同じものです。（バグ？）
Launchが選択されていることを確認します。
![スクリーンショット 2021-05-03 15.49.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613072/2ba80a8d-6636-71c2-0fc5-887d0e3c67c6.png)
Runボタンを押すとデバッグ実行されます。
ブレークポイントを設定しておくと、ブレークポイントで停止します。
![スクリーンショット 2021-05-03 15.54.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613072/b96198b9-5fda-ac59-444e-4fd61e97592f.png)

# まとめ
サーバサイドのプログラムをMacのVS Codeから開発、デバッグできるようになりました。
VS Codeは便利で大好きなのですが、うまくいかないとなかなか解決できずにハマってしまうので、いろいろ使い方をまとめていきたいと思います。
(基本)HerokuにNodeJsアプリをデプロイする際に確認すべき4つのポイント



#1.ポート設定
```javascript:index.js
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
  console.log("Server up!!")
})
```
#2.使用中のNode,NPMバージョンの指定
```json:package.json
 "engines": {
    "node": "使用中のバージョンを記載(14.15.0など)",
    "npm": "使用中のバージョンを記載(7.7.6など)"
  }
```

#3.開始スクリプトの指定
```json:package.json
"scripts": {
    "start": "node index.js"
}
```
#4.gitignoreファイルの作成
```text:.gitignore
node_module
etc..
```
TP-Linkのネットワークカメラの映像をOBSに取り込む

# TP-Linkのネットワークカメラの映像をOBSに取り込む

Qiita初投稿です。

本記事ではTP-Linkのネットワークカメラ、TapoカメラシリーズにあるRTSPライブストリーミング機能を利用して、Tapoカメラの映像をライブ配信ソフト、OBSに取り込む方法について説明します。

別途、Tapoアプリを操作するスマホが必要です。

ポート転送などを設定すればインターネット越しにOBSに映像を取り込めますが、セキュリティ上、TapoカメラとOBSを起動する端末は同じLAN上にあるほうが望ましいです。

以下環境で問題なく映像が取り込めることを確認しています。

Tapo C200<br>https://www.amazon.co.jp/dp/B07YG7RNF2

OBS Studio 26.1.1<br>https://obsproject.com/ja/download

## 1. Tapoアプリでアカウントを作成

以下TP-Link公式サポートページの「ステップ1: Tapoアプリでアカウントを作成」を実施し、スマホのTapoアプリからRTSP接続用のアカウントを作成してください。

https://www.tp-link.com/jp/support/faq/2680/

アカウントを作成したら、上記リンクに記載のあるこちらのURLを控えておきましょう。

> TapoカメラのRTSPライブストリームURLは以下の様になります: 
>
> 高画質な1080P (1920*1080) ストリームの場合: *rtsp://username:password@IP Address:554/stream1* 
>
> 低画質な360P (640*360) ストリームの場合: *rtsp://username:password@IP Address:554/stream2*

## 2. OBSにストリーミングURLを入力して映像を取り込む

Tapoカメラと同一LAN上にある端末からOBSを起動し、以下手順で「1」の手順で控えたRTSPストリーミングURLを入力すれば、OBSに映像を取り込むことが可能です。

1. 画面下部「ソース」にある「**+**」マークをクリック。
![2021-05-03 14_42_36-OBS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1434784/170392ce-a877-93da-7cfb-16554b782aee.png)


2. 「VLCビデオソース」をクリック
   ![VLCビデオソース.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1434784/0c73c377-c58f-8ba8-dbb7-3c1356a5e6af.png)



3. 「新規作成」を選択し、任意の名称を入力してOKをクリック。
   ![2021-05-03 14_52_15-OBS 26.1.1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1434784/c5a0bc3f-1166-7d42-8a35-4ef250a6bafe.png)


4. 表示されたVLCビデオソースプロパティウインドウ下の「**+**」マークをクリック。
   ![2021-05-03 14_55_01-OBS 26.1.1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1434784/29dacf2a-9f09-b842-304c-3e0d76b74d6f.png)


5. 「PathまたはURLを追加」をクリック
   ![PathまたはURL.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1434784/251ae717-8711-1efa-cb29-653d7ad5f9bd.png)


6. テキストボックスに控えたRTSPストリーミングURLを入力してOKをクリック。
   ![2021-05-03 14_59_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1434784/e132d144-f9b9-48e9-f0c0-3ceaa90a7d81.png)


7. 「プレイリスト」にRTSPストリーミングURLが入力されていることを確認後、再度OKをクリック。

8. カメラの映像がOBSに取り込まれていることを確認する(画像は加工済み)。
   ![2021-05-03 15_09_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1434784/a50d150b-996c-38c6-e5a9-857ae90a61c6.png)


   

## メリット・デメリット

以上で映像取り込みの説明を終わります。

このようにOBSに取り込めばTapoカメラ単体ではできないyoutubeなどの各種配信サービスでライブ配信ができますし、自身でnginxなどを利用して配信サーバーを立ててそこで配信することも可能です。録画もOBS経由でできます。

Tapo C200のように首振りに対応したTapoカメラを使えば、ライブ配信をしながら遠隔でカメラの向きを操作することもできます。

加えて、先日発表された防水防塵に対応した屋外用ネットワークカメラ「Tapo C310」を使えば、回線や電源の用意が必要なものの、山や川の様子をみたり、屋外設置の防犯カメラ代わりに使えるかもしれません。<br>https://internet.watch.impress.co.jp/docs/news/1321999.html

ちなみに本筋と関係ありませんが、OBSの仮想カメラ機能をオンにすると、zoomなどのビデオ会議ツールからOBSがカメラとして認識されるため、Tapoカメラ→OBS→ビデオ会議ツールという形でビデオ会議用カメラとして用いることが可能です。

注意すべき点は、rtspストリーミングURLにアカウント名とパスワードを入力しなければならない点です。これをそのまま入力することはセキュリティ上好ましくないため、なんらかの方法で回避すべきと考えています。

### 参考

Tapoを使用したRTSPライブストリーミングの利用方法<br>https://www.tp-link.com/jp/support/faq/2680/