OmniAICreator/Qiita-1.07M huggingface dataset:
GithubのReleaseをトリガーにしてCircleCI2.0でデプロイする

## GithubのReleaseを使う
GithubのRelease機能を使ったことある人はいますでしょうか？
これまでブランチをdevelopment, staging, productionに切って、それぞれに対応するデプロイ環境にリリースするようにしていたのですが、仕事ではフロントエンドとサーバーサイドの開発をそれぞれ別リポジトリで管理しており、デプロイしたバージョンに何を入れたか忘れてしまったり、コミット履歴長すぎて見る気しなかったりして、リリースノートにすべてまとめたいと思い、今回はGithubのReleaseを公開したらCircleCIでデプロイまで走る方法を調べました。

基本的な実装方法は、ここを参考にしました。
https://qiita.com/oohira/items/09aa91cc01109f8d053b

デプロイには以下の条件を設定しました。

- リポジトリのブランチはmasterブランチのみを使用する
- masterブランチにコミットされたら、develop環境にデプロイする
- GithubのReleaseでRCバージョンのタグ(ex. 0.1.0-rc1)が打たれたら、staging環境にデプロイする
- GithubのReleaseでリリースバージョンのタグ（ex. 0.1.0）が打たれたら、production環境にデプロイする
- sandboxブランチにコミットされたら、sandbox環境にデプロイする（masterブランチにマージする前に実験できるお遊びサーバーを追加しました）

## 対象のブランチ＆タグでビルドが走るようにする
要点だけまとめると、`.circleci/config.yml`に以下の点に気をつけて書くだけでOKです。

```
version: 2
jobs:
  build:
    docker:
      - image: circleci/node:8.15.1
    steps:
      - checkout
      - deploy:
          name: deploy build artifact
          command: |
            if [[ "${CIRCLE_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\-rc[0-9]+$ ]]; then
              echo "Deploy to staging"
            elif [[ "${CIRCLE_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
              echo "Deploy to production"
            else
              if [ "${CIRCLE_BRANCH}" == "master" ]; then
                echo "Deploy to development"
              elif [ "${CIRCLE_BRANCH}" == "sandbox" ]; then
                echo "Deploy to sandbox"  
              else
              fi
            fi
```
環境変数の`CIRCLE_TAG`が設定してある場合、`CIRCLE_BRANCH`にはブランチ名が入ってこないため、タグで判定したあとにブランチで判定しています。
念の為補足ですが、`CIRCLE_BRANCH`が設定してある場合、`CIRCLE_TAG`は空になっています。

```
workflows:
  version: 2
  build-and-deploy:
    jobs:
      - build:
          filters:
            tags:
              only:
                - /^[0-9]+\.[0-9]+\.[0-9]+\-rc[0-9]+$/
                - /^[0-9]+\.[0-9]+\.[0-9]+$/
            branches:
              only:
                - /^sandbox$/
                - /^master$/
      - deploy:
          requires:
            - build
          filters:
            tags:
              only:
                - /^[0-9]+\.[0-9]+\.[0-9]+\-rc[0-9]+$/
                - /^[0-9]+\.[0-9]+\.[0-9]+$/
            branches:
              only:
                - /^sandbox$/
                - /^master$/
```

requiresで指定している前処理でfilterを設定しているだけだと、その後の処理は実行されないため、タグですべての処理に実行してほしい処理全てにfilter設定を書く必要があります。
Bitrise/fastlaneでpod updateの自動化はいいぞー

# TL;DR
- Podで管理してるライブラリ群のアップデートをするlaneを書く
- BitriseでWorkflowを指定
- Workflowをスケジューリングしておこう

# 前書き
iOSの開発を行っているみなさん, Pod, 使いますよね?
Podに限らず, Railsで開発するときもGemでライブラリ群を管理すると思うのですが, ライブラリというのは定期的にアップデートしないといつの間にか古くなってしまったりしますよね.
マイナーバージョンやパッチバージョンがいくつかアップデートされてるだけならまだいいのですが, **気づいたらメジャーバージョンが二つも上がってる!** なんてこともあるかもしれません.

これにはいくつか原因があるかも知れないのですが, わたしは**気付けない**ことが原因になることが多いのではと思っています.
つまり, アップデートがあったときに検知できる仕組みがあることが重要だと考えます.

この記事では, Bitriseとfastlaneを用いてPodで管理されているライブラリ群のアップデートがあったときに検知できる仕組みを作っていこうと思います.

# FastfileにPodをupdateするlaneを用意する

```Ruby:Fastfile
desc 'Update pods'
lane :update_pods do
  date = Date.today.to_s # 現在日付を取得
  branch_name = "feature/pod-update-automation-" + date # branch名

  sh("pod update") # この時点でファイル差分があれば以降の処理でPRが出る
  sh("git checkout -b #{branch_name}")

  git_add
  git_commit(
    path: "./",
    message: "Update Pods"
  )
  push_to_git_remote(
    remote: "origin",
    local_branch: branch_name,
    remote_branch: branch_name,
    tags: false
  )
  create_pull_request(
    repo: "tihimsm/my_app",
    title: "Update Pods", # PRタイトル
    head: branch_name,
    base: "develop", # PRを出す先のブランチ
    body: "A difference exists in Podfile.lock.\n Please check!" # PRのメッセージ部分
  )

  slack(message: "A difference exists in Podfile.lock. Please confirm Pull Request.")
end
```
このようなlaneをFastfile内に記述します.
やっていることはシンプルです.
1. `pod update`コマンドをたたく
2. `Podfile.lock`に差分があればPRを作成

やろうと思えば, 差分があったらメインブランチに直接pushとかもできるのですが, さすがに動作確認などを行わずにメインブランチには反映したくないと思うので, PRを出すようにしています.

ちなみにこの中で使われている`sh`, `git_add`, `git_commit`, `push_to_git_remote`, `create_pull_request`はfastlaneが標準で用意しています.
オプションなど詳しい情報は公式ドキュメントを下に貼っておくのでご覧ください.

