OmniAICreator/Qiita-1.07M huggingface dataset:
Apeopleでの調べものを超絶楽にするBookmarklet (他のRPAツールのサイトにも多分応用できる）


RPAツールでのBot開発時に、Botの作り方やトラブルシューティング等をポータルサイトや、
コミュニティサイトで検索すると思いますが、毎回そのページを開いてから検索。とやっていると時間ばかりかかりますので、
ブックマークバーに検索ボタンを置いて、ワンクリック-> キーワード入力 -> Enter。といった具合に、
極力省力化しましょう。というのが趣旨の投稿です。

私はAutomation Anywhereを良く使うため、Apeopleというポータルサイトが今回のテーマになっていますが、
URLで検索キーワードを渡せるタイプのページでしたら同じように出来るはずですので、挑戦してみてください。

#使い方
適当なブックマークを作り、URLを以下のコードに置き換える。
下記ブックマークを押すと、検索キーワードの入力窓が表示されるので、キーワードを入力してEnterキーを押す。

```JavaScript:Bookmarkletのソースコード
javascript:(function(){var val=prompt("検索したいキーワードを入力してください","");if(val)location="https://apeople.automationanywhere.com/s/su?language=ja&searchString="+val;})()
```

Apeopleを新しいタブで開いてから検索できるように少し改良したバージョンも追加しました↓ （2020年7月31日）

```JavaScript:Bookmarkletのソースコード(改良版）
javascript:(function(){var val=prompt("検索したいキーワードを入力してください","");var val=encodeURIComponent(val);var val="https://apeople.automationanywhere.com/s/su?language=ja&searchString="+val;if(val)window.open(val);})()
```

こんなポップアップウィンドウが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490870/d46419dc-c2d7-ea09-0f0b-00720711e648.png)

検索キーワードを入力してEnterを押すと、一発でApeopleの検索結果に飛べます。

他のRPAツールのポータルや掲示板等でもURLで検索キーワードを指定できるものなら使えるはずなので、試してみてください。
phpstormのGitToolBoxがコードの行単位でログを確認できて便利

以前、phpstormのgitの注釈が履歴を追うのに便利という記事をあげましたが、
https://qiita.com/a-nishimura/items/3fc06c80958c04eef139
そのほかのサードパーティ製のプラグインでVS Codeの**GitLens**に似たプラグインを見つけました。

**GitToolBox**

です。
これを入れると行単位ごとに最終コミットのユーザとコミットコメントがインラインで表示されます。
現在の状況になったコードの経緯などをコードを読みながらシームレスに見れるので便利です。
横スクロール



- ポイント
  - overflow-x
  - white-space:nowrap;  ←　これないとカラム落ちみたいになるから、横幅をオーバーできない

```html

<!DOCTYPE html>
<html>
<head>
  <title>Horizontal Scroll</title>
  <style>

    .parent{
      overflow-x:scroll; overflow-y:hidden; width:50px; white-space:nowrap;
    }
    .child{
      display: inline-block;
    }
    .item {
      /* 横スクロール用 */
      display: inline-block;
      width: 90%;

      /* 見た目調整 */
      height: 400px;
      margin: 16px;
      font-size: 48px;
      background: rgba(255, 0, 0, 0.4);
    }

  </style>
</head>
<body>
  <div class="parent">
    <div class="child">
      aaa
    </div>
    <div class="child">
        aaa
    </div>
    <div class="child">
      aaa
    </div>

  </div>

</body>
</html>
```
Railsチュートリアル学習メモ2

## データ更新（rails cから）
```terminal
[1] pry(main)> post = Post.find_by(id: 1)
[2] pry(main)> post.content = "ああああああ"
[3] pry(main)> post.save
```

## データの削除（rails cから）
```terminal
[1] pry(main)> post = Post.find_by(id: 1)
[2] pry(main)> post.destroy
[3] pry(main)> post.save
```

## link_toでmethodを指定する
```ruby
link_to("文言", "パス", {method: "post"})
```

## modelにvalidationを設定
```ruby:modes/post
validates :content,  {presence: true, length: {maximum: 100}}
// presenceはカラムが存在するか確認する
```

```
uniqueness: true // データ上の重複を防いでくれる
```

## renderメソッド
renderメソッドを使うと、redirect_toメソッドを使った場合と違い、そのアクション内で定義した@変数をビューでそのまま使える。

## エラーメッセージはRails側で自動で保存される
`@post.errors.full_messages`

## view側でのエラーメッセージ表示
```ruby:test.html.erb
          <% @post.errors.full_messages.each do |message| %>
            <div class="form-error">
              <%= message %>
            </div>
          <% end %>
```

ん、railsってメッセージデフォルトで予測してくれて入っちゃってる感じ？

## フラッシュメッセージ
`flash[:notice] = "投稿を編集しました"`

## マイグレーションファイルだけを作成
```terminal
$ rails g migration migration_file_name
```

## 画像を表示（public配下の画像を表示させる）
```ruby
<img src="/user_images/<%= user.image_name %>">
```

## 画像をアップロードする際のformの書き方
```ruby
form_tag("パス", {multipart: true}) do
```

## 画像を保存
```ruby
[1] pry(main)> File.write("public/sample.txt", "Hello World")
[1] pry(main)> File.write("ファイルパス", "ファイルの中身")
```

## 画像をControllerから保存
```ruby
    if params[:image]
      @user.image_name = "#{@user.id}.jpg"
      image = params[:image]
      File.binwrite("public/user_images/#{@user.image_name}", image.read)
    end
```
`image.read` でPOSTされた画像データをopenして保存する

## セッション
`session[:name]`

## GET, POSTの使い分け
GET => DBの更新がない
POST => DBの更新がある。セッションの修正がある

## Appication_controllerに共通の変数を定義する
```ruby
class ApplicationController < ActionController::Base
  before_action :set_current_user
  def set_current_user
    @current_user = User.find_by(id: session[:user_id])
  end
end
```
これはミドルウェアっていう認識でいいのかな？

##
reference brokenでgit pullできなくなったときの対策

# 環境
この記事では、vagrant上のCentOS 7 、git 2.12.0 を使用している。

```
$ cat /etc/redhat-release 
CentOS Linux release 7.3.1611 (Core) 
$ git --version
git version 2.12.0
```
# 症状と原因
`git pull` で最新のコミットを取ってこようとすると、以下のエラーが出て失敗。
GITの参照が壊れているから、参照先が解決できないので、ローカルの参照は更新できませんよ～、と。

```shell

$ git pull
error: cannot lock ref 'refs/tags/v1.3.38': unable to resolve reference 'refs/tags/v1.3.38': reference broken
From github.com:repo/project-name
 ! [new tag]           v1.3.38    -> v1.3.38  (unable to update local ref)
```

その壊れているファイルはどうなっているかと言うと、

```shell
$ cat .git/refs/tags/v1.3.38 
$ 
```
空のファイルとなっていた。
このディレクトリにはバージョンのハッシュが記載されたファイルが配置されている。
だが `v1.3.38` に関しては空なので参照することができないとのことだ。
ブルースクリーンでPCが落ちてからこの症状が続いているので、書き換え中か何かに落ちたか、ディスクが壊れたのかと思われる。


# 対策

以下の`git gc`コマンドを実行すると、余計なファイルが削除されて最適化されて直る場合があるそうだ。

だが、今回のケースでは直らなかった。

```shell
$ git gc --prune=now
$ git remote prune origin
```

なので、手動で壊れたファイルを削除する。

```shell
$ rm .git/refs/tags/v1.3.38
$ git pull
From github.com:repo/project-name
 * [new tag]           v1.3.38    -> v1.3.38
Updating 3b1491d2..0ffa0fcb
Fast-forward
...
...
$ cat .git/refs/tags/v1.3.38
7e5aaf5ac820aaafa75329def011e3111a9c3f87
```

削除したタグのファイルが復活して、マージされた。
これで解決😉

