OmniAICreator/Qiita-1.07M huggingface dataset:
フリーランス準備メモ（主に経費まわり）

## はじめに
退職してフリーランスとして働くことになったので、事前に準備しておいた方が良いものと給料、経費辺りで関係ありそうなものをまとめておきます。

## 参考サイト

- [個人事業と開業　開業前に準備することは何？](https://www.freee.co.jp/kb/kb-kaigyou/preparation/)

- [開業費の範囲とは？開業費に関する疑問を解決](https://www.freee.co.jp/kb/kb-kaigyou/range/)

- [フリーランス（個人事業主）の経費はどこまでOK？！上限まで賢く節税！](https://kasegood.net/freelance-keihi)

- [会計ソフトを購入した際の仕訳（勘定科目）を解説](https://www.freee.co.jp/kb/kb-accounting/title_of_accounts/)
- [フリーランスを始めてみて疑問が解けたよ](https://qiita.com/clustfe/items/835c7a191380f95ffe9e)

## 準備しておいた方が良いもの

- 名刺
人脈を広げるためにもあった方が良い。

- 仕事用の携帯
プライベートなものと区別するためと、個人情報を守るためにも必要。

- 仕事用口座
確定申告を楽にするために必要。個人用と混在してると信用が下がることもある。

- ブログ、ポートフォリオサイト
実績、信頼から受けられる案件の増加や単価アップにも繋がるから出来るだけ用意したい。

## 経費に出来るもので自分に関係あるもの

- 交通費
  - 勘定項目：旅費交通費

- サーバー代、ドメイン代
  - 勘定項目：通信費

- 名刺代
  - 勘定項目：広告宣伝費

- スマホ代、電話代
  - 勘定項目：スマホの利用料と端末代は別  
    スマホの利用料は通信費  
    端末代は10万未満なら消耗品費、10万以上なら備品費

- 書籍代、雑誌代
  - 勘定項目：新聞図書費(基本的にこれ)、書籍代、研究開発費

- セミナー、勉強会の参加費
  - 勘定項目：研修採用費

- 同じ業界の人との交流費
  - 勘定項目：接待交際費

- 切手代
  - 勘定項目：通信費

- 封筒代
  - 勘定項目：消耗品費、事務用品費

- 振込手数料
  - 勘定項目：支払手数料

- パソコン関連の購入代
  - 勘定項目：10万未満なら消耗品費、10万以上なら備品費

- 会計ソフト
  - 勘定項目：クラウド型かインストール型で変わる  
    クラウド型：通信費  
    インストール型：消耗品費

## あとがき
開業前でも開業費として計上すれば節税につながるので、先に出来ることはやっておいた方が良いですね。  
調べて初めて知った中だと、レンタルサーバー代も経費に出来るというのが一番の魅力ですね。  
フロントエンドの勉強ついでにポートフォリオサイト作れば一石二鳥だけど、サーバー構築にコスト（時間的にも金銭的にも）かけたくないなぁ、と思ってたので・・・
New Relic InsightsのダッシュボードをREST APIから見たい

# TL;DR

* New Relic InsightでダッシュボードをREST APIから使うには、Admin user API Keyが必要
* [New Relic REST API Explorer](https://rpm.newrelic.com/api/explore/)に使いたいAPIと必要なパラメーターを入力すると、`curl`コマンドを作成してくれるので利用するとよい


# やりたいこと

New Relic Insightsのダッシュボードの定義を取得したり、定義からダッシュボードを作成するのにコードなどで表現できるといいなぁと思いまして。

[Insights Dashboard API](https://docs.newrelic.com/docs/insights/insights-api/manage-dashboards/insights-dashboard-api)を使うと良いようです。

で、ドキュメントから利用までの流れを掴むのにややてこずったのでメモとして書いておきます。


# New Relic Admin API Keyの入手

Insights Dashboard APIを使用するには、Admin API Keyが必要です。REST API Keyではありません。

New RelicのWeb UIのヘッダーから自分のアイコンをクリックして、`Account settings` → `Integrations` → `API Key`を選択します。

以下のような画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/9364e448-91ac-0ef3-a229-660070790f2e.png)

下の表になっているところに、Admin's API Keyが表示されるのですが、最初はなにもないので、矢印のアイコンをクリックして作成します（赤で囲っている部分です）

作成済みであれば、`Show key`をクリックして表示させて、Admin API Keyをコピーするなりします。


# Insights Dashboard APIにアクセスする

続いて、[New Relic REST API Explorer](https://rpm.newrelic.com/api/explore/)にアクセスして、APIの定義や呼び出し方を確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/fba8cf20-e959-fd8c-aade-0ebfb62092e8.png)


左上部に、現在ログインしているアカウントのキーを選ぶようにすれば、Admin API Key（REST API Keyも選べます）が補完されるので便利です。

次に、左のメニューから利用したいAPIを選びます。今回は`Dashboards`を。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/044012bb-b618-dca0-fd34-e5ec3f2510c6.png)

APIごとに必要なパラメーターを入力すると、`curl`コマンドを作成してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/295aca03-6ffe-d7ea-8923-9b5f6873a872.png)

あとは、このコマンドを使ってREST APIを使いましょう。
Nuxt.js Application で Safari 10 のバグを踏んだ時の対処法

先日、運用している Nuxt.js アプリケーションで「本番環境で特定の iOS 端末に限定してアプリケーションが動かない」という報告がきたのでその対処の話です。

## tl;dr 

- デフォルトの Nuxt.js では Mobile Safari 10 でバグる
  - teaser のオプションに safari10 を追加しろ

## `Cannot declare a let variable twice 'e'`

再現端末を用意してリモートデバッグしてみると、出ていたエラーは `Cannot declare a let variable twice 'e'` というエラーでした。let 宣言の重複エラーみたいなので、「実はうまく変換されてない？」という疑問が生まれます。

大体こういうのは Babel 設定か Uglify の設定の問題なので、その辺りを検索ワードに含めつつ検索。

### Mobile Safari 10 の ES6 実装のバグが原因

調べた結果、webpack-contrib/uglifyjs-webpack-plugin でドンピシャな Issue がありました。

<img width="777" alt="Screen Shot 2019-05-31 at 11.42.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75633/7272984e-c3ab-d9e0-3071-3840f3692264.png">

https://github.com/webpack-contrib/uglifyjs-webpack-plugin/issues/92

Uglify 周りの設定でうまくいくかなと思ってみてみると、

> SyntaxError: Cannot declare a let variable twice
> 
> This is an ES6 bug in Safari 10:
> https://bugs.webkit.org/show_bug.cgi?id=171041

https://github.com/webpack-contrib/uglifyjs-webpack-plugin/issues/92#issuecomment-324818437

ということで、 WebKit にバグがあって、それが Safari 10 でそのまま再現してしまっていたことがわかりました。Uglify としてはこの挙動の対処方法として、オプションを渡してやるのでそのまま反映してやるとよさそうです。

## Nuxt.js の内部的な Optimizer は Terser に変わっていた

### Uglify での設定 (Nuxt v1.x では有効)

まずはじめに、 nuxt.config.js の build オプションに、調べて出てきた fallback のためのオプションを追加してみることにしました。

Nuxt.js v1.x 時代に Uglify の設定を書き換えたことはあるので、どうやると良いかは把握していました。
https://qiita.com/potato4d/items/2c89cf6433a3833e005c

```ts:nuxt.config.ts
import { NuxtConfiguration } from '@nuxt/vue-app'

const config: NuxtConfiguration = {
  //

  build: {
    uglify: {
      uglifyOptions: {
        mangle: {
          safari10: true
        }
      }
    }
  } 
}

export default config
```

こんな感じで編集してみてビルド実行。しようと思ったのですが、 uglify が何故か TypeScript の型定義に怒られて config ファイルが invalid なものになっていました。

### Terser での設定 (Nuxt v2.0 or higher で有効)

ということで調べ直してみると、 Nuxt.js の optimizer は今は Uglify ではなく Terser になっていた様子。当然 Uglify は設定の型定義からも drop されています。

https://nuxtjs.org/api/configuration-build#terser

Uglify は uglify-es を使わない限り ES2015+ に対応していないのですが、 Terser は対応しているので、最近は割と好まれる optimizer になっています。

一方で、 Uglify だと通る時点で ES5 であることが確実だったりするので、こういう問題は基本起きなくて安心だったりする(後ろ向きながらも)利点はあったりします。

terser に変わっていたので、設定もそれに合わせて書き直すように。

```ts:nuxt.config.ts
import { NuxtConfiguration } from '@nuxt/vue-app'

const config: NuxtConfiguration = {
  //

  build: {
    terser: {
      terserOptions: {
        safari10: true
      }
    }
  } 
}

export default config
```

これで修正完了。デプロイして一件落着です。

## おわりに

Mobile Safari のアクセス数は普通だと 0.01% にも満たないと思うのであまり気にすることはないかもしれませんが、アクセスの絶対数が多いと無視できない数字になったりします。

今回は iOS 10 の端末がなければ再現できないという点で手間取りましたが、古いブラウザの場合はこういったバグも少なからずあるので、必ず再現するものを用意して一つずつ確実に潰していく必要がありますね。

- https://bugs.webkit.org/show_bug.cgi?id=171041
  - https://github.com/webpack-contrib/uglifyjs-webpack-plugin/issues/92
  - https://github.com/webpack-contrib/uglifyjs-webpack-plugin/issues/92#issuecomment-324818437
- https://nuxtjs.org/api/configuration-build#terser
Python で大量のファイルを並列で速く読み込む

些細なことでも [multiprocessing](https://docs.python.org/ja/3/library/multiprocessing.html) 使うと便利だよ、という小ネタ。

## やりたいこと
``` python
from glob import glob

files = glob('data/*.csv')

len(files)  # 10000
```

この 1万件の CSV ファイルを Pandas DataFrame として読み込みたい。

ちなみに検証用のデータは以下のようにして生成した。
(3列 x 10,000行 の CSV ファイル 10,000 個)

``` python
import numpy as np
import pandas as pd

row_n = 10000
col_n = 3

columns = [f'col{i}' for i in range(col_n)]
for i in range(10000):
    df = pd.DataFrame(np.random.randn(row_n, col_n), columns=columns)
    df.to_csv(f'data/{i:04}.csv', index=False)
```

## 並列化の手法いくつか
今回は

- 並列化なし (シングルスレッド)
- マルチスレッド
- マルチプロセス

で比較した。

asyncio (イベントループ) については、[asyncio がファイルの非同期読み込みをサポートしていなかった](https://github.com/python/asyncio/wiki/ThirdParty#filesystem)ので試さなかった。 aiofiles などの外部モジュールを使えばできると思うので、<del>誰か試してみてほしい。</del> [追記] 試してみた → [コメント](#comment-631a1ed95516c5186de6)を参照。

### 並列化なし (シングルスレッド)
並列化を考えずに全てのファイルを読み込もうとするとこうなる。

``` python
import pandas as pd

arr = [pd.read_csv(f) for f in files]
```

### マルチプロセス
[multiprocessing.Pool](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.pool.Pool) を使う。

``` python
import pandas as pd
from multiprocessing import Pool

def read_csv(f):
    return pd.read_csv(f)

with Pool() as p:
    arr = p.map(read_csv, files)
```

`p.map` には `pd.read_csv` を直接渡したり `lambda` を渡したりすることはできないので、 `read_csv` という関数を定義している。

`Pool()` で並列数を指定しなかった場合は CPU のコア数と同じ並列数で実行される。

### マルチスレッド
[multiprocessing.dummy.Pool](https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing.dummy) は threading を使っているとのことなので、これを使ってみる。

``` python
import pandas as pd
from multiprocessing.dummy import Pool

with Pool() as p:
    arr = p.map(pd.read_csv, files)
```

マルチスレッドの場合は `pd.read_csv` をそのまま渡せる。

## 結果
4コア CPU のマシンで計測した結果が以下。

|| 読み込み速度 |
|---|---|
| 並列化なし (シングルスレッド) | 82 sec |
| マルチスレッド | 28 sec |
| マルチプロセス | 22 sec |

マルチプロセスが一番速かった。

4並列で読み込んで4倍速くなるとまではいかなかったが、並列化の恩恵を十分に感じられる程度には速くなった。

### マルチスレッドの注意点
今回はマルチスレッドもマルチプロセスとほぼ同じくらいには速くなったので、手軽さを重視してマルチスレッドの方を採用してもいいケースもあるかもしれない。

ただし Python (CPython) のマルチスレッドは [GIL (Global Interpreter Lock)](https://wiki.python.org/moin/GlobalInterpreterLock) の制約があり、複数のスレッドが同時に Python バイトコードを実行することができない。

<del>そのため、今回のファイル読み込みのような I/O バウンドな処理は高速化できるかもしれないが、例えば「読み込んだ各データに対してなんらかの重い処理を行う」などの CPU バウンドな処理を併せて実行した場合はおそらく今回ほど速くならない。そのようなケースではマルチプロセスで並列化した方が高速化できると思われる。</del>

違う気がしてきた・・・。
詳しくは[コメント](#comment-c65a6ce1f11809eddeb3)を参照。

``` python
arr = [open(f).read() for f in files]
```

Pandas のパース処理を入れずに単純にファイル内容を読み込むだけにすると 3.2 秒で終わるので、今回の処理は I/O バウンドではなく CPU バウンドだった・・・。


## [2023.02 追記] AWS Lambda で Pool が使えない件
AWS Lambda の Python ランタイムで同じことをやろうとしたら `multiprocessing.Pool` が使えなくて困ったので、それについて別記事に書いた。

https://qiita.com/hoto17296/items/60092e4eca00e572ab3b
Apolloクライアントのキャッシュについて

Apolloクライアントには、キャッシュ機能が備わっています。
使い方は、[公式](https://www.apollographql.com/docs/react/advanced/caching/#inmemorycache)載っています。
これに絡んでちょっとはまってしまったので、メモとして残します。

# はまったこと
以下のような現象が発生しました。

* Apolloサーバー(NestJS)から、データベースに登録されているスタッフの一覧を取得する
* スタッフを1名追加するmutationを呼び出し、データベースに追加する
* 再度、Apolloサーバーから、スタッフ一覧を取得する

この結果、どうなると思いますか？
mutationで追加した後に、スタッフ一覧を取得しても、追加したはずのスタッフがいないんです。

# なぜこんなことが起きるのか？
調べて見て、分かったことは以下の通りです。

* Apolloクライアント側のスタッフ一覧は正常終了している
* 正常終了しているものの、追加したスタッフは入っていない
* ページを再ロードすると追加したスタッフが表示される
* Apolloサーバーのログを見ると、スタッフ追加後にスタッフ一覧を取得した形跡がない(SQLが発行されていない)

これらのことから、「Apolloクライアントにはキャッシュ機能があって、何らかの要因でキャッシュが有効になっているのではないか？」という結論に至りました。
英語が不得意なので、正確には読み取れていませんが、__typenameとidのデータを見てキャッシュを構成しているようです。mutationした場合に、__typenameとidを返すようにしていれば、キャッシュが更新されるようです。
しかし、私の場合、追加した結果は別の形で返しているので、この機能が働かず古いキャッシュ情報が返って来ていたと言う事のようです。

# どうするか？
とは言え、キャッシュが正しく機能するように改修するのは、時間がかかります。
何か、方法はないかと公式を見てみるとありました。
mutationでスタッフを追加するときに、強制的にスタッフ一覧を取得するという方法です。

```typescript:staff.ts
  save(_staff: User): Promise<ISaveStaffResult> {
    return new Promise((resolve, reject) => {
      this.apollo.mutate({
        mutation: this.saveStaffMutation,
        variables: {
          staff: _staff
        }
      })
      .subscribe(( {data} ) => {
        const ret: any = data;
        resolve(ret.savestaff);
      }, (err) => {
        reject(err);
      });
    });
  }
```

このようにmutationを呼び出すときに、refetchQueriesを追加します。

```typescript:staff.ts
  save(_staff: User): Promise<ISaveStaffResult> {
    return new Promise((resolve, reject) => {
      this.apollo.mutate({
        mutation: this.saveStaffMutation,
        variables: {
          staff: _staff
        },
        // 追加するのはこれ！！
        refetchQueries: [{
          query: this.getStaffAllQuery
        }],
        awaitRefetchQueries: true
      })
      .subscribe(( {data} ) => {
        const ret: any = data;
        resolve(ret.savestaff);
      }, (err) => {
        reject(err);
      });
    });
  }
```

こうすると、mutationが完了した後に、スタッフ一覧を取得するリクエストがApolloサーバーに飛んで行きます。
ABC110Cの嘘解法

### 問題
[ABC110 C問題 - String Transformation](https://atcoder.jp/contests/abc110/tasks/abc110_c) (300 点)

**概要**
英小文字のみからなる同じ長さの文字列S, Tが与えられます。
文字列Sに対して、次の操作を何度でも行うことができます。
0回以上操作を行って、SをTに一致させられるか判定してください。

**操作**
2つの異なる英小文字x, yを選び、Sに含まれる全てのxをyに、yをxに置き換える。

### 嘘解法

以下の<B><font color="#ec971f">嘘解法</font></B>を多く見かけました。

```python:嘘解法
from collections import Counter
 
s = input()
t = input()
 
c1 = Counter(s).most_common()
c2 = Counter(t).most_common()
 
for x, y in zip(c1, c2):
    if x[1] != y[1]:
        print("No")
        break
else:
    print("Yes")
```

テストケースで例えば

```
azzel
apple
```

に対して文字数のカウントが一致することを見ています。
文字数のカウントの個数に一致しないところがあれば、いくら操作を繰り返してもSはTに一致しません。

|Sの文字数のカウント|Tの文字数のカウント|判定|
|:-----------|:------------|:------------|
| (z, 2) | (p, 2) | 2 == 2 一致 |
| (a, 1) | (a, 1) | どちらも1個で一致 |
| (e, 1) | (l, 1) | どちらも1個で一致 |
| (l, 1) | (e, 1) | どちらも1個で一致 |

入力例に対してはすべて正しく判定でき、このコードを提出すると<font color="#449d44"><B>AC</B></font>に判定されます。
それでは、なぜこの方法は<B><font color="#ec971f">嘘解法</font></B>なのでしょうか。

以下のような入力例を考えてみます。

```
aba
ccb
```

どのように操作を行ってもSはTに一致しませんが、上記のコードでは"Yes"と判定されてしまいます。

### 正しい解法

正しくは、以下の2つの条件を確認する必要があります。

- Sの中の同じ文字が、Tの別の文字に対応していない
- Tの中の同じ文字が、Sの別の文字に対応していない

これをコードで表現すると以下のようになります。

```python:解答例

s = input()
t = input()

dict_st = {}
dict_ts = {}

for x, y in zip(s, t):
    if x not in dict_st:
        dict_st[x] = y
    else:
        if dict_st[x] != y:
            print("No")
            break

    if y not in dict_ts:
        dict_ts[y] = x
    else:
        if dict_ts[y] != x:
            print("No")
            break
else:
    print("Yes")

```

これを提出すると、正しく<font color="#449d44"><B>AC</B></font>となります。
先ほどのS = "aba", T = "cca"のケースに対しても正しく"No"と判定できます。
Pythonでjsonファイルを扱ってる時、「ValueError」に遭遇したら...

# ValueError: Unmatched ''"' when when decoding 'string' に遭遇したら、やってみる事

[参照先:ValueError: Unmatched ''"' when when decoding 'string'][link1]

上記の参照先で見てみると...
「jsonファイルの一部に何らかの不要な"引用符"が混じってるんじゃないか？」と言うものだったので、
~~探すのが面倒だから~~とりあえず"新しく空のjsonファイル"と作成してみたところ、無事解決した。

のちに、以前のファイルと比較してみたところ、やはり一部に混じっている事を確認した。

現場からは、以上です。


[](
comment-out:　Link's
)

[link1]:https://github.com/lil-lab/newsroom/issues/12
macでEmacsの起動を高速化(daemon/emacsclientを使う)

## 設定内容
Emacs daemonをログイン時に起動しておいてemacsclientを使用する。
Emacs daemonが落ちていたら再起動するようにする。

## 設定方法
Automatorで以下のようにAppleScriptを実行できるようにして， EmacsClientという名前で/Applicationsに保存する[1]。

```applescript
on run {input, parameters}
	
try
	tell application "Terminal"
		do shell script "/Applications/Emacs.app/Contents/MacOS/bin/emacsclient -create-frame --alternate-editor=''"
	end tell
on error
	tell application "Terminal"
		do shell script "/Applications/Emacs.app/Contents/MacOS/Emacs --daemon"
		do shell script "/Applications/Emacs.app/Contents/MacOS/bin/emacsclient  -create-frame --alternate-editor=''"
	end tell
end try	
	return input
end run
```

以下のファイルを~/Library/LaunchAgents/gnu.emacs.daemon.plistに保存して， ``launchctl load -w ~/Library/LaunchAgents/gnu.emacs.daemon.plist``を端末から実行する[2]。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>gnu.emacs.daemon</string>
    <key>ProgramArguments</key>
    <array>
      <string>/Applications/Emacs.app/Contents/MacOS/Emacs</string>
      <string>--daemon</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceDescription</key>
    <string>Gnu Emacs Daemon</string>
  </dict>
</plist>
```

## 参考ページ
[1] https://gist.github.com/redinger/1394910
[2] https://www.emacswiki.org/emacs/EmacsAsDaemon
自己拡張するスクリプトで円周率を計算してみた

# 前提
Windows Script Hostはスクリプトファイルをロックしないらしい
自己拡張するスクリプトも可能なのでは？
折角なら円周率でも計算させたろ！

# 自己拡張する円周率計算スクリプトを作ってみる

## コード

モンテカルロ法[^1]で円周率を計算して、
計算結果を**自身のスクリプトに書き込み**
平均値を出力するスクリプトにしてみました。

```vb:pi.vbs
' *** ここから円周率の計算 ***
' 計算にはモンテカルロ法を使用
Const N = 1000000
count = 0

Randomize 
For i = 1 To N
    x = Rnd
    y = Rnd
    If x * x + y * y <= 1.0 Then
        count = count + 1
    End If
Next

pi = 4.0 * count / N

Set piList = CreateObject("System.Collections.ArrayList")
piList.add pi
' *** ここから自己拡張コード ***
' *** ここまで自己拡張コード ***

' 今まで取得したPIの平均値を取得
For Each piItem In piList
    total = total + piItem
Next

avgPi = total / piList.Count
WScript.Echo avgPi
Set piList = Nothing
' *** ここまで円周率の計算 ***

' *** ここからスクリプトを拡張するコード ***
Set fso = CreateObject("Scripting.FileSystemObject")

' スクリプト読込
Set readFile = fso.OpenTextFile(WScript.ScriptFullName, 1, False, 0) 
Set scriptList = CreateObject("System.Collections.ArrayList")

Do Until readFile.AtEndOfStream
    scriptList.add readFile.ReadLine
Loop

readFile.Close
Set readFile = Nothing

' スクリプト書込
Set writeFile = fso.OpenTextFile(WScript.ScriptFullName, 2)

For Each scriptLine In scriptList
    if scriptLine = "' *** ここまで自己拡張コード ***" Then
        ' 自己拡張コード書込
        writeFile.WriteLine "piList.add " & pi & " ' " & Now() & " に追加"
    end if

    writeFile.WriteLine scriptLine
Next

writeFile.Close
Set writeFile = Nothing

Set fso = Nothing
' *** ここまでスクリプトを拡張するコード ***
```

# １回実行

## 実行結果
```console:１回実行
>cscript pi.vbs
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

3.141336
```

# 実行後のコード
全部コードを張るとみにくいので、自己拡張された部分のみ

```vb:１回実行後のコード（自己拡張コードのみ）
' *** ここから自己拡張コード ***
piList.add 3.141336 ' 2019/05/30 20:57:10 に追加
' *** ここまで自己拡張コード ***
```

# １０回実行

## 実行結果
```console:１０回実行
>cscript pi.vbs
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

3.1413832
```
## 実行後のコード

```vb:１０回実行後のコード（自己拡張コードのみ）
' *** ここから自己拡張コード ***
piList.add 3.141336 ' 2019/05/30 20:57:10 に追加
piList.add 3.14266 ' 2019/05/30 20:59:10 に追加
piList.add 3.139868 ' 2019/05/30 20:59:12 に追加
piList.add 3.141932 ' 2019/05/30 20:59:13 に追加
piList.add 3.14216 ' 2019/05/30 20:59:14 に追加
piList.add 3.1392 ' 2019/05/30 20:59:16 に追加
piList.add 3.139744 ' 2019/05/30 20:59:17 に追加
piList.add 3.14188 ' 2019/05/30 20:59:19 に追加
piList.add 3.141728 ' 2019/05/30 20:59:20 に追加
piList.add 3.143324 ' 2019/05/30 20:59:21 に追加
' *** ここまで自己拡張コード ***
```

# せっかくなので１０００回実行

流石に実行結果のみで

## 実行結果

```console:１０００回実行
>cscript pi.vbs
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

3.14167134
```

んーイマイチ

# ここまできたら１００００回実行

１０００回の結果がイマイチだったので…

## 実行結果

```console:１００００回実行
>cscript pi.vbs
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

3.1415769512
```

まぁ、こんなもんですかね

# 感想

円周率の計算は正直オマケで、
Windows Script Hostがスクリプトファイルをロックしていない事実確認が出来て良かったです！

[^1]: 乱数をつかって試行を繰り返し、近似解を求める手法。詳しくはググって！
Cognos Analytics データモジュール ナビゲーションパスの作成

#データモジュールでのナビゲーションパスの作成
ドリルダウン&ドリルアップは、一階層上と下への移動ですが、ナビゲーションパスでは、一気に階層を飛ばして、他のデータアイテムに移動できます。
下の図では、「キャンプ用品」に応じた「製品ブランド」の表示に切り替える事が可能で、この様に他のデータアイテムに飛ぶ「ナビゲーション」をデータモジュールで作成します。
![007.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/9ae13a99-78c0-dc01-835a-b7891093456b.jpeg)


#手順
C3後の「製品販売_データ・モジュール」を開始点とする。
製品マスタ内の、「製品ライン_タイプ」「製品ライン」「製品タイプ」「製品」「製品ブランド」間を自由に行き来できる「製品ナビ」ナビゲーションパスを作成する。
![001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/c2029f32-5d0e-88b7-0947-297e49d74ff8.jpeg)

ナビゲーションパスに含まれる、何れかのデータアイテム（例では「製品ライン_タイプ」）の「・・・」から「ナビゲーション・パスの作成」を選択。
![002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/ef1aefcd-f7d6-4fa8-6f69-16b44e87b619.jpeg)

「製品ライン」をドラッグ&ドロップで、ナビゲーションパスに追加。
![003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/b4e38e87-8d32-ba5f-fdc3-e79d271cccae.jpeg)

同様に「製品タイプ」「製品」「製品ブランド」を追加し、名前を「製品ナビ」に変更し「OK」。
![004.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/7d373913-d3d5-614f-b5ed-2c60e2cf36c1.jpeg)

赤枠の「ナビゲーション・パス・メンバーの指定」をクリックすると、ナビゲーションパスに含まれるメンバーに下線が表示される。
![005.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/144e508c-67f3-8632-6f86-24313259c449.jpeg)

データモジュールを保存し「レポート」の機能で開く。

データモジュールの中身に「製品ナビ」が含まれているのが見える。
ここでは赤枠の「製品ライン」と「数量」をリストにドロップ。
![006.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/6c896594-add6-59a7-2598-5a60e4ba0578.jpeg)

レポートを実行。
「キャンプ用品」を選択し、赤枠の「ナビゲート」アイコンから「製品ナビ」を選択し「製品ブランド」をクリック。
![007.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/efe52c8c-8686-1e2a-da96-58396511369d.jpeg)

キャンプ用品に含まれる「製品ブランド」の一覧が表示される。
![008.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/85c17f1a-cd9a-9302-a4d8-dc6f8a772cf6.jpeg)

「トレイルシェフ」を選択し「製品」にナビゲート。
![009.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/c37b2225-ad72-d8cb-83c5-39b8b76ca159.jpeg)

「トレイルシェフ」ブランド内の製品一覧が表示される。
![010.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/a0f604ed-ce58-8583-df63-3c46f64f867d.jpeg)

「製品ライン_タイプ」にナビゲート。
![011.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/498ffb17-957e-b67b-966d-6e8985e8dbea.jpeg)

トレイルシェフに応じた「製品ライン_タイプ」が表示されるが、一度「製品ライン_タイプ」を全表示したいので、「フィルター」アイコンから「すべてのフィルターを削除」。
![012.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/ec9bc976-afa3-8e76-23fd-64414002d608.jpeg)

全ての「製品ライン_タイプ」が表示される。
![013.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/20a6bd08-de9f-7e09-c396-c5c6374cd5cb.jpeg)


#自己学習記事一覧
**Cognos Analytics をエンドユーザーの方に自己学習して頂くためのサイト**
https://qiita.com/shinyama/items/95885c7246dc413b6448
Postgres SQL で ユーザとデータベースを作成し、ユーザにデータベースを割り当てる方法



```
$ psql -U postgres
ユーザ postgres のパスワード:
psql (11.3)
"help" でヘルプを表示します。

postgres=# CREATE USER my_username WITH PASSWORD 'my_password';
postgres=# CREATE DATABASE database_name;
postgres=# GRANT ALL PRIVILEGES ON DATABASE "database_name" to my_username;
```
受けたメールをすべて捨てるSMTPブラックホールサーバの作り方① (updated 2019.6.10)

メールセキュリティプロダクトの開発やテスト、運用をしていると、メール送受信をテストすることが頻繁にあります。その時、どんなメールでもどこからのメールでもどこ宛てのメールでもすべて受け、すべて捨ててくれるブラックホールのようなメールサーバがほしくなります。

ということで、Postfixを使ってSMTPブラックホールサーバを作る方法を紹介します。今回はtransportを利用する方法で行います。

#### Postfixのインストール
CentOS7.4でyumを使ってインストールしました。

#### main.cfの設定
/etc/postfix/main.cfを編集します。
変えた項目は以下の通り。あくまで私の設定例です。

```
myhostname = example.com
mynetworks = 127.0.0.0/8, 172.16.0.0/24
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
local_recipient_maps = (※追加 2019.6.10)

transport_maps = hash:/etc/postfix/transport (※最後に追加)
```

#### transportの設定
/etc/postfix/transportを編集します。
変えた項目は以下のとおり。

```
* discard:discard(※最後に追加)
```

#### transportの設定反映
編集した設定を反映させます。

```
# postmap /etc/postfix/transport
```

#### Postfixのreload
postfixをreloadします。

```
# postfix reload
```

これで作業は完了です。telnetなどでメールを送ると、mailogに以下のようなPostfixがメールをdiscardしたログが出力されます。

```
postfix/discard[3765]: BB98CE72A9: to=<test@example.jp>, relay=none, delay=14, delays=14/0.01/0/0, dsn=2.0.0, status=sent (discard TRANSPORT(5))
postfix/qmgr[3593]: BB98CE72A9: removed
```

注意点はネットワーク設定です。攻撃の対象になることもあるので十分気をつけましょう。

次回はもっとスマートにmaster.cfの設定変更だけでSMTPブラックホールサーバを作る方法を紹介します。

*関連記事
*関連記事
[受けたメールをすべて捨てるSMTPブラックホールサーバの作り方①](https://qiita.com/qualitia_cdev/items/3ab284ca92939f58b9bb)
[受けたメールをすべて捨てるSMTPブラックホールサーバの作り方②]
(https://qiita.com/qualitia_cdev/items/85aaffcd5fddae5afb4c)
[受けたメールをすべて捨てるSMTPブラックホールサーバの作り方③ - Dockerを使う]
(https://qiita.com/qualitia_cdev/items/7f165e5f7e62e46ebe2b)
Java基本構文+αの罠


# if
```Java
boolean b = false;

if (b = true){
    System.out.println("true");
}else{
    System.out.println("false");
}
```
* trueが出力される

# switch
* 同一のcase分を複数定義するとコンパイルエラー
* defaultを先頭においても、正常に動作する
* 対象変数と分岐先の変数の型が不一致だとコンパイルエラー(暗黙型変換はあり)
* 使える型は、byte, short, int, char, String, enum

# while
```Java
int i = 0;
while(i++ < 10);{
    System.out.println("a");
}
```
はiがインクリメントされるだけ。

# break
ループ(for, while)とswitchのみ使用可能

# コンストラクタ
* this()の引数にthis.変数は使えない。

```Java
class Orange{
    int i;

    Orange(){
        this(this.i);
    } 

    Orange(int i){}
}
```

# 配列と可変コンテナ(StringBuilder, List)の初期化

```java
	public static void main(String[] args) {
		String ary[] = new String[3];
		System.out.println(ary.length);  // => 3
		
		StringBuilder sb = new StringBuilder(3);
		System.out.println(sb.length());  // => 0
		
		List<String> list = new ArrayList<String>(3);
		System.out.println(list.size());  // => 0
	}


```

# ジェネリクス
```java

public interface Portable<Integer>{
    public void handCarry(Integer weight);
}
```
をラムダ式で利用するとき、
### NGパターン

```java
Portable p = (Integer w) -> System.out.println(w);
```

### OKパターン

```java

Portable<Integer> p = (Integer w) -> System.out.println(n);

Portable p = w -> System.out.println(w);
```

# Streamのparalell()とreduce()を組み合わせて使用する際は順序が維持される。

```java

System.out.println(Stream.of("a", "b", "c", "d").parallel().reduce((x,y)->x+"-"+y).get());  // => 常にa-b-c-d

Stream.of("a", "b", "c", "d").parallel().forEach(System.out::print);  // => 順不同でa, b, c, dが出力される
```
Facebook広告：カスタムオーディエンス作成時の個人情報の取り扱い

#目的
広告を受け取る利用者を定義するにあたり、CRMデータやビジネスデータを所有する場面が出てくる。その際にデータの所有者は、このデータを作成して管理する責任を負うため、カスタムオーディエンスの作成方法と、その管理方法を理解する必要がある。本記事ではカスタムオーディエンスの作成方法とその管理方法について説明する。
#内容
###カスタムオーディエンス
####広告を受け取る利用者の定義
方法としては以下の2通りある。  
**ターゲット設定**：[ターゲット設定](https://developers.facebook.com/docs/marketing-api/buying-api/targeting)を参照
**オーディエンス**：広告を受け取る利用者のグループを独自に作成。カスタマーデータや、アプリまたはウェブサイト内でのアクティビティといったコンバージョンデータなどに基づいて作成できる
####CRMデータからのカスタムオーディエンス
CRMデータからターゲットにするカスタムオーディエンスを作成する。
**CRMデータ**：メールアドレス、携帯電話、指名、生年月日、性別、位置情報、アプリのユーザーID、ページ範囲のユーザーID、AppleのAdvertising Identifier(IDFA)、AndroidのAdvertising IDなどのカスタマー情報  

オーディエンスを作成する際、プライバシー保護のためにハッシュ化したデータをFacebookに提供する必要がある。Facebook側でこのデータをFacebook側のハッシュデータと比較し、広告主の広告のオーディエンスに追加するFacebook利用者を割り出す。
**※CRMやその他のビジネスデータの所有者は、このデータを作成して管理する責任を負う。**
**※1つのオーディエンスに追加できるレコード数に制限はないが、一度に追加できるのは最大10,000件。**
**※Facebookによりオーディエンスへ利用者が追加されるには最大1時間、オーディエンスから利用者が削除されるには最大で24次官かかる場合がある。**
####カスタムオーディエンスの作成
次の手順を実行。  
1. からのカスタムオーディエンス`subtype=CUSTOM`と`customer_file_source`を作成。
2. ユーザーをアップデートすることにより、利用者を追加または削除。
[手順詳細はこちら](https://developers.facebook.com/docs/marketing-api/audiences-api/?translation#build)
Craft CMS のテンプレートやエントリー URI 形式などでゼロパディングする

`"%05d"|format(123)` の形で桁数を指定しつつ format フィルタに数値をセットすると、ゼロパディングができる。

```twig
{% for i in 1..5 %}
  {{ "%03d"|format(i) }}<br>
{% endfor %}
```

この出力結果は下記になる。

```text
001
002
003
004
005
```

なお、`エントリー URI 形式` 欄など個別ページの URL を定義するにあたって同様のフィルタ処理を適用したい場合は

```
news/{{"%05d"|format(id)}}
```

のように二重括弧で括ればよい。
importについて

##書き方
```go
//ひとつのとき
import "fmt"

//複数のとき
import (
	"fmt"
	"time"
)
```
##注意
```go
package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("hello world")
}
```
`"time"`がインポートされてるのに、関数で使ってない場合はエラー扱いになる。

>参考
現役シリコンバレーエンジニアが教えるGo入門(https://www.udemy.com/share/100BhMB0obeFpbTX4=/)
[Java] Integerラッパークラスの参照

* newでインスタンス化すれば別の参照
* 数値で初期化した場合は、値の範囲が-128~127のときは等価

```Java
		Integer a = new Integer(1);
		Integer b = new Integer(1);
		System.out.println(a == b); // #=> false
```

```Java
		Integer c = 127;
		Integer d = 127;
		System.out.println(c == d); // #=> true
		
		c = 128;
		d = 128;
		System.out.println(c == d); // #=> false
```

### 参考
* [Chapter 5. Conversions and Contexts](https://docs.oracle.com/javase/specs/jls/se10/html/jls-5.html#jls-5.1.7)
FirefoxでYouTube埋め込みプレーヤーの画面が更新されなくなる場合の対処法

# 内容

YouTube Player APIを有効にした状態で、音声だけ再生が続き、動画のみ止まってしまう現象の回避方法です。
この現象は、プレーヤー本体に影響する要素へ`transform`プロパティが設定されていて、`transform-style`プロパティの値が`preserve-3d`になっていると発生します。
レンダリング最適化処理による誤動作だと思われますので、要素内を一定周期で変更し回避します。
下記コードでは、一秒毎にカスタムデータ属性を変更し、擬似要素内のテキストを変更しています。（レンダリングに影響がないようにプレーヤーの後ろに配置しています）

# コード

```HTML:HTML
<div id="youtube">
  <iframe width="560" height="315" src="https://www.youtube.com/embed/（動画ID）?enablejsapi=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
```

```CSS:CSS
#youtube {
  position: relative;
  width: 50%;
  transform-style: preserve-3d;
}

#youtube::before {
  display: block;
  padding-top: 56.25%;
  content: "";
}

#youtube::after {
  position: absolute;
  top: 0;
  z-index: -1;
  content: attr(data-dummytext);
}

#youtube iframe {
  position: absolute;
  top: 0;
  width: 100%;
  height: 100%;
  transform: translateZ(0);
}
```

```JavaScript:JavaScript
const element = document.getElementById('youtube');
setInterval(() => {
  element.setAttribute('data-dummytext', new Date().getTime());
}, 1000);
```
[Java] CollectionとStringBuilderの操作メソッド比較

|メソッド|  Collectionインターフェース  |  StringBuilderクラス  |
| ---- | ---- | ---- |
|追加|  add()  |  append()  |
|挿入|  add()  |  insert()  |
|削除|  remove(), removeAll(), removeIf()  |  delete(), deleteCharAt()|
|書き換え|  set(), replace()  |  setCharAt()|
|長さ|  size()  |  length()|

```Java

public static void main(String[] args) {

		StringBuilder sb = new StringBuilder(10);
		System.out.println(sb.length()); // #=> 0
		sb.append("123456", 1, 3);
		sb.append("a");
		sb.setCharAt(0, 'c');
		sb.insert(1, "d");
		System.out.println(sb);  // #=> cd3a
		sb.replace(0, 2, "ab");
		sb.delete(0, 1);
		sb.deleteCharAt(0);
		
		List<String> list = new ArrayList<>();
		list.add("a");
		list.add("a");
		list.add("a");
		list.set(0, "b");
		list.add(1, "b");
		System.out.println(list);  // #=> [b, b, a, a]
		list.remove(0);
		list.remove("b");
		list.removeIf(s -> s.length() > 2);
		System.out.println(list);  // #=> [a, a]
		list.removeAll(Arrays.asList("a", "b"));
		list.size();
	}

```

* appendはaddと違い、追加場所は指定できない。代わりにinsertを使う。


# 参考

* [StringBuilder (Java Platform SE 7 )](https://docs.oracle.com/javase/jp/7/api/java/lang/StringBuilder.html)
* [Collection (Java Platform SE 8 )](https://docs.oracle.com/javase/jp/8/docs/api/java/util/Collection.html)
C#（.NET Core2.2）アプリをLinuxで動かし、シェルスクリプトを実行したらエラー

# やりたいこと
- C#コンソールアプリにより、LinuxからWindowsのフォルダをマウントする（mountコマンド）
 - Windows10上の仮想マシン（Linux）で、C#アプリを動かす
 - C#アプリで、Linuxのシェルスクリプトファイル（.sh）を実行する
 - .shファイルに、mountコマンドを記述しておく

# 経緯
仕事で検証が必要になったため。

# 環境
- ホストマシン：Windows10
- ゲストマシン：CentOS 7（Windows10のVirtualBox上）
- 開発言語：C#（.NET Core2.2）
- エディタ、ビルド：Visual Studio Code 1.34.0（Windows10上）

# 手順
## 1. C#アプリの準備
### (1)「.NET Core SDK」をインストール（Windows10）
（今回は、.NET Core SDK 2.2.300）
https://dotnet.microsoft.com/download#/sdk

### (2)Visual Studio Codeに、C#拡張機能をインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384619/a4b8d9cd-5226-1cc8-94d3-27d0004b611a.png)

### (3)コーディング、ビルド
次のようなコードで、.shを実行します。（真新しいことはありません・・・）

```c#
using System.Diagnostics;
// （省略）
  var processInfo = new ProcessStartInfo();
  processInfo.FileName = "/bin/sh";
  processInfo.UseShellExecute = false;
  processInfo.RedirectStandardOutput = true;
  processInfo.Arguments = @"./xxx.sh";

  Process process = Process.Start(processInfo);
  var stdOutput = process.StandardOutput.ReadToEnd();
  process.WaitForExit();
```

Linux用に、自己完結型の展開でビルドしました。

```shell
dotnet publish -c Release -f netcoreapp2.2 -r linux-x64 --self-contained true
```

## 2. .shファイルの準備
次のようなコマンドを記述。
・share_test：VirtualBoxで設定した共有フォルダー名
・/mnt/win_test：Linux側の、マウントするディレクトリ

```shell:xxx.sh
sudo mount -t vboxsf share_test /mnt/win_test
```

# 確認結果
### エラー
Linux上でアプリを実行したところ、次のようなエラーが発生し、マウントされませんでした。

```
No such file or directory
```

### 確認
- コマンド自体は不備がない
　.shファイルに記述しているコマンドを、Linuxのターミナルで実行すると正常にマウントできます。

- C#から.shファイルの実行も問題なさそう
　また、.shファイルにecho XXというコマンドを記述すると正常に出力されます。

### 原因
.shファイル内の改行コードに問題がありました。
-> 改行が「Cr＋Lf」になっていた。
-> 「Lf」で保存したところ、正常にマウントできました。

Linuxは改行をLfで判断する為、記述したコマンドに「Cr」まで含まれてしまい、
そんなはパスは存在しないというエラーになっていたようです。
（Linuxをあまり使った事がなく、なかなか分かりませんでした・・・）

# 今後
結局、開発言語は関係なく、単にLinuxについて勉強不足という話でした。
きちんと勉強しようと思います。。
# 参考
↓この情報に辿り着くまで時間が掛かりました・・・
[シェルスクリプトを書くときに気をつける9箇条](https://qiita.com/b4b4r07/items/9ea50f9ff94973c99ebe)
GoでHelloWorld

##Hello World
```go
package main

import "fmt"

func main() {
	fmt.Println("hello world")
}

```
##main関数の中で関数は実行される
```go
package main

import "fmt"

func hoge() {
	fmt.Println("hoge")
}

func main() {
	hoge()
	fmt.Println("hello world")
}

```
`func hoge()`を実行したければ、`func main(){}`の中に呼び出そう。
##特殊な`func init()`
```go
package main

import "fmt"

func hoge() {
	fmt.Println("hoge")
}

func main() {
	hoge()
	fmt.Println("hello world")
}

func init() {
	fmt.Println("init")
}
```
`func init()`は一番最初に実行される関数。入門ではあまり扱われないが初期設定などで使われる。
出力結果は

```
init
hoge
hello world
```
##文字の連結
```go
package main

import "fmt"

func main()
	fmt.Println("hello world","fuga fuga")
}
```
`,`で区切れば良し。
##大文字小文字の違い
`fmt.Println`の`P`が大文字か小文字かで振る舞いが変わる。パブリックかプライベートか。
##メモ
- Goのプログラムはpackageで構成される
- プログラムはmain packageからスタートされる
- package名はインポートパスの最後の要素と同じ名前になる。例えば、インポートパスが`math/rand`のpackageでは`package rand`ステートメントで始まるファイル群で構成する。もし、URLを含むインポートパスが`golang.org/x/net/hoge`なら、`package hoge`になる。
- packageのライブラリ(https://golang.org/pkg/)

>参考
現役シリコンバレーエンジニアが教えるGo入門(https://www.udemy.com/share/100BhMB0obeFpbTX4=/)
AWS SDK for Go SNS コードサンプル

## 概要

公式Doc
https://docs.aws.amazon.com/ja_jp/sdk-for-go/v1/developer-guide/using-sns-with-go-sdk.html

## SNSと接続するインスタンスの生成

#### アクセスキーをローカルファイルから自動で読み込む場合

```go
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sns"

// ~/.aws/credentialsからアクセスキーを読み込む
sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))
svc := sns.New(sess)
```

#### アクセスキーを明示する場合

```go
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sns"

creds := credentials.NewStaticCredentials("AWS_ACCESS_KEY", "AWS_SECRET_ACCESS_KEY", "")
sess, err := session.NewSession(&aws.Config{
    Credentials: creds,
    Region:      aws.String("ap-northeast-1"),
})
if err != nil {
    fmt.Println(err)
}

svc := sns.New(sess)
```

## すべてのトピックに関する情報を取得する

### ListTopics()

`func (c *SNS) ListTopics(input *ListTopicsInput) (*ListTopicsOutput, error)`

```go
result, _ := svc.ListTopics(nil)
for _, t := range result.Topics {
    fmt.Println(*t.TopicArn)
}
```

## トピックの作成

### CreateTopic()

`func (c *SNS) CreateTopic(input *CreateTopicInput) (*CreateTopicOutput, error)`

```go
result, _ := svc.CreateTopic(&sns.CreateTopicInput{
    Name: aws.String("test-topic"),
})

fmt.Println(*result.TopicArn)
```

## トピックのサブスクリプションに関する情報を取得する

### ListSubscriptions()

`func (c *SNS) ListSubscriptions(input *ListSubscriptionsInput) (*ListSubscriptionsOutput, error)`

すべてのサブスクリプションを取得する

```go
result := svc.ListSubscriptions(nil)

for _, s := range result.Subscriptions {
	fmt.Println(*s.Endpoint)
	fmt.Println(*s.Owner)
	fmt.Println(*s.SubscriptionArn)
	fmt.Println(*s.TopicArn)
}
```

### ListSubscriptionsByTopic()

`func (c *SNS) ListSubscriptionsByTopic(input *ListSubscriptionsByTopicInput) (*ListSubscriptionsByTopicOutput, error)`

TopicArnからサブスクリプションを取得する

```go
result, _ := svc.ListSubscriptionsByTopic(&sns.ListSubscriptionsByTopicInput{
		TopicArn: aws.String("arn:aws:sns:ap-northeast-1:1234567890:test-topic"),
	})

for _, s := range result.Subscriptions {
	fmt.Println(*s.Endpoint)
	fmt.Println(*s.Owner)
	fmt.Println(*s.SubscriptionArn)
	fmt.Println(*s.TopicArn)
}
```

## トピックのサブスクリプションを作成

### Subscribe()

`func (c *SNS) Subscribe(input *SubscribeInput) (*SubscribeOutput, error)`

eメールアドレスをトピックに登録してサブスクリプションを作成する

```go
result, _ := svc.Subscribe(&sns.SubscribeInput{
	Endpoint:              aws.String("example@example.com"),
	Protocol:              aws.String("email"),
	ReturnSubscriptionArn: aws.Bool(true),
	TopicArn:              aws.String("arn:aws:sns:ap-northeast-1:1234567890:test-topic"),
})

fmt.Println(*result.SubscriptionArn)
```

## トピックのサブスクライバーにメッセージを送信

### Publish()

`func (c *SNS) Publish(input *PublishInput) (*PublishOutput, error)`

```go
input := &sns.PublishInput{
	Message:  aws.String("Hello world!"),
	TopicArn: aws.String("arn:aws:sns:ap-northeast-1:1234567890:test-topic"),
}
result, _ := svc.Publish(input)

fmt.Println(result)
```
Rails6 のちょい足しな新機能を試す28（ActiveSupport::TaggedLogging編）

# はじめに

Rails 6 に追加されそうな新機能を試す第28段。 今回は、 `ActiveSupport::TaggedLogging` 編です。
Rails 6 では、 `ActiveSupport::TaggedLogging.new` の動作が変わります。
これまでは、引数で指定されたLogger オブジェクトを返していましたが、dup したオブジェクトを返すようになりました。

実際に Logger オブジェクトを作って、ログ出力して確認した方がわかりやすいので、試してみます。

Ruby 2.6.3, Rails 6.0.0.rc1 で確認しました。Rails 6.0.0.rc1 は `gem install rails --prerelease` でインストールできます。

```shell
$  rails --version
Rails 6.0.0.rc1
```

# Rails プロジェクトを作る

```shell
$ rails new rails6_0_0rc1
$ cd rails6_0_0rc1
```

# Controller と View を作る

ログ出力するため、Controller と View を作ります。

```shell
$ rails g controller tagged_logging index
```

# controller でログ出力する

controller で、ログ出力するように修正します。

- logger0 は `Logger.new`
- logger1 は `ActiveSupport::TaggedLogging.new(logger0)`
- logger2 は `ActiveSupport::TaggedLogging.new(logger1)`

として、それぞれのオブジェクトからログ出力します。

```ruby:app/controllers/tagged_logging_controller.rb
class TaggedLoggingController < ApplicationController
  def index
    logger0 = Logger.new(Rails.root.join('log', Rails.env + '.log'))
    logger1 = ActiveSupport::TaggedLogging.new(logger0)
    logger2 = ActiveSupport::TaggedLogging.new(logger1)
    logger1.tagged('TAG1') do
      logger2.tagged('TAG2') do
        logger0.info("log by logger0(id = #{logger0.__id__})")
        logger1.info("log by logger1(id = #{logger1.__id__})")
        logger2.info("log by logger2(id = #{logger2.__id__})")
      end
    end
  end
end
```

# rails server を実行してブラウザで表示する

`rails server` を実行して、ブラウザで http://localhost:3000/tagged_logging/index にアクセスします。

# log/development.log を確認する

log ファイルを確認すると、logger0, logger1, logger2 の出力がそれぞれ異なっていることがわかります。
また、 logger0, logger1, logger2 が異なるオブジェクトであることがわかります。

```log/development.log
I, [2019-05-28T13:34:30.186276 #254]  INFO -- : log by logger0(id = 47414341832000)
[TAG1] log by logger1(id = 47414341831820)
[TAG2] log by logger2(id = 47414341831700)
```

# Rails 5.2.3 では

Rails 5.2.3 では、logger0, logger1, logger2 ともに同じオブジェクトになるため、タグとオブジェクトのIDが同じになります。

```log/development.log
[TAG1] [TAG2] log by logger0(id = 47309018280300)
[TAG1] [TAG2] log by logger1(id = 47309018280300)
[TAG1] [TAG2] log by logger2(id = 47309018280300)
```

# 試したソース

試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try028_tagged_logging

# 参考情報

* [What is new in Rails 6.0](https://bogdanvlviv.com/posts/ruby/rails/what-is-new-in-rails-6_0.html)
* [TaggedLogging to return a new logger instance](https://github.com/rails/rails/pull/27792)
Androidアプリ64bit化必須に向けて検証デバイスのABIを調べる方法


#**Androidアプリ64bit化必須に向けて検証デバイスのABIを調べる方法**

![スクリーンショット1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51578/2c1bcccf-a9ef-62f7-3a8e-61aa2f66c958.png)
https://developer.android.com/distribute/best-practices/develop/64-bit

上記ページのとおり、
2019年8月1日以降、GooglePlayで公開するアプリは 64bitアーキテクチャをサポートする必要があるとのこと。
更には2021年8月1日から64bit版が含まれていないアプリはGooglePlayから排除されるとのこと。

アプリ(apk)を64bit対応することはもちろん、
その後に64bit対応端末できちんと動作するのかを検証する必要があります。

そこで手持ちのデバイスの**CPUアーキテクチャー**が何なのか、
**サポートしているABI**は何なのかを調べる方法を以下に掲載します。

※ABIの詳しい内容については以下ページにあります。
https://developer.android.com/ndk/guides/abis#sa
###**■ABI分類**
|プラットフォーム|32bitライブラリ|64bitライブラリ|
|:----------:|:-----:|:------:|
|ARM|armeabi, armeabi-v7a|arm64-v8a|
|x86|x86|x86_64|

###**■adbコマンドで調べる**
1. USBなどで調べたいデバイスをPC/Macに繋げる
2. コンソール(ターミナル)を開く
3. 以下adbコマンドを実行する

<pre><code>
$ adb shell getprop ro.product.cpu.abi
</code></pre>

実際の実行例
```$ adb shell getprop ro.product.cpu.abi
arm64-v8a
```

これで完了。

---
とは言え、現存のデバイスは、
ARMであれば、上記結果が**arm64-v8a**であっても、
下位互換性があるようなので、
**armeabi**, **armeabi-v7a**もサポートされるため、
結局のところ**arm64-v8a**がなくても、
動作確認はできてしまう。

<pre><code>
// Your app's build.gradle
    apply plugin: 'com.android.app'

    android {
       compileSdkVersion 27
       defaultConfig {
           appId "com.google.example.64bit"
           minSdkVersion 15
           targetSdkVersion 28
           versionCode 1
           versionName "1.0"
           ndk.abiFilters 'armeabi','armeabi-v7a','arm64-v8a','x86','x86_64'
    // ...
</code></pre>
*app/build.gradle*

ためしに**AndroidStudio**で確認してみる

1. app/build.gradleを開く
2. ndk.abiFiltersからarm系('armeabi','armeabi-v7a','arm64-v8a')を外す
3. 繋いだデバイスの実行を試みる（繋いだデバイスのABIは'arm64-v8a'）

![スクリーンショット2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51578/b2f66d81-609d-5aaa-fdde-d999d1cbb995.png)

`Device supports arm64-v8a, armeabi-v7a, armeabi, but APK only supports x86, x86_64`
とエラーが表示される

**armeabi**か**armeabi-v7a**どちらかが含まれていればエラーは表示されず、正常に動作するため、ABIが**arm64-v8a**のデバイスで64bitライブラリがなくとも、32bitのライブラリで動作することが分かる
Flutter for Webを動かしてみた

「Flutter for web」なるものが発表されたみたいなので、試してみた。

https://flutter.dev/web
まだプレビュー版みたいです。

# 環境構築
　以下のflutter_webリポジトリにスタートアップ手順が書いてあるので、それに従って進めます
　https://github.com/flutter/flutter_web
## 実行環境
- Windows10

## 前提
　Flutterの環境構築は終わってるものとします。
　参考：[Flutter環境を作ってみた（Windows）](https://qiita.com/teracy55/items/844f79dfdfd4b011780b)

## 手順
- webdevパッケージをインストールします

```
$ flutter pub global activate webdev
```

- 環境変数に「$HOME/.pub-cache/bin」を追加します

- flutter_webリポジトリをローカルに持ってきます
- hello_worldプロジェクトに移動します

```
$ cd examples/hello_world/
```

- hello_worldプロジェクトの関連パッケージをインストールします

```
$ flutter pub upgrade
```

- プロジェクトを起動します

```
$ webdev serve
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/17890fd3-7b02-eac1-9fde-d84fbbe0ce41.png)
⇒webdevコマンドが見つからない。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/4aa33890-6317-785e-66b4-a360922b5c06.png)
⇒PowerShellで実行したらコマンドは見つかるけど、動かない。。。


[ここ](https://github.com/flutter/flutter_web#install-the-flutter_web-build-tools)に書いてありました。
>> Note: if you have problems configuring webdev to run directly, try:
flutter pub global run webdev [command].

⇒`webdev`が直接呼べない場合は`flutter pub global run webdev [command]`を試してねということだそうです

- いわれたとおりに試してみます

```
$ flutter pub global run webdev serve
```

- 起動しました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/6b93db6e-8d4a-5bc7-bdd0-cb3336851215.png)
※空行が大量に出てきたため、削除してます。

# ブラウザからアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/a3cffa59-4bac-6c7c-1169-5673a5e79a24.png)

表示されました！！！


# 他のサンプル
他にもおしゃれなサンプルがいくつかありました！
https://flutter.github.io/samples/

実際に動かせるし、ソースコードも見れるので、今後参考にしながら何か作ってみようかと思います。
AWS Step Functionsのオンラインセミナー受けてみた

「[AWS Black Belt Online Seminar AWS Step Functions](https://www.slideshare.net/AmazonWebServicesJapan/20190522-aws-black-belt-online-seminar-aws-step-functions)」の自分向けメモ
Step Functions使ったことあるレベルの人向け


## Step Functions概要
 - マイクロサービスをオーケストレートするサービス
    - 各サービスをステートマシンと呼ばれる仕組みでつなぐ
 - 実行履歴のログトレースが可能

## ステートマシン
 - ASL（Amazon States Language）と呼ばれるJSON形式の言語で定義されるワークフロー
 - ASLチェックツールがある
 - 作成したステートマシンは複数種類の同時実行が可能

### ステートマシンの起動方法は以下
 - Amazon CloudWatch Events
 - Amazon API Gateway
 - AWSコンソール
 - AWS CLI
 - AWS Lambda
 - EC2に実装したアプリ

### ステートマシンから実行可能なサービスは以下
 - AWS Lambda
 - Amazon DynamoDB
 - AWS Batch
 - Amazon ECS
 - Amazon SNS
 - Amazon SQS
 - AWS Glue
 - Amazon SageMaker

### Activity
 - サーバー等のアプリからポーリングが可能
 - アプリから死活監視を行うことが可能

## データの入出力
### InputPath
 - 渡された入力データを取捨選択し、State内で利用する
 - 取得しなかった情報は後続のStateに渡らない？

### Parameters
 - 入力データを生成し、State内で利用する
 - JSON形式で生成可能

### ResultPath
 - Stateの実行結果を受け取るキーを指定する
 - 入力データと実行結果をマージして後続のStateに渡す
 - Stateの実行結果を受け取るキーを指定しなかった場合、実行結果のみを後続のStateに渡す
 - InputPathで取得しなかった情報でも、指定すれば後続のStateに渡せる？

### OutputPath
 - 後続のStateに渡す情報を取捨選択する
 - 未指定の場合はResultPathが全て後続のStateに渡る

### その他
 - Comment：任意のコメントを記述できる
 - StartAt：最初に実行するStateを指定する
 - TimeoutSeconds：ステートマシン全体のタイムアウト秒を指定する
 - Version：ASLのバージョン
 - States：Stateを記述する

## Stateの記述
### Stateの種類
#### Task
 - 基本的なStateでLambdaやDynamoDB、SNSを呼び出す
 - Parametersで呼び出すサービスに渡す情報をセットする

#### Wait
 - 指定された時間待機した後、次のStateに移る
 - 待機時間秒や待機期限日時などで指定できる

#### Pass
 - 何もせずに次のStateに移る

#### Parallel
 - 並列にStateを実行する
 - 並列実行したStateが1つでも失敗になるとParallel配下のStateが全て失敗扱いになる
 - Branches内にStartAtとStatesを複数記述する

#### Choice
 - 指定した条件にマッチするか、それ以外（Default）かで分岐させる
 - 条件指定は複数可能
 - 多くの比較演算子が利用可能
 - 異なる型（数値と文字列）の比較はできない
 - StringEqualsで文字列としての数値の比較はできない（NumericEqualsを使う）

#### Fail
 - ステートマシンの実行を失敗として終了させる

#### Succeed
 - ステートマシンの実行を成功として終了させる

### エラー判定
 - タイムアウトやState失敗などエラー内容を区別できる
 - 呼び出したLambadaのエラー内容を区別することも可能

#### Retry
 - Task、ParallelではRetryが指定でき、エラー時に再試行が可能

#### Catch
 - Task、ParallelではCatchが指定でき、エラー時に遷移させるStateを指定可能

## 実行状況の確認
 - AWSコンソールからStateごとの実行結果の確認が可能（エラー内容も確認できる）
 - 実行結果の変化をトリガーにCloudWatch Eventにイベント発行が可能
 - メトリクス収集も可能
    - ExecutionTime：実行時間
    - ExecutionThrottled：スロットリングされた実行数
    - ExecutionAborted：中断された実行数
    - ExecutionFailed：失敗した実行数
    - ExecutionStarted：開始された実行数
    - ExecutionSucceeded：正常終了した実行数
    - ExecutionTimedOut：タイムアウトした実行数

## 補足や料金
### 料金
 - 状態遷移回数での従量課金
 - 状態遷移：Start⇒State、State⇒State、State⇒Endをそれぞれ1回とカウント
 - 4000回/月は無料

### AWS Step Functions Local
 - ローカル環境でStep Functionsのテストができる

### 他サービスとの使い分け
#### SQS
 - サービス間のメッセージを受け渡す点は同じ
 - スケーラブルな要求ならSQS
 - 処理の追跡が必要であればStep Functions

#### SWF
 - ワークフロー制御する点は同じ
 - 高機能なことをするならSWF
 - 新規開発するならStep Functions

## まとめ
 - アプリの構築が容易、構成を可視化
 - 余分なコーディングなしでアプリの構成できる
 - エラー処理も構築できかつトレース可能
《備忘録》Laravelの記事とコマンドとか

Laravelの学習書籍とかUdemyとか。
フレームワークについてはrailsを最初だったが、内定をとるということに関してはPHPとLaravelをやった方が良いと思われたので、そちらに移行した。

##Laradock導入に際して

https://qiita.com/skmt719/items/a296d81150fd7319e71a
nginxのポートを変える
dockerを再度立ち上げることの重要性
Laradockの導入


##Vue.jsとLaradockの関連
についての記事置き場
https://teratail.com/questions/122336



Laravelコマンド
```
###php artisanコマンドを使ってコントローラー・モデル・マイグレーションファイルを生成する。

```
コントローラーの作成
$php artisan make:controllerコントローラー名

リソースフルなアクションを自動で定義したコントローラーを生成
$php artisan make:controller ArticlesController -r

モデルの作成
$php artisan make:model モデル名

モデルとマイグレーションファイルの生成
$php artisan make:model Article -m

マイグレーションファイルの作成
$php artisan make:migrationマイグレーションファイル名
$php artisan make:migrattion create_login_table —create=users

＄php artisan make:model Task -m -c -r
```
(—resourceでも可)
https://qiita.com/33yuki/items/7bab0d596ae9a0930f18

https://qiita.com/sympe/items/9297f41d5f7a9d91aa11
Resourceを用いた対応するコントローラーとメソッドの自動生成


```
$ php artisan make:controller PhotoController --resource
// show、updateのルーティングを削除
// onlyを使う方法
Route::resource('hoge', 'HogeController', ['only' => ['index', 'create', 'edit', 'store', 'destroy']]);
// exceptを使う方法
Route::resource('hoge', 'HogeController', ['except' => ['show', 'update']]);
```

###ローカルに繋ぐ

```
$php artisan serve
```

###Docker内でmigrateをする。

```
＄cd laradock
＄docker exec -it laradock_workspace_1 bash
＄php artisan migrate 
$php artisan migrate:refresh
```

###migrateした後にDocker内のmysqlに繋ぐ

```
$docker exec −it laradock_mysql_1 bash
$mysql -u root -p
```
###mysqlにログインするためのパスワードmysqlにログインするためのパスワード

```
$use データベース名
$show tables;
```
@csrf
Cross-site request forgery(偽造)


###ルーティングの設定

```
$Route::get('/index', 'HelloController@index');
$Route::get('/index’, function () {
return view(‘index’);
});
```


###シーダー関連

```
・シーダーファイルの作成
$php artisan make:seeder PhotoTableSeeder
コンポーザーのオートローダー(エラーが出た際）
$ composer dump-autoload
全てのSeederを実行
$ php artisan db:seed
・指定したSeederクラスを実行
php artisan db:seed --class=CategoriesTableSeeder
・マイグレーションファイルとシーダーファイルのリフレッシュ
$php artisan migrate:refresh --seed
.envファイルの編集時やること
php artisan config:cache
```

Laravelコマンド集
https://qiita.com/ChiseiYamaguchi/items/46c0e969d6323b15c888

Facadesはどこから使うか。
https://public-constructor.com/laravel-what-is-facade/

##使った教材とか
LEARNING PATH: Laravel: Complete Guide to Laravel
https://www.udemy.com/share/1005V2BEYSd1dXRng=/

Real Time Single Page Forum App with Pusher Laravel & vuejs
https://www.udemy.com/share/101cdYBEYSd1dXRng=/

Projects in Laravel: Learn Laravel Building 10 Projects
https://www.udemy.com/share/1002YSBEYSd1dXRng=/

PHPフレームワーク Laravel入門
https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF-Laravel%E5%85%A5%E9%96%80-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798052582

Laravel リファレンス[Ver.5.1 LTS 対応] Web職人好みの新世代PHPフレームワーク
https://www.amazon.co.jp/Laravel-%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9-Ver-5-1-LTS-Web%E8%81%B7%E4%BA%BA%E5%A5%BD%E3%81%BF%E3%81%AE%E6%96%B0%E4%B8%96%E4%BB%A3PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF/dp/4844339451
アジャイル開発・スクラム開発に関する良記事まとめ

アジャイル開発・スクラム開発について大体はわかったが詳しい所が分からなかったので、色々まとめて見ました。
主に次に入る会社でスクラム開発をするみたいなので、軽くそれについて勉強している感じがあります。
ただの備忘録みたいな記事なので、読み飛ばして大したことはないので、
もうスクラム開発について知っているという人はブラウザバックをお願いします。


####アジャイル開発～顧客を巻き込みチーム一丸となってプロジェクトを推進する～ （前編）
https://www.nec-solutioninnovators.co.jp/column/01_agile.html
アジャイル開発に関してざっくりわかるのは良いと思われた。
・アジャイル開発の利点
・ウォーターフォール型VSアジャイル開発
・スクラム開発⊂アジャイル開発の関係性


####スクラムの概要を1分で理解できるイラスト【2018版】
https://www.ryuzee.com/contents/blog/7124

####スクラムで失敗する5大理由とその対策としてできること
https://postd.cc/5-reasons-why-scrum-fails-and-what-you-can-do-to-overcome-them/
スクラム開発のマイナス面をあげた記事
1. 組織の賛同が得られていない
2. スクラムの導入を急ぎすぎる
3. 計画の失敗
4. アジャイル方式に関する知識や経験が足りない
5. スクラムがその組織に適したフレームワークではない
雑にまとめると、スクラムに関する知識やスクラムを導入する意義付けがチーム内で共有出来ていない場合は失敗するとみて良いらしい。
【備忘録】よく使うDockerコマンド・ウェブサイト

###使う利点
・Security：複数人環境での環境の際をなくす
・Speed：開発環境の構築までのスピードを早くする

起動中のDockerコンテナの表示

```
docker ps
```
Docker-composeファイルの全削除

```
コンポーザーのアップデート
$composer update
全コンテナ停止
$docker stop (docker ps −q)
全コンテナ削除
$docker rm (docker ps −q −a)
全イメージ削除
$docker rmi (docker images −q)
laradock追加 
$docker-compose up -d mysql nginx php-fpm workspace
```

Dockerコンテナに入る

```
$docker exec -it [コンテナ名] bash
```

mysqlにアサイン

```
$mysql −u root −p
$use [データベース名]
$show tables;
$drop table [テーブル名];
```