OmniAICreator/Qiita-1.07M huggingface dataset:
Next.jsで"document is not defined." "window is not defined."のエラーが出たときの対処法

#Next.jsで"document is not defined." "window is not defined."のエラーが出たときの対処法

##原因
Next.jsのSSRが原因である可能性が高いです。
###SSR = Server Side Rendering
本来クライアント（ブラウザ）側でしか動かないJSフレームワークなどによるレンダリングをサーバー側で行うことによって、初期表示時の高速読み込みや検索エンジン最適化（SEO）を向上するもの。

サーバー側でJSの処理を実行しようとしているときに、ブラウザ側にしか存在しないグローバルオブジェクトの`window`や`document`を参照しようとすると、標題のエラーが起こります。

##対策
###1. `componentDidMount()`内で処理を行う
`componentDidMount()`内に書いた処理は、基本的にcomponentがmountされた後にクライアント側のみで起こる処理なので、このエラーは起こらないようです。

ただ、`componentDidMount()`はクラスコンポーネントのライフサイクルメソッドなので、関数コンポーネントでは使えません。

###2. if文で条件分岐
React Hooksが主流の現在、こちらの方が汎用性が高いです。

```javascript:ssr1.js
if (process.browser) {
  // windowやdocumentを使う処理を記述
}
```
もしくはシンプルに：

```javascript:ssr2.js
if (typeof window !== "undefined") {
  // windowを使う処理を記述
}
```
（コメントでのご指摘・編集リクエストを受けて修正）

##参考
[Stack Overflow - Window is not defined in Next.js React app](https://stackoverflow.com/questions/55151041/window-is-not-defined-in-next-js-react-app/55151122#55151122)
https://nextjs.org/blog/next-9#dead-code-elimination-for-typeof-window-branches
https://github.com/vercel/next.js/issues/5354#issuecomment-520305040
Arch Linux上でリモート授業を受けるためにしたこと


# はじめに
この記事は意地でもArch Linuxをつかってリモート授業を受けようと奮闘している学生がやってきたことを記しているだけです.
MSが手厚くLinuxをサポートしてくれるようになるまではなにかの役に立つかもしれません.
こだわらなければ~~Linux上でVMをつかって~~ Windowsを動かせば苦労はしませんし,あくまでも参考として温かい目で見ていだだければと存じます.

## 動作環境
- PC : Dell inspiron 13 (CPU i7-8550U RAM 16GB SSD 128GB(全体では512GB))
- OS : Arch Linux
- DE : Cinnamon

## 内容
- 基本的なパッケージのインストール
- Teamsのインストール

# やったこと
##基本的なパッケージのインストール
ブラウザ,オフィススイート,圧縮ファイル解凍,描画,PDFビューワなど

```shell

 sudo pacman -S firefox libreoffice-fresh file-roller inkscape nomacs evince
```

必要に応じてLaTeX環境なども

```sh

sudo pacman -S texlive-most texlive-langjapanese texlive-latexextra texlive-pictures
```

AURヘルパーのyayも導入します

```shell
git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -si
cd ..
rm -rf yay
```
yayからVSCodeなどを入れることもできます

```shell
yay -S visual-studio-code-bin
```

これで一通りいろいろできるようにはなっているかと思います

## Teamsのインストール
なぜここだけ別項目になったのか,それはAURに3つも(**3つも!!**)Microsoft Teamsのリポジトリがあるためです.
画像を見てください.一番下にある3つがMicrosoft Teamsのパッケージです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466993/5c433040-1747-c9ef-101a-f3470cecefb7.png)
`teams`と`teams-insiders`は同じバージョン[1.3.00.16851-1]ですが,これらのパッケージではうまく動かず,他のいくつかのプロセスも巻き込んでフリーズしました.
Teamsを導入するときは`teams-for-linux`をインストールするといいようです.

```shell
yay -S teams-for-linux
```
#おわりに
ここまでするのにリモート授業が始まってから2ヶ月半もかかったのでせっかくなのでメモっておこうと思い立って書きました.
足りない点などがあれば指摘いただけるとありがたいです.読んでくださりありがとうございました.
【progate復習】Python 学習メモ（随時更新）

実務でPythonやNumpy、Pandas、その他のライブラリを使うことはありましたが、
自分の知識が歯抜けなのを自覚していたので、
今回Progateで1から復習しようと思いました。

progateの学習コースの上級の知識は知っているのに
初級のある部分が抜けていたりと、本当に歯抜けの知識です。

抜けている部分をメモしていこうと思います。（随時更新）

---

**辞書**

※注意　ゲーム「CLOCK ZERO～終焉の一秒～」のネタバレを含みます

```script01.py


#Chara = {'King':'Takato', 'Wonderer':'Riichiro', 'Bishop':'Madoka', 'Traitor':'Toranosuke', 'Philosopher':'Syuya'}

#長い辞書を見やすくする
Chara = {'King':'Takato',
         'Wonderer':'Riichiro',
         'Bishop':'Madoka',
         'Traitor':'Toranosuke',
         'Philosopher':'Shuya'}

print('攻略対象は以下の5人です。')
for target in Chara :
   print (Chara[target])

#辞書要素の追加
Chara['Journalist'] = 'Nakaba'
print(Chara)
print('2015年発売のExtimeから' + Chara['Journalist'] + 'が攻略対象に追加されました。')

```

<BR>

**ループ処理のスキップ continue**

```script02.py
numbers = [1, 2, 3, 4, 5, 6]
for number in numbers :
   if number % 3 == 0 ;   #変数numberが3の倍数の時
      continue            #ループ処理をスキップ
   print (number)
```








---

**私の経歴について**

プログラミング歴は1～6年ちょい？？
OA事務として仕事していたときに
Windowsのバッチスクリプトをゴリゴリ書いて業務を自動化したり、
Excel VBAで数値計算用のデータを整理したりしていました。
ある数値計算プログラムを動かすのにシェルが必要だったので
WindowsにCygwinを入れてシェルのコードを書いたり
fortranのコードを書き直したり。
（当時は77と90の違いが分からなかった！）
ソフト上でデータベースを扱っていたので
SQLの仕組みも知っているけどコードは分からない。
本当に変な経歴です。
nuxt-telemetryとはなんぞや？

### はじめに
Nuxtをローカルで立ち上げると、見慣れない文言がターミナルに出てきました。
<img width="505" alt="スクリーンショット 2020-07-14 10.22.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252687/7dacc533-2a83-a68f-79ed-60a657136165.png">

なんだなんだ？「てれめとり」だって？
普段通りに立ち上がらないと一瞬焦りますが、どうやら新規仕様のようです。

### Nuxt Telemetryとは

なるほどNuxt 2.13で導入されたモジュールらしく、Nuxt機能の使用状況やカスタマイズ状況などの統計を取るものらしいですね。

<img width="603" alt="スクリーンショット 2020-07-14 10.24.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252687/ca2c6860-8cb1-405e-819e-f5198214f1fd.png">

収集データ例
- SSRモードかどうか
- TypeScriptビルドかどうか
- ビルドコマンドは何か（nuxt dev, nuxt build）
- etc

先ほど現れた文言は、その情報収集に対して同意するかどうかの確認だったっぽいですね
yes/noを選んでenterで進みましょう。すると今まで通りのビルドが走ります。

安心:relaxed:

### 間違えてYesを押してしまった場合
READMEにも書いてありますが、取り消し/変更には３つの方法があるそうです

#### 1.`nuxt.config`に以下を追加する

```nuxt.config.js
export default {
  ....
  telemetry: false
  ...
}
```
#### 2.環境変数で指定する
dotenvやcross-envを使っている人はそちらで指定ですね

```env
NUXT_TELEMETRY_DISABLED=1
```
#### 3.ターミナルでコマンドを打つ
対象のプロジェクトルートに行って、`npx nuxt telemetry disable`を入力
<img width="568" alt="スクリーンショット_2020-07-14_10_36_57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252687/cf53b231-73ec-8ec2-3b13-0dda9ada821f.png">
こちら実際にやってみると上記のようなメッセージが出ました。
そして、`.nuxtrc`というファイルが自動生成されました。
<img width="557" alt="スクリーンショット_2020-07-14_11_28_45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252687/d69029e7-94f9-894b-dec0-726568fa7ed6.png">

ここを編集するだけでまた切り替えできそうですね！


### さいごに
こういったデータの提供は任意ですので、懸念がある方などは参加する必要はないと思います。ただ、集計データが気になる自分としてはいろんな人が積極的に参加して世界でどんな感じにnuxtが使われているのか見てみたいなという好奇心も強くあります。

次は実際にこのモジュールの中身のソースコードを見て解説記事にしてみたいと思います

### 参考
https://github.com/nuxt/telemetry
[docker]dockerなにそれからのhello world　

#目的

- 環境構築や環境の差で問題解決が遅れるの（時間がかかる）のは面倒なので使いこなせるようになりたい。

#dockerって簡単にいうと？

PC内のコンテナ型の仮想環境のこと。
コンテナ型の他に、ホスト型、ハイパーバイザー型がある。

