OmniAICreator/Qiita-1.07M huggingface dataset:
[Go] 並列処理と非同期処理

Goで並列処理。非同期処理を組み合わせた場合どう書く

<h1>使うもの</h1>
<i>sync package (https://golang.org/pkg/sync/)</i>
※ 非同期処理


<i>go routine</i>
※ 並列処理



<h2>コード</h2>


```lang:go
package main

import (
    "fmt"
    "sync"
    "time"
)

const (
    MAX_EXECUTION_COUNT = 10 // 実行回数
    CONCURRENT_COUNT = 5　　　// 同時実行数
)


func main() {
    fmt.Printf("Start : %s \n", time.Now())
    res := make(chan string, MAX_EXECUTION_COUNT)
    concurrent := make(chan string, CONCURRENT_COUNT)
    defer close(res)
    defer close(concurrent)

    var results []string
    var wg sync.WaitGroup
    wg.Add(MAX_EXECUTION_COUNT) // 非同期処理のカウンターをセット
    for i := 0; i < MAX_EXECUTION_COUNT; i++ {
        go func(res chan string, concurrent chan string, no int, wg *sync.WaitGroup) {
            defer wg.Done() // defer で waitGroupのカウンターを減少
            name := fmt.Sprintf("No. %d", no)

            concurrent <- fmt.Sprintf("%s execute %s", time.Now(), name) // 同時実行カウンターをアップ（makeで変数サイズを固定。待機する）
            time.Sleep( 5 * time.Second)
            fmt.Printf("%s wait 5seconds. \n", name)
            res <- fmt.Sprintf("%s response %s", time.Now(), name) // 結果に詰めていく
            <- concurrent // 同時実行カウンターの開放
        }(res, concurrent, i, &wg)
    }
    wg.Wait() // 非同期処理が終わるまで待つ

    for {
        results = append(results, <- res) // 一つづつ結果を別変数に
        if len(res) <= 0 {
            break
        }
    }

    fmt.Printf("End : %s \n", time.Now())
}
```
Wio Teriminalでネコ走らせてみた🐈(2)

[Wio Teriminalでネコ走らせてみた🐈](https://qiita.com/eurogrve/items/53f9ee368fab0d6f1d52)の続きです。

# 謝辞

@Kyome さんから[高解像度の画像](https://github.com/Kyome22/menubar_runcat/tree/master/resources/cat/svg)があることを教えて頂きました。

教えて頂いた恩は、実装して返さねばいけませんので、高解像度画像を使うように改良してみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">原作者に高解像度の画像の置き場所を教えて頂いたので利用してみた。省メモリのために2値画像。<br>スプライトを使って高速描画。<br>なぜか画面下側にノイズが乗るけど...<a href="https://t.co/liilhzH8Cp">https://t.co/liilhzH8Cp</a><a href="https://twitter.com/hashtag/WioTerminal?src=hash&amp;ref_src=twsrc%5Etfw">#WioTerminal</a><a href="https://twitter.com/hashtag/LovyanGFX?src=hash&amp;ref_src=twsrc%5Etfw">#LovyanGFX</a><a href="https://twitter.com/hashtag/RunCat?src=hash&amp;ref_src=twsrc%5Etfw">#RunCat</a> <a href="https://t.co/6N0dxoeYJr">pic.twitter.com/6N0dxoeYJr</a></p>&mdash; たかよひ (@TKawamorita) <a href="https://twitter.com/TKawamorita/status/1297934523728973826?ref_src=twsrc%5Etfw">August 24, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## ソース

こちらからドウゾ。
https://github.com/t-kawamorita/RunCat_for_WioTerminal


## ポイント(って程でもないですが)

### ■ 自動化
ImageMagickやsedを使って、SVG画像をC言語のデータ定義に出力するスクリプトを書いた。
※これが一番時間かかった....

### ■ メモリ削減
SVG画像をPGMに変換したところ1ピクセルあたり1byteなのでWio Terminalで使用するとメモリ使用量が75%となった。
幾つかの解像度の画像を持つことが出来ないのでPBMに変換する。
それでも1ピクセルあたりのサイズは変わらないので、sedを使って8ピクセル分を正規表現をメモリ削減。
圧縮するかとも思ったが未対応。...

```bash
sed -e '1,3d' -e "s/ //g" -e "s/\(........\)/0b\1,/g" -e "s/^/  /" 入力ファイル
```

### ■ 描画のチラつき改善
320 x 206ピクセルの画像を1ピクセルずつ描画する体たらくなので描画のチラつきが発生するようになった。
スプライトを動的に作成しつつ、描画することでチラつきは、あまり感じなくなったかな？
たったの3秒でJava環境を作る方法

## はじめに
Dockerというソフトウェアを活用してjavaの環境を一瞬で作る方法について解説します。
いくつかのJavaのバージョンをローカルマシンで管理することによってバグが発生。なんてことはこれでおしまいです。

## 作業　
任意の名前のディレクトリを作成します。次にDockerfileとMain.javaをそのディレクトリの中に作成します。
内容は次の通りです。

```Dockerfile:Dockerfile
FROM openjdk:7
# Dockerfileのあるディレクトリの中のファイルをコンテナに保存する。
COPY . /usr/src/myapp
# 作業ディレクトリを指定する
WORKDIR /usr/src/myapp
# コンテナ内でコンパイルする
RUN javac Main.java
# コンテナで"java Main"を実行する
CMD ["java", "Main"]
```

```Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World!!");
    }
}
```

次にDocker imageを作成します。
カレントディレクトリで以下のコマンドを実行します。

```shell
docker build -t java_image .
```

次に作成したimageをコンテナにします。

```shell
docker run -t java_image
```

するとMainが実行され次のように出力されます。

```
Hello World!!
```

Dockerについて手を動かしながら学びたいという方は次の一冊がおすすめです。

<a href="https://www.amazon.co.jp/%E3%81%9F%E3%81%A3%E3%81%9F1%E6%97%A5%E3%81%A7%E5%9F%BA%E6%9C%AC%E3%81%8C%E8%BA%AB%E3%81%AB%E4%BB%98%E3%81%8F%EF%BC%81-Docker-Kubernetes%E8%B6%85%E5%85%A5%E9%96%80-%E4%BC%8A%E8%97%A4-%E8%A3%95%E4%B8%80-ebook/dp/B08CMMN45Z/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=Dokcer+kubernetes+%E8%B6%85%E5%85%A5%E9%96%80&qid=1598285130&sr=8-1-fkmr0&linkCode=li2&tag=qiita08-22&linkId=74b38dbe92634b0cdd161f43398ba4c0&language=ja_JP" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B08CMMN45Z&Format=_SL160_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=qiita08-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=qiita08-22&language=ja_JP&l=li2&o=9&a=B08CMMN45Z" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

<a href="https://amzn.to/3gpQcKX">伊藤 裕一 : たった1日で基本が身に付く！ Docker/Kubernetes超入門</a>
【Nuxt.js】データ・状態の一元管理（Vuex）を試してみた【勉強３】

## はじめに

自分が勉強した内容のまとめなので、正確性は保証しません。

[こちらのサイト](https://moneyhack.tech/07-nuxt/)にcodesandboxを埋め込んでいます。

実際の振る舞いを見ながらコードの確認ができるので非常に便利です。

https://moneyhack.tech/07-nuxt/

シンプルにcodesandboxめちゃくちゃおすすめなので、気になる方使ってみてください。

# データ・状態の一元管理(Vuex)とは

今回はデータ・状態の管理に用いられる Vuex について紹介します。

プロジェクト内で複数のページ、コンポーネントを作成していると、

共通のデータを用いたい時が出てくると思います。

そんな時にデータの保管場所となってくれるのが、「Vuex」というプラグインです。

[Vuex の公式サイト](https://vuex.vuejs.org/ja/)

**※対象読者**

Vue.js - HTML/CSS/Javascript を簡単に書けるフレームワーク

Nuxt.js - Vue.js をさらに便利にしたもの

WEB 系プログラムは触れたことがないが、上記くらいの知識を持っている。

プログラミングはやってみたいが、できる自信はない。緩く学びたい人。

## 利用するフォルダの確認と実装イメージ

Vuex では pages フォルダだけでなく、store フォルダも利用していきます。

- store フォルダ：Vuex に格納する変数や必要な処理を用意します。

- pages フォルダ：Vuex に格納した変数を取り出したり、格納したりします。

実際に Vuex を用いたカウントページを作成しました。

Home Page と About Page で count データを共有出来ていることがわかると思います。

[こちらのサイト](https://moneyhack.tech/07-nuxt/)にcodesandboxを埋め込んでいますので、実際の振る舞いをご確認ください。

codesandbox のページをリロードすると、保管していたデータが消えていることがわかると思います。

これは、ブラウザ上にデータを保管していることで起きる現象です。

リロードしてもデータを消さないようにするには、ストレージを用意する必要があります。

Firestore など外部にストレージを用意するか、

vuex のプラグインである「vuex-persistedstate」を使い、

ローカルストレージ（cookie と似たようなイメージ）を用意することで、

リロードしてもデータを消さない WEB ページを実装することができます。

## Vuex のコードの解説

**store フォルダの実装**

store フォルダに格納された index.js を見ていきましょう。

    export const state = () => ({
      count: 0
    });

    export const mutations = {
      increment(state) {
        state.count++;
      },
      decrement(state) {
        state.count--;
      }
    };

上記のコードは大きく 2 つの役割に分かれています。

「データの定義」と「データの操作」の定義です。

次のコードがデータを定義しているコードになっています。

    export const state = () => ({
      count: 0
    });

コード自体は非常にシンプルであり、ここで定義したデータが store に保持されます。

次のコードはデータを操作しているコードです。

    export const mutations = {
      increment(state) {
        state.count++;
      },
      decrement(state) {
        state.count--;
      }
    };

store 内のデータを操作できるのは、mutations に記載された操作からのみです。

今回のサンプルのように、pages フォルダや components フォルダに格納された vue ファイルからこれらの操作を呼び出し、データの変更を行います。

実際に呼び出している pages の index.vue ファイルがこちらです（script のみ抜粋）

    <script>
    export default {
      computed: {
        count() {
          return this.$store.state.count;
        }
      },
      methods: {
        increment() {
          this.$store.commit("increment");
        },
        decrement() {
          this.$store.commit("decrement");
        }
      }
    };
    </script>

上から少しずつ解説していきます（正しく解説出来ているかは怪しい）

次のコードで store に定義したデータを呼び出しています。

    this.$store.state.count

store から呼び出した state.count を return で count に格納しています。

次が store に定義した操作を呼び出しているコードです。

    this.$store.commit("increment")

先ほど store で定義した increment の操作を呼び出し、count の値を変更しています。

## おわり

以上が vuex を用いたデータの共有と同期的な操作のやり方です。

データの管理まで出来れば、簡単なアプリケーションを作ることもできると思います。

お疲れ様でした。
GitHubプロフィールにブログやQiitaの最新記事を表示する

こんにちは.

皆様, [GitHub Profile README](https://docs.github.com/en/github/setting-up-and-managing-your-github-profile/managing-your-profile-readme) は使っていますか？ GitHub のプロフィールページに任意の Markdown 文章を表示できるアレです.

私も最初は名前とリンクだけを適当に貼ったページを用意していましたが, [GitHub Readme Stats](https://github.com/anuraghazra/github-readme-stats) を見つけてから, README のカスタマイズが楽しくなってしまいました.

# ブログの新着記事を表示したい

本題です.

GitHub で, 生やした草やリポジトリに加え, README でアピールできるようになった今, プロフィールを見に来てくださった人に最新のブログ記事や Qiita 記事更新をアピールしたくないですか？

というわけで, RSS フィードから最新記事を取得して Markdown を自動更新する GitHub Actions アクションを作りました[^1]:

[Actions Readme Feed - GitHub Marketplace](https://github.com/marketplace/actions/actions-readme-feed)

# 使い方

基本的にはマーケットプレイスのページに書いてある通りです.

`README.md` の記事一覧を挿入したい箇所にフラグコメントを突っ込みます:

```markdown
### Recent Blog Posts
<!-- feed start -->
<!-- feed end -->
```

`.github/workflows/` 以下のワークフローにステップを追加します. コミットまではやらないので気合で頑張ります. [この辺](https://github.com/marketplace/actions/add-commit)のアクションを使うと楽かもしれません...:

```yaml
steps:
  - uses: actions/checkout@v2
  - uses: sarisia/actions-readme-feed@v1
    with:
      url: 'https://note.sarisia.cc/index.xml'
      file: 'README.md'
  - run: |
      git config --global user.name "${{ github.actor }}"
      git config --global user.email "${{ github.actor }}@users.noreply.github.com"
      git add .
      git commit -m "docs: update feed" || true
      git push
```

プロフィールページにブログの投稿が追加されます！

![actions-readme-feed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252498/8a70e38e-6c73-2f55-4ee7-27266957a745.png)

## 応用編

### Qiita の表示

`https://qiita.com/[username]/feed` でRSSフィードが取れるので[^2], これを `url` として渡します:

```yaml
- uses: sarisia/actions-readme-feed@v1
  with:
    url: 'https://qiita.com/sarisia/feed'
    file: 'README.md'
```

### 自動更新

Workflow を `schedule` で回してあげれば自動更新できます:

```yaml
on:
  schedule:
    - cron: '0 */6 * * *'

jobs:
  readme:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: sarisia/actions-readme-feed@v1
```

# まとめ

出力のテンプレート機能やフラグ変更など, もっと高度なカスタマイズも出来るようになっているので, [リポジトリページ](https://github.com/sarisia/actions-readme-feed)も参考に是非使ってみてください！

[^1]: 実は一週間先を越されていた: [README the RSS](https://github.com/marketplace/actions/readme-the-rss) が, 多分カスタマイズできるオプションはこっちのほうが多いはず…

[^2]: 公式のドキュメントが無いのでいつか急に消滅するかもしれません
メモ Docker + Go + MYSQLをvscodeで開発

Docker + Go + MYSQLをvscodeで開発するときにしたの記事がとても参考になりました。

[Docker + VSCodeでGoの環境構築(ホットリロード対応)]( https://qiita.com/S-Masakatsu/items/62f15528d5827d71b0e0 )


それを参考にリポジトリ作成しました。
https://github.com/kenjiSpecial/docker-go-mysql-starter
糞コードと上手く付き合う技術

システムが大きくなり、要件が増え、ビジネスロジックが肥大化する。
数千行の処理が１つの関数に詰め込まれ、少しの修正を加えるだけで膨大な工数とデグレの嵐が巻き起こる。
誰しも経験したことはあるのではないでしょうか
[プログラマをクソコードで殴り続けると死ぬ](https://www.megamouth.info/entry/2017/08/01/083126)

こちらの記事には技術的連帯保証人というパワーワードが出ていました、言い得て妙だなと
[糞コードは直すな。](https://qiita.com/kotauchisunsun/items/d03c1e6936ffb250e4a1)


注意：

- ここで述べている糞コードとは文法的にもっと可読性が良く、テスタブルに書ける可能性を秘めているコードではありません。（こちらは言語仕様勉強するのとリーダブルコードでも読んでください）
- 残念ながらすでに巨大な糞コードになったものをリファクタリングする技術についてではありません。
- 多分絶対的な正解はないと思います。

# ビジネスロジックは足し算で共通化（条件分岐）すると死ぬ

ユーザを更新するというupdate関数だとしましょう。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55077/a4f612cb-200b-d578-2cb1-591670de113b.png' width=100 />

ここに何らかのキャンペーンを実施して特別なロイヤリティユーザを作成するという要件が加わるとします。

普通に対応すると現行のuserのupdate関数に条件分岐を埋め込む場合が多いのではないでしょうか？
最初は問題ないのかもしれませんが、これを素直に条件分岐を増やしていくといずれ死にます。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55077/5c54baf8-dc3a-0afc-0c51-dcb9a7c6191a.png' width=300 />

さらに期限切れの処理を実装しようとして同じ関数内に条件分岐が追加されるとします。

![スクリーンショット 2020-08-25 0.24.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55077/99c65a53-59a1-6308-b301-f45e59a73218.png)

もう駄目ぽ（^p^）・・・

※あくまで一例です。駄目な長ったらしい関数にありがちなのが通常ユーザもキャンペーンユーザも対応するために条件文が入り混じったスパゲッティコードになります。

# 上位レイヤーを作り、ドメインで関数を分ける
さて根本的な問題は通常のユーザ更新と特別なユーザ更新が同じ関数に混在していることが原因だとわかります。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55077/8aeda392-bb51-658f-eee8-b808412eee6e.png' width=400 />


上位のレイヤーを設けることでドメイン単位で早々に処理を分離することができます。
この分け方はAPIレベルなのか、APIの最上位で関数を２つ作り分離するのかは状況とか好みが分かれると思います。
<b>肝心なのはドメインが分かれた早期のタイミングでこの形に分離すると後々苦しまなくてすむかもしれません</b>

多くの人はここでDRY（Don't Repeat Yourself）の原則を浮かべると思います。
ただしこの場合、要件が異なる以上、コピペコードではなく変更可能性を秘めたものになります。

２重メンテになるという考え方もあると思うのですが、
そもそも修正はドメイン単位で入るわけなので、適切にドメイン単位で分離できていれば
修正は片方で済む場合が多いです。（両方必要な場合ももちろんありますが）

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55077/1326091d-0e2f-39ed-b3b0-5de3891f4f9b.png' width=500 />

また、ドメインで関数を分けた後に内部関数を共通化すれば問題ないはずです。

このやり方のもう一つのメリットとしては特別なユーザが不要になったタイミングで該当ドメインの関数ごと削除で済みます。

<b>デッドコードが残り続けるという事態を減らしていくのが健全なプロダクトとして大事なことだと思います。</b>
<b>もちろんある程度上位のPMやPdMなどは常に施策をトラッキングしておき、インパクトが低い施策だとわかった際には積極的に該当ビジネスロジックを消していく（という組織文化を作るというのが大事だと思います）</b>

参考：[役割駆動設計で巨大クラスを爆殺する](https://qiita.com/MinoDriven/items/2a378a09638e234d8614)

# リファクタリングは一気にやるな、死ぬぞ
負債の量が大きいほど修正にかかる時間は比例します。
（要は常日頃からできる限り良い実装とレビューしましょうということなんだけど）
負債が大きくなる前に返せるものは返していく、ライブラリのバージョンを上げることが大事です。
ライブラリのバージョンを上げることを恐れると後でサポートが切れたり、ドキュメントの参照が大変になったりと手痛いしっぺ返しを食らうことになるかもしれません。
また、ライブラリのバージョンを上げることによるBreaking Changeにも気を配る必要があります。
そのためにもテストを書くわけですが・・・

参考：[技術的負債とどうやって戦うか](https://qiita.com/kamykn/items/ad687e772da454e3f614)

# 分けた関数の共通内部処理を関数化する
ビジネスロジック的に早々に変更が入らないだろうという箇所で共通化できる箇所はもちろん関数化すべしです。（主にビジネスロジックの分岐を除いた処理、複雑な判定条件は判定条件のみの関数を作っておくと良いです）
気をつけたいのは共通処理の関数は１関数に１機能以上持たせないということです。
１機能以上になるのだとしたら関数を分けましょう。

まとめると

- ビジネスロジックは本質的に汚い
- 安易な共通化（条件の継ぎ足し）は複雑度を増し、可読性を落とし修正工数を増やし、事故の要因となる
- まずドメインで関数を分ける、処理の共通化はその後
- ビジネスロジックのフロー処理をする関数と共通化する関数を分ける
ブロードキャストを使ってデータ内すべてのペアに対する演算を簡潔に書く

# 3行で
* 類似度に基づくレコメンドやk近傍法など、データ同士の可能なペアすべてに対して計算を行いたい場面がある
* forループを書けばできるが、numpyなりtfなりの機能を活かしたい
* ブロードキャストを使って簡潔に記述できる

# 問題設定
$-1\leq x \leq 1$, $-1\leq y \leq 1$を満たすすべての$(x, y)$の集合を$A$とする。
$A$から任意の元を選んだ際、$A$に含まれる格子点と選んだ元とのL1距離を計算する。

なお、$(x_1, y_1)$と$(x_2,y_2)$のL1距離は以下で表される

```math
d_1((x_1, y_1),(x_2,y_2)) = |x_1 - x_2|+|y_1 - y_2|
```

# 考え方
選んだ元とすべての格子点とのL1距離を計算し、距離が小さい順に5つ選ぶ。

L1距離の計算を一斉に行うため、次のようなnp.ndarray(もしくはtf.tensor)を考える。

```python
lattice=np.array([[ 1,  1],
                  [ 1,  0],
                  [ 1, -1],
                  [ 0,  1],
                  [ 0,  0],
                  [ 0, -1],
                  [-1,  1],
                  [-1,  0],
                  [-1, -1]]) #shape = (9, 2)
```

今、仮に選んだ元が$(0.1,0.5)$だったとする。実は、L1距離の計算として次の記法は有効

```python
data = np.array([0.1,0.5])
l1_dist = np.sum(np.abs(data-lattice),axis=1)
```
一見なんの変哲もない式に見えるが、`data-lattice`の部分でshapeが異なるもの同士の引き算を行っている。
ここで自動的に2つのshapeがブロードキャストによって調整されている。

(参考: https://numpy.org/doc/stable/user/basics.broadcasting.html)

公式によれば、shapeの後ろから次元を比較し、片方の次元が1の場合もう片方に合わせてコピーで次元が増やされる。
今回の場合、`data`のshapeは`(2,)`、`lattice`の`shape`は`(9,2)`なので、`data`側の次元が調整され

```python
array([[0.1, 0.5],
       [0.1, 0.5],
       [0.1, 0.5],
       [0.1, 0.5],
       [0.1, 0.5],
       [0.1, 0.5],
       [0.1, 0.5],
       [0.1, 0.5],
       [0.1, 0.5]])
```
と見なされて引き算が実行された。
そして`np.abs`でelement wiseに絶対値を計算し適切な`axis`に沿って和を取ればいい。
`l1_dist`は次のようなshapeが`(9,)`の`np.ndarray`になる

```python
array([1.4, 1.4, 2.4, 0.6, 0.6, 1.6, 1.6, 1.6, 2.6])
```

# バッチ処理への応用
L1距離を計算する対象の元を2個以上に増やしても同様の考え方ができる。
仮に、対象の元を2つとし、それぞれを$(0.1,0.5),(0.7,0.8)$とする。
今度はおそらく`data`が次の形式で供給されるだろう

```python
data = np.array([[0.1, 0.5],
                 [0.7, 0.8]]) # shape = (2,2)
```
この場合、`data-lattice`でブロードキャストは発生せずエラーになる。
shapeの後ろから次元を比較し、片方の次元が1の場合ではなくなったからである。
対処法は`np.expand_dims`で次元が1の軸を追加すればいい。

```python
data = np.expand_dims(data,axis=1) # dataのshape = (2,1,2) latticeの(9,2)と比較してaxis=1のdataが9つ複製され、axis=0のlatticeが2つ複製される
l1_dist = np.sum(np.abs(data-lattice),axis=2) # (2,9,2)同士の引き算ののち、axis=2のsumが行われる。sumのaxisがexpandのせいで変わっているので注意
```

とすれば、`l1_dist`は

```python
array([[1.4, 1.4, 2.4, 0.6, 0.6, 1.6, 1.6, 1.6, 2.6],
       [0.5, 1.1, 2.1, 0.9, 1.5, 2.5, 1.9, 2.5, 3.5]]) # shape = (2, 9)
```

となる。

# ぼやき
まあコードは簡潔になるんだけど、暗黙的にshapeが変わるのって可読性をめちゃくちゃ下げてないかなと思う。
処理時間・可読性・簡潔さを兼ね備えたもっといいプラクティスがあれば知りたい。

# 参考
[TensorFlow機械学習クックブック Pythonベースの活用レシピ60+](https://www.amazon.co.jp/gp/product/4295002003/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1)
(挙げといてなんだが、この本を買うのはあまりおすすめしません・・・)
Oracle VM VirtuarlBox　がセッションエラーで起動しないのを解決する方法

**解決したこと：**virtualBoxのセッションが開けない、起動しないエラーを解決（vagrant up のエラーも同時に解決　URL：）

**環境：**Windows10　HOME
　　　Oracle VM VirtualBox 6.1(?) DL先:https://www.virtualbox.org/

---------------------------------------------------------
 
**エラー内容と画面：**
![コメント 2020-08-24 205219.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455182/e01bfda5-fdfa-8485-9682-281226e8d504.png)

**エラー詳細：**
――
仮想マシン"XXXX"のセッションを開けませんでした。

Not in a hypervisor partition (HVP=0) (VERR_NEM_NOT_AVAILABLE).

VT-x is disabled in the BIOS for all CPU modes (VERR_VMX_MSR_ALL_VMX_DISABLED).
――

と表示されて起動しませんでした。

この文言そのままググると　「Hyper-V を有効にしている」ことが原因であるというような内容の記事を多く見かけました。

**結果：**
エラーを解決できた方法は、BIOSでHyper-Vを無効化するした。

**参考記事：**
https://qiita.com/yamasaki1ma/items/141f12d52ef38f3f3f85
（この操作方法がずっとわからなかった・・・）

**手順：**
１、起動画面からBIOSに入る（Think pad の自分は起動時の”Think pad”のロゴの画面で”F１”を一回おすだけで、
　　　　　ピー音がなって、入れた）
２、初期画面から右ボタンでカーソル動かして”**Security**”でEnter。
３、Securityの画面から下ボタンでカーソルを"**Virtualization**"に動かして、Enter。
４、適応して、終わり。（自分の場合はSave & ExitはF10） 　　　　　　　　　　　　以上



**vagrant について：**
vagrantの導入での”vagrant up”のエラーも同時に解決しました。

**エラー内容：**
Bringing machine 'default' up with 'virtualbox' provider...
・・・・
Stderr: VBoxManage.exe: error: Not in a hypervisor partition (HVP=0) (VERR_NEM_NOT_AVAILABLE).
VBoxManage.exe: error: VT-x is disabled in the BIOS for all CPU modes (VERR_VMX_MSR_ALL_VMX_DISABLED)
VBoxManage.exe: error: Details: code E_FAIL (0x80004005), component ConsoleWrap, interface IConsole
　　　　　　　（正直、エラーの内容は良くわかありません。「Stderr・・・」から始まる分が解消できて、上手く行ったのかと。）

![vagrantup-errer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455182/8aad3125-395b-fa6c-bba2-6645061e6f1e.png)
vagrantの導入での”vagrant up”のエラーも同時に解決したので、
ドットインストールの”ローカル開発環境の構築 [Windows版] ”#05 仮想マシンを立ち上げよう”　などでつまづいた方などの
参考になればとおもいます。

**まとめ**
自身としてはBIOSの設定だということはなんとなくあったんですが、Hyper-V の有効、無効の替え方が分からずに4時間程さまよいました。
CDK for TerraformでtfstateファイルをS3に配置する(Python)

# 概要
- CDK for Terraformで生成されるtfstateファイルをS3に配置する
    - デフォルトではtfstateファイルはローカルのカレントディレクトリに作成される
- [S3以外にも配置可能](https://github.com/hashicorp/terraform-cdk/blob/master/docs/working-with-cdk-for-terraform/remote-backend.md#other-supported-backends)


# 方法
- [TerraformBackend](https://github.com/hashicorp/terraform-cdk/blob/2e137f5506ba4b7e283a6784ce39fd3772a0a93c/packages/cdktf/lib/terraform-backend.ts)クラスを使う
- [TerraformBackendを継承した各Backendごとのクラス](https://github.com/hashicorp/terraform-cdk/tree/2e137f5506ba4b7e283a6784ce39fd3772a0a93c/packages/cdktf/lib/backends)があるのでそれをimportして使う


# PythonでtfstateファイルをS3に配置する具体的なコード
- 以下はVPC, Public Subnetを作るコード
- 利用するBackendクラスをimportする(ここでは`S3Backend`)
- `remote backend`の箇所がS3を定義している箇所
- これで`cdktf deploy`すれば、S3にtfstateファイルが配置される

```
#!/usr/bin/env python
from constructs import Construct
from cdktf import App, TerraformStack, S3Backend # 利用するBackendクラスをimport
from imports.aws import AwsProvider
from imports.terraform_aws_modules.vpc.aws import Vpc

class MyStack(TerraformStack):
    def __init__(self, scope: Construct, ns: str):
        super().__init__(scope, ns)

        # provider
        AwsProvider(self, 'Aws', region='ap-northeast-1')

        # remote backend
        S3Backend(self,
            bucket="s3-bucket-name",  # S3バケット名
            key="vpc-example/terraform.tfstate", # S3バケット内のtfstateファイルのPATH
            region="ap-northeast-1"  # リージョン
        )

        # resources
        Vpc(self, 'vpc-from-cdk-for-terraform',
            name='vpc-from-cdk-for-terraform',
            cidr='10.0.0.0/16',
            azs=["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"],
            public_subnets=["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
        )

app = App()
MyStack(app, "vpc-example")
app.synth()

```

# どうしてTerraformBackendクラスはTypeScriptのクラスなのにPythonからimportできているのは何故？
- [jsii](https://github.com/aws/jsii)というライブラリを[cdktfが使っている](https://github.com/hashicorp/terraform-cdk/blob/76c3e125e8e01f77d5588fa369b30f8c2324d411/packages/cdktf/package.json)ので、TypeScriptの単一のコードベースからPython, Java, C#などでも使えるらしい

例えば以下のようなTypeScriptのクラスを、

```
export class HelloJsii {
  public sayHello(name: string) {
    return `Hello, ${name}!`
  }
}
```

Pythonから呼べる

```
hello = HelloJsii()
hello.say_hello("World"); # => Hello, World!
```

- 具体的には、[サンプルページ](https://github.com/hashicorp/terraform-cdk/blob/master/examples/typescript/backends/s3/main.ts)にあるS3Backendの利用方法を参照して、Pythonで書いてみた。

TypeScriptの場合

```
new S3Backend(this, {
  bucket: "mybucket",
  key: "path/to/my/key",
  region: "us-east-1"
});
```

Pythonの場合

```
S3Backend(self,
    bucket="mybucket",
    key="path/to/my/key",
    region="us-east-1"
)
```

# まとめ
- tfstateファイルは今まで通り（S3とかで）の管理ができる
- JSiiというツールでTypeScriptで書いた単一のコードベースからPythonや他の言語で使えるクラスを提供している
ThunderbirdからDovecotへ接続した際にPermission Deniedと表示されてしまう


## 環境
- Centos7.8
- dovecot-2.2.36-6.el7.x86_64
- Maildir形式ではなく、Mailbox形式にすると発生

## エラーメッセージ

```/var/log/mail.log
Aug 25 00:11:46 mail1 dovecot: imap(cent): Error: fchown(/home/cent/mail/.imap/INBOX, group=12(mail)) failed: Operation not permitted (egid=1000(cent), group based on /var/mail/cent - see http://wiki2.dovecot.org/Errors/ChgrpNoPerm)
```

## 対処方法
- メールボックスファイルのパーミッションが過剰

```bash
chmod 0600 /var/mail/*
```


## 参考
- 原因はパーミッションがゆるすぎるからみたい

https://server-setting.info/centos/dovecot-fchmod-error.html
Next.jsでの_documment.js(tsx)・App.js(tsx)について爆速で理解しよう


今回は、Next.jsで全体の設定ができる`_document.js(tsx)` と`_app.js(tsx)` について解説してききます✍️

# _document.js(.tsx)

Next.jsのPageコンポーネントはデフォルトでは`<html>`・`<body>`タグの定義を行いますが、それらを拡張したい場合は `_documet.js(tsx)` を作成し、その中で `Document` コンポーネントを継承したクラスを実装しましょう。

```jsx:_document.js
class SampleDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return { ...initialProps }
  }

  render() {
    return (
      <Html>
        <Head>
          <link rel="dns-prefetch" href="//www.google.co.jp" />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default SampleDocument
```

`_document.js(tsx)`では、`<Html>`, `<Head />`, `<Main />`, `<NextScript />` がページが適切にレンダリングするために必要となります。このHeadタグの中に`<title>` など、全ページ共通の設定を行います。

また注意点としては以下のことがあります。

- **SSR(**サーバサイドレンダリング)のみの実行なので、クライアントサイドの処理を書くべきではありません。← 間違いやすいので注意してください！
- `<Main />` 内に入る外部のReactコンポーネントはブラウザによって初期化されないため、ここでアプリケーションのロジックや、styled-jsxのようなCSSを設定してはいけません。全てのページのコンポーネントに共通させたい場合は代わりに`App` コンポーネントを使ってください(`_app.js(tsx)`に定義)
- `Document`の`getInitialProps`は、クライアントサイドの遷移中には呼び出されず、ページが静的に最適化されている場合にも呼び出されません

次に、`_app.js(tsx)`の説明をしていきます。

# _app.js(tsx)

Next.jsでは`App`コンポーネントを使用して全てのページを初期化するようになっています。 そのため、このコンポーネントを継承したクラスがあるファイル、`_app.js(tsx)` を作成することでデフォルトのAppコンポーネントを上書きできます。

つまり、 全ページで必要な処理をここに書くことができます。他にもAppコンポーネントでは以下のようなことができます

- ページ間の共通レイアウトを持たせることができる
- 共通のstateを持つことができる
- グローバルなCSS(全ページ共通の)を定義できる
- `componentDidCatch`を利用したカスタムエラー処理
- 各Routeコンポーネントをラップするもの
- ReduxのProvider設定をする

```jsx:app.js
import * as React from "react";
import { Provider } from "react-redux";

function MyApp({ Component, pageProps }) {
  return (
    <Provider store={store}>
      <Layout>
        <Component {...pageProps} />
          <style jsx global>
            {`
              #container {
                min-width: 800px;
              }
            `}
          </style>
        )}
      </Layout>
    </Provider>
  )
}

export default MyApp
```

また、`_document.js(tsx)` と異なり、AppはPageコンポーネントと同じ動きをするので、_app.js(tsx)はSSRされ、ライフサイクル周りのイベントはクライアントサイドでも実行することができます。

# まとめ

Next.jsではDocument, Appコンポーネントを用いることでページ間の共通処理や共通レイアウトを定義することができます！

`_document.js(tsx)`にはDocumentコンポーネントを継承したクラスを実装し、共通レイアウトを定義し、`_app.js(tsx)`ではAppコンポーネントを継承したクラスを定義し、全ページで共通の処理などを書きましょう！

上手く使い分けて、快適なNextライフを送ってください！👨‍💻

こちらにも記事が載っています: https://tyotto-good.com/blog/next-document-app
【Ruby】each_with_indexとsearchを組み合わせたプログラム・考え方

アウトプット用に記します。
`macOS Catalina10.15.6にインストールしたRuby 2.6.5を使用。`
#やりたいこと#
数を探して何番目に含まれているか結果を返すメソッドを**search**と**each_with_index**を用いて作成したいんよね。

###まずこういう配列があるたいな###
```
input = [3, 5, 9 ,12, 15, 21, 29, 35, 42, 51, 62, 78, 81, 87, 92, 93]
```
###んで、こんな感じに使えるsearchにしたいわけたいな###
```ruby

search(12, input)
=> 4番目にあります

search(7, input)
=> その数は含まれていません
```
###each_with_indexについて###
**each_with_index**はRubyに標準で組み込まれているメソッドの1つたいね。要素の繰り返し処理と同時に、その要素が何番目に処理されたのかも表せるんよ。

```ruby

#each_with_indexの使い方

配列名.each_with_index  do |item, i|

end
```

**さらに詳しいeach_with_indexの使用例**

```ruby

cigarettes = ["MEVIUS", "highlight", "LuckyStrike"]

cigarettes.each_with_index do |item, i|
 puts "#{i}番目のタバコは、#{item}です。"
end
```

これ↑を実行すると、以下のような出力結果が得られるとよ。

```
0番目のタバコは、MEVIUSです。
1番目のタバコは、highlightです。
2番目のタバコは、LuckyStrikeです。
```

#さあ本題、どうやる？#

1. なにはともあれ**search**メソッドを自分で定義せいっちゅうことやね。
2. 仮引数を２つ用意するノリやね。（tage_i,input）と、しとこうか。
3. **配列input**を**each_with_index**の使い方に当てはめて・・・。ブロック変数にも２つ引数を渡しす（なんとなく | i, index |にした）。
4. 含まれてたら〜と、含まれてなかったら〜があるから、条件分岐if使うっしょ・・・？もしiと入力してtarget_numと等しければreturn前のputsを出力する。returnしとかんと、要素の数だけ繰り返しちゃうかんね！
5. 配列並べて、ためしに一個呼び出してみる

```ruby:array.rb

def search(tage_i, input)
  input.each_with_index do |i, index|
    if i == tage_i
      puts"#{index + 1}番目にあります!"
      return
    end
  end
  puts "その数は含まれていません"
end

input = [3, 5, 9 ,12, 15, 21, 29, 35, 42, 51, 62, 78, 81, 87, 92, 93]
search(11, input)
```

**結果**
![スクリーンショット-2020-08-24-23.42.57.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685096/46e68fd5-2f72-af58-5397-4e9d43c5867f.jpeg)

ちなみに当てはまってる数字も出力させてみる・・・

```ruby:array.rb

def search(tage_i, input)
  input.each_with_index do |i, index|
    if i == tage_i
      puts"#{index + 1}番目にあります!"
      return
    end
  end
  puts "その数は含まれていません"
end

input = [3, 5, 9 ,12, 15, 21, 29, 35, 42, 51, 62, 78, 81, 87, 92, 93]
search(11, input)
search(29, input) #「〜番目にあります！」の条件にあてはまる数字の追加
```

![スクリーンショット-2020-08-24-23.42.57.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685096/41b8661a-3dfe-97d4-3da1-5626de9a5127.jpeg)

#なにをともあれ#
ゆっくりじっくり考えればいける・・・？
まだ表面だけしか理解できてない感否めないから、いったんメモる。またアップデートすると思う。
herokuへアップロードできない

#環境
・Rails 6.0.3.2
・mysql Ver 14.14 Distrib 5.6.47
・osx10.15

#はじめに
`Rails`でWEBアプリを作成し初めて`heroku`へデプロイするときにうまくできなかったり画面が表示されず困ったのでケアレスミスもありますがその時の対処を載せます。

#問題点１（アプリ名）
アプリ名やファイル名に`アンダーバー「_」`は使用できないということ。自分の場合はGithubへもPUSHができませんでした。
`ハイフン「-」`は利用できるので自分の場合はハイフンを変更することにより進みました！


#問題点2（マイグレーション）
デプロイ後にマイグレーションしてなかった。初めてのことだったので、この単純な作業になかなか気づけませんでした。。。

```
git push heroku master
```
その後にDBを作成を忘れずに！

```
heroku run rake db:migrate
```

#問題点3（DBの種類が違う）
`heroku`のDBは『PostgreSQL』であり自分の環境(MySQL)と異なっていたことです。
詳細は別記事に記載↓
・https://qiita.com/yamato1491038/items/4884b8d77c2852425cd1



ドキドキしながらアクセスすると画面表示！
晴れてデプロイ完了しました！
Spotifyのランキング特徴【8/17〜8/23】

#Spotify APIを使ったランキング分析【8/17〜8/23】
今週の動きを見ていきましょう！

##「香水」「夜に駆ける」強すぎ
相変わらず首位はYOASOBIの「夜に駆ける」。すごいですね。
トップソングにあるから聴いちゃう→聴かれるからランキングに居続ける、という好循環が最強。

###夜に駆ける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661171/652f5da6-fb26-109d-2a8b-67fb446a523c.png)
一瞬下がっている日は米津玄師の「Kanden」が1位を取った8/5のみ！

###香水
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661171/bfefc35f-59b8-ef05-772c-952a3e0ab29b.png)
YOASOBIの1日以外にも動きはありましたが、安定して2位をキープ。

##後を追う米津玄師
3位は米津玄師の「Kanden」が3位をキープしています。
###米津玄師「Kanden」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661171/d2a43420-3cb7-db4c-ded2-e95e14e1563f.png)

##今週の注目は？
じわじわとランキングをあげているのがあいみょんの「裸の心」。これがこんご順位をあげていくのか、下がっていくのか注目です！
###あいみょん「裸の心」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661171/1a48a831-1136-8487-95f9-97cffa5c035e.png)

##まとめ
ランキングの予測をしてみると、少し伸びるようだけど、、どうなることやら？？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661171/321f3b72-ccc4-2a76-d3a2-0c9e9af93e4b.png)

では、また！
オンサイト保守とオフサイト保守について

サーバーのハードウェア保守において、押さえておくべき以下の2つのポイントがある。

- **オンサイト保守**

- **オフサイト保守**

#オンサイト保守とは？

- 故障が起きた際に、メーカーの技術員がサーバー本体が設置されている場所に来訪し、修理・部品交換を実施するサポート方式のこと。

- 多くの場合、「提供する時間帯」によって費用に差が出る。

- 一般にサービス提供時間帯は「時間×日」で表記される。
  ex) 「12×6」と表記されていれば、契約で指定された６日間の日中、12時間のどこかで対処を実行するということ。


#オフサイト保守とは？

- **「センドバック保守」**とも呼ばれ、故障した製品や部品を自分で取り外してメーカーに発送し、メーカーからは修理完了品もしくは代替品が手元に配送されてくるというサポート方式のこと。

- **`故障品を自分の手で交換し、修理を完了させる必要がある点`**が、オンサイト保守とは大きく違う。

- センドバック保守は、以下の2種類がある。
    - 先に代替品が手元に送られきて、交換完了後に故障品を送り返す先出しセンドバック
    - 故障した部品・製品をメーカーに送り、その間は故障部品や故障サーバーなしでどうにかしなければいけないセンドバック

#どちらの保守を選ぶべきか

- 「状況次第」ということになるが、企業内でそれなりの稼働率が要求される業務に利用されるサーバーであれば、原則としてオンサイト保守を契約し、常に故障に備える体制を整えておくことが要求される。
Linux初心者がやらかしたConfig編集ミス3点

なんだかんだでLinuxの業務経験が1年半になったので今までにやらかした~~(死にかけた)~~経験を書いていきます。
特に最近はオンプレだとBIOSレベルで操作できてたのが、クラウドだとできず詰みかけるパターンも多いです。（救えるパターンもあり）

やらかし防止と、リカバリ含め傷を最小限に抑えられればと思います。
※本記事はRHEL7,CentOS7を前提とします。

#### ざっくりと筆者の経歴
* 高専時代：Linuxによる自宅サーバ運用歴2年(何も理解してなかった)
* 最近：Linux業務経験1年半
* LPICレベル1所持
* 応用情報技術者
* 業務歴は6年くらい(Linuxやる前は、Windows,Networkが中心でした)



## SElinuxの編集ミスで死亡

SElinuxの無効化を行うために、コンフィグファイル(/etc/selinux/config)を修正。
本来は「SELINUX=disabled」とすべき所を、
誤って「SELINUXTYPE=disabled」としてしまった。
またはタイプミスなど。
詳細はこちらで紹介されてるので割愛。
https://qiita.com/daisuke0115/items/4b0ed3a5888cf81efd0a

biosレベルでマシンに接続できる環境なら良いですが、AWSなどのクラウドだと詰みかけます。

→別EC2に該当のEBSをマウントして編集で救えます。
http://blog.serverworks.co.jp/tech/2020/04/14/post-82871/

ただし、国産クラウドみたいに？ディスクの付け替えが容易に行えない場合は詰みます。
バックアップから戻す、もしくは再構築が必要になります。

### 対策
こればかりはコピペで行って、更にとかやると安心。

    cat /etc/selinux/config | grep SELINUX=disabled 

## fstabの編集ミスで死亡

正しい例

    /dev/sda3 /home xfs defaults,nofail 0 2

自分の場合は途中のxfsを書き忘れて再起動し、ssh接続不可に。。
これもやってしまった場合、上述と同じ方法で救えます。
が自分が触ってたクラウド環境はそれが使えず、バックアップから復元しました。

### 対策

    sudo mount -a
で**エラーが無いこと**を確認してから再起動を行う。
>俺は構築の勢いでそのエラーを無視して再起動してしまったんだ。。ﾕﾙｼﾃ

### 余談
>クラウドサーバーの追加ディスクマウント時はnofailオプションを！
https://inaba-serverdesign.jp/blog/20170210/cloud_disk_mount_fstab_nofail.html

にあるようにnofailをつけましょう。


## root sshの許可で死亡

(編集ミスとはまた少し違う気もしますが)

原則サーバに置いて、rootのsshは無効です。
稀に閉域環境下では便器性などで一時的に有効化されているケースもあります。
自分の場合はついそれに慣れてしまい、検証として立てて頂いた、公開サーバでも変更してしまいました...

→クラウドサービス（Azure）のアタック検知により発覚し変更。パスワードは複雑なので事なきを得た。
※AWSは公開鍵認証固定ですが、AzureはSSH公開鍵認証と文字列認証が選べるようです。

### 対策
* 操作するサーバが誰がアクセスできる状態か認識する。
    * 社内ネットワークのみなのか
    * 情報を知っていればどこでもアクセスできるのか
* 公開サーバで文字列認証は極力使用しない。使用する場合はユーザ名を複雑にする。
* 公開サーバとはいえ可能であればセキュリティグループでSSHは接続元を絞る。

## 番外編：AWSのEC2誤削除
検証サーバをさー停止するかってと思って操作してたら終了を選択していた。
> terminated と表示される画面と、真っ青になる俺

### 対策
終了保護を有効にしましょう。
あとはAMI、スナップショットの取得、場合によってはIAMレベルでの制御を行いましょう。

今回は何もしてなかったので3時間くらいかけ構築し直しました。。検証用サーバとはいえ痛い。

## フェールセーフと言う考え方
今回の失敗を受け改めて意識しました。

>フェイルセーフ（フェールセーフ、フェイルセイフ、英語: fail safe）とは、なんらかの装置・システムにおいて、誤操作・誤動作による障害が発生した場合、常に安全に制御すること。 またはそうなるような設計手法で信頼性設計のひとつ。 これは装置やシステムが『必ず故障する』ということを前提にしたものである。
https://ja.m.wikipedia.org/wiki/%E3%83%95%E3%82%A7%E3%82%A4%E3%83%AB%E3%82%BB%E3%83%BC%E3%83%95

情報処理の試験でよく出ますが、システムを設計する上では必要な考え方です。
そのままフェールセーフの考え方を取り込む。というよりは「人間は必ず失敗する」ので、失敗を前提に作業する。という意識が大事です。
(細かく言うと対策によっては別の信頼性設計だったりしますが割愛)

今回のケースだと、以下を考えましょう。

* 誤操作を仕組み的に減らす
    * 再起動後適応等の場合は、記載したようにチェックを入れる。
    * 本番作業は開発・ステージング環境で実績のある作業手順を使う、オペレーター、チェッカーの2名体制で行う。
    * 手動でConfigを編集せずに、Ansibleなどの構成管理ツールを使う。
* 誤操作が起きてもバックアップなどにより元の状態に復元できるようにする。
    * Configを編集するときはシステムバックアップを取得する。
    * システムバックアップに加え、業務データなどを別途バックアップする。
* 誤操作が発生しても、業務影響を最小限に抑える。
    * 本番作業の場合は、サービス時間外に作業を行う。
* (操作に対するリスクを理解すること)←フェールセーフとは違いますが大事であり、これが一番経験が物を言ったり...

日常生活にも応用ができて、いい例が出ないですが...

* 雨が降ってもいいように折りたたみ傘をいつも持ち歩く
* 自分はリップクリーム必須なので、職場、鞄など使う場所に置いておく。
* 当日の朝は理想の時間に起きれない可能性があるから、前日のうちに荷物を準備する。
* お米を炊いたあと冷凍を忘れないように、手間だけど後回しにせず食事前に必ず済ませるとか。


クラウドサービスは気軽に起動停止できる分、コンソールから(BIOSレベル)の作業ができずトラブル時逆に面倒なときもあります。
失敗例や、オペレーション時のリスク想像とかにより、製造業で言うヒヤリハットのように防げるミスは事前に防いで行きましょう。

>本番環境でやらかしちゃった人 Advent Calendar 2019
https://qiita.com/advent-calendar/2019/yarakashi-production
【Vuetify】メインコンテンツの背景色を変更する

![smart-sr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122790/ee2c1ffd-9135-ff97-42ff-a00a7bd6a892.png)

赤枠部分の背景色を変更するのに地味にハマったのでメモ。

## 環境
Vuetify 2.3.9

## 変更方法

テーマをカスタマイズして`background`を設定する。

```vuetify.ts
import Vue from "vue";
import Vuetify from "vuetify/lib";

Vue.use(Vuetify);

export default new Vuetify({
  theme: {
    themes: {
      light: {
        background: "#f5f5f5"
      }
    }
  }
});

```

`v-app`にスタイルをバインドする

```App.vue
<v-app :style="{ background: $vuetify.theme.themes.light.background }">
  <v-navigation-drawer app>
    <!-- -->
  </v-navigation-drawer>

  <v-app-bar app>
    <!-- -->
  </v-app-bar>

  <v-main>
    <v-container fluid>
      <router-view></router-view>
    </v-container>
  </v-main>

  <v-footer app>
    <!-- -->
  </v-footer>
</v-app>
```

## 参考
https://stackoverflow.com/questions/50243769/vuetify-how-to-set-background-color
https://vuetifyjs.com/ja/customization/theme/
Cloud Firestore のセキュリティルールでよくやる書き方

今回は、Cloud Firestore のセキュリティルールでよく書く記法などをまとめていきたいと思います。(他にもでてきたら随時更新していく)

<img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yum_fishing/20200817/20200817200916.png">



### 認証系

認証しているユーザのみ読み取りが可能になります。

```typescript
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if request.auth != null;
    }
  }
}
```

アクセスするドキュメントID がリクエストの `uid` と一致する場合に読み取りが可能になります。つまり自分のデータだった場合に読み取りが可能になります。

```typescript
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if request.auth.uid == userId;
    }
  }
}
```

Cloud Firestore はドキュメントデータに基づいてルールを動的に作ることが可能なので下記のようなこともできます。便利ですね😄 
ちなみに、コメントアウトしてる部分のように絶対パスを指定し、`get` 関数でドキュメントを取得することも可能です。

https://firebase.google.com/docs/reference/rules/rules.firestore.Resource?hl=ja



```typescript
service cloud.firestore {
  match /databases/{database}/documents {
    match /posts/{postId} {
      allow update: if resource.data.teacherId == request.auth.uid;
      // allow update: if get(/databases/$(database)/documents/posts/$(postId)).data.teacherId == request.auth.uid;
    }
  }
}
```


### バリデーション系

リクエストのデータに `email` が存在する場合はドキュメントを作成することができます。

```typescript
service cloud.firestore {
  match /databases/{database}/documents {
    match /posts/{postId} {
      allow create: if ('email' in request.resource.data);
    }
  }
}
```

リクエストのデータの `email` が **String** だった場合はドキュメントを作成することができます。また、`is` を使って確認できるデータ型は下記の通りです。詳しくは[こちら](https://firebase.google.com/docs/firestore/security/secure-data?hl=ja#conditional_logic)を参照してください。

- string
- int
- float
- bool
- null
- timestamp
- list
- map



```typescript
service cloud.firestore {
  match /databases/{database}/documents {
    match /posts/{postId} {
      allow create: if (request.resource.data.email is string);
    }
  }
}
```

リクエストのデータの `email` のサイズが**3文字以上かつ254文字以下**だった場合はドキュメントを作成することができます。

```typescript
service cloud.firestore {
  match /databases/{database}/documents {
    match /posts/{postId} {
      allow create: if (request.resource.data.email.size() >= 3) && (request.resource.data.email.size() <= 254);
    }
  }
```


### その他

User テーブルに自分の `uid` と一致するテーブルが存在するユーザのみ読み取りが可能になります。

```typescript
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if exists(/databases/$(database)/documents/users/$(request.auth.uid));
    }
  }
}
```


下記は使用頻度が高いのでカスタム関数として切り出しておくと便利です。

```typescript
    function isAuthenticated() {
      return request.auth != null;
    }
    function isUserAuthenticated(userId) {
      return request.auth != null && userId == request.auth.uid;
    }
    function requestData() {
      return request.resource.data;
    }
```

## 参考

- https://firebase.google.com/docs/firestore/security/rules-conditions?hl=ja
- https://firebase.google.com/docs/firestore/security/secure-data?hl=ja
エラー：warning: adding embedded git repository:

##エラー
背景：
1、既にgitにpushしたリポジトリB(最新のもの)にあります。リポジトリBは他の方で作成したもの。現時点は自分のローカルにはないです。
2、既にgitにpushしたリポジトリA(過去のもの)にあります。リポジトリAは自分で作成したもの。現時点は自分のローカルにあります。
3、リポジトリBにリポジトリAのコードを取り込みたいです。
4、ローカルで　`$ git clone リポジトリB` でリポジトリBをcloneしました。
5、ローカルで　リポジトリAを　リポジトリBのディレクトリの下にコピーしました。
6、リポジトリBのディレクトリで　`$ git add .`　　を実行する時に、下記のエラーが発生した。

```
$ git add .
warning: adding embedded git repository: リポジトリ名
hint: You've added another git repository inside your current repository.
hint: Clones of the outer repository will not contain the contents of
hint: the embedded repository and will not know how to obtain it.
hint: If you meant to add a submodule, use:
hint: 
hint:     git submodule add <url> リポジトリ名
hint: 
hint: If you added this path by mistake, you can remove it from the
hint: index with:
hint: 
hint:     git rm --cached リポジトリ名
hint: 
hint: See "git help submodule" for more information.
```
#原因

原因：cloneしたリポジトリBはリポジトリAのものを取り込んできていました。

#解決策
色々試したが、下記の通りにうまくできました。あまり技術的にならないですが、、(1~4は上記の背景と同じ内容です）

1、既にgitにpushしたリポジトリB(最新のもの)にあります。リポジトリBは他の方で作成したもの。現時点は自分のローカルにはないです。
2、既にgitにpushしたリポジトリA(過去のもの)にあります。リポジトリAは自分で作成したもの。現時点は自分のローカルにあります。
3、リポジトリBにリポジトリAのコードを取り込みたいです。
4、ローカルで　`$ git clone リポジトリB` でリポジトリBをcloneします。
5、gitにあるリポジトリAはローカルでリポジトリBのディレクトリに直接のコピーではなく、リポジトリAをgitからzip fileの形でリポジトリBのディレクトリにdownloadしてください。
6、downloadしたリポジトリAを展開します。zip fileを削除します。
7、再び　`$ git add .`　を実行すれば、うまくできました！

#参考
[git add .で警告。warning: adding embedded git repository:](https://qiita.com/baby-0105/items/3a819d25c905dc8bcb19) を参考しました！
FullCalenderの使い方まとめメモ(v5.3.0)

FullCalenderを使用した備忘録をまとめます。

### ダウンロード
https://fullcalendar.io/docs/getting-started

- 今回はPre-built Bundlesのzipファイルをダウンロードして使用
Download: fullcalendar-5.3.0.zip

- ダウンロードして展開したlibディレクトリの中身を使用するプロジェクトに移す


### カレンダーの表示

https://fullcalendar.io/docs/initialize-globals
こちらを参考に記載

```calender.html
<!DOCTYPE html>
<html lang='en'>
  <head>
    <meta charset='utf-8' />
    <link href='fullcalendar/main.css' rel='stylesheet' />
    <script src='fullcalendar/main.js'></script>
    <script src='calender.js'></script>
  </head>
  <body>
    <div id='calendar'></div>
  </body>
</html>
```

```calender.js
document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');
    var calendar = new FullCalendar.Calendar(calendarEl, {
      initialView: 'dayGridMonth'　// オプション　（月表示）
    });
    calendar.render();　// カレンダーの初期化（再レンダリング）
});

```

- calernderというidを振った場所にカレンダーが表示される
変数calenderを初期化（レンダリング）することで表示できる

- 変数calenderの第2引数のオブジェクトにオプションを指定でき、
カレンダーの設定などが行える

- jQueryは削除されたため、以前のバージョンで使用できた
下記のような記載方法では表示できない

```
$('#calendar').fullCalendar()　
```
Alpha Release: jQuery Removal | FullCalendar Blog 
https://fullcalendar.io/blog/2018/04/alpha-release-jquery-removal

バージョンによって記載方法や指定方法が大きく異なるので注意


### オプション
ドキュメントをみて使用しそうなオプションを列挙

- タイムゾーン

```
timeZone: 'Asia/Tokyo',
```

- ロケール

```
locale: 'ja',

```

- 週の初めの日を設定

```
firstDay: 0,
```
0：日曜始まり、1：月曜始まり
（デフォルトは日曜始まり）

- カレンダー上部のタイトルやボタンを設定

```
headerToolbar: {
    left: false,
    center: "title",
    right: "today prev,next"
},
```
左：なし（なしの場合はfalse）
中央：タイトル
右：今日へ戻るボタン、先月ボタン、次の月ボタン

- 設定したボタンのテキストを設定

```
buttonText: {
    today: '今月',
},
```

- カレンダーに表示するイベントを設定

```
  events: [
    {
      id: 'a',
      title: 'my event',
      start: '2018-09-01'
    }
  ]
```
jsonを指定できる
そのためPHP等でjsonを返すような処理を作成し、下記のようにURLを指定することもできる

```
events: '/hoge/list',
```

- 予定をクリックして動作する処理を設定

```
eventClick: function(info) {
    // 処理
},
```

- カレンダーの日付の枠内をクリックして動作する処理を設定

```
dateClick: function(info) {
　　// 処理
},
```

---

js初心者で言い回し等が間違っている箇所があると思います…
書き方や言い回しなどがおかしい部分があれば教えていただけると幸いです！
python 文字列のスライス

#はじめに
この記事を書く理由は、競プロを始めてスライスを使う場面が多く、頭の中が混雑してきたので簡単にまとめようと思ったことがきっかけです。単なるスライスのメモです。

##プログラムコード
数字の文字列です。数字の文字列にした理由は、出力結果がわかりやすいと思ったからです。

```python

s = "12345"
print(s[-1])  # 末尾
5 # 出力結果
print(s[:-1])  # 末尾を削除
1234
print(s[0])  # 先頭
1
print(s[0:])  # 先頭から最後まで
12345
print(s[1:])  # 1番目から最後まで
2345

start = "6" + s[1:]
print(start) # 先頭を削除して、6を先頭に追加
62345

end = s[:-1] + "6"
print(end) # 末尾を削除して、6を末尾に追加
12346
```
【Railsチュートリアル 4章】Rails風味のRuby

# 引数のデフォルト値
メソッドを呼び出した時に指定した引数は、メソッド側で先頭から順に代入されていきます。
この時、代入するオブジェクトが無かった場合(呼び出し側で指定した引数の数が、メソッド定義側で指定した引数よりも少なかった場合)、
デフォルト値が設定されていればその値が代わりに代入されます。

```ruby
def printHello(msg="No msg", name="No name")
  print(msg + "," + name + "¥n")
end

printHello("こんにちは", "佐藤") #=>こんにちには,佐藤
printHello("お元気ですか") #=> お元気ですか,No name
printHello() #=> No msg, No name

```

```ruby
def printHello(msg="No msg", name="No name")
  print(Kconv.tosjis(msg + "," + name + "¥n"))
end



```




# カスタムヘルパー

Railsのビューでは膨大な数の組み込み関数が使えるが、それだけでなく、新しく作成することもできる。
単なるRubyのコードを書くのであれば、モジュールを作成するたびに明示的に読み込んで使うのが普通。
Railsでは自動的にヘルパーモジュールを読み込んでくれるので、
include行をわざわざ書く必要がない。

```ruby:app/helpers/application_helper.rb
module ApplicationHelper

  # ページごとの完全なタイトルを返します。
  def full_title(page_title = '')
    base_title = "Ruby on Rails Tutorial Sample App"
    if page_title.empty?
      base_title
    else
      page_title + " | " + base_title
    end
  end
end


```

```erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title> <!-- full_tileメソッドの使用ができている -->
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

```
【Railsチュートリアル 3章】リファクタリング

# DRYなコードを書く

同じコードを書く事はRubyの「DRY」（Don’t Repeat Yourself: 繰り返すべからず）という原則に反する。

# provideメソッド
文字列とラベルを与えて、関連付ける

```erb
<%　provide :ラベル, 'タイトル' %>
```

**yieldメソッドを用いて呼び出す**

```erb
<%= yield(:ラベル) %>
```

# application.html.erbのレイアウト

下のコード内にあるyieldは

例えば/static_pages/homeにアクセスすると
home.html.erbの内容がhtmlに変換され、<%= yield %>の位置に挿入される。

```erb
:application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag    'application', media: 'all',
                               'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag    'application',
                               'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %> 
  </body>
</html>
```
operator does not exist: timestamp without time zone ~~ unknownというエラーの対処

#環境
・Rails 6.0.3.2
・mysql  Ver 14.14 Distrib 5.6.47
・osx10.15
・herokuへデプロイ

#はじめに
railsでWebアプリを作成しherokuへデプロイするときにエラーが発生した。

heroku log でエラーを確認すると以下のような表示を発見

```
operator does not exist: timestamp without time zone ~~ unknown
```
エラー文は初めはよくわからなかったがtimestampとはカラムの型なので型のところで何かエラーが起こっていることがわかりさらに調べて見ました。

そうするとDBの検索の条件文に問題点があることが判明。
もうすこし詳しくいうと、データの作成日時で検索をかけていたロジックが以下みたいに文字列（string型）で検索していたため問題が発生。

```
where('created_at: LIKE(?)', "%%-%%-%%") #左記は問題のコード
```

#原因
原因は端的にいえばherokuのDBは『PostgreSQL』であり自分の環境(MySQL)と異なっていたことです。
『MySQL』ではtimestamp型のカラムをstring型で検索しても自動で変換してくれる（寛容）みたいです。
『PostgreSQL』ではSQL文を厳密にしないと動作しないみたいです。（厳しい・・・）

#対策
xxx.in_time_zone.というメソッドを使うことで解決しました！
例えば自分の場合は月単位でデータを取りたくて2020年8月のデータを取得したい場合（以下）

```
search_time = "2020-08-01"
(モデル名）.where(created_at: search_time.in_time_zone.all_month)
```

とすることでうまくtimestamp型でデータ検索ができるので『PostgreSQL』でもうまく動きました！
また記述も少なくなりスッキリしました！
最後のall_monthをall_dayなどに変更可能でかなり使えます！詳しくはリンクがあるのでそちらがとてもわかりやすく書いてあります！



#参照
エラー文について
・https://nobuneko.com/blog/archives/2010/05/postgresql83operator_does_not.html
TimeクラスとDateTimeクラスについて
・https://qiita.com/jnchito/items/cae89ee43c30f5d6fa2c
nuxt generateの際に「[BABEL] Note: The code generator has deoptimised the styling of」のメッセージ

## 概要
Nuxt.jsにてファイル出力時（nuxt generate）の際に、`[BABEL] Note: The code generator has deoptimised the styling of・・`というファイルサイズが大きすぎるというメッセージが出ることがあります。ファイルサイズが大きいというだけなので無視もできるのですが、このメッセージを非表示にする方法を書いてみたいと思います。

## 対応
* [[BABEL] Note: The code generator has deoptimised the styling of "〜〜.js" as it exceeds the max of "500KB".というエラーが出た](http://simoothie-cafe.hatenablog.com/entry/2018/01/13/170329)の記事にあるとおり、babelの設定で`compact`というのがあるのですが、これをfalseにすればいけそうです。
* Nuxt.jsでどうやってbabelの設定を行えばよいかというと、[こちら](https://ja.nuxtjs.org/api/configuration-build/#babel)の公式ドキュメントの記述にある通り、`nuxt.config.js`のbuildプロパティで設定を行えます。

## 設定例

```nuxt.config.js
export default {
  build: {
    babel: {
      babelrc: false,
      compact: false
    }
  }
};

```
Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.

## 生じたエラー
```
Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
訳：未処理の例外：ナビゲーターを含まないコンテキストでナビゲーター操作が要求されました。
```

# 原因
[stackoverflow](https://stackoverflow.com/questions/44004451/navigator-operation-requested-with-a-context-that-does-not-include-a-navigator)の回答欄を参考にしました。

>現在の親ウィジェットがMaterialAppと同じレベルでないことを確認してください
MaterialAppで下位レベルのツリーのコンテキストを使用する

# 解決策
```sample.dart

 void main() => runApp(MyApp()); //改良前

 void main() => runApp(MaterialApp(home: MyApp())); //改良後

```
WordPress標準のXMLサイトマップを無効化する方法

##はじめに
WordPressでは、2020年8月にアップロードされた5.5のバージョンから、標準のXMLサイトマップが出力されるようになりました。

以下のURLにアクセスすると、標準のXMLサイトマップを確認することができます。

`https://hogehoge.com/wp-sitemap.xml`

ただし、標準のXMLサイトマップには以下のような課題があり、不十分な点もあります。

- 重要度・更新頻度・更新日時などの情報が出力されない
- 全てのページのURLがサイトマップに登録されてしまう

現時点では、WordPress標準のXMLサイトマップを無効にして、他のプラグインなどにより生成されたサイトマップを利用するのが、SEO的にはベストプラクティスでしょう。

##WordPress標準のXMLサイトマップを無効化する方法

WordPressのfunction.phpに以下のコードを設置してください。
管理画面から、外観→テーマエディター→テーマファイルで編集できます。

```function.php
add_filter( 'wp_sitemaps_enabled', '__return_false' );
```

たった1行のコードを追記するだけで、XMLサイトマップの生成機能を完全に無効化できます。

##参考ページ

[WordPress 5.5 sitemap feature](https://wordpress.org/support/topic/wordpress-5-5-sitemap-feature/)
Geolonia 住所データを使って不審者MAPをサクッと作ってみた

# この記事について
箇条書きにすると、個人的やりたい事に以下の2点がありました。
ったのですが以下のモチベーションで本件に取り組みました。

- [Geolonia 住所データ](https://jp.techcrunch.com/2020/08/05/geolonia-retechjapan-open-data/) というものが公開されたので、これを使って何かしてみたかった
    -そんな時に不審者情報サイトを見つけたので、これしかない！と即決
- selenium を使ったスクレイピングをしてみたかった
    - beautifulsoupしか利用経験がなかったのです


# 成果物
このようなマップができました。

https://suzukidaisuke.gitlab.io/fushinsha_map/
**※ 2020/8/27 全国版にしました**
そのため重くなってしまった。地方はクマとか動物情報が多い。

大島てるの不審者情報バージョンみたいなものですね。
比べちゃ失礼なほど完成度低いけど。

また、[gitlab pages](https://gitlab.com/help/user/project/pages/index.md) というものを初めて使いました。こんな機能が有ったんですね。


# どうやって作ったか
コードを gitlab にアップしたので、これを読めばわかります。
https://gitlab.com/suzukidaisuke/fushinsha_map

一応書くと

- [日本不審者情報センター](https://fushinsha-joho.co.jp/)から 2020年8月 ~~東京都の~~ 不審者情報をスクレイピング
- 基本的に以下のようなタイトルになっているので、正規表現で住所部分を取得。
> （東京）西東京市田無町３丁目で公然わいせつ　８月２４日昼過ぎ

- 取得した住所と Geolonia 住所データを結合して、緯度経度を得る
- folium ライブラリを使って、地図上に不審者情報をマッピング

# 感想など
- サクッとつくった割にはいい感じのものができたように思う。
    - git の notebook みればサクッと加減がわかると思います。
    - もっと作り込むこと（全国版にするとか、サーバ立てるとか）も出来そう
    - だけど一旦ここでお終いの予定
- 住所が「○○丁目」まであれば簡単にこの位のものは作れる。
- selenium は簡単・便利。でも beautifulsoup のほうが早いかな？
- 気づかずサイズが大きいファイルを git にアップしてしまった。こういうの使えばいいのかしら。  
  https://docs.gitlab.com/ee/topics/git/lfs/

# 最後に
不審者には気をつけましょう。
[Linux]よく使うLinuxコマンド(フォルダ操作編)

#よく使うLinuxコマンド
まだ学習し始めて数ヶ月ですが、ここまででよく使ったコマンドをアウトプット代りに書いていきますので、学習し始めたばかりの人などの参考になればと思います。
今回はフォルダ操作について、書いていきます。ファイル操作は別のページで書きます。


###カレントディレクトリを表示

```
$ pwd
```

###カレントディレクトリのファイル情報を表示

```
$ ls
```

オプションで、ファイルの一覧をリスト表示したり、更新時間順に並べるなどの詳細を設定できます。


ls -l	ファイル一覧（詳細）をリスト表示する
ls -t	リストをファイルの更新時間順に並べる
ls -r	リストを降順に並べる
ls -ltr	ファイル一覧を更新時間の降順で並べる

###ディレクトリを新規作成
これでaaaというファイルが作成できました。

```
$ mkdir aaa
```

###現在の作業ディレクトリを移動

cd	（移動先指定なし）ホームディレクトリへ移動する
cd .	カレントディレクトリへ移動する
cd ..	1つ上のディレクトリへ移動する

###ディレクトリを削除
ディレクトリを削除しますが、中身が空でないディレクトリは削除できません。

```
$ rmdir aaa
```
Dart：関数の書き方

# これは何か
以下のコードを書いていて、見慣れない書き方があったのでいつでも振り替えられるようにメモ。

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:audioplayers/audio_cache.dart';

void main() => runApp(XylophoneApp());

class XylophoneApp extends StatelessWidget {
  void playSound(int soundNumber) {
    final player = AudioCache();
    player.play('note$soundNumber.wav');
  }

  Expanded buildKey({Color color, int soundNumber}) {
    return Expanded(
      child: FlatButton(onPressed: () {
        playSound(soundNumber);
      },
        color: color),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              buildKey(color: Colors.red, soundNumber: 1),
              buildKey(color: Colors.blue, soundNumber: 2),
              buildKey(color: Colors.yellow, soundNumber: 3)
            ],
          ),
        ),
      ),
    );
  }
}
```

# 関数を定義する
Dartは関数の返り値の型を定義することもできるし（ここではExpandedを指す）

```dart:main.dart
Expanded buildKey({Color color, int soundNumber}) {
    return Expanded(
      child: FlatButton(onPressed: () {
        playSound(soundNumber);
      },
        color: color),
    );
```
型を定義しなくても良い。型を定義した方が視認性が良い。

```dart:main.dart
buildKey({Color color, int soundNumber}) {
    return Expanded(
      child: FlatButton(onPressed: () {
        playSound(soundNumber);
      },
        color: color),
    );

```

# 名前付き引数
引数に{}をいれる記述を名前付き引数と呼ぶみたい。
個人的にあまり見ない書き方だったのでメモ。

```dart:main.dart
Expanded buildKey({Color color, int soundNumber}) {
    return Expanded(
      child: FlatButton(onPressed: () {
        playSound(soundNumber);
      },
        color: color),
    );
```

# 参考
https://dart.dev/guides/language/language-tour#optional-parameters