OmniAICreator/Qiita-1.07M huggingface dataset:
firestoreのindexを取得してfirestore.index.jsonに書き出したい

# firestoreのindexをコードに書き出したい

- 環境が複数個有ったりして、それぞれidenxを書いていくのは面倒。
- json形式で自分で書くのは大変

そんな時に下記の記事を読ませていただきました。
[Firebaseのfirestore.indexes.jsonの書式とかインデックスの作り方とかで戸惑った。](https://ginpen.com/2019/06/01/firestore-indexes-json/)

正直上記の記事さえあればいいのですが、自分のメモとして書かせていただきます。


## firestore.index.jsonの書き出し

デプロイしたいソースコードのディレクトリへ移動して下記をターミナルで入力します。
※Firebase Client SDKが入っている前提でお話しています。

```
$ firebase firestore:indexes > {fileName}
```

ex)

```
$ firebase firestore:indexes > firestore.indexes.json
```

コレを書き出しておけばGCPのコンソールで自動生成したindexも自分で書いたindexも全てjson形式で書き出してくれるので
後は別環境にデプロイしたり、書き換えてしまったindexを上書いたりできるのでとても助かります。

## 実行時の注意点

- `firebase use`でfirebase-toolsがどの環境へ向いているのか確認する
laravel 多対多 タグ付け

新しいの書いた
https://qiita.com/ma7ma7pipipi/items/a5ea71071fbaf9311cfe

参考
https://qiita.com/Ioan/items/bac58de02b826ae8e9e9

Profile テーブル
Tag テーブル


をそれぞれ 多対多 で結びつけたい。
profile の綴りを間違えないように気をつけて。


```Profile.php

    public function tag(){
        return $this->belongsToMany('App\Tag', 'profile_tag', 'profile_id', 'tag_id');
    }


```


```Tag.php

    public function profile(){
        return $this->belongsToMany('App\Profile', 'profile_tag', 'tag_id', 'profile_id');
    }

```



データ読み出し


```

        //タグをすべて読みだし、タグがいくつのプロフィールを持っているか取得
        $hoge = Tag::withCount('profile')
            ->orderBy('profile_count', 'desc')
            ->get();


//        タグとともにすべてのデータを取得
        $res = Profile::query()//単数形 User
            ->with('tag')
            ->get();

```

これでOK。
中間テーブルを複数作れば
User と Profile にTagテーブルのタグをつけれるようになる。


```User.php

    public function tag(){
        return $this->belongsToMany('App\Tag', 'user_tag', 'user_id', 'tag_id');
    }


```


```Tag.php

public function user(){
    return $this->belongsToMany('App\User', 'user_tag', 'tag_id', 'user_id');
}

```

# タグ付けしたい

ProfileTag.phpを作成し、指定した記事を保存したあとに
タグは別途で保存する。

タグがすでにあれば、タグのIDを取得。
タグがなければタグを新規作成し、IDを取得。

また、保存する際は古いタグをすべて削除して再度新規保存する。


```ProfileTag.php

class ProfileTag extends Model
{
    protected $table = 'profile_tag';//使うテーブル名を指定
    protected $guarded = ['hoge2'];
    use InsertOnDuplicateKey;
}

```


```HogeContorller.php

<?php

    $profile_id = 22163702;
    
    $tags = [
        'ウェブショップ',
        'りんご',
        '小麦'
    ];
    
    $tag_ids = [];
    
    foreach ($tags as $v) {
    
        $tag = Tag::query()//単数形 User
        ->where('name',$v)
            ->first();//最初の
    
    
        if($tag){
    
    
            //あればタグのIDを取得
            $tag_ids[] = $tag['id'];
    
        } else {
    
            //なければ新規保存
            $model = new Tag;
            $model->name = trim($v);
            $model->save();
            $tag_ids[] = $model->id;
    
    
        }
    
    }
    
    
    $now =  Carbon::now();
    
    
    $data = [];
    foreach ($tag_ids as $v) {
    
        $data[] = [
            'id' => null,
            'profile_id' => $profile_id,
            'tag_id' => $v,
            'created_at' => $now,
            'updated_at' => $now
        ];
    
    }
    
    $data = array_values($data);
    
    
    ProfileTag::query()
        ->where('profile_id',$profile_id)
        ->delete();//削除
    
    ProfileTag::insertOnDuplicateKey($data);


```
公開鍵をワンライナーでクリップボードに持ってくる（Mac限定）


# pbcopyコマンドを使おう

公開鍵をサーバに持っていってログインで使うときに
リダイレクトミスを起こさないためにも　Macをご利用の方は 以下をお使いくださいませ・・・

## 私のオススメ

パブリックキーを標準出力に表示して、パイプで クリップボードへ！
（less でもできたけど）

```bash
cat ~/.ssh/id_rsa.pub | pbcopy
```

## 一般的な方法

これでもできる。
しかし、不等号を逆にした場合、変なものを上書きしてしまうので危険が伴う

```bash
pbcopy < ~/.ssh/id_rsa.pub
```

# おまけ

## コピーした公開鍵は以下のコマンドで 追加してくださいな。

```bash
echo 公開鍵 >>authorized_keys
```
Herokuでaxios実行時にhttpでAPIが呼び出されてしまう際の解決策

# 結論

- リクエストURLの末尾のスラッシュをつけない

```js
axios.get("/api/hoge?fuga=a")
```

## 経緯

```js
axios.get("/api/hoge/?fuga=a")
```

をHeroku上で実行すると

> Mixed Content: The page at 'https://example.html' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://....js'. This request has been blocked; the content must be served over HTTPS.

がでてAPIを呼び出せない。

