OmniAICreator/Qiita-1.07M huggingface dataset:
【Vue.js】条件に応じて表示するリストを切り替えるサンプルコード

## はじめに
先日、[こちらの記事](https://qiita.com/terufumi1122/items/5254f69956be600b6af4)を書きました。

ここで登場したコードに追記して、**条件に応じて表示するリストを切り替える方法**について記載します。

## 環境
```yaml
OS: macOS Catalina 10.15.1
Vue: 2.6.10
vue-router: 2.6.10
vuetify: 2.1.0
```
## 結論

```vue:Sample.vue
<template>
  <v-list>
    <v-list-item
      v-for="item in selectedItems"
      :key="item.id"
      @click="triggerClick(item.action)"
    >
      <router-link :to="{ name: item.link }">
        <v-list-item-title>
          {{ item.name }}
        </v-list-item-title>
      </router-link>
    </v-list-item>
  </v-list>
</template>

<script>
  export default {
    data() {
      return {
        selectedPattern: 1, //ここで条件を切り替える
        items: [
          {id: 1, name: '1へのリンク', link: 'Component1', action: '', pattern: 1},
          {id: 2, name: '2へのリンク', link: 'Component2', action: '', pattern: 2},
          {id: 3, name: 'action1を実行', link: '', action: 'action1', pattern: 1},
          {id: 4, name: 'action2を実行', link: '', action: 'action2',  pattern: 2},
        ]
      }
    },
    computed: {
      /* 
       * filterを使って事前にリストを精査しておく
       * patternが1か2かで表示する内容を変更
       */
      selectedItems(){
        return this.items.filter(item => item.pattern === this.selectedPattern)
      }
    },
    methods: {
      triggerClick(action) {
        if (action === 'action1') {
          anyAction1()
        } else if (action === 'action2') {
          anyAction2()
        }
      }
    }
  }
</script>
```

この例では、`selected`を手動で`1`としていますが、
応用として**Vuex**で作成したストアから`state`を呼び出し、それに応じてリストを切り替える、といったようなことも可能になります。

※ログインしないと**ログアウト**を表示しない、など。

## 補足：`v-if`を使わない理由: 効率悪化
今回のパターンでは、つい`v-if`と`v-for`を同時に使えば切り替え出来るのでは？となりがちですが、公式ドキュメントでは**非推奨**となっています。
> v-if と v-for を同時に利用することは 推奨されません。 詳細については スタイルガイド を参照ください。

[スタイルガイド](https://jp.vuejs.org/v2/style-guide/#v-for-%E3%81%A8%E4%B8%80%E7%B7%92%E3%81%AB-v-if-%E3%82%92%E4%BD%BF%E3%81%86%E3%81%AE%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B-%E5%BF%85%E9%A0%88)によると、

`v-if`と`v-for`を同時に使用した場合
> 再レンダリングするたびにリスト全体を繰り返し処理する必要があります。


`computed`プロパティ内で`filter`を使っていた場合
> フィルタリングされたリストは配列に関連する変更があった場合に _のみ_ 再評価されるので、フィルタリングがはるかに効率的になります。

**描画効率が悪くなってしまう**んですね:sweat_smile:

## おわりに
最後まで読んで頂きありがとうございました:bow_tone1:

どなたかの参考になれば幸いです:relaxed:

## 参考にさせて頂いたサイト（いつもありがとうございます）
- [【Vue.js】Vue warn: Error in v-on handler: &quot;TypeError: handler.apply is not a function - Qiita](https://qiita.com/terufumi1122/items/5254f69956be600b6af4)
- [条件付きレンダリング — Vue.js](https://jp.vuejs.org/v2/guide/conditional.html)
sqlldrの実行状況をpvコマンドで監視する方法

# sqlldrについて
Oracleのsqlldrユーティリティはファイルをテーブルにロードするときに使用します
sqlldrは標準出力に以下のような途中経過を出力するので、実行状況を確認することができます
しかし、ロード件数が多い場合は、あとどのくらいの時間でロードが完了するのか把握できません

```
SQL*Loader: Release 12.1.0.2.0 - Production on 木 1月 23 14:36:14 2020

Copyright (c) 1982, 2014, Oracle and/or its affiliates.  All rights reserved.

使用パス:      従来型
コミット・ポイントに達しました。 - 論理レコード件数64
コミット・ポイントに達しました。 - 論理レコード件数128
コミット・ポイントに達しました。 - 論理レコード件数192
コミット・ポイントに達しました。 - 論理レコード件数256
コミット・ポイントに達しました。 - 論理レコード件数320
コミット・ポイントに達しました。 - 論理レコード件数384
コミット・ポイントに達しました。 - 論理レコード件数448
コミット・ポイントに達しました。 - 論理レコード件数512
コミット・ポイントに達しました。 - 論理レコード件数576
```
そこで、Linuxのpvコマンドを利用して実行状況を監視できないかと考えました

# pv コマンドについて
Linuxではpvコマンドが利用できます
pvコマンドはパイプでつながれたコマンドにはさんで実行し、全体のデータ量とパイプを通過したデータ量から現在の状況と完了までの予想時間を表示してくれる便利なツールです

たとえば、大きなファイルをgzipコマンドで圧縮する場合、

```
$ gzip bigfile
```

を実行すると、圧縮されたbigfile.gzができます
しかし、実行中は何のメッセージも出力しないので、いつ終わるのかがわかりません

そこで、pvコマンドを利用して、

```
$ pv bigfile | gzip -c > bigfile.gz
```

を実行すると、

```
$ pv bigfile | gzip -c > bigfile.gz
129MB 0:00:15 [92.8MB/s] [===========>                       ] 36% ETA 0:00:31
```
のように、全体量、経過時間、秒あたりの通過量、現在実行状況（ゲージと％）、残り時間が表示されます

このようにpvは非常に便利ですが、パイプを通過するデータ量を監視するので、パイプでつながれたコマンド形式にしか対応できません

# sqlldrとpvをつなげる
前述のとおり、sqlldrは現在、何件ロードしたかを標準出力に書き出しています
この件数の部分だけをとりだして、pvにパイプで渡すことができれば、何とかなりそうです

実行状況がわかればいいので、ロードするバイト数ではなく、レコード件数で十分です
そこで、簡単なawkを実行するシェルスクリプト作成し、sqlldrの標準出力を読み取り、件数に相当する文字数を出力するようにしてみます

```bash:loadcount
#!/bin/bash
awk -F'件数' '
BEGIN { SV = 0; }
NF==2{
    for (i = 0; i < $2 - SV; i++) {
        printf("1");
    }
    SV = $2;
}'
```

このスクリプトは実行可能にする必要があるので、エディタで保存後に実行権を与えます

```
$ chmod +x loadcount
```

処理内容は以下の通りです
・「件数」という文字列を区切りとして、フィールド数（NF）が２のとき（＝ｘｘｘ件数ｙｙｙとなっているとき）の「件数」の
後ろの文字列を取り出します（$2）
・前回取り出した件数との差分の数だけ「1」という１バイトの文字を出力しています
  つまり、sqlldrが1000レコードロードすると、「1」が1000個出力されます

pvコマンドは入力がパイプの場合、全体量がわからないので、その場合は-sオプションで全体量を指定することができます
この場合の全体量はロード対象ファイルのレコード件数になります
レコード件数（行数）はwcコマンドを使って得ることができます

```
$ wc -l ファイル名
```

最終形は以下のようになります

```
$ sqlldr USER/PASS@SID control=t1.ctl | ./loadcount | pv -p -t -e -s `cat t1.csv|wc -l` > /dev/null
0:00:20 [========>                                            ] 17% ETA 0:01:33
```

・USER/PASS＠SIDはOracleに接続するための記述子です
・t1.ctlはsqlldrの入力制御ファイルです
・t1.csvはロード対象のデータファイルです

うまくsqlldrの実行状況監視をすることができました
カレンダーと第何週目かをOracle Databaseで取得する方法

## やりたいこと
対象の日付が、その月の第何週目にあるのかを出したい。(週の開始は日曜日とする)
2019年12月で例えると、イメージは以下。
![無題001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404417/4836923b-5312-06ae-37d4-c6ec80d2e50a.png)


## 必要になった背景
週ごとに値を集計するSQLを書くことになり、調べてもto_charの'w'でその日付が第何○曜日であるかの求め方しか出てこなかったので、備忘録として投稿。

## 結論
ロジックやSQLだけ知りたい人向けに、先に結論を書いておきます。
### 式
```
(対象日付 + 月初日付の曜日番号 - 1 + 6 ) ÷ 7
```
### SQLサンプル
```
SELECT
  TRUNC((TO_NUMBER(TO_CHAR(TO_DATE('2020/01/01', 'YYYY/MM/DD'),'DD')) + TO_NUMBER(TO_CHAR(TRUNC(TO_DATE('2020/01/01', 'YYYY/MM/DD'),'MONTH'),'D')) - 1 + 6) / 7,0) as week
 FROM
   DUAL
```

## 具体的な方法
まずは、月初めの曜日を気にせずに、その日付が第何週にあるかを7で割った商で求めます。
第1周目は1と出すため、日付に6を足します。
(7日に7を足して14にすると2になってしまうので、6を足します)

例）
x月1日 + 6 / 7 ＝ 1 (あまり0)
x月2日 + 6 / 7 ＝ 1 (あまり1)
x月3日 + 6 / 7 ＝ 1 (あまり2)
x月4日 + 6 / 7 ＝ 1 (あまり3)
x月5日 + 6 / 7 ＝ 1 (あまり4)
x月6日 + 6 / 7 ＝ 1 (あまり5)
x月7日 + 6 / 7 ＝ 1 (あまり6)

ここまでで、以下の式が完成します。
`(対象日付 + 6) ÷ 7`

次に、その月の開始曜日を求めます。
カレンダーは必ず日曜日で始まってくれるわけではないので、考慮する必要があります。。。

そこで、開始日付の曜日番号を取得します。
※Oracleでは、曜日番号はto_charの'D'で取得できます。

各曜日番号は以下の通りです。

| 番号 | 曜日 |
|-----:|-----:|
|1|日曜日|
|2|月曜日|
|3|火曜日|
|4|水曜日|
|5|木曜日|
|6|金曜日|
|7|土曜日|

2020年1月を例に挙げると、以下のようにします。
![無題002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404417/ac0c045f-d843-1b80-2b4d-de2ee9083446.png)

日曜日から開始曜日までの差分を求めます。
2020年1月は開始曜日が水曜日で、日曜日から3日経っているので先程の式の対象日付のあとに`曜日番号 - 1`を加えます。
`(対象日付 + 曜日番号 - 1 + 6) ÷ 7`

これで式が完成しました。
試しに2020/01/01を対象日付にすると、以下のようになります。
`(1 + 4 - 1 + 6) ÷ 7 = 1週目`

## SQLでカレンダーを表示しその日付に対応する週番号を表示する
これまでの考え方を使用して、2020/01/01～2020/01/31の日付と週番号を求めるサンプルは以下のようになります。

### SQLサンプル
```
SELECT
  TRUNC(TO_DATE('2020/01/01', 'YYYY/MM/DD'),'MONTH') + ROWNUM - 1 as ac_date,
  TRUNC((TO_NUMBER(TO_CHAR(TRUNC(TO_DATE('2020/01/01', 'YYYY/MM/DD'),'MONTH') + ROWNUM - 1,'DD')) + TO_NUMBER(TO_CHAR(TRUNC(TO_DATE('2020/01/01', 'YYYY/MM/DD'),'MONTH'),'D')) - 1 + 6) / 7,0) as week
 FROM
   ALL_CATALOG
 WHERE
   TRUNC(TO_DATE('2020/01/01', 'YYYY/MM/DD'),'MONTH') + ROWNUM - 1 <= LAST_DAY(TO_DATE('2020/01/01', 'YYYY/MM/DD'))
```

### 実行結果
```
AC_DATE        WEEK
-------- ----------
20-01-01          1
20-01-02          1
20-01-03          1
20-01-04          1
20-01-05          2
20-01-06          2
20-01-07          2
20-01-08          2
20-01-09          2
20-01-10          2
20-01-11          2
20-01-12          3
20-01-13          3
20-01-14          3
20-01-15          3
20-01-16          3
20-01-17          3
20-01-18          3
20-01-19          4
20-01-20          4
20-01-21          4
20-01-22          4
20-01-23          4
20-01-24          4
20-01-25          4
20-01-26          5
20-01-27          5
20-01-28          5
20-01-29          5
20-01-30          5
20-01-31          5

31行が選択されました。
```
【AWS】S3へのデータアップロード

```
aws s3 cp uploadFileName s3://bucketName/
```

▼403になったらアクセス権限を確認
https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-troubleshoot-403/

・private
・public-read
・public-read-write
・authenticated-read
・bucket-owner-read
・bucket-owner-full-control
・log-delivery-write

```
aws s3 cp uploadFileName s3://bucketName/ --acl public-read
```

ただし、public-readにすると全世界からアクセス可能になるので注意
【rails】ユーザー 登録時にnameカラムに自動的に@を付ける方法

#はじめに
初学者がポートフォリオ作成でハマったことをメモします。
TiwtterのアカウントIDのように特定のカラムの最初に@を付ける方法です。ホートフォリオ作成時にユーザーの名前やアカウントIDの最初に@を付けたいという方は多いと思います。
初歩的な内容すぎて調べてもそのような記事がすぐ見つからなかったので残しておきます。

##結論
~~`before_save`をmodelに設定する。~~

上記の方法ではログイン、ログアウトの際もbefore_saveが実行されてしまいログインする度に@が増えてしまう為他の方法で実装した。(特定のコントローラーでのみbefore_saveを実行する方法がわからなかった。)


##コードと説明
今回Userモデルのaccount_nameカラムに@を付けたい

```ruby:controllers/users_controller.rb
def create
  @user = User.new(user_params)
  @user.account_name = "@" + @user.account_name  #ここで@を付ける
  if @user.save                                       
    @user.send_activation_email                     
    flash[:info] = "メールを確認してアカウントを有効化して下さい"
    redirect_to root_url
  else
    render "new"
  end
end

def update
  @user = User.find(params[:id])
  if @user.update_attributes(user_params)
　　　@user.account_name = "@" + @user.account_name
     @user.save
    flash[:success] = "プロフィールを編集しました"
    redirect_to @user
  else
    render 'edit'
  end
    
end

 def edit
    @user = User.find(params[:id])
    @account_name = @user.account_name
    @account_name.slice!(0) 
    @account_name
  end
```

```views/users/edit.html.slim
= form_with model:@user, local:true do |f| 
 = f.label :account_name, 'アカウントID'
        .input-group
          .input-group-prepend
            .input-group-text @
          = f.text_field :account_name, class: 'form-control' , placeholder: "9文字まで", value: @account_name
```

formから送られてきた値を保存する前に加工する。
またプロフィール編集ページでフォームに初期値をセットする際、@を除いた値を入れる必要がある。
そこでコントローラーのeditアクション内でsliceメソッドを使用して@を削除した。
その変数をformのvalue属性で初期値としてセットした。

コールバック処理について
http://www.techscore.com/blog/2012/12/25/rails%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%AF%E3%81%BE%E3%81%A8%E3%82%81/

sliceメソッドについて
http://doc.code161.com/ruby/string-delete-method/


<br>
参考までにnewテンプレートのコードです。

```ruby:views/users/new.html.slim
#slim,bootstrap使用
= form_with model: @user, local: true do |f|
（中略）
  = f.label :account_name, 'アカウントID'
    .input-group
      .input-group-prepend
        .input-group-text @
          = f.text_field :account_name, class: 'form-control' , placeholder: "9文字まで" 
```
<img width="900" alt="スクリーンショット 2020-01-23 18.52.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370948/c7803991-3ee8-5b61-91e5-50623179c635.png">

#終わりに
誰かのお役に立てれば幸いです。
もっとスマートなやり方があれば教えてください。
また間違えている部分があればコメントお願い致します。

参考にした記事
https://qiita.com/KeisukeYoshida0220/items/e1ce152ac8d89845aab3
運用/保守の手間を減らした話

## 前提
作業端末はWindows。運用/保守対象はUnix系サーバが数十台。
このUnix系サーバで必要なデータをCSV形式で生成し、Windows上でゴニョゴニョするのが目的。
以下言語はksh93とPython

## 当時の状況
各サーバにログインしてコマンド叩いてテキストでデータ取ってた。
こんな非効率的なことはありえない。
改良してやる！

## 改良
### 第一手
各Unix系サーバ上に、必要なデータをCSV化するスクリプト(以下moge.sh)をばらまく。
これで1台あたり数分まで短縮。
数十台でスクリプト実行してからFilezilla等で取ってくる。それからWindowsでゴニョゴニョする。
まだ面倒。

### 第2手
どこか1台のサーバで全サーバのスクリプト起動できるようにして、ついでにコピーもしよう。
こんな感じ

``` ksh:kicker.ksh
cat servers.list | while read HOST ; do
    ssh ${HOST} -n /hoge/moge.sh
    scp ${HOST}:/hoge/moge.csv ./data/${HOST}.csv
done
```

終わったら1台から全CSVをFilezilla等で取ってくる。
でも**直列**だからスクリプトが終わるまで**1時間位**かかる。

### 第3手
sshが遅いんだからこいつをバックグラウンドにしたらいいじゃん。
つーわけでこんな感じ

``` ksh:kicker2.ksh
cat servers.list | while read HOST ; do
    ssh ${HOST} /hoge/moge.sh &
    PID[${HOST}]=$!
done

while [[ ${#PID[*]} -ne 0 ]] ; do
    for HOST in ${!PID[*]} ; do
        if ! ps -ef | grep -w ${PID[${HOST}]} ; then
            scp ${HOST}:/hoge/moge.csv ./data/${HOST}.csv
            unset PID[${LPAR}]
        fi
    done
    sleep 1
done
```
数分で終わるようになったけど、結局WindowsからFilezilla的なものが面倒。

### 第4手
CSVをゴニョゴニョするのにexcel作れるPythonが都合がいいってことで言語決定。
※自分がお勉強したかったからという理由も当然ある。
こんな感じ

``` python:kicker3.py

with open("server.lst", "r", encoding='shift-jis') as fd:
    for host in fd:
        proc = subprocess.Popen(["ssh", host, "/hoge/moge.sh"], stdout=DEVNULL, stderr=DEVNULL)
        proclist[proc.pid] = proc

while proclist:
    for pid in list(proclist):
        if proclist[pid].poll() is not None:
            del proc[pid]
            subprocess.Popen(["scp", host + ":/hoge/moge.csv", "./" + host + ".csv"], stdout=DEVNULL, stderr=DEVNULL)
    sleep(1)
```

WSLだと動く、でもコマンドプロンプト向けにすると**途中で止まる**。server.listの中身を少なくする(5～6個まで)なら動く。
なんで？

### 第4手延長戦
全くわからなかったので、取り敢えずPythonのasyncioで非同期実行させたほうが
いいかもしれない。ということで研究開始。
紆余曲折を経てこんな感じ。

``` python:kicker4.py
async def _run(host):
    ssh = "ssh %s /hoge/moge.sh" % host
    p = await asyncio.create_subprocess_exec(ssh, stdout=DEVNULL, stderr=DEVNULL)
    await p.wait()
    scp = ["scp", host + ":/hoge/moge.csv", "./" + host + "%s.csv"]
    p = subprocess.run(scp, stdoutDEVNULL, stderr=DEVNULL)

loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)

with open("server.lst", "r", encoding='shift-jis') as fd:
    funcs = asyncio.gather(*[_run(host) for host in fd])

loop.run_until_complete(funcs)
```

これまた動かない。全く事象は変わらない。
ここで気づいたこと。**止まったときに*Enter*を叩くと動く**。
なんで？
標準入力がなにか問題？

## 解決
最初のkshのスクリプトに正解が書いてあります。
sshの**"-n"オプション**が原因です。
kshではreadとsshが標準入力を食い合うから"-n"が必要だと思っていたので、
最初からつけていました。ところがPythonはssh以外に標準入力を食うやつが
いないので、何もしないでもいいだろうという先入観が問題だったようです。
バックグラウンドで複数のsshを起動するにあたり、標準入力は制御が必要なようです。
(`stdin=subprocess.DEVNULL`は駄目でした)
WSLで動いたのはまだ謎のままですが、もう使わないので調査しません。

### なぜWSLを使わなくしたのか
Pythonスクリプトの中で、Windowsでゴニョゴニョのためにopenpyxlも使っています。
これがWSL上だと時々BSODを食らわしてくれるので、コマンドプロンプトから動く
ように改修しました。

## 素朴な疑問
なんでsubprocessってコマンドの与え方が複数あるんだろう？統一したらいいのに。
webpackとは　

# この記事について
webpackとは何かという概念を理解することを目的としています。

# 記事のサマリ

#### webpackとは、
- モジュール管理システム（モジュールバンドラー）

#### モジュール管理システムとは、
- プログラムはモジュールの集まりでできており、そのモジュールの構成や依存関係を管理する。
- プログラム(機能)がどう構成されているかを先にざっくりイメージできると、理解しやすい。

#### モジュールとは、
（とりあえずここでは、）ファイルと同義で扱います。sample.jsや、sample.docxのような拡張子のついたもの。

---

# 1. プログラム（機能）の中身
- 一つのプログラム（機能）を実行した時の処理量が多かった場合、そのプログラム（機能）が一つのjsファイルだけで構成されていては、そのjsファイルは何千行、何万行にもなってしまうかもしれない。
- 多くの処理が一つのjsファイルに記述されていては、作るのも修正するのも大変。
- 処理は上に書かれたコードから順番に実行されていくので、一つのjsファイルに全部の処理を記述するのでは実現できる処理も限られてくる。

#### プログラム（機能）は複数のモジュールから構成されている
- プログラム（機能）を作成する際には処理内容ごとに複数のモジュールを作成する。
- それらのjsファイルは必要な時に適宜呼び出され実行される必要がある。

#### モジュールの構成や依存関係をモジュール管理システムが管理
- どのjsファイルを・いつ・どのjsファイルと一緒に（等々）実行するか決めておく必要がある。

# 2. webpackのインストール方法
#### 方法１　ディストリビューション公式パッケージマネージャ経由でインストール
 - Linux環境の場合、ディストリビューションがパッケージを提供している場合がある。

#### 方法２　npm経由でインストール
- webpackはJAvaScriptで実装されているので、Node.jsのパッケージマネージャであるnpm経由でもインストールできる。

#### 導入方法や実際の利用例などは、
[【さくらのナレッジ】面倒なJavaScriptコードのとりまとめがこれ1つで可能に、「webpack」入門](https://knowledge.sakura.ad.jp/21623/)
こちらの記事の解説がとってもわかりやすいです。

# 参考
[【さくらのナレッジ】面倒なJavaScriptコードのとりまとめがこれ1つで可能に、「webpack」入門](https://knowledge.sakura.ad.jp/21623/)
appiumをiOSの実機で使うまでの手順・方法

appiumをiOSの実機で動かすまでの手順です。

### 使用環境

使用環境は以下の通りです。
Xcode, command line toolsはインストール済とします。

Mac OS Catalina(10.15.2)
Xcode 11.2.1
appium v1.15.1


### Appiumのダウンロード

公式サイトより環境にあった物をDLする。
 http://appium.io/

### Appium側の設定

ダウンロードしたら起動をし、Start Serverをクリック

<img width="762" alt="スクリーンショット 2020-01-23 13.04.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64331/529a9772-a408-0aec-b024-e6311ce4314a.png">

Start Serverをクリックするとログが出る画面になるので虫眼鏡ボタンをクリック

<img width="692" alt="スクリーンショット 2020-01-23 13.05.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64331/59679b80-d828-f46e-989d-7b522a6a7cb0.png">

<img width="1298" alt="スクリーンショット 2020-01-23 10.19.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64331/e7d079c2-5b35-f677-2124-a5b2fa0b0bbd.png">

Automatic Server(1)を選択し、以下のJSONを(3)のところから入力入力し保存する。(JSONを入力する画面にも保存ボタンがあるので注意)

１度保存した設定は Saved Capability Sets(2)からロードが可能です。

```JSON
{
  "deviceName": "iPhone",
  "udid": "hogehogehogehoge",
  "platformName": "iOS",
  "automationName": "XCUITest",
  "useSimpleBuildTest": false,
  "platformVersion": "13.3",
  "bundleId": "hogehoge.hoge.hoge",
  "xcodeSigningId": "iPhone Developer",
  "xcodeOrgId": "hogehogehogehoge"
}
```

重要なのはudid、xcodeOrgIdになります。
udidはXcodeのdeviceからxcodeOrgIdはdeveloper.appleから自身のteam IDを入力します。
bundleIdを入力したアプリを起動します。
また変更した際はsaveをするのを忘れずに。


### あとは実行
右下のStart Session(4)を押せば完了！！


### うまくいかない場合に確認する箇所

・xcodeOrgIdで入力したteam IDでXcodeで設定からログインできているか
・deriverd dataを削除してみる
IntelliJ IDEAでSubversionを使えるようにしてみる

IntelliJ IDEA Ultimate を日本語化して、ライセンスを購入して、早速Subversionからソースを取得して使い始めようとしたところ次のようなエラーが表示されて取得できませんでした。

```
Cannot run program "svn" (in directory "～"): CreateProcess error=2, 指定されたファイルが見つかりません。
```

こちらのサイトを見ると、自分でsvnのコマンドラインクライアントをインストールする必要があるとのこと。
https://pleiades.io/help/idea/using-subversion-integration.html


# 環境

- Windows 10 Pro
- IntelliJ IDEA Ultimate 2019.3

# 手順

今回はコマンドラインクライアントに「VISUALSVN」を使用します。

1. こちらのサイトから「Apache Subversion command line tools」をダウンロードします。  
    https://www.visualsvn.com/downloads/

2. ダウンロードしたファイルを展開して、任意のディレクトリに配置します。

3. 「IntelliJ IDEA」を起動して次の通り選択していきます。
    「IntelliJ IDEA へようこそ」画面の＜編成＞→＜設定＞を選択。
    「新規プロジェクトの設定」画面の左メニューから＜バージョン管理＞→＜Subversion＞を選択。
4. 画面上部のファイル選択ボックスに2.でダウンロードしたファイルに含まれるsvn.exeへのパスを指定して＜OK＞をクリックします。（初期値はsvnとなっていると思います）

これでリポジトリから取得できるようになっているはずです。

以上です。
GoにてRedirectの注意点(初心者向け)(Echo)

#リダイレクトで困った事が起きました

特定のページにリダイレクトする時に、1度目のリダイレクトは成功するが、2回目以降実行しても正しく実行してくれない。

```go
func hoge(c echo.Context)error{
//省略
  return c.Redirect(http.StatusMovedPermanently, "/")
}
```
これはルートパスにリダイレクトしてくれというコードですね
この**StatusMovedPermanetly**というやつにやられました

どうやら**Chormeブラウザ**にて **GET**アクションで**StatusMovedPermanetly**を実行するとブラウザにキャッシュが溜まるらしいです。(要するに2回目以降動かない)

これを解決するには

```go
func hoge(c echo.Context)error{
//省略
  return c.Redirect(http.StatusFound, "/")
}
```
**StatusMovedPermanetly**を**StatusFound**に変更してやれば大丈夫です。

これで僕は半日潰れました
terraformで単一アカウントのECRを複数アカウントでアクセスさせる

# overview

複数アカウントが前提なAWSで、個人的にはECRは一つのアカウントに集約したほうが管理しやすいです。

その集約したECRに対して、各アカウントに権限を与えるような設定を施します。

# コード

#### tree

```sh
$ tree ecr/
ecr/
├── main.tf
└── variables.tf
```

#### variables.tf

```hcl
variable "ecr_repositories" {
  type = list(string)

  default = [
    "hoge", // https://github.com/xxxxx/hoge
    "fuga", // https://github.com/xxxxx/fuga
  ]
}
```

#### main.tf

```hcl
/* ECRは1箇所に集約したほうが管理しやすいので、operationアカウントのみに作成します */
resource "aws_ecr_repository" "this" {
  # countでやると、listの中間削除すると全部作り直しになる
  # ので0.12から入ったfor_eachを入れると、問題なくなる
  # https://github.com/hashicorp/terraform/issues/10850
  for_each = toset(var.ecr_repositories)
  name     = each.value

  image_scanning_configuration {
    scan_on_push = true
  }
}

resource "aws_ecr_repository_policy" "this" {
  for_each   = toset(var.ecr_repositories)
  repository = aws_ecr_repository.this[each.value].name

  # もしアカウントが追加されたら、arn:aws:iamを追加してね
  policy = data.aws_iam_policy_document.this.json
}

/* クロスアカウントにECRの操作権限を与えるポリシー */
data "aws_iam_policy_document" "this" {
  statement {
    effect = "Allow"

    principals {
      type = "AWS"

      identifiers = [
        "arn:aws:iam::${var.AWS_ACCOUNT_自分自身のアカウントID}:root",
        "arn:aws:iam::${var.AWS_ACCOUNT_権限を与えたいアカウントID}:root",
        "arn:aws:iam::${var.AWS_ACCOUNT_権限を与えたいアカウントID}:root",
      ]
    }

    # Delete以外を与える
    actions = [
      "ecr:GetAuthorizationToken",
      "ecr:BatchGetImage",
      "ecr:BatchCheckLayerAvailability",
      "ecr:GetDownloadUrlForLayer",
      "ecr:InitiateLayerUpload",
      "ecr:CompleteLayerUpload",
      "ecr:UploadLayerPart",
      "ecr:DescribeImages",
      "ecr:PutImage",
      "ecr:DescribeRepositories",
      "ecr:GetRepositoryPolicy",
      "ecr:ListImages",
      "ecr:BatchDeleteImage",
    ]
  }
}

# untagged な イメージについては 1日で削除する
resource "aws_ecr_lifecycle_policy" "this" {
  for_each   = toset(var.ecr_repositories)
  repository = aws_ecr_repository.this[each.value].name

  policy = <<EOF
{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Expire images older than 1 days",
      "selection": {
          "tagStatus": "untagged",
          "countType": "sinceImagePushed",
          "countUnit": "days",
          "countNumber": 1
      },
      "action": {
          "type": "expire"
      }
    }
  ]
}
EOF
}
```


# ポイント

```hcl
for_each = toset(var.ecr_repositories)
```
コメントにも書いてますが、countでやると、listの中間削除すると全部作り直しになる
のでterraform v0.12 から入ったfor_eachを入れると、問題なくなります。
ref: https://github.com/hashicorp/terraform/issues/10850

untaggedなイメージは削除して良いとして、それ以外のライフサイクルはruleで定義するのは難しそうだったので、Goなどでlifecycleツールを作ってcronで毎日動かす想定をしてます。

なのでまた、アカウントに対してdelete権限は与えてません。
mockReturnValue()とmockResolvedValue()


mockReturnValue()とmockResolvedValue()で勘違いしていたことがあったので書いておく

```
// モックがPromise<void>を返すようにしておく
mockfn.mockReturnValue(Promise.resolve());
```

mockfnがrejectを返すケースを確認したいと思い以下のようにした
`mockfn.mockRejectedValueOnce();`

ここで勘違いしていて、
mockRejectedValueOnce()は一度呼ぶ時にデフォルトで設定しているほうではなく、こちらのモックの結果を優先してくれると思っていた

実際は、
`mockReturnValue()`は`mockReturnValueOnce()`で、
`mockResolvedValue()` `mockRejectedValue()` は `mockResolvedValueOnce()` `mockRejectedValueOnce()`で
一度呼んだ時にOnceで設定している値を返して、そのあとはデフォルトを返すようになる
デフォルトで返すのが`mockReturnValue()`のときは、一度呼んだときに返すものを設定するのは`mockReturnValueOnce()`でないとできない

こんな感じ

```
const mockfn = jest.fn();
mockfn.mockReturnValue(1);
mockfn.mockReturnValueOnce(2);

mockfn() // 2
mockfn() // 1

mockfn.mockResolvedValue(1);
mockfn.mockResolvedValueOnce(2);

await mockfn() // 2
await mockfn() // 1

mockfn.mockReturnValue(Promise.resolve(1));
mockfn.mockResolvedValueOnce(2);

await mockfn() // 1
await mockfn() // 1
```

そもそもなぜ`mockReturnValue`と`mockResolvedValue`を混在しようとしたのかと過去の自分になんで？？と思ったけれど
こういう仕組みになっているんだということがわかってよかった

どうしても`mockReturnValue`にしていたものを`mockResolvedValue`にしたい場合は`mockfn.mockReset()`を使って`mockfn.mock`を置き換えるようにする
GoogleChromeがUAを廃止する予定なので試してみた

# GoogleChromeがUAを廃止するらしい
- [Intent to Deprecate and Freeze: The User-Agent string](https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/-2JIRNMWJ7s/yHe4tQNLCgAJ) - Googleグループ
- [ユーザーエージェント（UA）文字列は時代遅れ？ ～「Google Chrome」で凍結・非推奨に](https://forest.watch.impress.co.jp/docs/serial/yajiuma/1229968.html) - 窓の杜
- [GoogleはChromeでユーザーエージェント文字列を段階的に廃止する方針](https://gigazine.net/news/20200115-chrome-phase-out-user-agent-strings/) - GIGAZINE

#実際にUAからバージョン情報などを消して試してみた。
User-Agent SwitcherなどのUA偽装機能を使って既存の判定スクリプトと勘案してなるべく情報を削ってみる
##環境は以下の通り
 - Windows10 Pro 1909 (Build 18363.592) 64Bit
 - GoogleChrome 79.0.3945.130 (Stable) 2020/01/23現在

```text:User-Agent
Mozilla/5.0 (Windows NT 10.0; x64) AppleWebKit/Blink Chrome/Stable
```

##各種サイトの表示に相違がないか確かめる
- ポイント: 偽装前後で表示が大きく変化するか

| サイト名(URL) | UA偽装で表示できたか | 備考 |
|:----|:----:|:----:|
| Google検索 (www\.google\.com) | NG | 旧バージョンで表示される |
| Yahoo!検索 (www\.yahoo\.co\.jp)| NG | 簡易表示となる |
| Twitter (twitter\.com) | NG | モバイル版にリダイレクトする |
| 阿部寛のHP (abehiroshi\.la\.coocan\.jp) | OK | ~~IE6でも大丈夫じゃないかな~~ |
| ２ちゃんねる (2ch\.sc) | OK | 元祖 |
| Gigazine (gigazine\.net) | OK |  |
| 週刊アスキー (weekly\.ascii\.jp) | OK |  |

#まとめ
検索サイトを中心としたUAでサービスを切り替えるところは軒並みエラーとなって非対応ブラウザと同じ処理をしているっぽい。また、Google各サービスはほぼ問題なく利用できた。
User-Agentの代替としてUA-CH (User-Agent Client Hints)というAPIが策定中でこれが実装されたなら結果は違うのだろう。
2020年中にはUA文字列が有名無実となるので、それまでには対策がされているのだろうか
Auth0を使ってPython/Flaskで手軽に多機能なログイン/ログアウトを実現する　修正

# 参考サイト
Auth0を使ってPython/Flaskで手軽に多機能なログイン/ログアウトを実現する
https://blanktar.jp/blog/2017/11/python-flask-auth0.html

上記サイトに一部、動かない部分があったので修正した。
# 修正箇所
```
from jwt.algorithms import RSAAlgorithm

@app.route('/callback')
def auth_callback():
	# Auth0がくれた情報を取得する。
	resp = auth0.authorized_response()
	if resp is None:
		return 'nothing data', 403

	# 署名をチェックするための情報を取得してくる。
	jwks = json.loads(urllib.request.urlopen("https://"+AUTH0_DOMAIN+"/.well-known/jwks.json").read())
	
    # JWT形式のデータを復号して、ユーザーについての情報を得る。
	# ついでに、署名が正しいかどうか検証している。
	try:
		payload = jwt.decode(resp['id_token'], RSAAlgorithm.from_jwk( json.dumps(jwks['keys'][0])), audience=AUTH0_CLIENT_ID, algorithms='RS256')
	except Exception as e:
		print(e)
		return 'something wrong', 403  # 署名がおかしい。

	# flaskのSessionを使ってcookieにユーザーデータを保存。
	flask.session['profile'] = {
		'id': payload['sub'],
		'name': payload['name'],
		'picture': payload['picture'],
	}

	# マイページに飛ばす。
	return flask.redirect(flask.url_for('mypage'))
```
redashのグラフ化でハマる

# 現象
redashを使って、下記のsqlである数を日毎に集計した折れ線グラフを作ろうとしたら、なぜかグラフがうまく作れませんでした。

```sql
SELECT date_format(datetime, '%y/%m/%d') AS date,
       count(id) AS count
FROM sample
GROUP BY date;
```

# 解決
日付のフォーマットの`%y/%m/%d`を`%y-%m-%d`に修正したらきちんとグラフ化されました:clap:
mysqlの日付の形式が'2015-07-21'、'20150721'、20150721のようにしないと日付として認識されないからでしたー
[日付リテラルと時間リテラル](https://dev.mysql.com/doc/refman/5.6/ja/date-and-time-literals.html)

```sql
SELECT date_format(datetime, '%y-%m-%d') AS date,
       count(id) AS count
FROM sample
GROUP BY date;
```
PyKNPでJUMAN++を使ったらValueErrorが出た

## エラー内容
PyKNPからJuman++を使って日本語文を形態素分解しようとしたらこんなエラーが...！
`ValueError: invalid literal for int() with base 10: 'input'`
(PythonからJuman, Juman++を使う方法は省略)

```shell
  File "/$HOME/.pyenv/versions/anaconda3-2019.03/lib/python3.6/site-packages/pyknp/
juman/morpheme.py", line 143, in _parse_spec                                                   
    self.hinsi_id = int(parts[4])

ValueError: invalid literal for int() with base 10: 'input'

```

### エラーの原因候補
とりあえずエラーメッセージを元に調べてみると

- [JUMANをPyKNPから使う際に気をつけたい記号](https://qiita.com/NLPingu/items/3cd77eb2421283b851b4)
- [JUMAN++で遊んでる時にValueErrorが出ちゃう原因と対策の話 --EnsekiTT Blog](https://ensekitt.hatenablog.com/entry/juman)

半角スペースとか、半角文字が悪さをしてしまう模様。
### 入力テキストの修正

- [【Python】一行で全角と半角を相互変換する（英字＋数字＋記号）](https://qiita.com/YuukiMiyoshi/items/6ce77bf402a29a99f1bf)

ということで半角文字を全部全角文字に置き換えます。

### しかし
半角文字を全部全角文字、修正しても同じエラーが出続けた。
どうやら上記記事の状況とは原因が違うらしい。

## 原因判明
### 関係ないけどpdbって便利よね
そこでpdbで実行し、エラー時の変数`parts`の中身をチェックしてみた~~最初からそうしろ~~。

```shell
(Pdb) parts
['InvalidParameter:', 'byte', 'size', 'of', 'input', 'string', '(4302)', 'is', 'greater', 'than│(base)
', 'maximum', 'allowed', '(4096)']

```

(エラー発生時に本来は解析結果が入るリストにエラー内容が入る仕様だったとは...)

どうも**入力文字列のサイズ(バイト数)が大きすぎた**そうです。
**入力文字列の限界は合計4096バイト**みたいなのでそれ以下の容量に制限した方が良さそう。

### とりあえず解決法

BERTに流すデータセットを作る過程だったんですが、長すぎる文はパス！
~~UTF-8は文字種によってバイト数が違うっぽいのでカットするのめんどくさい~~

4096バイトより大きい文は次のような条件で検出して何らかの回避策をしましょう。
（分割するなりパスするなり）
これは文字列`text`のバイト数を調べて比較しています。

```python
if len(text.encode('utf-8')) > 4096:
```

文字列の文字数長ではなくバイト数を調べる方法はこちら

- [Python 文字列の長さとエンコード別のバイト数 --Memoize2](http://basicwerk.com/memoize2/index.cgi?python.str_len_encode.txt)

## まとめ
PyKNPからJuman++を使う時にエラーが発生する原因は、以上で紹介した記事と合わせると

- [半角スペース](https://ensekitt.hatenablog.com/entry/juman)
- [一部の半角記号](https://qiita.com/NLPingu/items/3cd77eb2421283b851b4)
- **入力文字列サイズが4096バイト以上**

でした。
Microsoft Ignite Osaka 1/23 APPS50

# APPS50 監視、パフォーマンス、スケーリングを使用したアプリの次のレベルへの移行

MicrosoftIgniteOsaka

1/23 session5 APPS50 監視、パフォーマンス、スケーリングを使用したアプリの次のレベルへの移行のメモです。

本セッションはデモ中心。
デモは下記セッション動画を参照。（英語）

https://aka.ms/APPS50

## 状況

- 月曜日、休み明け
- 金曜の午後から一切売れてない
- すぐに修正してくれ

## 計画

- 問題の特定
- トラブルシューティング
- 修正
- 防止策

### ApplicationInsights

- リクエスト数、応答時間、失敗率、例外
- ページビュー
- パフォーマンス
- カスタムイベントとメトリック

ApplicationInsights作成時に発行されるInstrumentionKeyを埋め込むことで集中管理できる。
React用のプラグインもあるみたい。

障害検出だけでなく、理由も説明される。
それをメールで送ることもできる。

## 障害の把握と修正

ApplicationInsightsを使うことで、分散トレーシングの画面が見れる。
障害ポイントの確認、さらに詳細を見ることでサービス内のどの処理でエラーが発生しているか確認できる。

https://aka.ms/apps-insights-ignite

### AzureMonitor for Containers

- アプリケーションログ
- OSメトリクス
- コンテナメトリクス

https://aka.ms/azure-monitor-ignite

通常はkubectlなどでログを見るとか、外に出したログを１つずつ見ていくことになるが、AzureMonitor for Containersで見ると、ポータルである程度俯瞰的に見ることができる。

## 対応策

データセンター障害、大規模ネットワーク障害などで特定のリージョンにアクセスできなくなることを想定。

### AzureFrontDoor

- トラフィック負荷分散
- CDN
- トラフィックの切り替え
- 地理的に近いリージョンに接続される

GCPのグローバルロードバランサとほぼ同様のもの。

https://aka.ms/azure-frontdoor-ignite
[Golang] aws Lambda で、s3へファイルをstreamingに出力する

# 概要

大量のデータを処理するとき、メモリにすべてを展開せずにstream的に処理する必要があるときがある。
こういうstream的な処理は、大体どの言語でもあまりサンプルがなく、調べながらやるしかない。
ということでgoでやってみたのが以下。

## Streamingの利点
* メモリの使用が最小限であること
* json linesフォーマットと親和性が高い

### 補足> json linesフォーマットとは？

jsonフォーマットはこんな感じ。

```js
"list": [
  { "hoge": 1, "fuga": 2 },
  { "hoge": 1, "fuga": 2 },
  { "hoge": 1, "fuga": 2 },
  { "hoge": 1, "fuga": 2 },
  { "hoge": 1, "fuga": 2 }
]
```

json linesフォーマットはこんな感じ。

```js
{ "hoge": 1, "fuga": 2 }
{ "hoge": 1, "fuga": 2 }
{ "hoge": 1, "fuga": 2 }
{ "hoge": 1, "fuga": 2 }
{ "hoge": 1, "fuga": 2 }
```

jsonファイルの拡張子は`.json`だが、json linesの拡張子は`.jsonl`だったり`.json`だったり固定ではない模様。

## Streamingの欠点
* 通常のjsonフォーマットが使えない事
* どうしてもgoroutineを使った非同期処理が必要となる事

なので、データ量が多くないなら、Streamingに処理せず普通にメモリに展開したほうが良いかもしれない。

# Lambda

以下のサンプルは、Dynamodbにデータが挿入・更新されると実行される Dynamodb streamsという仕組みで動くLamba。
出力先のS3ファイルは、一行が一つのdynamodbレコードに相当するjsonであるような、json linesフォーマット。

```go
func handler(ctx context.Context, event events.DynamoDBEvent) error {
	r, w := io.Pipe()

	go func() {
		defer func() {
			if err := w.Close(); err != nil {
				log.Println("writer close error: ", err)
				return
			}
		}()
		for _, r := range event.Records {
			if err := UnmarshalDynamoEvent(r.Change.NewImage, &data); err != nil {
				log.Println("unmarshal dynamo event error: ", err)
				w.CloseWithError(err)
				return
			}
			b, err := json.Marshal(&data)
			if err != nil {
				log.Println("json marshal error: ", err)
				w.CloseWithError(err)
				return
			}
			if _, err := w.Write(b); err != nil {
				log.Println("data buffer write error: ", err)
				w.CloseWithError(err)
				return
			}
			if _, err := w.Write(lf); err != nil {
				log.Println("LF buffer write error: ", err)
				w.CloseWithError(err)
				return
			}
		}
	}()

	key := fmt.Sprintf("%s/%s/%s.json", keyPrefix, now.Format("20060102"), now.Format("150405"))
	result, err := s3uploader.Upload(&s3manager.UploadInput{
		Body:   r,
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	})
 	log.Println("result:", result)
	if err != nil {
		return err
	}
	return nil
}

```

こんな感じでStreamingにS3に出力することができた。
ちなみにPipeは以下のようなもの。

# io.Pipe

```go
func Pipe() (*PipeReader, *PipeWriter){
```

## io.PipeWriter

```go
func (w *PipeWriter) Write(data []byte) (n int, err error) {
func (w *PipeWriter) Close() error {
func (w *PipeWriter) CloseWithError(err error) error {
```

データをWriterに書き込むわけだが、書き込み中になんらかのエラーが発生してStreamをクローズしたいとき、CloseWithErrorを使って失敗したことをReader側に通知できる。
成功したら普通にCloseで閉じる。

## io.PipeReader

```go
func (r *PipeReader) Read(data []byte) (n int, err error)
func (r *PipeReader) Close() error {
func (w *PipeReader) CloseWithError(err error) error {
```

Writer側で何等かのエラーが発生（CloseWithError）すると、Readに失敗してerrが帰ってくる。なので、エラーが帰ってきたら処理を中断する。
Read側でエラーが発生してWriter側に通知したい場合はこちらのCloseWithErrorを使うことになるが、main threadをRead側にするのかWrite側にするのかで通知の方向が変わりそう。

# 結論

1. `io.Pipe`を使う事で、データを書きこみながらio.Readerに流すことができる
2. Write中に処理を中断する必要がある場合、`CloseWithError`でReaderに通知する
2. json lines形式を入出力に使えば、streamingな処理を書きやすい
3. writerのCloseを忘れずに！（closeを忘れるとdeadlockになる）

goroutineを使うコードを書くのは抵抗があるが、こういうコードを書く場合逆にgoroutineを使ったほうが綺麗に書けるきもする。
golangと仲良くなりたいが、悩みはつきない・・・
moment.jsのsubtract（減算）で時間の分（m）がうまく行かなかった件

## 問題定義

moment.jsで30分減算した時間を出したかったが `subtract(int, 'm')` でブラウザがフリーズした

```javascript
import moment from 'moment'
const time = moment('22:00', 'HH:mm');
// これを実装するとブラウザが固まる
const reducedTime = time.subtract(30, 'm');
```

## 解決

`subtract(int, 'm')` を `subtract(int, 'minutes')`に変えると解決した

```javascript
import moment from 'moment'
const time = moment('22:00', 'HH:mm');
// これを実装するとブラウザが固まる
const reducedTime = time.subtract(30, 'minutes');
```

#### コメント

なぜかはわからないので原因がわかる方はコメントで教えてくださると嬉しいです。
(検証)Google広告から発行されるURLパラメータ"gclid"がないとGAでは広告流入と見なされないのか？

#疑問
Google広告のクロスドメイン時によく話に上がるURLパラメータ`gclid`は、Google広告のコンバージョン測定だけでなく、Googleアナリティクスのレポートにおける広告流入の測定にも必要なのだろうか？ `gclid`がなくても、広告キャンペーン別レポートが見れなくなるだけではないのだろうか？ 「アナリティクスのレポートの「参照元/メディア」で`google / cpc`として計測されず、セッション数がGoogle広告のクリック数よりも少ない」といった要因になりうるのだろうか？ 

#前提
Google広告におけるgclidの前提について
※詳しくは関連記事を参照「[Google広告：クロスドメインコンバージョン計測の実装パターンと検証](https://qiita.com/MasatoEmata/items/1dfe2b780eb8315feb70#%E5%89%8D%E6%8F%90%E8%A8%88%E6%B8%AC%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF)」

 - 発行のタイミング
Google広告をクリックしてサイトにランディングしたとき、正しく設定をしていればURLパラメータに`gclid`が付与される。

 - 広告コンバージョン測定での利用
`gclid`はJavascriptでCookieの値にセットされ、コンバージョン時にはGoogle広告へのHTTPリクエストのパラメータとして送信される。


 - 「[自動タグ設定](https://support.google.com/google-ads/answer/3095550?hl=ja)」をすると、自動で発行される
 - 上記前提のもと、広告アカウントをアナリティクスのプロパティとリンクすると、`gclid`をキーにしてアカウント・キャンペーンごとのコンバージョン測定がアナリティクスのレポートでできるようになる。

それでは、Googleアナリティクスではどうなのだろうか？

#検証
##条件
 - URLパラメータなしで検索広告を出稿した
 
    - 自動タグ設定：いいえ
<img width="892" alt="without-gclid-session-00ads_setting2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/13d7ea72-f6f5-7a00-209e-680002291e98.png">

    - 広告のURLオプション：なし
 <img width="855" alt="without-gclid-session-00ads_setting1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/7a626d54-e078-f8f6-dba2-4189d8f4fcac.png">

##過程
 - 検索結果に表示された
 
<img width="477" alt="without-gclid-session-00search_result.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/0d6cc044-16f4-2d69-06bf-638dc3188514.png">

 - ランディングする
    - URLパラメータに`gclid`や`utm_source`/`utm_medium`がないことをチェック
    - アナリティクスのCookieのユーザー識別子`clientID`をコピーしておく
    (正確に言うと、`clientID`の値をセットしたカスタムディメンション・・・キャプチャの`cd2`)

<img width="777" alt="without-gclid-session.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/f549ae26-e597-5bb7-bc2a-fb71c380c9ce.png">

`会社名のマスキング途中でやめました。キャプチャが汚れるしプロフにも記載済なので。`

##結果
アナリティクスでは「参照元/メディア」が`google / organic` として登録された（`clientID`の値をセットしたカスタムディメンションで検索）。
<img width="533" alt="without-gclid-report.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/b1fef5be-e6fc-41ad-c285-e0c558c877bf.png">


#結論
`gclid`がないとgoogle広告経由のセッションであることが識別できず、広告コンバージョンも測定できない。

---
何かあればお手数ですが、本記事か以下アカウントでお知らせください！

**\ *Follow Me!* /**
**[*Qiitaアカウント*](https://qiita.com/MasatoEmata)**
**[*Twitterアカウント*](https://twitter.com/masatoemata)**
Flutter Integration Testの基本

## Integration Testの基本
Integration Testを色々調べて書いているうちに量が多くなってきたので基本部分だけ記事を分けました。
こちらは良く書かれている事ばかりですが、おさらいの意味で書きました。
### flutter_driverライブラリを追加
`pubspeck.yaml`に以下のように記載します。

```
dev_dependencies:
  flutter_driver:
    sdk: flutter
```
### 基本のディレクトリ構造
```
lib
res
test
test_driver
|____●●●.dart
|____●●●_test.dart
```
`test_driver` のディレクトリを作成

### 各ファイルの設定
`●●●.dart`と `●●●_test.dart` というファイルを作成します。※ ●●●は共通
```
●●●.dart
●●●_test.dart
```
WebViewの簡単なサンプルアプリです。
下記のコードのRaisedButtonウィジェットにkeyプロパティを設定しています。
Keyクラスの引数に名前を入れるとその名前でアクセスできるようになります。

- main.dart
- 
```
import 'package:flutter/material.dart';
import 'package:flutter_webview/pages/web_view.dart';

void main() =>   runApp(new MaterialApp(
  title: 'Navigation with Routes',
  routes: <String, WidgetBuilder> {
    '/': (BuildContext context) => Home(),
    '/webView': (BuildContext context) => Browser()
  },
));


class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: const Text("Home"),
      ),
      body: new Center(
        child: new RaisedButton(
          // keyを設定
          key: Key('openPage'),
          child: const Text("Launch Next Screen"),
          onPressed: () {
            // WebView画面へ
            Navigator.of(context).pushNamed("/webView");
          },
        ),
      ),
    );
  }
}
```

- main.dartの記述例

```
import 'package:flutter_driver/driver_extension.dart';
import 'package:sample/main.dart' as app;

void main() {
  // Flutter driver機能をONにする
  enableFlutterDriverExtension();
  // メインアプリを起動する
  app.main();
}
```
- main_test.dartの記述例

```
// Imports the Flutter Driver API
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';

void main() {
  group('Counter App', () {

    final counterTextFinder = find.byValueKey('openPage');

    FlutterDriver driver;

    setUpAll(() async {
      driver = await FlutterDriver.connect();
    });

    tearDownAll(() async {
      if (driver != null) {
        driver.close();
      }
    });
    // ボタンをタップ
    test('starts at 0', () async {
      await driver.tap(openPageFinder);
    });
  });
}
```
- テスト方法
以下のコマンドにてテスト。

```
#flutter  drive --target=test_driver/main.dart
```
## 参考文献
[Flutterの3種類のソースコードテスト(Unit Test, Widget Test, Integration Test)についてのまとめ](https://qiita.com/tez/items/755f340e84e87cfd7609)
【備忘録】ExcelからPythonのコードを実行する（xlwings）

他者のPC上で行う業務（Excelのデータ加工）の自動化のため、openpyxl + PyInstallerで自動化ツールを作成するものの起動が遅くてイライラ。かといって、Excel VBAを覚えるのもめんどくさい。もっと楽な方法ないかな～と思っていたら以下の記事を発見。

>[ExcelにPythonが搭載？その後 - xlwings を使おう](https://qiita.com/yniji/items/b38bc312e860027108ac)

ExcelからPythonコードを呼び出して使えるとのこと。しかし、どうもうまくいかない。そんなときに以下の記事を発見。

>[【VBA】VBAからPythonのコードを実行してみる（１）【Python】](https://celaeno42.hatenablog.com/entry/2018/12/03/191854)

これが上手くいった。
Excelが入っているWindows PCにAnacondaインストール＆ちょっと設定して貰えれば、ExcelファイルとPythonファイルを渡すだけで良くなりそう。
なので備忘録にまとめた。


# 環境
- Windows 10 Home Edition
- PyCharm Community Edition 2019.1.3
- Anaconda 3（xlwings==0.15.8　pywin32==223）
- Excel（Office 365）


# ExcelからPythonコードを実行する（やり方）
前述の環境は整っている前提。xlwingsとpywin32はAnacondaとセットでインストールされる。

### ①Excel マクロ有効ブック（*.xlsm）を作成する
後で作成するPythonコードとExcel マクロ有効ブックは、
1)同じディレクトリにあること
2)ファイル名（拡張子より前）が同一であること
が動作の必要条件。それを考慮したファイル名にすること。
今回はファイル名を「excel_test.xlsm」とした。

### ②Excel VBEにxlwings.basをインポート
1)Excelを起動し、開発タブの「Visual Basic」をクリックしてVBEを起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373977/4ed8636e-54fc-e053-24cb-504fc44d6a95.png)

2)VBEのファイル＞ファイルのインポートをクリックし、下記パスのファイル（xlwings.bas）を選択、インポート
パス：C:\Users\{ユーザー名}\Anaconda3\pkgs\xlwings-{xlwingsのバージョン}-py{Pythonのバージョン}\Lib\site-packages\xlwings\xlwings.bas
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373977/d450696e-b1da-3667-d674-3430e76a407e.png)

インポートが成功していれば、下図のとおり、標準モジュールフォルダに「xlwings」ができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373977/855a1116-a152-0209-edf0-0c44bf08a49e.png)


### ③Pythonファイルを作成
前述のとおり、Excel マクロ有効ブックと同じファイル名（拡張子より前）で、同じディレクトリに作成すること。
今回はファイル名を「excel_test.py」とし、コードは下記内容とした。

```python:excel_test.py
# coding: utf-8

import xlwings as xw


def copy_add_text():
    txt = xw.Range('A1').value
    txt += ', I am the Doctor.'
    xw.Range('B3').value = txt

```

### ④VBEで標準モジュールを追加し、Pythonファイルのメソッドを呼び出すコードを記述
コードの内容は以下のとおり。

```
1  Option Explicit
2  
3  Public Sub copyText()
4      Call RunPython("import excel_test; excel_test.copy_add_text()")
5  End Sub
```

【補足】
4行目の引数は、`"import モジュール名; モジュール名.メソッド名"`とする。
※モジュール名＝Pythonファイル名（拡張子不要）

### ⑤Excelの開発タブ＞マクロにメソッドが追加されているので呼び出す
今回のコードは「●●, I am the Doctor.」の●●にA1セルの文字列が代入されたものをB3セルに貼り付けるというもの。
実行結果は下図のとおり。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373977/dd49dc81-bfbd-443b-5299-a0c0ab7b5313.png)


# その他
pywin32==227でwin32apiのインポートエラーが発生。
pywin32==224にしたら解決。
詳細は不明。
jsPDFでHTML上の日本語表記のテーブルをサクッとPDF化

# 概要
- クライアントサイドで手軽にPDFを作成したい
    - HTML上の特定テーブル（日本語表記）をそのままPDF化

## [jsPDF](https://github.com/MrRio/jsPDF)とは？
- JavaScriptを用いてPDFを作成するライブラリ

## [jsPDF-AutoTable](https://github.com/simonbengtsson/jsPDF-AutoTable)とは？
- jsPDFのテーブル作成プラグイン

# How to
- 1. 使用したい日本語フォント（.ttf）をダウンロード
    - ここは個人の好きなフォントでOK
      - 今回は [Koruri](https://koruri.github.io/) という軽量日本語フォントを利用
- 2. [ここ](https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html)からフォントをJSファイルに変換する
    - fontNameに適当な名前を入力
    - fontStyleはダウンロードしたフォントのスタイルを指定
    - ファイルにダウンロードしたフォントファイルttfを指定
- 3. 各種JSをHTMLにて読み込み、jsPDFを用いてPDF化処理を記述
    - jspdf.min.js
    - jspdf.plugin.autotable.js
    - Koruri-Regular-normal.js ← ２でフォントファイルから変換したJS

```html
<html>
  <head>
    <script type="text/javascript" src="assets/js/jspdf.min.js"></script>
    <script type="text/javascript" src="assets/js/jspdf.plugin.autotable.js"></script>
    <script type="text/javascript" src="assets/js/Koruri-Regular-normal.js"></script>
    <script>
      $(function() {
        // 縦表示が'p'、横表示が'l'
        // 用紙サイズはA4
        let doc = new jsPDF('l', 'pt', 'a4', false);
        // ここでセットしたフォントはjsPDFのtext()で指定したテキストにのみ反映
        doc.setFont('Koruri-Regular', 'normal');
        doc.text(40, 30, 'HTMLテーブルをPDF化');
        doc.autoTable({
          theme: 'grid',
          html: '#table',
          // ここでフォントの指定をしないとテーブル内部の文字が化ける
          styles: {font: 'Koruri-Regular', fontStyle: 'normal', fontSize: 12}
        });
        doc.save('table.pdf');
      });
    </script>
  </head>
  <body>
    <table id="table">
      <tr>
        <th>名前</th>
        <th>年齢</th>
      </tr>
      <tr>
        <td>ほげ</td>
        <td>20</td>
      </tr>
      <tr>
        <td>ふが</td>
        <td>30</td>
      </tr>
    </table>
  </body>
</html>
```

# まとめ
- クライアントサイドでPDF化する方法はいくつかあるが、いまいち日本語化対応になっていなかったり、日本語対応するやり方が複雑だったりで情報も少ない。今回のやり方が一番サクッとできそうな方法かなーと。

# 参考
- jsPDF
    - https://github.com/MrRio/jsPDF
- jsPDF-AutoTable
    - https://github.com/simonbengtsson/jsPDF-AutoTable
- Koruri
    - https://koruri.github.io/
統計的因果探索

```{r}

#統計的因果探索　p.94

library(mvtnorm)

q=5;l=5;n=10

sig=sample(1:100,q)

#sig=rep(1,q)

X=array(abs(rnorm(l*n)),dim=c(l,n))

I=function(w){

val1=c();val2=c()

for(j in 1:q){

val1=c(val1,mean(-log(pnorm(w[j,]%*%X,sd=sig[j]))))

val2=c(val2,-log(pmvnorm(c(w%*%X[,j]),sigma=diag(sig))[1]))  

}

val2=mean(val2)

return((sum(val1)-val2)^2)

}


ite=10000

h=0.01

alpha=0.1

W=array(1,dim=c(q,l))

for(s in 1:ite){

vec=W  

dw=vec;ddw=vec

for(i in 1:q){
for(j in 1:l){  

vec_sub=vec;vec_sub[i,j]=vec_sub[i,j]+h 

vec_sub_sub=vec;vec_sub_sub[i,j]=vec_sub_sub[i,j]-h

dw[i,j]=(I(vec_sub)-I(vec))/h

#ddw[i,j]=(I(vec_sub)-2*I(vec)+I(vec_sub_sub))/(h^2)

}}  

W=W-alpha*abs(I(W))*dw

val1=c();val2=c()

for(j in 1:q){

val1=c(val1,mean(-log(pnorm(W[j,]%*%X,sd=sig[j]))))

val2=c(val2,-log(pmvnorm(c(W%*%X[,j]),sigma=diag(sig))[1]))  

}

val2=mean(val2)

print((sum(val1)-val2))



}




```

```{r}

#統計的因果探索　p.94 part2

library(mvtnorm)

l=5;n=5

sig=sample(1:100,l);k1=10;k2=10

#sig=rep(1,q)

X=array(abs(rnorm(l*n)),dim=c(l,n))/10

I=function(w){

val1=c();val2=c()

for(j in 1:l){

val1=c(val1,mean(-log(pnorm(w[j,]%*%X,sd=sig[j]))))

}

for(j in 1:n){

val2=c(val2,-log(pmvnorm(c(w%*%X[,j]),sigma=diag(sig))[1]))  

}

val2=mean(val2)

w2=t(w)%*%w;vec=diag(w2);diag(w2)=0

return((sum(val1)-val2)^2+k1*sum((vec-1)^2)+k2*sum(w2^2))

}


ite=10000

h=0.01

alpha=0.01

W=array(0.01,dim=c(l,l))

for(s in 1:ite){

vec=W  

dw=vec;ddw=vec

for(i in 1:l){
for(j in 1:l){  

vec_sub=vec;vec_sub[i,j]=vec_sub[i,j]+h 

vec_sub_sub=vec;vec_sub_sub[i,j]=vec_sub_sub[i,j]-h

dw[i,j]=(I(vec_sub)-I(vec))/h

#ddw[i,j]=(I(vec_sub)-2*I(vec)+I(vec_sub_sub))/(h^2)

}}  

W=W-alpha*dw

val1=c();val2=c()

for(j in 1:l){

val1=c(val1,mean(-log(pnorm(W[j,]%*%X,sd=sig[j]))))

}

for(j in 1:n){

val2=c(val2,-log(pmvnorm(c(W%*%X[,j]),sigma=diag(sig))[1]))  

}

val2=mean(val2)

print(I(W))



}




```

```{r}

#統計的因果探索　p.94 part3

library(dplyr)

data=data.frame(num=1:20,y=c(0.20, 0.10, 0.49, 0.26, 0.92, 0.95, 0.18, 0.19, 0.44, 0.79, 0.61, 0.41, 0.49, 0.34, 0.62, 0.99, 0.38, 0.22,0.71,0.40),x1=c(84,87,86,85,82,87,92,94,88,84.9,78,90,88,87,82,84,86,83,85.2,82),x2=c(61,55.5,57,57,50,50,66.5,65,60.5,49.5,49.5,61,59.5,58.4,53.5,54,60,58.8,54,56),x3=c(24.5,24,23,22.5,22,24,25,26,25,24,23,21,26,25.5,24,23,24,24,24,22),sign=0)

X=as.matrix(cbind(rep(1,nrow(data)),data[,colnames(data) %in% c("x1","x2")]))/100

pis=array(sample(data$y,prod(dim(X)),replace=T),dim=dim(X))

w=array(0.01,dim=c(nrow(X),nrow(X)))

pthi=function(W){

prob=1/(1+exp(-W%*%X))  

p_val=c()

for(m in 1:nrow(X)){
  
p_val=c(p_val,mean(-log(1/(1+exp(-W[m,]%*%X)))))  
  
}

return(sum(p_val)-mean(-log(apply(pis,2,mean))))

}



ite=20000

h=0.01;eta=0.01

cost=c()

for(l in 1:ite){

vec=w;dw=array(0,dim=dim(w))

for(i in 1:dim(w)[1]){
for(j in 1:dim(w)[2]){

vec_sub=vec;vec_sub[i,j]=vec_sub[i,j]+h

dw[i,j]=(pthi(vec_sub)-pthi(vec))/h

}}

w=w-eta*dw

qr.w=qr(w);Q=qr.Q(qr.w);R=qr.R(qr.w)

S=diag(ifelse(diag(R)>0,1,ifelse(diag(R)<0,-1,0)))

w=Q%*%S

cost=c(cost,pthi(w))

print(pthi(w))

}

```
VagrantでLinux(CentOS)構築時に正しくソフトウェアをバージョンアップする方法 　〜Python2.7からPython3.6へのバージョンアップの例を用いて〜

####PATHとは？
Linuxに限らず、コマンドを実行する際にフルパスを書く必要がないのはPATHにそのパスの情報が保存されているからです。例えば、Linuxをシャットダウンする際に`/usr/sbin/shutdown -h now`ではなく`shutdown -h now`と書いて実行できるのは、`/usr/sbin/`がPATHに登録されているからです。

#####PATHの確認方法
以下を実行。

```bash
echo $PATH
```
実行結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464595/572e09a4-7d21-343f-50fd-fbf2a3be4dd1.png)

自分の場合、いじったのでこうなっています。PATHは何個でも登録してもよく、`:`で各パスに区切られています。

#####バージョンが違う同じソフトウェアを入れた時の対処
例えばCentOS7だとディフォルトで`python 2.7`が入っています。`python --version`を実行すると、そのバージョン情報が出てきます。
ここで、新たに以下のコマンドを叩き`Red Hut Enterprise Linux`を使用して`python 3.6`を落としてくるとします。

```bash
sudo yum -y install centos-release-scl;
sudo yum -y install rh-python36;
sudo scl enable rh-python36 bash;
```
この後に`python --version`を実行すると、`python 3.6`を見ていますが、Vagrantの操作等でパスを再度読み込んだ際に元に戻ってしまいます。これは`Red Hut Enterprise Linux`で落とした`python 3.6`が`/usr/bin`には行かずに`/opt/rh/rh-python36/root/bin/`へ落ちるためです。この`/opt/rh/rh-python36/root/bin/`をPATHへ登録し、`/usr/bin`にある`python2.7`を取り除かない限りは綺麗に`python`のバージョンアップができません。ちなみにLinuxが参照している`python`のパスは以下のコマンドでわかります。

```bash
which python
```
`python`に限らず、なんでもこの`which`でLinuxが参照しているコマンドの実際のパスがわかります。

`python2.7`など、古いバージョンのプログラムを取りのぞくときは、`rm`コマンドで削除するより、`mv`コマンドで名前を変えて取り置いといた方がいいです。以下Pythonの例をとった時のコマンドです。

```
sudo mv /usr/bin/python2.7 /usr/bin/python2.7_old
```
これでLinuxがPython2.7を退避することができます。

#####PATHの変更方法
いくつかあると思いますが、自分が好きなのは`source`コマンドで`~/.bash_profile`というファイルを取り込む方法です。`~/.bash_profile`にはPATHの情報があり、`source　~/.bash_profile`を実行することでPATH登録が行われます。シェルスクリプトでこれを実行する人に注意して欲しいんですが、この`~`がどこなのかスクリプト内に明記しておくべきです。というのもルートユーザーと一般ユーザーでは`~`の部分が違います（動画参照）。
![vagrant_root_homedirectory.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464595/6fc38705-9ff7-ad2f-715e-22a324aad20c.gif)

`Vagrantfile`にシェルを仕込ませて実行した場合、`~`がどちらを向いてるか自分はわからなかった（`vagrant provision`を行うと実行ユーザーは`vagrant`なのに`~`は`/root/`側を見ているようだった）ので、明記しました。

結果、以下のコマンドでPATHを読み込ませました。

```
#/home/vagrant/.bash_profileにPATH情報を設定
echo "export PATH="/opt/rh/rh-python36/root/bin:/usr/bin:/usr/sbin"" >> /home/vagrant/.bash_profile;
#PATH情報を登録
source /home/vagrant/.bash_profile;
```

####最後に
上記のステップを押さえておけば、どんなソフトウェアでも問題なくバージョンアップが可能です。
自分は`sqlite 3.2`を`sqlite 3.29`へ同じアプローチでバージョンアップできました。

##参考
https://teratail.com/questions/50308
https://qiita.com/nito128/items/e91e8510c882a7f24768
【初心者向け】関数について

||意味　　　　　　|
|:--|--:|
|関数|一つの処理をまとめたもの|
|引数|関数に渡せる値|
|返り値|関数から戻ってくる値|
|初期値|引数がない時の値|

#関数とは

処理をひとまとめにすることで使いまわせる
似たような処理をまとめられる

```php:
//定義
function sayHello() {

//処理
  echo "Hello!";
}

//呼び出し
sayHello();// Hello!
sayHello();// Hello! 何度も呼び出し可能
```

#引数とは
関数に渡す値

```php:
//渡された引数が$nameに入る
function sayHello($name) {

//$nameは関数の中で使用できる
  echo "Hello!" . $name;
}

//関数に引数を渡す
sayHello("Tom");// Hello!Tom
sayHello("Bob");// Hello!Bob


//引数は複数指定できる
function sayHello($name,$ago) {

  echo "Hello!" . $name . $ago;
}

sayHello("Tom",19);// Hello!Tom19
sayHello("Bob",20);// Hello!Bob20
```

#返り値
処理を終了させ、関数から戻ってくる値

```php:

function sayHello($name) {

//値を返す
  return "Hello!" . $name;

  echo "ここは処理をされない。";
}

$test = "jon";
//sayHello関数の呼び出し
echo sayHello($test);// Hello!jon
```

#初期値
引数を指定しなった時の値

```php:
//初期値指定
function sayHello($name = "Jon") {

  echo "Hello!" . $name;
}

sayHello("TOM");// Hello!Tom
sayHello("Bob");// Hello!Bob
sayHello();     // Hello!Jon　初期値
```
Go言語の似た概念を触る

# はじめに

本題に入る前に、前提となることを記述しておきます。

## 目的
目的は以下です。

- Go言語を読んでいて、似た概念を読み間違えないようにするため

それだけです。

## 読者の対象
読者の対象は以下です。

- プログラミング初心者
- Go初心者
- 軽くGo言語を使っている人

裏を返せば、例えば以下のような方は対象ではありません。

- Go言語を体系的に理解したい方
- 似た表現の実体を比較したい方、メモリの使い方を理解したい方

## 参考

- [A Tour of Go](https://go-tour-jp.appspot.com/list)

## おことわり
- 少しずつ文を追加しています。
- 初心者目線で「これとこれも紛らわしいから説明してくれ！」というものがあれば、連絡ください。

# 本題

## ArraysとSlices

A Tour of Goを読んでいて、ArraysとSlicesは似ているなーと思ったのでまとめました。

- [Arrays](https://go-tour-jp.appspot.com/moretypes/6)
- [Slices](https://go-tour-jp.appspot.com/moretypes/7)

### Arraysは固定長、Slicesは可変長

宣言する形からしてもわかるように、Arraysは固定長でSlicesは可変長です。

Arrays/Slices | 宣言 | 意味
--- | --- | ---
Arrays | var a [10]int | 10個のintからなる配列a
Slices | var b []int | 個数は問わないスライスb

### 見分け方

[]の中に数字が入っているかどうかですね。
数字があればArrays、なければSlicesです。

## 外部パッケージ呼び出しと、構造体フィールドへのアクセス

仕事でGoのプログラムを読んでいて、???となりました。
どちらもドットを使っています。

### 外部パッケージ呼び出し

```main.go
package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello, World!") //ここ！
}
```

`fmt.Println`とあるように、ドットを使っています。

参考：[A Tour of Go>外部パッケージ呼び出し](https://go-tour-jp.appspot.com/basics/1)

### 構造体フィールドへのアクセス

```main.go
package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	v.X = 4 //ここ！
	fmt.Println(v.X)
}
```

構造体Vertexを型とする変数vについて、Xの値を4とする。
これを、ドットを用いて`v.X`としています。

参考：[A Tour of Go>構造体のフィールド](https://go-tour-jp.appspot.com/moretypes/3)

### 見分け方
`<importされているパッケージ>.*`であれば外部パッケージ。
`<構造体を型とする変数>.<構造体のフィールド>`であれば、構造体フィールドへのアクセス、でよいでしょう。