- [sh](https://docs.fastlane.tools/actions/sh/)
- [git_add](https://docs.fastlane.tools/actions/git_add/)
- [git_commit](https://docs.fastlane.tools/actions/git_commit/)
- [push_to_git_remote](https://docs.fastlane.tools/actions/push_to_git_remote/)
- [create_pull_request](https://docs.fastlane.tools/actions/create_pull_request/)

# BitriseにWorkflowを設定
Workflowはとても簡単です.
リポジトリをCloneしてきてfastlaneで`update_pods`を起動させるだけです.
<img width="358" alt="スクリーンショット 2019-07-16 0.11.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142392/92b99da8-788e-99ad-0b5d-97d69d8fa50c.png">

# Workflowをスケジューリングしよう
`Builds`タブの画面右上の方に`Start/Schedule a Build`というボタンがあるので, そこからスケジューリングの設定を行います.
![スクリーンショット 2019-07-16 0.18.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142392/7fbe07ec-5311-85a5-e929-3e6800094c9d.png)
上のような画面で設定が行えます.

- 時間
- 曜日
- ブランチ
- Workflow

を設定することで, 自動でWorkflowが起動できます.
上の例だと`毎日AM02:00`に起動しますが, 毎日だとさすがに鬱陶しい場合は週一とかにすると良いと思います.

# まとめ
いかがでしょうか?
今回はPodのアップデートについて書きましたが, Gemのアップデートも同様に行えるので, fastlaneやcocoapodsのアップデートも自動で検知できるようにすると非常に便利ですよ!

ちなみに, **ライブラリをアップデートしたら不具合が!** なんてこともよくあると思うので, PRが出た時に自動テストが走るようにしておくとGoodですね!
アニメの名言を返すbotを作って、LINEの会話がもっと伝わるようにしてみた件について

# LINEの会話を盛り上げたい
日本人の多くが使っているLINE。お手軽にテキストチャットできて、便利ですよね！

でも、こんなチャットだとちょっと物足りなくなってきませんか？
![before.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275279/29dace52-f1d3-aede-40cf-6edf6fa33b86.jpeg)

mitsui君に試合終了感が伝わりませんね

そこで、LINEの会話を盛り上げるためのBOTとして、 **animergen** を開発しました。

# animergenってどんなもの？

```math
animergen（あにめーげん） = anime（アニメ） + mergen（名言）
```

animergenとは、LINEの発言の中からアニメや漫画の名言を見つけて、**名言画像を返してくれるBot** なのです。

animergenを導入しただけで、さっきの会話もこの通り！！

![after.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275279/079de9eb-d9d8-6c4e-b78f-594b1f5e38c3.jpeg)

mitsui君に試合終了感がよく伝わってますね！（ごり押し）

# 何ができる？

グループにanimergenを追加することで、グループ内のすべての発言に対して名言をチェックし、画像を返します。

animergen には２つの機能があります。どちらもLINEのインターフェースとなっており、エンジニアじゃなくても簡単に操作することが出来ます。

### animergen
LINEのトークフィールドに送信された発話にマッチしたアニメ画像のURLを返します。animergenがURLをつぶやくと、LINEのプレビュー機能によって画像で表示されます。

### mergen_register
animergenの名言を追加する機能。
登録したい名言を投げると、候補画像を表示してくれるので、選択するだけで名言が追加されます。

# どうやって作ったか？

### 使ったもの
- Python3
- LINE Messaging API
- kintone
- cotoha

全体構成はこんな感じ。

![animergen_structure.001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275279/b398f251-a829-53fd-a38a-6cf553db2e1b.png)

### メインアルゴリズム
python3で書かれたメインアルゴリズムをherokuで動作させています。
グループにコメントが投稿されると、形態素解析や正規表現によって、DBに登録された名言を含んでいるかを検索します。
一致する名言があると、名言画像のURLを返します。

### データベース
名言のDBには[kintone](https://devmyumit.cybozu.com) を使わせていただきました。去年の[One JAPAN HACKATHON TOKAI](https://onejapan-hackathon-tokai.jp/) に参加した時に使い方を教えてもらえたので、活用してみました。
どんな名言が登録されたかがGUIで見れるので、animergenのような不特定多数から登録されるデータの管理には向いてるかと思います。

### 形態素解析
形態素解析には、[cotoha](https://api.ce-cotoha.com/contents/) を使わせていただきました。
最初はjanomeを使って形態素解析しようとしたのですが、herokuのフリープランのメモリ上限512MBを余裕で超えてデプロイできなかったので、既存のサービスを使わせていただきました。


# よかったら使ってみてください

以下のQRコードからanimergenの友達申請ができるので、使ってみてください。
現在は、僕のアニソンカラオケ友達が登録してくれた400件以上の名言が登録されています。

「あきらめたらそこで試合終了だよ」とか「だが断る」とか言ってみると良いと思います。

![animergen_bot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275279/c869e893-dfc1-bb63-6c9a-36c00b55bb53.png)


#　締め
mergen_registerはもうちょっと改良出来たら公開するつもりです。

~~あとは、DB内に登録されている名言の可視化もやっていきたいと思っています。~~
@the1031hiroto さんに協力してもらったことで、可視化ページが完成しました！ →　[mergen_view](https://animergen.herokuapp.com/mergen_view)
mergen_viewの記事も作ってもらったので、ぜひご覧ください →　[mergen_viewの記事](https://qiita.com/the1031hiroto/items/7d76d8c2a987288711e4#_reference-a33652372671202ffb0f)
DockerHubにあるimageを使ってCakePHPを表示、少し中をみるまで…

#はじめに
今回使うDockerHubのimageがあるところは、以下URLです。
https://hub.docker.com/r/quantumobject/docker-cakephp

`$`はうつコマンドの前につけてあるだけなので`$`部分は打たないでください。

あと以下で行うのは本格的開発には向いていません。少しみて少し中いじいじしたいんだと言う方へ向けたものです(/ω＼)

#使ってみる
●まずはCakePHPの表示を行うまで

・はじめにDockerを使えるようにするまでの私のいつもの手順のcommand書いておきます。
Docker始めるまでの[記事](https://qiita.com/sachiko-kame/items/35e0cf07d117c3b92613)も書いたのでもしよかったらみてください。

```
//defaultマシーン起動
$ docker-machine start default
//環境変数の確認
$ docker-machine env default
//環境変数の適応
$ eval "$(docker-machine env default)"
```
・早速URL先のimageをとってきてbuild、Runまで行う。

```
$ docker run -d -p 80 quantumobject/docker-cakephp
```
はい。たったの一行です。完了するまで環境にもよりますが15分ほどでしょうか？

終わったら現在Dockerで走っているのにこれがあるか見てみます。

```
$ docker ps
```
走っていれば以下のようになってます。
<img width="1072" alt="スクリーンショット 2019-07-15 22.32.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133940/71dc98a0-9359-8467-b2d7-5116c61f882d.png">

ポート32769で動いているようです。
これで`0.0.0.0:32769`で表示できる方もいるかもしれませんが私はここで表示されているipの確認をしないといけないので確認をします。

```
$ docker-machine ip default
```
あとは、表示されたipアドレスを使い、

http://<ここipアドレス>:32769/　な感じでアクセスすれば出来ます。

<img width="1044" alt="スクリーンショット 2019-07-15 22.35.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133940/459149fe-42fc-eb30-f378-e4258278df3c.png">

- 表示出来たのでだいぶ満足なのですが中も少しみてみます。
まずは今動いているものを表示。表示されたら一番左に表示されている`CONTAINER ID`を使います。
え~たくさんあるぞって方は一番右から2番目に`IMAGE名`が表示されているのでそれが`quantumobject/docker-cakephp`のものを

```
$ docker ps
```

- 動いているコンテナに入る

```
$ docker exec -it <先ほどのCONTAINER ID> bash
```

- 本体色々と入っているところまで移動(`/var/www`以下)

```
$ cd /var/www
```
<img width="561" alt="スクリーンショット 2019-07-15 23.24.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133940/7dd09acd-01ce-2262-668d-eb8a4da38a82.png">

- もう少し中身をみる。

```
$ cd src
```
<img width="478" alt="スクリーンショット 2019-07-15 23.26.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133940/993e9c88-6915-ec6b-8990-ea5f693cc740.png">

ちなみに抜けるのは、

```
$ exit
```
で出来ます。

#おまけ
っといっても本当これだけだと中身みるだけで終わってしまいます。`vim`コマンド使えない…。

なので`vim`コマンド使えるようにするためだけに`Dockerfile`を作ります。
`vim`コマンド使えるのに参考にさせていただいたのは以下の記事です。
https://qiita.com/YumaInaura/items/3432cc3f8a8553e05a6e

```:Dockerfile
FROM quantumobject/docker-cakephp

RUN ["apt-get", "update"]
RUN ["apt-get", "install", "-y", "vim"]
```
で、その`Dockerfile`がある場所までいき、以下コマンドをうちimageを作成します。タグ名を`cakephpaddvi`としています。

```
$ docker build -t cakephpaddvi .
```

とりあえずimageが出来てるか確認

```
$ docker images
```
次にここでRUNしたいのですが、先ほど入っているものがあるとRUN出来ないので一回とめます。

```
起動確認
$ docker ps

起動確認で得たコンテナIDを使い止める
$ docker stop <コンテナID>
```

準備出来たので早速RUNします。先ほど上で出てきたコマンドのimagem名が変わっただけです。
あとは上で行ったように中に入ったり、もう編集もできると思うので編集して中をいじいじしてみてください(✿´ ꒳ ` )

```
$ docker run -d -p 80 cakephpaddvi
```


#最後に
以上！終わりです！
elixirでリストの中身を検索したかったやつ

elixirで

```elixir
iex> lists
[
  ["1", "a1", "a2", "a3"],
  ["2", "b1", "b2", "b3"],
  ["5", "c1", "c2", "c3"],
  ["8", "d1", "d2", "d3"]
]
```

的なリストの中身をID(1,2,5,8)で検索したくて、
とりあえず調べながらやってみたやつです。(もっと綺麗なやり方とかあるはず、、、)

## コード

```elixir
defmodule ListFind do
  # id が含まれている list を探す 
  def id_find(id) do
    Enum.find(lists, fn list ->
      Enum.at(list, 0) == Integer.to_string(id)
    end)
  end
  # 探したリストから要素を取り出す
  def data_find(id) do
    case id_find(id) do
      nil -> "nil"
      list -> Enum.at(list, 1)
    end
  end
end

```

`Enum.find`と`Enum.at`で、引数で渡したidが含まれるのリストを探し、
`case`でidが存在しなかった場合を弾いて`Enum.at`で抽出。
Node.jsでGoogle Drive内の特定のファイルが特定のフォルダの配下にいるかどうかを調べる  (Google Drive API v3)


Google Drive APIをNode.jsから触る以下の記事たちの続きです

* [Node.jsでGoogle Driveの指定フォルダからファイル一覧を取得メモ](https://qiita.com/n0bisuke/items/ff1479cd14e7a0c0be0c)
* [Node.jsでGoogle Drive上のファイルを複製（copy）する](https://qiita.com/n0bisuke/items/6d73bb6e1af123db9a9b)
* [Node.jsでGoogle Drive上のファイルを指定フォルダに移動する](https://qiita.com/n0bisuke/items/8f108408a9e1067b9225)
* [Node.jsでGoogle Drive上のファイルをリネームする](https://qiita.com/n0bisuke/items/dcc7be337a555b018b19)
* [Node.jsでGoogle Drive上のファイルを削除する (Google Drive API v3)](https://qiita.com/n0bisuke/items/a1b39635029242f31713)

## GETメソッドを再帰的に使う

[GETメソッド](https://developers.google.com/drive/api/v3/reference/files/get?apix_params=%7B%22fileId%22%3A%2214Ki6cHIglEfN2uyQ0xftak6ux0ZD6-zJ%22%7D)で`fields`に`parents`を指定することで、親フォルダのIDを取得できます。
これを再帰的に繰り返していって、祖先を遡っていったときにフォルダ名が指定した名前のものが見つかったら終了です。

ちなみにGETメソッドの返却値は[FILESのリファレンス](https://developers.google.com/drive/api/v3/reference/files#resource)を見ると確認できますが、けっこうたくさんあるので把握するのは大変そうですね。

## スコープ

```
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/drive.readonly
https://www.googleapis.com/auth/drive.metadata.readonly
https://www.googleapis.com/auth/drive.appdata
https://www.googleapis.com/auth/drive.metadata
https://www.googleapis.com/auth/drive.photos.readonly
```

なかなか多い。

## 簡単な実装

基本的な認証周りなどのコードは他の記事同様です。

```get.js

省略

//特定のファイル(fileId)が特定フォルダ(folderName)の配下にいるか確認
const folderName = `定期発生`; 
const fileId = `xxxxxxxxxxxxxxxxxxxx`;

async function loop(drive, fileId, path = ''){
    //STEP1: IDからファイル情報を取得
    const params = {
        fileId: fileId,
        fields: 'parents,name,kind,mimeType,id,spaces'
    }
    const res = await drive.files.get(params);
    console.log('---',res.data);
    path = `/${res.data.name}${path}`;

    //STEP2: 親フォルダのIDをGET - ここが複数あるとうまく動かないときあるかも...
    const parentsFolderId = res.data.parents[0];

    //STEP3: 親フォルダを再帰的に探していく
    try {
        if(res.data.name === folderName){
            console.log(`このファイルは${folderName}の配下です。`, path);
        }else{
            await loop(drive, parentsFolderId, path);        
        }
    } catch (error) {
        console.log(`このファイルは${folderName}の配下ではありません。`)
    }
}

async function main(auth) {
    const drive = google.drive({version: 'v3', auth});
    await loop(drive, fileId);
}
```
laravelを使用したjsonを返すAPIの作り方

>Laravelのリソースクラスは、モデルやモデルコレクションを記述しやすく簡単に、JSONへと変換してくれます。

↑公式から引用

## モデル作成

```
php artisan make:model UserSample
```

## モデル記述


- $fillableに指定したカラムのみ、create()やfill()、update()で値が代入されます。

- モデルから変換する配列やJSONに、パスワードのような属性を含めたくない場合があります。それにはモデルの$hiddenプロパティに定義を追加してください。



```/api/app/UserSample.php
namespace App;

use \App\UserSample;
use Illuminate\Database\Eloquent\Model;


class UserSample extends Model
{

    protected $table = 'UserSample';
//    上記コードでテーブル指定
    protected $fillable = [
        'name', 'email', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

}

```

##　コントローラー作成


```
php artisan make:resource UserSampleResource
```

## コントローラー記述

```/api/app/Http/Resources/UserSampleResource.php
<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserSample extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return parent::toArray($request);
    }
}

```

## route記述

```/api/routes/api.php
<?php

use App\UserSample;
use Illuminate\Http\Request;
use App\Http\Resources\UserSampleResource;

Route::get('/user', function () {
    return new UserSampleResource(UserSample::all());
});

```


## マイグレーション作成

```
php artisan make:migration UserSample
```

## マイグレーション記述

```/api/database/migrations/2019_07_15_042644_UserSample.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UserSample extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('UserSample', function (Blueprint $table) {
            $table->increments('id')->index();
            $table->string('name')->nullable();
            $table->string('email')->nullable();
            $table->string('password')->nullable();;
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}

```


## マイグレーション実行

```
php artisan migrate
```

## 実行する

ローカルにサーバーを立てる

```
php artisan serve
```
下記をGETする
http://localhost:8000/api/userSample


下記のようにjson形式でデータが返ってくるAPIの完成

```
{"data":[]}
```

次回はuserを作成するAPI開発について書く。

サンプルコード
https://github.com/taichi0514/laravel_sample_api-
書籍『たのしいRuby』の練習問題を解いてみた Part.3

# 本題  
今回は第14章の練習問題をいく。少し難しい部分もあった。
**(1)**　"Ruby is an object oriented programming language."という文を書く単語に分け配列にせよ。

```ruby:1_1.rb
text = "Ruby is an object oriented programing language"
arry = text.split(/ /)

#出力して確認してみます
p arry
# 実行結果：["Ruby", "is", "an", "object", "oriented", "programing", "language"]
```
特にコメントはない。

**(2)**　(1)の配列をアルファベット順にソートせよ。

```ruby:2_1.rb
text = "Ruby is an object oriented programing language"
arry = text.split(/ /)
#アルファベット順にソートする
arry.sort!
#出力しておきます
p arry
#実行結果：["Ruby", "an", "is", "language", "object", "oriented", "programing"]
```

ちなみに、sortよりsort_byの方が処理が早いそうです。

**(3)**　(2)の配列を大文字小文字の区別なくアルファベット順にソートにせよ。

```ruby:3_1.rb
text = "Ruby is an object oriented programing language"

arry = text.split(/ /)

#出力しておきます
p arry.sort_by {|v| v.downcase }
#実行結果：["Ruby", "an", "is", "language", "object", "oriented", "programing"]
```

downcaseで一度大文字にしてから比較させてみました。

**(4)** (1)の文字列に含まれる文字とその数を ' ': ****** , `R` : *,....のような形式で表示させよ。

```ruby:4_1.rb
text = "Ruby is an object oriented programing language"

table = Hash.new(0)

text.scan(/./){|m| table[m] += 1}

table.each do |key , value|

      count = "*" * value

      p "#{key}：#{count}"

end
#実行結果："R：*"\n"u：**"\n"b：**"\n"y：*"...省略
```

scanメソッドを利用しハッシュ化させました。

**(5)**　”七千百二十三"といった、漢数字による1~9999の数の表現技法を「7123」のような数値に帰るメソッドkan2numを定義せよ。

```ruby:4_1.rb
def kan2num(str)

      str.gsub!(/一/, "1")

      str.gsub!(/二/, "2")

      str.gsub!(/三/, "3")

      str.gsub!(/四/, "4")

      str.gsub!(/五/, "5")

      str.gsub!(/六/, "6")

      str.gsub!(/七/, "7")

      str.gsub!(/八/, "8")

      str.gsub!(/九/, "9")

      str =~ /((\d)?千)?((\d)?百)?((\d)?十)?(\d)?$/

            if $1
                  sen = $2 || "1"
            end
            
            if $3
                  hyaku = $4 || "1"
            end

            if $5
                  zyu = $6 || "1"
            end

            if $7
                  ichi = $7
            end
      ans = sen.to_i * 1000 + hyaku.to_i * 100 + zyu.to_i * 10 + ichi.to_i


end

p kan2num("千二十三")
#実行結果：1023
p kan2num("二千十九")
#実行結果：2019
p kan2num("七百九十四")
#実行結果：794
p kan2num("千百九十二")
#実行結果：1192
```

泥臭いですが、まずは漢数字の一、二、三、四…を先に数字に変換しました。その次に正規表現を使い、それぞれの位(千,百,十,一)の数値を取得し、その値を桁の数に合わせて掛け合わせ足すという方式を取りました。結構、自分には難しかったです。

# 最後に
今回は文字列に対する操作が多い問題でした。そして、最後の問題が思ったよりもヘビーでした…正規表現、使いこなそうと思うと難しいなぁ…
MarkLogic10のCNTKでONNXモデルを使ってみる

# はじめに
[前回](https://qiita.com/t2hk/items/ea9a842327ef5ffa682a)はCNTKでirisの推論モデルを作成し、ONNX形式で出力しました。MarkLogic10はCNTKとONNXに対応しており、ONNXに対応するフレームワークで作成したモデルを読み込めます。
今回はオリジナルのCNTKで作成したモデルをMarkLogicのCNTKで読み込み、推論してみます。

# 環境
| 環境 | バージョン |
| --- | --- |
| CentOS | 7.6 |
| MarkLogic | 10.0-1 |

# ONNXモデルをDBにロードする
使用するONNXモデルをMarkLogicにロードします。ロードはMarkLogicのロードツール[MLCP](https://developer.marklogic.com/products/mlcp)を使用します。

MLCPの実行例は以下の通りです。ポイントはバイナリ形式でロードする点です。

```shell
$ mlcp.sh import \
-host [MarkLogicサーバ] \
-port [XDBCサーバのポート] \
-username [ユーザ名] \
-password [パスワード] \
-input_file_type documents \
-document_type binary \
-input_file_path [ONNXモデルのファイルパス] \
-output_uri_replace "[ONNXモデルのファイルパス], '[MarkLogic上のロード先URI]'"
```

# ONNXモデルで推論してみる
ロードしたONNXモデルを使って、MarkLogic上でirisの推論を行います。irisデータセットは[以前の投稿](https://qiita.com/t2hk/items/455f676851cec8d8b796)に記載したものです。言語はXQueryです。

なお、ソースコードは以下に公開しています。
https://github.com/t2hk/marklogic_cntk_onnx

## ONNXモデルの読み込み
以下のようにMarkLogic上のONNXモデルを読み込みます。バイナリとして読み込むことがポイントです。

```
(:ONNXモデルの読み込む。:)
let $doc := fn:doc("[ONNXモデルのURI]")/binary()
let $model := cntk:function($doc, cntk:gpu(0), "onnx")
```

## 入出力データの変数定義
モデルの入力データ、出力データの変数定義を行います。モデル定義から読み込めます。

```
(:モデルの入出力形式を取得する。:)
let $input_variable := cntk:function-arguments($model)
let $output_variable := cntk:function-output($model)
```

## 入力データを用意する
テストデータ（irisの特徴量）からモデルの入力データを作成します。入力データは、モデルの入力定義である[cntk:input-variable](https://docs.marklogic.com/cntk:input-variable)と、入力データである[cntk:value](https://docs.marklogic.com/cntk:value)を組み合わせたJson形式の配列でなければなりません。

```
let $test := json:to-array(($sepal_length, $sepal_width, $petal_length, $petal_width))
let $input_value := cntk:batch(cntk:variable-shape($input_variable), $test)
let $input_pair := json:to-array(($input_variable, $input_value))
```

## 推論する
推論は[cntk:evaluate](https://docs.marklogic.com/cntk:evaluate)関数を使います。
推論結果は[cntk:value](https://docs.marklogic.com/cntk:value)形式であるため、[cntk:value-to-array](https://docs.marklogic.com/cntk:value-to-array)関数を使ってJSON配列に変換します。

```
(:ONNXモデルを使用して推論する。:)
let $output_value := cntk:evaluate($model, $input_pair, $output_variable)

(:結果を出力する。:)
let $infer_result := cntk:value-to-array($output_variable, $output_value)
return fn:index-of($infer_result[1], fn:max($infer_result[1]))
```

上記の変数$infer_resultは、irisの種類に応じた確率値となります。この中で最大値のクラスのラベルを推論結果として返却しています。

```
[[-3.597829, 1.868926, 1.515098]]]
```

# おしまい
MarkLogic10がCNTKを搭載したことによりDB上での機械学習モデルの構築が実現しましたが、XQueryでネットワークを構築するのは大変な点が多いです。
また、CNTKは本家が開発を中止しており情報も少ないこともあり、TensorflowやChainerなど使い慣れたフレームワークを使いたくなります。
ONNXを使用することで、使い慣れた環境で構築したモデルをMarkLogic上で動かせるようになります。
Svelte3 svelte:componentでコンポーネントを動的にレンダリングする


プルダウンで選択した内容によってコンポーネントを動的に書き換えたい、みたいな時のやり方。

# 参考リンク
- [チュートリアルページ](https://svelte.dev/tutorial/svelte-component)


# ソース
```html
<select bind:value="{selected}">
    {#each options as option}
        <option value="{option}">{option.name}</option>
    {/each}
</select>

<!-- ここが動的にレンダリングされる -->
<svelte:component this="{selected.component}"/>

<script>
    import Hoge1 from './Hoge1.svelte';
    import Hoge2 from './Hoge2.svelte';
    import Hoge3 from './Hoge3.svelte';

    const options = [
        { name: '', component: null },
        { name: 'hoge1', component: Hoge1 },
        { name: 'hoge2', component: Hoge2 },
        { name: 'hoge3', component: Hoge3 },
    ];
    let selected = options[0];
</script>
```

## thisにコンポーネント以外を渡した場合
`null`とか`false`とかとか...。
コンポーネント以外を渡すとなにもレンダリングされません。

前にレンダリングされていたコンポーネントがある場合、前のコンポーネントが破棄されるだけです。

## プロパティを渡す
特別なことはなく普通に渡すだけ。

```html
<svelte:component this="{selected.component}" fuga="{selected.name}"/>
```
今日の学習

##やったこと
・progateでHTML,CSSの学習、理解

・Rails チュートリアル２章のrails consoleの立ち上げのところ

##難しくてハマってるところ

・[http://localhost:3000/microposts](http://localhost:3000/microposts)を開くと、
![画像](http:localhost:3000/microposts)　←のようにエラーが出た。
【Unity】別プロジェクト・別コンポーネント間で値のコピー (YAML)

### 環境
- Windows10
- Unity2019.1.1
- Unity2018.3.6

### 本題
UnityのプレハブはYAML形式であり、普通にテキストエディタで開いて編集できたりする
なので、アタッチされているコンポーネントの変数を「Copy Component/Paste Component」を使わなくてもテキストでコピペできる

以下は「あるコンポーネントのstring配列の値を、別プロジェクトの同じくstring配列を持つコンポーネントに全部コピペしたい。プロジェクトはそれぞれ別バージョンのUnity」の例

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156809/4c90a6d0-af73-f63a-4a13-6b4e9bf7069b.png" width="640">

それぞれのプレハブを適当なテキストエディタで開いて、該当箇所を形式を合わせてコピペする

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156809/409136ce-9bbf-c13e-3079-eff1be4efaf3.png" width="640">

Unityに戻ってプレハブを確認すると、ちゃんと値が反映されているはず
反映されていない場合はプレハブをReimportする必要がある場合があるかも
デコレータとスレッドの組み合わせ

# デコレータを子クラスで実装する
仕事のプログラムでどうしてもクラスで一元化したいところがあった。
親クラスのインスタンスメソッドをデコレータにして、
子クラスにデコレートされるインスタンスメソッドと
並列処理をしたいメソッドを書く。
さらに親クラスと子クラスでファイルを分けて、
インスタンスを作成し、実行するだけで動くようにしたかった。

teratailでは基本的にデコレータはトップレベル以外では
使うなとお言葉をいただいたが、今回は無視して実装。

## まずは同ファイル内で。

```python:test1.py
import threading
from time import sleep

class P(object):
    def printing(func):
        def printing_w(self, *args):
            t1 = func(self, args[0], args[1])
            t2 = func(self, args[2], args[3])
            t1.start()
            t2.start()
            t1.join()
            t2.join()
            print('finish')
        return printing_w

class C(P):
    def worker(self, *args):
        print('start')
        print(args[0])
        sleep(2)
        print(args[1])
        print('end')
    @P.printing
    def work(self, a, b):
        return threading.Thread(target=self.worker, args=(a, b))

c = C()
c.work(100, 200, 300, 400)
```
意外とあっさりできた。

# ファイル分割

同ディレクトリ上に作成。

```python:test1.py
import threading
from time import sleep

class P(object):
    def thre(func):
        def thre_w(self, *args):
            t1 = func(self, args[0], args[1])
            t2 = func(self, args[2], args[3])
            t1.start()
            t2.start()
            t1.join()
            t2.join()
            print('aaaaa')
        return thre_w
```
```python:test2.py
import test1

class C(test1.P):
    def worker(self, *args):
        print('start')
        print(args[0])
        test1.sleep(2)
        print(args[1])
        print('end')
    @test1.P.thre
    def work(self, a, b):
        return test1.threading.Thread(target=self.worker, args=(a, b))
```
```python:test3.py
import test2

c = test2.C()
c.work(100, 200, 300, 400)
```
以上メモ書きでした。
[Unity] ObjectPool

##はじめに
個人メモのため限定共有公開ダヨ。
Unityでの、オブジェクトプールと簡単な使い方のみ。（2019/07/15）
UniRx使ってるヨ。

##コード

```C#
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEngine;

public class ObjectPool
{
    private GameObject obj;         // 生成元のオブジェクト
    private int objNum;             // 生成する数
    private GameObject[] objs;      // オブジェクトプール配列

    public ObjectPool(GameObject obj, int objNum, bool instantiate = true)
    {
        this.obj = obj;
        this.objNum = objNum;

        objs = new GameObject[objNum];
        if (instantiate) Init();
    }

    public void Init()
    {
        var objParent = new GameObject(obj.name).transform;
        for (int i = 0; i < objNum; i++)
        {
            objs[i] = Object.Instantiate(obj) as GameObject;
            objs[i].name = obj.name + i;
            objs[i].transform.parent = objParent;
            objs[i].SetActive(false);
        }
    }

    private int stateIndex = 0;

    public void SetActive(Vector3 position)
    {
        if (objs[stateIndex].activeSelf)
        {
            var addObjs = Object.Instantiate(obj);
            addObjs.transform.position = position;
            Observable.Timer(System.TimeSpan.FromSeconds(10)).Subscribe(_ => Object.Destroy(addObjs));
        }
        else
        {
            objs[stateIndex].SetActive(true);
            objs[stateIndex].transform.position = position;
            Observable.Timer(System.TimeSpan.FromSeconds(10)).Subscribe(_ => objs[stateIndex].SetActive(false));    // 一定時間後にアクティブファルス - オブジェクト側で捜査したほうがいい
            RoundRobin();
        }
    }

    public void RoundRobin()
    {
        stateIndex = stateIndex < objNum-1 ? stateIndex+1 : 0;
    }
}
```

###使うとき

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectPool_Test : MonoBehaviour
{
    public GameObject obj;
    private ObjectPool objPool;

    void Start()
    {

        objPool = new ObjectPool(obj, 100);             // 生成
        objPool.SetActive(new Vector3(0f, 10f, 0f));    // 使用
    }
}
```

##おわりに
とりあえず作ったものなので要改良。

ゲームオブジェクトにアタッチしてないので、MonoBehaviour使うのなら、改造してね。
追記：最初限定公開で個人メモにしてたのでいろいろ雑
nginxでPythonをCGIとして実行する


```bash:インストール
apt install python3 nginx-full fcgiwrap
```
```bash:nginxの設定
vi /etc/nginx/conf.d/fcgiwrap.conf
```
```conf:中身
server {
	listen 80;
	listen [::]:80;

	server_name cgitest;
	set $base /home/あなたのhome/DocumentRoot;
	root $base/cgitest;

location ~ \.py$ {
	gzip off;
	include fastcgi_params;
	fastcgi_pass unix:/var/run/fcgiwrap.socket;
	fastcgi_index index.py;
fastcgi_param DOCUMENT_ROOT		$realpath_root;
	fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
	}
}
```

```bash:再読込
service nginx restart
service fcgiwrap restart
```

```py:スクリプトに実行権限を与えておこう
mkdir ~/htdocs
vi test.py 
chmod +x test.py 
```

```py:test.py
#!/usr/bin/python3
print("HTTP/1.0 200 OK")
print("Content-type: text/html\n\n")
print("")
print("Hello world")
```

```bash:domainを通す
vi /etc/hosts
```

```
127.0.0.1 cgitest
```
ブラウザで
http://cgitest/test.py
を開けば問題ないでしょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245977/f6224cd5-4969-bd59-0dc4-7f148388f514.png)

#query(パラメタ)とPOST
url?foo=bar とかPOSTは以下の通り。

```python:test.py
#!/usr/bin/python3
import urllib.parse

print("HTTP/1.0 200 OK")
print("Content-type: text/html\n\n")
print("")
print("url?var=foo <br>")
getquery = os.environ.get('QUERY_STRING')
print(getquery)
query = urllib.parse.parse_qs(getquery)
print(query)
print("post <br>")
posted = input()
print(posted)
print(urllib.parse.parse_qs(posted))
```

```sh:curlテスト
# curl -X POST -d "eee=uuu" -d "aaa=bbbb"  "http://cgitest/test/removeimage.py?py=aa&chin=5"


url?var=foo <br>
py=aa&chin=5
{'py': ['aa'], 'chin': ['5']}
post <br>
eee=uuu&aaa=bbbb
{'eee': ['uuu'], 'aaa': ['bbbb']}
```

#Ref
http://ekzemplaro.org/data_base/doc/web_server/nginx/
https://stackoverflow.com/questions/16253036/python-on-nginx-using-fcgiwrap-upstream-closed-prematurely-fastcgi-stdout-whil
https://qiita.com/gam0022/items/d16cc83a32c5c2efdefc
https://note.nkmk.me/python-urllib-parse-query-string/
https://www.setouchino.cloud/blogs/33#part-5b2df4e0f04afe49
Herokuで有料プランから無料プランに変更した場合の注意点

## Herokuで有料プランから無料プランに変更した場合の注意点
Herokuでサービスを運営するときの注意点です。
僕は今までは独自ドメイン対応や、ダイノのスリープを防ぐために有料プランにしていました。
しかし、CloudFlareによるDNS設定と、cron-job.orgでの定期アクセスにより、無料プランでも問題がなくなったため、無料ダイノに変更しました。

しかし、ここで問題がおきました。複数のアプリケーションをこの方法でデプロイしていたところHerokuの無料枠を超過してしまったのです。結果として、少しの間サービスが停止してしまいました。

一つのアカウントで複数の無料ダイノを動かすとこのようになるのでご注意ください。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
SQL基本コマンド

##はじめに
[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンをしている<小栗>です。
「プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

今回はSQLの基本コマンドについてまとめます。
ほんのさわりの部分しか学んでいないので、知識が増えしだい、アップデートします。


##データ操作言語DML

####SLECT
```sql


SELECT 列名 FROM テーブル名;--基本

```

```sql

SELECT 列名 FROM テーブル名 WHERE 条件式;--条件を付与して要素を取り出したいとき
```
```sql
ORDER BY 列名 ASC--昇順でソート
ORDER BY 列名 DESC --降順でソート
```


また、列名の欄には関数や演算式を入れることもできる。sum()、+=*/など。
深層学習（後編 1）：「Section7：Attention Mechanism」

Seq2Seqとはシーケンスのペアを大量に学習させることで、片方のシーケンスからもう一方を生成するモデルである。そのため、2単語でも100単語でも固定次元ベクトルの中に入力しなければならず、長い文章となるとシーケンスの内部表現の次元も大きくなり、対応が難しい。そこで入力と出力のどの単語が関連しているのかという関連度を学習する仕組みがAttention Mechanismである。
力の除数

#問題文
NK の正の約数であって、M 以下のものの個数を求めてください。

#ソース
```php
<?php
//入力値
$nyu1 = 12; //値
$nyu2 = 3;  //累乗値
$nyu3 = 50; //M以下の値(上限値)

//算出対象値を求める(乗算)
$nyu = pow($nyu1,$nyu2);

//小数点以下を切り上げ
$limit = ceil($nyu);
//約数を求める
for($i=1; $i<=$limit; $i++){
    if($nyu%$i == 0){
        $array[] = $i;
    }
}

//M以下のものの値を求める
for($i=0; $i < count($array); $i++){
    if($array[$i] <= $nyu3){
        $answer[] = $array[$i];
    }
}
echo count($answer);
//var_dump($answer);
?>
```
深層学習（後編 1）：「Section6：Word2Vec」

word2vecとは、大量のテキストデータを解析し、各単語の意味をベクトル表現化する手法である。単語をベクトル化することで以下が可能になる。
- 単語同士の意味の近さを計算
- 単語同士の意味を足す、引く
この手法により、大規模なデータの分散表現の学習が、現実的な計算速度とメモリ量で実現可能になった。
Qiitaコーパスを作る会 1️⃣Qiitaの全記事を取得してみる

# はじめに
NLPモデルを試すときに、コーパスとしてとりあえずWikipediaやLivedoorニュースを使ってみる例は結構あると思います。
しかし、技術系のコーパスとしてQiita記事もなかなか面白い結果が得られるよ！ってことで、その軌跡を記します。

今回のシリーズで作ったソースコードは[GitHub](https://github.com/LeftLetter/qiita_corpus)に置いてあります。


## Qiitaの全記事を取得してみる

はじめに、Qiita APIを使って全記事を取得します。
ソースコードは以下です。
このソースでは記事を投稿日毎にjson出力しています。


Qiita APIの詳細は[こちら](https://qiita.com/api/v2/docs)

```python:qiita_api_client.py
# --------------------------------------------------
# Qiita APIから記事データを取得
# --------------------------------------------------
import requests
import json
import time
from datetime import datetime, timedelta
import os


headers = {
    'Authorization': 'Bearer ' + os.getenv('ACCESS_TOKEN')
}
start = datetime.strptime(os.getenv('START_DATE'), '%Y-%m-%d')  # 開始日を設定
end = datetime.strptime(os.getenv('END_DATE'), '%Y-%m-%d')  # 終了日を設定

# API実行
results = []
for i in range((end - start).days):
    today = (start + timedelta(i)).strftime('%Y-%m-%d')
    print(today)

    params = {
        'page': 1,
        'per_page': 100,
        'query': 'created:' + today
    }
    res = requests.get('https://qiita.com/api/v2/items',
                       params=params, headers=headers)
    results.extend(res.json())
    total_count = int(res.headers['Total-Count'])
    print('total_count: ' + str(total_count))
    print(1)
    time.sleep(3.6)  # 3600秒に1000回まで

    # １日に101件以上投稿されていた場合
    for j in range(2, total_count // 100 + 2):
        params['page'] = j
        res = requests.get('https://qiita.com/api/v2/items',
                           params=params, headers=headers)
        results.extend(res.json())
        print(j)
        time.sleep(3.6)  # 3600秒に1000回まで

    # ファイル書き込み
    with open('data/qiita_' + today + '.json', 'w') as f:
        json.dump(results, f)
    results = []

```

## 補足
### 取得対象の日付
`end`は最新より少し昔に設定することをお勧めします。スパム記事が大量に投稿されており、まだ削除されていない可能性があるので・・・

```python:
end = datetime.strptime(os.getenv('END_DATE'), '%Y-%m-%d')  # 終了日を設定
```

今回は`.env`に以下の設定をしています。

```
START_DATE=2011-09-15
END_DATE=2019-07-01
```


### アクセス制限
アクセストークンを設定した場合、1時間に1000回のアクセス制限があるため待機処理を入れています。

```python:
    time.sleep(3.6)  # 3600秒に1000回まで
```

### ページング
`page`、`per_page`でページングができますが、100までしか対応していません。
つまり、一回のクエリで10000件を超える場合は取得できないので注意が必要です。
今回、記事を一日毎に取得しているのはそういう背景もあります（まさか1日に10000件以上投稿されることなんてないだろ・・・）。

```python:
    params = {
        'page': 1,
        'per_page': 100,
        'query': 'created:' + today
    }
```


# おわりに
次回→
[Qiitaコーパスを作る会 2️⃣前処理をする](https://qiita.com/LeftLetter/items/80b40574311448ea9290)
次々回→
[Qiitaコーパスを作る会 3️⃣単語埋め込みの様子を見てみる](https://qiita.com/LeftLetter/items/fcbe827c8af66160a429)
CEM Edge Manager 設定

https://docs.hortonworks.com/HDPDocuments/CEM/CEM-1.0.0/installation/content/configure-efm-server.html


> Configure your connection by editing the following two properties:
> Change efm.nifi.registry.enabled=false to efm.nifi.registry.enabled=true.
> Change efm.nifi.registry.url=http://localhost:18080 to efm.nifi.registry.url=http://{YOUR_REGISTRY_IP}:18080.

ここの説明はミスリード。

~~http://{YOUR_REGISTRY_IP}:18080.~~

```
efm.nifi.registry.url=http://zzeng-hdp-ambari.field.hortonworks.com:61080/nifi-registry/
```

.bashrc

```
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64
```


```
cd ~/tools/CEM/centos7/1.0.0.0-54/tars/minifi/minifi-toolkit-0.6.0.1.0.0.0-54
~/tools/CEM/centos7/1.0.0.0-54/tars/minifi/minifi-toolkit-0.6.0.1.0.0.0-54]$ bin/config.sh transform ~/tools/MiNiFi_Image_Capture_03.xml ~/tools/MiNiFi_Image_Capture_03.yml
```
深層学習（後編 1）：「Section5：Seq2Seq」

Seq2SeqとはEncoder-Decorderモデルの一種を指す。機械対話や翻訳等で使用されるモデルである。Encoderとはユーザーよりインプットされたデータを単語等のトークンに区切って渡す構造であり、Decorderとはシステムがアウトプットデータを。単語等のトークンごとに生成する構造である。課題としては一問一答しかできず、問いに対してただ応答が行われるだけである。
深層学習（後編 1）：「Section4：双方向RNN」

過去の情報だけでなく、未来の情報も加味することで、精度を向上させたRNNのモデルを双方向RNNと呼ぶ。一方のRNNは配列を左から右へ、もう一方は右から左へと処理する。統合された出力は教師が与えられた対象シグナルの予測である。機械翻訳等で実用されるモデルである。
深層学習（後編 1）：「Section3：GRU」

従来のLSTMではパラメータが多くなり、計算負荷が高くなる課題があった。そこでパラメータを大幅に削減し、精度は同等またはそれ以上の結果が見込めるRNNの構造をGRUと呼ぶ。GRUでは、入力ゲート、出力ゲート、忘却ゲートの代わりに更新ゲートがある。更新ゲートは最後の状態からどれだけの情報を保持し、前の層からどれだけの情報を取り込むかを決定する。リセットゲートはLSTMの忘却ゲートのように機能するが、位置付けが異なり、常に完全な状態を発信するが、出力ゲートはない。多くの場合、LSTMのようにGRUは機能するが、最大の違いはGRUの方が高速で簡単に実行できるところである。
GASで引数エラー(Ljava.lang.Object;@6cddb344)

# GASで引数に伴うエラー
## しようとしたこと
Google Formから入力された値をForm入力のタイミングでSpreadsheetに入力しようとした。
主なファイルの構成としては,
- mainFunction.gs
- setManageSheetValue.gs
- getYearMonth.gs
である。
`setManageSheetValue.gs`で対象のスプレッドシートにGoogleFormから取得した内容の一部を書きこもうとしていた。
スプレッドシートの名前は`2019年7月`のような年と月を示すもので、シートの名前を作る関数が`getYearMonth.gs`に書かれてある。
### 結果
下記のコードをやってみたが、ちゃんと書き込みができなかった。
GoogleFormから取得する内容の型に対してスムーズにいかなかったようだ。

##最初のコード
```js:getYearMonth.gs
//
function getYearMonth(){
  var today = new Date(); 
  var year = today.getFullYear() + '年';
  var month = (today.getMonth() + 1) + "月"; 
  var result = year + month;
  return result; //YYYY年MM月
}
```
```js:mainFunction.gs
function mainFunction(e){
...
var mailSender = e.namedValues['メール送信者'];
var timestamp = e.namedValues['タイムスタンプ'];
var dateOfSale = e.namedValues['営業日'];
...
setManageSheetValue(mailSender, timestamp, dateOfSale);
...
}
```

```js:setManageSheetValue.gs
/*
mailSender, timestamp, dateOfSaleはそれぞれGoogle Formから値を取得したものを引数として与えている。
*/
function setManageSheetValue(mailSender, timestamp, dateOfSale) {
  var spreadsheet = SpreadsheetApp.openById('AAA');
  var sheetName = getYearMonth(); 
  var sheet = spreadsheet.getSheetByName(sheetName);
  var getApoDate = Utilities.formatDate(new Date(timestamp), 'Asia/Tokyo','YYYY/MM/dd');
  sheet.appendRow([mailSender, getApoDate, dateOfSale.toString]);
  //[Ljava.lang.Object;@6cddb344, 2019/07/03,function toString() { [native code for Array.toString, arity=0] }
}

```
しかし、引数をそのまま指定すると
`[Ljava.lang.Object;@6cddb344`という値がシートの記入されていた。
うーん、toStringで変換した方がいいのかと考えて`dateOfSale.toString`のように変更してみたが`function toString() { [native code for Array.toString, arity=0]`という結果が返ってきた。

## 解決策
引数をStringとして扱う。
引数に対して`String()`を用いて解決した。

```js:setManageSheetValue.gs
function setManageSheetValue(mailSender, timestamp, dateOfSale) {
  var spreadsheet = SpreadsheetApp.openById('AAA');
  var sheetName = getYearMonth(); 
  var sheet = spreadsheet.getSheetByName(sheetName);
  var apointerNAme = String(mailSender);
  var apoDate = String(dateOfSale);
  var getApoDate = Utilities.formatDate(new Date(timestamp), 'Asia/Tokyo','YYYY/MM/dd');　
  sheet.appendRow([apointerNAme, getApoDate, apoDate]);
  //John,2019/07/03,2019/07/04
}
```
これでうまく書き込めた。
JavaScript 他言語によって制御されるHTMLタグへのイベントの追加

最近ハマったところです。

**ループによって生成されているボタンにJSイベントを追加する書き方**

```html:html
<div <!--なんらかの繰り返し処理 PHPとかで書くやつ-->>
	<form>
		<input class="hoge" type="button" name="huga">
	</form>
</div>
```


```JavaScript:js
var btn = document.getElementByClassName("hoge");
	for(var i = 0;i < btn.length;i++){
		btn[i].addEventListener('click',function(){
			//お好きな処理をどうぞ
		});
	}
```

##よくわかるかわからない解説
GetElementById以外は配列で取得されます。

JSの実行より先にHTMLが読み込まれるので、J生成されたタグをJS側で配列として取得し、その配列の長さ文for文を回します。
そうするとあら不思議！各要素にイベントが追加できちゃいます。

###〜書き方〜
最初にイベントを追加したいタグの配列を取得します。
サンプルコードだとボタンってやつ。
.lengthメソッドで長さ所得して、その長さ分forでくるくるします。
for文のiを添字に勝手に作られてしまった各ボタンにイベントを追加しています。
ちなみに親要素とか子要素になんかしたい場合は**this.parentNode**とかで親要素にDOMDOMできます。


function内では自身のインスタンスを参照してイベントを追加しているので？？？？？？？　-->書いててわからなくなりました。誰か正しい言葉を教えてください。

まあなんかaddEvent('●●' functin(){~~~});は追加するやつの独壇場って感じです。
**俺だ俺だ！！！！**ってのが**this**です。**this.parentNode**じゃなくて普通に**btn[i]**でもいいんですけどね。




###おしまい

めちゃめちゃググっても出てこねえし備忘録的なアレ。この墓場にたどり着いた人がいたら正しい表現を教えてくださいね。
深層学習（後編 1）：「Section2：LSTM」

LSTM(Long short-term memory)は、RNN(Recurrent Neural Network)の拡張として1995年に登場した、時系列データ(sequential data)に対するモデルのことを指す。
LSTMはRNNの中間層のユニットをLSTM blockと呼ばれるメモリと3つのゲートを持つブロックに置き換えることで実現されている。
メモリ：勾配消失及び勾配爆発の解決方法として、勾配を1とした自己ループ（CEC）
ゲート：入力ゲート、忘却ゲート、出力ゲート
またパラメータ数が多くなり、計算負荷が大きくなる課題がある。
CentOSにRuby on Rails開発環境を構築する方法（CentOS7.6 Ruby2.6.3 Rails 5.2.3）

#sudoersにユーザー登録

```
$ su

$ visudo
Allows people in group wheel to run all commands 
%wheel  ALL=(ALL)  ALL    #この行のコメントをはずす
```
ユーザをwheelグループに追加

```
$ usermod -G wheel username   
```
ユーザ切り替え

```
$ su username  
```
##参考サイト
 [一般ユーザでsudoが実行できない場合](https://qiita.com/ume_tomo/items/71861a7797d5f5f12b2b) 

#GitとRubyのビルドに必要なものをインストール

```
$ sudo yum update

$ sudo yum install -y git

$ sudo yum install -y bzip2 gcc openssl-devel readline-devel zlib-devel
```

#rbenvのインストール

```
$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv

$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
```

~/.bashrc(または~/.bash_profile)に以下を追記する。

```
# rbenv
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
```

反映させ、確認する。

```
$ source ~/.bashrc

$ rbenv -v
>rbenv 1.1.2-2-g4e92322   # バージョンが表示される。
```

#Rubyのインストール

Rubyのインストール可能なバージョンを確認する。

```
$ rbenv install --list 
>Available versions:
  1.8.5-p52
  1.8.5-p113
  1.8.5-p114
  1.8.5-p115
   .....
   .....
```

任意のバージョンのRubyをインストールする。

```
$ rbenv install 2.6.3
```
インストールしたバージョンを指定

```
$ rbenv global 2.6.3

$ ruby -v
>ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
```

#Rails環境の作成

bundlerをインストール

```
$ gem install bundler
```

Railsの利用可能なバージョンを確認する

```
$ gem query -ra -n  "^rails$"
```

カレントディレクトリにGemfileを作成

```
$ bundle init
```
任意のバージョンを指定

```

$ echo 'gem "rails", "5.2.3"' >> Gemfile
```

./vendor/bundleにRails関連のGemが入る

```

$ bundle install --path vendor/bundle

```

#bundle execの省略設定

スクリプトをダウンロード

```
$ curl -L https://github.com/gma/bundler-exec/raw/master/bundler-exec.sh > ~/.bundler-exec.sh
```

~/.bundler-exec.shを編集する

```
.....
.....
unicorn
unicorn_rails
wagon
rails   #railsを追記する
}"

define-bundler-aliases

unset -f define-bundler-aliases
```

~/.bashrc（または~/.bash_profile）に以下を追記する

```
# "bundle exec" shortcut setting
[ -f ~/.bundler-exec.sh ] && source ~/.bundler-exec.sh
```

反映する

```
$ source ~/.bashrc
```

SQLiteをインストール

```
$ sudo yum install sqlite-devel 

$ bundle install
```

##参考サイト
 [CentOS7にRubyとRuby on Rails環境構築](https://qiita.com/ponsea/items/aaff4c6b0bb8eed1d5e3) 
 [bundle execを省略してみる](https://qiita.com/uryonet/items/42ce27f04af462e2591b)
深層学習（後編 1）：「Section1 ：再帰型ニューラルネットワークの概念」

再帰型ニューラルネットワークとは、時系列データに対応可能なニューラルネットワークである。時系列データとは時間的順序を追って一定期間ごとに観察され、相互に統計的依存関係が認められるものである。例えばテキストデータや音声データ等のことを指す。時系列モデルを扱うには、初期状態と過去の時間t-1の状態を保持し、そこから次の時間でのtを再帰的に求める再帰構造が必要となる。
またRNNでは、入力から現在の中間層を定義する際にかけられる重み、中間層から次の中間層を定義する際にかけられる重み、中間層から出力を定義する際にかけられる重みの三つの重みが定義される。
OpenCVとdlibの物体(顔)検知の速度比較

# 目的

`OpenCV`の顔検知と`dlib`の顔検知はどちらの方が(処理が)軽いのかを調べる


# 動機

現在作っている[Cj-bc/Face-data-server](https://github.com/Cj-bc/Face-data-server)で[参考にしていたコード](https://qiita.com/kekeho/items/0b2d4ed5192a4c90a0ac)では、場所によって`dlib`と`OpenCV`を使い分けていました。
自分のコードを書いている時に、何か理由があるのか気になったので、「実行速度」という観点から何か違いがあるのかを調べてみることにしました。

# 検証

## 環境
(2019/10/25 追記)
処理系: `1.2GHz デュアルコアIntel Core m5`

## 方法

以下のコードを用いて、各項目毎100回の平均値を比較しました。
又、`OpenCV`のカスケードファイルは[Cj-bc/Face-data-server -- face_detection/haarcascades/haarcascade_frontalface_default.xml](https://github.com/Cj-bc/Face-data-server/blob/develop/face_detection/haarcascades/haarcascade_frontalface_default.xml)です


```python:検証コード
import time
import cv2
import dlib
from functools import reduce

# prepare dlib and cv2
face_cascade = cv2.CascadeClassifier('<PATH_TO_REPO>/face_detection/haarcascades/haarcascade_frontalface_default.xml')
detector = dlib.get_frontal_face_detector()


def ptime(f, arg):
    """Record how much time does f(arg) take"""
    s_time = time.time()
    f(arg)
    return (time.time() - s_time)


cap = cv2.VideoCapture(0)

# with face
input("show face to the camera")
_, frame = cap.read()
# with no face
input("Then, hide your face plz")
_, nofaceFrame = cap.read()

cap.release()

# helper wrapper to repeat ptime for 100 times and calculate average
result = lambda f, arg: reduce(lambda prev, n: prev + ptime(f, arg), range(100), 0.0) / 100

print("==== Gray scale ====")
print(f"cv2 with face     : {result(face_cascade.detectMultiScale, gray)}")
print(f"cv2 with no face  : {result(face_cascade.detectMultiScale, nofaceGray)}")
print(f"dlib with face    : {result(detector, gray)}")
print(f"dlib with no face : {result(detector, nofaceGray)}")
print("==== original Color ====")
print(f"cv2 with face     : {result(face_cascade.detectMultiScale, frame)}")
print(f"cv2 with no face  : {result(face_cascade.detectMultiScale, nofaceFrame)}")
print(f"dlib with face    : {result(detector, frame)}")
print(f"dlib with no face : {result(detector, nofaceFrame)}")
```

## 結果


```
==== Gray scale(include convert time) ====
cv2 with face     : 0.13291994094848633
cv2 with no face  : 0.03347130537033081
dlib with face    : 0.043859701156616214
dlib with no face : 0.04444729089736939
==== original Color ====
cv2 with face     : 0.12641916751861573
cv2 with no face  : 0.03346560716629028
dlib with face    : 0.061687271595001224
dlib with no face : 0.06083619832992554
```

# 考察

**いいからdlibを使え(速度重視の場合)**

`OpenCV`は、顔が検出されない時は`dlib`より速いものの、顔を検出するとなると圧倒的に遅くなることがわかりました。
その一方で、`dlib`は安定した数値を出しているようです。
稀にしか顔検出を行わない場合などは`OpenCV`の方が良い時がありそうですが、基本的には`dlib`を用いる方が安定しており得策かなと思いました。
又、これはおそらく学習データに依存した結果だと思うので他の場合も同様な結果になるのかはわかりません。
`dlib`の場合、グレースケールの方が変換する時間を含めても速かったですが`OpenCV`の場合はやや遅くなったことから、`OpenCV`での検出を使う場合はグレースケール変換を行わないほうが良いようです。

| ユースケース | 結果に基づくおすすめ |
| :-:|:-:|
| 常時顔検出をし続ける | Dlib(グレイスケール) |
| 極偶に顔検出する       | cv2 |


# 留意点

- このデータは以下の要素に依存する可能性があります。
  - 使用した学習データ
  - 実際に使用したキャプチャのフレーム
個人的なVim入門

# はじめに
[Vim幼稚園からVim小学校へ](https://qiita.com/hachi8833/items/7beeee825c11f7437f54)の記事がとても面白かったので、私も備忘録的に残します。
思い出しながら書いているので多少の前後はあるかもしれませんが、レベル感は雑に小刻みにレベルアップすることにして今後も書き足していけたらなと思います。
まだまだ使いこなしてはいませんが、Mac,Ubuntuを普段使いしていてVimを日常的に使用しています(まだVim幼児ぐらい笑)。

# 使うことになった経緯
Ubuntuを使うことになりました。ドットファイルや`/etc/...`を編集する際にターミナルから開けるエディタということで使い始めました。

色々な方がコマンドリストなどを紹介していると思いますが、最初から完璧に覚えるというより必要になるごとに適宜使えるコマンドを増やしていくとよいのかなと思っています。(一気に覚えようとしても無理だと思います）

# レベル0
- インサートモード`i`で←↓↑→キー移動
- 何も分からず`Esc`キーから`:wq`で保存終了
- `sudo`で開くのを忘れて困った時は`:q!`で終了

# レベル1
- インサートモードとノーマルモードの存在に気づく
- まだ移動は`h,j,k,l`のみ
- `yy`と`p`を使える

# レベル2
- `i,s,a`を使い分けられる
- `u, Ctrl+r`を使える
- `.vimrc`をネットから拾ってきて設定
- `gg, G`も移動に組み込める
- `/...`で検索、`n, Shift+n`で上下移動
- `x`で文字削除
- `dd`で行削除＆ヤンク
- `:set number`の存在に気づく

# レベル3
- `.vimrc`を作成
- ビジュアルモード`v`の存在に気づく
- `Visual+y, Visual+d`で一気にヤンク,ヤンク＆削除ができる
- `:split, :vsplit`からの`:open path/to/file`で他のファイルを同時に開ける(Ctrl+wで移動できる)
- 移動に`Ctrl+u, Ctrl+d`を使える
- tmuxと組み合わせるようになり、キーボードからあまり手を離さなくなる

# レベル4
- 行ビジュアルモード`Ctrl+v`の存在に気づく
- `:new, :vnew`からの`:e .`で他のファイルを開ける
- 矩形ビジュアルモード`Shift+v`の存在に気づく
- `ggVGy`で文書全体ヤンクを使える
- `:s/before/after`で置換できる
- `:%s/before/after/g`で文書全体置換できる
- vimium, vimium-ffの存在に気づく

# レベル5
- 矩形ビジュアルモード`Shift+v`の存在に気づく
- コメントアウト、アンコメントアウトのショートカットを作成
- コンパイル、実行のショートカットを作成
- Windowsにもvimをインストール(tmuxが使えず不便、上記ショートカットで対応)
- WindowsでWSLをインストールしてvimを使用(遅いから不便)
- VSCodeでvimキーバインドを使用(:eが使えず不便,Intellisense便利)

# レベル6
- macの購入とともにvimの使用頻度上昇
- `Ctrl+p`が使える
- この頃から日常生活に支障(他のエディタが使いづらい問題,jk連打してしまう)
- `Visual+y, Visual+d`の有効活用
- `x`でヤンクしないように設定
- `Visual+s`が使える
- `%`で対応括弧へ移動
- `f`で該当文字まで移動できることを知っている(が使わない)
- `0`で行頭まで移動できることを知っている(が使わない)

# レベル7
- `zf, zd, zm, zr`等のfoldingが使える
- `Visual+...`で一部だけ置換できることに気づく
- `.`が使える
- `@:`が使える
- `q:`が使える
- `/`検索でスッと移動
- `zz, zt`で文書の見え方を変更できる

# レベル8
- ターミナルのカーソルを`ブロック→垂直バー`に変更したら`i,a,s`を意識できるようになった
- 矩形ビジュアルモードで一気に文字を追加できる
- `$`で行末に移動できることを知っている(が使わない)
- 矩形ビジュアルモードに`$+A`で末尾に一気に文字追加できる
- `Ctrl+a, Ctrl+x`でインクリメント、デクリメントできる

# レベル9
- サーバ構築を試し、Vimの素晴らしさに気づく
- `vimdiff`の存在を知る
- `diffsplit [filename]`,`vertical diffsplit [filename]`を通常のvim上で実行して`:dp`でマージできる
Windows版QEMUにTAP-driverをインストールしてみた。

Windows版QEMUにブリッジ接続をする為のTAP-driverをインストール～設定した時のメモ。
Linux版QEMUでのブリッジ接続方法は記載が多いが、Windows版で纏められている記事は無さげなので記録を残しておく。
汎用的に利用できる手順のため、この項目を独立させる。

※自分もWindowsのTAP-driverとブリッジ接続の動きをきちんと理解している訳ではなく、手順に過不足あるかもしれないがご容赦。実際に動作した実績として記録する。

### 環境情報
端末：Windows 10 (64bit), NEC Lavie LS150/F(Pentium B950 2.10GHz, MEM 4GB)
QEMU-w64-setup-20190218.exe

### ブリッジ接続までの作業の流れ
1. [Windows版OpenVPNインストーラー](https://openvpn.net/community-downloads/)をダウンロードし、その中からTAP-driverのみインストールする

2. インストールされた[TAP-Windows Adapter V9]インターフェースに英数字で名前を付ける(ここでは"mytap"とする)

3. [TAP-Windows Adapter V9]インターフェースのプロパティを開き、NICにMACアドレスを設定する(既定値は空)

4. 既存の有線NICと[TAP-Windows Adapter V9]インターフェースを二つ同時選択し、右クリック(コンテキストメニュー)から「ブリッジ接続」を選択する
⇒ブリッジインターフェースが作成される

5. ブリッジインターフェースのNIC設定を確認する(コマンドプロンプトから ipconfig /all)

6. QEMUの仮想マシンを起動するときに、ゲストOS用のブリッジインターフェースにMACアドレスの引数をつけて起動する
(-net nic,macaddr=xx:xx:xx:xx:xx:xx -net tap,ifname=mytap)

### 事前準備
・[Windows版OpenVPNインストーラー](https://openvpn.net/community-downloads/)をダウンロードする

### インストール
・openvpn-install-2.4.7-I607-Win10.exeをダブルクリックし、その中から"TAP Virtual Ethernet Adapter"のみインストールする
![OpenVPN_inst_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451166/8d940106-2ef0-ea7b-7c6a-c39725c59271.png)
⇒Windowsの[コントロールパネル]-[ネットワークとインターネット]-[ネットワーク接続]に"TAP-Windows Adapter V9"が追加される
![TAPdriver_setting_011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451166/d8643bba-48a3-74b3-4a79-7c85e702ef4b.png)

### インストール後の設定
・インストールされた[TAP-Windows Adapter V9]インターフェースに英数字で名前を付ける(ここでは"mytap"とする)
・[TAP-Windows Adapter V9]インターフェースのプロパティを開き、NICにMACアドレスを設定する(既定値は空、QEMUでは"52:54:"で始まる値にした方がよい)
![TAPdriver_setting_091.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451166/0dee2233-c149-19c5-31f3-2fe9d7fda0ff.png)

・既存の有線NICと[TAP-Windows Adapter V9]インターフェースを二つ同時選択し、右クリック(コンテキストメニュー)から「ブリッジ接続」を選択する
![TAPdriver_setting_041.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451166/acff2f50-6b4e-4ae9-bff3-6217b6fb3d1e.png)
⇒ブリッジインターフェースが作成される
![TAPdriver_setting_051.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451166/32a06a0a-e799-2bce-e83e-cf06e68f830f.png)
・ブリッジインターフェースのNIC設定を確認する(コマンドプロンプトから ipconfig /all)
　DHCPならばブリッジインターフェースにも自動でIPアドレスが割り振られる

### QEMU起動
・QEMUの仮想マシンを起動するときに、ゲストOS用のブリッジインターフェースにMACアドレスの引数をつけて起動する
(-net nic,macaddr=xx:xx:xx:xx:xx:xx -net tap,ifname=mytap)
※[TAP-Windows Adapter V9]に設定したMACアドレスとは別のアドレスを設定する

Enjoy it!

(参考)
https://superuser.com/questions/1317652/how-to-set-up-nat-for-qemu-with-tap-backend-windows-10
[Documentation/Networking - QEMU](https://wiki.qemu.org/Documentation/Networking)
[QEMU ArchWiki - ネットワーク](https://wiki.archlinux.jp/index.php/QEMU#.E3.83.8D.E3.83.83.E3.83.88.E3.83.AF.E3.83.BC.E3.82.AF_2)