OmniAICreator/Qiita-1.07M huggingface dataset:
Prometheusのバックアップを取得、リカバリする

コンテナで起動したPrometheusのデータをバックアップする方法の要点は、３つになります。

- Prometheusのデータは`/prometheus`に保存されている。
- PrometheusのTSDB (time series database)のAdminAPIには、"snapshot"という機能があり、/prometheusのある時刻での断面を取得できる
- 新規Prometheusが起動したら、`/prometheus`ごとスナップショットを上書きすることでリカバリできる

以下の記事を参考にしています。

https://prometheus.io/docs/prometheus/latest/querying/api/#snapshot
https://prometheus.io/docs/operating/security/
https://devopstales.github.io/home/backup-and-retore-prometheus/

検証環境は以下です。

- Prometheus 2.23.0
- Kubernetes 1.20

詳細な手順は以下です。

### Admin API有効化

PrometheusがKubernetesクラスタ内にDeploymentとして起動中の状態を想定します。データディレクトリ`/prometheus`はPersistentVolumeなどで永続化されていることを確認してください。（されていなければ以下の作業をやってしまうとデータは消えます）

まず、Admin APIが有効かを確認をします。Deploymentを以下コマンドで確認し、`- --web.enable-admin-api`の行がなければ足し、保存して終了します。これでDeploymentは更新されました。

```diff
$ kubectl edit deploy prometheus

    spec:
      containers:
      - args:
        - --config.file=/etc/prometheus/prometheus.yml
        - --storage.tsdb.path=/prometheus
        - --storage.tsdb.retention.time=30d
        - --web.console.libraries=/usr/share/prometheus/console_libraries
        - --web.console.templates=/usr/share/prometheus/consoles
+        - --web.enable-admin-api
        image: prom/prometheus:v2.23.0
```

Podが自動で再起動します。これでAdmin APIは有効化されます。

(注: 有効化前にAdmin APIを実行しても`404 page not found`が返ってきます)

### "snapshot" APIでバックアップ作成

次に、PrometheusのAPIに`port-forward`などを使い接続します。

```
$ kubectl port-forward svc/<prometheusのService名> 9090:9090 &
$ curl -XPOST http://localhost:9090/api/v1/admin/tsdb/snapshot
│{"status":"success","data":{"name":"20210106T080347Z-0af2560383d17909"}}
$ bg
(Ctrl+cでport-forwardを終了)
```

以下コマンドで`/prometheus/snapshots`にバックアップのディレクトリ（APIの返り値のnameと同じ)があることを確認します。

```
$ kubectl exec prometheus-5fd8f7f855-hnhvd -- ls /prometheus/snapshots -lt
total 4
drwxr-xr-x    8 nobody   nogroup       4096 Jan  6 08:03 20210106T080347Z-0af2560383d17909
```

### バックアップをコンテナ内から退避

先程確認したディレクトリをまるごと端末にコピーします。

```sh
mkdir backup-prometheus
kubectl cp prometheus-5fd8f7f855-hnhvd:/prometheus/snapshots/20210106T080347Z-0af2560383d17909 ./backup-prometheus
```

ちゃんと中身があることを確認します。

```sh
ls backup-prometheus
01EV938GHBWTFM8ZMTWDWA1FTK 01EVAT6A9S7CV7SGD6HAJHK4WX 01EVAT6AMWFF76KPXWEN14VG23 01EVB121HNVRERS45KPTXXNSA8 01EVB7XRSQZ9WQ57ECD17DV548 01EVBBJ9TQ0XVHGGN5BQ7FD3GJ
```

### 新規Prometheus上へのデータリカバリ

新規Prometheusを起動します。

Prometheus上の既存フォルダを一度消します。

```sh
kubectl exec -it prometheus-57df548d7c-tvx4d -- /bin/sh -c "rm -rf /prometheus/*"
```

バックアップ(snapshot)をPrometheusコンテナ内にコピーします。

```sh
kubectl cp ./backup-prometheus prometheus-57df548d7c-tvx4d:/prometheus/
kubectl exec -it prometheus-57df548d7c-tvx4d -- /bin/sh -c "mv /prometheus/backup-prometheus/* /prometheus/"
```

もしデータが復元されていなければ、一度コンテナを停止・再作成すると良いです。

```sh
kubectl delete pod prometheus-57df548d7c-tvx4d
```

これにより、新しい名称でPrometheusコンテナが再起動しており、データは復元されています。

# まとめ

`/prometheus`フォルダをsnapshot APIによりバックアップし、それを`kubectl cp`で取り出し、新規作成したPrometheusに`kubectl cp`するという流れで、Prometheusのデータをバックアップ・リカバリしました。
GCEでFreeBSDを運用する

だいぶ昔に、インストール編を書いた。しばらく経つので運用編を書いてみる。

GCEでサポートのあるOSであれば簡単に使えるロギングやモニタリングが簡単ではなかったので、対策をまとめる。

## Cloud Logging
公式では、fluentdをベースにしたエージェントを配布している。当然FreeBSDではそのままでは動かない。

fluentdと[GoogleCloudPlatform/fluent-plugin-google-cloud](https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud)で構築可能。

```
<match **>
  @type google_cloud
</match>
```

## Cloud Monitoring
公式では、collectdをベースに改造したものを配布している。FreeBSDでビルドできるか不明。

調べると、telegrafが対応していることが分かった。

```shell-session
> pkg install telegraf
```

```
[[outputs.stackdriver]]
  ## GCP Project
  project = "some project code"

  ## The namespace for the metric descriptor
  namespace = "telegraf"
```

influxDBを併用しないなら、無効化しておく。というか今更気付いたけど、urlsがコメントアウトされているので何も必要なかった。

```
[[outputs.influxdb]]
  ## The full HTTP or UDP URL for your InfluxDB instance.
  ##
  ## Multiple URLs can be specified for a single cluster, only ONE of the
  ## urls will be written to each interval.
  # urls = ["unix:///var/run/influxdb.sock"]
  # urls = ["udp://127.0.0.1:8089"]
  # urls = ["http://127.0.0.1:8086"]
```
RaspberryPiでWindowsの共有フォルダをマウントする

#1.この記事の内容

Raspberry Pi から Windows の共有フォルダをマウントする手順を紹介します．
Raspberry Pi からの手順ですが，Linux PCからでも同様の手順でマウント可能と思います．

##1-1.使用環境

* Raspberry Pi 3 Model B+
* Windows 10

#2.Windowsの共有フォルダマウント手順

## Windowsの共有フォルダを作成する

共有するフォルダを右クリックし，プロパティの共有タブの「共有」ボタンをクリックして設定します．

![01_Windowsプロパティ（共有前）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/ddd1b172-a341-0852-06b0-045db9ae0a5c.png)

![02_Windowsプロパティ（共有設定画面）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/600c046e-7c91-74ba-4e61-79d4d985dba5.png)

共有ボタンクリックで共有設定が完了します．
共有時に共有する範囲を指定する画面が表示された場合は，プライベートネットワーク内で共有する設定とすることをお勧めします．

![04_Windowsプロパティ（共有完了）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/1e89a830-7292-858c-fd33-3d5291d660b8.png)

## RaspberryPiで共有フォルダをマウントする

