OmniAICreator/Qiita-1.07M huggingface dataset:
同一のシートを参照している複数のGlide(app)をそれぞれ複製した場合のシートの扱い

[Glide](https://www.glideapps.com/) はそのお手軽さから様々な用途での利用が増えていると思いますが、アプリケーションを複製可能な状態で公開しているアプリはあまり見かけません、残念です。

さて、本題に入ります。イラストなど使わず無愛想な投稿ですが御了承下さい。

尚、Glideの複製機能やテンプレートについては公式ドキュメント参照。

- [🧩 Templates \- Glide Library](https://docs.glideapps.com/all/reference/templates)
- [Copy app as template \- Glide Library](https://docs.glideapps.com/all/reference/templates/copy-app-as-template)
- [Allow people to copy your app as a template](https://docs.glideapps.com/all/guides/quick-starts/getting-started/sharing-your-app#allow-people-to-copy-your-app-as-a-template)

# 複数のアプリケーションから同一のGoogleシートを利用する

Glideでアプリケーションを新規作成する際、既存のGoogleシートを選択する方法がありますが、この際既に他のアプリケーションで利用されているものを選択することが可能です。Glideを利用された方であればまぁご存知かと思います。

# 同一のシートを参照している複数のGlide(app)をそれぞれ複製した場合のシートの扱い

以下のようなアプリケーションがいずれも複製可能な状態で公開されているとします。

- AppA(Glide app) 
    - Data1(Google Sheetsのspreadsheet)
- AppB(Glide app)
    - Data1(Google Sheetsのspreadsheet)

この状態で2つをコピーするとこうなります

- AppC (Copy of AppA)
    - Data2(Data1の複製)
- AppD (Copy of AppB)
    - Data3(Data1の複製)

注記) 完全な複製ではなく`App:Logins`シートはシート自体が複製されず。他にも差異があるかも。

# それがどうした?

Spreadsheet 複製時の動作はある意味当然ではありますが、Data2とData3が同一のものを指していれば嬉しいといったケースもありますよね。

Glide側で複数のアプリケーションとシートの関連性を考慮した複製が可能になれば、先の例で言うとData3がData2になれば、あるいはそもそもGlideの機能としてデータソースとしてのGoogleシートの変更が可能になれば、まぁいずれも実現されることは無いと思いますが...

# Data3をData2と同じ内容にしたい!!

色々とやり方があるかとは思いますがなかなかそこまでやるべきかGlide使うのに、という感じだと思います。

また、Glideはノーコード的でお手軽なので、黒い画面は使ったこと無いけれどスプレッドシートならかなり使いこなせるよ、という方々に対してはやはり、例えば[Google Apps Script](https://www.google.com/script/start/)でも敷居が高いと思うので、どうしたものかという話でした。以上です。
Backlog API と curlコマンド対応メモ

[Backlog API](https://developer.nulab.com/ja/docs/backlog/)をcurlコマンドで叩いてみたメモです。
Backlog APIごとのパラメーターの渡し方に悩むので、備忘録として書いておきます。
自分が必要な都度追記していきます。


# 共通設定
以下で試すcurlコマンドの共通設定です。

```
APIKEY="<API Key>"
BACKLOG_URL="https://<Backlogアカウント>.backlog.com"
```

# 環境

* mac OS10.14.6
* jq
* bash


# プロジェクト関連

## [プロジェクト一覧の取得](https://developer.nulab.com/ja/docs/backlog/api/2/get-project-list/#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E4%B8%80%E8%A6%A7%E3%81%AE%E5%8F%96%E5%BE%97)

[プロジェクト一覧の取得](https://developer.nulab.com/ja/docs/backlog/api/2/get-project-list/#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E4%B8%80%E8%A6%A7%E3%81%AE%E5%8F%96%E5%BE%97)

```
コマンド
curl -s $BACKLOG_URL/api/v2/projects\?apiKey=$APIKEY\&archived=false | jq -r '.[]'
```

```
実行結果
$ bash project.bash 
{
  "id": <プロジェクトid>,
  "projectKey": <"プロジェクトKey">,
  "name": "プログラミング開発",
  "chartEnabled": false,
  "subtaskingEnabled": false,
  "projectLeaderCanEditProjectLeader": false,
  "useWikiTreeView": true,
  "textFormattingRule": "markdown",
  "archived": false,
  "displayOrder": 2147483646
}
```


## [プロジェクトの状態一覧の取得](https://developer.nulab.com/ja/docs/backlog/api/2/get-status-list-of-project/#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E7%8A%B6%E6%85%8B%E4%B8%80%E8%A6%A7%E3%81%AE%E5%8F%96%E5%BE%97)

[プロジェクトの状態一覧の取得](https://developer.nulab.com/ja/docs/backlog/api/2/get-status-list-of-project/#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E7%8A%B6%E6%85%8B%E4%B8%80%E8%A6%A7%E3%81%AE%E5%8F%96%E5%BE%97)


```bash
コマンド
APIKEY="<API Key>"
BACKLOG_URL="https://<Backlogアカウント>.backlog.com"
curl -s $BACKLOG_URL/api/v2/projects/<プロジェクトKey又はプロジェクトId>/statuses\?apiKey=$APIKEY | jq -r '.[]'
```


```bash
実行結果
$ bash project.bash 
{
  "id": 1,
  "projectId": 19547,
  "name": "未対応",
  "color": "#ed8077",
  "displayOrder": 1000
}
{
  "id": 2,
  "projectId": 19547,
  "name": "処理中",
  "color": "#4488c5",
  "displayOrder": 2000
}
{
  "id": 3,
  "projectId": 19547,
  "name": "処理済み",
  "color": "#5eb5a6",
  "displayOrder": 3000
}
{
  "id": 4,
  "projectId": 19547,
  "name": "完了",
  "color": "#b0be3c",
  "displayOrder": 4000
}
```

# 課題関連

## [課題一覧の取得](https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-list/#%E8%AA%B2%E9%A1%8C%E4%B8%80%E8%A6%A7%E3%81%AE%E5%8F%96%E5%BE%97)

[課題一覧の取得](https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-list/#%E8%AA%B2%E9%A1%8C%E4%B8%80%E8%A6%A7%E3%81%AE%E5%8F%96%E5%BE%97)

```bash
# プロジェクトIDごとの課題一覧を取得
# Backlog APIのクエリパラメータ内の[]を無効にする為に、crulに -g オプションを付けています
curl -g -s $BACKLOG_URL/api/v2/issues\?apiKey=$APIKEY\&parentChild=0\&projectId[]=19547\&count=100 | jq -r '.[]'
```

```bash
# プロジェクトの状態(ステータス)をクエリパラメータに設定
# statusシェル変数にステータスの配列から0番目のステータスIDを取得
status=`curl -s $BACKLOG_URL/api/v2/projects/19547/statuses\?apiKey=$APIKEY | jq -r '.[0] | .id'`
curl -g -s $BACKLOG_URL/api/v2/issues\?apiKey=$APIKEY\&parentChild=0\&projectId[]=19547\&statusId[]=$status\&count=100 | jq -r '.[]'

# ステータス名"完了"から、ステータスIDを取得してもOK
status=`curl -s $BACKLOG_URL/api/v2/projects/19547/statuses\?apiKey=$APIKEY | jq -r '.[] | select(.name == "完了") | .id'`

```
SpringBoot + GradleのプロジェクトのCIをGitHub Actions + Dockerで回す（改）

## はじめに

Spring Boot + GradleのプロジェクトのCIをGitHub Actions + Dockerで回すということを[先日](https://qiita.com/shavada/items/2e889c9f6c3e440bb793
)から試している。
[こちら](https://help.github.com/ja/actions/building-actions/creating-a-docker-container-action)のドキュメントのやり方では、その都度イメージをビルドしてしまうので、非効率であるという指摘をもらった。

そこで、先日の記事とは別のやり方を試してみた。

以下、手順。

1. パブリックなカスタムDockerイメージを作る
2. workflow.ymlを修正
3. コミットをプッシュする

## パブリックなカスタムDockerイメージを作る

先日の記事と同様に`amazoncorretto:11.0.7`というDockerイメージを使用する。
ただ、このイメージはかなりミニマムに作ってあり、デフォルトでは`tar`や`gzip`コマンドが使えない。
このままでは、リポジトリのチェックアウトなどができないので、これらをインストールしたイメージを用意する必要がある。

まずは、`amazoncorretto:11.0.7`をベースに自前のイメージを作成する。
DockerHubのパブリックなリポジトリにプッシュするという前提で進める。

最初に下のようなDockerfileを用意する。
`tar`と`gzip`をインストールするだけの簡単なものになっている。

```Docker:Dockerfile
FROM amazoncorretto:11.0.7
RUN yum install -y tar gzip
```

このDockerfileを使って、イメージをビルドする。

```sh
docker build .
```

DockerHubにリポジトリを作る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628798/a7ffe6a8-1f56-c309-db58-93eec16979a2.png)

DockerHubにログインする。
パスワードにはDockerHub上で作成したトークンを入力する。

```sh
docker login
```

先ほどビルドしたイメージに名前とタグを付ける。

```sh
docker tag {ImageID} shavada/mycorretto:11.0.7
```

リポジトリにイメージをプッシュする。

```sh
docker push shavada/mycorretto:11.0.7
```

これで、DockerHubからイメージをpullできるようになる。

## workflow.ymlを修正

workflow.ymlを改めて書き直す。

```yml:./.github/workflows/workflow.yml
name: SpringBoot CI with Gradle

on:
  push:
    branches: [ master ]

jobs:
  test-build:
    runs-on: ubuntu-latest
    container:
      image: 'shavada/mycorretto:11.0.7'
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Add exec Permission
        run: chmod +x gradlew
      - name: Build with Gradle
        run: ./gradlew build
      - name: Archive production artifacts
        uses: actions/upload-artifact@v2
        with:
          name: demo.zip
          path: build/libs/demo-0.0.1-SNAPSHOT.jar
      - name: Archive test reports
        uses: actions/upload-artifact@v2
        with:
          name: test-reports.zip
          path: build/reports/tests/test
```

下のURLのドキュメントにも書かれている通り、ジョブの最初で`container`を指定できる。

https://help.github.com/ja/actions/reference/workflow-syntax-for-github-actions#

このようにしておくと、ジョブ内の全てのステップで同じコンテナが使用される。
また、先の記事ようにわざわざDockerfileを使ってその都度イメージをビルドすることなく、イメージをプルしてくるだけで済む。

## プッシュする

修正のコミットをプッシュすると、ワークフローが成功する。
ジョブの最初にコンテナを作成し、その中で処理を行った後、最後にコンテナを片付けているのが分かる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628798/ce0fe3a5-7e76-fc88-d1e2-16016c26ade9.png)
SwiftUIで画面の大きさに応じて内容が変わるビューを作る

[GeometryReader](https://developer.apple.com/documentation/swiftui/geometryreader)を使うと、ビューのサイズを取得できる。

```swift
struct ContentView: View {
    var body: some View {
        GeometryReader { geometry in
            Text("\(Int(geometry.size.width)) x \(Int(geometry.size.height))")
        }
    }
}
```
<img width="704" alt="スクリーンショット 2020-05-03 15.44.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14097/df73de82-07be-120c-88e7-d399dd83180f.png">

取得したサイズによって、表示する内容を変化させることでレスポンシブなビューを作ることができる。下のコードでは、横幅が800px未満の時はビューを縦に並べ、800px以上の時は横に並べている。


```swift
struct ContentView: View {
    var body: some View {
        GeometryReader<AnyView> { geometry in
            if geometry.size.width < 800 {
                return AnyView(VStack{
                    Color.red
                    Color.blue
                })
            } else {
                return AnyView(HStack{
                    Color.red
                    Color.blue
                })
            }
        }
    }
}
```

横幅が800px未満のとき
<img width="704" alt="スクリーンショット 2020-05-03 15.55.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14097/7374c2f6-cd81-9242-28c7-c5883d8694d4.png">

縦幅が800px以上のとき
<img width="1163" alt="スクリーンショット 2020-05-03 15.55.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14097/0b6ea3cb-8237-daa6-266d-c45f2ea50581.png">
Pythonでスクレイピングー貿易統計で使う輸出品目分類をPyhotnで自動取得

#このドキュメントのテーマ

Pyhonを使用してイケてないWebページのデータをイケてるCSV出力に！！

#何をしたかったのか？
[e-stat](https://www.e-stat.go.jp/)で提供される普通貿易統計をダウンロードしたら品目がHSコードという統計品目コードになっていてどの品目であるかのマスタをダウンロードしたかった。

#ダウンロードしたかったデータは存在するのか？
結論から言うと、存在しない。
税関のサイト（下図）のように品目の大枠の分類ごとにhtmlのテーブルタグが作成され、ドラッグして表計算ソフトへ貼り付け．．．が１回でできないようになっている。
手操作で行おうとすると21回もドラック＆ペーストしないといけないと思うと
とても心理的負荷が高く、イケてない！！
（オープンデータとか言っておきながらマスタデータが利用しにくいようになっているのは非常に残念。）

![2020-05-03 15.40のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470427/05b28a07-87d8-dd98-dca4-39324f9a6dcb.jpeg)

#何をしたか
PyhotnによるWebスクレイピングにてCSVに保存するコードを作成！

#コード
```python:makeCSV_HScode.py
import sys
import re
from urllib.request import urlopen
from html import unescape
import csv

def main():
    
    # 輸出統計品目表のURL(2019年4月版を入手）
    f=urlopen('https://www.customs.go.jp/yusyutu/2019_4/index.htm')
 
    # エンコード指定
    encoding=f.info().get_content_charset(failobj="shift-jis")

    # 指定されたURLを指定エンコードで読む
    html = f.read().decode(encoding)

    # CSVファイルのヘッダ項目書き込み
    writecsv('HSCodelist.csv','w','分類','内容')
    
    # 指定されたURLの一部を読み取り、正規表現で指定された内容を1行として切り出し、文字処理を行う。
    for partial_html in re.findall(r'(<td width="10%" nowrap="nowrap">第..類</td><td>\S*</td>)' ,html,re.DOTALL):
        strcd=re.search(r'(第.*類)</td>',partial_html).group(0)
        strcd=strcd[1:3]
        strcd=int(strcd)

    
        name=re.search(r'(<td>\S*)',partial_html).group(0)
        offset=len(name)-5
        name=name[4:offset]

        # CSVファイルへの書き込み
        writecsv('HSCodelist.csv','a',strcd,name)

# CSVへの書き込み関数    
def writecsv(filename,mode,value_No,value_str):
    
    with open(filename,mode,newline='',encoding='cp932') as f:
        writer= csv.writer(f,lineterminator='\n')
        writer.writerow([value_No,value_str])
        

if __name__ =='__main__':
    main()
```

#ハマったところ
指定されたURLの一部を読み取り、正規表現で指定された内容を1行として切り出す部分。
正規表現に慣れていなかったので、分類コード（HSコード）の先頭２桁に相当する「第xx類」と分類名を1セットにして取り出すところ。
試行錯誤ののち、取得できた。

#結果
下図のようにCSVデータ取得完了！！
![2020-05-03 16.06のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470427/4a3d5c8d-5f7c-6ea1-21be-6200707752e5.jpeg)
マイグレーションファイルを指定及び複数rollbackする方法


今回はマイグレーションファイルを複数rolllbackする方法を解説していきます。


下記のコマンドではマイグレーションファイルを１つずつしか差し戻すことができません。

```
$ rails db:rollback
$ rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20200421074000  Create spending categories
   up     20200421074008  Create income categories
   up     20200421074059  Create incomes
  down    20200421074131  Create spendings

```

下記のように末尾にSTEP＝で数を指定してあげると複数のファイルを差し戻すことが可能です。

```
$ rails db:rollback STEP=4　　　←
$ rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
  down    20200421074000  Create spending categories
  down    20200421074008  Create income categories
  down    20200421074059  Create incomes
  down    20200421074131  Create spendings
```

下記のようにVERSIONで "Migration ID" を指定してあげると選択のマイグレーションファイルのみを差し戻すことが可能です。

```
$ rails db:migrate:down VERSION=20190611235049 
```
BST Kính Xuân Hè 2020

![dominic_da_bao.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/4de44c92-1086-f370-501a-1955ee3565a6.jpeg)
![dominic_da_bao_mau_nu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/b2287253-ebb8-98ef-5a18-676fe9545608.jpeg)
![dominic_xanh_co_ban_goc_nghieng.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/316cb510-d68e-b64c-8ade-114b5be1408f.jpeg)
![dominic_xanh_co_ban_anh_mau_nu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/8107f8f8-4aea-f8db-e1e5-b08af3fb111a.jpeg)
![ula_hong_goc_nghieng.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/db268dd2-c6a4-83bb-8185-b8b59be54324.jpeg)
![ula_hong_mau_nu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/2e0c6e09-aa98-9cd2-7fe3-5dc463f1fe65.jpeg)
![wilson_da_bao_mau_nu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/892e15c6-19cd-7b1e-86fd-8884cc72bf8b.jpeg)
![wilson_den_bong_mau_nam.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/9e1eb874-ff32-a7b6-e587-427b42801546.jpeg)
![wilson_den_vang_goc_nghieng_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/b7a7a42c-48e4-1085-1d52-ab4c2e06e52a.jpeg)
![wilson_den_vang_mau_nu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/9aebf719-f204-53bd-7fc4-be685c9d2d7b.jpeg)
![wilson_doi_moi_goc_nghieng_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/70057f1c-3788-7891-07c1-39f1aca683d4.jpeg)
![wilson_vang_den_mau_nam.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622733/9ad6170f-7406-bc48-dc40-c6a79e8f36a2.jpeg)
Ruby on Rails チュートリアル 第１章②

○この記事の要点
「第1章　ゼロからデプロイまで」の途中から最後までの実施内容メモ
思ったことなどのメモ

○内容
■Gitによるバージョン管理
　・初期設定 git init
　・リポジトリに追加 git add -A
　・コミット git commit
　（git commitはローカルマシン上までの反映。git pushでリモートリポジトリへの反映）
　・バージョン管理のメリット
　　・誤って削除しても元に戻せる
　　・他人と共有できる
　　・好きなバージョンに戻せる

■Bitbucketによるリモートリポジトリ管理
　・Bitbucketのユーザ登録（https://bitbucket.org/account/signup/）
　・公開鍵の作成（https://git-scm.com/book/ja/v2）4.3 Gitサーバー - SSH 公開鍵の作成　参照
　・Bitbucketへ公開鍵の登録
　　Bitbucketの自分のページの左下にあるEボタン⇒personalsetting⇒SSH鍵⇒鍵を追加。keyにat ~/.ssh/id_rsa.pub　で表示されたssh-rsaをペースト
　・リポジトリの作成
　　Bitbucketでcreate repository
    ubuntu:~/environment/hello_app (master) $ git remote add origin git@bitbucket.org:ユーザ名/hello_app.git
    git push -u origin --all　※１　エラー発生

```ruby:エラー
ubuntu:~/environment/hello_app (master) $ git push -u origin --all
・・・
省略
error: failed to push some refs to 'git@bitbucket.org:ユーザ名/hello_app.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```
対処：理由は不明だったが、ローカルリポジトリとリモートリポジトリで差異があるから？
ググって強制的にプッシュ。解決
$ git push -f origin master

※GitHubではなく、Bitbucketを利用する理由
⇒どちらもGitリポジトリのホスティングと共同作業を行うことができ、リポジトリの表示や検索を行いやすくできる。GitHubは「リポジトリを一般公開する場合は無料、公開しない場合は有料」なのに対し、Bitbucketは「共同作業者が一定数以下ならリポジトリを公開しなくても無料、共同作業者が一定数を超えると有料」。本チュートリアルではWebアプリケーションの様々なコードを扱うため、全てのリポジトリがデフォルトで非公開になっている方がセキュリティ上安心して取り組めるため、Bitbucketを利用。※2019年1月からGitHubの非公開型レポジトリが無料になったため、本チュートリアルでも現在のBitBucketからGitHubに切り替える可能性あり。

■Gitの使い方（branch、edit、commit、merge）
ブランチの作成～masterへのマージ
・git checkout -b modify-README   modify-READMEというブランチを作成
・git branch    存在するローカルブランチの表示。*がついているのが現在卯使用中のブランチ
・git commit -a -m "コミットメッセージ"　ブランチ内でコミット
・git checkout master      マスターブランチに切り替え
・git merge modify-README      modify-READMEブランチの変更内容をマージ
・git branch -d modify-README      modify-READMEブランチの削除（削除は必須ではない）
・git push　　マスターへプッシュ

■Herokuを利用したデプロイ
・Herokuで利用するPostgreSQLデータベースのインストール
・Gemfileの追記　※解説には以下の2点が記載されているが、事前の書き換えで1点目はすでに記載

```ruby:Gemfileファイル
group :development, :test do
  gem 'sqlite3', '1.3.13'　　←この1行
  gem 'byebug',  '9.0.6', platform: :mri
end
group :production do　←ここから3行
  gem 'pg', '0.20.0'
end
```
・bundle installの実行
$ bundle install --without production
・Gemfileの変更内容コミット
git commit -a -m "Update Gemfile for Heroku"
・Herokuのアカウントを新規作成
・IDEでHerokuのインストール
source <(curl -sL https://cdn.learnenough.com/heroku_install)
・Herokuにログイン、SSH鍵の追加

```ruby:SSH鍵の追加
heroku login --interactive
heroku keys:add
```
・Herokuサーバーにサンプルアプリケーションの実行場所を作成
Herokuのサイトから、登録されたアプリケーション実行場所が表示されるようになる
・Herokuにデプロイする
git push heroku master
・Webサイトを見る
heroku createで作成されたURLを開くと、表示される

■メモ（アプリの修正とデプロイ手順）
（１）IDEでファイルの修正
（２）git commit
（３）git push
（４）git push heroku
※試してみたが、（３）git pushを飛ばした以下の順番でも、Herokuに載せたアプリは
修正後の動作になったが、Bitbucketから見たリモートリポジトリには変更が反映されていなかったので、実施することを推奨
（１）IDEでファイルの修正
（２）git commit
（４）git push heroku

■感想
・GitHubは利用したことがあったが、Bitbucketは初利用。まだ触ったばかりなので、良さは全然わかっていない。これから。
・Herokuはアプリケーションサーバだと思うけど、gitのプッシュと連携していていい感じ。
IoT開発で地味に使えるプロトタイピングツールたち - ソフトウェア


#とにかく早く思考を形にする

プロトタイピングは技術力とはまた違い、豊かな構想、エクストリームな想像とか妄想とかの存在性、意味性を高めるものという話を聞き、最近はいかに思考を早く形にするかとその手法探求にエネルギーを注いでいる。そんな中で、普段からヘビーユースしている3つのソフトウェアを紹介。

特に、
・入力、出力のインターフェース
・センシング
・無線回線
等のめんどくさい仕様をごく簡単に"とりあえず"実装できる。

#Blynk

Blynkは、ArduinoやRaspberry Pi,ESP23モジュールなんかをスマホからインターネット経由で簡単にコントロールするためのアプリ

![e8b00fab597d540410e8ae9165a3e78ec865b749.12.2.9.2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/d7c5ddcf-972a-20f8-9422-f8e4c6348c50.jpeg)

明治大学の渡邊恵太先生の研究室が、ExUI の設計手法を提案しているが、プロダクトは機能だけを備え，UIをスマートフォン上に外在化する。つまり全てがスマートフォンから操作できるという世界観を考えると、このアプリはドンピシャだと思う。加えてこの手のアプリはUIが雑に作られがちなのだが、シンプルながら使いやすくかなり洗練されている印象。多分これが使い続けているモチベーションとして一番大きいかも。

仕組みとしては、
<img width="375" alt="IMG_7A4748B15C71-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/e94fb112-bc29-42e1-8ea6-f0b1f7ccbe00.jpeg">

deviceと通信タイプを選択するだけでプロジェクトが立ち上がり、ここでプロジェクトのトークンが発行される。


<img width="375" alt="IMG_46645A71752B-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/135be499-64df-42af-6b31-78b5aaf7833e.jpeg">

これは例だが、espからの入力を受けるとtwitterをつぶやく、あるいはジョイコンを操作してラジコンを動かすといったことが30分程度で実装できる。

<img width="1405" alt="スクリーンショット 2020-05-03 15.11.24.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/1008a557-fbd9-7989-8254-ab76cab4892c.jpeg">

Arduino側のコード自体もライブラリをインポートし、プロジェクトのトークンのキーを入力するだけで簡単に使えてしまう。

#ZigSim

ZigSimはスマートフォンに入っているセンサー情報をOSC通信で、簡単に他のデバイス(PC,マイコンなど)に送ることができる。
![header_bg_full.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/1234aa90-4cb7-740b-8e4e-2d8552984f91.png)

これだけたくさんセンサーが積んであるスマホを活用しない手はあるはずもない。スマホとPCで簡単なIotアプリケーションまで30分で組める代物。実際に、手に装着したスマホから加速度センサをPCにおくり、Wekinatorと呼ばれる機械学習を簡単に試せるアプリで機械学習をさせることで、ジェスチャーを認識させることができるというアプリを組むことも可能。

仕組みは、
<img width="375" alt="IMG_2947.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/c211572c-e161-cc1c-b2fb-51019580aae1.png">
<img width="375" alt="IMG_2948.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/b8d8d690-f8e7-533a-9831-cc53fb464e36.jpeg">

センサーを選択し、ipアドレスやportを入力し、受けたいデバイスでデータを受け取るだけ。

#Ifttt(Alexa + Webhook)

近頃、音声をインターフェースにするVUI = Voice User Interfaceが増えてきている。
現に、alexaやgoogle homeは家電と音声を連携させることでon,offの管理、温度制御などを可能にしている。
実際にAlexaと生活していると、その恩恵が計り知れない。今後10年はこのVUIが定着していくフェーズと思われるので、ここのインターフェースの開発もかかせない。特にAlexaを入力として使用する場合のプロトタイピングで使えるツールの紹介。

<img width="692" alt="スクリーンショット 2020-05-03 15.31.14.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/dc324376-c853-4730-1cf4-60ecd6d1d1da.jpeg">

<img width="412" alt="スクリーンショット 2020-05-03 15.29.41.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222551/e3184b2d-3954-19cd-efc0-b7fe5546e10a.jpeg">

もちろんAlexaアプリを作ることもできるのだが、時間がかかるということでiftttを使うことをおすすめしたい。
iftttで〇〇という音声がalexaに呼びかけられたときというトリガーを作り、webhookというアプリでhttpリクエストをおくることができる。先程の、blynkなどはhttpリクエストによる制御が可能なので、alexaに呼びかけると、webhookからblynkを通じて、マイコンの操作などが可能になる。
Todoistのタスク名に，内容に応じて自動的に絵文字を追加する (例: Buy milk → 🛒 Buy milk)

## やりたいこと
Todoistにタスクを自分で追加すると，勝手にタスク名に絵文字をつけてくれる
→ **なんか見やすい！！！**

![wanttodo](https://user-images.githubusercontent.com/20534543/80897168-02e99d80-8d31-11ea-9ed0-f963dc22a475.png)

## どうすればできる？
下図のような処理のフローで実現する！

![flow](https://user-images.githubusercontent.com/20534543/80907138-1a378380-8d4f-11ea-8f20-94d0ccfd6583.png)

## 準備すること
### Python 依存環境
```
python==3.7.4
todoist-python==8.1.1
```

### Python スクリプト
```py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import os
import re
import todoist

# 前回のタスク情報のキャッシュがある場合，キャッシュを削除．
if os.path.exists(r"~/.todoist-sync/"):
    print("===== Deleting cache ...")
    os.rmdir("~/.todoist-sync/")

# APIキーを環境変数から取得．
print("===== Sync my todoist data ...")
api_key = os.environ.get("TODOIST_API_TOKEN")

# Todoistのサーバーデータをローカルに同期．
api = todoist.TodoistAPI(api_key)
api.sync()

# 全タスク情報を取得．
tasks_all_list = [item.data for item in api.state["items"]]

# 絵文字に置換する言葉と対応する絵文字のディクショナリ．
wordspattern_and_emoji_dict = {
    r"[Rr]eply|[Mm]ail"                : "✉",
    r"[Cc]ancel|[Uu]nsubscribe"        : "❌",
    r"[Cc]heck|[Ee]xpire"              : "⚠",
    r"[Hh]ospital"                     : "🏥",
    r"[Bb]arber"                       : "💈",
    r"[Mm]ovie|[Cc]inema"              : "🎥",
    r"[Dd]inner|[Ll]unch|[Bb]reakfast" : "🍽",
    r"[Bb]uy|[Oo]rder"                 : "🛒",
    r"[Mm]eeting"                      : "🤝",
    r"[Ww]atch"                        : "📺"
}

print("===== Renaming tasks ...")
for task in tasks_all_list:
    # タスク名とタスクIDを抽出．
    task_name = task["content"]
    task_id   = task["id"]

    for word, emoji in wordspattern_and_emoji_dict.items():
        if re.search(word, task_name):
            # 絵文字置換対象のタスク名であった場合
            if re.search(r"^[\w\[]", task_name):
                # 文頭が絵文字ではない場合
                task_name_replaced = f"{emoji} {task_name}"

                print(
                    f"   *** Replaced:\n"
                    f"         {task_name}\n"
                    f"         -> {task_name_replaced}\n"
                )

                # タスク名を絵文字置換後のものにアップデート
                api.items.update(task_id, content=task_name_replaced)
                break

# 変更内容をサーバーに反映
api.commit()
```

## 注意点
- Todoistで一回Syncすると`~/.todoist-sync/`ディレクトリにキャッシュが保存される．  
そして，Syncすると上記キャッシュファイルからの差分を取得する．  
本スクリプトでは毎回全タスクを取得したいため，最初にキャッシュを削除している．
- Todoistサーバーに反映させるためには，スクリプトの最後に`api.commit()`をする必要がある．
- 置換文字のディクショナリは，上から順番に探索してマッチしたら置換して`break`するため，優先的に置換したい絵文字はディクショナリの上位に配置する必要あり．
大学生がGatsby.js×Netlify CMSで自作ブログを開設してみた

Gatsby.jsで↓のようなブログを作ってみました。

[http://keisukee.com/](http://keisukee.com/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311529/f9006811-decd-5121-7e17-086aa64cf327.png)

ということで本記事では、 Gatsby.js×Netlify CMSで自作ブログを作ってみた感想とか、カスタマイズした部分、使用したテンプレートなどについて書きます。
## 公式のドキュメントが最強

公式のドキュメントがめちゃくちゃ充実しているため、ドキュメント+サンプルコードがあれば、必要な機能はだいたい実装できちゃいます。

必要なことは全部ドキュメントに書いてあります。

[https://www.gatsbyjs.org/](https://www.gatsbyjs.org/)

チュートリアルもちゃんとあって、プロジェクトの立ち上げ→プラグインの入れ方・カスタマイズ方法→Graphqlでデータを取得まで、Gatsby.jsでサイトを作る上で最低限のことは全部学べます！

公式バンザイ！！！

## 使用したテンプレート＆カスタマイズしたこと

使用したテンプレートはこれ

[https://www.gatsbyjs.org/starters/netlify-templates/gatsby-starter-netlify-cms/](https://www.gatsbyjs.org/starters/netlify-templates/gatsby-starter-netlify-cms/)

デモサイトはこんな感じです。

[https://gatsby-netlify-cms.netlify.app/](https://gatsby-netlify-cms.netlify.app/)

このテンプレートを使っておけば、ブログを運営するのに最低限の機能はそろいます。

- **ブログ機能（CMS）**
- **タグ機能**
- **Netlifyでのホスティング**

僕が追加でカスタマイズした箇所は、

- **SNSシェア機能**
- **Navbarのリンク張り変え**
- **検索バーを設置**
- **全体的なデザインをちょっと変更**
- **日本語対応**
- **Google Analytics追加**
- **Youtube, Twitterなどのコンポーネントの埋め込み**
- **数式をLatex風味で出力**
- **独自ドメイン（Netlifyでボタンをポチポチするだけ）**

ぐらいですね。まあ、色々手間取ったので、今の状態に持っていくまでに2,3日かかりましたが、まあ満足してます！まだまだ全体的にデザインがアレだったり、ページネーションがなかったりと、不満なことはあるので、気が向いたときにカスタマイズしようかなと。

## Gatsby.jsを使うメリット

- 全部gitで管理できること。**自分の文章をリライトするとき、github上でセルフレビューしながらやったらめちゃめちゃライティングの力つきそう**ですよね。**コミットごとに、自分の人生の歴史を刻んでいる感じがして、中二病な僕にとってはすごい楽しいです**
- 超早い
- カスタマイズ性

## Gatsby.jsを使うデメリット

Gatsby.jsのメリットとデメリットは表裏一体です。すなわち、

- 動的にコンテンツを作成できないこと。まあカスタマイズすれば色々やれるんでしょうが、めんどいっすよね
- コメント機能、サイト内検索、などを実装するのが面倒
- 記事をアップロードしてから公開されるまでにタイムラグがあること
- メンテナンスしないといけないこと

## 自作ブログはいいぞ。ポートフォリオに最適では？

特に未経験から転職・インターンを考えている人は、ポートフォリオを作ると思うのですが、**Gatsby.jsでブログを作るのも、すごいよい練習になるのでは？**と思いましたね。

**自作ブログ自体もポートフォリオになりますし、その自分のブログ上で、学んだことをアウトプットしたり、「制作物一覧」みたいなページを作って、そこに自分の作ったアプリを載せるのもアリ**ですよね。

特にフロントエンドを軸に学習している人にとっては、Reactとか、Graphql、Netlifyなんかは頻出のトピックですし、アピールになりそうですね！
【GitLab】Google OAuth2 OmniAuth Providerを使ってアカウント管理を楽にする


社内でGsuiteを使っている環境でGitLabを立てたが、アカウント管理が面倒なので、
Google Oauth2を使って楽に管理することにした。

参考：
https://docs.gitlab.com/ee/integration/google.html

## Google Api側の設定

**プロジェクト作成**
https://console.developers.google.com/apis/

新しいプロジェクトよりOAuth-Web-credentialsを作成
![806a6ae7-5b33-44d1-a1e1-d84e469ad7c6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272635/52ad1184-2d40-f966-352e-42f64d8c93e5.png)


**認証情報を作成**

認証情報を作成 > OauthクライアントIDを選択
![dc10a2a3-f43f-4143-a2e6-4b4dd16e3823.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272635/33b12e45-a3b9-41bf-7043-50e6e07fb94f.png)


ウェブアプリケーションを選択して作成
![5dbd1101-b132-4ad1-9477-eff4ff1173e9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272635/b752fbfe-2a76-d087-4a25-a20d53363cc7.png)


認証情報を以下のように設定
名前：GitLabCE

承認済みの JavaScript 生成元
URI: 
https://gitlab.hoge.net

承認済みのリダイレクト URI
URI: 
https://gitlab.hoge.net/users/auth/google_oauth2/callback
https://gitlab.hoge.net/-/google_api/auth/callback

![d67cb99c-03d9-41a9-bdfe-78bf66ba8522.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272635/55c041fc-5ce4-7a71-e889-f946b2d4e6dd.png)

発行されるクライアントIDとクライアントシークレットは控えておく。

**OAuth同意画面**

組織内で利用するため内部を選択する

![3c616027-3979-436f-b988-49226664bffd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272635/2ed62643-4091-81bb-6b0d-ee7dbb97c167.png)


## GitLab側の設定

/etc/gitlab/gitlab.rbよりOminiAuthを有効にする。

```
### OmniAuth Settings
###! Docs: https://docs.gitlab.com/ee/integration/omniauth.html
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_allow_single_sign_on'] = ['google_oauth2']
gitlab_rails['omniauth_external_providers'] = ['google_oauth2']
#  trueはブロック
gitlab_rails['omniauth_block_auto_created_users'] = false
# gitlab_rails['omniauth_sync_email_from_provider'] = 'saml'
# gitlab_rails['omniauth_sync_profile_from_provider'] = ['saml']
# gitlab_rails['omniauth_sync_profile_attributes'] = ['email']
# gitlab_rails['omniauth_auto_sign_in_with_provider'] = 'saml'
# gitlab_rails['omniauth_block_auto_created_users'] = true
# gitlab_rails['omniauth_auto_link_ldap_user'] = false
# gitlab_rails['omniauth_auto_link_saml_user'] = false
# gitlab_rails['omniauth_allow_bypass_two_factor'] = ['google_oauth2']

gitlab_rails['omniauth_providers'] = [
  {
    "name" => "google_oauth2",
    "app_id" => "XXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com",
    "app_secret" => "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "args" => { "access_type" => "offline", "approval_prompt" => "" }
  }
]
```

設定を有効にする

```
$ gitlab-ctl reconfigure
```

ログイン画面に以下が表示され、Gsuiteのログイン画面にリダイレクトされたらOK
![2ee1d588-1286-444d-99a1-f33465b5bb99.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272635/2e1c50df-3c55-997f-f3f2-b22da3038f1b.png)
rails db:migrateが反映されない

#rails db:migrateが反映されない

CSVファイルをインポートするアプリを作っていたのですが、いざimportを実行しても`
ActiveModel::UnknownAttributeError (unknown attribute 'name' for User.)`
のエラ〜メッセージでできない、、、、、

マイグレーションファイルをちょこちょこ書き換えていたせいで混乱しました。

`rails c`から`User.new`で見てみると、マイグレーションが全くできていないことが判明。
その後、`rails db:migrate`をしても反映されないため、以下のコードを入力して解決しました。

```
./bin/rails db:migrate:reset
```

データベースを削除して作り直し、マイグレーションファイルを古い順から適応してくれるそうです。
【ふくだ学習録】自学自習 part2【48日目】

# ふくだ学習録とは？
ふくだが学習したことの備忘録。
目に見える形で残すことによってやる気を出す個人的な作戦です。
他人に見せるように書いているわけではないので、すごく読みにくいです。

### 読了した本
[データベースエンジニア養成読本 [DBを自由自在に活用するための知識とノウハウ満載!]](https://www.amazon.co.jp/dp/4774158062/ref=cm_sw_r_tw_dp_U_x_FPphEbQFPPQRM )
[ゼロから作るDeepLearning](https://www.amazon.co.jp/dp/4873117585/ref=cm_sw_r_tw_dp_U_x_y3UiEbF3P6EG7)
[PHPフレームワーク CakePHP 3入門](https://www.amazon.co.jp/dp/4798048577/ref=cm_sw_r_tw_dp_U_x_.YIjEbS1K4JY2)
[SQLアンチパターン](https://www.amazon.co.jp/dp/4873115892/ref=cm_sw_r_tw_dp_U_x_XlokEbJQK2N7P )
[Docker入門](https://www.amazon.co.jp/dp/480071091X/ref=cm_sw_r_tw_dp_U_x_xVlmEbN8ZTHZK)
[PHPフレームワーク Laravel入門](https://www.amazon.co.jp/dp/4798052582/ref=cm_sw_r_tw_dp_U_x_zzeyEbJBSQ5Y0 )
[サブスクリプション](https://www.amazon.co.jp/dp/B07HY1TND9/ref=cm_sw_r_tw_dp_U_x_lp4NEb3EEGD7Y)


### 今読んでいる本

なし

# 自学自習

### シンボリックリンクの使い道と落とし穴
各環境ごとに適切な構成にしやすいってメリットがあったんか。なるほどなぁ。

[シンボリックリンクの使い方と落とし穴](https://qiita.com/go_astrayer/items/ab993cdc420d4f7f50d4)

### ALGOLIAとは
全文検索サービス。
[イケてる全文検索サービス「Algolia」を触ってみよう](https://qiita.com/tschy/items/eefbb3a0dc60cd11ab9a)


LaravelでALGOLIAを使用する（APIを通す）には、[algoliasearch-client-php](https://github.com/algolia/algoliasearch-client-php)を使用する。

[Lalavel ScoutでAlgoliaを使って全文検索を実装してみた！](https://qiita.com/maip0902/items/4e8a1af752a993c48aa2)

### Scoutとは
[意外と簡単！Laravel で全文検索をつくる（Laravel Scout + Algolia）](https://blog.capilano-fw.com/?p=3843)

### フロント環境変数の扱い方
初めてこの記事見たけど、めちゃめちゃまとまってる。いい記事。
[dotenvとcross-envで環境変数を設定して開発環境の処理を切り替える](tam-tam.co.jp/tipsnote/program/post17589.html)


# 今日の一言
GWは読書週間にする！
文字コードの変換。nfkない。iconvとtrで代替

似た記事や詳しい記事（詳細リンク）があったのですが、備忘のため記載

#背景
- linuxでファイル処理
- windows用のファイル(sjis)なので内容がわからない
- nkf が未導入（勝手に導入できない）

nkfを導入せずに、iconvとtrコマンドでの変換を代わりに行った。


#やったこと
 - iconvも文字コードを変換（sjis→utf8）
 - trで改行コード削除（windowsの改行コード¥n¥r → ¥n） ¥rを削除
 
```bash:sjis→utf8への変換
　iconv -f SHIFT-JIS -t UTF-8　sjisファイル名 | tr -d ¥¥r > utf8変換後のファイル名
```
#関連リンク
　詳しく記載しています。もっと早く見つけたかった。
　[Linux【 nkf, iconv 】文字＆改行コード変換](https://qiita.com/r18j21/items/78d8501888839b13c770)
 [【 iconv 】コマンド――文字コードを変換する](https://www.atmarkit.co.jp/ait/articles/1609/12/news019.html)
 [【 tr 】コマンド――テキストファイルの文字を置換する／削除する](https://www.atmarkit.co.jp/ait/articles/1610/03/news017.html#sample2)
jqの備忘録

こういうJSONがあった場合

```item.json
{
  "items": [
    {
      "id": 1,
      "name": "Item1",
      "price": 1500
    },
    {
      "id": 2,
      "name": "Item1",
      "price": 1500
    }
  ]
}
```

idとnameだけ出したいとき

```
$ cat item.json | jq '.items | .[] | [.id, .name]'
[
  1,
  "Item1"
]
[
  2,
  "Item1"
]
```

こんなJSONの場合は

```item.json
[
  {
    "id": 1,
    "name": "Item1",
    "price": 1500
  },
  {
    "id": 2,
    "name": "Item1",
    "price": 1500
  }
]

```

```
$ cat item.json | jq '.[] | [.id, .name]'
[
  1,
  "Item1"
]
[
  2,
  "Item1"
]
```
Nimの基本的な書き方を習得する ～ブラックジャックを作る～

Nim言語の学習として、ブラックジャックを作成してみました。
こちらの記事
　[プログラミング入門者からの卒業試験は『ブラックジャック』を開発すべし](https://qiita.com/hirossyi73/items/cf8648c31898216312e5)
がとても良かったので、真似してブラックジャックを作ってみた次第です。

# 作るうえで気を付けたこと
- 公式のマニュアルのみを参照する

こちらの記事
　[ググるのをやめるとプログラムの生産性が上がるかもしれない](https://simplearchitect.hatenablog.com/entry/2018/09/18/080347)
に感銘を受けたこともあり、
主に下記の公式ページのみを参照して、コーディングを進めました。

- Tutorial
    - Part1 : https://nim-lang.org/docs/tut1.html
    - Part2 : https://nim-lang.org/docs/tut2.html
- Documentation  
https://nim-lang.org/documentation.html

# 作成したプログラム
https://github.com/TakumiHANAUE/nim_blackjack
（本記事ではプログラムの解説は割愛します）

# 作ってみた感想
言語の基本的な書き方[（下記）](#（参考）プログラム中で経験できた型／命令など)を習得することができました。
新しい言語の学び始めとして、とても良い課題だと思いました。

# （参考）プログラム中で経験できた型／命令など
- 型
    - int
    - bool
    - range
    - enum
    - string
    - seq
    - tuple
    - Object
- 命令文
    - var
    - const
    - if
    - for
    - while
    - case
    - return
    - break
    - cast
- proc
- method
- import

# （参考）実行結果
```
Welcome to Nim Blackjack !
>>> Initializing
>>> Deal Cards

**** Dealer ****  // ディーラーの最初の手札（1枚は"X"表示で伏せてある）
Score: 4
♥  X
4  X

**** Player01 ****  // プレイヤーの最初の手札
Score: 10
♣ ♥
8 2

>>> Draw Card (Player)  // プレイヤーがカードを引く
> Do you draw an additinal card ? [y/n]  // カードを引くなら y、 もう引かないなら n
y  // もう1枚引くので y を入力

**** Player01 ****
Score: 20
♣ ♥ ♠
8 2 K  // K を引いた
> Do you draw an additinal card ? [y/n]

n  // もう引かないので n を入力。
> Your turn finished
>>> Draw Card (Dealer)  // ディーラーがカードを引く
> Dealer turn a card up

**** Dealer ****
Score: 5
♥ ♥
4 A  // 伏せていたカードを表にした。A だった。
> Dealer draws a card [Press ENTER]


**** Dealer ****
Score: 12
♥ ♥ ♣
4 A 7  // ディーラーが 7 を引いた
> Dealer draws a card [Press ENTER]


**** Dealer ****
Score: 21
♥ ♥ ♣ ♣
4 A 7 9  // ディーラーが 9 を引いた

>>> Judgememt  // 勝敗判定

**** Dealer ****
Score: 21
♥ ♥ ♣ ♣
4 A 7 9

**** Player01 ****
Score: 20
♣ ♥ ♠
8 2 K
> Player01 LOSE !  // 負けた
```
#Vue #Nuxt 初心者向け – Vuex で store を使って、ボタンを押すと数が増えるシンプルなカウンタを作る ( simple counter example )

# NOTE

- Nuxt プロジェクトを作成しておく ( `yarn create nuxt-app my-project` )
- クラシックモードとモジュールモードがあるらしいが、クラシックモードは廃止予定のようなので、モジュールモードを利用する (モードの違いなんていうものは忘れよう)

# store/increments.js

- とてもシンプルな書き方が出来る
- state に状態を定義する
- mutations に変更処理を書く

```js
export const state = () => ({
  count: 1
})

export const mutations = {
  increment (state) {
    state.count++
  },
}
```

# pages/increment.vue

- Vue script の method から store の処理を呼び出している (処理をラップしている感じ)
- computed で値の計算をして、 Vue テンプレートでの `{{ count }}` に紐づけている
- `$store.commit` の引数が `$store.commit('storeのファイル名/storeの関数名)` という形式で対応してるみたいだ

```vue

// https://nuxtjs.org/guide/vuex-store/

<template>
  <div>
    <div>
      <h1> {{ count }} </h1>
      <input type="button" @click="incrementCounter" value="Increment!">
    </div>
  </div>
</template>

<script>

export default {
  computed: {
    count () {
      return this.$store.state.increments.count
    }
  },
  methods: {
    incrementCounter (e) {
      this.$store.commit('increments/increment')
    }
  }
}
</script>

<style>
body {
  text-align: center;
}
</style>


```

- このように component に対しての呼び出しも値の取得も、ラップして書いてやるのが流儀というか、やや迂遠な気もするけれど、こういうものとして覚えておくか
- store の仕組みとは全く関係ないが、この例の場合トップレベルのcomponentなので、export default  っていう名前なのに 別に export してる感はないけど、気にしない ( 根本的に Vue の分かりづらいところだと思うけど... )

# 動作

yarn dev で起動している場合

http://localhost:3000/increment にアクセスしてボタンを押す

![image](https://user-images.githubusercontent.com/13635059/80855662-0f60ee00-8c7e-11ea-9c0b-350db2f16587.png)
![image](https://user-images.githubusercontent.com/13635059/80855663-0ff98480-8c7e-11ea-9d39-f13a6e19c637.png)
![image](https://user-images.githubusercontent.com/13635059/80855664-10921b00-8c7e-11ea-9259-a6252b074376.png)


# 参考

https://nuxtjs.org/guide/vuex-store/

なぜカウンタの例とTODOリストの例が一緒に出てくるのだろうか...

![image](https://user-images.githubusercontent.com/13635059/80855728-84342800-8c7e-11ea-862c-cd223696b080.png)

クラシックモードとかモジュールモードとか state とか mutation とか、書き方に種類があってよくわからないのと、公式ドキュメントも断片的すぎていやはやという感じ


# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3120











<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
AsciiDoc の画像をVSCodeでうまいこと扱う

VSCode の[AsciiDoc extension](https://marketplace.visualstudio.com/items?itemName=joaompinto.asciidoctor-vscode)には、クリップボード上の画像を保存し画像の参照記述を挿入する機能[^1]があります。これを利用することで、画像が多い手順書などをスムーズに作成できます。

具体的には、
1. スクリーンショットを取る
2. 画像を保存する
3. AsciiDoc上に画像の参照記述を記載する

という手順の2,3がショットカットキーひとつで済むようになります。

[^1]: [Paste Image](https://marketplace.visualstudio.com/items?itemName=mushan.vscode-paste-image)という同じ機能を持ったextensionもありますが、画像貼り付けのショートカットキーが同じで競合します。自分の環境では、AsciiDoc extensionが優先されました。



## 基本的な挙動

AsciiDocファイルを編集中にショートカットを実行すると、

* クリップボード上に保存されている画像がファイルとして保存され、
* カーソルの位置に　`image::0-5-2020-13-13-28-PM.png[] ` のように保存された画像を表示するための記述が挿入される


### ショートカットキー


* Macの場合、 `Cmd + Alt + v`
* Winの場合、 `Ctr + Alt + v`


### 画像のファイル名

`d-M-YYYY-HH-mm-ss-A.png` で保存されますが、文字列を選択した状態でショートカットを実行すると、選択した文字列が画像のファイル名になります。


### 画像ファイルの保存場所

通常、編集中のファイルと同じフォルダに画像ファイルは保存されます。
しかし、`imagesdir` attributeを設定している場合、画像はそのフォルダに保存されます。

以下の場合、images フォルダに画像が保存されます。

```:top.adoc
:imagesdir: images

= Title

|
```


## AsciiDocで画像を扱うときの悩ましい所
上記の機能で画像を含むドキュメントの作成はスムーズになりますが、そもそもAsciiDocを複数ファイルに分割管理した場合に、以下の悩ましい問題にぶち当たります。
次のような構造になっているとき、`ABC.png` はどこにおけばいいでしょうか？

```:top.adoc
= Top

include::./partial/A.adoc[]
```

```:partial/A.adoc
== Aについて

image::ABC.png[] 
```

答えは、`top.adoc` と同じフォルダです。そうしないと、`top.adoc` を変換した場合画像が表示されなくなります（include した側のファイルを基準に画像を探しに行きます）。
しかし、この場合 `A.adoc` 単体で参照すると、画像が表示されなくなってしまいます。編集中に画像を含めた確認をしようとした場合、いちいち `top.adoc` からする必要がありかなり不便です。
また、せっかく説明した機能で画像挿入をしようとしても、A.adoc のフォルダに画像が保存されてしまいます。

### 解決方法

いろいろ調べましたが、少しトリッキーな気もしますが以下の方法がベターなのかなと思いました。


1. 画像保存用のフォルダ(images)を用意
2. 各ファイルに imagesdir を設定する。画像フォルダは各ファイルからの相対パスを記述
3. 全体の変換時に imagesdir attributeを設定して変換。画像フォルダはtop.adoc からの相対パスを記述

  ```
  asciidoctor -a imagesdir=images -D build top.adoc
  cp -r images build/images
  ```


### 例

```:ファイル構造
|--top.adoc
|--partial
|  |--A.adoc
|--images
   |--ABC.png

```

```:top.adoc
= Top

include::./partial/A.adoc[]
```

```:partial/A.adoc
:imagesdir: ../images

== Aについて

image::ABC.png[] 
```

この方法だと、説明したExtensionの機能も使いつつ個別のファイルごとで画像込みの確認もできるようになります
(top.adoc をVSCodeのプレビューでみると画像は見えなくなりますが、全体の確認は変換したもので確認するのがいいのかなと。。。)
RubyOnRails備忘録

# RubyOnRails　概要
　railsは[MVCモデル](https://teratail.storage.googleapis.com/uploads/contributed_images/4042f554557abe95724fcdcd9dae51b5.png)と言われ、Model(データベースを操作する役割)、Controller(ブラウザへhtmlファイルを渡す役割)、Views(ウェブサイトを表示させるファイルを作成する役割(htmlなどで記述))を中心としてwebアプリケーションを簡単に作成できるRubyで書かれたパッケージである。
## webサイトを表示する簡単な流れ
1. ユーザーがwebサイトを閲覧するとき、webサイト(アプリケーション)が格納されているサーバーに対してリクエスト(見ようとするページのURL)を送信する。
2. routingがroutes.rbファイルからリクエスト(url)と一致するコントローラー内のアクションを探し出す。
3. アクションに定義した処理を行い、modelを経由してデータベースからデータを引っ張ってくる。
4. アクションまで引っ張ってきたデータを、対応するviewsに渡して、viewsを.html.erbから.htmlファイルへ変換(*1)してブラウザに渡す。 


*1. プリプロセッサ・エンジン
　.erbや.scssや.coffeeなどの拡張子を持っているファイルを変換するエンジン。例えば、example.html.erbなどは.erbのファイルをhtmlファイルへ変換し、ブラウザに渡す際にはexample.htmlのファイルとなる。

## Railsの主要ファイルを作成するコマンド

```console
$ rails generate controller static_pages home help

$ rails destroy controller static_pages home help
```

　1番目のコマンドはコントローラー内にアクションを自動生成までしてくれるコマンドになる。アクション名を自動生成するとルーティングとviewsファイルまで自動で生成してくれるため、非常に便利で手動で作成した場合の名前間違いなどのミスを減らせる。また、コントローラー名まで書いた場合は中身が空のコントローラーが生成される。
　2番目のコマンドはコントローラーを作成した際に、それらの生成したファイルをキャンセルしてくれるコマンド。自動生成した場合、ルーティング内とviewsファイルまでが作成されるため、手動でひとつひとつ削除する面倒な作業を省いてくれる。ただし、アクションやviewsをある程度作成してしまうと、ファイル自体が削除されてしまうため自動生成直後までしか使用できない。
　

## Railsの静的ページの作成手順
　上記で自動生成したファイルを以下の手順を踏むことで、Railsでサイトを作成することができる。
1. routes.rb (ルーティング)
 ↓　urlを書いてそれに対応するアクション名を記述
2. examples_controller.rb (コントローラー)
 ↓　アクション内に変数を定義する
3. examples/example.html.erb (views)
　　htmlでブラウザに表示する内容を記述していく

　Railsでは、主に上記3ファイルを中心に編集していくことで、webアプリケーション(webサイト)を作成していく。

----
1)routes.rb (ルーティング)

```ruby:routes.rb
Rails.application.routes.draw do
  # prefixでのルートパスの指定
  root 'static_pages#home'
  # 名前付ルーティング(as:で指定することでprefixを指定することができる)
  get 'static_pages/help', to:'static_pages#help', as:'help'
end
```
---

2)static_pages_controller.rb (コントローラー)

```ruby:static_pages.rb
class StaticPagesController < ApplicationController

  def home
  end

  def help
  end

end
```

---

3)home.html.erb (views)

```ruby:home.html.erb

<h1>Welcome to the Sample App</h1>

```

---
　以上の流れで静的なページを作成することができる。
[Windows10]キーボードに音量調整ショートカットを割り当てる

# はじめに
キーボードに音量調整用のキーが存在しない場合、音量調整が面倒くさい。音量調整コマンドをキーボードに割り当てて、簡単に調整できるようにする。

# 音量調整コマンドをキーボードに割り当てる
## 1. ショートカットの作成
1. デスクトップで右クリック→新規作成→ショートカットをクリック
2. 「どの項目のショートカットを作成しますか？」で`sndvol.exe -f`と入力し次へ進む
3. 「ショートカットの名前を付けてください」で好きな名前を付ける（Volume）など

## 2. ショートカットキーの割り当て
1. デスクトップに作成したショートカットを右クリック→プロパティをクリック
2. ショートカットキー(k)の項を選択し、割り当てたいショートカット入力する。
3. 適用

# 使い方
2.2で割り当てたショートカットをキーボードから入力することによって、音量調整バーが表示される。マウスホイールなどで簡単に設定できる。
【Swift】Mailcore2を使ってアプリからメールを飛ばす


[Mailcore2](https://github.com/MailCore/mailcore2)を使ってアプリからメールを飛ばすsnippetです。
事前にCocoaPodsかCarthageを使って[インストール](https://github.com/MailCore/mailcore2/blob/master/build-mac/README.md)してください。
データベースはFirebaseを使用しています。

```swift:ViewController.swift
func sendMail(email: String, name: String, orderId: String, orderText: String) {
            
            let smtpSession = MCOSMTPSession()
            smtpSession.hostname = "smtp.gmail.com"
            smtpSession.username = "example@gmail.com"
            smtpSession.password = "password"
            smtpSession.port = 465
            smtpSession.authType = MCOAuthType.saslPlain
            smtpSession.connectionType = MCOConnectionType.TLS
            smtpSession.connectionLogger = {(connectionID, type, data) in
                if data != nil {
                    if let string = NSString(data: data!, encoding: String.Encoding.utf8.rawValue){
                        NSLog("Connectionlogger: \(string)")
                    }
                }
            }
            let builder = MCOMessageBuilder()
            builder.header.to = [MCOAddress(displayName: name, mailbox: email)]
            builder.header.from = MCOAddress(displayName: "〇〇運営", mailbox: "example@gmail.com")
            builder.header.subject = "ご予約完了のお知らせ"
            builder.htmlBody="\(name)さん<br>
            〇〇をご利用いただきありがとうございます。<br>
            下記の〇〇のご予約が完了しました。<br>
            ■ご予約情報<br>
            オーダーID : (orderId)<br>
            受取人：<br>
            オーダー詳細：(orderText)<br>
            ■支払い金額<br>
            商品代金 : ￥ (price)<br>
            --------------------------<br>
            支払い金額 : ￥(price)<br>
            支払い方法 : クレジットカード<br>
            お届けまでしばらくお待ちください。<br>
            通常3日ほどでお届け致します。<br>
            サイトに戻る。<br>
            ※お問い合わせはexample@gmail.comまでお願い致します。"
            
            
            let rfc822Data = builder.data()
            let sendOperation = smtpSession.sendOperation(with: rfc822Data)
            sendOperation?.start { (error) -> Void in
                if (error != nil) {
                    NSLog("Error sending email: \(error)")
                    
                    
                } else {
                    NSLog("Successfully sent email!")
                    
                    
                }
            }
        }

            
        }
```
レコード間で同じフィールド同士の計算をする ｜Power Query

今日たまたま書いたので、残しておきます。

##Power Queryのレコード（record）とは
名前でアクセスできる配列です。個人的には多用しています。
Power Queryにおいては、下図のようにして定義できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/86806953-17ea-d6ba-c88a-64e74b0308db.png)

フィールド値の取り方

```
//簡単な記法。
= [a=10,b=2,c=5][b]　　　　　　　　　　//=2
//関数に入れれば、テキストで指定できる。
= Record.Field( [a=10,b=2,c=5],"a")　//=10
```

なお、一致判定上、順序が考慮されません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/2cc476dd-ed50-0378-415d-cbebcfc4c847.png)


##やりたいこと
フィールド間の計算を直接やってくれる関数はありませんので、自分で書くしかないわけです。
今回は、2つのレコードの差を取ってみます。

##コード
色々やり方はあると思いますが、素直にフィールド名で値を取っていきます。
ちなみに、フィールドに適用する関数を`fx`として抜き出してありますので、ここをいじったり、引数に組み込んでやれば、引き算以外もできます。

```pq:fx_レコード差分
(x as record,y as record) as record=>
let
    FieldNames = Record.FieldNames(x),
    fx = (a,b)=> a-b,
　　//FieldNamesの値を1個ずつ使って計算。アンダーバーの箇所に中身が入ります。
    calculation =List.Transform(
                    FieldNames,
                    each fx(Record.Field(x,_),Record.Field(y,_))
    ),
    Result =Record.FromList(calculation,FieldNames)
in
    Result
```
##適用例
出来上がりのフィールド順序は、1個目の引数に入れたレコードの順番に合わせています。値自体はどちらのレコードも同じなので、差は0になっていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/8a4b3df5-77e5-7318-3465-68a092edfad1.png)

実用的には、レコード列をそのまま計算するのに使えます。この例では`data`列はその日の値、`data0`は前日の値を格納してあり、その差分の計算結果をレコードとして列追加しています。
ここまでくれば、あとはレコード展開などもできます。
※データは架空のものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/a6e51792-6140-7e3d-f7bf-a5d81a75117f.png)

展開後（GUIで可能）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/3dece187-e711-bcbd-7573-794a96bb97c5.png)

##レファレンスなど
[レコード関数 - PowerQuery M | Microsoft Docs](https://docs.microsoft.com/ja-jp/powerquery-m/record-functions)

[ Power Query M 言語仕様 値 レコード](https://docs.microsoft.com/ja-jp/powerquery-m/m-spec-values#record)

[List.Transform - PowerQuery M | Microsoft Docs](https://docs.microsoft.com/ja-jp/powerquery-m/list-transform)
FlutterでHeroアニメーションを実装してみた

### Heroアニメーションとは
Heroアニメーションとは、画面遷移時に同じ画像をサイズ比率を変えるなどのアニメーションを加えることで、シームレスな画面遷移を実現するためのアニメーションです。
例えば、ECサイトにおいて、お店のアイコンが並んでおり、クリックするとアイコンがそのまま大きくなり、詳細説明ページが表示されるような時に利用します。

### サンプル
https://github.com/kiriko-rs/day2_hero

![hero_flutter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526878/729ce92b-281b-c47d-cce5-b125c604a9f9.gif)

### 実装
Hero widgetは呼び出し元と呼び出し先のアイコンと呼び出し先ページのアイコンそれぞれをWrapします。
呼び出し元と呼び出し先の紐付けはtagプロパティにて行っており、それぞれにおいて一致するように実装します。
例のように、Hero widgetを利用する際は引数にtagとpathを持たせることが多いと思います。

```
# 呼び出し元 Hero Widget
class _MyHomePageStaete extends State<MyHomePage> {
.... 省略 ....
          Hero(
            tag: "マクドナルド",
            child: Container(
              height: 100.0,
              width: 100.0,
              decoration: BoxDecoration(
                  image: DecorationImage(
                      image: AssetImage("images/logo.jpg"), fit: BoxFit.fill)),
              child: FlatButton(
                onPressed: () {
                  # Popup widgetを呼び出す。
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => Popup("man", "images/logo.jpg"),
                    ),
                  );
                },
              ),
            ),
          ),
.... 省略 ....
}

class Popup extends StatelessWidget {
  final String tag;
  final String imagePath;
  Popup(this.tag, this.imagePath);
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      body: Center(
        child: Column(
          children: <Widget>[
            Expanded(
              flex: 7,
              child: Hero(
                tag: tag,
                child: Container(
                  height: 400.0,
                  width: 400.0,
                  decoration: BoxDecoration(
                      image: DecorationImage(image: AssetImage(imagePath))),
                  child: FlatButton(
                    onPressed: () {
                      Navigator.pop(context);
                    },
                  ),
                ),
              ),
            ),
            Expanded(
              flex: 3,
              child: Text("This tag is " + tag),
            ),
          ],
        ),
      ),
    );
  }

```
【SQL】 検索基礎

#基本の検索の構文
###1.基本的な検索文の形（SELECT句とFROM句）

```sql
SELECT *
FROM テーブル名
```
FROM句はテーブルを指定。SERECT句はカラムを指定。
＊はワイルドガードSERECT句において、全て取得の意味。


###2.検索条件の指定(WHERE句とAND演算子・OR演算子・NOT演算子)
**WHERE句**

```sql
WHERE 条件
/*WHERE句の条件には比較演算子を使用することができる。*/
WHERE id = 1
WHERE id <= 5
WHERE first_name = "田中"
```

**AND演算子**

```sql
WHERE a AND b
/*ageが22以下かつprefectureが神奈川県のレコードを取得*/
SELECT *
FROM users
WHERE age <= 22 AND prefecture = "神奈川県"
```
**OR演算子**

```sql
WHERE a OR b
/*ageが20以下またはprefectureが東京都であるレコードを取得*/
SELECT *
FROM users
WHERE age <= 20 OR prefecture = "東京都"
```
**NOT演算子**

```sql
WHERE NOT a
/*prefectureが東京都でないレコードを取得*/
SELECT *
FROM users
WHERE NOT prefecture = "東京都"
```



###3.単一カラムの範囲検索

**BETWEEN演算子**
　1つのカラムに対し上限と下限を指定して、その範囲に含まれる値を取得する

```sql
WHERE カラム名 BETWEEN 下限 AND 上限
/*ageが21以上24以下のuserを探す*/
SELECT *
FROM users
WHERE age BETWEEN 21 AND 24
```

###4.単一カラムのリスト検索
**IN演算子**
　1つのカラムに対しリストを指定して、そのリストに含まれる値を取得する

```sql
WHERE カラム名 IN (値1, 値2, ……)
/*prefectureが"東京都"もしくは"神奈川県"であるuserを検索*/
SELECT *
FROM users
WHERE prefecture IN ("東京都", "神奈川県")
```

#検索したデータの形成
###1.データの結合(COUNAT関数)
**COUNAT関数**
　複数の文字列を連結させることが出来る関数

```sql
CONCAT(文字列1, 文字列2, ……)
/*フルネームで取得できる*/
SELECT CONCAT(family_name, first_name)
FROM users
```
###2.結合した値を別のカラムにする(AS句)
**AS句**
　SELECT句で取得したデータを別のカラム名に指定できる。

```sql
SELECT 取得するデータ AS 別名

SELECT CONCAT(family_name, first_name) AS "名前"
FROM users
```
###3.重複する値の除外する(DISTINCTキーワード)
**DISTINCTキーワード**
　DISTINCTキーワードで指定したカラムの値が重複する場合、重複する行を除外してデータを取得する。

```sql
SELECT DISTINCT カラム名
/*2015年7月1日にシフトに入った人の"user_id"を取得*/
SELECT DISTINCT user_id /*DISTINCTキーワード*/
FROM shifts
WHERE date = "2015-07-01"
```

###4.レコードをグループ化する(GROUP BY句)
**GROUP BY句**
　指定したカラムの中で、同じ値を持つデータを1つのグループとしてまとめることで、
そのグループ単位で集計した結果を取得することが出来る。

```sql
GROUP BY カラム名
/*グループ化された一覧の"user_id"のみを表示*/
SELECT user_id
FROM shifts
WHERE date = "2015-07-01"
GROUP BY user_id
```

###5.レコードの数を数える(COUNT関数)
**COUNT関数**
　グループ化されたデータに対して使用することが出来る集計関数

```sql
SELECT COUNT(カラム名)
/*"2015-07-01"に誰が、何コマずつシフトに入ったか取得*/
SELECT
    user_id, 
    COUNT(*) "コマ数"
FROM shifts
WHERE date = "2015-07-01"
GROUP BY user_id
```
カラム名の指定でワイルドカードを使用すると、行の値が全て`NULL`であるレコードも含め、その行数を取得。
AS句でカラム名を"コマ数"に変更。