[【Javascript】Fetch APIのFetch()で予期せぬMixed Content Errorが起きた話](http://lamechang.work/js-1/)
によると、

> 「リクエストURLの末尾のスラッシュ有無でmixed contentが解消される可能性がある」

とのこと。


```js
axios.get("/api/hoge?fuga=a")
```

でリクエストURLの末尾のスラッシュをつけない場合は問題なく呼び出せる
~~Herokuの仕様わからない~~

## 参考

[【Javascript】Fetch APIのFetch()で予期せぬMixed Content Errorが起きた話](http://lamechang.work/js-1/)
C++/CLIでConsole.WriteLine()は表示されるのにprintf()やcoutは表示されない時の対処法

#概要
VisualStudio2015にて、C++/CLIプロジェクトとC#プロジェクトを同居させたソリューションを作っていました。C++/CLIの方でprintf()やcoutでログ出力しようとしたのですが、VisualStudioでデバッグ実行すると表示されませんでした(プログラムはそのまま動いていました)。
Console.WriteLine()での出力は表示されており、なんでかなーと思っていたら解決したので、書いておきます。ググってもあまりヒットしなかったので・・・

#対処法
C#プロジェクトの、プロパティ⇒デバッグ⇒デバッガーを有効にするにある、「Visual Studio ホスティングプロセスを有効にする」チェックボックスのチェックを外すと表示されるようになりました。

#その他
表示されていない時のことをもう少し詳しく書いておきます。

１つ目。表示されないと言いつつ、生成されたtest.exeを直接叩いた場合には、printf()やcoutで出力したログはコンソールに表示されていました。VisualStudioで動作させた場合には表示されていなかったという感じです。

２つ目。チェックボックスにチェックが入っている状態だと、実行時のコンソール上の表示が.exeではなく.EXEと大文字になっていました。
Wiki Cabinet Media - ウィキキャビネットメディア

Wikiキャビネットとは何ですか？
人類の典型的な知識が、本のすべてのページ、すべてのコレクション、すべての雑誌、古代の金属や心のあらゆるデータベースに世界中に散在していると想像してみてください。すべての人間は、あらゆる場所、時間、空間に収束され、要約され、継承されます。それが私たちの夢であり、誇りであり、知識百科事典を構築したいという願望です。
私たちのビジョン
![Logo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669235/aaf82e68-7c1e-bd99-61b5-5d7de69eea11.jpeg)

人間の知識の百科事典による知識のグローバル化。
我々の使命
人類の真髄を世代から世代へと広める知識の火を呼び起こす信頼できる仲間になります。
基本的価値観
私たちが共有する知識の真髄は、信頼性が高く、合法で、有用です
私たちはエリートの人々を集めて、人間の知識の真髄を促進し、継承しました。
私たちは最新のテクノロジーを使用して、さまざまなナレッジプラットフォームを統合、リンク、体系化します。
さまざまな検索エンジンとデータサービスを使用して、複数レベルの詳細で知識へのアクセスを提供します。
PHPのWhile文にif文を書く！

# PHPの学習中のアウトプットとして書きます！

例えば変数$xを定義し、変数$xを用いて2〜100までの偶数をechoする場合！


```index.php

 $i = 2;              //変数定義
 while ($i <= 100){    //$iが100になるまでループ
   if ($i % 2 == 0){    //if分で$iを2で割った時余り0になる数字をechoする
    echo $i;
    echo '<br>';
    }
   $i++;               //$iが100になるまで1を足す
 }
```

#結果
2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
36
38
40
42
44
46
48
50
52
54
56
58
60
62
64
66
68
70
72
74
76
78
80
82
84
86
88
90
92
94
96
98
100

#このようになります！！

以上です！！！
browser-syncのport番号をランダムにする

複数の案件を同時に進めている都合上、複数個の[browser-sync](https://www.npmjs.com/package/browser-sync)を同時に走らせたいときportが衝突してイライラしちゃうので、そもそもportをランダムにしとけばいいんじゃないか説。

他にいい方法があれば教えてください。。。

```js
// browser-sync.js
module.exports = port => {
    const path = require('path');
    const browser = require('browser-sync').create();

    browser.init({
        files: [
          // 監視したいファイルのパターンリスト
        ],
        // 動的・プライベート ポート番号からランダムで
        port: port || Math.floor(Math.random() * (65535 - 49152)) + 49152,
        startPath: '/',
        server: {
            baseDir: path.join(__dirname, 'public')
        }
    });
};

```

```js
// 呼び出し側のjs
require('./browser-sync')(); // 引数にポート番号を入れれば固定でも実行できる
```

## 参考

- [TCPやUDPにおけるポート番号の一覧 - wikipedia](https://ja.wikipedia.org/wiki/TCP%E3%82%84UDP%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7%E3%81%AE%E4%B8%80%E8%A6%A7#%E5%8B%95%E7%9A%84%E3%83%BB%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88_%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7_(49152%E2%80%9365535))
ちょこっと修正して、Google Formをレスポンシブに表示する

Google Formをそのまま埋め込むと、スマホで見たときに
表示がはみ出ました。

右側が切れてしまっています。

<img height="300px" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507586/1146d980-9061-e4e4-3513-802be58ddd32.png">


そこで、レスポンシブにする方法をググって見つけたので
書いておきます。
[ここ](https://gotitnow.in/how-to-make-google-form-responsive-for-mobile/)に解決法が書いてありました。

Google Formをレスポンシブにするには、
`<iframe src="～" width="100%" height="800" frameborder="0" marginheight="0" marginwidth="0">読み込んでいます…</iframe>`
とあるところの、`width="640"`のように直接サイズが書かれているところを<strong>`width=100%`</strong>のように<strong>%</strong>で指定するように変更します。

変更してみると、きっちりスマホでもはみ出さずに表示されるようになりました。

<img height="300px" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507586/b2bf6f3b-e880-7e50-f6ac-ae4cc21ea2e2.png">
Ginza, ginzameを用いてGoogle Colaboratory上で形態素解析をする

#準備


```
!pip install -U ginza
```


```
import pkg_resources, imp
imp.reload(pkg_resources)
```

#便利な関数


```
nlp = spacy.load('ja_ginza')

def morphologicalAnalysis(sentence, part_of_speech):
  result = nlp.tokenizer.tokenizer.tokenize(sentence)
  returnWords = []
  for i in range(len(result)):
    original = result[i].surface()
    temp = result[i].part_of_speech()
    if temp[0] in part_of_speech:
      returnWords.append(result[i].normalized_form())
    
  return ' '.join(returnWords)

returnWords = morphologicalAnalysis('銀座でランチをご一緒しましょう。', ['名詞','形容詞','動詞'])
returnWords
```


```
#実行結果
銀座 ランチ 一緒 為る
```



#Ginza


```
import spacy
nlp = spacy.load('ja_ginza')
doc = nlp('銀座でランチをご一緒しましょう。')
for sent in doc.sents:
  for token in sent:
    print(token.i, token.orth_, token.lemma_, token.pos_, token.tag_, token.dep_, token.head.i)
  print('EOS')
```


```result_Ginza.txt
0 銀座 銀座 PROPN 名詞-固有名詞-地名-一般 compound 5
1 で で ADP 助詞-格助詞 case 0
2 ランチ ランチ NOUN 名詞-普通名詞-一般 obj 5
3 を を ADP 助詞-格助詞 case 2
4 ご 御 NOUN 接頭辞 compound 5
5 一緒 一緒 VERB 名詞-普通名詞-サ変可能 ROOT 5
6 し 為る AUX 動詞-非自立可能 aux 5
7 ましょう ます AUX 助動詞 aux 5
8 。 。 PUNCT 補助記号-句点 punct 5
EOS
```



#ginzame
名詞・動詞・形容詞の基本形が欲しい場合

```
result = !echo '銀座でランチをご一緒しましょう。' | ginzame
for i in range(len(result)):
  try:
    original, others = result[i].split('\t')
    temp = others.split(',')
    if temp[0] in ['名詞', '形容詞', '動詞']:
      print(temp[6], end = ' ')
  except:
    pass
```


```result_ginzame.txt
銀座 ランチ 一緒 為る 
```
Laravel-mixのnpm watch-pollのcpu負荷が重いのでwatch-pollの間隔を変える

windowsのdockerの環境をhyper-vからwsl2に乗り換えた時にnpm run watchが聞かなくなったので、npm run watch-pollに切り替えました。
が、npm run watch-poll をするとcpuの負荷が重すぎてファンがうるさかったので、なんとかcpu負荷を軽減できないかと対策したときのメモ。

# 結論
laravelのプロジェクト直下のpackage.jsonに対して

```package.json
{
    "scripts": {
        "watch-poll": "npm run watch -- --watch-poll=5000",
    },
}
```
と時間(watch-poll=5000で5000ms=5sの意味)を指定しましょう。(参考[1])

#解説
## watchとwatch-pollの違い
そもそもwatchはwebpackの仕組みです。
ファイルを監視し、ファイルの変更があった時に差分だけをトランスパイル先にアップロードしてくれます。
watchのおかげで、何回も全体のトランスパイルを繰り返すことなく、最小限の時間で更新を確認することができます。

このwatchは仕組みとしては、ファイル変更のイベントを検知して、それに処理をするようです。
なので、ファイルシステムやパスの等に問題が発生して適切にファイル変更のイベントを受信できなければwatchは機能しません。[注釈1]

watchが動作しない環境のために、webpackにはpollというオプションがあります。
webpackのwatchが変更の通知を待つのに対して、pollはwebpackから更新処理を定期的に確認しにいきます。
webpackをラップしているlaravel-mixでは、pollオプション付きのwatchが--watch-pollで使用することができます。

## watch-pollの処理間隔の仕様
pollingの間隔はデフォルトでは1秒になっています。
webpackにおいて、処理の間隔は変更が可能です。
Laravel-mixでも--watch-poll=(時間) とすればpollingの間隔を変更できます。

## 注釈
1. 自分の場合はwsl2のdockerコンテナで稼働するlaravelを使っています。
この場合は、vscode等によるwindows上でのファイルの変更がdockerの使っているwsl2上のlinux(ubuntu)に通知されなかったことが原因です(参考[2])。
vscodeの場合はremote-wslでホスト元となっているディストリビューションを使えば、ファイルの変更がwsl2に通知されるため、npm run watchを使用することができるという話もあります。ただ自分の環境では試してみたらダメだったので、気が向いたり必要になったら調査するかもしれません(wslベースでvscodeするなら移行するデータも多いし、とりあえずはwatch-pollで十分なため）。

#参考
[1]https://github.com/JeffreyWay/laravel-mix/issues/1418
[2]https://github.com/microsoft/WSL/issues/4739
Flutter Stateのライフサイクルまとめ

Flutterのライフサイクルは下記のように分かれています。

- createState
- mounted is true
- initState
- didChangeDependencies
- build
- didUpdateWidget
- setState
- deactivate
- dispose
- mounted is false


## ➀createState（Stateを作成する）
まず、FlutterのSDKはStatefulWidgetのcreateStateを呼び出し、Stateを作成します。

```
class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() = _MyHomePageState();
}

class _MyHomePageState extends State MyHomePage {
  .....
}
```

## ➁mounted is true（Stateをマウントする）
➀にて作成されたStateは**BuildContext**に紐づけられます。
BuildContextとは端的に言うと、**各WidgetのWidget Tree上の位置（そのWidgetがどこにあるのか）**を制御するためのクラスです。
このタイミングで、Stateオブジェクトはマウントされたと認識されます。

## ➂initState（Stateを初期化する）
クラスのコンストラクターが呼び出されたあと、すぐにこのinitStateが呼ばれます。
最初に一度だけ実行されます。
オーバーライドできますが、その際は必ず親クラスのinitStateも呼び出す必要があります。

```
// これを記述することでオーバーライドと認識される
@override
initState() {
  // 必ず、super.initState()を呼ぶこと
  super.initState();
  // Streamをlistenしてデータを連続したデータを受け取れるようにする
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}
```

## ④didChangeDependencies
initStateを呼び出した後にはdidChangeDependenciesが呼び出されます。
didChangeDependenciesは、InheritedWidgetのBuildContext.inheritFromWidgetOfExactTypeが実行された場合に呼び出されます。
InheritedWidgetとは、Treeの下位のWidgetから直接参照できるWidgetのことです。


>例
それぞれの開発のフェーズ（開発・検収・本番など）に応じて接続するURLを変えたい場合、InheritedWidgetを用いて上位のWidgetでデータを設定しておいて、それを下位のWidgetからアクセスする。こうすることで、毎回親Widgetから子Widgetへパラメーターを渡す手間を省くことができます。

アクセス方法は、ConfigInheritedWidget.of(context).hogeUrlのような形で情報を取得します。
ただその場合contextにアクセスしたいのですが、initState内ではまだcontextにアクセスすることができません。
そこで、didChangeDependencies内でこれを実行し、InheritedWidgetからデータを取得するようにします。

## ➄build
build関数はほぼ確実に使われます。描画したいWidgetを記述するのに用います。

```
@override
Widget build(BuildContext context) {
  return Widget();
}
```

## ➅didUpdateWidget(Widget oldWidget)
親Widgetが変更されて（親Widgetから渡されるパラメーターの値が代わり）、再ビルドされる必要がある場合にこのdidUpdateWidgetが呼ばれます。
FlutterではStateは使い回しますが、initStateで初期化をしたデータは再び初期化しなければならない場合があります。

> 例
もしStateのbuild関数がStreamや他のオブジェクトに依存していた場合、古いオブジェクトを購読解除し、didUpdateWidgetで作られた新しいオブジェクトを購読し直すようにすることができます。

これが呼ばれたのちにbuild関数も呼び出されるため、setStateをこの関数内に記述する必要はありません。

## ➆setState
State内の変数の値を変更したい場合に呼び出されます。これが呼ばれた後、build関数が再実行されます。
この関数は、同期的なコールバックを持ちます。これは、再描画が安価であるため、必要に応じて頻繁に呼び出すことができるためです。

```
void updateProfile(String name) {
 setState(() => this.name = name);
}
```

## ➇deactivate
これはほとんどの場合、使われません。Stateがツリーから削除される場合に呼び出されます。

## ➈dispose
Stateオブジェクトが削除されるとdisposeが呼び出されます。これは永続的なものです。
このメソッドでは、以下のようなものを取り消す場合に用いられます。

- アニメーションの購読
- Streamの購読
- コントローラーの参照


## ➉mounted is false
disposeが呼び出されると、Stateオブジェクトは再マウントされません。
ここでsetState関数を呼び出した場合、エラーとなります。
インターン日記

#やること
いきなりデザインナーが作ったUIを実装してと頼まれる、、、
ほんまにいきなりやなあ。
ざっくりどこにでもあるメンバーの一覧とかみれたり検索できたりするやつ。
とりあえずReactでやりますか。

##git環境
mac proでpushとかやっていたのに、謎にpullできないというトラブル。
結局公開鍵を自分のアカウントに登録すれば解決。
あれ？前できていたよなあ？
ちなみにgitで使用している認証は公開鍵認証。
公開鍵と秘密鍵をペアで作って、公開鍵をサーバへ渡しておく。
認証時に秘密鍵で暗号化したものは渡しておいた公開鍵で復号できるから、その人だよねってわかるっていう仕組み。

macだとユーザーディレクトリの.sshにあるid_rsa.pubが公開鍵。catなんかで出力してコピペでgitに登録してあげればOK。

##react環境構築
早速react環境を作りましょー。

```
create-react-app
```
を使ってあげれば超簡単にreact環境ができるよねfacebookさんありがとう。
ただ、ここで沼にハマった。
何かのトラブルでディレクトリに不足があった。(あとで気付く)
通常のディレクトリ構成だとすぐにnpm startでローカルサーバが立ち上がるが、エラーとなる。
ファッ！？！？
しかも、gitにpushしてしまったから最悪だわ、、、
何回かやり直したら、通常のディレクトリのものができた。
何が原因なのか？？ネットワークトラブル？？？？
とりあえず、それらのファイルをgitで管理している方にコピペして解決。

##reactでのcss
reactでcssを使うにはcss moduleを使ってあげればok
詳しくは以下参照
[https://kapu-kapu.hatenablog.com/entry/2018/11/19/132655](https://kapu-kapu.hatenablog.com/entry/2018/11/19/132655)

##create-react-appでのimgのパスについて
通常通り、imgのsrcにファイルのディレクトリ構成の相対パスを書いてもどーも画像が表示されない。
なんでだろうと調べたところ、create-react-app公式にやり方が書いていました。
要は、画像ファイルもモジュールとして読み込みましょうねってこと。
[https://create-react-app.dev/docs/adding-images-fonts-and-files/](https://create-react-app.dev/docs/adding-images-fonts-and-files/)


##コンポーネントを横に並べたいが、一段ずれる
display: flexを使えばうまくいけた
https://mamewaza.com/support/blog/howto-use-flex.html


##初めてのデザイナーとのMTG
いやー、やっぱり細かいところによく気づく。
こういうところが気になって仕方がない人もいるのよねえ。気になって使ってもらえないのが一番最悪。
自分は細かいところは気にならないタイプだから、何か作る時には必ずそーゆう人の意見を聞くようにしよう。
【初心者用】GASを利用してSlackにメッセージを送るbotを作成する

何かしらのメッセージをSlackにbotとして投稿する際に、準備することや書き方をメモがてら記載します

###準備
まだ、投稿したいSlackにbotなどを追加したことがない場合は、以下の手順を踏みます。
　→すでにWebhook URLを発行済みの方は[こちら](https://qiita.com/drafts/4772b2f5c1b21129ab93/edit#%E6%8A%95%E7%A8%BF%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B)

Slackにbotを追加するには【Webhook URL】というものが必要になります。
そのURLの発行・取得の方法をここで記載します。

①[こちら](https://slack.com/apps)にアクセスし上部の「管理」をクリック
②表示された画面の左メニューの「カスタムインテグレーション」をクリック
③その後、上部の検索窓で「incoming Webhook」と入力
④候補一番上に三角っぽいアイコンの「Incoming Webhook」というものが出てくるので、クリック
⑤表示された画面で「Slackに追加」をクリック（以下の画像のような画面です）
![Slackの画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496836/169c6ca2-ac43-ae16-b1cd-43d75b5bbc00.png)
⑥その後、どのチャンネルに追加するかを設定します
　この際テストであれば、一旦自分宛に届く様に設定してもよいと思います
　また、投稿するチャンネルは後から変更できるので、安心して設定しましょう！
⑦チャンネルを設定したら、「Incoming Webhookの追加」をクリック
⑧次の画面で【Webhook URL】が赤字で表示されます 以下のようなURLです。
![3015665dc1367af26b82f96030a89067.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496836/f08d8650-def5-5f2a-d6fe-34d14bff7f54.png)

ここまでで、WebhookURLの取得は完了です。
では、これを使って実際に投稿をためしてみましょう。

###投稿してみる
既にWebhookを設定している方は[こちら](https://slack.com/apps/A0F7XDUAZ--incoming-webhook-?next_id=0)から、【Webhook URL】を取得してください。

実際にGASを利用利用してSlackに投稿できるようにしてみましょう！
まず[こちら](https://script.google.com/home)の画面にアクセスします。
普段はスプレッドシートやフォームに紐づいたGASを利用することが多いのですが、今回はとりあえず投稿を試すだけなので、こちらから新規作成をしてみましょう。
ということで、左上に表示されている「新しいプロジェクト」をクリック！

すると、エディタ画面が開きますので、以下を入力しましょう。

```
function sendToSlack() {
  //このurlの部分には、先ほど取得したURLを入力してください。
  var url = "https://hooks.slack.com/services/XXXXXXXX/XXXXXXXX/XXXXXXXXXXX";
  var data = {
    //ここで投稿したいチャンネルを設定します
    //自分宛に送る場合は「#」以降に、普段自分宛メンションされる時の名前を入力
    "channel" : "#program",
    
    //ここでbotの名前を決めてあげます
    "username" : "botの名前ですん",
    
    //ここで投稿する内容を設定します
    "text" : "こんにちは世界",

    //アイコンを、そのチャンネルにある絵文字の中から選択します
    "icon_emoji" : ":earth_asia:",
    
    "link_names":1};

  //ここから下は魔法の言葉です。
  var payload = JSON.stringify(data);
  var options = {
    "method" : "POST",　　
    "contentType" : "application/json",
    "payload" : payload,
  };
  var response = UrlFetchApp.fetch(url, options);
}
```

これを全てコピペして、【チャンネルだけ変更して】上部の「▶︎」をクリックしてみましょう。
おそらく、承認画面がポップアップで表示されますので、許可してあげると
![こんにちはせかい](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496836/a058ae00-da4f-48d0-4abd-02926382e34b.png)

こんな感じで、投稿が手元に届いたんじゃないでしょうか？
上記コード内でも記載しておりますが、チャンネルやBot名、内容は如何様にも変えることができます。
便利ですね！

###最後に
今回は投稿する方法を説明するだけのページでした。
今後は、別のfunctionでメッセージを生成して、トリガーで投稿するタイミングを決めて...
など様々な内容を書いていきます。

※非エンジニアの記事なので、変な部分があれば逆にお教えいただけると嬉しいです...
vue.js コマンドメモ

```
vue init webpack my-project
npm install -g @vue/cli-init
vue init webpack my-project
npm ls | grep ele
npm i element-ui -S 
npm install @nuxtjs/axios
npm install @nuxtjs/dotenv
npm run dev

npm install --save-dev eslint eslint-plugin-vue
npm install stylus-loader stylus --save-dev
```
Herokuアプリでrails jQuery must be included before Bootstrap's JavaScriptと言われたら

出典：https://stackoverflow.com/questions/45699456/js-jquery-not-working-with-heroku

ローカルではbootstrapもopalもうまく動いていたのに、Herokuにデプロイしたらブラウザのコンソールに「jQuery must be included before Bootstrap's JavaScript」となってしまって困っていました。
bootstrapのインストール方法等、をまずは普通にググッて、間違っていないか確認しましょう。そのうえで、それでもだめなときに、やってみてください。

```
bundle exec rake assets:precompile
```

これでGitコミットして、herokuデプロイしてみてください。
Docker rakeタスクをcron実行したい

# rakeタスクをcronで動かせない
前回の記事では、CronをDocker上で動かす方法を紹介しました。
[CronをDocker上で動かす](https://qiita.com/mofuko0213/items/9ff8090ee7f2860f0f6e)

今回は前回の方法とは違いますが、rakeタスクのcron実行に手こずったところと、解決方法を紹介していきます。

前回はDocker環境でcronを動かすなら、[busybox](https://qiita.com/mofuko0213/items/9ff8090ee7f2860f0f6e)を使用することをおすすめしていました。
しかし、私の環境ではrakeタスクをcron実行する際に起きた問題がありました。

cron実行時(busyboxコンテナでのコマンド実行)に、以下のエラーが発生しました。

```
PG::ConnectionBad: could not translate host name "db" to address: Name or service not known
```
busyboxコンテナが、dbコンテナと疎通できていない！

## 試したこと

- そもそもdbコンテナは立ち上がっているか確認 →　`up`になってる。
- postgresコンテナに環境変数POSTGRES_PASSWORDを設定する。その値をconfig/database.ymlのpasswordに定義する。
- database.ymlの書き換え。

```ruby:database.yml
default: &default
 host: localhost
```
`host: db`となっていた部分を、`host: localhost`に変更しました。
これを行うと、

```
could not connect to server: Connection refused
    Is the server running on host "localhost" (127.0.0.1) and accepting
    TCP/IP connections on port 5432?
```

というエラーの内容に変わります。
これに対して、

- pgの再インストール
- pgの起動確認・rake db:create
を実行するも、エラーの内容に変わりありませんでした。
ちなみに、`rake db:create`はhost:dbのまま実行すれば、問題なかったです。
webも問題なく動いています。

- busyboxのコンテナも、dbコンテナが起動している必要がある構成になっているので、depends_onを付けてみる。

```ruby:docker-compose.yml
  busybox:
    build: .
    volumes:
      - ./crontab:/var/spool/cron/crontabs/root
    depends_on:
      - db
```
しかし、同じエラーが出現してしまい、状況は変わりませんでした。

その他色々と試行錯誤した結果、結局busyboxコンテナをdbコンテナと疎通することができませんでした。(完全に力不足です。2週間悩みましたが解決には至らず...。)

そこで解決までに至ったのが、Dockerのimage内でcronをinstallし、cronを実行する方法です。

# Docker-compoeのコンテナ内でcronを動かす方法

こちらの記事を参考にさせていただきました。
[docker-composeのコンテナ内でcronを動かす](http://my0shym.hatenablog.com/entry/2018/09/05/020019)

## インストール手順

 - Dockerコンテナの中に入る

```
docker exec -i -t myapp_web_1 bash
```

- cronをinstall

```
# apt-get install cron
```

- editorのinstall

```
# apt-get install vim
```

- crontab -eで編集

※ 環境変数を設定する記述がなければ、エラーになります。(私の場合、gemやpathなどの環境変数の設定も必要でした。)
※ 環境変数の値は、`printenv`で確認できます。
※ ruby実行時に、「/usr/bin/env: 'ruby': No such file or directory」というエラーが出現してしまうことを防ぐために、以下を設定します。
rbenvにのせたrubyを使うためのパス設定を~/.bash_profileにしておく。
これをcrontabからの実行でも読み込まれるよう、crontabにbash経由で実行するよう設定。
【参考記事】
https://normalblog.net/system/cron-ruby-command-not-found/#i
https://normalblog.net/system/install/

```
RUBY_VERSION=2.6.5
BUNDLE_APP_CONFIG=/usr/local/bundle
RUBY_MAJOR=2.6
GEM_HOME=/usr/local/bundle
PATH=/usr/local/bundle/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
RAILS_ENV=development
* * * * * /bin/bash -l -c 'cd /myapp/lib/tasks && bundle exec rake notify_user_mailer:notify_user_mail >>/var/log/cron.log 2>&1'
```

`毎分、全てのユーザーに対してメールを送信する`という定期実行を設定しています。

 - cron起動

```
# service cron start
```
すると1分ごとに全てのユーザーにメールが届いており、
見事rakeタスクのcron実行に成功しました！
TDD勉強#1環境構築した&はじめてのテスト駆動開発(July 6th, 2020)

javaの環境構築をした．
#動作環境
- visual studio code
- windows10
 
#vscodeのjava環境構築
下のサイトみた
https://qiita.com/takuma-jpn/items/b49785a314fb4db85775



#早速Hello World!に苦戦
javaで `Hello World!`を表示するプログラム↓

```java:Test.java

public class Test {
    public static void main(String[] args) {
        System.out.println("Hello.World!");
    }
}
```
どうもファイル名とクラス名を一致させる必要があるらしい．沼だった．
あとは，`launch.json`をつくる．フォルダを選択してプロジェクト化する(?)

#maven使ってTDD動いた
下のサイトみた．
https://engineeringnote.hateblo.jp/entry/java/junit_with_maven_in_vscode

注意事項
設定からjavahomeでmavenにチェックを入れる必要がある．

#そもそもjavaが分からない
###classの仕組みてきな

```java:class.java
class AA{
    AA();        //コンストラクタ(?)
    void BB(){
    AA C = new AA();   //インスタンス(?)
    C.BB()
    }
}
```
###新しい知識（キーワード）
- new演算子
- assertEquals(引数1，引数2)：引数が等しいかどうか調べるメソッド

#おわりに
vscodeでpythonでもテスト(javaのテストをpythonに翻訳) しようとしたが，環境構築はうまくいったが，classまわりの書き方が分からず断念．
ひとまず慣れないjavaでTDDを一通り勉強していく．
【IntelliJ】 ショートカット集

## IntelliJショートカット集

### 実装関連
内容 | ショートカット
---|---
なんか色々生成 | ```Ctrl``` + ```n```
フォーマット | ```Opt``` + ```cmd``` + ```l```
エラー箇所修正 | ```Opt``` + ```Enter```
System.out.println | ```sout```と打つ

### 検索関連
内容 | ショートカット
---|---
なんでも検索 | ```shift```2回
キーワード検索 | ```cmd``` + ```Shift``` + ```f```
ファイル内置換 | ```cmd``` + ```r```
コマンド検索 | ```cmd``` + ```Shift``` + ```a```

### ジャンプ関連
内容 | ショートカット
---|---
定義に移動 | ```cmd``` + ```b``` 
実装に移動 | ```cmd``` + ```Opt```  + ```b```
親クラスに移動 | ```cmd``` + ```u```
使用箇所検索 | ```Opt``` + ```F7```

### テスト関連
内容 | ショートカット
---|---
実装クラスとテストクラスの移動（もしくはテスト作成） | ```cmd``` + ```Shift``` + ```t``` 
テストの実行 | ```Opt``` + ```Shift```  + ```F10```
テストの実行 | ```⌃``` + ```R```
テストのデバッグ実行 | ```⌃``` + ```D```

### 表示関連
内容 | ショートカット
---|---
プロジェクトウィンドウ表示切替 | ```cmd``` + ```1```
デバックウィンドウ表示切替 | ```cmd``` + ```0```

### コードフォーマット
内容 | ショートカット
---|---
コードフォーマット | ```cmd``` + ```Opt```+ ```L```
ExcelVBAで行の繰り返し処理をしたときに使ったやつ

（何番煎じだ！ とか言わないで）

# はじめに

ExcelVBAで何らかのデータ加工をする際、避けては通れないのが行の繰り返し処理。
他言語では「値が空白でない間繰り返し」などで簡単に実装できますが、ExcelVBAでは空白判定そのものが複雑怪奇で、さらにVBAの仕様も相まって、スパゲティソースになってしまうことが多々あります…

そこで

* データの終端を表す文字列を明示的に記入してもらう
空白もデータとして取り扱いたい時にも有用

* 終端文字列の記入漏れによるフリーズを防ぐ機構の追加
これがないと限界までループを回すことになり、プロセスが応答しなくなり、最終的に桁あふれで落ちたりするかもしれません。

という仕様で、汎用的に使えるよう実装してみることにしました。

以下のVBAは、Excel 2010で動作確認を行いました。


# コードと解説

```vb
Sub ボタン1_Click()

    ' 1) 各種定義
    '    「読取現在行数」は、行のポインタとして使用している。2行目から読取開始するものとする
    EOL文字列 = "EOL"
    読取現在行数 = 2

    ' 2) EOL文字列が存在するかどうか
    '    A列のデータが埋まっている最終行番号を検索し、上方向にEOL文字列を探す
    '    Excelが認知している最大行から、上方向にデータが入っているセルを探しに行く
    '    終端文字列が存在しなければ、メッセージボックスを表示し処理を中断する
    EOL文字列が存在する = False
    使用済み行数 = Cells(Rows.Count, 1).End(xlUp).Row
    For i = 使用済み行数 To 読取現在行数 Step -1
        If Cells(i, 1) = EOL文字列 Then
            EOL文字列が存在する = True
            Exit For
        End If
    Next i
    If EOL文字列が存在する = False Then
        ret = MsgBox("終端文字列が見つかりません。" & vbCrLf & "A列の最終行に「" & EOL文字列 & "」を記入してください。", vbCritical + vbOKOnly)
        Exit Sub
    End If

    ' 3) 処理を止める
    '    自動計算をオフ、イベント発火の阻止、画面更新を中止することにより、動作速度の向上を図る
    With Application
        .Calculation = xlCalculationManual
        .EnableEvents = False
        .ScreenUpdating = False
    End With

    ' 4) メインループ
    '    終端文字列が出てくるまで繰り返し処理を行う
    Do While Cells(読取現在行数, 1) <> EOL文字列

        ' 何らかの処理

        ' 5)「応答なし」回避
        '    たまに DoEvents を挟むことにより、「応答なし」を回避する
        If 読取現在行数 Mod 3 = 0 Then DoEvents

        読取現在行数 = 読取現在行数 + 1
    Loop

    
    ' 6) 止めた処理を元に戻す
    '    (3)で止めた項目を再度有効にする
    With Application
        .Calculation = xlCalculationAutomatic
        .EnableEvents = True
        .ScreenUpdating = True
    End With

End Sub
```

## 既知の問題、Tips

* 終端文字列が複数存在した場合、最初に出現したところで処理終了してしまう
最後に出現するところまでループしたい場合は、 (2) の 検索ループ内の添え字 `i` を終了行数として使って、メインループを`For`で回せばよい

* 終端文字列を使わず、最終行番号まで繰り返し処理を行いたい
(2)の「使用済み行数」を流用し、メインループを`For`で回すとよい。
Scrapbox向けにURLを整形してコピーするブックマークレット

## はじめに
[Scrapbox](https://scrapbox.io)は手軽で便利なドキュメント共有サービスです。
ただ、ドキュメントを書く上での記法が特殊です。
個人的に、よくWebページへのリンクをScrapboxへ記載するので、Scrapbox向けにURLリンクを整形し、クリップボードへコピーするブックマークレットを作りました。

## ブックマークレット

次がブックマークレットです。

```js
javascript:(
    function(){
        let scarpLink = '['+document.title.replace(/\s*[\[\]]\s*/g,' ')+' '+location.href+']';
        if(navigator.clipboard){
            navigator.clipboard.writeText(scarpLink);
        }
    }
)();
```

1. 適当なページをブックマークする
2. ブックマークのタイトルを、CopyScrapboxLinkに編集する
3. ブックマークのURL部分に、上記ブックマークレットを貼り付け

とすれば、ブックマークレットを登録できます。


## 参考文献
[Scrapbox - チームのための新しい共有ノート](https://scrapbox.io/product)
WebpackのMultiple Targetsを使ってIE11互換とそうでないjsを一度でビルドする

# やりたいこと
IE11向けのページと、そうでないページのビルドをどっちも一度の`webpack`コマンドでビルドする。よくありそうなケースとしてはLPサイトはIE11向け、そうでないページはパフォーマンスを考えて少しでも容量が少なくなるようIE11互換を切りたい、二つのビルド設定が必要だがビルドは１コマンドで行いたいようなケース。またはUA判定してIEはIE11互換のjsを読み込んで、そうでないブラウザはIE11互換を切ったjsを読み込ませる、など。

# 動作確認済の実装
https://github.com/yas-tyoukan/webpack-multi-build-sample

# Webpack Multiple Targets

https://webpack.js.org/concepts/targets/#multiple-targets

`webpack.config.js`で返すwebpackの設定オブジェクトは、配列で返すことができ、それを使って複数の設定を記述できる。

# caller
babel-loaderのoptionsに、babelのconfigに渡せる`caller`を設定できる

https://babeljs.io/docs/en/options#caller

babelの設定箇所(`babel.config.js`)で、`caller`を使って呼び出し元の情報を取得できる

https://webpack.js.org/loaders/babel-loader/#customize-config-based-on-webpack-target


# 具体的な実装

webpack.config.babel.js

```js
import path from 'path';

export default (env, args) => {
  const isProduction = args.mode === 'production';
  const devtool = !isProduction && 'inline-source-map';
  const rules = [
    {
      test: /\.js?$/,
      use: ['babel-loader'],
    },
    {
      test: /\.css$/,
      use: ['style-loader', 'css-loader'],
    },
  ];

  const plugins = [];

  return [{
    devtool,
    entry: './entry.js',
    output: {
      path: path.join(__dirname, './'),
      filename: 'bundle.js',
    },
    module: { rules },
    plugins,
  }, {
    devtool,
    entry: './entry.js',
    output: {
      path: path.join(__dirname, './'),
      filename: 'bundle_for_ie.js',
    },
    module: {
      rules: [{
        test: /\.js?$/,
        use: [{
          loader: 'babel-loader',
          options: {
            caller: { target: 'ie11' },
          },
        }],
      }, ...rules.slice(1)],
    },
    plugins,
  }]
};

```

babel.config.js

```js
const isIncludeIE11 = (caller) => caller && caller.target === 'ie11';

module.exports = (api) => {
  const includeIE11 = api.caller(isIncludeIE11);
  const targets = {
    chrome: '79',
    firefox: '72',
    safari: '13',
  };
  if (includeIE11) {
    targets.ie = '11';
  }
  const presets = [
    [
      '@babel/preset-env',
      {
        targets,
        useBuiltIns: 'entry',
        corejs: 3,
        debug: true,
      },
    ],
  ];

  const plugins = [];

  return {
    presets,
    plugins,
  };
};

```

# 結果（一部抜粋）
見やすくするためにdevelopment buildにしている

bundle.js

```js
const buttonEl = document.getElementById('sample-button');
const inputEl = document.querySelector('[name=key]');
buttonEl.addEventListener('click', () => {
  alert(Object(_maskKey__WEBPACK_IMPORTED_MODULE_0__["default"])(inputEl.value));
});
```

bundle_for_ie.js

```js
var buttonEl = document.getElementById('sample-button');
var inputEl = document.querySelector('[name=key]');
buttonEl.addEventListener('click', function () {
  alert(Object(_maskKey__WEBPACK_IMPORTED_MODULE_0__["default"])(inputEl.value));
});
```
~「クラウドAI開発講座」に挑戦してみたとある高専生の道のり#1~

##目次
1.この記事について
2.はじめに
2.7/25までのッション
2.進捗状況
3.次回までの目標

#1.この記事について
　高専キャリアとMicrosoftがコラボした「クラウドAI開発講座」というものに参加しました！与えられたミッションは「Azureを使ってteams連携のbotを開発すること」、期間は約２ヶ月間でメンターさんに相談できる環境です。この記事はその道のりを1週間ごとに報告するものになります！


#はじめに
　私は自分のできること作りたい！しかし何をどう始めればいいのか分からず気持ちばかりで何もできずにいました。そんな時に高専キャリアを知りました。私はプログラミングはほぼ初心者でAzure? AI?と知識も全然ないのにやる気と勢いだけで挑戦してしまった高専生です:scream:とにかく最後までやる！こんな気持ちでやっています
 [高専キャリアONELINE](https://t.co/bkPHtGobbK?amp=1) 

#2.7/25までのミッション

####step1- Azure For Studentsに登録する

- https://azure.microsoft.com/ja-jp/free/students/?WT.mc_id=azureforstudents-docs-nosuzuk


####step2-de:code2020に登録し以下のコンテンツを視聴し学習する

- https://www.microsoft.com/ja-jp/events/decode/2020session/detail.aspx?sid=Z01
- https://www.microsoft.com/ja-jp/events/decode/2020session/detail.aspx?sid=A02


####step3-Microsoft Learn For Studentsで学習する

- https://docs.microsoft.com/ja-jp/learn/roles/student?WT.mc_id=BlendedCurriculum-MSLearn-nosuzuk

####step4-ちょまどさんとおーちょさんのレッスンを消化する

- https://qiita.com/chomado/items/6bda10abde0551f25723
- https://qiita.com/miokawa/items/6f1a3e480580e1e29abc


#進捗報告

- step1~2は完了しました。


 はじめにde:code2020に登録しようとサインインを押すとサイトが真っ白になって入力も何もできない事態が起き、え〜となりました:sweat_smile:再起動や時間を置いてみたりキャッシュクリアを試しても同じことが起きてしまう、Google Chromeをダウンロードしインストールしてやっと解決しました。こんな最初のところから時間がかかっててしまいました:sweat:

-  [Google Chrome無料ダウンロード](https://www.google.co.jp/chrome/)



#次回までの目標

- ちょまどさんのレッスンを消化すること
 https://qiita.com/chomado/items/6bda10abde0551f25723

- Azureとその活用について理解を深めること
[Mac] brewでVirtualBoxをinstallしようとして「製造元に問い合わせてください」エラー

# インストールコマンド
brew cask install virtualbox

# エラー内容
installer: The install failed (エラーによってインストールできませんでした。ソフトウェアの製造元に問い合わせてください。)
==> Purging files for version 6.1.10,138449 of Cask virtualbox

# 解決
システム環境設定 > セキュリティとプライバシー
一般のタブに「~Oracle~」の許可ボタンがあるので、ぽち
その後、再度インストール
GitHub Actions に待望の手動トリガーが実装されました

# The GitHub Blog

[GitHub Actions: Manual triggers with workflow_dispatch](https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/)

# 概要

今まで GitHub Actions を手動で実行するには WebHook イベントや外部イベントなどを使って自前実装するしかありませんでした。[^1]
今回、手動で実行するためのトリガーとして `workflow_dispatch` イベントが実装されたので紹介します。

# 実装方法

```yml
on: 
  workflow_dispatch:
    inputs:
      パラメーター名:
        description: '説明'
        required: true
        default: 'デフォルト値'
```

`workflow_dispatch` を指定します。
`inputs` にパラメーターを設定できます。パラメーター名に日本語は使えません。
各パラメーターには `required`, `description`, `default` の3つの値を設定できます。いずれも省略可能です。

設定したパラメーターには `${{ github.event.inputs.パラメーター名 }}` でアクセスできます。

手動トリガーが設定されると Actions タブのワークフローに `This workflow has a workflow_dispatch event trigger. [Run workflow]` という項目が追加され、 `[Run workflow]` から手動実行できるようになります。
パラメーターをここで指定します。実行ブランチも選択できるようです。

# パラメーターなしサンプル

パラメーターなしで手動実行するサンプル。

## コード

```yml:.github/workflows/manual.yml
name: Manual Trigger

on: [ workflow_dispatch ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - run: echo Hello, world!
```

## 実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455401/bc290e56-913c-a6c9-6405-b5a2887b160e.png)

## 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455401/ea35aab0-4986-8786-1c7a-fe752b2ad9c7.png)

# パラメーターありサンプル

パラメーターありで手動実行するサンプル。

## コード

```yml:.github/workflows/manual.yml
name: Manual Trigger

on:
  workflow_dispatch:
    inputs:
      logLevel:
        required: true
        description: ログレベル
        default: warning
      tags:

jobs:
  printInputs:
    runs-on: ubuntu-latest

    steps:
    - run: |
        echo "Log level: ${{ github.event.inputs.logLevel }}"
        echo "Tags: ${{ github.event.inputs.tags }}" 
```

## 実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455401/e1fc61aa-f6e0-c6b9-2859-ed09a2d9ddfe.png)

## 結果

パラメーターなしと同じなので省略します。

[^1]: [GitHub Actions で手動トリガーのワークフローを作る - Qiita](https://qiita.com/proudust/items/51599abd2b107b708e1e)
REST APIベースwebアプリ開発時のHTTPキャッシュについて【GCP使用】

# 概要

自分はサーバサイドをCloud runにてPython(Flask)、クライアントサイドはFirebaseにてJavascript(Vue.js)で開発しています。pythonではFirestoreのデータの読み書きを主に行っています。このとき、以下の二つの課題に当たってしまいました。

1. GETリクエストしているのに、OPTIONSリクエストしている（ブラウザにて確認）
- GETリクエストがCloud runに届いていないが、レスポンスが返ってくる。このとき、PUTなどでFirestoreの内容を変更していても、GETリクエストのレスポンスが以前のFirestoreの内容になっている。

本記事は、これらの原因と対策について示します。

# 「1.」について

1については、OPTIONSリクエストはプレフライトリクエストと言い、単純リクエストではない場合、CORS プロトコルが理解されているかどうかを確認する CORS リクエストであるらしいです。これはクライアント側のリクエスト設定を見直すと飛ばなくすることが出来ます（REST APIの時、Authrizationヘッダがある場合があるため、飛んでしまうことが多いかもしれない）。プレフライトリクエストについては、以下のサイトを参考にしてください。結局これは特に問題ではなかったので、ここまで。

- オリジン間リソース共有 (CORS)：[https://developer.mozilla.org/ja/docs/Web/HTTP/CORS](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)


# 「2.」について

こちらは、HTTPキャッシュが原因となっています。**サーバサイドでレスポンス生成した際、自分はHTTPキャッシュに係る「Cache-controlヘッダ」を設定していなかったことが原因でした**。これにより、本来Cloud run側にリクエストがいかず、FirebaseにあるHTTPキャッシュがクライアントサイドにレスポンスされていました。deploy後の1回目のGET通信は問題ないですが、その後はFirestoreの内容を変更しても、2回以降のGET通信は1回目の内容と同じものとなってしまいます。

- HTTP キャッシュ：[https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=ja](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=ja)
- HTTP キャッシュ(MDN web docs)：[https://developer.mozilla.org/ja/docs/Web/HTTP/Caching](https://developer.mozilla.org/ja/docs/Web/HTTP/Caching)

# おわりに

もしかしたらweb屋さんの常識過ぎるためか、あまりそれっぽい記事はありませんでしたので、備忘録として記述しました。
Wi-Fiが不安定な原因

# ・はじめに
現在インフラ関連を独学で学習中の者です。
ふと喫茶店にてWi-Fiが不安定になったので調べてみると様々な
原因が見つかり、思い切ってQiita書いてみました。
セキュリティや付随したことを調べるのが好きなので記載します。


## ・主な原因

## 1.ファームウェアが最新版ではない

#### ファームウェアとは
 
電子機器に組み込まれたシステムを制御する為の`ソフトウェア`、機器に__組み込んだもの__
書き換えることのない媒体に__書き込まれたもの__
現在では半導体メモリ価格の下落により、C言語などの
高級な言語が使用できるようになった

> バージョンを管理してupdateしないと問題が生じる原因になる
あと半導体ってのが気になったので付け足します。↓


#### 集約回路

セキュリティチップのこと
`Worm機能`などが盛り込まれ、__中間者攻撃__や__サイドチャネル攻撃__からシステムを防御する
ICチップが世界で最も使用されているらしい
バックエンドシステムにDBを備え、そのDBにアクセスする鍵が格納される


- `サイドチャネル攻撃`
暗号解読方法
処理時間に注目したタイミング攻撃や装置から漏洩する電磁波に注目した電磁波解析攻撃がある



- `中間者攻撃`
盗聴等の方法
攻撃者が被害者との間に独立した通信経路を確保し
Messageを中継し横取りする攻撃
中間部分でAへ偽の情報 Bへ偽の情報とお互いに公開鍵の認証を捏造することで
原理的に成功するパターン



### Worm機能
1度書き込んだ`データを消去、変更できない`追記型の記憶方式
セキュリティの強化に有効

>PCのシステム的に不具合が生じている可能性が原因ってのもあるのがわかりました。

## 2.LANドライバが正しく動作していない
#### LANドライバとは
PCなどに接続されているネットワーク関連の機器をOSによって制御する専用のソフトウェア

>LANドライバ周りで補足

### SSID
`アクセスポイントの識別名`<br>グループ分けをし認証にも使用される
最大32文字の英数字が設定できる<br>アクセスポイントとクライアントの設定を一致させないと接続できない

### WPA
上で通信を暗号化して保護するための技術規格の一つ<br>1.2.3とバージョンが続いており脆弱性問題で<br>バージョンを上げては問題が発生するのいたちごっこになっている



## 3.IPアドレスの自動割り当てが正常ではない

そもそも私は__PCにIPアドレスを設定した覚えがない__
PCにはIPアドレスを自動で設定してくれる機能もある
IPアドレスを自動で割り当てる仕組みを
作っちゃえと考え出された技術が、`DHCP`

### DHCP
>（__Dynamic__ Host Configuration Protocol）

自動割り当ての中にはIPアドレス取得と他にも
__サブネットマスク__、__デフォルトゲートウェイ__、__DNSサーバ__等の情報も取得している
DHCPを使ったIPアドレス自動割り当てを行っているネットワーク上には
少なくとも1台以上のDHCPサーバが存在

※補足
`・スタティック`
自身がどこにルーティングしていいのかわからない
`・ダイナミック`
自立的にルーティングできる
### サブネットマスク
クラス分けを簡単に見分けれるみたいなもの
これを調べることによりどこまでが`ホストアドレス`なのか<br>`ネットワークアドレス`なのか調べることができる

### デフォルトゲートウェイ
別のネットワーク間で最初に通るルータ
次に通るルータがわからないと迷子になる
ルーターにはMACアドレスが必ず1つ割り振られている
このMACアドレスを使い次々道が割り当てられている
ルーターを通るごとにMACアドレスは変更される


### DNSサーバ
ドメインからIP変換してくれる
これによってサイトが見れてる
IPアドレスを文字列化する仕組みがあるサーバ

- `DNS経由のweb画面が表示されるまで`<br>
1.DNSサーバにアクセスしIPアドレスを特定<br>
2.そのIPアドレスの持つサーバにHTTPリクエストを要求<br>
3.サーバ側が承認すると’200ok’をレスポンスで返す<br>
4.サーバからネットパケットという情報でリクエスト側に返る


## 4.そもそも電波力が弱い
意外にも物理的なダメージを受けやすく
通り抜けはするが強度は弱くなる
主に__`2.4GHz`__  __`5GHz`__の2種の周波数が使用されている

### 2.4GHz
◯障害物があっても電波が`届きやすい`
✖︎他からの干渉を受けやすく、速度が`遅い`

### 5 GHz
◯電波干渉(電子レンジ等)を受けにくく、通信速度も`早め`
✖︎障害物に弱く、壁や家具で電波が`届かない場合がある`

# 終わりに
かなり脱線しましたが、環境や状況によってWi-Fiが不安定になると知りました。
周辺の知識を今一度学習しようと思います。
twitterにてアウトプットを日頃しています
PHPで配列を比較して差分を抽出するときに使えるメソッド

# はじめに
PHPで配列の要素の比較をしたいと思い、調べていたら、「array_diff」というメソッドがあり、使ってみたら便利だったので、備忘録を残します。

# 使い方（例）
```hoge.php
<?PHP
$array1 = ['a', 'b', 'c'];
$array2 = ['a', 'b', 'c'];
$array3 = ['b', 'c', 'a'];
$array4 = ['a', 'b'];
$array5 = ['a', 'b', 'c', 'd'];

// 順序、値が一致する場合
$diff1and2 = array_diff($array1, $array2);
print_r($diff1and2);
// Array()

// 順序が不一致、値が一致する場合
$diff1and3 = array_diff($array1, $array3);
print_r($diff1and3);
// Array()

// $array1と$array4の値が不一致（$array1に「c」が存在）
$diff1and4 = array_diff($array1, $array4);
print_r($diff1and4);
// Array([2] => c)

// $array1と$array5の値が不一致（$array5に「d」が存在）
$diff1and5 = array_diff($array1, $array5);
print_r($diff1and5);
// Array()

```

# 参考
[array_diff](https://www.php.net/manual/ja/function.array-diff.php)
「bundle install」するとgem系のファイルについて大量にgit差分が発生してしまう

###  <font color='lightblue'>発生した背景</font>
新しいgemを入れるときに、以下のコマンドを実行するとgitに大量に差分が発生することがあります。

```:コマンド
bundle install --path vender/bundle
```

（スクショの「Unstaged Files（1）」というところが、10000とかになったりする。ごめんなさい、再現ができなかったです）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647299/712e9a14-4552-8860-7bf2-f638093e3874.png)

<font color="red">この件について対応方法を検討したいと思います。</font>

###  <font color='lightblue'>環境</font>
| 項目              |               内容 | 
|:-----------------|:------------------:|
| OS.Catalina      |           v10.15.4 |      
| Ruby             |            v2.5.1 |  
| Ruby On Rails    |           v5.2.4.3 |   
| Git          |           2.20.1 |   


###  <font color='lightblue'>対応手順</font>

【1】Gitignoreを編集する。
Gitignoreのフォーマットなるものがあります。
詳しくは参考文献「編集済みの.gitignoreを簡単に得る方法」を。
以下内容を掲載しておきます。

```:.gitignore
*.rbc
capybara-*.html
.rspec
/log
/tmp
/db/*.sqlite3
/db/*.sqlite3-journal
/public/system
/coverage/
/spec/tmp
**.orig
rerun.txt
pickle-email-*.html

# TODO Comment out this rule if you are OK with secrets being uploaded to the repo
config/initializers/secret_token.rb

# Only include if you have production secrets in this file, which is no longer a Rails default
# config/secrets.yml

# dotenv
# TODO Comment out this rule if environment variables can be committed
.env

## Environment normalization:
/.bundle
/vendor/bundle

# these should all be checked in to normalize the environment:
# Gemfile.lock, .ruby-version, .ruby-gemset

# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc

# if using bower-rails ignore default bower_components path bower.json files
/vendor/assets/bower_components
*.bowerrc
bower.json

# Ignore pow environment settings
.powenv

# Ignore Byebug command history file.
.byebug_history

```

特に「/vendor/bundle」が重要ですね。
gitにあげるとパフォーマンスも落ちますし、よくないことだらけなので私は、上記を書き換えるだけでなく、既存のファイルに追記という形をとりました。


###  <font color='lightblue'>参考文献</font>
[編集済みの.gitignoreを簡単に得る方法](https://www.sglabs.jp/github-gitignore-gibo/)
Bitrize + mac + unity でモバイルアプリを作成する時に調べたこと

とりあえずCIツール知識が0な自分でcliを使って色々しようとして
調べる必要があった部分のメモ書き

BitrizeとGithubActionを使ってみようとしたけど
基本１こ使い方覚えれば、少しは学習コストが下がりそうだなぁ
と思った。

### yaml に泣かされる

半角スペースの個数に泣かされる
https://qiita.com/jerrywdlee/items/d5d31c10617ec7342d56

### Xcodebuild　コマンドを使うにはインストールが必要だと知る

※これ結果的に不要ポイ？
https://qiita.com/mym/items/8bc079b7d0f5f55c49dc

```
error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance
```
と思ったらXcodeのインストール済みなら設定画面で設定すれば良さそうだったと言う罠
https://qiita.com/eytyet/items/59c5bad1c167d5addc68


###project_pathはファイル名を指定する

Bitrizeの ymlファイル内にて
contents.xcworkspacedataが無いみたいなエラーでなんぞや？と思ったらそう言うことだった。

```
    - xcode-archive@2.8.5: 
        inputs:
        - project_path: ./output/Unity-iPhone.xcodeproj
        - scheme: Unity-iPhone
```



んで出来上がったipaファイル何処いったんだ？

output delectoryにできた。

```
/var/folders/_v/r_bddp7d4z3c650zzb4xhw940000gp/T/deploy706604927
```
何処だよこれ！
ちなみに
`- app_path: $BITRISE_IPA_PATH`
みたいな環境変数を使えば動いてくれるっぽいのであんまりいらない


# Deploygateに upできない

これなんで解決したんだっけかな・・・
TOPぺージのコマンド入れたおかげ？

```
INFO[11:06:05]  * [OK] Step dependency (curl) installed, available. 
curl: (26) Failed to open/read local data from file/application
{"message":"You do not have a permission to upload applications.","because":"You do not have a permission to upload applications.","error":true}|
```

### terminal
途中でやめたくなった時のコマンド
Control + C

### yamlの文字列の扱い
シングルクォーテーション、ダブルクォーテーション等
あろうがなかろうが関係ないなかろうが関係ない
https://neos21.hatenablog.com/entry/2020/01/11/080000

### バッチ(command)ファイル

windowsだと batだけど
macの場合 commandファイルね

`chmod u+x login.command`
こんな感じで権限付与しないと動かない
https://qiita.com/TatsuyaOGth/items/f15bfa9aeb68d8ecfc67


これバッチを作った時のカレントディレクトリーを変更するコマンド、超大事
```
cd `dirname $0`
```


# terminal が閉じない

https://ocs.hatenadiary.org/entry/20111010/1318209350


# 隠しファイルの表示方法
Mac の Finder で 隠しファイル を表示するためのショートカットは command + shift + . 

# Provisioning Profiles
cd ~/Users/******/Library/MobileDevice/Provisioning Profiles
DataFrameで'nan'が消えてしまうのを直す。

CSVの段階で"nan"という文字列を利用していたのに、DataFrameに入れたときに勝手に'NaN'になってしまうので困った。
もう一度"nan"を利用するためには、`fillna('nan')`を使うことで解決。
まぁ空の部分も'nan'になるんですけど


```Python
import math
import numpy as np
import pandas as pd
# データの作成
data = [
    ['', 1, '2', 3],  #
    [math.nan, np.nan, pd.np.nan, 'np.nan'],
    [None, None, 'nan', 'nan']
]
df = pd.DataFrame(data)
df.to_csv('test.csv')

# CSVにある'nan'を読み込むとNaNになる
df = pd.read_csv('test.csv')
print(df)
#   0    1    2       3
# 0 NaN  1.0  2.0       3
# 1 NaN  NaN  NaN  np.nan
# 2 NaN  NaN  NaN     NaN

# fillnaをするとnanになる
na = df.fillna('nan')
print(na)
#     0    1    2       3
#0  nan    1    2       3
#1  nan  nan  nan  np.nan
#2  nan  nan  nan     nan
```
メッセージに含まれる特定の単語を＊で置き換える


##文字を置き換えたい
メッセージに含まれる不適切な単語を＊で置き換える処理を考える際に作った関数です。
例)
置き換える単語の配列 = ["ハンバーグ","アメリカ合衆国"]
「今日のご飯はハンバーグだ」-->「今日のご飯は＊＊＊＊＊だ」
「アメリカ合衆国に留学したい。」--> 「＊＊＊＊＊＊＊に留学したい」

のように、指定した文字列を＊に置き換える処理をします。
置き換えたい文字を要素にもつ配列を作れば利用することができます。
Swiftには指定した文字を置き換える`replacingOccurrences`,指定した文字列を繰り返す`String(repeating:, count:)`があるのでそれらを組み合わせていきます。

##ソースコード
```Swift
import UIKit
let prohibittenWordArray = ["落とし前","ゲーセン"]

//不適切な文字を置き換える関数
func checkMessage(_ message: String) -> Void {
    var message = message
    for prohibittenWord in prohibittenWordArray {
        if message.contains(prohibittenWord) {
            message = message.replacingOccurrences(of: prohibittenWord, with: convertWord(prohibittenWord.count), options: .literal, range: nil)
        }
    }
    print(message)
}

//禁止用語を文字数分の*に置き換える
func convertWord(_ wordCount: Int) -> String {
    return String(repeating: "*", count: wordCount)
}
checkMessage("こんにちは")//こんにちは
checkMessage("ゲームセンターで落とし前をつける")//ゲームセンターで****をつける
checkMessage("ゲーセンで財布落とした")//****で財布落とした
```
flex box 基礎

レイアウトを整えるにはfloatやmargin:0 auto;を使っていましたが、Flexboxがとても便利だったので備忘録とて投稿します。

参考>https://coliss.com/articles/build-websites/operation/css/css3-flexbox-properties-by-scotch.html
#Flexboxの利点
flexboxとは、『簡単にいい感じのレイアウトにですることができるcssの仕組み』
floatやmargin:0 auto;と違った利点があります。

　　・複雑な内容を上下左右に簡単にレイアウト可能
　　・高さが消えず、clearfixが不要
　　・HTMLソースはそのままに、CSSのみで順序を入れ替え可能
　　・中央寄せ、均等分布などの画像ソフトで行なうような整列をHTML上で簡単に実現可能
　　・親や子のサイズが拡大縮小しても、その空間に応じて柔軟性高くレイアウトが可変する

などなど

#Flexboxの注意点
　　・古いブラウザだと非対応
　　・IEでは最新版でも挙動がおかしい場合がある
#FlexコンテナーとFlexアイテム
Flexレイアウトは大きく分けて2種類の要素に分かれており、それぞれ設定できるプロパティが異なります。

####Flexコンテナー
Flexレイアウトを行うための親の箱です。下例で紹介しますがdisplay:flexと設定することでFlexコンテナーになります。
####Flexアイテム
Flexコンテナー直下の要素は全て自動的にFlexアイテムとなります。
※Flexアイテム内に更にdivが含まれるなど、入れ子になっているアイテムはFlexアイテムとはなりません。

#基本のflexレイアウト
```php:html
<div class="flex">　/* flexコンテナー */
    <div>1</div>　/* flexアイテム */
    <div>2</div>　/* flexアイテム */
    <div>3</div>　/* flexアイテム */
</div>
```

```php:css
.flex {
    background-color: grey;
    display:flex;
}
.flex > div {
    background-color: white;
    margin: 10px 10px;
}
```
すると<img width="1147" alt="スクリーンショット 2020-07-07 9.09.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641744/0034ff66-5a2c-add6-387b-995bfcf1edb2.png">
こんな感じ

これの親要素（.flex)のCSSにdisplay:flex;を追加します


```php:css
.flex {
    background-color: grey;
    display:flex;/* 追加 */
}
.flex > div {
    background-color: white;
    margin: 10px 10px;
}
```
<img width="1154" alt="スクリーンショット 2020-07-07 9.20.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641744/3380f5eb-8271-21b4-0fe2-018478d04849.png">
これだけで、簡単に横並びのレイアウトを作ることができました。

さらに追加します。

```php:css
.flex {
    background-color: grey;
    display:flex;
    justify-content: center;/* 追加　*/
    align-items: center;/* 追加 */

}
.flex > div {
    ~省略〜
}
```
<img width="1151" alt="スクリーンショット 2020-07-07 9.34.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641744/36fd2591-6f2e-cace-86bf-d0ebe2cc1caf.png">

こんな感じで簡単にレイアウトを変更できます。
#まとめ
便利なFlexboxのおかげでのおかげで思い通りのレイアウトが格段にやりやすくなりました。
この記事で紹介できなかったプロパティがまだまだ沢山あるので、また別記事で書きたいと思います。

ゲームでflexboxを学べるのでおすすめ
https://flexboxfroggy.com/#ja
Rテクニック データの読み込み csv/excel/sas7bdat

Rによるcsv/excel/sas7bdatの読み込み

read.csvなどが用意されているが、遅い
freadやreadrがおすすめ
SASデータセットの読み込みならhavenやsas7bdat

# fread

```r
# ライブラリ
library(data.table)
library(tidyverse)
library(sas7bdat)

# dataの保管先
File_Pass <- "パス/ファイル名"

# 列の名前や型を定義しておく
Var_Name <- c( "列名1" , "列名2" , "列名3" )
Var_Type <- c( "character" , "numeric" , "numeric" )

Csv_Data <- fread( file = File_Pass , sep = "," , col.names = Var_Name , colClasses = Var_Type , stringsAsFactors = FALSE , skip = 1 , header = FALSE , na.strings = "" , data.table = FALSE )
```
sep = ","を変更すれば、区切り文字が「,」じゃなくても読み込むことが可能
skip = で何行目から読むのか(1行目に列名あるのかどうかなど)
header = FALSEで列名をcsvから取らない
(データに列名まで含まれていない場合や、列名はskipしている場合に使用)

列の定義面倒くさい場合、全部文字変数としてしまえばいいかも

# readr
read_csv:csv読み込み
read_delim:テキストファイル読み込み(区切り文字を選べる)
excelはreadxlのread_excelでも読み込める
シートはsheetかrangeで指定

```r
File_Pass <- "パス/ファイル名"
Rg <- "シート名!A1:E100"
Excel_Data <- readxl::read_excel( path = File_Pass , range = Rg )
```

readrはチートシートあるので、細かな仕様は略
(Rstudioにていくつかのチートシートを公開している)
https://rawgit.com/rstudio/cheatsheets/master/data-import.pdf

日本語含むときはこっちのほうが使いやすい

# sas7bdat
read.sas7bdat:SASデータセット読み込み

特別な指定は不要

```r
File_Pass <- "パス/ファイル名"
Data <- read.sas7bdat( file = File_Pass )
```
※sas7bdatの場合はcompress = yesしているデータセットを読み込めないため、havenのread_sasの方がいいかも
ただし、havenのread_sasは日本語のデータでエラーが出ることがあったので、微妙な感じもする…

https://www.rdocumentation.org/packages/readr/versions/1.3.1
https://www.rdocumentation.org/packages/readxl/versions/1.3.1/topics/read_excel
https://readxl.tidyverse.org/reference/read_excel.html
https://readxl.tidyverse.org/reference/cell-specification.html
https://www.rdocumentation.org/packages/data.table/versions/1.14.0/topics/fread
https://www.rdocumentation.org/packages/sas7bdat/versions/0.5/topics/read.sas7bdat
https://www.rdocumentation.org/packages/haven/versions/2.4.1/topics/read_sas
https://haven.tidyverse.org/
Nuxt.jsで動的に画像のパスを指定する💪🐻

#Nuxt.jsで画像のパスを指定したかった
requireを使って解決しました
（パスというより名前の指定な気もする…）

##失敗：よっしゃこれで…

```
 <img src="@/static/images/{{ $store.state.img }}" /> 
```

ダメだった🥺🥺🥺🥺🥺🥺🥺🥺🥺🥺🥺🥺

##成功：じゃあこれで…

```
<img :src="require(`@/static/images/${$store.state.img}`)" />
```

ヤッターうまく表示できた💪💪💪💪💪💪💪💪🐻
俺のVR 2020/07/06: VRの感動

# VRの感動

俺はただの外国人のオタクです。　ゲームが好き、SFが好き、サイバーパンクも好きです。
今までのゲームはすべてスーファミやファミコンの「スーパーマリオ」や「ぷよぷよ」などなどです。
「DOOM」もめっちゃやってた。こどものごろも3D環境でチャットが大好きでした。

バーチャルリアリティーはいつでも遠い未来の話だと思いました。
オキュラスクエストを買って、世界観は全く変わりました。「未来はもう届いたよ」とわかりました。

![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393501/2a8ac457-024d-1daa-8133-5c3500db52c5.jpeg)
↑俺のお友達ですけど。

やるとき、マジで別の世界に入っていてると思います。
ハンドトラッキングは内臓のカメラでキャプチャーしているので、コントローラーなしで、自分の手だけでバーチャル世界に入れます。すごくない？？？

今までのゲームはすべてオキュラスショップの１千円から３千円のゲームですけど、
オキュラスクエストはPCを繋がれます。PCのゲームはまったく安いし、めっちゃキレイな映像もできます。

## POLYBIUS

皆さん、ポリビウスの都市伝説が知っていますか？
アメリカで某ゲームセンターに入ると新しいゲームがあったらしいです。
あのゲームをやっていた人は、すぐにはまって、朝から夜までポリビウスをやりました。
終わったら、あの人は頭が痛くて、幻覚や記憶喪失を感じたそうでした。
もちろん、発売したの一か月後、黒服のGメンがゲームを消えるようにしました。

ポリビウスの本体はもう二度と見つかりませんでしたが、
[あの伝説のゲームを創造して、２０１７年のVRでも遊べるPOLYBIUSです。](https://www.youtube.com/watch?v=bnYuGsx7cmo)

![polyb.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393501/684e8fd3-1b6f-6e96-b105-2cd3588fd955.png)

まあ、楽しいゲームです。ちょっとピカピカやりすぎて、ちょっと怖かったｗ。

その上に他のゲームもあったし、テトリスエフェクト、ノーマンズスカイ、卓球シムレーターなどなど・・

## VRは未来だ。

一体どの風に君がわかるため説明ができる？　

茨城は何もないけど、牛久で大仏があります。ものすごくでかいものです。
「へー、そうなんだ。」って言ってるでしょ。
じゃあ自由の女神より三倍大きいです。
「へー、そうなんだ。」ってね
世界で一番大きい像の中で、第四番目だ。
あんまり伝えないんだよね？

どの風にあのすばらしさを伝えても、伝えないんだ。
大仏を本当に見たら、すぐにわかります。本当にバカでかいものだ。

とりあえず、いとしい読者、オキュラスクエストが遊べるきっかけがあれば、ぜひ試してください。

「俺のVR」は、これからシリーズになります。このオタクは、初ゲームが作れるまで、毎日書きます。
よろしくお願いします　mm