「コンテナ」と呼ばれるゲームのカセットのように入れ替えて開発環境を変更することができる。
また、ゲームのカセット（コンテナ）は、「イメージ」から作ることができる。

#なぜdockerが必要になのか？

「あっちのPCではできるけどこっちのPCではできない！」のようなローカル環境など開発環境の差を吸収し、環境構築やデプロイのスピードを向上する。


カーネルとシェルの関係のように、dockerはdockerクライアントから操作する必要がある。

#まずはHello worldまで

①DockerHubの登録とDockerクライアントのインストール

②ターミナルで```docker login```
　 ※もし反応しない場合はDockerが起動しているか確認。

③```docker pull hello-world```　
　これでコンテナの元になるイメージを取得。
　 ※```docker images```で現在取得しているイメージを確認できる。

④```docker run hello-world``` hello-worldイメージからコンテナを作り起動。

　※ちなみに、runはイメージ取得＋コンテナ生成＋コンテナ起動まででき、pullはイメージ取得だけのコマンド。
<img width="721" alt="Screen Shot 2020-07-13 at 21.48.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665832/f04b3fb4-010f-4ea2-c2c5-06e6558c3f54.png">


コンテナをつけっぱなしではなく、取引の度に消すこともありえるので、コンテナを作ってdockerイメージに返すということができる。

#今後理解したいこと

- コンテナを作って、dockerイメージに戻す。
salesforce vfページの参照画面に新規ボタン追加

①カスタムボタンまたはカスタムリンク追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393170/35b37aa1-9c9a-7eae-1aaa-32fe82eca3ad.png)

```javascript
{!REQUIRESCRIPT('/soap/ajax/46.0/connection.js')} 
{!REQUIRESCRIPT('/soap/ajax/46.0/apex.js')} 

var ret = sforce.apex.execute('ClassName','CreateObject',{}); 
location.href = ret;
```

②Apexクラス作成 　３桁のPrefix取得

```apex:ClassName.cls
global class ClassName {
    webService static String CreateObject() {
        String prefix = CustomObject__c.sObjectType.getDescribe().getKeyPrefix();
        return URL.getSalesforceBaseUrl().toExternalForm() + '/' + prefix + '/e?&retURL=%2F' + prefix;
    }
}
```
③画面表示　新規ボタンをキリックして、新規画面へ遷移
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393170/b26c877a-0817-6640-2daa-74b6a659dfe8.png)
Microsoft Teamsでクラウドストレージの利用を禁止する方法

自分用のメモです。

①管理センターにアクセス
https://admin.teams.microsoft.com/

②左ペインから「組織全体の設定」＞「Teams の設定」を選択
https://admin.teams.microsoft.com/company-wide-settings/teams-settings

③「ファイル」の選択肢を全部OFFにする。



20200727追記
OneDriveは制限できなさそう。これどうやるんだろ。。。
後回しにしてたけどそろそろいるかも？
Pycharmの日本語化

![pycharm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643675/6b77a252-f81f-04ef-ff9b-f6dd3824728f.png)

環境　windows7 32bit

公式サイトから日本語化zipファイルをダウンロードして解凍先から.exeを実行しても~.dllがありませんと
日本語化出来ずにハマりました。

少しだけのコツであっさり日本語化出来ました。

#Pycharm日本語化

1，まずは日本語化のプラグイン本体をダウンロード