# 参考にした文献
- [git pull fails “unable to resolve reference” “unable to update local ref” - stackoverflow](https://stackoverflow.com/questions/2998832/git-pull-fails-unable-to-resolve-reference-unable-to-update-local-ref)
- [.gitディレクトリの中身を見てみる👀](https://qiita.com/tatane616/items/dbad66179754be57d2e2)
- [Gitの公式ドキュメント](https://git-scm.com/docs/gitrepository-layout)
既存EC2インスタンスにAWS Cloud9を構築する

# 前提条件
- EC2 インスタンスが既に構築済み
- 対象インスタンスのセキュリティグループを変更可能（運用的に）
- EC2にEIPが設定済みである（インスタンス再起動時にEIPじゃないとCloud9で再ログインできなくなる）
- regionが東京である（東京ではない場合、22portを許可する帯域を調べる必要がある）
- 踏み台を使って構築することも可能だが今回は行わない

# 手順

1. EC2のセキュリティグループに18.179.48.128/27,18.179.48.96/27を22portに対して許可 
1. [AWS Cloud9](https://ap-northeast-1.console.aws.amazon.com/cloud9/home?region=ap-northeast-1#)にアクセスする
1. 「Create environment」を押す
1. 適当なNameとDescriptionを入れてNextStep
1. 「User」「Port」に適切な値を入力し、「Host」にGIPを入力する
1. 「Connect and run in remote server (SSH)」を選択し、「View public SSH key」をクリックして表示される公開鍵を対象のEC2インスタンスの/home/{User}/.ssh/authorized_keysに追加する
1. 「Next Step」を押し、内容に間違いないことを確認したら「Create environment」でcloud9構築準備完了。画面で進捗が確認できます。

# Appendix
## 作成したユーザ以外からアクセスできるようにする
1. cloud9にログインし、右上の「Share」をクリック
2. 「Invite Members」の欄にIAM User名を入力して「Invite」ボタンを押す

## Could not run nodeなどとエラーが出てきてaws cloud9が作れない
EC2がAmazon Linuxの場合など、yum repositoryにnodejsがない場合があるので事前に、nvmなどでnodejsをインストールしておく。

## 東京region以外に作りたいので許可するIP帯を知りたい　
1. aws cloud9を「Create a new instance for environment (EC2)」を使っていったんaws cloud9用のEC2を作る (後で削除する）
2. 作られたEC2のセキュリティグループに設定されているIP帯域がそのregionでアクセスしてくるIPアドレスです。
3. 1で作成したaws cloud9のEC2を削除し冒頭の手順を使ってaws cloud9を作る

## EIP忘れてcloud9作ってしまった場合の修正方法
1. EIPを発行して対象インスタンスに紐づける（この時点で一時的にcloud9に接続できなくなる）
2. aws cloud9 のコンソールにログインし、対象environmentの[Edit]をする
3. [Host]のIPをEIPのものに変更し[Save Changes]を押す


## Oregonの場合の許可する帯域
34.218.119.32/27, 34.217.141.224/27
[UE4]マテリアルでインスタンス毎の位置を取得する

FoliageやInstanced Static MeshでObject Positionを取ろうとしても一律の値が返ってきてしまいます。
![2019-11-29_11h39_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/e7eacbbc-7906-cfed-ea7b-987298d55a24.png)
Vertex Interpolatorノードを挟むことで個別の値を取得することができます。
![2019-11-29_11h38_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/ebbcd568-22ef-a80b-e9e7-4e1937f9ea6e.png)
Laravel6.x移行でハマった話

Illuminate\Support\Facades\LangのLang::getFromJsonが6.x移行で使えなくなってて
> local.ERROR: Method Illuminate\Translation\Translator::getFromJson does not exist.
などというエラーに見舞われてしまった
ググっても

```terminal
php artisan view:clear
php artisan view:cache
```
しろとしかヒットせず
自作のメールテンプレートで多言語処理を実装していた場合、これでは解決できない

Laravel5とLaravel6にて
Illuminate\Translation\Translator.phpを見比べてみると確かにgetFromJsonメソッドがなくなっており
getFromJsonを利用する側のIlluminate/Auth/Notifications/VerifyEmail.phpのtoMail()メソッド内の処理を見比べてみると

```diff
-Lang::getFromJson()
+Lang::get()
```
と置き換わっており
このメソッド書き換えを行うと6.x（6.2環境で確認）で正しく動作した

関連
Laravelで多言語対応いろいろ
https://qiita.com/shikigamix/items/d92ec72b4418f31c356d
SSHポート転送して踏み台経由でデータをコピーする

### やりたいこと
踏み台サーバを経由してデータをコピーする
ローカル <- 踏み台 <- 宛先

### 事前にポートが空いているかを確認する
ポート番号は適当なものを
``` netstat -an | grep 10022 ```

### ポート転送
下記コマンドを実行する
``` ssh -N -f -L 10022:<宛先> <ユーザ>@<踏み台> ```

### データコピー(rsync)
下記コマンドを実行する
```rsync -avzn --bwlimit=4096 -e 'ssh -p 10022' localhost:<コピー元>/ <コピー先>/ ```
Amazon Linux 2 + nginx + php-fpm + PostgreSQL10

# nginx

### インストール
`# sudo amazon-linux-extras install nginx1.12 -y`
`# nginx -v`

### 起動と自動起動
`# sudo systemctl start nginx.service`
`# sudo systemctl enable nginx.service`

# PostgreSQL10
### インストール
`# amazon-linux-extras install postgresql10`
`# sudo yum install postgresql-server postgresql-libs postgresql-contrib -y`
この順でインストールするとpostgresql-serverもバージョン10が入る

### 初期化
`initdb -U postgres --local=ja_JP.UTF-8 -E UTF-8 -D /var/lib/pgsql/data`


# php-fpm
### インストール
`# sudo amazon-linux-extras install ｐｈｐ7.3 -y`
`# php-fpm -v`

### 関連パッケージのインストール
`# sudo yum install php-mbstring -y`
`# sudo yum install php-pgsql -y`

### 起動と自動起動
`# sudo systemctl start php-fpm.service`
`# sudo systemctl enable php-fpm.service`

### config編集
```/etc/php-fpm.d/www.conf
user = nginx
group = nginx
```
C++でテキストファイル中の値をプログラムで使用する

C++でのテキストファイル入力を行ったときにファイルの数値をプログラム上の変数に取得する方法です（よくやるけどいつも忘れるので備忘録です）

# 前提

あるデータ・セット(data.dat)

```data.dat
1 0.1 0.01
2 0.2 0.02
3 0.3 0.03
...
```

の数値をそれぞれ一行ずつ読んで配列(vector)に入れる

# 方法

stringstreamを使うと簡単です。sstreamヘッダをincludeしてください。

```c++
#include <string>
#include <fstream>
#include <sstream>
#include <vector>

using namespace std;
int main(void)
{
        ifstream ifs("data.dat");
        if (ifs.fail()) {
           cerr << "Cannot open file\n";
           exit(0);
        }
        string str;
        vector<double> x, y, z;
        double x_temp, y_temp, z_temp;
        while (getline(ifs,str)) {
              stringstream ss(str);
              ss >> x_temp >> y_temp >> z_temp;
              x.push_back(x_temp);
              y.push_back(y_temp);
              z.push_back(z_temp);
        }

        return;
}
```
Eclipseプロジェクト(Maven)のアプリのURLを変更する。

もともとあったEclipseプロジェクトをMavenに変更したときに適当な名前を付けてしまったため、元のURLが変わってしまいました。
おかげでアプリがうまく動かない事象が発生したので:sweat_smile:、その解決策を備忘録として残してあります。

### 今回やりたいこと。

<img width="400" alt="スクリーンショット (12).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/acecda2e-2248-f4ff-4677-adb312d08ab7.png">

↑アプリを開いた際のトップページのURLが「localhost:8080/<font color="Blue">test1</font>/」となっているところを「localhost:8080/<font color="Blue">docoTsubu2</font>/」に直したい↓。

<img width="400" alt="スクリーンショット (11).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/fb116c98-62fe-204e-0917-6ffa4c750c66.png">


- プロジェクト配下にある、pom.xmlを書き換える。
	- < artifactId >ｘｘｘ< /artifactId >の中身を書き換える。
	<img width="617" alt="スクリーンショット (8).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/1329794d-9f72-45d6-5a48-e642bd4625da.png">

- コンテキストルートの変更
	- プロジェクト「右クリック」→「プロパティ」→「Webプロジェクトの設定」→「コンテキスト・ルート：」の中身を変更し「適応」をして閉じる。
	<img width="786" alt="スクリーンショット (6).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/fa675c3f-0465-cad0-4849-48707fc1200e.png">

	
- Tomcatに保存されている、コンテキストルートパスの変更
	- 「Serversプロジェクト」を開く
	- 「Server.xml」を開く
	- 「ノード」の欄から、「Server」→「Service」→「Engine」→「Host」→「Context」の順で開いていく。
	- ノード欄の「Path」のコンテンツ部分を変更する。
	<img width="960" alt="スクリーンショット (9).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/65c7f39d-a08c-8ba3-d6f2-f0bd211d4125.png">

- 最後に変更を保存してアプリを実行しURLが変更されていることを確認します。
カラムを追加・削除・編集する方法 ❏Rails❏

#カラムを追加・削除・編集したい時ってあるよね〜
テーブルを作ったはいいものの後々で必要なカラムが出てくることありますよね？
カラムの洗い出しが甘いって？そのとおり！

ではいってみよう！！

<br>
#カラムの追加
ターミナルでマイグレーションファイルを作成

`rails g migration Addカラム名Toテーブル名 カラム名:型`

```:ターミナル
①
rails g migration AddTitleToTweets title:string

②
rails g migration AddDetialsToTweets title:string date:date
#複数選択も可能
#Detailsの部分は何でもOK
```

```ruby:マイグレーションファイル
①
class AddTitleToTweets < ActiveRecord::Migration[5.2]
  def change
    add_column :tweets, :title, :string
  end
end

②
class AddTitleToTweets < ActiveRecord::Migration[5.2]
  def change
    add_column :tweets, :title, :string
    add_column :tweets, :date, :date
  end
end
```

<br>
いざ実行！！

```:ターミナル
rails db:migrate
```

<br>
#カラムの削除
ターミナルでマイグレーションファイルを作成

`rails g migration Removeカラム名Fromテーブル名 カラム名:型`

```:ターミナル
rails g migration RemoveTitleFromTweets title:string
```

```ruby:マイグレーションファイル
class RemoveTitleFromTweets < ActiveRecord::Migration[5.2]
  def change
    remove_column :tweets, :title, :string
  end
end
```

<br>
いざ実行！！

```:ターミナル
rails db:migrate
```

<br>
#カラム名変更
ターミナルでマイグレーションファイルを作成
`rails g migration rename_変更前のカラム名_column_to_テーブル名`

```:ターミナル
rails g migration rename_title_column_to_tweets
```

<br>
changeメソッドの中に追記

`rename_column :テーブル名, :変更前の名前, :変更後の名前`

```ruby:マイグレーションファイル
class RenameTitleColumnToTweets < ActiveRecord::Migration[5.2]
  def change
    rename_column :users, :title, :theme
  end
end
```

<br>
いざ実行！！

```:ターミナル
rails db:migrate
```

<br>
#データ型変更
ターミナルでマイグレーションファイルを作成

`rails g migration ChangeDatatypeカラム名Ofテーブル名`

```:ターミナル
rails g migration ChangeDatatypeTitleOfTweets
```

```ruby:マイグレーションファイル
class ChangeDatatypeTitleOfTweets < ActiveRecord::Migration[5.2]
  def change
  end
end
```

<br>
changeメソッドの中に追記
`change_column :テーブル名, :カラム名, :新しいデータ型`

```ruby:マイグレーションファイル
class ChangeDatatypeTitleOfTweets < ActiveRecord::Migration[5.2]
  def change
    change_column :tweets, :title, :text
  end
end
```

<br>
いざ実行！！

```:ターミナル
rails db:migrate
```

<br>
ではまた！
PDF/TIFF Document Text Detection

# PDF/TIFF Document Text Detectionとは
https://cloud.google.com/vision/docs/pdf

Google Cloud Platform上のCloudVisionAPIという画像分析を行うAPIの中の一種。
CloudVisionAPIには[Text Detection](https://cloud.google.com/vision/docs/detecting-text?hl=ja) という画像のOCRの機能が存在している

## 類似サービス
基本的にJPG/PNG内のテキストを検出する物が多い

- [Amazon Rekognition](https://aws.amazon.com/jp/rekognition/)
- [Azure Computer Vision](https://azure.microsoft.com/ja-jp/services/cognitive-services/computer-vision/)
- [IBM Watson: Visual Recognition](https://www.ibm.com/watson/jp-ja/developercloud/visual-recognition.html)
- [Tesseract OCR](https://github.com/tesseract-ocr/) テッセラクトと読む。Hewlett-Packardが開発してGoogleがOSS化したもの
など。

AWSやAzureといったクラウドサービスを提供しているところでは、機能として用意されている。
あとは[パナソニック](https://www.panasonic.com/jp/business/its/ocr_sdk/cloudocr.html)が出してたりする。


## なぜPDF/TIFF Document Text Detectionなのか。
- ちょうど調査しているタイミング(※2019/4月時点)でGAになった。 
- Goのライブラリが存在していた。
- PDFを直接OCRできるAPIが他ではなかった (※他のAPIではJPG/PNGのOCRを行うことが主用途)
- https://aws.amazon.com/jp/textract/
    - AWSもPDFを直接OCRできるもの出してるけど日本語未対応のようだ

# 使うもの
![スクリーンショット 2019-04-11 13.06.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57634/f3e8692e-8fd4-b2b7-bee5-1ad78b48d613.png)

# 注意点
- 結果は、GCSにjson形式で出力されるので利用する際には、GCSからjsonを取得してくる必要がある。
- 割と複雑なjsonなのでGoで取り扱うのは大変だった。

# ソースコード
https://github.com/ytakky2014/gcp-pdf-tiff-document-text-detection/blob/master/ocr/ocr.go


 
# 結果
1.国土交通省: `令和元年度「年末年始の輸送等に関する安全総点検」の取組を実施します`
  https://www.mlit.go.jp/report/press/content/001317333.pdf
結果: https://github.com/ytakky2014/gcp-pdf-tiff-document-text-detection/blob/master/result/1.txt
問題なくOCRできている。

2.経済産業省: `生産性向上特別措置法【生産性革命法】及び産業競争力強化法等の一部を改正する法律の概要`  
  https://www.meti.go.jp/policy/jigyou_saisei/seisanseisochihoukyoukahou/pdf/gaiyou-1.pdf

結果: https://github.com/ytakky2014/gcp-pdf-tiff-document-text-detection/blob/master/result/2.txt
段組みされているPDFでも問題なくOCR化されている


3.`令和元年度 情報セキュリティマネジメント試験　午後 問題` 
https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2019h31_2/2019r01a_sg_pm_qs.pdf

割と長いPDFもOCR化できているし、図表内のテキストもOCRできているがさすがに試験問題だと文のみだと理解ができないところもある。

なお、jsonを一部マスクしたのもリポジトリ内においてあるのでそちらも参照。


# まとめ
- PDF/TIFF Document Text Detection結構良い。すぐ使える
- GCSにさえPDFを入れておけば、GCSにファイルに出力が出るので使いやすい。
- 今回リポジトリに結果は載せなかったが、試したところ手書きした写真をPDF化したものに対して実行してもテキストを抽出できていた。
- GCPはやっぱり機械学習系に強いなと思う。これからはデータをどうやって活用していくかという時代になっていくと思うので、積極的にこのような技術を使えるようにしていきたいですね。
Firebase Dynamic Links Analytics APIを叩いてPERMISSION_DENIEDのエラー

## 問題
アクセストークンを作成して、Firebase Dynamic Links Analytics APIを叩いても下記のようなエラーが帰ってくる

```
{
    "error": {
        "code": 403,
        "message": "The caller does not have permission",
        "status": "PERMISSION_DENIED"
    }
}
```

## 解決方法
サービスアカウントにアクセスできる役割を確認し、「Firebase Grow Viewer」がまだない場合は追加する必要があった。


```
I just managed to reproduce your problem with a freshly-created service account with no permissions. 
I then added the "Firebase Grow Viewer" role to the service account in the IAM dashboard and the error went away.
 Could you check what roles your service account has access to, and try adding "Firebase Grow Viewer" if it's not already there?
```
## Firebase Dynamic Links Analytics APIで何ができるのか
Dynamic Linksで設定した、URLのクリック数やアプリインストール数をFirebase Dynamic Linkのページで確認できる。
しかし、各プラットフォーム(webからiOSからAndroidから)などのクリック数は見れない。より詳細に、データを取得したい場合Firebase Dynamic Links Analytics APIを用いるとか下記のようなjsonで帰ってくる。(公式ドキュメントより引用)

```json
{
  "linkEventStats": [
    {
      "platform": "ANDROID",
      "count": "123",
      "event": "CLICK"
    },
    {
      "platform": "IOS",
      "count": "123",
      "event": "CLICK"
    },
    {
      "platform": "DESKTOP",
      "count": "456",
      "event": "CLICK"
    },
    {
      "platform": "ANDROID",
      "count": "99",
      "event": "APP_INSTALL"
    },
    {
      "platform": "ANDROID",
      "count": "42",
      "event": "APP_FIRST_OPEN"
    },
    ...
  ]
}
```

## 設定の仕方の手順

### FirebaseGUIからおとしてくる秘密鍵

```
サービス アカウント用の秘密鍵ファイルを生成するには:
Firebase コンソールで、[設定] > [サービス アカウント] を開きます。
[新しい秘密鍵の生成] をクリックし、[キーを生成] をクリックして確定します。
キーを含む JSON ファイルを安全に保管します。
```

上の歯車ボタンから設定画面を開きサービスアカウントタブの中の、新しい秘密鍵を作成を押すと、秘密鍵のjsonが落ちてくる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176479/f66e8343-20d4-9c70-a640-a02f363b32ed.png)

### Firebase Grow 閲覧者権限を設定する
設定画面の右上のサービスアカウント権限の設定のリンクからGoogle Cloud PlatformのIAMと管理画面に飛ぶ。
右のセルの中から一番上のAIMを選ぶ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176479/0cc3672a-5fa6-fc91-f19d-527230282e56.png)

Firebaseの設定画面の中からFirebase サービス アカウントに設定されている
`firebase-xxxxxxx-xxxxxx@xxxxx.iam.xxxxxxxxxx.com`のような文字列と同じものを探す。
一番右の編集を押すと下記のような画面ながでてくる
<img width="1150" alt="スクリーンショット 2019-11-28 18.08.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176479/9e9fc0af-4475-4229-5a3c-dd3116c4f397.png">
「Firebase Grow 閲覧者」の権限を追加する


### アクセストークンの取得方法
落としてきたjsonファイルを使ってドキュメント通りnodeで実行してアクセストークンを取得する
`ya29.xxxxxxxxxxxxxxxxxxxxxxxxxxxx`　みたいなのが帰ってくる。

### Postmanでjsonが帰ってくるのを確認
ドキュメント通りGetでAPIを叩く
Hedersのなかに key `Authorization` value `Bearer {アクセストークン}`と入れる

<img width="979" alt="スクリーンショット 2019-11-29 11.11.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176479/a80f3aff-c918-3d2d-7f9b-a70bb5da70ea.png">




## 参考文献
### 公式ドキュメント
[Firebase Dynamic Links Analytics API](https://firebase.google.com/docs/reference/dynamic-links/analytics?hl=ja)
[サーバーに Firebase Admin SDK を追加する](https://firebase.google.com/docs/admin/setup?hl=ja#prerequisites)

### 問題の解決になったコメント
https://github.com/googleapis/google-api-dotnet-client/issues/1448#issuecomment-527084824
カラムにインデックスを貼ろう ❏Rails❏

#インデックスとは
カラムにインデックスを設定することで、`データ検索を高速化`させることができます！

<br>

#使い方
マイグレーションファイルを作成

```:ターミナル
rails g migration AddIndexToTweets
```

<br>
マイグレーションファイルに、
`add_index :テーブル名, :カラム名`を追記

```ruby:マイグレーションファイル
class AddIndexToTweets < ActiveRecord::Migration[5.2]
  def change
    add_index :tweets, :text
  end
end
```

<br>
複数ver.

```ruby:マイグレーションファイル
class AddIndexToTweets < ActiveRecord::Migration[5.2]
  def change
    add_index :tweets, [:text, :title]
  end
end
```

<br>
#デメリットも

①データを保存・更新する速度が遅くなる
②データベースの容量を使う

<br>
インデックスの使い所は、
【格納するデータが多い時】
【データの検索が頻繁に行われる時】

<br>
ではまた！
カラムに制約をかけよう ❏Rails❏

###カラムに制約をかけ、予期せぬデータが保存されるのを防ごう

<br>

|制約|意味|
|:-:|:-:|
| NOT NULL制約| 空データはダメよ|
| 一意性制約   | 他と被るのはダメよ|
| 外部キー制約  |外部キーに対応するテーブルのレコードがないとダメよ|

<br>
#NOT NULL制約

空データは禁止
カラムの後ろに`null: false`を追記

```ruby:マイグレーションファイル
class CreateTweets < ActiveRecord::Migration[5.2]
  def change
    create_table :tweets do |t|
      t.text :text, null: false
      t.timestamps
    end
  end
end
```


```:ターミナル
rails db:migrate
```
これでtextに値がないツイートは作れないようになりました。

<br>
#一意性制約

他と同じデータは禁止
`add_index :テーブル名, :カラム名, unique: true`を追記

```ruby:マイグレーションファイル
class CreateTweets < ActiveRecord::Migration[5.2]
  def change
    create_table :tweets do |t|
      t.text :text
    end
    add_index :tweets, :text, unique: true
  end
end
```

```:ターミナル
rails db:migrate
```

これで、同じ内容のテキストは保存できなくなりました。
`バルス`とツイートできるのは１人だけ。早いもの勝ちとなります。

<br>
#外部キー制約
外部キーに対応するテーブルのレコードがないとダメ
`t.references :対応先のテーブル名, foreign_key: true`を追記

```ruby:マイグレーションファイル
class CreateTweets < ActiveRecord::Migration[5.2]
  def change
    create_table :tweets do |t|
      t.text :text
      t.references :user, foreign_key: true
    end
  end
end
```

```:ターミナル
rails db:migrate
```

これですべてのツイートが誰かしらのユーザーにひも付きます。
迷子のツイートが現れることはありません。

また、`テーブル名_id`というカラムが自動で生成されます。
今回は`user_id`ですね。

<br>
ではまた！
04. 元素記号

## 04. 元素記号
"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し，1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字，それ以外の単語は先頭に2文字を取り出し，取り出した文字列から単語の位置（先頭から何番目の単語か）への連想配列（辞書型もしくはマップ型）を作成せよ．

###Go
```go
package main

import (
	"fmt"
	"strings"
)

func main() {
	var src = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.";
	var dw = map[int]bool{1: true, 5: true, 6: true, 7: true, 8: true, 9: true, 15: true, 16: true, 19: true}; //  1文字の単語番号
	var res map[string]int = map[string]int{};

	//	単語に分割
	words := strings.Split(src, " ")
	for i, word := range words {
		idx := i + 1

		//	配列の exists的関数がなさそうなので Map を使用...
		if dw[idx] {
			//  1文字を map へ保存
			res[word[0:1]] = idx
		} else {
			//  2文字を map へ保存
			res[word[0:2]] = idx
		}
	}

	//	結果を表示
	fmt.Println(res)
}
```


###python
```python
# -*- coding: utf-8 -*-
src = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
dw = [1, 5, 6, 7, 8, 9, 15, 16, 19]  # 1文字の単語番号
res = {}

#   単語に分割
words = src.split(" ")
for i in range(len(words)):
    #   単語番号
    idx = i + 1

    #   1文字の単語番号の場合
    if idx in dw:
        #   1文字を map へ保存
        res[words[i][0:1]] = idx
    else:
        #   2文字を map へ保存
        res[words[i][0:2]] = idx

#   結果を表示
print(res)
```


###Javascript
```Javascript
var src = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
var dw = [1, 5, 6, 7, 8, 9, 15, 16, 19];    //  1文字の単語番号
var res = new Map();

//  単語を空白で分割し単語数処理
var words = src.split(' ');
for (var i = 0; i < words.length; i++) {
    //  単語番号
    var idx = i+1;

    //  1文字の単語指定の場合 (ES2017)
    if (dw.includes(i+1)) {
        //  1文字を map へ保存
        res.set(words[i].substring(0,1),idx);
    }
    else {
        //  2文字を map へ保存
        res.set(words[i].substring(0,2),idx);
    }
}

//  結果表示
console.log(res);
```

## まとめ
if文で or を書くのがイマイチかと思い 1文字の単語番号をまとめてみた。
Goの配列などの存在チェックがイマイチ？。

次の「05. n-gram」 は問題のの意味がよくわからない、まずは問題の理解から初めて見る。

他の人のを確認したら Map の内容が [文字 => 単語番号] と逆だったため修正しました。

## その他
もともと、C言語やPHPが長いので Goの行末の ";" 癖が治らない。ｗ



[トップ](https://qiita.com/naoshin1984/items/3d7814e2f8eb01eea8dd)
クラウドサービスはOSと並ぶ情報処理の共通レイヤー

# デファクトスタンダードとなるクラウドサービスの登場

　個々数年、GoogleのGSuiteをはじめ多くのグループウェアやタスク管理のシステムがクラウドサービス化して、業務で使うことが多くなった。
　OSにローカルアプリケーション入れるだけで仕事はできず、必ずクラウドサービスのアカウントを取得し、それらも使えるようになって初めて仕事ができる。

 私がプログラマーを始めたときは、そのクラウドサービス自体を作ろうとみんな躍起になっていたが、その勝者が覇権を握る時代に来たのだと思う。いわば、OS戦争の次の、クラウド戦争が集結して、クラウドサービスのデファクトスタンダードができあがりつつある。
　
# クラウドサービスの統合的な運用、管理が次の課題へ

　クラウドサービスもいろいろなものを使うため、そのURLやアプリの移動がめんどくさい。もちろん、アカウントの管理も。
　オールインワンなサービスがその内できるかもしれないが、まだその兆しはない。今は、各分野でのクラウドサービスが確立し、それが普及していいっている段階。
　
　その過渡期にあっては、これら分散したクラウドサービスを管理することが一つの課題になっている。

　それぞれのクラウドサービスは、APIを提供しているので、APIをつかった統合アプリやサービス、ブラウザのプラグインを作るうごきも見られる。

　いずれにしろ、管理が生まれるほど、クラウドサービスはOSと並ぶ必須のインフラになりつつあるように思う。
KEPから知るKubernetes


MeetupやKubeConの発表でよくKEP(けっぷ)というワードがでてきます。
まずはこのKEPとは何ぞやの話をして、次にどう利用しているかについて紹介したいと思います。


# KEPとは?

このKEPというのはKubernetes Enhancement Proposalの略のことです。その名の通りKubernetesに対する新機能の提案で、新機能を提案した時の可否/Alpha/Beta/GAまでのフローも細かく定義されています。また、このKEPは[kubernetes/enhancements](https://github.com/kubernetes/enhancements)リポジトリで管理されています。

コミュニティからKEPを検索するためのページも提供されています。
https://www.kubernetes.dev/resources/keps/

## 導入のモチベーション

KEPは変更や進捗を明確にして品質を保ち、以前は統一されていなかったalpha/beta/GAの条件を明確にするために導入されました。

現在のKubernetesコミュニティは、30のSIG<sup><a id="fnr.1" class="footref" href="#fn.1">1</a></sup>、10のWG<sup><a id="fnr.2" class="footref" href="#fn.2">2</a></sup>、2つのUG<sup><a id="fnr.3" class="footref" href="#fn.3">3</a></sup>によって構成されています。
(Kubernetes本体のコントリビュータ数だけでも2,369人!)

以前は、新機能については各グループのメーリングリストやビデオ会議、F2Fで話し合われていました。しかし、ここまでプロジェクトが大規模になるとSIGのPMやリリースマネージャが全体像を把握できないという問題が出てきます。

そんなこともあり、1つのPRやIssueを見ただけで概要を把握できて、かつ優先順位付けもできるKEPが導入されました。

> より詳しい話は[KEP-1](https://github.com/kubernetes/enhancements/blob/master/keps/0001-kubernetes-enhancement-proposal-process.md)を読んでみてください。これはKEP自体をKEPとして定義ものです。


# どんな時に便利か?

私もKubernetesを把握するのによくKEPを見ています。(最近はChangeLogとかIssueの参照先としてリンクが貼られることが多くなってきたので見ざるをえない感じですが&#x2026;)
特に次のようなときに便利です。

1.  新機能の動向を知るためにkubernetes/enhancementsのIssueをwatch
2.  ある機能の、導入に至ったモチベーションを知る
3.  ある機能のGAまでのスケジュールを把握する
4.  コード読んでて分かりにくいところのコミットからKEPを辿る

進行中のものについてはIssueがCloseされていないので、Issueを見ると把握できます。すでに入っている機能についてはkepsディレクトリを見るとよいでしょう。またKEP導入以前の話であったり全体のアーキテクチャについては、[kubernetes/community - contributors/design-propsals](https://github.com/kubernetes/community/tree/master/contributors/design-proposals)を参照してください。

> ちなみに最近気になっているKEPはSidecar Containersです。v1.17にalphaリリースを目指していましたが現在はv1.18にリスケされました。なので早くて2020年の3月、デフォルトで有効になるのは2020年の初夏頃でしょう。これが入るとメインアプリケーションとは別にSidecarがマークできるので、KnativeでどのコンテナにProxyするかみたいな問題が進捗することを期待しています。


# Footnotes

<sup><a id="fn.1" href="#fnr.1">1</a></sup> Special Interest Groups(SIG)は、特定の分野(ex. API/Storage/Network)の特化した開発を進めるためのグループです。SIGの中でさらに複数のサブプロジェクトに分かれていることもあります。

<sup><a id="fn.2" href="#fnr.2">2</a></sup> Working Groups(WG)は、SIGをまたいだトピックを議論するための一時的なグループです。

<sup><a id="fn.3" href="#fnr.3">3</a></sup> User Groups(UG)は、BitDataなどKubernetesユーザに関連する長期的に情報交換が必要なトピックのためのグループです。(Kubernetesの特定のコードを担当しているわけではありません。)
UnityのTilemapで有名ゲームのステージを作成してみる(見た目だけ)

Tilemapという面白そうなものを試すために、有名ゲームのステージを作成してみました。
※今回は見た目だけの作成です

Tile Palletを開くときの詳しい流れについての記事が少なかったため、そちらのまとめでもあります。

# 画像の設定
まず、Tilemapで使用したい画像を用意します。今回はこちらの画像を使用します。もうどのゲームかお分かりですよね。
![Tile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/7f31d94f-8e32-a156-d178-5d68b8712ed3.png)

画像をインポートし、設定を以下のように変更します。
![TileImportSettings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/ddfb4518-d852-a4b4-9cac-bb67f223c49a.png)

そして、Sprite Editorをクリック。ここから画像を区切っていきます。
上の方にあるSliceをクリックし、TypeとPixel Sizeを変更します。今回の画像は一つ一つを32×32で作成しているため、Pixel Sizeも32にしています。
![SpriteEditor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/9201eea0-8356-3aa3-9614-94944735644c.png)

**Sprite Editorをクリックしてエラーが出た場合**
以下の方法で解消されます。
1. Window > Package Managerを開く
2. 2D Spriteを選択し、右下のInstallをクリック
![PackageManager_2DSprite.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/7af7291a-e78d-9c71-2d6e-72ebfd6103d7.png)

これで画像の設定は完了です。

# Tile Palletの作成
まず、Window > 2DからTile Palletを開きます。

**Tile Palletが表示されていない場合**
Window > 2DにTile Palletが表示されていない場合には、以下の方法で開くことができます。
1. Window > Package Managerを開く
2. 2D Tilemap Editorを選択し、右下のInstallをクリック
![PackageManager_2DTilemapEditor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/3d9b1504-e693-36a0-dcd6-88837153c5d8.png)

これでもう一度Window > 2Dを確認するとTile Palletが追加されています。

Tile Palletを開くと、以下のようなウインドウが開きます。
![TilePalet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/146ffd5a-5bc7-0a8d-d347-1757558121b6.png)

Create New Paletteをクリックすると、新しいTile Palletを作成できます。
![CreateNewPalette.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/34aab8bf-056c-d88b-c513-aeaef10e181f.png)

# Tile Assetの作成
画像をTile Palletウインドウにドラッグ＆ドロップすることで作成できます。
![TileAsset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/95ad3bcf-cf40-8f25-75fa-4f8e61e57abf.png)

# Tilemapを使ってみる
では、実際にTilemapを使って、ステージを作ってみます。

タイルの塗り方は、Tile Palletウインドウでブラシを選択し、塗るタイルを選択。
そして、塗りたい場所でクリックするだけです。ドラッグでも塗ることができます。
![Paint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/043244b1-3b6f-32f5-2e71-9853cf2b38c6.png)

これで、有名ゲームのステージが完成しました！
![complete.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463664/a79ee978-26dc-8cbb-ce08-926dee0fec96.png)


# おわりに
今回はステージの見た目だけを作成しましたが、Tilemapでは当たり判定もできるということで、色々試してみたいと思います。そして、可能であればこのステージを完成させていきたいです！
Vuetifyのv-selectにてitemsのキーがtextとvalueじゃないときの対処法

# はじめに

vuetifyjsのv-selectでは、デフォルトのitemsの仕様は以下となっています

```
{
  text: string | number | object
  value: string | number | object
}
```

itemsにtextとvalueがないときの設定に迷ったので、備忘録を兼ねてメモを残します


# 対処法

itemsとして、以下のオブジェクトを使用する場合のコード例です

```
{
  [
    { categoryName: "カテゴリ1", id: 1 },
    { categoryName: "カテゴリ2", id: 2 },
    { categoryName: "カテゴリ3", id: 3 },
    { categoryName: "カテゴリ4", id: 4 }
  ]
}
```

textにcategoryName、valueにidを使用する場合、v-selectのitem-valueとitems-textにitemsの対応するキーを指定します。ここでは以下のようにします

- text  : categoryName
- value : id

```
<v-select
  v-model="id"
  label="*カテゴリ名"
  :items="categories"
  item-text="categoryName"
  item-value="id"
  required>
</v-select>
```


# 参考
[Select component](https://vuetifyjs.com/ja/components/selects)
【Ruby】配列のnilチェック＋部分一致検索

## やりたいこと
1. Rubyハッシュ(連想配列)のnilチェック
2. 配列の部分一致検索

### 1. Rubyのハッシュ(連想配列)のnilチェック

- 最初はif文でnilチェックをやろうと思ったけど、Ruby2.3で導入された`dig()`を使う方が簡単だった

```ruby
params.dig(:q, :name)
```

### 2. 配列の部分一致検索

```ruby
search_text = '検索したい文字'
array.select { |e| e =~ %r{^.*#{search_text}.*} }
```

- `#{}`で囲うとで変数を入れられる
- `%r{}`で正規表現オブジェクトを作成した場合、パターン内に「/」が含まれていてもエスケープは不要らしい。便利！

---

「もっとこうした方が楽だよ！」と言った知見があれば、コメントお待ちしてます

## 参考サイト
- [サンプルコードでわかる！Ruby 2.3の主な新機能 - Qiita](https://qiita.com/jnchito/items/0faac073cb77417d61c7#%E6%B7%B1%E3%81%84%E9%9A%8E%E5%B1%A4%E3%81%AB%E3%81%82%E3%82%8B%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%81%AE%E5%80%A4%E3%82%92%E4%B8%80%E6%B0%97%E3%81%AB%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B-hashdig)
- [RubyでネストしたHashやArrayから値を取り出す方法いろいろ - Qiita](https://qiita.com/vzvu3k6k/items/1705c7f4b29c08787ea0#dig%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E4%BD%BF%E3%81%86)
- [「=~」メソッドによるマッチング - 正規表現の基本 - Ruby正規表現の使い方](https://www.javadrive.jp/rubyregexp/ini/index4.html)
- [%rを使ったパターンの定義 - 正規表現の基本 - Ruby正規表現の使い方](https://www.javadrive.jp/rubyregexp/ini/index6.html)
[用語bak] ユーザー、グループ、ロール、およびレルムについて

#ユーザー、グループ、ロール、およびレルムについて
Application Server は次のエンティティーに対して認証および承認ポリシーを実施します。

「ユーザー」: 「Application Server で定義される」個別の ID。一般に、ユーザーとは、人物、Enterprise JavaBeans などのソフトウェアコンポーネント、またはサービスを意味します。認証されたユーザーを「主体」と呼ぶ場合もあります。また、ユーザーが「被認証者」と呼ばれる場合もあります。

「グループ」: 「Application Server で定義される」一連のユーザー。共通の特性に基づいて分類されます。

「ロール」: アプリケーションによって定義される指定した承認レベル。ロールは錠を開ける鍵に例えられます。多くの人が鍵のコピーを所持している場合があります。錠は、だれがアクセスを求めるかにかかわらず、適切な鍵が使用される場合だけ対応します。

「レルム」: ユーザーとグループの情報、および関連するセキュリティー資格を含むリポジトリ。レルムは、「セキュリティーポリシードメイン」とも呼ばれます。

#From Url
https://docs.oracle.com/cd/E19159-01/820-4604/abloe/index.html

「エスケープ」：escape
JSTL - fn:escapeXml() Function
https://www.tutorialspoint.com/jsp/jstl_function_escapexml.htm
「なりすまし」：
有名な格子暗号ライブラリの使用感をまとめてみた。

「使用感」て言うとなんか、、、
はい。

## 概要
**準同型暗号**は、

- **暗号化したまま計算**ができる
- 量子コンピュータでも簡単に解読できない(**量子コンピュータ耐性**)

という特徴を持った**次世代暗号**と呼ばれています。
学術的には**2009年くらいに大きなブレークスルー**があり、そこから学術分野を中心に研究が盛んに行われています。実用化に関してはまだまだ計算が遅いとか、暗号化した後のデータサイズが大きすぎるとか、いろいろあってなかなか難しい面もあります。
ただ、今の準同型暗号を中心とした秘密計算分野は、機械学習でいうところの2011年頃の感覚と似ている、という言い方をされます。つまり、ハードウェアとかさらなる理論的なブレークスルーが重なれば、**今の機械学習と同じくらいのブームが来るかも！！？**

まあ、来ても来なくても、**魅力的な技術だし数学的にも面白い**ので勉強する分には良いよね？？（震え声）

## 内容
正直、**格子暗号**と呼ばれる準同型暗号のうちの１つは

-  **理論が難しい**
-  既存ライブラリが**やたらとややこしい**
-  既存ライブラリは足し算掛け算だけを実装した**超低レイヤ**

という理由から日の目を見ていない感じがあります。
今回は、たぶんよく学術的に使われているであろう２つの格子暗号ライブラリ、

- [HElib (オープンコミュニティ)](https://github.com/homenc/HElib)
- [SEAL (マイクロソフト)](https://github.com/Microsoft/SEAL)
- [Palisade (MIT, Duality Inc)](https://gitlab.com/palisade/palisade-release)
 
を使ってみた感想を雑談的に書いていきます。

## HElib (オープンコミュニティ)

格子暗号の中の**BFV形式**をバックエンドにしている**オープンコミュニティのライブラリ**。
一言で言うと、カオス。どんな機能が使えるのかまとめてあるわけでもないし、ソースコード読むの前提？でも**ソースコードもかなり追いにくい**です。。
コミュニティはとても**活発**です。**機能のリッチ**さとかを考えたり、オープンコミュニティと言うことを考えると個人的には応援してるし、よく使ってます。また、**ブートストラップ**とよばれる格子暗号の禁止技みたいなものも実装されています（実運用に耐えるかは置いといて）。
格子暗号は高次元の多項式環を用いているので、バックエンドで離散フーリエ変換を駆使して計算を高速化しています。HElibは**NTL**(11.3.2とかのバージョン）を裏で使ってこの高速化を実現しています。
BFV形式を使っているので、エンコードするところが比較的直感的です。したがって、係数に平文を詰め込む方式のパッキング手法は簡単に実装することができ、そこが重宝しています。係数パッキングとかが、高速化にどう寄与しているかとかは、[これ](https://mshcruz.wordpress.com/2016/09/27/scalar-product-using-helib/)にわかりやすくまとめられています。
バックエンドはC++なので、環境設定の闇が深いですが、Dockerfileが置いてあるのでubuntu18.04 の環境では環境構築しやすいです。


## SEAL (マイクロソフト発)
SEALは**マイクロソフトのリサーチグループ**が開発しているライブラリですが、ライセンスはMITなので**商用も可能な完全なオープンソース**です。
一言で言うと、使いやすいです。ソースコードももちろん難しいですが、コメントが豊富で秩序立ってコーディングがしてあるのがわかります。マイクロソフトのトップリサーチャーはやはりすごい、、
例えば、

- 上記のHElibのgitにある[Exampleコード](https://github.com/homenc/HElib/blob/master/example_program/helib_example.cpp)
- SEALのgitにある[Exampleコード](https://github.com/microsoft/SEAL/blob/master/native/examples/4_ckks_basics.cpp)

を見てみると一目瞭然ですよね、、情報量が違いすぎる、、

個人的には最近SEALをよく使うことが多く、その理由としては**SEALがCKKS形式の格子暗号を実装している**からで、BFV形式の実装もあるのですが、CKKS形式が使い勝手が良いからです。マイクロソフトも、たしかコメントの中でCKKSを特別な理由がなければ使うことを推奨しています。ただ、CKKSはエンコードの仕方が特徴的なため、先ほどのような係数パッキングは使わない前提になっています。もうひとつのCRTパッキングというものが主流ではあるけど、やっぱ特定の計算に対しては遅いもんね？？


## Palisade (MIT, Duality Inc発)
**MITと、MIT発のDuality**と言う会社が開発しているライブラリです。オープンソースですが、ライセンスは大学の名前で縛ってあるので、**商用は不可**です。
このライブラリについてはまださわれていないですが、[ドキュメント](https://gitlab.com/palisade/palisade-release/wikis/home)がめちゃくちゃしっかりしていて、世界獲ろうとしている感が伝わって来ます。MITの格子暗号領域でのトップリサーチャーが専門としている、**格子暗号のマルチキー形式が実装されている**ようで、それがどう使えるか早く試してみてまたレビューしたいと思います！！


## 雑談
マイクロソフト、MIT、世界のオープンコミュニティがそれぞれ作っている格子暗号ライブラリの稚拙な紹介でしたが、やっぱり**日本発のものを作ってみたいなあああ**と思うわけです。**だってなんか世界に負けてるの、くやしいやん？？**
ただ、それを実現するには筆者の脳みそではスペックが足りないのと、手も後４本くらいは欲しいわけで、、
なかなか難しいなあと思っているところです。

もしくは、これらの低レイヤーは海外の天才たちに任せて、もっと**使い勝手のいい高レイヤーのラッパーに注力する**、これもこの分野への貢献度は高いと思います。これに関してもいろいろ出て来ています。有名なのは、[SEALのPythonラッパー](https://github.com/ibarrond/Pyfhel)。この人たちのコミットも尊敬する。。


以上、雑談的に格子暗号のライブラリについて書いてみました。
だれか興味ある人いたら、連絡ください！！
いいねやコメントお待ちしております！！
sEasyEditerNET.exeを使って、IPアドレスから地域を推定する

sEasyEditerNET.exeにGeoIP2の設定をすると、IPアドレスから地域が推定できる

# 事前準備

sEasyEditerNET.exe(sWebTool) には GeoIP2 のデータベースは同梱していないので、取りに行く必要がある。

下記のメニューから、[MaxMind社](https://www.maxmind.com/en/home)へアクセスして、最新の**「GeoLite2-City.tar.gz」**をダウンロードする

![geoip-EasyEdiyor01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/9eb97b44-d30b-734b-cdbc-8293c51d5a17.png)

開発環境では無料版の **GeoLite2 City** で開発している。有料版は試していない。

![geoip-EasyEdiyor02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/156a4b57-bee1-fb79-2bff-4708ec9d35c6.png)

ダウンロードしたファイルを解凍して**「GeoLite2-City.mmdb」**を抜き出す。

![geoip-EasyEdiyor03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/d31d7467-86d9-b03b-730e-4a15cf42981c.png)

**「GeoLite2-City.mmdb」**のファイルパスを、メニューの「GeoIP2/Whois/Etc」→「GeoIP2データベース」に指定する。
(**「GeoLite2-City.mmdb」**単体を gzip 圧縮してもよい)

# IPアドレスから地域を推定する

![geoip-EasyEdiyor04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/c2801f45-9894-cd30-f8d3-bb6e15465826.png)

後は、IPアドレスと思われる文字列を選択して、右クリックで「Internet」→「GeoIP2」を選択すると、
別のウインドウが開いて、推定される地域を出力する

![geoip-EasyEdiyor05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/440358f3-22ae-d8ee-6f69-a0e27dbeb593.png)

Googleマップへのリンクもあるよ。

# インデックスへ戻る

[sEasyEditerNET.exe の画面説明へ戻る](https://qiita.com/tomoki0sanaki/items/c2f48713a886a8889b87#geoip2-1)

[sWebTool Manual index](https://qiita.com/tomoki0sanaki/items/b8f571ae296a32f7b434)
"「ループ・再帰・gotoを使わず1から100までの数値を印字する」Conner Davis 氏の回答の考察"のpython版をやってみた

いつもの日課でQiitaのトレンドページを見ていたのですが、こんな記事を見かけました！

> 「ループ・再帰・gotoを使わず1から100までの数値を印字する」Conner Davis 氏の回答の考察
> https://qiita.com/xtetsuji/items/19d07c629852876da401

いやいやいや 

$$ 1000\div999^{2} $$

$$ = 0.001002003004005...099100 $$

これで1から100までの数値を出せるなんて面白すぎますし、凄過ぎません？

perlとrubyでの再現を記事中ではされているのですが、普段僕の使っているpythonでは再現はされていないようなのでやってみました。

```python:make_num.py
from decimal import *
import re
getcontext().prec = 298

data = Decimal(1000) / Decimal(999**2) #計算部分
data = (str(data).split(".")[1])

print(re.findall(r'...', data)) #分割+出力部分
```

> [@shiracamus](https://qiita.com/shiracamus)様 [@LouiS0616](https://qiita.com/LouiS0616)様 お二人のご指摘により計算部分と分割部分を変更しました。
> ↓変更前
> data = Decimal("1000")/Decimal(str(999**2))
> print(re.split('(...)',data)[1::2])

pythonの通常の割り算では結果がfloatになってしまい、300桁まで出力することができません。
そのため、decimalライブラリを使うことで指定桁数まで出力するようにしています。
また、計算結果は0.001002003....といったようにくっついているので、分けるために正規表現を使っています。

出力は次のようになりました。

```
$ python make_num.py
['001', '002', '003', '004', '005', '006', '007', '008', '009', '010',
 '011', '012', '013', '014', '015', '016', '017', '018', '019', '020',
 '021', '022', '023', '024', '025', '026', '027', '028', '029', '030',
 '031', '032', '033', '034', '035', '036', '037', '038', '039', '040',
 '041', '042', '043', '044', '045', '046', '047', '048', '049', '050',
 '051', '052', '053', '054', '055', '056', '057', '058', '059', '060',
 '061', '062', '063', '064', '065', '066', '067', '068', '069', '070',
 '071', '072', '073', '074', '075', '076', '077', '078', '079', '080',
 '081', '082', '083', '084', '085', '086', '087', '088', '089', '090',
 '091', '092', '093', '094', '095', '096', '097', '098', '099', '100']
```

今後使うところは予測がつきませんが、for文を使わずに1~100の数値を表示できるという発想が面白かったです。

> 参考文献

> * https://techacademy.jp/magazine/19130
> * https://kaworu.jpn.org/python/Python%E3%81%A7%E6%96%87%E5%AD%97%E5%88%97%E3%82%922%E6%96%87%E5%AD%97%E3%81%9A%E3%81%A4%E5%88%86%E5%89%B2%E3%81%99%E3%82%8B
肥大化した.git ファイルのtmpファイルを探して削除

# なにがしたい
200GくらいあるでかいGitリポジトリを使用していた．
気がつけば100Gくらい容量が膨れ上がった．
調べてみると.git以下のファイルが肥大化していた．

# 対処
`git gc`で失敗した際のtempファイルが悪さをしていたみたい．
以下コマンドで思いファイルを探す．

```
# 不要ファイルがないか確認したい
find .git/ -iname "*tmp_pack*" -print0| xargs -0 du -sh

# 不要ファイルを直接削除
find .git/ -iname "*tmp_pack*" -print0| xargs -0 rm
```
このファイル一覧の中に
`tmp_pack_AbCdEfg`
のようなものがいれば消しても良いはず． `git gc`時に中断してしまった際のtmpファイルのようだ．

自分の場合はlfs管理しているところで80Gほどのtmpファイルが作成されていた．

# 参考
https://www.reddit.com/r/git/comments/324ejz/can_i_safely_delete_tmp_pack_files_in/
Flutterで作ったアプリから入力した電話番号あてにAWS SNSからSMSの送信をする方法(ざっくり)

## やりたいこと

入力された電話番号あてにPINを送信したい！

## 使うもの

```
AWS
|	DynamoDB
|	API Gateway
|	Lambda
|	L	Node.js 12x
L	SNS
Flutter
L	http 0.12.0+2
```

## DynamoDBの準備

PINコード保存用のテーブルを作成します。

```json
"pin": {
    "user_id":"",
    "pin":"",
    "ttl":"" //TTL設定
}
```

## Lambdaの準備

SMSの送信は ```publish()```を使うことで簡単に送ることができます。

```js
const AWS = require('aws-sdk');
const sns = new AWS.SNS();
const documentClient = new AWS.DynamoDB.DocumentClient();

exports.handler = async (event) => {
    //eventをparseする
    let body = JSON.parse(event.body);
    //電話番号とユーザーIDを取得
    let phone_number = body.phone_number;
    let user_id = body.user_id;
    
    //PINを生成してデータベースに保存する
    let pin = await getPIN(user_id);
    if(pin == false){
        return false;
    }else{
        //ユーザーにPINを送る
    	const phone_number = '+819012345678';// E.164番号の形式 (例: 08012345678 -> +818012345678)
    	const message = "あなたの確認コードは${pin}です";
    	await sendSMS(phone_number, message); 
    }
}

//PINを生成してDBに保存する
async function genPIN(user_id){
    //今から10分後のエポック秒を生成
   	let date = new Date();
  	let epoc10min = Math.floor(date.setMinutes(date.getMinutes() + 10) / 1000);
    
    //PINコードの作成
    let pin = {pinを生成するコード};
    
    // DBに保存するパラメータ
    let params = {
      	'TableName': 'pin',
      	'Item': {
         	'user_id': user_id,
         	'pin': pin,
         	'ttl': epoc10min
      	}
   	};
    try{
        await documentClient.put(params).promise();
        return pin;
    }catch(err){
        console.log(err);
        return false;
    }
}


//SMSを送信する
async function sendSMS(phone_number, message) {
    
    // ユーザーにPINを早く、確実に送りたいのでSMSの送信タイプをTransactionalにする
    // もし重要度の低い情報であれば、DefaultSMSTypeのValueをPromotionalにする
    const sms_params = {
        attributes: {
            'DefaultSMSType': 'Transactional',
        }
    }
    //送信タイプの設定
    var setSMSTypePromise = new AWS.SNS({
        apiVersion: '2010-03-31'
    }).setSMSAttributes(sms_params).promise();
    setSMSTypePromise.then(
        function (data) {
            console.log(data);
        }).catch(
        function (err) {
            console.error(err, err.stack);
        });
    
    //送信用パラメータの設定
    var params = {
        Message: message,
        PhoneNumber: phone_number,
    };

    let result;
    // SMS送信
    try {
        await sns.publish(params).promise();
        result = true;
    } catch (e) {
        console.log(e);
        result = false;
    }
    return result;
}
```

## API Gatewayの設定

Lambda統合プロキシでAPI GatewayとLambdaをつないでください。

メソッドはPOSTで。

## テスト

Postmanを使ってJSON形式のデータを送ります

```json
{
	"phone_number": "+818012345678",
    "user_id": "hoge"
}
```

SMSが送信されてきたらOK

## Flutter側

このクラス[http class]( https://pub.dev/documentation/http/latest/http/Request-class.html )を使って、作ったAPIあてにPOSTする
DockerでGoのRestAPIを作ってみた（ホットリロード対応）

dockerでGolangのAPIを作りたいと思いましてやってみました。
ちなみに、dockerはホットリロードさせたかったので、docker-composeを使っています。

#環境
それぞれのバージョンはこちら。
Dockerについての説明とかは省きます。

```console
$ docker-compose --version
docker-compose version 1.24.1, build 4667896b

$ go version
go version go1.13.4 darwin/amd64
```
■　echo 4.1.11 （ルーティングが便利になるかな、と）
　　公式はこちら　https://echo.labstack.com/guide
　　以下によると、RestAPIに最適化されているらしー。
　　　https://rightcode.co.jp/blog/become-engineer/go-flamework

■　oxequa/realize
　　ホットリロードを行うために入れてみた。

#ファイルの準備
適当なフォルダに以下の３ファイルを用意します。

##Docker
###Dockerfile

```Dockerfile
# 公式 golang ランタイムをイメージとして使用
FROM golang:1.13

# ソース入れる用のディレクトリ作成（名前はなんでもいいけど、この後の「app」は全部合わせる）
RUN mkdir /app 

# ソース入ってるのここだよ
WORKDIR /app

# ホスト側のカレントにあるファイルをソースフォルダにコピーするよ
COPY . /app

# echo と oxequa/realize のライブラリ取ってくるよ（ぼちぼち時間かかるよ...）
RUN go get -u github.com/labstack/echo/...
RUN go get github.com/oxequa/realize
```

###docker-compose.yml

```docker-compose.yml
version: '3'

services:
  api:
    build: .

    #buildが指定されている場合は作成イメージの名前になる
    #build指定なし：このイメージを元に作成される(ex.mysqlとか)
    image: sample_api:0.1

    # ポートフォワーディング（ホスト側：docker側）
    # ホスト側のブラウザで実行するときは http://localhost:1000 で見れるようになる
    ports:
      - "1000:1323"
     
    # (ホスト側：docker側)dockerの「/app」フォルダとホストのカレントを繋げるよ。
    # ホストの変更が反映されるようになる
    volumes:
      - .:/app
    
    # デフォルトのコマンドをこれに変える。ホットリロードを有効にする？
    command: realize start --run --no-config

    tty: true
```

##Golang
###server.go

```server.go
package main

import (
	"net/http"

	"github.com/labstack/echo"
)

func main() {
	e := echo.New()
	routing(e) 
	e.Logger.Fatal(e.Start(":1323"))
}

/* ルーティングを行う */
func routing(e *echo.Echo) {
	e.GET("/", hello)
	e.GET("/:name", greeting)
}

/* http:/~/ の時 */
func hello(c echo.Context) error {
	return c.JSON(http.StatusOK, map[string]string{"message": "hello"})
}

/* http:/~/(名前) の時 */
func greeting(c echo.Context) error {
	/* c.Param("name")　とすることで、URLの:name　と対応させて取得 */
	return c.JSON(http.StatusOK, map[string]string{"message": "hello " + c.Param("name")})
}
```



#Docker起動
上記ファイルを保管したフォルダに移動して、コマンド実行
（「-d」オプションつけてバックグラウンド実行しない理由は後述。つけても大丈夫）

```console
 $ docker-compose up
```

これで、ローカルのブラウザから`http://localhost:1000`ってしたら
`{message:hello}`が。

`http://localhost:1000/taro`ってしたら
`{message:hello taro}`って帰ってくるはず。



###詰まった時の小ネタ
**docker-compose up でやってみる**
　どういうことかというと、「-d」を取ることでエラーの内容を教えてくれる。

　あずきはコマンド実行後、ターミナルをそのまま使いたかったので、おまじないのように「-d」をつけてました。
　で、エラーで動かないんだけど（docker ps にあがってこない)なんでか分かんなかった。

　原因は同じフォルダ内に「func main()~」が書かれたファイルがいたってことだった。
　試行錯誤しながら作ってたので、バックグランド実行だと気づかなくて何時間も無駄にした。

　でも、苦労したことは忘れない。きっと。






#参考
https://qiita.com/y-ohgi/items/671de11f094f72a058b1
https://www.fox-hound.tech/1179/
https://qiita.com/prgseek/items/e557a371d7bd1f57b9b1
https://qiita.com/TsutomuNakamura/items/7e90e5efb36601c5bc8a
http://docs.docker.jp/engine/articles/dockerfile_best-practice.html
https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa
API関連
https://ken-aio.github.io/post/2019/01/30/golang-echo/
【Unity】ファイル名とクラス名が合ってるのにコンパイルエラーで動かなくなる現象の対策法

# 公式から対策が公開されました（追記）
こちらを参考にしてください。なるほど環境変数のPATHだったのですね。
であればユーザーを作り直せば回避できたと言う。
https://helpdesk.unity3d.co.jp/hc/ja/articles/360037037212

# やらかした
急にUnityが言うことをきかなくなってしまいました。
コンパイルが全く通らなくなりました。
思い当たる直接の原因はUnityを起動した状態のまま、その開いているプロジェクトをコピーしたことです。

検索してもファイル名とクラス名が違う話ばかり…そういうことではないんです。
Unityを再インストールしても症状は変わらず。そんな場合の対策記事です。

## 環境
- OS：Windows10 Pro
- Unityバージョン：2019.2.12.f1

## 公式の解決策
こちらの作業を行ってください。
https://helpdesk.unity3d.co.jp/hc/ja/articles/360037037212
## 自分で編み出した解決策
- Unityをアンインストールします。
- Unityのアンインストーラーが削除しないファイルを消します。
    - 参考URL　https://freelyapps.net/reinstall-unity/
- 新しくWindowsのユーザーを作ります。
- 再度Unityをインストールします。

# 出た症状や詳細
起こったことや情報をまとめます。

## 症状
- 急にコンポーネントをアタッチできなくなりました。
    - アタッチしようとするとエラーメッセージが出てつけられなくなります。メッセージは `Can't add script component 'コンポーネント名' because the script class cannot be found. Make sure that there are no compile errors and that the file name and class name match.`
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75653/7aedbc54-ef53-b0e2-bfff-cf6cd0f1bdfb.png)
    - スクリプトを選択すると `No MonoBehaviour script in the file, or their names do not match the file name.` と言うメッセージがインスペクタに表示されます。
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75653/c74c7e6b-949e-f75b-d212-0181b7ee4772.png)

- 空白メッセージの謎のコンパイルエラーが常に発生します。
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75653/d5e961b7-b7a1-7ec2-1c1a-0c2a8c1d9194.png)

- Visual Studio上でも作りたてのスクリプトが `using UnityEngine` や `MonoBehaviour` の参照を認識しません。
- アンインストールしようがアプリケーションデータを消そうが再インストールしたら症状が続きます。

## もしかして
- 権限関係が破壊されたのでは、という情報をもらいました。権限が破壊され操作不能になったファイルを含む部分の権限を正しく再設定すればよいのは道理です。ただし検証や修復には莫大な時間がかかるでしょう。私は新しいユーザーを作ることで済ませることにしました。
Vue.jsでHTMLのバリデーションが効かなくて詰まった時の話

## inputタグに使用できる入力必須の機能
http://www.htmq.com/html5/input_required.shtml

入力してなかったら弾かれるという基礎的なバリデーションの機能をつけようとして、よく使用するhtmlの機能のrequired="true"で処理しようとした。が、バリデーションが効かず入力してなくても次のページへ遷移してしまう。。。

HTML、CSSに関しては個人アプリやスクールで利用していたため、requiredが効かない原因がVue.jsの何らかの機能のせいなのだろうということは何となくわかったのですが、知識がなくてどこでバリデーションが無効になっているのかがわからず...


## 原因
submitボタンでの処理が原因でした。

```js
//template部分
@on-click="$emit('next'); submit()"
```
この一行。

```js
//js部分
  methods: {
    submit() {
      this.$emit("update", {
        eventId: this.$route.params.id,
        Name: this.Name,
        mailAddress: this.mailAddress,
      });
    }
  }
```
クリックした時に関数のsubmitが発火。$emit('next')で次に遷移している。
この$emit('next')で、バリデーションに引っかかってようがいまいが、データを持って次に遷移してしまっている。
なので、バリデーションをかけるのはsubmitの関数の中。

```js
  methods: {
    submit() {
      if(this.eventId && this.eventId && this.eventId){
        this.$emit("update", {
          eventId: this.$route.params.id,
          Name: this.Name,
          mailAddress: this.mailAddress,
        });
        this.$emit('next');
      }
    }
  }
```
こうすることで、入力していないとボタンが押せなくなりました。
Vue.jsを使った初めてのフロント実装

# Vue.jsとは？
https://lab.aratana.jp/entry/2017/12/09/000000
↑参考資料

jQueryは少し触ったことがありますが、動きをつけたい部分にちょこっと使用していただけのため、そこまでJavaScriptに詳しいわけでもなく....。

本当に漠然とした理解なのですが、動きをつけたい部分をそれぞれコンポーネントとして分けて記載し、それをhtmlで記載した部分の骨組みの中で呼び出して使用するという感じでしょうか。
今回はすべてVue.jsでの実装になるので混乱していますが、パーツ利用だともう少し理解しやすいのかなーと思ったり。
知識的にはほぼない状態のスタートなのではやく慣れていきたいです。



## よく出てくるメソッドのメモ

- v-bind 属性を反映する

下記（HTML側）は、この要素のclass属性を、VueインスタンスのisActiveプロパティによって更新して保存するという処理になっている。

```js

//例） HTML側。この場合、isActiveが真偽値となっており、trueだとactiveクラスが生成される。
<div class="app">
  <div v-bind:class="{ active: isActive }"></div>
</div>

//例）　js側
new Vue({
  el: 'app',
  data: {
    isActive: true
  }
});
```

- v-for(htmlとjsにそれぞれの記載が必要)　配列の繰り返しを扱う

```js

//例） HTML側。listsという配列の入ったメソッドを、listというメソッドに代入して繰り返し処理
<div id="app2">
  <li v-for="list in lists" :key="list.id">
    {{ list.name }}
  <li>
</div>

//例）　js側
var vueApp= new Vue({
  el: '#app2',
  data: {
    lists: [
      { name: 'Vue.js' },
      { name: 'Angular.js' },
      { name: 'React' }
    ]
  }
});

vueApp.lists.push({ name: 'Nuxt.js'})
//この記載でvueAppの中の配列listsにname:'Nuxt.js'を追加できる。
```

- v-model(htmlとjsに) 入力を反映する

```js
//例） HTML側
<div id="app4">
  <p>{{ message }}</p>
  <input v-model="message">
</div>

//例） js側
new Vue({
  el: '#app4',
  data: {
    message: 'Hello Vue!'
  }
})
```




## local-strageとは？？
Cookieとかsessionみたいなもの。
検索機能つけるときに。
https://qiita.com/RunEagler/items/4496161d3b709659a897