[ラズパイでWindows共有フォルダーを使用できるようにする](https://qiita.com/Zen-GoTo-May/items/6919b4fd0e8e9a327c70)　に記載の手順で共有フォルダへのアクセスが可能となります．

* 必要な環境のインストール
<pre>
$ sudo apt-get update
$ sudo apt-get install samba
$ sudo apt-get install smbclient
$ sudo apt-get install winbind
$ sudo apt-get install libnss-winbind
</pre>
* /etc/nsswitch.confへのwins設定の追加
* Windows共有フォルダのマウント
<pre>
$ sudo mount -t cifs -o user=abc,password=xxx //(コンピューター名)/(共有フォルダー名) /(マウント先)
</pre>


## 備考：Windowsの共有フォルダの解除

フォルダ共有が不要となった場合などは，右クリックメニューからアクセスを解除することができます．

![05_Windowsプロパティ（解除）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/d67652ac-e0aa-37c5-a96c-1d30121d605c.png)

![06_Windowsプロパティ（解除実行）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/01195e28-cd49-1a6d-23a1-89378332c5f3.png)


#3.さいごに

[RaspberryPi上でCOCOデータセットが扱えない問題](https://qiita.com/ryoma-jp/items/f9124a057ac8c646ae61#3%E3%81%95%E3%81%84%E3%81%94%E3%81%AB)への対策として，Windowsの共有フォルダへアクセスする手段をとることとしました．

Linux環境からWindows環境へのデータ転送を行う際などの参考になればと思います．

#4.関連リンク

* [ラズパイでWindows共有フォルダーを使用できるようにする](https://qiita.com/Zen-GoTo-May/items/6919b4fd0e8e9a327c70)
* [Windows10 共有フォルダの共有を解除する方法](https://pc-chain.com/windows10-share-cancel/1224/)
Windows10のインストールメディアが0x8007025dで失敗

##できねえ
FUJITSU CELSIUS W520のリカバリの最中。
そこら辺に在ったUSBでWin10のインストールメディアを作ることに。
[Rufus](https://rufus.ie/ja_JP.html)や[balena Etcher](https://www.balena.io/etcher/)等ならフォーマットしてくれるので、
MediaCreationToolもフォーマットしてくれるだろうと思いそのまま実行。
その結果、**0x8007025d** エラーで失敗。
なぜだろうか。試しにRufusで焼くとできる。
でもRufusで焼くとLegacyになるから使えない。
詰んだ
##あった
流石インターネット。ちょっと調べるだけですぐ出てくる。
### [Windows10のUSBインストールがエラー0x8007025dで失敗する](http://nor.blog.jp/archives/68804358.html)
>今回はUSBのフォーマットがFAT32だったのが原因っぽい。
>NTFSでフォーマットし直してインストールメディアを作成したところエラーが回避できた。

###これだ
ということで念には念を入れてdiskpart上でNTFSにフォーマットしてから
MediaCreationToolで作ってみると...

##でけた
いやーよかった。
これでQuadro搭載つよつよワークステーションにできる。
= render @collection を忘れがちなのでメモを残しておく

## これは何？
すごーく初歩的なことなのですが、あるファイル（便宜的に**「呼び出し元ファイル」**とします）のなかで、

```slim
- @comments.each do |comment|
   = render 'comment', comment: comment
```
上記の様に書いて、`_comment`のパーシャルの中では

```slim:_comment.html.slim
= comment.body
```
とかで「コメント一覧」を表示するのはよくあると思います。
この時、呼び出し元ファイルの方で、

```slim
= render @comments
```
とシンプルに1行で書いても同じ結果が得られます。
ただし、条件が２つあリます。

- パーシャルの**ファイル名が渡しているコレクション名の単数形**である
- そのパーシャルは**コレクション名と同じ名前のビューのディレクトリ内にある**

つまり、この組み合わせはOKで、(それぞれ、下段は呼び出したいパーシャル名)

```haml
= render @messages
# messages/_message

= render @comments
# comments/_comment
```
この組み合わせはダメ。(下段同じ)

```haml
= render @messages
# messages/_messages (複数形)

= render @comments
# posts/_comment (ディレクトリがNG)
```

忘れがちなのでメモしました:relaxed:

Railsガイドでの記載はこちら（アドバイスありがとうございます！）：
[レイアウトとレンダリング - 3.4.5 コレクションをレンダリングする](https://railsguides.jp/layouts_and_rendering.html#%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B)

### TIPS

例えば、`=render @comments`と書くと、自動的にRailsは`comments/_comment`のファイルを探しに行くので、**呼び出し元ファイルがcommentsディレクトリになくても**`=render @comments`と書けば@commentを繰り返し呼びだすことができました。

つまり例えば`posts#show`アクションのページで

```slim:posts/show.html.slim
 = render @comments
```

と書いても、自動的に`comments/_comment`が呼び出されるという仕組み。すごいですね。:grinning:
ジョーカーゲーム作成

定義
・ジョーカーを引いたら負け
・ランダム関数でカードを出力
・ユーザー1と2が交互にトランプを引いていく
・3枚まではジョーカーが出ない
・出たカードを真ん中に縦で並べていく
・リセットボタンも作成

使うものは連想配列(オブジェクト)、dom

補足
今回はあまりリッチなものにしない
順番に押せばゲームが出来る
ランダン関数で同じ番号が出たら関数内で再度引き直す
どっちがカードを出したかわかるようにして別途で順番を表記しない
カードをひっくり返した毎にそのカードの数字を配列に追加して、その配列と照らし合わせて重複を確認
重複したら自動的に引き直す

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./style.css">
    <title>jokergame</title>
</head>
<body>
    <div>
        <button>ユーザー1</button>
        <button>リセットボタン</button>
        <button>ユーザー2</button>
    </div>
    <p id="game-log">ハート6</p>
    <p>ハート6</p>
    <script src="./index.js"></script>
</body>
</html>
```

```css
div {
  display: flex;
  justify-content: space-around;
}
p {
  display: flex;
  justify-content: center;
}
```

組んでみたロジック

```js
const trump = {
    1: "♠1",
    2: "♠2",
    3: "♠3",
    4: "♠4",
    5: "♠5",
    6: "♠6",
    7: "♠7",
    8: "♠8",
    9: "♠9",
    10: "♠10",
    11: "♠11",
    12: "♠12",
    13: "♠13",
    14: "♥1",
    15: "♥2",
    16: "♥3",
    17: "♥4",
    18: "♥5",
    19: "♥6",
    20: "♥7",
    21: "♥8",
    22: "♥9",
    23: "♥10",
    24: "♥11",
    25: "♥12",
    26: "♥13",
    27: "♦1",
    28: "♦2",
    29: "♦3",
    30: "♦4",
    31: "♦5",
    32: "♦6",
    33: "♦7",
    34: "♦8",
    35: "♦9",
    36: "♦10",
    37: "♦11",
    38: "♦12",
    39: "♦13",
    40: "♣1",
    41: "♣2",
    42: "♣3",
    43: "♣4",
    44: "♣5",
    45: "♣6",
    46: "♣7",
    47: "♣8",
    48: "♣9",
    49: "♣10",
    50: "♣11",
    51: "♣12",
    52: "♣13",
    53: "ジョーカーやで＾＿＾",
}
var randoms = []
var turn = 0
var GameLog = document.getElementById('game-log')


function opencard(user) {
    var card = Math.floor(Math.random() * 53 + 1)
    var num=document.createElement('p')
    num.innerHTML = user + ':' + trump[card]
    if (user === 'user1') {
        num.style.color='red'
    } else {
        num.style.color='blue'
    }
    
    GameLog.appendChild(num)
    if (card == 53) {
        if (turn < 3) {
            alert('まだ試合を終えるには早すぎる')
            num.remove()
        } else {
            alert(user+' lose!!!!!!!!!!!!!!!!!!!!!!')
        }
    }
    for (var i = 0; i < randoms.length; i++){
        if (randoms[i] == card) {
            num.remove()
            turn = turn-1
        } 
    }
    randoms.push(card)
    turn = turn + 1
}

function reset() {
    turn = 0
    randoms = []
    while (GameLog.firstChild) GameLog.removeChild(GameLog.firstChild);

}
```
PRODORIC2で転写因子の結合配列を検索する

## 背景
転写因子がどのような配列に結合するのか調べたいとき、メジャーなもので無い限りは文献を1つずつ調べていく必要があると思います。PRODORIC2は細菌の転写因子の結合配列を簡易に検索できるWebツールです。
原著論文：[PRODORIC2: the bacterial gene regulation database in 2018](https://academic.oup.com/nar/article/46/D1/D320/4607805)

## 方法
[PRODORIC2](http://www.prodoric2.de/index.php)にアクセスします。結合配列を調べたい遺伝子名を入力し「Search database」をクリックします。
ここではラクトースオペロンのリプレッサーであるLacIを入力しました。
![PRODORIC_2_-_Main_page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363491/7eecd66c-82e9-d0b5-a520-d334a6ee875c.png)

## 結果
コンセンサス配列と参照された細菌種（今回は大腸菌K-12）が表示されます。Accessionをクリックすると詳細を確認できます。
![PRODORIC_2_-_Browse.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363491/cd01f638-5de2-a9dd-959d-5c30e4df1671.png)

結合配列をグラフィカルに表示してくれます。Motif Listには根拠となる文献へのリンクもあるので便利です。
![PRODORIC_2_-_Details_for_Matrix_MX000137.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363491/8621ff19-daba-4e60-5926-2b8c89d90ccc.png)
[serverless / API Gateway] メソッドリクエスト-リクエストの検証をserverless deployで設定する

# 概要

題名の通り。
ただ単に、ここに書いてあることを試しただけ。

- serverless公式ドキュメント  
[Serverless Reqvalidator Plugin](https://www.serverless.com/plugins/serverless-reqvalidator-plugin)

...ではあるのですが、ドキュメントに書いてあることよりも若干行数を減らせたような気がするので記事化( ..)φメモメモ
（日本語の記事も他にあまり見つけられなかったし...）

# 準備

```bash
$ npm install serverless-reqvalidator-plugin serverless-aws-documentation
```

# serverless.yml

`INFO: `と書いてあるところの書き方を間違えなければ、うまく設定できる

```yaml:serverless.yml
service: app-name
frameworkVersion: '2'

# INFO: 必須みたいです
plugins:
  - serverless-reqvalidator-plugin
  - serverless-aws-documentation

provider:
  apiGateway:
    shouldStartNameWithService: true
  endpointType: regional
  name: aws
  region: us-east-2
  role: arn:aws:iam::{AWS_ACCOUNT_ID}:role/service-role/xxxxxxxxxxx
  runtime: python3.8

package:
  exclude:
    - ./**
  include:
    - main.py

functions:
  tradehist:
    handler: main.lambda_handler
    name: {app-name}-dump
    events:
      - http:
          path: methodname
          method: get
          # INFO: RequestValidatorをここで読み込む
          #   Resourcesで作成した名前と一致していないと動かないよ
          reqValidatorName: onlyStringParameters
          request:
            parameters:
              querystrings:
                # INFO: ここでtrueにしたパラメータを検証してくれる
                #   この場合、param1, param2 どちらかでもなければアクセスをブロックしてくれる
                param1: true
                param2: true

resources:
  Resources:
    # INFO: API Gatewayのリクエストの検証有効化
    #   上記 'reqValidatorName:' には、これを指定しよう
    onlyStringParameters:
      Type: AWS::ApiGateway::RequestValidator
      Properties:
        Name: 'only-string-parameters'
        RestApiId:
          Ref: ApiGatewayRestApi
        # 本文(Body)を検証したい人はここをtrueにする
        ValidateRequestBody: false
        # クエリ文字列パラメータ(Parameters)を検証したい人はここをtrueにする
        ValidateRequestParameters: true
        # header検証したい人はどうすんの？ => すみませんわかりません
```

ちなみに、`{}`が書いてあるところは各自適切な文字列に書き換えていただければ！

公式には、`Outputs`とか、`requestModels`とかいろいろ書いてあるけど、最低限上記のコメントの通りにやれば動くことが確認できた。

# 結果確認

```
{"message": "Missing required request parameters: [param1]"}
```

API Gatewayにアクセスする際に、queryStringParameterをつけずにアクセスすると、上記のようなメッセージが返却されるようになる。

今回のserverless.ymlの例でいえば、以下のようなパターンの結果を得ることができる

|URL|結果|
|----|----|
|`https://xxxxxxxx.amazonaws.com?param1=hoge&param2=huga`|OK|
|`https://xxxxxxxx.amazonaws.com?param1=hoge`|NG|
|`https://xxxxxxxx.amazonaws.com?param2=huga`|NG|
|`https://xxxxxxxx.amazonaws.com?param2=huga&param2=huga`|NG|
|`https://xxxxxxxx.amazonaws.com?param1=hoge&param2=huga&param3=gehe`|OK|

# 参考記事

- serverless公式ドキュメント  
[Serverless Reqvalidator Plugin](https://www.serverless.com/plugins/serverless-reqvalidator-plugin)
- Qiita  
[API Gatewayのrequest validationをserverless frameworkでdeployする](https://qiita.com/picapica/items/1a47847d3beb689a5740)  
こちらの方は私のやり方とは違いました。  
この方法も学んでおくことで、やれることの幅が広がるかもしれない。(かもしれない)
Web API入門#1 〜APIとWeb API、Webの概要〜

## はじめに

タイトルについて記事にしました。
このシリーズで得る内容は以下の通りです。

・ Web APIを正しく使えるようになる
・ Web APIを正しく設計して作ることができるようになる（使いやすく・保守をしやすくする）

Web APIを使ったり設計したりするのにも、フロントエンド・バックエンドの領域を問わずエンジニアにとって
必要不可欠な知識かと思いましたのでご紹介します。

■ Web API入門についての記事
・ [Web API入門#2 〜REST、アーキテクチャについて〜](https://qiita.com/s79ns/items/bd8b1f50c34ada016196)
・ [Web API入門#3 〜URIの基礎知識〜](https://qiita.com/s79ns/items/c4ec2db048fa3b13638e)
・ [Web API入門#4 〜クールなURIの設計方法について〜](https://qiita.com/s79ns/items/e2f3b6f66059c2917206)
・ [Web API入門#5 〜HTTPの基礎〜](https://qiita.com/s79ns/items/31a6f6affdd28bb8b026)
・ [Web API入門#6 〜CRUDとHTTPメソッド〜](https://qiita.com/s79ns/items/9b0f76f4bfdf4140a506)
・ [Web API入門#7 〜ステータスコードの意味と活用〜](https://qiita.com/s79ns/items/043a00330e1259673167)
・ [Web API入門#8 〜HTTPヘッダー・キャッシュ〜](https://qiita.com/s79ns/items/c39e9fc3cc117348b269)

## APIとWeb APIとは何か

<font color="red">API（Application Programming Interface）</font>とは、サービス提供者が、そのサービスを利用する為に提供する
インターフェース（プログラム同士の間でデータのやり取りをする際の形式を定めたもの）です。
<font color="red">Web API</font>は、HTTP通信によってやりとりを行うAPIのことです。

## なぜ全てのエンジニアが知っておいた方が良いのか

<font color="red">マイクロサービス</font>が流行していて、マイクロサービスを利用する為に、APIが必要になります。
また、便利な<font color="red">SaaS</font>が増え、これを扱うのにもAPIの利用が不可欠となります。

#### マイクロサービス

1つのアプリケーション内で、特定の機能に応じて細かく開発を行うことです。アプリケーションをリリースする時に、APIを使ってマイクロサービスを連結します。

#### SaaS（Software as a Service）

今までソフトウェアとして提供されていたものが、APIを使ってアクセスし、その機能を使うことができるようになる仕組みです。（オンライン決済や認証など）

マイクロサービスやSaaSを扱う上で、APIを実行する機会が増えます。
その上、簡単なAPIであれば、フロントエンドエンジニアでも扱うので、現在のWebサービス開発ではAPIは必須と言えます。そしてWeb APIでやりとりされる大半のデータフォーマットは、JSONではないでしょうか。

## 現代のWebを支える技術

#### HTTP

通信を行う為のルールで、プロトコルと呼ばれます。
シンプルで扱いやすいという特徴を持っているので、全世界で広まり、使われ続けています。

#### URI（Uniform Resource Identifier）

端的に表現すると、リソースを識別するIDです。皆さんがよく聞き慣れているのはURLではないでしょうか。
URIは、データが存在している場所にIDが紐付いている状態のことで、URLはデータが存在する場所は分かりますが、IDが分かっていない状態です。URIの中にURLが含まれていると考えれば良いのかもしれません。

#### HTML

Webエンジニアの皆さんでしたら触っていると思いますが、Webで表示する為の文書フォーマットです。
HTMLで定義されている書式に従い記述すると、文字を表示させたり大きくしたりすることができます。

## 集中システムと分散システム

#### 集中システム

メインフレームと呼ばれる巨大なコンピュータみたいなものが、全て処理をしているシステムです。
1980年代に主流だったそうで、巨大なコンピュータを用意する必要があり、多大なコストがかかってしまいます。
ただ、コンピュータが1台になるので、信頼性が重視されるシステム運用管理の面で、現代でも多少なりとも使われているところはあるそうです。

#### 分散システム

複数のコンピュータが相互に処理を担当し、それぞれで1つのシステムを作っているような状態です。
Webは世界規模の分散システムと呼ばれています。仮に1つサーバーがダウンしても、同じ役割を持つサーバーが動き続けることにより、サービスを止めずに稼働し続けることができます。

## 次の記事はこちら

[Web API入門#2 〜REST、アーキテクチャについて〜](https://qiita.com/s79ns/items/bd8b1f50c34ada016196)
webpack-dev-serverからリモートSSL環境のAPIを使用する

<!--# webpack-dev-serverからリモートSSL環境のAPIを使用する-->

webpack-dev-serverにはproxyオプションがあり、エンドポイントをwebpack-dev-serverのホストに組み込むことができます。

- https://webpack.js.org/configuration/dev-server/#devserverproxy

また、webpack-dev-serverにはSSL化のオプションもあり、これらを組み合わせるとリモートのSSLのAPIをsame originで扱うことができます。

- https://webpack.js.org/configuration/dev-server/#devserverhttps

(あまりお目にかかることはないのですが、最終的にはsame originになるけど開発用のAPIがリモートしかない、といった場合を想定しています)

# 必要なもの

webpack-dev-serverを使用しますので、webpackでの開発環境が存在する前提です。

ローカル環境用の秘密鍵、証明書、中間証明書を用意しておく必要があります。私はmkcertを使用しました。

- https://github.com/FiloSottile/mkcert

ここではプロジェクトルートにlocalhost-key.pem(秘密鍵)、localhost.pem(証明書)がある想定で進めます。

中間証明書はmacであれば`/Users/<ユーザー名>/Library/Application Support/mkcert/rootCA.pem`に生成されます(異なる場合もあるかもしれません)

# 記述例

`https://localhost:8080`にDevServerが起動し、リモートSSL環境のホストは`https://localhost:8080/api`に書き換えられ、same originでアクセスできます。

```js:webpack.config.js
{
  /** ... */
  devServer: {
    /** ... */
    https: true,
    cert: fs.readFileSync('./localhost.pem', 'utf8'),
    key: fs.readFileSync('./localhost-key.pem', 'utf8'),
    ca: fs.readFileSync('/path/to/mkcert/rootCA.pem', 'utf8'),
    proxy: {
      '/api': {
        target: '<リモートSSL環境のURL>',
        secure: false,
        changeOrigin: true,
        pathRewrite: {
          '^/api': '' // target以下をプロキシの/apiに書き換え
        }
      }
    }
    /** ... */
  }
}
```

# おまけ

ビルド後のファイルを使ってdockerでnginxのproxyを立てる方法です。

ビルドファイルが`./dist/`以下に生成される前提です。

## dockerに食わせるnginxの設定

あまり詳しくないです。とりあえず動く。

```nginx:default.conf
server {
    listen              443 default ssl;
    ssl_certificate     /etc/nginx/conf.d/localhost.pem;
    ssl_certificate_key /etc/nginx/conf.d/localhost-key.pem;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    location / {
        root      /usr/share/nginx/html;
        index     index.html index.htm;
        try_files $uri /index.html;
    }

    location /api {
        proxy_redirect off;
        proxy_pass <リモートSSL環境のURL>;
    }
}
```

## Dockerfileの例

`./dist/`以下のファイル群、鍵、証明書、nginxの設定もろもろをコピーしてnginxを起動すればOK

```dockerfile:Dockerfile
FROM nginx:latest
COPY ./default.conf /etc/nginx/conf.d/default.conf
COPY ./localhost.pem /etc/nginx/conf.d/localhost.pem
COPY ./localhost-key.pem /etc/nginx/conf.d/localhost-key.pem
COPY ./dist/ /usr/share/nginx/html/
EXPOSE 9000
# 適当なport
```
Salesforceのレコードコピー機能～Lightning環境とClassic環境のコピー機能の違いについて～


こんにちは。本橋です。

この記事はSalesforce 開発者向けブログ投稿キャンペーンへのエントリー記事です。

Salesforceは標準機能で様々な開発が行えます。
今回はその中でも「コピー機能」について説明し、つまづくところをご紹介しようと思います。

##そもそもレコードコピー機能ってなんだ？

レコードコピー機能についてヘルプはこちら
・レコードのコピー
https://help.salesforce.com/articleView?id=basics_clone_records.htm&type=5

ページレイアウト上に「コピー」ボタンを表示させることによりレコードコピーができます。
。

###コピー機能　つまづきポイント１　
####ページレイアウト上に表示されない項目はコピーされない

コピー機能であまり知られていない（？）事実ではないでしょうか？（少なくとも私はここにつまづきました）
ページレイアウト上に表示されない項目はコピーされない動作となります。

参考のヘルプはこちら
・コピー機能の制限について
https://help.salesforce.com/articleView?id=000321711&type=1&mode=1

###レコードコピー機能　つまづきポイント2 
####取引先オブジェクトにはコピーボタンがデフォルトでない

なんと！取引先オブジェクトにはデフォルトでコピーボタンがありません。
解決策としてカスタムボタンを作成になると思いますが、意外な盲点ですね。

###レコードコピー機能 つまづきポイント3
####Lightning環境とClassic環境でコピーする項目の値が異なる場合がある。

今回伝えたいのはこのポイント3です。
このポイントを説明するのはややこしいので、以下順序だてて説明します。

#####前提１
コピー対象のオブジェクト権限において「すべて変更」権限がないユーザの場合

今回のユーザは「すべて変更」権限がないユーザがレコードのコピーをする場合です。
![カスタムオブジェクト権限.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/a0ec8b6c-990a-2198-3a16-8c8e5b4b1b17.png)

#####前提2
ページレイアウトの項目設定で「参照のみ」の設定がされている場合

![ページレイアウト参照のみ設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/30c34e70-a650-c522-09b5-f34a62ddb248.png)

#####前提3
項目のレベルセキュリティで「参照のみ」にチェックが入っていない場合

項目レベルセキュリティ設定で一番右に「参照のみ」チェックボックスがありますが、こちらにチェックがない状態です。
![項目設定1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/3c85f6c7-0e13-6dce-96e0-20f69d467615.png)

ちょっと分かりにくいのでプロファイル側のスクショも貼ります。
なお、参考までに
「参照のみ　チェックあり」パターンと
「参照のみ　チェックなし」パターンの項目を今回準備しました。
![項目設定2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/b52b7aa1-6671-fbf5-183c-7810ec624061.png)



上記の条件の場合、Lightning環境とClassic環境でコピーする項目の値が異なります。

#####検証1 Lightning環境でコピーを行う

まずはLightning環境でコピーします。
（コピー後の状態が分かりやすいように項目に値が入っています。今回はテキスト項目と選択リスト項目で試します）
![Lightning1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/0598418c-d1c6-64b4-7fdc-b970a8e84809.png)

結果として「参照のみ　チェックなし」項目の値のみがコピーされました。
![LightningResult.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f0595854-9b94-96d2-eb65-3dec3fbabc5e.png)

#####検証2 Classic環境でコピーを行う

次に、Classic環境で先ほどと同じレコードをコピーします。
![Classic1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/cdc3a1cf-011a-c2b1-8945-fad7b62511cf.png)


↑の状態的には、Lightningの時と同じに見えますが。
結果は、、
![ClassicResult.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/9a9a3f29-c5a9-3e20-fcbc-d975cba273e1.png)

御覧のように。項目レベルセキュリティ設定に関わらず、すべての項目の値のコピーができない結果となりました。

リストビューで並べると違いが一目で分かりますね。
![結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/b4b3a037-6485-9b5c-a727-773f821d98dd.png)

####対策
今回のように、Classic環境とLightning環境ではコピーされる項目に違いがあることが分かりました。
これはClassic環境とLightning環境を併用している企業は混乱を招く要因になるかと思います。
対策としては
・項目レベルセキュリティ設定の見直し
・自動化を使用し（Classic環境やLightning環境に関わらず）同じ結果にする
という対策になりますね
自動化ではコピーしたことが条件となるISCLONE()関数が使用できますね。

####まとめ
今回、Lightning環境とClassic環境のコピー機能の違いがあることが分かりましたが、Lightning環境とClassic環境で違いがあることに私は驚きました。

今後Salesforceの構築を行う際はLightning環境でもClassic環境の想定の動きになるか、しっかりと確認していきたいと思いました。
curl で SwitchBotAPI を叩いて SwitchBotを動かす

# はじめに
この記事は、CUI を使って、インターネット経由で SwitchBot を動かす方法のメモです。
PC の terminal から、SwitchBot Bot（ボタン）を制御するような事が簡単に行えます。

具体的には、curl で SwitchBotAPI を叩き、SwitchBot を動かします。

SwitchBot を制御する手段には、[Bluetooth 通信を使ったアクセス方法](https://qiita.com/search?q=Bluetooth+Switchbot)もあります。
この Bluetooth 通信を使ったアクセスでは、通信範囲が限られますので、通信距離を気にせず、手っ取り早く叩いてみたければ、この記事で扱っている SwitchBotAPI を利用する方法がおすすめです。

# 必要なもの

* Switchbot デバイス 
* Switchbot Hub Mini または plus （クラウドサービスを利用するため Hub が必須）
* Switchbot アカウントでログイン済みの Switchbot アプリ（Android or iOS） 
* curl を実行する環境（PC）

# 手順
最初に SwitchBotAPI を叩くために必要な token を取得し、次に、取得した token を使って curl で SwitchBotAPI を叩きます。

## token の取得
1. Android または iOS 上で、Switchbot アプリを起動。
1. 未ログインであれば、 Switchbot アカウントでログイン。
1. 「プロフィール」タブの、「設定」メニューを選択し、最下部の「アプリバージョン」を 10 回タップ。
1. 「開発者向けオプション」が表示されるのでタップ。
2. 「トークンを取得」ボタンをタップ。
3. 赤字で表示された英数字列が取得できたトークンです。

* __このトークンがあれば、誰でも あなたの Switchbot を制御可能です。トークンを他人に共有したり、Github上で公開することの無いよう注意して下さい。__
* __2020/1/9 現在、作成したトークンは削除できず、リセットのみが行えるようです。
* トークン発行済みの状態で、さらにトークンを取得しても、最初に取得したトークンは有効のままです。適宜トークンのリセットを行い、意図しないトークンが残らないようにするのがおすすめです

## curl で SwitchBotAPI を叩く （デバイス一覧の取得）
最初にデバイス一覧の取得を行ってみましょう。
デバイス一覧の取得は、指定すべきパラメータがなく、簡単です。
トークンの問題や、デバイスの設定に問題がないかは、このAPIを試すと良いです。

以降は、curl を実行する環境（PC）上で作業を行います。

```
token="<取得したトークン>"
auth="Authorization:${token}"
url_list="https://api.switch-bot.com/v1.0/devices"

curl -H "${auth}" "${url_list}"
```

トークンが有効で、アカウントに紐づく switchbot デバイスがあれば、次のようなレスポンスが返ってきます。
（※ IdやdeviceNameは伏せています。内容の一部は省略しています。）

```
{"statusCode":100,"body":{"deviceList":[{"deviceId":"FFFFFFFF","deviceName":"XXXXXXXX","deviceType":"Bot","enableCloudService":true,"hubDeviceId":"FFFFFFFF"}, ... ]},"message":"success"}
```
### エラーになる場合

#### Authorization header requires ...

```
{"message":"Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header. Authorization=XXXXXXXXXXXXXXXXXXXXXXXXXXX
```
上記のエラーになる場合、ヘッダーの Authorization 指定を見直して下さい。
指定されていないか、指定が誤っている可能性があります。

#### Unauthorized

```
{"message":"Unauthorized"}
```
上記のエラーになる場合、トークン 指定を見直して下さい。
無効なトークンが指定されているか、文字列が誤っている可能性があります。

## Switchbot Bot (ボタン)を押す

対象の Switchbot Bot (ボタン) は、「クラウドサービス」を有効にしておく必要があります。

以降は、curl を実行する環境（PC）上で作業を行います。

### device ID の取得

前述の 「 curl で SwitchBotAPI を叩く （デバイス一覧の取得）」 で得られたレスポンスから、 device ID を取得します。
`"deviceId":"FFFFFFFF"`
となっている部分が、 device ID です。

### APIの実行

```
token="<取得したトークン>"
deviceid="<device ID>"
auth="Authorization:${token}"
type="Content-Type: application/json"
command='{"command": "turnOn"}'
url_commands="https://api.switch-bot.com/v1.0/devices/${deviceid}/commands"

curl -H "${auth}" -H "${type}" -X POST -d "${command}" "${url_commands}"

```

正常であれば、次のようなレスポンスが返ってきます。

```
{"statusCode":100,"body":{},"message":"success"}
```

うまく行かない場合は、次の点を確認して下さい。

* device ID に誤りがないか。
* そのデバイスのクラウドサービスが有効になっているか。

# SwitchbotAPI
その他の SwitchbotAPI の仕様については、下記を参照下さい。
https://github.com/OpenWonderLabs/SwitchBotAPI
Exam AI-900: Microsoft Azure AI Fundamentalsに合格した

新型コロナウイルス感染症のせいで業務量が減り、出勤を減らされていてしまい、平日に休みになった。
時間がある今だからこそ出来ることをと思い、[ベータ試験の時のリベンジ](https://qiita.com/allforbigfire/items/68dfe2e2a5b682bf70d1)を果たしてきた。

#### 受験料
ベータ試験を受験したことで25パーセントOFFのバウチャーをいただいていた。
![AI-900-Beta.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155894/4596cca7-0c65-502f-5182-e78318000a82.png)

しかし、申し込みの段階で、**受験料0円**、無料のバウチャーをいつの間にか貰っていたことを知り、それを今回使用した。「Microsoftのトレーニング日」って何のイベントだったっけ。
![AI-900.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155894/b885cfa3-049d-b6e4-aa9f-a3b3139bb079.png)


#### 勉強の方法
[Microsoft 資格 AI-900 / DP-100 勉強法](https://qiita.com/junichia/items/0f13dd5d5f19081be2b5)の記事が大変参考になりました。

[MS Learn > Microsoft Certified: Azure AI Fundamentals](https://docs.microsoft.com/ja-jp/learn/certifications/azure-ai-fundamentals)を合計2周しました。
直前に見直しをしようと、試験センター近くのネットカフェに入りましたが、ブラウザがIEのため表示しかできず、万事休すの状態になりました。
ポテトおいしかったのに、2021年にもなってInternet Explorerを標準ブラウザにするのは本当に止めてほしかったです。

#### 試験結果
790点で合格しました。700点以上なので、ギリギリでした。
![IMG_4776.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155894/cdaf90a5-e60e-92ee-5dd6-f7e4c5ae64dc.jpeg)

![IMG_4777.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155894/b6349c13-2ef7-ded3-2156-caf90cb846b2.jpeg)

#### 感想
引用した記事を読んでいなかったら、点数が足りなかったと思います。
試験範囲のMS Learnでは足りないです。
AIの基礎試験を受けるぐらいなんだから、AIの基本事項や用語は知っているでしょ、という事なのでしょうか。手元にある本をパラパラみたら、「Pythonによるあたらしいデータ分析の教科書」の記述ぐらいは読んでおけば、もっと理解できたと思います。
あと、試験範囲のMS Learnのキーワードは、日本語と英語の両方を覚えたほうが記憶に残りやすいと思いました。

次は、AI-100に挑戦します。

また、余裕のある時にDP-900も受験して、Azure Fundamentals試験三銃士フルコンプしようと思います。[放送大学生の私の場合、odysseyで受験](https://mta.odyssey-com.co.jp/outline/#studentdiscount)すると半額になるようです。
【AWS】Route53

#Route53とは
・権威DNSサービス
　– AWSの提供する権威DNSサービス
　– DNSはドメイン名をIPアドレスに変換するインターネット上の「電話帳」
・AWS上で高可用性、低レイテンシなアーキテクチャを実現するツール
　– ポリシーベースの柔軟なトラフィックルーティング、フェイルオーバー、
　　トラフィックフローなどの機能により、様々な条件に基づくルーティングが可能
・高い可用性を提供
　– DNSはインターネットの根幹のサービス
　– Route 53 は 100%のAvailabilityのSLAを提供
・マネージドサービスとして提供
　– DNSサーバーの設計・構築・維持管理が不要
　– 冗長性・性能・セキュリティ等は全てAWSにて管理される

#ホストゾーン
・ホストゾーンとは
　– ドメイン、サブドメイン内のDNSリソースレコードを管理するコンテナ
　　• ホストゾーンの中に、DNSリソースレコードを登録
　– ホストゾーンには、ゾーンを管理する複数のDNSサーバーが割り当てられる (Delegation Set)
　　• 1つのホストゾーンに対して、4台のDNSサーバーが割り当て
　　• DNSサーバーは、全て異なるエッジロケーションに配置されている
　　• 4つのトップレベルドメイン (*.com, *.org, *.net, *.co.uk) にまたがる
　– パブリックホストゾーン、プライベートホストゾーンを作成可能
・ホストゾーンの制限
　– AWSアカウント毎に500ゾーンまで (上限緩和可能)
　– レコードはホストゾーンあたり10,000個まで (上限緩和可能)

#ALIASレコード
・ALIASレコードとは
　– Route 53固有の仮想リソースレコード
　– DNSクエリに対して、以下のAWSサービスのエンドポイントのIPアドレス
　　を直接返す(通常はCNAMEを利用)
　　• 静的ウェブサイトとして設定されたS3バケット
　　• CloudFront ディストリビューション
　　• ELB
　　• ホストゾーン内のリソースレコードセット (複雑なポリシーの作成で使用)
・ALIASレコードを使うメリット
　– DNSクエリに対するレスポンスが高速
　– Zone Apexが利用可能
　– ALIASレコードに対するクエリが無料(S3, CloudFront, ELB)

#ALIASレコードによるDNS名前解決の高速化
・Route 53と連携したDNS Lookupの高速化
　• CloudFrontのAlternative Domain NameをRoute53を利用して名前解決する際は、
　　レコードセットTypeをCNAMEではなくAレコードのAlias設定することでクエリの回数が削減

#トラフィックルーティング
・トラフィックルーティングとは
　– クライアントからのトラフィックを、要件に応じて適切な宛先へ転送すること
　– ここでは、DNS名前解決によるトラフィックの転送を対象とする
　– DNSクエリに対して適切な転送先を応答するために、ルーティングポリシーを活用する
　– トラフィックルーティングを適切に設計することにより、
　　可用性が高くレイテンシの少ないアーキテクチャを構築することができる
・従来のDNSでのルーティング
　– DNSで事前に定義された、静的なリソースレコードにのみに基づいてDNSクエリに応答
　(例)
　　• www.example.com へのリクエストは IPアドレス 1.1.1.1 に転送
　　• ポリシーベースのルーティング
　– DNSクエリに対して、ポリシーで定義されたルールに基づいて、
　　動的に状況に応じた転送先を応答
　(例)
　　• www.example.com へは、送信元が日本の場合、東京リージョンへ転送
　　• 送信元が日本以外の場合、送信元からのレイテンシーが最も小さいリージョンへ転送

#ルーティングポリシー
 Route 53では、複数のルーティングポリシーにより柔軟なルールを作成可能
　• シンプルルーティング (Simple)
　　– レコードセットで事前に設定された値のみに基づいてDNSクエリに応答する
　　– 従来のDNSと同様に、静的なマッピングによりルーティングが決定される
　• 加重ルーティング (Weighted)
　　– 複数エンドポイント毎に設定された重みづけに基づいて、DNSクエリに応答する
　　– より重み付けの高いエンドポイントのリソースに、より多くルーティングされる
　　– A/Bテスト、段階的な移行、サーバー毎に性能に偏りがある場合
　• レイテンシールーティング (Latency)
　　– AWSリージョンとの遅延によって、DNSクエリに応答する
　　– リージョン間の遅延が少ない方のリソースへルーティングされる
　　– エンドユーザーのレイテンシーを低減したい
　　　動的なサイトでレスポンスを早くしたい
　　　（静的：CloudFrontでキャッシュを活用、動的：キャッシュの制約がある）
　• フェイルオーバールーティング (Failover)
　　– ヘルスチェックの結果に基づいて、利用可能なリソースをDNSクエリに応答する
　　– 利用可能なリソースにのみルーティングされる
　　– 複数のリージョンにまたがるシステムで冗長化構成、
　　　災害発生時にリージョン間でフェイルオーバー、
　　　サイト障害時にS3静的WebサイトホスティングのSorryPageを表示
　• 位置情報ルーティング (Geolocation)
　　– クライアントの位置情報に基づいて、DNSクエリに応答する
　　– 特定の地域・国からのDNSクエリに対して、特定のアドレスを応答する
　　– ローカライズ：クライアントの地域により適切な言語でコンテンツを提供
　　　コンプライアンス：コンテンツディストリビューションを
　　　　　　　　　　　　ライセンス許可した市場のみに制限
　　　パフォーマンス：特定の地域からエンドエンドポイント間の
　　　　　　　　　　　安定したルーティングを必要とするケース

#DNSフェイルオーバとは
ヘルスチェックによりエンドポイントのリソースの正常性をチェックし、正常な場合のみルーティングされるようにDNSクエリに応答

#ヘルスチェック
<font color="red">異常と判断した対象のIPアドレスをクエリ結果として返さない。全て以上の場合はIPアドレスを返す仕様</font>
Sidekiq pro を Rails にインストールする

sidekiq proをRailsで使おうとしたときに、
公式wikiのほうでは、インストール方法がどうにも見つけられず、
手こずったので、まとめてました。

sidekiqの使い方ブログ記事も色々ありますが、proのほうはなかなか無かったり……

公式wiki
https://github.com/mperham/sidekiq/wiki

# 手順
sidekiq-proをGemfileに追加します。

```Gemfile
gem 'sidekiq-pro', source: "https://gems.contribsys.com/"
```

bundle install時に https://gems.contribsys.com/ というサイトを確認しにいくのですが、その際に認証情報が必要です。

接続に必要なIDとパスワードは、環境変数に入れておくのが一般的なようです。
(ちなみにIDとパスワードは、proライセンスの購入時に入手できるっぽいです。)

```sh
export BUNDLE_GEMS__CONTRIBSYS__COM= id : pass
```
環境変数に設定ができたら、インストールします。

```sh
bundle install
```

インストールが出来たら sidekiq を起動します。

```sh
bundle exec sidekiq
```
sidekiq起動時に、アスキーアートみたいなのがsidekiq proになっていればインストール出来ています。

![スクリーンショット 2021-01-07 16.32.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8222/db9c0e20-9a6a-e171-9266-d938721fd7ce.png)


参考：
https://tech.medpeer.co.jp/entry/2020/04/01/090000
https://devcenter.heroku.com/ja/articles/bundler-configuration
[CpawCTF]Q14.[PPC]並べ替えろ!をPythonで書いてみる

https://ctf.cpaw.site/questions.php?qnum=14
CpawCTFのQ14をPython解いてみるメモです


配列を降順に並び替えるらしい
せっかくなのでPythonで記述したい
結果を先に書くとこんな感じ

```python
list = [15,1,93,52,66,31,87,0,42,77,46,24,99,10,19,36,27,4,58,76,2,81,50,102,33,94,20,14,80,82,49,41,12,143,121,7,111,100,60,55,108,34,150,103,109,130,25,54,57,159,136,110,3,167,119,72,18,151,105,171,160,144,85,201,193,188,190,146,210,211,63,207]
sort_list = sorted(list, reverse=True)
answer = ''.join(map(str,sort_list))
print(answer)
```
※参考させていただいたURL
https://note.nkmk.me/python-list-sort-sorted/
https://note.nkmk.me/python-string-concat/

最初にjoinのところを

```
answer = ''.join(sort_list)
```
と記述したところ下記のようなエラーが出た

```
TypeError: sequence item 0: expected str instance, int found
```

どうもjoinはstr型じゃないといけないらしく、下記の通りmap()で型を変換できるらしいのでやってみたらエラーを吐かなくなった

```
answer = ''.join(map(str,sort_list))
```

調べればもっと簡単なのがありそうな気もするけどとりあえず解けたのでメモとして残しておく(´・ω・｀)


###※追記

遠回りせずともIDLEで一発だった(´；ω；｀)

```python
>>> spam = [15,1,93,52,66,31,87,0,42,77,46,24,99,10,19,36,27,4,58,76,2,81,50,102,33,94,20,14,80,82,49,41,12,143,121,7,111,100,60,55,108,34,150,103,109,130,25,54,57,159,136,110,3,167,119,72,18,151,105,171,160,144,85,201,193,188,190,146,210,211,63,207]
>>> 
>>> 
>>> spam
[0, 1, 2, 3, 4, 7, 10, 12, 14, 15, 18, 19, 20, 24, 25, 27, 31, 33, 34, 36, 41, 42, 46, 49, 50, 52, 54, 55, 57, 58, 60, 63, 66, 72, 76, 77, 80, 81, 82, 85, 87, 93, 94, 99, 100, 102, 103, 105, 108, 109, 110, 111, 119, 121, 130, 136, 143, 144, 146, 150, 151, 159, 160, 167, 171, 188, 190, 193, 201, 207, 210, 211]
```
atom が表示されない



テキストエディタはatomを使用しているのですが、
昨日起動はするものの、メニューバーには終了のメニューしか表示されず。

公式サイトからダウンロードして、しばらく問題なく使えたのになぜ？
https://atom.io


やったこと
・Atom 本体とcom.github.atom.plist削除
・ゴミ箱を空にして、Mac再起動
・もう一度ダウンロード
・zipファイルを解凍し、ダウンロードフォルダのAtomアイコンをアプリケーションフォルダにドラッグ＆ドロップして使用
rubyの「||=」の仕様を理解と、Railsのpresenceメソッドとは

# なにこれ
筆者が`||=`の扱いでずっこけたので、備忘録として書いてます。
presenceメソッドの解説(?)もしてるので、良かったら見てください！
ご指摘があればコメント欄までお願いいたします。


# そもそも「||=」とは
簡単に言うと**自己代入**
rubyでよく見る下記のコードと同じ意味

```rb
result = 1
result += 2
p result #=> 3
```

これを「もしnil or falseだったら、右辺を代入する」に変えたバージョン。

```rb
def check(arg)
  arg ||= 'nil or false'
  p arg
end
check('hoge') #=> 'hoge'
check(nil) #=> 'nil or false'
check(false) #=> 'nil or false'
```

# ||= の詳しい動き
Rubyのドキュメントに素晴らしいサンプルコードがあったので、抜粋します

```rb
p obj.foo ||= true
p obj.foo || (obj.foo = true)
```

まさに上記と同じ動きをしています。

`||`で比較をする。`||`は最初に真になったものを返す。
`obj.foo`がnil or falseじゃなければ真つまり左辺を返す。
左辺が偽なら、左辺の変数に対して右辺のコードを代入する。ということです。



# 筆者がハマった罠（余談）
上記の**nil or falseだったら左辺に代入する**という仕様を理解できてなかったせいで、
若干沼ったので備忘録として残します。
この記事を書こうとした理由でもあります。

Railsで開発してて、次の要件を満たすメソッドを作りたかった。

・DBから指定したidかつboolean型がtrueのレコードを取得する
・取得したレコードのboolean型をfalseにしてupdateする

・必ずレコードが存在するとは限らない。
・条件に一致したレコードが取得できなければreturnする

下記のようなコードを書きました（変数名は仮）

```rb
def find_and_change_default(post_id)
  post = Post.find_by(id: post_id, boolean: true)
  if post.present?
    post.update(boolean: false)
  end
end
```

1つ問題として思ったのが
「postをfind_byしたのにpresent?で存在確認するって冗長じゃね？」
と、思いました。

そこで色々調べたところ、Railsのpresenceメソッドを知って、下記のように修正しました

```rb
def find_and_change_default(post_id)
  post = Post.find_by(id: post_id, boolean: true).presence || return
  post.update(boolean: false)
end
```

presneceメソッドはRailsで次のように定義されてます。

```activesupport/lib/active_support/core_ext/object/blank.rb
  def presence
    self if present?
  end
```

レシーバ（今回はpost）がpresent?でtrueが返されれば、selfを返します。
Railsガイドに下記のような用法が紹介されてました。

```rb
host = config[:host].presence || 'localhost'
```

configにhostがあれば、そちらを代入。なければlocalhostを代入する。というコードです。

# 「||=」とpresenceメソッドの関係性
~~ここを一番説明したかった。今までは前座です~~

`||=`の左辺がnil or falseなら右辺を代入する。という仕様を理解してなくて起こった悲劇です。

nilだったらreturnするから、`||=`が使えそう！と何故か思ってしまい、
こんなコードを書いてしまいました

```rb
  post = Post.find_by(id: post_id, boolean: true).presence ||= return
  #=> undefined method `presence=' for nil:NilClass (NoMethodError)
```

上記は一致するレコードがなかった時の結果です。
エラーを吐いた時は頭を抱えましたが、rubyのドキュメントを100回確認したら理解できました。
https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html

用法を調べたら、Railsに下記のようなコードがありました（メソッドはRailsのコードから適当に抜粋しました）

```rb
def open_connection(server = nil)
  server ||= TestServer.new
  # 後続の処理
end
```

**引数にとった値を確認する時に使う**のが一般的だと思いました。
さっきの場合は、DBからデータを取得して変数に格納したいのに、左辺に代入するという意味が分かってなくて、
上記のようなコードを書いてしまいました。
`nil.presence`メソッドを実行してる左辺に対してreturnを代入するって、もはやメチャクチャですね
VisualStudioCode 現在登録されているショートカットを確認する

# 目的

- 現在設定されているVisualStudioCode（以後VScode）のショートカットの確認方法をメモ的にまとめる

# 補足

- デフォルトで設定されているショートカットを見たい方はこちらを参照してみてください
    - [https://code.visualstudio.com/docs/getstarted/keybindings#_default-keyboard-shortcuts](https://code.visualstudio.com/docs/getstarted/keybindings#_default-keyboard-shortcuts)

# 方法

1. VScodeを開き左下の歯車マークをクリックする。

    ![Visual_Studio_Code.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/8e847c0b-b6b3-26d7-cf05-de3ec1b0a669.png)

1. 「キーボード ショートカット」をクリックする。

    ![スクリーンショット_2021-01-08_18_22_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/9bb3a3fe-9e27-e65e-d839-a4e6a1a185f6.png)

1. ショートカットの一覧が表示される。「コマンド」の部分がショートカットキーで実行される動作で、「キーバインド」に記載されている部分がショートカットキーになる。

    ![キーボード_ショートカット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/79135c8b-ef1e-e921-30b8-9d6f538e06fe.png)

1. 「〇〇に関するショートカットが知りたい！！」というときには「入力してキーバインド内を検索」の部分にキーワードを入力すると関連したショートカットが絞り込み表示される。（例えばターミナルに関してのショートカットを知りたい時は「ターミナル」と入力するだけで関連するショートカットが表示される。）

    ![キーボード_ショートカット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/3c6b842d-9396-ff3c-6546-77efc3c4780e.png)
    ![キーボード_ショートカット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/888b8b00-95ec-39ce-d1e9-f5077a7c641d.png)

1. 既に多くの先駆者のみなさんがVScodeのショートカットをまとめてくださっているが自分がやりたい動作のショートカットをぱっと検索で確認できるからこの方法もありかもしれない。
尾藤 克之　頭がいい人の読書術　まとめ


これからたくさん本を読もうとしているひと（自分）にむけて簡潔にまとめる。
前回同様内容全てを記述するわけではなく、あたりまえだろｗと思ってる部分とか自分では常識になっているところは省略している。

結論
#読書は知識と成長を手に入れられる最強の娯楽である
ただ、
##読書はアウトプットしないと意味がない、アウトプットする為には理解することが重要
なるほど

###読んだ内容を人に話したり、共有することで記憶に定着しやすくなる

「エビングハウスの忘却曲線」
例えば本を一冊３時間くらいで普通に読んだとして、
２０分後に42％忘れる
１時間後には56％忘れる
９時間後には64％忘れる
1日後には６７％忘れる
2日後には72％忘れる
6日後には７５％忘れる
らしい、だからアウトプットや共有、記録が重要なのだということ。

そこでおすすめと言われてるのが
###読んだ本の内容を文章にする
さらに大事と言われているのが、最初に結論を書くこと。この記事を見てもらったらわかる。

では
###読書習慣をつけるには？

１、読書日記をつける
２、手軽に文庫本から読む
３、目に見える場所に本を置く
自分は今までは断然紙派だったけど、本を置く場所ももうないし
これから電子書籍に移行するので（キンドルペーパーホワイトを購入2021/1/8）、３は難しいけど読み返したいと思う本は紙で買おうと思う。


###三分の一リーディング
短時間でなるべく早く本を読む「ページの三分の一しか読まない」方法。
これはタイポグリセミア現象を利用している
　→文節の単語の最初と最後の文字さえあっていれば順番がばらばらでも読み取れる現象のこと。
はやく読むコツは、頭の中で音読してはいけない。


###本は何を読むかよりも何を読まないかが９割
自分が本を読んで何を得たいのか、明確にしてから本を選ぶこと。
目的を明確にすることで得たい情報だけを読み取るので20％くらいの情報量で理解はできる。


###本を読むタイミングは朝一番と夜寝る前
本を読むのは集中力が必要、一番脳がすっきりしてのめり込めるのは"朝"
集中力を上げるには良質な睡眠が必要
→夜寝る前に読書する（スマホやパソコンなどのブルーライトを浴びない）ことで眠りに入りやすくなる。


####集中するための環境が必要、余計なものはすべてシャットアウトする
####読書と学習においてはキッチンタイマーが有効
スマホのタイマーよりも、それだけの機能で数字が可視化できるほうが危機感もてるので集中力があがる

###本をはやく読んで的確な情報を入手することの練習
・ビジネスパーソンは日経新聞を読むことから始める
・ダイヤモンド、東洋経済、日経ビジネスは社会人の鉄板ビジネス本意外だとシンクタンクのレポートがおすすめ

###国境
「こっきょう」とよむのか、「くにざかい」と読むのか。
なぜこれをピックアップしたのかは忘れた。

##最後に
著者の一番おすすめの本は「「死ぬくらいなら会社辞めれば」ができないわけ」
今度読んでみる。

---
以上になります。
もう少し記事をまとめる速度をはやくするように頑張ります。
ありがとうございました。
【Java】全角⇔半角の変換

DefaultFullHalfクラスを使いました。

・参考
[TERASOLUNA Server Framework for Java 7.6文字列処理](http://terasolunaorg.github.io/guideline/5.6.1.RELEASE/ja/ArchitectureInDetail/GeneralFuncDetail/StringProcessing.html?highlight=%E6%96%87%E5%AD%97%E5%88%97%E5%87%A6%E7%90%86#stringprocessinghowtousefullhalfconverter)

# ライブラリの追加
https://mvnrepository.com/artifact/org.terasoluna.gfw/terasoluna-gfw-string

```xml:maven
<!-- https://mvnrepository.com/artifact/org.terasoluna.gfw/terasoluna-gfw-string -->
<dependency>
    <groupId>org.terasoluna.gfw</groupId>
    <artifactId>terasoluna-gfw-string</artifactId>
    <version>5.6.1.RELEASE</version>
</dependency>
```

```gradle:gradle
dependencies {
// https://mvnrepository.com/artifact/org.terasoluna.gfw/terasoluna-gfw-string
compile group: 'org.terasoluna.gfw', name: 'terasoluna-gfw-string', version: '5.6.1.RELEASE'
}
```

Gradle→Gradleプロジェクトのリフレッシュを忘れずに。

# 全角から半角へ変換

```java
import org.terasoluna.gfw.common.fullhalf.DefaultFullHalf;

// 中略
        String halfwidth = DefaultFullHalf.INSTANCE.toHalfwidth(ａタチヅデプ);// 濁点・半濁点もOK
		System.out.println(halfwidth); //aﾀﾁﾂﾞﾃﾞﾌﾟ

```

# 半角から全角へ変換

```java
import org.terasoluna.gfw.common.fullhalf.DefaultFullHalf;

// 中略
        String fullwidth = DefaultFullHalf.INSTANCE.toFullwidth("ｱﾞ!A8ｶﾞザ");
		System.out.println(fullwidth);// ア゛！Ａ８ガザ

```

# その他の方法
[Javaの文字変換ライブラリICU4Jを使ってみよう](https://weblabo.oscasierra.net/java-icu4j-1/)
[Javaにおける文字列の全角⇔半角変換について](https://qiita.com/makimaki913/items/df745b85b802099a6e32)
他にもICU4Jやjava.text.normalizerで変換する方法があります。
normalizerだと全角カタカナ→半角カタカナ変換ができませんでした
Railsでログデータが溜まって環境が動かなくなった時

![スクリーンショット 2021-01-09 13.03.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/958041/bc840cfb-b02e-dc93-815d-f2e0a1490021.png)

　Cloud9でRilasチュートリアルをやっていたら 『容量が足りません！』 的な警告が出てきました。

　これは 『rails server』 や 『raila test』 時にログが記録されてそのデータが圧迫しているがために表示されるものです。

　解決策としては図で示したログフォルダ内の『development.log』 と『test.log』 の中身を空にしてあげればOKです。

　ログデータを増やし続けるとターミナルすら動かなくなってしまう為ログデータの整理は定期的に行った方が良いですね。
discordで据え置きゲーム配信

# こんな人に
- switchやps4などのHDMI出力のゲーム画面をdiscordで画面共有したい

# 用意するもの
- ゲーム自体（本体、HDMIケーブル）
- キャプチャ機器
    - 自分はこれを使ってます( https://www.amazon.co.jp/gp/product/B08BCBLGTG/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)
- OBS Studio
    - https://obsproject.com/ja/download
- discord
    - https://discord.com/

# 手順
## キャプチャ機器を介してPCにゲームの出力を流す
1. 普段ゲーム機からHDMIケーブルでディスプレイにつなぐところを、ディスプレイの代わりにキャプチャ機器のHDMIを差すところにつなぐ
2. キャプチャ機器のUSB端子をPCにつなぐ
3. PCにつないだ際にPCの画面に「○○の接続を検知しました」などがもし表示されたら、その名前を覚えておく
    - のちにOBSでその入力元を探すときに楽です
    - 後でdiscordからでも探せるので確認できなくても問題ないです
    - switchは電源からの電力供給をしないとテレビ出力がそもそもできないので、switchのUSBType-cから直接PCにつなぐと映りません。ドックなどにswitchをセットする必要があります。
    - あああ


## PCでOBSのセットアップをする
参考元：https://vip-jikkyo.net/go-live-on-discord

1. OBSをインストールして起動
2. メニューの「シーンコレクション」から「新規」を選択してシーンコレクションを作成
    - 名前は分かりやすい名前ならなんでも（画面共有など）
3. OBSにゲーム映像を追加
    - OBSの画面下「ソース」という項目でソースを追加
    - OBSの画面にあるように「＋」を押すか右クリックメニューで「追加」を選択
    - 「映像キャプチャデバイス」を選択して適当な名前で新規作成（ゲーム画面など）<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98140/7905ffeb-a065-6673-5b03-b5ef63f20c56.png" width="50%">
    - キャプチャ機器のデバイスを指定して設定<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98140/9c58288c-2202-67cf-3fd2-3b35450a607a.png" width="50%">
        - ここで指定するのは、もしキャプチャ機器接続時に出てきた名前があればそれを
        - １つしか候補がないのであればそれを
        - discordのビデオ設定で指定できる入力名があればそれを
    - ゲーム画面がはみ出る場合は「ソース」に追加されたものを右クリック、「出力サイズ変更（ソースサイズ）」でいい感じに画面に収まってくれます
    - もし画面が黒いままなら以下を試してみてください
        - ゲーム機がスリープに入っているのであれば起動する
        - 追加したソースの項目をダブルクリックで開き、デバイスを再設定する
        - 追加したソースを削除してやり直す

4. ゲームの音を追加
    - 3と同じようにしてソースを追加
        - 今回は「音声入力キャプチャ」を選択（名前は適当に「ゲーム音」など）
        - デバイスの指定では映像と同じような名前があるはずなので、それを選択
5. 配信する際の音を設定
    - 「音量ミキサー」の歯車マークを右クリック、「オーディオの詳細プロパティ」を選択して設定画面を開く
    - 「音声モニタリング」のところを以下のように設定
        - 映像（ゲーム画面）：モニターオフ
        - 音声（ゲーム音）：モニターのみ（出力はミュート）
    
## Discordで画面共有をする
discordのGoLiveでOBSの画面をそのまま共有すれば、ゲーム画面の部分だけを自動に切り取って画面共有してくれます
【AWS】ロードバランサー

#複数AZに分散

・二段階での負荷分散
１）DNSラウンドロビンで各AZ内のELBに振り分け
２）負荷が均等になるようにバックエンドのEC2にそれぞれのルーティングアルゴリズムで振り分け
　ALB：ラウンドロビンルーティング
　NLB：フローハッシュアルゴリズムルーティング

・クロスゾーン負荷分散
　ALB：デフォルトで有効
　NLB：デフォルトで無効
　CLB:デフォルトで有効

・同一のインスタンスで複数ポートに負荷分散可能
　異なるポートに対して負荷分散

・IPアドレスをターゲットに設定
　ALB \NLB

・ELB自体のスケーリング
　ALB,CLBにおいては接続が習慣的に急増した場合、HTTP５０３を返す
　　→Pre-Warming(暖機運転)の申請をサポートケースにて行う
　　→自前で付加を段階的にかけてスケーリングさせておく
・NLBは暖機不要で突発的な数百万リクエスト１/秒のトラフィックも捌ける

#モニタリング
・ヘルスチェック
<font color="red">1)HTTP及びHTTPSリスナーを使用する場合には、EC2インスタンスでキーアライブのオプションを有効化することでロードバランサーがバックエンドインスタンスへの接続を再利用できるようになり、CPU使用率が削減される
2)異常と判断したインスタンスにはトラフィックは流さない</font>
・アクセスログ
　ELBのアクセスログを取得可能
　S３バケットに簡単にログを自動保管

#スティッキーセッション
・一時ファイルなどをEC2インスタンスが保持するな場合に必要　
・デフォルトで無効
・HTTP/HTTPのみ利用可能

#SL/TLS Termination
・ELB側でSSL/TLS認証ができる
　１）ELBでSSLTerminationし、バックエンドとはSSLなし　←通常これが多い
　２）ELBでSSLTerminationし、バックエンドとは別途SSL
　３）SSLをバイパスしてバックエンドにTCPで送信

ACMを利用すれば証明書を利用可能



#ALB
・L7ロードバランサー
・HPPP \HTTPSのみ対応
・コンテンツベースのルーティング（高度なリクエストルーティング）
・ユーザー認証機能
　Cognitoによる認証
　OIDC　IdPによる認証（Google、Amazonなど）
・暖機申請は必要
・その他
　・ネイティブHTTP/2対応
　・ターゲットとしてのLambda関数
　・クライアントのIPアドレス取得について（ALB \NLBの違い）
　・AWS WAFとに連携について
　　ALBのみ可能
　・Websocketに対応

#NLB
・TCP（L4）のバランサとして機能
・固定IPアドレス：AZごとに1つ、既に持っているEIPも利用可能
・送信元にIPアドレスの保持：X−Forwarded−ForやProxy Protocolが不要
・暖機なしに急激なスパイクにも対応
・Vpcエンドポイントサービス（AWS PrivateLink）のサポート
・NLBnihaセキュリティグループの設定がない

→以下、特に重要
　１）高可用性、高スループット、低レイテンシー
　２）Source IP/Portがターゲットまで保持される
　３）固定IP


#Glocal Acceleratorとの連携
　ALBとNLBを指定できる
　ユーザは近いエッジjロケーションからGlobal Networkを経由して最も近いリージョンにアクセス可能

#メモ
・トラフィックを複数のインスタンスに分散
・ヘルスチェック機能で、ELB配下のインスタンスがヘルスチェックに失敗した場合、振り分けを停止
・ヘルスチェックが回復した場合、振り分け再開
・暗号化・複合化（SSL）機能あり
Intellij idea で Railsプロジェクトを認識する

# 課題
Intellij idea で Railsプロジェクトを開く際に、Railsのプロジェクトと認識されない

# 解決策
Project Structureを開き、moduleを消して、再度取り込む
![_2021-01-09_14.30.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12759/77119ddc-ebb8-0efb-f1b7-d4b7f0594d93.png)

認識しない場合は、以下を試す

- node_modulesディレクトリを削除する
    - webプロジェクトと認識される場合がある
- vendorディレクトリを削除する
  - Javaのプロジェクトと認識される場合がある

# 補足
ここでめっちゃ話してた
[https://youtrack.jetbrains.com/issue/RUBY-21465](https://youtrack.jetbrains.com/issue/RUBY-21465)
Storybook6.1 トラブルシューティング(Nuxt store, v-data-table)

## はじめに

Storybook が大変便利と聞いて使い始めましたが、2020年8月にVer6.0 にアップデートしてドキュメントが充実しておらず困った点をメモしておきます。

## Nuxt store

Nuxt の store はフォルダに配置したファイルを自動で認識してくれるモジュールモードで利用するのが便利ですが、storybookでは認識してくれません。

- store フォルダに以下配置

typescript での store の書き方は色々あるが以下が一番シンプルに思える(2021/1/9時点)
 
``` store/SampleStore.ts
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'

@Module({
  name: 'SampleStore',
  stateFactory: true,
  namespaced: true
})
export default class SampleStore extends VuexModule {

  someValue: int = 0

  @Mutation
  ...(略)

  @Action
  ...(略)
}
```

### 対応

#### 1. store を使える様に、preview.js に Vuex 追加

以下はVuetify利用時の preview.js

``` .storybook/preview.js
import Vue from 'vue'
import Vuex from 'vuex' // ★追加
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.css'
import colors from 'vuetify/es5/util/colors'
import '@mdi/font/css/materialdesignicons.css'

const vuetifyOptions = {}

Vue.use(Vuex) // ★追加

Vue.use(Vuetify, {
  // customVariables: ['../src/assets/variables.scss'], // 必要な場合
  theme: {
    dark: false,
    themes: {
      dark: {
        primary: colors.blue.darken2,
        accent: colors.grey.darken3,
        secondary: colors.amber.darken3,
        info: colors.teal.lighten1,
        warning: colors.amber.base,
        error: colors.deepOrange.accent4,
        success: colors.green.accent3
      }
    }
  },
  icons: {
    iconfont: 'mdi'
  }
})

export const decorators = [
  () => {
    return (
      { vuetify: new Vuetify(vuetifyOptions), template: '<v-app><story/></v-app>' }
    )
  }
]

```

#### 2. storeを参照するコンポーネントの stories.js で、ダミーのストアを作成し template に渡す

``` components/SampleComponent.stories.js
import Vuex from 'vuex'

import SampleComponent from './SampleComponent'

import SampleStore from '../store/SampleStore' // @/が解決できていないので相対パス

export default {
  title: 'SampleComponent',
  argTypes: {
  },
}

// ★追加
const store = new Vuex.Store({
  // 2021/01/30 修正：module モードの時は、modules
  modules: {
    SampleStore
  }
})

// いつものテンプレート
const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { SampleComponent },
  template: '<SampleComponent v-bind="$props" />',
  store: store // ★追加
})

export const Default = Template.bind({})
Default.args = {}

```

## v-data-table

v-data-table を利用しているコンポーネントは以下の様なエラーが発生しレンダリングされません。

```
Cannot read property 'mobile' of undefined
TypeError: Cannot read property 'mobile' of undefined
```

### 対応

github で issue が上がっています。(2021/1/9)
神々による対応が一日でも早く終る様に祈り中です。
[Internal vuetify methods error #13532](https://github.com/storybookjs/storybook/issues/13532)

(2021/01/30追記)
神々によってワークアラウンドが提示されてました！感謝しかありません。
他にも情報追加しましたので、詳細は別記事に記載しました。

[【超簡単フロントエンド開発】Storybook6.1 + Nuxtjs (+Vuetify) : フォローアップ](https://qiita.com/kaku3/items/f9240bd7e95185b58401)

## おわりに

Nuxt + Vuetify + Storybook での開発では、ドキュメント製造、コミュニーケーション、および **教育** のコストを大きく下げる開発様式が提案されている様に思えます。
Storybook を利用する方が増える様に知識を共有していければと思います。