[ Pycharm:日本語化プラグイン本体](https://mergedoc.osdn.jp/)

2，解凍先に**Pycharmのフォルダ**を選択

3，解凍先から.exeを実行する

4，Pycharmを立ち上げる

これだけでした。

ちなみに私のPycharmのインストール先は
C:\Program Files\JetBrains\PyCharm Community Edition 2018.3.7\bin
にありました。

fin
【C#】ジェネリック

★ジェネリックとは
・様々な型に対応できるようにパラメータとして与え、オブジェクトを定義できるようにした機能

◇ジェネリッククラス
特定のデータ型の引数の差異を一元化してコードを簡略化することが可能

```C#:ジェネリッククラスの記述方法
//型に依存していない場合
public class SampleJeneric<VAR>
{
    public VAR Test(VAR a1){ return a1; }
}

//型に依存しているメソッドを呼び出す場合
public class SampleJeneric<VAR>
    where VAR : struct
{
    public VAR Test(VAR a1){ return a1; }
}
```
<br>◇ジェネリックメソッド
・様々なデータに対応したメソッド
・引数の数やデータ型、戻り値の型を指定

```C#:ジェネリックメソッドの記述方法
int Min<T>(int a, int y)
 where int : IComparable
{
    return a.ComparaTo(b) < 10 ? a : b;
}
```

★ジェネリック型制約
・ジェネリックメソッドの型引数が持つ機能を指定し、対応できるようにします。
・各製薬は併用指定可能

**ジェネリック型制約の種類**

|種類|内容|
|:--|:--|
|where T:struct|値型のみ<br>値型と参照型を参照<br>他制約と併用する場合は最初に記述|
|where T:class|参照型のみ<br>他制約と併用する場合は最初に記述|
|where T:クラス名|指定したクラス、またはその派生クラス|
|where T:インターフェース名|指定したインターフェイスクラスを継承するクラス|
|where T:new()|引数無しのコンストラクターを持つクラス<br>他制約と併用する場合は最初に記述|
|where T:unmanaged|アンマネージ型<br>値型をポインタで扱う場合に使用|
vue-good-tableの検索ボックスに前回の検索キーワードを入れる

vue-good-tableの検索ボックスに、ローカルストレージなどに保存しておいた前回の検索キーワードを入れておく方法です。

## 環境

- Vue.js 2.6.11
- vue-good-table 2.16.3

## HTML

vue-good-tableタグ内のrefで任意の名前を与えます。

```html
<vue-good-table
  ref="my-table"
  :columns="columns"
  :rows="rows"
  :search-options="{
    enabled: true
  }">
</vue-good-table>
```

## Vue.js

mountedで先ほど名前を与えたコンポーネントを取得し、そのglobalSearchTermにローカルストレージなどから取得した前回の検索キーワードを渡します。ここでは「my initial value」を代入しています。

```js
// in js
mounted() {
  this.$refs["my-table"].globalSearchTerm = "my initial value";
}
```

## サンプル

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="MtDeity" data-slug-hash="jOWpRwr" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="vue-good-table initial global search">
  <span>See the Pen <a href="https://codepen.io/MtDeity/pen/jOWpRwr">
  vue-good-table initial global search</a> by Kamiyama (<a href="https://codepen.io/MtDeity">@MtDeity</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## 参考

[Global Search reset · Issue #452 · xaksis/vue-good-table](https://github.com/xaksis/vue-good-table/issues/452)
個人用メモ：CSSで縦を自由にリサイズする方法

#結論
![上下操作.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493888/2337185c-b53f-7038-c7d8-bbb0db07fe0f.gif)

```html
<!DOCTYPE html>
<html lang="ja">

<head>
    <title>test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="UTF-8"/>
    <!-- FontAweSome -->
    <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
    <!-- JQuery -->
    <script
        src="https://code.jquery.com/jquery-3.5.1.js"
        integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
        crossorigin="anonymous">
    </script>
    <!-- bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
</head>
<body>
    <!--  -->
    <div class="container all-container">
        <div class="sub-container">
            <div class="area area1"></div>
            <div class="area area2"></div>
            <div class="area area3"></div>
            <div class="area area4"></div>
            <div class="area area5"></div>
        </div>
    </div>
</body>
<style>
    .all-container {
        height: 100vh;
    }
    .sub-container {
        height: 100%;
        background-color: #696969;
        overflow-y: scroll;
        -ms-overflow-style: none;/* IE, Edge 対応 */
        scrollbar-width: none;/* Firefox 対応 */
    }
    .sub-container::-webkit-scrollbar {
        display:none;/* Chrome, Safari 対応 */
    }
    .area {
        height: 20%;
        border: solid 1px rgb(37, 37, 37);
        resize: vertical;
        overflow: hidden;
        background-color: #696969;
    }
    .area1 {
        min-height: 200px;
    }
    .area2 {
        min-height: 100px;
    }
    .area3 {
        min-height: 50px;
    }
    .area4 {
        min-height: 150px;
    }
    .area5 {
        min-height: 250px;
    }
</style>
</html>
```
IntelliJでプロジェクトを開いた際に、指定したコマンドが自動実行されるように設定する

特定のプロジェクトを開いたらDBなどを起動する、という使い方をしている。

# 環境
IntelliJ IDEA Ultimate Edition 2023.1.2

# 手順
(1) Settingsを開く。

(2) Settingsの[ツール]-[スタートアップタスク]を開く。

![スクリーンショット 2023-05-26 8.16.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/6010a679-2e0d-e129-ae5a-db38021978dd.png)

> メニューの配置はバージョンアップでよく変更されるので、検索キーワードに「スタート」と入力して検索するといいかもしれません。

(3) 画面左上の[+]をクリック→[新規構成の追加]→[Shell Script]を選択

![スクリーンショット 2023-05-26 8.18.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/0901df14-7a01-e129-24bb-ec4f857632f7.png)

(4) 次のように入力

- 名前: 適当な名前
- 実行: スクリプトテキスト
- スクリプトテキスト: 実行したいコマンド（例えばdocker composeでDBを起動するとか）
- 作業ディレクトリ: 適当なディレクトリ
- 環境変数: 必要があれば設定
- ターミナルで実行: チェックを入れる

![スクリーンショット 2023-05-26 8.22.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/f86608f1-39f7-7751-1435-38f6611859bb.png)

> [実行]で[スクリプトファイル]を選べば、ファイルに書かれたシェルスクリプトを実行することもできます。

(5) [OK]をクリック
Javaプロセスのログを削除後、ログが出力されなくなった

Linuxサーバ検証環境でログが蓄積していたのでファイル名を置き換えた
その後Javaプロセスを再起動したが思うようにログが吐かれない…

⇒rsyslogプロセスを再起動することで解消。
rsyslogのログ転送対象になっていたため、手動で削除した時に関連付けがおかしくなったのかもしれない。
【C#】XMLドキュメントコメントのタグ一覧

###C#のXMLドキュメントコメント記述の際に使用されるタグの一覧

|タグ名|内容|
|:--|:--|
|summary|型また型のメンバの概要|
|remarks|追記(追加情報)|
|value|プロパティ値説明|
|para|記タグ内で段落作成が可能<br>summary・remarks・returns|
|param|メソッドパラメータ、型自動判定|
|typeparam|ジェネリック型[^1]パラメータ、型自動判定|
|paramref|インラインのパラメータ参照|
|typeparamref|ジェネリック型[^1]パラメータ参照|
|returns|戻り値|
|exception|例外|

```C#:タグの記述方法
/// <summary>概要の説明</summary>
/// <remarks>備考</remarks>
/// <value>プロパティ値説明</value>
/// <para>段落テキスト</para>
/// <param name="メソッド パラメータ名">パラメータの説明</param>
/// <paramref name="参照パラメータ名" />
/// <typeparam name="型パラメータ名>型パラメータの説明</typeparam>
/// <typeparamref name="参照パラメータ名" />
/// <returns>戻り値の説明</returns>
/// <exception cref="member">例外説明</>
```
[^1]: [ジェネリックとは](https://qiita.com/sasami_dc2/items/aac978a31fb8b5245355)
ターミナルでコマンドを実行した時に出てきた「qoute>」の消し方

ターミナルを触りたての頃、コマンドを実行した時に

`qoute>`

というよくわからないメッセージが出てきて、

-deleteしてみるも全く動かなかったり
-qouteと入力してもまた次の行で「quote>」と出てきたり
-よくわかないからenterを押しまくって「quote>」地獄に陥ったり

そういうことがあるかと思います。（実体験）


##　原因と対応策

原因としては、「'」とか「`」とかクォート系が1個紛れ込んだためです。

ターミナルは入力が続いてると判断するので、コマンドを打ち切らずに入力を継続させるようになっており、その結果、「quote>」と続きをどうぞというメッセージが表示されてしまいます。

**Ctrl+c**を押すことで前文のコマンドを強制終了出来るので、落ち着いて対処してください。


このメッセージは「' ''」のようにシングルクォートが余分に１つ含まれていたり、「' "」のようにシングルクォートとダブルクォートが混じったときにも表示されます。
【rspec】fill_inがあっているのにfetureテストが失敗する原因　ログインで失敗してない？

# rspecのfeatureテストが通らない
capybaraでわかりやすくて便利なのですが、fill_inハマったので解決策の１つを紹介します。

expect内のfiii_inのところでどうしてもエラーが起きてしまう。

検証して生成されたhtmlから見つけたidを指定しても、新たにidを作っても、findを使ってもできませんでした
。。

しかし数時間の格闘の末結論が出ました。

##この記事のゴール
fill_inのエラー解決策の１つとして検証してみてください！

## 結論　ログインに失敗している

自分の場合は結論ログインがうまくできていないためエラーが起きていました。

失敗したコード

```rby:topics_spec.rb
scenario "user creates a new topic" do
    user = FactoryBot.create(:user)
    visit root_path
    click_link "ログイン"
    fill_in "Email", with: user.email
    fill_in "Password", with: user.password
ココ→ click_link "ログイン"

    expect {
      visit new_topic_path
      fill_in "topic_description", with: "test"
      click_button "投稿"
      
      expect(page).to have_content "投稿しました"
      expect(page).to have_content "test"
      expect(page).to have_content "#{user.name}"
    }.to change(user.topics, :count).by(1)
```
<img width="1245" alt="スクリーンショット 2020-07-14 9.39.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637746/6a5d1da6-2d50-436f-6ac8-c153bd770c2d.png">



click_linkでログインを指定ためsubmitではなくヘッダーのリンクをクリックしていました。
そのためログインページでメールアドレスとパスワードを入力して、もう一度ログインページをクリックしていました。。
なんと不毛なことを。。。。


ということでclick_linkではなく、click_buttonを指定。

```rby:topics_spec.rb
scenario "user creates a new topic" do
    user = FactoryBot.create(:user)
    visit root_path
    click_link "ログイン"
    fill_in "Email", with: user.email
    fill_in "Password", with: user.password
ココ→ click_button "ログイン"

    expect {
      visit new_topic_path
      fill_in "topic_description", with: "test"
      click_button "投稿"
      
      expect(page).to have_content "投稿しました"
      expect(page).to have_content "test"
      expect(page).to have_content "#{user.name}"
    }.to change(user.topics, :count).by(1)
```

これでちゃんと通りました。

## まとめ
fill_inでエラーが起きているのでfill_inばかり見ていましたが、一度立ち止まって全体を見ることの重要性を再認識できました。

参考になれば嬉しいです！
【技術書】Pythonによるデータ分析入門 -1章 はじめに-

本書で使うデータファイルや関連する素材は下記のGitHubレポジトリ
https://github.com/wesm/pydata-book
要点をまとめた備忘録


目次
---
1. 覚えておくとよいこと
2. 必須のPythonライブラリ
3. 専門用語等
4. 感想等

覚えておくとよいこと
---

- 優秀なデータ分析者になることを目的に書かれており、データ分析のために必要なプログラミングをPythonによって行うための知識を学ぶ本。
- PythonはDjnagoなどのウェブフレームワークを使って、ウェブサイトの構築によく利用されている。データサイエンス、機械学習、一般的なソフトウェア開発において、最も重要な言語の１つ。
- pandasやscikit-learnといったライブラリのサポートの改善により、Pythonはデータ分析における有力な選択肢になった。
- Pythonはインタプリタ型言語なので、実行速度が遅い。待ち時間が短いことが求められるアプリケーションや、リソースの有効利用を要求するようなアプリケーション（例えば高頻度の取引システム）などでは、C++のような低レベル言語で性能を極限までに高める方が、有効な時間の使い方になる。
- Pythonは、並列でマルチスレッドなアプリケーションを開発する言語としては難易度が高い（GILという機構による）

必須のPythonライブラリ
---
**Numpy** 
Pythonにおける数値計算の基盤で、データ構造やアルゴリズムを提供
高速で効率的な多次元配列オブジェクトndarrayや数学的演算が代表的。

**pandas**
2010年に登場。
主要なオブジェクトはDataFrame = テーブル形式で列指向のデータ構造
numpyの高性能な配列計算機能と、スプレッドシートやリレーショナルデータベースのデータを(SQLのように）柔軟に操作する機能を併せ持つ。
pandasはこの本で主に扱うものの１つ。
データの操作や準備、クリーニング等行える。

**Matplotlab**
グラフなどの２次元形式の可視化に用いる最も一般的なPythonのライブラリ。
デフォルトで使う可視化ツールとして安全な選択肢

**IpythonとJupyter**
IPythonは、編集して実行して試行錯誤する状況での利用を推奨
2014年に、IPython web notebookはJupyter Notebookに変わり、今では40以上のプログラミング言語をサポートしている。Ipythonは、JupyterでPythonを使うためのカーネルとして使われている。
Jupyter Notebookは、ウェブベースでコードを書くための「ノート」である。
MarkdownやHTMLで内容を編集できるため、コードと文章が混在したリッチなドキュメントを作ることができる。

**SciPy**
科学計算の領域における一般的な問題を扱うパッケージを集めたもの。
NumpyとSciPyを一緒に用いることで、それらを合理的で成熟した計算基盤として使うことができ、多くの伝統的な科学計算に適用できる。

**scikit-learn**
一般的な「機械学習ツール」のトップに立つ。
分類、回帰、クラスタリングを始めとするサブモジュールや、交差検証、前処理など

**statsmodels**
scikit-learnと比べ古典的な統計分析用パッケージ。

専門用語等
---
- Python 2.xは「レガシー Python」、Python 3.xを単に「Python」と呼ぶ
- **マンジング、ラングリング** … 構造化されていなかったり、乱雑なデータを構造化されたきれいな形式に操作するプロセス全体のこと。
- **疑似コード** … アルゴリズムやプロセスを説明するため、ソースコードに似た形式で説明するもの。
- **シンタックスシュガー** … 新機能を追加するわけではないが、入力を便利にするようなプログラミング言語の文法のこと。

感想等
---
初めてのqiita投稿は技術書の備忘録
復習に応じて編集したりしよう
qiitaで技術発信、人に見てもらいたいことを載せたりする
なるべく自分の言葉で書く。完璧を求めすぎず。
人に見てもらうというのは大変良いモチベーション、かつ勉強が効率的に進む。
全ては書けない、覚えておきたいことや理解に頑張ったこと、興味を持ったことをまとめる
AWS認定をピアソンVUEのテストセンターで受験した（カメラ監視やチャットはなかった）

:::note alert
この記事は2020年7月時点の情報です。現在とはかなり異なっています。
:::

AWS認定の試験をピアソンVUEのテストセンターで受けてきたので、体験記をダラダラ書きます。

# 主なトピック
- **カメラによる監視や試験官とのチャットはなかった**
- **両手を机に出していないと怒られるということもなかった**
- **結果は試験後すぐに表示された**
- **所要時間は60分くらいだった（CLFの場合）**
- **会場は割と良かったのでリピートしたい**

# 概要

- 受験日　**2020/07/10(土)**
- 試験名　**AWS認定 クラウドプラクティショナー** (CLF)
- 会場　**渋谷テストセンター**
  - [公式サイト](https://cbt.e-ntk.co.jp/testcenters/77)
  - [Google Map](https://goo.gl/maps/ZjcZ5bqpQx5isPgV6)

なぜオンライン受験にしなかったかというと、自宅をカメラに写したくなかったからです。

# 会場について

「テストセンター」という施設に行くのは学生のころSPIを受けたのが最後。キレイで広い会場だった記憶が。

それをイメージして渋谷テストセンターに行ったら**会場がコンパクトで驚く。** 小さな古めの雑居ビルの5階にあったが、テナント全体で学校の教室1個分か、それより少し広いくらい。受付や待機スペースもあるので、試験の部屋はさらに小さい。

でも古いながら**そこそこ清潔感あっていい感じだった。**

# 当日の流れ

## 試験前

何も考えず30分前に到着する。受付でフルネームを訊かれ、説明書(的な紙)と受付書(的な紙）を渡される。説明書には試験上の注意がギッシリ。受付書は5箇所くらい埋めてサイン。

受付書を提出し、**身分証明書(2点)の確認**や**写真撮影(顔のみ)**のあと、ロッカーの鍵を渡される。**「身分証明書のうち1点」以外はロッカーにしまうよう言われた。**（ティッシュはセーフみたいな記事も見かけたが、そんな説明は受けなかった）

ロッカーへの預け入れを終えると、すぐに「どうぞ〜」と受付に呼ばれる。試験場の注意事項を口頭で伝えられ、**ペンとホワイトボード（正確に言うと、ラミネートされたA4用紙）を渡される。** さらにマスクとメガネを外すよう言われ、**マスクの裏側とメガネの裏側を確認された。** メガネの裏側見るんだ。

そしていよいよ試験の部屋に入室。試験開始10分前まで待機したという記事も見たが、**自分は待ち時間ゼロだった**（コロナで空いていただけかもしれない）。会場入りからここまで10分。

## 試験中

机に置いてあったイヤーマフは使わず。PCはほぼ想像通りだったが、**カメラは付いていなかった。**

部屋に大きな窓ガラスがあり、受付のスタッフが随時目視で監視していた模様。**両手を机の上に出していないと注意されるという話も聞いたが、そんなことはなかった**（というわけで試験中ずっと左手を机の中にしまっていた）

画面は最初に注意事項やUIの説明が表示され、試験が始まると問題が1問ずつ表示される。**チャットもついていなかった。** あるのは問題と残り時間と残り問題数だけ。

入室前の説明によると「何かあればボタンでスタッフを読んでください」とのこと。確かにPC横にファミレスにあるようなボタンが置いてある。したがって**PC操作もマウスのみ**で、キーボードは一切使わなかった。

試験中は**問題に「あとで見直す」フラグを立てられる。**全問問いたあとに問題一覧が表示され、そこから**「あとで見直す」のついた問題を一気に表示することができた。**

全65問あり、自分は40分くらいで解き終えた。

## 試験後

「試験を終える」的なボタンを押すと、すぐにアンケート（全9問）が始まる。そしてアンケートを終えると**すぐに合否が表示された。予想していなかったのでとてもビビったw**

事前に「画面が黒くなったら退室してください」と言われていたとおり、画面が黒くなったので退室する。ペンとホワイトボードを返却し、再度マスクの裏側を確認された（今度はメガネの裏側は確認されなかった）

最後に受験証明書(的な紙)をもらって終了！ 「合否は5営業日以内に出ます」って書いてあるが、さっき合格って表示されたんだが？

# 感想

- **英語チャットとカメラ監視がないのは良かった**
- 会場入りから退出まで1時間ほど。とてもスムーズで良かった
- 渋谷テストセンターは(たまたまかもしれないが)待ち時間が短く、立地も良かったので**リピートしたい**

# 類似記事

自分の受験前に以下のQiita記事が大変役に立ちました。ありがとうございました。私の体験と違う箇所もあるので、読み比べてみてください。

[ピアソンVUEでAWS認定試験を受けてきた](https://qiita.com/amamillen/items/79bcc20973afac94adeb) (2019/04/24)

# おわりに

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

:::note alert
この記事は2020年7月時点の情報です。現在とはかなり異なっています
:::
railsにgRPCクラアント導入

# 経緯
会社でPMを担当しているプロダクト(Rails)の実装で他のサービスから情報を取得する必要があり、そのサービスがOpenAPIでなく、gRPCでAPIインタフェースが定義されていたので、gRPCのクライアントを実装しました。
僕が前職でrailsでのgRPC周りを少し触っていたので、相対的に僕がやった方がチームの開発工数が増えると思ったので自分でやることにしました。
それについてのアウトプットです。

# 実装手順
##### 1. gem導入

※前職で使っていた[gruf](https://github.com/bigcommerce/gruf)というライブラリを使いました。

```ruby:Gemfile

gem "google-protobuf" 
gem "grpc-tools"
gem "gruf"
```

※ webというコンテナで開発してる

```
docker-compose run --rm web bundle install
```

##### 2. protoファイルが管理されているリポジトリをsubmoduleでアプリケーションのサブディレクトリとして登録して、protoファイルを元のリポジトリから取ってくる

```shell
$ git submodule add [web URL or ssh key] proto
$ git submodule init
$ cd proto
$ git submodule update
```

##### 3. protoファイルをrubyファイルにコンパイル

```
docker-compose run --rm web grpc_tools_ruby_protoc -I [コンパイル対象のprotoディレクトリ] --ruby_out=[コンパイル後のファイル保存先のディレクトリ] --grpc_out=[コンパイル後のファイル保存先のディレクトリ] [コンパイル対象のprotoディレクトリ内の対象ファイル]
```

##### 4. コンパイル後のrubyファイル(*_pb.rb)の読み込み設定

コンパイル後のファイルは、ファイル名と、クラス名が噛み合っておらず、Railsの読み込み規則に則っていなく自動読み込まれないので、指定してあげる必要がある。

```ruby:config/initializers/gruf.rb
require "gruf"

Gruf.configure do
  Dir.glob(Rails.root.join("[コンパイル後のファイル保存先のディレクトリ]/*_pb.rb")).each do |file|
    require file
  end
end
```

コンパイル後のファイルでは下記のように自動で指定されており、`auto_load_path`に追加しておく必要がある。
e.g. [gruf-demo](https://github.com/bigcommerce/gruf-demo/blob/master/app/rpc/app/proto/Products_services_pb.rb)から
`require 'Products_pb'`

※コンパイル後のファイルは基本修正しないので。

```ruby:config/application.rb
  class Application < Rails::Application
    config.paths.add [コンパイル後のrubyファイルディレクトリ], eager_load: true
  end
```

##### 5. クライアントがサーバをコールする部分の実装

ここまでで、全てのコンパイル後のrubyファイルは使えるようになったでのクライアントの実装。

moduleにしようかとか悩みましたが、既存の実装でクライアント系の処理はservice層にまとめていたので、今回もそれに習う形にしました。

※特に`metadata`周りはサーバ側の実装に依存するので注意。
[grufのwiki](https://github.com/bigcommerce/gruf/wiki/Client%3A-Making-Your-First-Call)だと、クライアントの初期化(`Gruf::Client.new`)時の`options`引数のキーで`username`を入れていたりとこの辺が今回の実装と違っており、若干悩みました。

```ruby:app/services/grpc_client_service.rb

class GrpcClientService
  def initialize
    @metadata = {
      login: ENV["GRPC_CLIENT"],
      password: ENV["GRPC_PASSWORD"]
    }
  end

  def run(service_klass, method, request)
    client = Gruf::Client.new(
      service: service_klass,
      options: {
        hostname: ENV["GRPC_HOST"],
        channel_credentials: :this_channel_is_insecure
      }
    )

    client.call(method, request.to_h, @metadata)
  end
end
```


## 導入してみての感想とか
前職でgrufは使っていたので、余裕かと思っていましたが、やはり導入するのと、ただ使うだけでは結構違うなと思いました。
しっかり設定周りのコードを読んでおけば良かったと後悔してます。

また、今回gRPCサーバがgoで書かれており、クライアントからのコールがうまく行かないときにコード読むのに苦労して結局諦めたので、goも勉強したいなと思いました。

また少し詰まったのは、クライアントの初期化(`Gruf::Client.new`)時に`metadata`を入れると謎の勘違いしており(本当はcall時の引数に入れる)、ライブラリのWikiに書いてないことはやはり、しっかりコード読まないといけないなと初歩的なことを改めて実感しました。
IBM Cloudの仮想サーバーをGoogle Colaboratory の ローカルランタイムとして使用する

[こちら](https://qiita.com/schiyoda/items/44cdcf0574602f1e776b)の記事でIBM Cloud上の仮想GPUサーバーをDockerコンテナで使用する方法を紹介しました。今回はこの環境をGoogle Colaboratoryのローカルランタイムとして使用する方法を紹介します。Google Colaboratoryが提供するホスト型ランタイムは12時間の制限がありますが、ローカルランタイムを使用すると無制限に使用することが可能です。

# 1. NVIDIA Container Toolkit環境の構築
[こちら](https://qiita.com/schiyoda/items/44cdcf0574602f1e776b)に従ってNVIDIA Container Toolkitの環境を構築します。

# 2. Jupyter Notebookの起動
以下のコマンドでDockerコンテナ上でJupyter Notebookを起動します。

```console
$ docker run -it --gpus all -p 8888:8888 tensorflow/tensorflow:latest-gpu-jupyter \
jupyter notebook --ip 0.0.0.0 --no-browser --allow-root --NotebookApp.allow_origin='https://colab.research.google.com'
```

以下のようにJupter Notebookの接続先が表示されます。

```console
http://10313cb03051:8888/?token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```


# 3. ポートフォワーディングの構成
ローカルのPCでポートフォワーディングの構成をします。

```
ssh schiyoda@169.62.141.xxx -L 8888:localhost:8888 -N
```

# 4. Google Colaboratoryから接続
Google Colaboratoryで「ローカルランタイムに接続」を選択し、バックエンドURLを指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/f5caf7bf-c35a-22f5-dfb8-f02d33be9087.png)

接続ができると、nvidia-smi コマンドでGPUの構成が見えるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/540ff150-7e75-c3ac-9062-74029ab456c1.png)


## 参考
以下のように起動のオプションでDockerやJupyter Notebookの起動時の設定が可能です。

```console
docker run -it --gpus all -p 8080:8080 -v ~/workspace:/tf tensorflow/tensorflow:latest-gpu-jupyter \
jupyter notebook --ip 0.0.0.0 --port 8080 --no-browser --allow-root --NotebookApp.allow_origin='https://colab.research.google.com'
```

`-p` : Dockerのポートフォワードの設定
`-v` : ホストのディレクトリをコンテナ上にマウント
`--port`: Jupter Notebookの起動ポート
【XML】XMLタグ

★XMLタグとは
XMLは**拡張可能なマークアップ言語**のためHTMLで使われるようなタグを使用することができ、それをXMLタグと言う。
XMLタグは任意のタグ名で定義することが可能。

```XML:XMLタグの記述方法
<要素名>要素の内容</要素名>
```

また開始タグ内に属性を設定することができる

```XML:XML属性の記述方法
<!ATTLIST 要素名 属性名 属性のデータ型 属性値>
```

```XML:XMLの属性宣言(例)
<!ATTLIST xml:lang CDATA 'jp'>
```
railsアンインストール時のエラーの対処法(Directory not empty @ dir_s_rmdir - /Users)

諸事情により現在利用していたRails6.0から5.3へバージョンダウンする事になったのですが、

$ gem uninstall rails

を実行した際に以下のようなエラーが発生しました。

ERROR: While executing gem ... (Errno::ENOTEMPTY)
Directory not empty @ dir_s_rmdir - /Users/ユーザ名/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/rails-6.0.3.2

このエラーの原因はインストールの際に管理者権限で作成していたからで、対処法としては冒頭にsudoをくっつけて、Enterを押せば、以下の成功メッセージが表示されました。

sudo:UNIXおよびUnix系オペレーティングシステムのプログラムの1つで、ユーザーが別のユーザーの権限レベルでプログラムを実行するためのコマンド

$ sudo gem uninstall railties -v '6.0.3.2'
Successfully uninstalled rails-6.0.3.2



ただまだこれで終了ではなく、railtiesというRailsのコアライブラリをアンインストールする必要があります。


次のコマンドを行いメッセージが表示されれば、指定したバージョンのアンインストールは完了です。(sudoを忘れずに)



sudo gem uninstall railties -v '6.0.3.2'
web-console-4.0.3 depends on railties (>= 6.0.0)
If you remove this gem, these dependencies will not be met.
Continue with Uninstall? [yN]  y
Successfully uninstalled railties-6.0.3.2


念の為、最後にチェックしておきましょう。command not foundと表示されていればバッチリです。

$ rails -v
rbenv: rails: command not found
Goでクッキーをブラウザに渡したり取得したりしてみる

Goの標準パッケージを使ってクッキーの操作をやってみました。

#クッキーをブラウザに渡す
コードはこんな感じです。

```go:main.go
package main

import (
	"net/http"
	"log"
)

func setCookie(w http.ResponseWriter,r *http.Request){
	c1:=http.Cookie{
		Name: "cookie1",
		Value:"Hello World!",
		HttpOnly: true,
	}
	c2:=http.Cookie{
		Name:"cookie2",
		Value:"Hello Quita!",
	}
	http.SetCookie(w,&c1)
	http.SetCookie(w,&c2)
}

func main(){
	http.HandleFunc("/set_cookie",setCookie)
	log.Fatal(http.ListenAndServe(":8080",nil))
}

```

実行して　[localhost:8080/set_cookie](localhost:8080/set_cookie)　をブラウザで開くと一見なにも変化がないこのような画面になります。
<img width="1566" alt="スクリーンショット 2020-07-13 20.41.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649199/71877f2e-55ea-a5f4-5b08-ec7b74472017.png">

しかし、Chromeの検証でApplication>Storage>Cookiesを見るとこのようにクッキーがブラウザに渡せていることがわかります。
次は逆に渡したクッキーをブラウザから取得し、画面に出力してみます。
<img width="1792" alt="スクリーンショット 2020-07-13 20.44.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649199/eaed66cd-8229-5509-6943-70f4c3b8b82a.png">

##クッキーをブラウザから取得
コードはこちらです。

```go:main.go

package main

import (
	"fmt"
	"log"
	"net/http"
)

func getCookie(w http.ResponseWriter,r *http.Request){
	//名前が"coockie1"であるクッキーを取得
	c1,err:=r.Cookie("cookie1")
	if err!=nil{
		log.Fatal(err)
	}

	//c1を出力
	fmt.Fprintln(w,c1)

	//クッキーをスライスで全取得
	cSlice:=r.Cookies()

	//cSliceを出力
	fmt.Fprintln(w,cSlice)


}

func main(){
	http.HandleFunc("/get_cookie",getCookie)
	log.Fatal(http.ListenAndServe(":8080",nil))
}
```

http://localhost:8080/get_cookie にアクセスするとこのように先ほどブラウザに渡したクッキーを取得できていることがわかります。
メソッドCoockies()はすべてのクッキーをスライス形で返します。
<img width="1547" alt="スクリーンショット 2020-07-13 21.06.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649199/706ad31e-8bcc-1b44-9346-d430e8d1b45f.png">


##参考
- https://golang.org/pkg/net/http/
正規表現re

```py
import re

"""
match()     文字列の先頭で正規表現とマッチするか判定
search()    文字列を操作して、正規表現がどこにマッチするか調べる
findall()   正規表現にマッチする部分文字列を全て探し出しリストとして返す
finditer()  重複しないマッチオブジェクトのイテレータを返す
"""

# .は任意の1文字
# マッチオブジェクトが返ってきます
m = re.match('a.c', 'abc')
# group()で中身が見れます。
print(m.group())

# マッチオブジェクトが返ってきます
m = re.search('a.c', 'test abc test abc')
print(m)
print(m.span())
print(m.group())

m = re.findall('a.c', 'test abc test abc')
print(m)

# マッチオブジェクトのイテレータが返ってくる
m = re.finditer('a.c', 'test abc test abc')
print([w.group() for w in m])

# 0または1の繰り返し
m = re.match('ab?', 'a')
print(m)
# 0回以上の繰り返し
m = re.match('ab*', 'abb')
print(m)

# 1回以上の繰り返し
m = re.match('ab+', 'abbb')
print(m)

# 3回の繰り返し
m = re.match('a{3}', 'aaaa')
print(m)

# 2-4回の繰り返し
m = re.match('a{2,4}', 'aaaa')
print(m)

# 英数字とアンダースコアー、[]の部分は集合といいます。
m = re.match('[a-zA-Z0-9_]', '1')
# m = re.match('\w', '1')
print(m)

# 英数字とアンダースコアー以外
m = re.match('[^a-zA-Z0-9_]', '@')
# m = re.match('\W', '1')
print(m)

# 任意の数字
m = re.match('[0-9]', '1')
# m = re.match('\d', '1')
print(m)

# 任意の数字以外
m = re.match('[^0-9]', '@')
# m = re.match('\D', '1')
print(m)

# aまたはb
m = re.match('a|b', 'b')
print(m)

# かたまりとして扱います
m = re.match('(abc)+', 'abcabc')
print(m)

# スペース
m = re.match('\s', ' ')
print(m)

# スペース以外
m = re.match('\S', '1')
print(m)

# エスケープ
m = re.match('\*', '*')
print(m)
m = re.match('\?', '?')
print(m)

# 先頭一致
m = re.search('^abc', 'abctest abc')
print(m)
# 末尾
m = re.search('abc$', 'test abc')
print(m)

```
実行結果：

```txt
abc
<re.Match object; span=(5, 8), match='abc'>
(5, 8)
abc
['abc', 'abc']
['abc', 'abc']
<re.Match object; span=(0, 1), match='a'>
<re.Match object; span=(0, 3), match='abb'>
<re.Match object; span=(0, 4), match='abbb'>
<re.Match object; span=(0, 3), match='aaa'>
<re.Match object; span=(0, 4), match='aaaa'>
<re.Match object; span=(0, 1), match='1'>
<re.Match object; span=(0, 1), match='@'>
<re.Match object; span=(0, 1), match='1'>
<re.Match object; span=(0, 1), match='@'>
<re.Match object; span=(0, 1), match='b'>
<re.Match object; span=(0, 6), match='abcabc'>
<re.Match object; span=(0, 1), match=' '>
<re.Match object; span=(0, 1), match='1'>
<re.Match object; span=(0, 1), match='*'>
<re.Match object; span=(0, 1), match='?'>
<re.Match object; span=(0, 3), match='abc'>
<re.Match object; span=(5, 8), match='abc'>
```

##参考文献
- [ドキュメント](https://docs.python.org/ja/3.7/library/re.html "参考文献")
ASP.Net Core+RazorPage+Non-SPA Vueコンポーネント（サンプルソース）

#目的
　今まで書いてきた記事で作成していたASP.Net Core RazorPageでnon-SPAなVueコンポーネントの作成と、関連して作っていたTestCafeのテストコードをまとめたプロジェクトソースがある程度整ったのでサンプルs-すとして提供します。気が向いたら遊んでみてください。

## 前提
　ASP.NetCore RazorPage+Vue+blumaの環境を利用します。
　以前に書いた「[Vue.jsを利用してみる（１）](https://qiita.com/nosa67/items/49ac036a15a4f7deed8b)」と「[Vue.jsを利用してみる（１）](https://qiita.com/nosa67/items/49ac036a15a4f7deed8b)」を参照しての環境を構築します。

##ソース
GitHUBの以下のURLに公開しています。
https://github.com/nosa67/RazorPageVue

## 提供内容
###Vueコンポーネント
| コンポーネント名 | 概要|
|:-----------------|:------------------|
| vueCheckButton  | 複数選択可能なチェックボタン |
| vueRadioButton  | 未選択可能なラジオボタン |
| vueTextInput  | テキスト入力 |
| vueIntegerInput  | 整数入力 |
| vueRealInput  | 実数入力 |
| vueTimeInput  | 時刻入力（サーバーではTimeSpan） |
| vueDateInput  | 日付入力（サーバーではDateTime） |

###バリデーション属性
| バリデーション属性 | 概要|
|:-----------------|:------------------|
| Required  | 入力必須 |
| StringLength  | テキストの、最小長、最大長 |
| Range  | 整数、実数、時刻の最小、最大、ステップ |
| Email  | メールアドレスかどうか |
| Url  | URLかどうか |
| Compare  | ２つのテキストの同一性 |

###TestCafe
| テストファイル | 概要|
|:-----------------|:------------------|
| VueCheckButton.test.ts  | チェックボタンのテスト |
| VueRadioButton.test.ts  | ラジオボタンのテスト |
| VueTextInput.test.ts  | テキスト入力のテスト |
| VueIntegerInput.test.ts  | 整数入力のテスト |
| VueRealInput.test.ts  | 実数入力のテスト |
| VueTimeInput.test.ts  | 時刻入力のテスト |
| VueDateInput.test.ts  | 日付入力のテスト |

## 補足
　不要なコードを整理したり、バグを修正したりしていますので、今まで書いてきた記事のコードとは少し異なります。記事の方は修正しませんので、ソースを追ってください。テストコードがあるように、ある程度のテストはしていますが、まだまだバグはありますので使おうと思っているならもっとテストしてください。
　もともとの記事では、EdgeとIE11を別のコンポーネントにしていましたが、Edgeがchromiumベースになって、インターフェースがこなれたので、IE11のみ別コンポーネントになるように変更しています。
　ブラウザごとにインタフェースが異なるのを避けるなら、全て独自コンポーネントにしてもいいかもしれません。
Laravel ルートパラメータ持ちのURLにリダイレクトする

# 目的

- ルートパラメータが設定されているURLにパラメータ値を指定してリダイレクトする方法をまとめる

# 実施環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.5) |
| ハードウェア | MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) |
| プロセッサ | 2 GHz クアッドコアIntel Core i5 |
| メモリ | 32 GB 3733 MHz LPDDR4 |
| グラフィックス | Intel Iris Plus Graphics 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| PHP バージョン | 7.4.3 | Homwbrewを用いて導入 |
| Laravel バージョン | 7.0.8 | commposerを用いてこちらの方法で導入→[Mac Laravelの環境構築を行う](https://qiita.com/miriwo/items/adaaaeecae69d6392e08) |
| MySQLバージョン | 8.0.19 for osx10.13 on x86_64 | Homwbrewを用いてこちらの方法で導入→[Mac HomebrewでMySQLをインストールする](https://qiita.com/miriwo/items/ef6a064bc545fbea29d9) |

# 前提条件

- 実施環境と同じ環境が構築されていること。

# 前提情報

- 公式ドキュメントを読んでおくと理解が早いかもしれない。
    - [Laravel 7.x ルーティング](https://readouble.com/laravel/7.x/ja/routing.html)
- `/user/{user_id}`にリダイレクトする方法を記載する。
- ルーティングには下記の様な記載があるとする。ルーティング設定部分のみ記載する。

    ```web.php
    Route::get('/user/{user_id}', 'UserHomeController@index');
    ```

# 読後感

- ルートパラメータが設定されているURLへのリダイレクト方法が分かる。
- 名前付きルーティングにパラメータを渡す方法が分かる。

# 実施(一つのルートパラメータ)

1. ルーティングファイルを開きリダイレクト先のルーティングの記載を編集し、ルーティング情報に名前をつける。

    ```web.php
    Route::get('/user/{user_id}', 'UserHomeController@index')->name('user.index');
    ```

1. リダイレクト処理を行いたい場所に下記の記載を行う。(下記が実行されると`/user/1`にリダイレクトする。)

    ```php
    return redirect(route('user.index', [
        'user_id' => 1,
    ]));
    ```

# 実施(複数のルートパラメータ)

1. ルーティングファイルを開きリダイレクト先のルーティングの記載を編集し、ルーティング情報に名前をつける。

    ```web.php
    Route::get('/user/{user_id}/{age_id}', 'UserHomeController@index')->name('user.index');
    ```

1. リダイレクト処理を行いたい場所に下記の記載を行う。(下記が実行されると`/user/1/2`にリダイレクトする。)

    ```php
    return redirect(route('user.index', [
        'user_id' => 1,
        'age_id' => 2,
    ]));
    ```

# 簡単なまとめ

- ルーティング情報に名前をつける方法

    ```php
    //ルーティング情報->name('ルーティング情報の名前')
    Route::get('/user/{user_id}/{age_id}', 'UserHomeController@index')->name('user.index');
    //上記の記載でルーティング情報に「user.index」という名前が付けられた。
    ```

- 名前付きのルーティング情報にリダイレクトする方法

    ```php
    return redirect('ルーティング情報に付けた名前');
    ```

- リダイレクト先のURLにルートパラメータがあるときにリダイレクトする方法

    ```php
    return redirect('ルーティング情報に付けた名前', [
        'ルートパラメータ' => リダイレクト時にルートパラメータに入る値,
    );
    ```

# 参考文献

- [Laravel 7.x ルーティング](https://readouble.com/laravel/7.x/ja/routing.html)
[WinForms] USBカメラの列挙

```CS
var searcher = new ManagementObjectSearcher(@"SELECT * FROM Win32_PnPSignedDriver WHERE DeviceID LIKE 'USB%' AND DeviceClass = 'Camera'");

foreach (var device in searcher.Get().Cast<ManagementObject>().OrderBy(n => n["PDO"]))
{
    Debug.WriteLine("-----");
    Debug.WriteLine(device.GetPropertyValue("FriendlyName"));
    Debug.WriteLine(device.GetPropertyValue("DeviceClass"));
    Debug.WriteLine(device.GetPropertyValue("DeviceID"));
    Debug.WriteLine(device.GetPropertyValue("PDO"));
    Debug.WriteLine("-----");
}
```

※「Video Capture Device ID」(index)は、PDOが小さい順に振られると思っていますが、完全には調べ切れていません...
【Vue.js】コンポーネント $emit で 子 → 親 へデータを渡す

# はじめに
$emitを使ったコンポーネント親子間のデータのやりとりがなかなかややこしく感じた。
なのでやったことを記録に残します。

**$emit とは？**
[Vue.js リファレンス](https://jp.vuejs.org/v2/api/index.html) を読んでも正直よくわかりませんでした。
この親子間のデータのやりとりに関しては、
「子コンポーネントで指定したタイミングに、親コンポーネントで処理を起こさせることができる。その処理ついでにデータを渡す。」

みたいな感じで勝手に解釈しました。（わかりずらくてすみません）


# どんなものを実装するか？
・子コンポーネントにボタンを設置。
・そのボタンをクリックすると親コンポーネントのdataの値（初期値０）に１加算された値が子コンポーネントから送られる。


# 実装してみる

```Child.vue
<template>
  <!-- クリックでplus1メソッドを呼び出す -->
  <button @click="plus1">プラス１</button>
</template>

<script>
export default {
  props: ["childScore"],
  methods: {
    plus1() {
      // $emit('親コンポーネントで発火させる関数の名前', 処理の内容);
      this.$emit('plus-click', this.childScore + 1);
    }
  }
}
</script>
```

```Parent.vue
<template>
  <!-- :child-score="score" で初期値を渡している。 -->
  <!-- そして@plus-clickイベントが発火したら、$event($emitで発火させたplus1メソッド処理後の値)をscoreに代入する -->
  <Child :child-score="score" @plus-click="score = $event"></Child>
  <p>{{ score }}</p>
</template>

<script>
import Child from "Child.vue"

export default {
  data() {
    return {
      score: 0,
    }
  }
}
</script>
```

# 最後に
props, $emit などコンポーネント間のデータやりとりなかなか難しい。
間違いなどなどあれば、気軽にご指摘ください。
C/C++ では+++は許される

[JavaScriptで+++は許されない+ ++は許される]( https://qiita.com/matyapiro31/items/19d62605632dd90d0647 ) を読んで書いた。

C / C++ の場合、許される。

というわけで、JavaScript で許されないのは「解析できないから」というよりも、これを合法とすることで幸せになる人よりも不幸せになる人のほうが多そうだったので違法にした、ということだと思う。

---

追記。
「JavaScript で許されないのは」と書いたものの、上記記事の[コメント](https://qiita.com/matyapiro31/items/19d62605632dd90d0647#comment-b836cce8af43e3118dad) にある通り、本当は許されるっぽい。
手元で試しても許されていた。

---

```c++:c++
#include <stdio.h>

struct Foo{
	bool operator&() const {  return 0; }
};

int main() {
	int a=0, b=0;
	printf( "%d\n", a+++b); // okay. (a++) + b
	printf( "%d\n", a---b); // okay. (a--) - b
	int * pa=&a;
	int ** p = &pa;
	printf( "%d\n", a***p); // okay. a * (*(*p))
	Foo e;
	printf( "%d\n", a&&&e); // okay. a && (&e)
	return 0;
}
```

ちなみに、 `a+++++b` は `(a++) + (++b)` とはならず、エラーになる。
これはたぶん、ここを頑張っても意味ないだろ、と思って頑張らなかったからだと思ってるんだけど、どうだろう。
mixinとは何か

##参考
「what are mixins 」
https://medium.com/flutter-community/dart-what-are-mixins-3a72344011f3

##概要
flutterを学習していていきなり出てきたmixinについて調べたので共有します。

##mixinとはなにか
単純に言えばClassと似たようなもの。
ただし、Dartにおいて、Classと異なるのは複数個継承できるということ。

ここで参考元に記載されていた例を添付する。
<img width="1250" alt="mixin.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581713/c2e64ec6-2296-3651-92c9-104eac23f23d.png">

画像にある通り、個々の動物の技能にあたる場所がmixinです。

##まとめ
mixin自体は結構古い概念らしいことを知り、驚いた。
まだまだ勉強することはたくさんあるな。。。
ということでよければLGTMお願いします！
みなさんの参考になれば幸いです！
kintone hack 2019の予選敗退ネタを供養する

[kintone hack 2020](https://kintonehack2020.qloba.com/)の募集が始まっていますね。

昨年のkintone hack 2019の予選に参加したのですが、あえなく敗退してしまいました。
1年経ってようやく悔しさが半減してきたのでネタを公開して供養したいと思います。

# kintoneモバイルの可能性

## kintoneを初めて操作したときの印象
「業務システムをすぐに、簡単に作れる」ということよりも「親しみやすい画面、期待を裏切らない操作性」の印象が強く残っていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102790/c1a2515b-c56c-a075-74bb-e9cd605e23ef.png)

## kintoneモバイルバージョンアップの印象
[2019年3月にkintoneモバイルがバージョンアップ](https://kintone.cybozu.co.jp/update/main/2019-03.html)しました。
しかし、PCと同じような操作ができるようになっただけで、kintoneらしさが足りないと感じました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102790/bdbca070-53b3-7ee3-bfd0-f1b5eb8d745c.png)

## kintoneモバイルにモバイルらしさを追加
そこで今回のkintone hackではkintoneモバイルにモバイルらしさを追加しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102790/b4c13681-efe3-9e7e-588c-225e6f226e73.png)


### ①外出先からレコード閲覧
外出先では必要な情報を素早く呼び出せることが重要です。
しかし、kintoneモバイルではフィールドが縦1列に並ぶので、フィールド数が多くて見たいフィールドを探すのに苦労します。（例えば在庫数や金額だけ見たい）

そこでタブ機能を追加しました。
タブをクリックすることで遷移できるのですが、それではスマートフォンから操作しづらいので親指ポジションのアイコンからも操作できるようにしました。
![swipeview1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102790/c01c027c-ddfe-699d-aa90-39bd4cf5f4bd.gif)

### ②外出先からレコード登録
外出先では最低限のフィールドを登録して、残りは会社や自宅などからPCで入力します。
しかし、保存時に必須フィールド未入力でエラーになる場合があります。
イライラしますし、必須フィールドを探すのも時間がかかります。

そこで必須フィールドだけを表示するタブを作りました。
![swipeview2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102790/5a88bac7-92b6-841b-23c3-17a086a84493.gif)


### ③会社や自宅（PC）から残りのフィールドに入力
②で登録したレコードに後から追記したい場合に、そのレコードを探すのが大変です。
特にアプリが複数あると追記漏れなどが発生する場合があります。

そこで自分に通知する機能を追加しました。（APIトークンを利用）
![ezgif-5-dc8bb0c64d51.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102790/20a49da3-2bda-962b-8d2d-840548782a1d.gif)


## kintoneモバイルの可能性
どうでしょうか。使いやすそうじゃないですか？
kintoneモバイルの可能性はまだまだありそうです！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102790/c84104e0-7b5a-b494-8b08-c4e2397f26b4.png)
Chrome リンク先のページ移動、別タブ、新しいウィンドウで開く方法

# 実施環境

|項目 |情報  |
|---|---|
|OS  |Windows 10 Pro |
|ブラウザ  |Google Chrome バージョン: 83.0.4103.116（Official Build） （32 ビット）  |

# リンク先に移動
* リンクを左クリック
* Tabボタン押下で対象のリンクまで移動してEnter押下

# リンク先を別タブで開く
* リンクを右クリック→新しいタブで開く(T)
* Ctrl押しながらリンクを左クリック

# リンク先を新しいウィンドウを開く
* Shift押しながらリンクを左クリック
* リンクを右クリック→新しいウィンドウを開く(W)

# シークレットウインドウを開く
* リンクを右クリック→シークレットウインドウを開く(G)
* リンク元、リンク先でCtrl + Shift + N

他にもあれば随時追加します。
isVisible is deprecated and will be removed in the next major version.

## はじめに
Jest ^25.5.4を利用してMocalが表示されることをテストしてみました。

```javascript
  const modal = wrapper.find('modal-stub')
  expect(modal.isVisible()).toBe(true)
```

その際、テストは通るものの、以下のような警告がコンソールに表示されました。
どうやら、将来的にisVisible()は削除されるとのことです。

__[vue-test-utils]: isVisible is deprecated and will be removed in the next major version. Consider a custom matcher such as those provided in jest-dom: https://github.com/testing-library/jest-dom#tobevisible. When using with findComponent, access the DOM element with findComponent(Comp).element.__

## 対応
今回は以下のように回避しましたが、別途、jest-domというライブラリを使用するという方法もあるようです。
[こちら](https://qiita.com/taneba/items/b21f5fee17eb593b30c8)にQiitaでも記事を書いてくださっている方がいらっしゃいるようです。

```javascript
  const modal = wrapper.find('modal-stub')
  expect(modal.exists()).toBe(true)
```

## 追記
コメントで頂いたように、isVisible()は存在チェックに利用するのは正しい使い方ではないです。
それを理解したうえで使うのもありかもしれませんが、やはりjest-domを利用するのがよさそうです。。
Vert.x WebClientを使ったテストの最小コード

WebClientを絡めたテスト動かしたいなーとおもっていてずっと動かなかったんだ。死んでた。
今日見てみてサーバー起動しきれてないのでは？って気づきがあって`Thread.sleep`追加したら見事に動いてうわーってなってる午前４時。

```Kotlin
@ExtendWith(VertxExtension::class)
class TestHogeVerticle {
  val port = xxxxx
  val host = "localhost"

  @BeforeEach
  fun deploy_verticle(vertx: Vertx, testContext: VertxTestContext) {
    val options = DeploymentOptions()
      .setConfig(
        JsonObject()
          .put("serverport", port)
          .put("dbport", xxxx)
          .put("dbhost", "xxxxxx")
          .put("dbname", "xxxx")
          .put("dbuser", "xxxx")
          .put("dbpass", "xxxxx")
          .put("dbpoolsize", 5)
          .put("sessionfile", "xxxx")
          .put("environment", "xxxx")
      )
    vertx.deployVerticle(HogeVerticle(),DeploymentOptions(options), testContext.completing())
    Thread.sleep(3000) //これ！ 1000じゃだめ。2000で動いたけど余裕をもって+1000
  }

  @Test
  @DisplayName("get xxx ok")
  fun get_xxx_ok_response(vertx: Vertx, testContext: VertxTestContext) {
    WebClient.create(vertx)
      .get(port, host, "/xxxx")
      .send(testContext.succeeding { response ->
        testContext.verify {
          assert(response.body().toString().contains("xxxx"))
          testContext.completeNow()
        }
      })
  }
}
```

Jenkinsも無事動いてまぁ、良い。Issueクローズして寝よ。
Blenderでポリゴンを切り抜く＆壊れた頂点の直し方

皆さん、元気にバ美肉してますか。
画像を入れる予定だったのですが、編集がだるく放置してたので、
とりあえず公開して、時間があるときに入れます。

私のBlogでもVRoidをVRChatに持っていくという話で何度か記事を書いていますが、
今回はポリゴンを切り抜く究極的な対応です。

VRoidをVRChatに対応する時、面倒なのが半透明
PCモードでは半透明シェーダーを使うことで対応できますが、
どうもSafetyを低く抑えている人には、半透明がうまく表示されないようです。

ということで、手間はかかりますが、Blenderを使ってポリゴンを切り取る方法です。
Questへの対応としてもある意味究極的な対応にもなります。
ポリゴン数も削減できますからね。

#メッシュの分割

まず、CATSでインポートを終わらせた状態です。
このままだと作業がしづらいので、マテリアル単位で分割します。

オブジェクトモードでBodyを選び、編集モードに変えます。
そこで、[P]を押し、マテリアルで分割します。

もとに戻すには、CATSのModel Options、JoinMeshのすべてを押せばいいです。

#作業するべき部位

まず、目、目のハイライト、眉毛、まつげ(2個)です。
そして、服のデザインによっては服も切り抜く必要があります。

あとは、服で隠れている部分の体も消していいでしょう。
特に脇のあたりは、腕の角度で下の体が服の前に出てくるので、
元から消しておくとはみ出ることはありません。

#面を削除
今回は例としてまつげを切っていきます。

まず、まつげをオブジェクトモードで探します。
見つけたら[/]を押すと他のモデルが消え拡大されるので作業しやすくなります。

オブジェクトモードから編集モードに切り替えます。

面モードに切り替えて、
[C]を押すと、カーソルが円になり選択しやすくなります。

そして、[DEL]を押し、面を削除で消していきます。

#ポリゴンの分割

面単位で消していくと途中でポリゴンを分割したい場合があります。
その時は、[K]を押してナイフツールを使います。

切り抜きたいラインでマウスをクリックし、[ENTER]を押せば確定します。

ナイフで切り抜くときは、頂点、辺、面の3つがあります。
この時、必ず面で切り抜かないようにします。
面で切り抜くと、後述する「壊れた頂点」が生成されます。

面の途中に頂点を起きたい場合は、その

#壊れた頂点
VRChatにデータを持っていくとこのように足元に向かって伸びたポリゴンになることがあります。

まず、Blenderでこれを確認する方法です。

編集モードに入り、三角のタブをクリックします。
そこで、シェイプキーを一番上以外を選びます。
すると、原点に飛んでいく頂点があることが確認できます。

ナイフツールで切り抜く時、面でカットしたのが原因です。

#壊れた頂点の修復方法

結論から言えば、壊れた頂点を確認した時点でやり直したほうが早いです。
それでも、少しなら手作業で直してもいいでしょう。

まず、ウェイトを付けなおします。
頂点グループを選び、他の頂点がどのグループに属しているのか探します。

選ばれてない黒い頂点がありますが、これが壊れた頂点です。
これを選んで、割当を押します。

次に、その頂点を選んだまま、シェイプキーをBasisにして、
上の頂点メニューからシェイプに反映を選びます。

これで「すべてのシェイプキー」に同じ座標が反映されました。

シェイプキーとは、値を入れることで一部の座標を移動させる機能です。
簡単に言えば、目を閉じたり口を開いたりする機能です。

「すべてのシェイプキー」に同じ座標が反映されているため、
目を閉じていても、開いた位置に座標が反映されているわけです。

そこで全てのシェイプキーを確認します。
キーボードの下を押し続ければいいでしょう。

例えば、眉毛の壊れた頂点ですが、BRW Angryのときに移動するので、
その時は個別に頂点を移動させて対応します。
他にも壊れているシェイプキーがないか探して下さい。

これらすべてが終われば、壊れた頂点の修復ができます。
react Hooks useState　使ってみた

#useStateを実際に使おう

##useStateとは？

>Returns a stateful value, and a function to update it.

>During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).

>The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.

(react 公式サイトuseStateより引用)

React公式サイトにはこのように書いています。

ん？わからない。

なので実際に簡単なコードを書いてみました。

※これはReact Application上で書きました
##コード1
```react
const example = useState(0)
console.log({example})
```

この場合のconsole.logの出力は次のようになります。

```
example: Array(2)
```
これの中身を見るとこのようになっています。

```
0: 0
1: f()
```
つまりexampleは配列になっています。
1番目には初期値である0が
2番目には関数が入ります。

##コード2
useState()の括弧の中が
本当に初期値なのかと疑問に思ったので
console.logしてみました。

```react
const example = useState(500)
console.log({example})
```

この場合のexampleの配列の中身は次のようになります。

```
0: 500
1: f()
```
ちゃんと初期値になってます！

##コード3
この配列には2つの要素が入ることがわかりました。
ここでjavascriptの分割代入を使って
それぞれの要素を受け取るようにします。

```react
const [count, setCount] = useState(0);
const up =() => setCount(count +1)
```
ここでupはcountを+1します。
countの状態を変えるために
setCountをこのように使います。
これによりcountの値を+1していくことができます。

##実際に書いたコード
```react
import react, {useState} from 'react';
const App = () => {
const [count, setCount] = useState(0);
const up =() => setCount(count +1)
const down =() => setCount(count -1)
return (
<>
<div>count: {count}</div>
<div>
<button onClick={up}>+1</button>
<button onClick={down}>-1</button>
</div>
</>
);
}

export default App;
```
学習したことを応用して
簡単なカウンターを作ってみました。

buttonタグでボタンを表示し
onClickはボタンを押したときの処理です。
こうすることでボタンを押して
+1,-1できるカウンターの出来上がりです！
【Rails】セッションタイムアウトがうまくいかない事象の解決

##  前提

・タイムアウトのメソッドを定義
・コード自体間違っていないにもかかわらず、セッションがnilと判定されてしまい、メソッドがうまく処理されずエラーとなる。

## タイムアウトのメソッド

```sessions_controller.rb

  def create
# ...

   session[:last_access_time] = Time.current

# ...
  end
```


```application_controller.rb
  TIMEOUT = 5.minutes

  def time_out
     if session[:last_access_time] > TIMEOUT.ago
       session[:last_access_time] = Time.current
     else
       session.delete(:user_id)
       flash[:danger] = "タイムアウトしました。"
       redirect_to :login
      end
    end
```

上記のメソッドを組み、その後ログインを試みるとエラーが発生する。

```
NoMethodError (undefined method `>=' for nil:NilClass):
# session[:last_access_time] がnil判定される。
```

## 解決方法
ブラウザ側のクッキーを削除することで解決しました。
おそらくログインしている状態でメソッドを定義したから、
「session[:last_access_time]なんかないぞ」って怒られてしまったのかもしれません。